1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sfx2/dispatch.hxx>
22 #include <tabvwsh.hxx>
23 #include <uiitems.hxx>
25 #include <rangenam.hxx>
26 #include <rangeutl.hxx>
27 #include <reffact.hxx>
28 #include <document.hxx>
29 #include <scresid.hxx>
31 #include <globstr.hrc>
32 #include <strings.hrc>
34 #include <consdlg.hxx>
35 #include <o3tl/safeint.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/weld.hxx>
41 void INFOBOX(weld::Window
* pWindow
, TranslateId id
)
43 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(pWindow
,
44 VclMessageType::Info
, VclButtonsType::Ok
,
57 void Set( const OUString
& rName
, const OUString
& rArea
)
67 ScConsolidateDlg::ScConsolidateDlg(SfxBindings
* pB
, SfxChildWindow
* pCW
, weld::Window
* pParent
,
68 const SfxItemSet
& rArgSet
)
70 : ScAnyRefDlgController(pB
, pCW
, pParent
, u
"modules/scalc/ui/consolidatedialog.ui"_ustr
, u
"ConsolidateDialog"_ustr
)
71 , aStrUndefined ( ScResId( SCSTR_UNDEFINED
) )
72 , theConsData ( static_cast<const ScConsolidateItem
&>(
73 rArgSet
.Get( rArgSet
.GetPool()->
74 GetWhichIDFromSlotID( SID_CONSOLIDATE
) )
76 , rViewData ( static_cast<ScTabViewShell
*>(SfxViewShell::Current())->
78 , rDoc ( static_cast<ScTabViewShell
*>(SfxViewShell::Current())->
79 GetViewData().GetDocument() )
80 , nAreaDataCount ( 0 )
81 , nWhichCons ( rArgSet
.GetPool()->GetWhichIDFromSlotID( SID_CONSOLIDATE
) )
82 , bDlgLostFocus ( false )
83 , m_xLbFunc(m_xBuilder
->weld_combo_box(u
"func"_ustr
))
84 , m_xLbConsAreas(m_xBuilder
->weld_tree_view(u
"consareas"_ustr
))
85 , m_xLbDataArea(m_xBuilder
->weld_combo_box(u
"lbdataarea"_ustr
))
86 , m_xEdDataArea(new formula::RefEdit(m_xBuilder
->weld_entry(u
"eddataarea"_ustr
)))
87 , m_xRbDataArea(new formula::RefButton(m_xBuilder
->weld_button(u
"rbdataarea"_ustr
)))
88 , m_xLbDestArea(m_xBuilder
->weld_combo_box(u
"lbdestarea"_ustr
))
89 , m_xEdDestArea(new formula::RefEdit(m_xBuilder
->weld_entry(u
"eddestarea"_ustr
)))
90 , m_xRbDestArea(new formula::RefButton(m_xBuilder
->weld_button(u
"rbdestarea"_ustr
)))
91 , m_xExpander(m_xBuilder
->weld_expander(u
"more"_ustr
))
92 , m_xBtnByRow(m_xBuilder
->weld_check_button(u
"byrow"_ustr
))
93 , m_xBtnByCol(m_xBuilder
->weld_check_button(u
"bycol"_ustr
))
94 , m_xBtnRefs(m_xBuilder
->weld_check_button(u
"refs"_ustr
))
95 , m_xBtnOk(m_xBuilder
->weld_button(u
"ok"_ustr
))
96 , m_xBtnCancel(m_xBuilder
->weld_button(u
"cancel"_ustr
))
97 , m_xBtnAdd(m_xBuilder
->weld_button(u
"add"_ustr
))
98 , m_xBtnRemove(m_xBuilder
->weld_button(u
"delete"_ustr
))
99 , m_xDataFT(m_xBuilder
->weld_label(u
"ftdataarea"_ustr
))
100 , m_xDestFT(m_xBuilder
->weld_label(u
"ftdestarea"_ustr
))
102 m_pRefInputEdit
= m_xEdDataArea
.get();
106 ScConsolidateDlg::~ScConsolidateDlg()
110 void ScConsolidateDlg::Init()
115 m_xRbDataArea
->SetReferences(this, m_xEdDataArea
.get());
116 m_xEdDataArea
->SetReferences(this, m_xDataFT
.get());
117 m_xRbDestArea
->SetReferences(this, m_xEdDestArea
.get());
118 m_xEdDestArea
->SetReferences(this, m_xDestFT
.get());
120 m_xEdDataArea
->SetGetFocusHdl( LINK( this, ScConsolidateDlg
, GetEditFocusHdl
) );
121 m_xEdDestArea
->SetGetFocusHdl( LINK( this, ScConsolidateDlg
, GetEditFocusHdl
) );
122 m_xLbDataArea
->connect_focus_in( LINK( this, ScConsolidateDlg
, GetFocusHdl
) );
123 m_xLbDestArea
->connect_focus_in( LINK( this, ScConsolidateDlg
, GetFocusHdl
) );
124 m_xEdDataArea
->SetModifyHdl( LINK( this, ScConsolidateDlg
, ModifyHdl
) );
125 m_xEdDestArea
->SetModifyHdl( LINK( this, ScConsolidateDlg
, ModifyHdl
) );
126 m_xLbConsAreas
->connect_selection_changed(LINK(this, ScConsolidateDlg
, SelectTVHdl
));
127 m_xLbDataArea
->connect_changed( LINK( this, ScConsolidateDlg
, SelectCBHdl
) );
128 m_xLbDestArea
->connect_changed( LINK( this, ScConsolidateDlg
, SelectCBHdl
) );
129 m_xBtnOk
->connect_clicked( LINK( this, ScConsolidateDlg
, OkHdl
) );
130 m_xBtnCancel
->connect_clicked( LINK( this, ScConsolidateDlg
, ClickHdl
) );
131 m_xBtnAdd
->connect_clicked( LINK( this, ScConsolidateDlg
, ClickHdl
) );
132 m_xBtnRemove
->connect_clicked( LINK( this, ScConsolidateDlg
, ClickHdl
) );
134 m_xBtnAdd
->set_sensitive(false);
135 m_xBtnRemove
->set_sensitive(false);
137 m_xBtnByRow
->set_active( theConsData
.bByRow
);
138 m_xBtnByCol
->set_active( theConsData
.bByCol
);
139 m_xBtnRefs
->set_active( theConsData
.bReferenceData
);
141 m_xLbFunc
->set_active( FuncToLbPos( theConsData
.eFunction
) );
143 m_xLbConsAreas
->set_selection_mode(SelectionMode::Multiple
);
144 m_xLbConsAreas
->set_size_request(m_xLbConsAreas
->get_approximate_digit_width() * 16,
145 m_xLbConsAreas
->get_height_rows(5));
147 // read consolidation areas
148 m_xLbConsAreas
->clear();
149 const formula::FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
150 for ( i
=0; i
<theConsData
.nDataAreaCount
; i
++ )
152 const ScArea
& rArea
= theConsData
.pDataAreas
[i
];
153 if ( rArea
.nTab
< rDoc
.GetTableCount() )
155 aStr
= ScRange( rArea
.nColStart
, rArea
.nRowStart
, rArea
.nTab
,
156 rArea
.nColEnd
, rArea
.nRowEnd
, rArea
.nTab
).Format( rDoc
,
157 ScRefFlags::RANGE_ABS_3D
, eConv
);
158 m_xLbConsAreas
->append_text(aStr
);
162 if ( theConsData
.nTab
< rDoc
.GetTableCount() )
164 aStr
= ScAddress( theConsData
.nCol
, theConsData
.nRow
, theConsData
.nTab
165 ).Format( ScRefFlags::ADDR_ABS_3D
, &rDoc
, eConv
);
166 m_xEdDestArea
->SetText( aStr
);
169 m_xEdDestArea
->SetText(OUString());
171 // Use the ScAreaData helper class to save those range names from the
172 // RangeNames and database ranges that appear in the ListBoxes.
174 ScRangeName
* pRangeNames
= rDoc
.GetRangeName();
175 ScDBCollection
* pDbNames
= rDoc
.GetDBCollection();
176 size_t nRangeCount
= pRangeNames
? pRangeNames
->size() : 0;
177 size_t nDbCount
= pDbNames
? pDbNames
->getNamedDBs().size() : 0;
179 nAreaDataCount
= nRangeCount
+nDbCount
;
182 if ( nAreaDataCount
> 0 )
184 pAreaData
.reset( new ScAreaData
[nAreaDataCount
] );
189 ScAreaNameIterator
aIter( rDoc
);
190 while ( aIter
.Next( aStrName
, aRange
) )
192 OUString
aStrArea(aRange
.Format(rDoc
, ScRefFlags::ADDR_ABS_3D
, eConv
));
193 pAreaData
[nAt
++].Set( aStrName
, aStrArea
);
198 ModifyHdl( *m_xEdDestArea
);
199 m_xLbDataArea
->set_active( 0 );
200 m_xEdDataArea
->SetText(OUString());
201 m_xEdDataArea
->GrabFocus();
203 //aFlSep.SetStyle( aFlSep.GetStyle() | WB_VERT );
205 //@BugID 54702 enable/disable only in base class
206 //SFX_APPWINDOW->set_sensitive(true);
209 void ScConsolidateDlg::FillAreaLists()
211 m_xLbDataArea
->clear();
212 m_xLbDestArea
->clear();
213 m_xLbDataArea
->append_text( aStrUndefined
);
214 m_xLbDestArea
->append_text( aStrUndefined
);
216 if ( pAreaData
&& (nAreaDataCount
> 0) )
219 (i
<nAreaDataCount
) && (!pAreaData
[i
].aStrName
.isEmpty());
222 m_xLbDataArea
->append_text(pAreaData
[i
].aStrName
);
223 m_xLbDestArea
->append_text(pAreaData
[i
].aStrName
);
228 // Handover of a range within a table that has been selected by the mouse.
229 // This range is then shown in the reference window as new selection.
231 void ScConsolidateDlg::SetReference( const ScRange
& rRef
, ScDocument
& rDocP
)
233 if ( !m_pRefInputEdit
)
236 if ( rRef
.aStart
!= rRef
.aEnd
)
237 RefInputStart( m_pRefInputEdit
);
240 ScRefFlags nFmt
= ScRefFlags::RANGE_ABS_3D
; //!!! nCurTab is still missing
241 const formula::FormulaGrammar::AddressConvention eConv
= rDocP
.GetAddressConvention();
243 if ( rRef
.aStart
.Tab() != rRef
.aEnd
.Tab() )
244 nFmt
|= ScRefFlags::TAB2_3D
;
246 if ( m_pRefInputEdit
== m_xEdDataArea
.get())
247 aStr
= rRef
.Format(rDocP
, nFmt
, eConv
);
248 else if ( m_pRefInputEdit
== m_xEdDestArea
.get() )
249 aStr
= rRef
.aStart
.Format(nFmt
, &rDocP
, eConv
);
251 m_pRefInputEdit
->SetRefString( aStr
);
252 ModifyHdl( *m_pRefInputEdit
);
255 void ScConsolidateDlg::Close()
257 DoClose( ScConsolidateDlgWrapper::GetChildWindowId() );
260 void ScConsolidateDlg::SetActive()
264 bDlgLostFocus
= false;
266 if ( m_pRefInputEdit
)
268 m_pRefInputEdit
->GrabFocus();
269 ModifyHdl( *m_pRefInputEdit
);
273 m_xDialog
->grab_focus();
278 void ScConsolidateDlg::Deactivate()
280 bDlgLostFocus
= true;
283 bool ScConsolidateDlg::VerifyEdit( formula::RefEdit
* pEd
)
285 if (pEd
!= m_xEdDataArea
.get() && pEd
!= m_xEdDestArea
.get())
288 SCTAB nTab
= rViewData
.GetTabNo();
289 bool bEditOk
= false;
290 OUString theCompleteStr
;
291 const formula::FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
293 if ( pEd
== m_xEdDataArea
.get() )
295 bEditOk
= ScRangeUtil::IsAbsArea( pEd
->GetText(), rDoc
,
296 nTab
, &theCompleteStr
, nullptr, nullptr, eConv
);
298 else if ( pEd
== m_xEdDestArea
.get() )
302 ScRangeUtil::CutPosString( pEd
->GetText(), aPosStr
);
303 bEditOk
= ScRangeUtil::IsAbsPos( aPosStr
, rDoc
,
304 nTab
, &theCompleteStr
, nullptr, eConv
);
308 pEd
->SetText( theCompleteStr
);
315 IMPL_LINK( ScConsolidateDlg
, GetEditFocusHdl
, formula::RefEdit
&, rControl
, void )
317 m_pRefInputEdit
= &rControl
;
320 IMPL_LINK( ScConsolidateDlg
, GetFocusHdl
, weld::Widget
&, rControl
, void )
322 if (&rControl
== m_xLbDataArea
.get())
323 m_pRefInputEdit
= m_xEdDataArea
.get();
324 else if (&rControl
== m_xLbDestArea
.get())
325 m_pRefInputEdit
= m_xEdDestArea
.get();
328 IMPL_LINK_NOARG(ScConsolidateDlg
, OkHdl
, weld::Button
&, void)
330 const sal_Int32 nDataAreaCount
= m_xLbConsAreas
->n_children();
332 if ( nDataAreaCount
> 0 )
334 ScRefAddress aDestAddress
;
335 SCTAB nTab
= rViewData
.GetTabNo();
336 OUString
aDestPosStr( m_xEdDestArea
->GetText() );
337 const formula::FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
339 if ( ScRangeUtil::IsAbsPos( aDestPosStr
, rDoc
, nTab
, nullptr, &aDestAddress
, eConv
) )
341 ScConsolidateParam
theOutParam( theConsData
);
342 std::unique_ptr
<ScArea
[]> pDataAreas(new ScArea
[nDataAreaCount
]);
344 for ( sal_Int32 i
=0; i
<nDataAreaCount
; ++i
)
346 ScRangeUtil::MakeArea(m_xLbConsAreas
->get_text(i
),
347 pDataAreas
[i
], rDoc
, nTab
, eConv
);
350 theOutParam
.nCol
= aDestAddress
.Col();
351 theOutParam
.nRow
= aDestAddress
.Row();
352 theOutParam
.nTab
= aDestAddress
.Tab();
353 theOutParam
.eFunction
= LbPosToFunc( m_xLbFunc
->get_active() );
354 theOutParam
.bByCol
= m_xBtnByCol
->get_active();
355 theOutParam
.bByRow
= m_xBtnByRow
->get_active();
356 theOutParam
.bReferenceData
= m_xBtnRefs
->get_active();
357 theOutParam
.SetAreas( std::move(pDataAreas
), nDataAreaCount
);
359 ScConsolidateItem
aOutItem( nWhichCons
, &theOutParam
);
361 SetDispatcherLock( false );
363 GetBindings().GetDispatcher()->ExecuteList(SID_CONSOLIDATE
,
364 SfxCallMode::SLOT
| SfxCallMode::RECORD
,
370 INFOBOX(m_xDialog
.get(), STR_INVALID_TABREF
);
371 m_xEdDestArea
->GrabFocus();
375 response(RET_CANCEL
); // no area defined -> Cancel
378 IMPL_LINK( ScConsolidateDlg
, ClickHdl
, weld::Button
&, rBtn
, void )
380 if ( &rBtn
== m_xBtnCancel
.get() )
381 response(RET_CANCEL
);
382 else if ( &rBtn
== m_xBtnAdd
.get() )
384 if ( !m_xEdDataArea
->GetText().isEmpty() )
386 OUString
aNewEntry( m_xEdDataArea
->GetText() );
387 std::unique_ptr
<ScArea
[]> ppAreas
;
388 sal_uInt16 nAreaCount
= 0;
389 const formula::FormulaGrammar::AddressConvention eConv
= rDoc
.GetAddressConvention();
391 if ( ScRangeUtil::IsAbsTabArea( aNewEntry
, &rDoc
, &ppAreas
, &nAreaCount
, true, eConv
) )
393 // IsAbsTabArea() creates an array of ScArea pointers,
394 // which have been created dynamically as well.
395 // These objects need to be deleted here.
397 for ( sal_uInt16 i
=0; i
<nAreaCount
; i
++ )
399 const ScArea
& rArea
= ppAreas
[i
];
400 OUString aNewArea
= ScRange( rArea
.nColStart
, rArea
.nRowStart
, rArea
.nTab
,
401 rArea
.nColEnd
, rArea
.nRowEnd
, rArea
.nTab
402 ).Format(rDoc
, ScRefFlags::RANGE_ABS_3D
, eConv
);
404 if (m_xLbConsAreas
->find_text(aNewArea
) == -1)
406 m_xLbConsAreas
->append_text( aNewArea
);
410 else if ( VerifyEdit( m_xEdDataArea
.get() ) )
412 OUString
aNewArea( m_xEdDataArea
->GetText() );
414 if (m_xLbConsAreas
->find_text(aNewArea
) == -1)
415 m_xLbConsAreas
->append_text(aNewArea
);
417 INFOBOX(m_xDialog
.get(), STR_AREA_ALREADY_INSERTED
);
421 INFOBOX(m_xDialog
.get(), STR_INVALID_TABREF
);
422 m_xEdDataArea
->GrabFocus();
426 else if ( &rBtn
== m_xBtnRemove
.get() )
428 std::vector
<int> aSelectedRows(m_xLbConsAreas
->get_selected_rows());
429 std::sort(aSelectedRows
.begin(), aSelectedRows
.end());
430 for (auto it
= aSelectedRows
.rbegin(); it
!= aSelectedRows
.rend(); ++it
)
431 m_xLbConsAreas
->remove(*it
);
432 m_xBtnRemove
->set_sensitive(false);
436 IMPL_LINK( ScConsolidateDlg
, SelectTVHdl
, weld::TreeView
&, rLb
, void )
438 if (rLb
.get_selected_index() != -1)
439 m_xBtnRemove
->set_sensitive(true);
441 m_xBtnRemove
->set_sensitive(false);
444 IMPL_LINK( ScConsolidateDlg
, SelectCBHdl
, weld::ComboBox
&, rLb
, void )
446 formula::RefEdit
* pEd
= (&rLb
== m_xLbDataArea
.get()) ? m_xEdDataArea
.get() : m_xEdDestArea
.get();
447 const sal_Int32 nSelPos
= rLb
.get_active();
450 && (nAreaDataCount
> 0)
451 && (pAreaData
!= nullptr) )
453 if ( o3tl::make_unsigned(nSelPos
) <= nAreaDataCount
)
455 OUString
aString( pAreaData
[nSelPos
-1].aStrArea
);
457 if ( &rLb
== m_xLbDestArea
.get() )
458 ScRangeUtil::CutPosString( aString
, aString
);
460 pEd
->SetText( aString
);
462 if ( pEd
== m_xEdDataArea
.get() )
463 m_xBtnAdd
->set_sensitive(true);
468 pEd
->SetText( OUString() );
469 if ( pEd
== m_xEdDataArea
.get() )
470 m_xBtnAdd
->set_sensitive(true);
474 IMPL_LINK( ScConsolidateDlg
, ModifyHdl
, formula::RefEdit
&, rEd
, void )
476 if ( &rEd
== m_xEdDataArea
.get() )
478 OUString
aAreaStr( rEd
.GetText() );
479 if ( !aAreaStr
.isEmpty() )
480 m_xBtnAdd
->set_sensitive(true);
482 m_xBtnAdd
->set_sensitive(false);
484 else if ( &rEd
== m_xEdDestArea
.get() )
486 m_xLbDestArea
->set_active(0);
491 // Resource of the ListBox and these two conversion methods are also in
492 // tpsubt and everywhere, where StarCalc functions are selectable.
494 ScSubTotalFunc
ScConsolidateDlg::LbPosToFunc( sal_Int32 nPos
)
498 case 2: return SUBTOTAL_FUNC_AVE
;
499 case 6: return SUBTOTAL_FUNC_CNT
;
500 case 1: return SUBTOTAL_FUNC_CNT2
;
501 case 3: return SUBTOTAL_FUNC_MAX
;
502 case 4: return SUBTOTAL_FUNC_MIN
;
503 case 5: return SUBTOTAL_FUNC_PROD
;
504 case 7: return SUBTOTAL_FUNC_STD
;
505 case 8: return SUBTOTAL_FUNC_STDP
;
506 case 9: return SUBTOTAL_FUNC_VAR
;
507 case 10: return SUBTOTAL_FUNC_VARP
;
510 return SUBTOTAL_FUNC_SUM
;
514 sal_Int32
ScConsolidateDlg::FuncToLbPos( ScSubTotalFunc eFunc
)
518 case SUBTOTAL_FUNC_AVE
: return 2;
519 case SUBTOTAL_FUNC_CNT
: return 6;
520 case SUBTOTAL_FUNC_CNT2
: return 1;
521 case SUBTOTAL_FUNC_MAX
: return 3;
522 case SUBTOTAL_FUNC_MIN
: return 4;
523 case SUBTOTAL_FUNC_PROD
: return 5;
524 case SUBTOTAL_FUNC_STD
: return 7;
525 case SUBTOTAL_FUNC_STDP
: return 8;
526 case SUBTOTAL_FUNC_VAR
: return 9;
527 case SUBTOTAL_FUNC_VARP
: return 10;
528 case SUBTOTAL_FUNC_NONE
:
529 case SUBTOTAL_FUNC_SUM
:
535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */