calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / sc / source / ui / dbgui / pvfundlg.cxx
blob7f97e257679543d5e96994aeee44975aeefdab7a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 #undef SC_DLLIMPLEMENTATION
22 #include <pvfundlg.hxx>
24 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
25 #include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
26 #include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp>
27 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
28 #include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
30 #include <osl/diagnose.h>
32 #include <scresid.hxx>
33 #include <dpobject.hxx>
34 #include <dpsave.hxx>
35 #include <pvfundlg.hrc>
36 #include <globstr.hrc>
37 #include <dputil.hxx>
39 #include <vector>
41 using namespace ::com::sun::star::sheet;
43 using ::com::sun::star::uno::Sequence;
44 using ::std::vector;
46 namespace {
48 /** Appends all strings from the Sequence to the list box.
50 Empty strings are replaced by a localized "(empty)" entry and inserted at
51 the specified position.
53 @return true = The passed string list contains an empty string entry.
56 bool lclFillListBox(weld::ComboBox& rLBox, const Sequence< OUString >& rStrings)
58 bool bEmpty = false;
59 for (const OUString& str : rStrings)
61 if (!str.isEmpty())
62 rLBox.append_text(str);
63 else
65 rLBox.append_text(ScResId(STR_EMPTYDATA));
66 bEmpty = true;
69 return bEmpty;
72 bool lclFillListBox(weld::ComboBox& rLBox, const vector<ScDPLabelData::Member>& rMembers, int nEmptyPos)
74 bool bEmpty = false;
75 vector<ScDPLabelData::Member>::const_iterator itr = rMembers.begin(), itrEnd = rMembers.end();
76 for (; itr != itrEnd; ++itr)
78 OUString aName = itr->getDisplayName();
79 if (!aName.isEmpty())
80 rLBox.append_text(aName);
81 else
83 rLBox.insert_text(nEmptyPos, ScResId(STR_EMPTYDATA));
84 bEmpty = true;
87 return bEmpty;
90 bool lclFillListBox(weld::TreeView& rLBox, const vector<ScDPLabelData::Member>& rMembers)
92 bool bEmpty = false;
93 for (const auto& rMember : rMembers)
95 rLBox.append();
96 int pos = rLBox.n_children() - 1;
97 rLBox.set_toggle(pos, TRISTATE_FALSE);
98 OUString aName = rMember.getDisplayName();
99 if (!aName.isEmpty())
100 rLBox.set_text(pos, aName, 0);
101 else
103 rLBox.set_text(pos, ScResId(STR_EMPTYDATA), 0);
104 bEmpty = true;
107 return bEmpty;
110 /** This table represents the order of the strings in the resource string array. */
111 const PivotFunc spnFunctions[] =
113 PivotFunc::Sum,
114 PivotFunc::Count,
115 PivotFunc::Average,
116 PivotFunc::Median,
117 PivotFunc::Max,
118 PivotFunc::Min,
119 PivotFunc::Product,
120 PivotFunc::CountNum,
121 PivotFunc::StdDev,
122 PivotFunc::StdDevP,
123 PivotFunc::StdVar,
124 PivotFunc::StdVarP
127 const sal_uInt16 SC_BASEITEM_PREV_POS = 0;
128 const sal_uInt16 SC_BASEITEM_NEXT_POS = 1;
129 const sal_uInt16 SC_BASEITEM_USER_POS = 2;
131 const sal_uInt16 SC_SORTNAME_POS = 0;
132 const sal_uInt16 SC_SORTDATA_POS = 1;
134 const tools::Long SC_SHOW_DEFAULT = 10;
136 } // namespace
138 ScDPFunctionListBox::ScDPFunctionListBox(std::unique_ptr<weld::TreeView> xControl)
139 : m_xControl(std::move(xControl))
141 FillFunctionNames();
144 void ScDPFunctionListBox::SetSelection( PivotFunc nFuncMask )
146 if( (nFuncMask == PivotFunc::NONE) || (nFuncMask == PivotFunc::Auto) )
147 m_xControl->unselect_all();
148 else
150 for( sal_Int32 nEntry = 0, nCount = m_xControl->n_children(); nEntry < nCount; ++nEntry )
152 if (bool(nFuncMask & spnFunctions[ nEntry ]))
153 m_xControl->select(nEntry);
154 else
155 m_xControl->unselect(nEntry);
160 PivotFunc ScDPFunctionListBox::GetSelection() const
162 PivotFunc nFuncMask = PivotFunc::NONE;
163 std::vector<int> aRows = m_xControl->get_selected_rows();
164 for (int nSel : aRows)
165 nFuncMask |= spnFunctions[nSel];
166 return nFuncMask;
169 void ScDPFunctionListBox::FillFunctionNames()
171 OSL_ENSURE( !m_xControl->n_children(), "ScDPMultiFuncListBox::FillFunctionNames - do not add texts to resource" );
172 m_xControl->clear();
173 m_xControl->freeze();
174 for (size_t nIndex = 0; nIndex < SAL_N_ELEMENTS(SCSTR_DPFUNCLISTBOX); ++nIndex)
175 m_xControl->append_text(ScResId(SCSTR_DPFUNCLISTBOX[nIndex]));
176 m_xControl->thaw();
177 assert(m_xControl->n_children() == SAL_N_ELEMENTS(spnFunctions));
180 namespace
182 int FromDataPilotFieldReferenceType(int eMode)
184 switch (eMode)
186 case DataPilotFieldReferenceType::NONE:
187 return 0;
188 case DataPilotFieldReferenceType::ITEM_DIFFERENCE:
189 return 1;
190 case DataPilotFieldReferenceType::ITEM_PERCENTAGE:
191 return 2;
192 case DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
193 return 3;
194 case DataPilotFieldReferenceType::RUNNING_TOTAL:
195 return 4;
196 case DataPilotFieldReferenceType::ROW_PERCENTAGE:
197 return 5;
198 case DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
199 return 6;
200 case DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
201 return 7;
202 case DataPilotFieldReferenceType::INDEX:
203 return 8;
205 return -1;
208 int ToDataPilotFieldReferenceType(int nPos)
210 switch (nPos)
212 case 0:
213 return DataPilotFieldReferenceType::NONE;
214 case 1:
215 return DataPilotFieldReferenceType::ITEM_DIFFERENCE;
216 case 2:
217 return DataPilotFieldReferenceType::ITEM_PERCENTAGE;
218 case 3:
219 return DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE;
220 case 4:
221 return DataPilotFieldReferenceType::RUNNING_TOTAL;
222 case 5:
223 return DataPilotFieldReferenceType::ROW_PERCENTAGE;
224 case 6:
225 return DataPilotFieldReferenceType::COLUMN_PERCENTAGE;
226 case 7:
227 return DataPilotFieldReferenceType::TOTAL_PERCENTAGE;
228 case 8:
229 return DataPilotFieldReferenceType::INDEX;
231 return DataPilotFieldReferenceType::NONE;
236 ScDPFunctionDlg::ScDPFunctionDlg(
237 weld::Widget* pParent, const ScDPLabelDataVector& rLabelVec,
238 const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData)
239 : GenericDialogController(pParent, "modules/scalc/ui/datafielddialog.ui", "DataFieldDialog")
240 , mxLbFunc(new ScDPFunctionListBox(m_xBuilder->weld_tree_view("functions")))
241 , mxFtName(m_xBuilder->weld_label("name"))
242 , mxLbType(m_xBuilder->weld_combo_box("type"))
243 , mxFtBaseField(m_xBuilder->weld_label("basefieldft"))
244 , mxLbBaseField(m_xBuilder->weld_combo_box("basefield"))
245 , mxFtBaseItem(m_xBuilder->weld_label("baseitemft"))
246 , mxLbBaseItem(m_xBuilder->weld_combo_box("baseitem"))
247 , mxBtnOk(m_xBuilder->weld_button("ok"))
248 , mxBtnCancel(m_xBuilder->weld_button("cancel"))
249 , mrLabelVec(rLabelVec)
250 , mbEmptyItem(false)
252 mxLbFunc->set_size_request(-1, mxLbFunc->get_height_rows(8));
254 Init(rLabelData, rFuncData);
257 ScDPFunctionDlg::~ScDPFunctionDlg()
261 PivotFunc ScDPFunctionDlg::GetFuncMask() const
263 return mxLbFunc->GetSelection();
266 DataPilotFieldReference ScDPFunctionDlg::GetFieldRef() const
268 DataPilotFieldReference aRef;
270 aRef.ReferenceType = ToDataPilotFieldReferenceType(mxLbType->get_active());
271 aRef.ReferenceField = GetBaseFieldName(mxLbBaseField->get_active_text());
273 sal_Int32 nBaseItemPos = mxLbBaseItem->get_active();
274 switch( nBaseItemPos )
276 case SC_BASEITEM_PREV_POS:
277 aRef.ReferenceItemType = DataPilotFieldReferenceItemType::PREVIOUS;
278 break;
279 case SC_BASEITEM_NEXT_POS:
280 aRef.ReferenceItemType = DataPilotFieldReferenceItemType::NEXT;
281 break;
282 default:
284 aRef.ReferenceItemType = DataPilotFieldReferenceItemType::NAMED;
285 if( !mbEmptyItem || (nBaseItemPos > SC_BASEITEM_USER_POS) )
286 aRef.ReferenceItemName = GetBaseItemName(mxLbBaseItem->get_active_text());
290 return aRef;
293 void ScDPFunctionDlg::Init( const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData )
295 mxBtnOk->connect_clicked( LINK( this, ScDPFunctionDlg, ButtonClicked ) );
296 mxBtnCancel->connect_clicked( LINK( this, ScDPFunctionDlg, ButtonClicked ) );
298 // list box
299 PivotFunc nFuncMask = (rFuncData.mnFuncMask == PivotFunc::NONE) ? PivotFunc::Sum : rFuncData.mnFuncMask;
300 mxLbFunc->SetSelection( nFuncMask );
302 // field name
303 mxFtName->set_label(rLabelData.getDisplayName());
305 // handlers
306 mxLbFunc->connect_row_activated( LINK( this, ScDPFunctionDlg, DblClickHdl ) );
307 mxLbType->connect_changed( LINK( this, ScDPFunctionDlg, SelectHdl ) );
308 mxLbBaseField->connect_changed( LINK( this, ScDPFunctionDlg, SelectHdl ) );
310 // base field list box
311 OUString aSelectedEntry;
312 for( const auto& rxLabel : mrLabelVec )
314 mxLbBaseField->append_text(rxLabel->getDisplayName());
315 maBaseFieldNameMap.emplace(rxLabel->getDisplayName(), rxLabel->maName);
316 if (rxLabel->maName == rFuncData.maFieldRef.ReferenceField)
317 aSelectedEntry = rxLabel->getDisplayName();
320 // select field reference type
321 mxLbType->set_active(FromDataPilotFieldReferenceType(rFuncData.maFieldRef.ReferenceType));
322 SelectHdl( *mxLbType ); // enables base field/item list boxes
324 // select base field
325 mxLbBaseField->set_active_text(aSelectedEntry);
326 if (mxLbBaseField->get_active() == -1)
327 mxLbBaseField->set_active(0);
328 SelectHdl( *mxLbBaseField ); // fills base item list, selects base item
330 // select base item
331 switch( rFuncData.maFieldRef.ReferenceItemType )
333 case DataPilotFieldReferenceItemType::PREVIOUS:
334 mxLbBaseItem->set_active( SC_BASEITEM_PREV_POS );
335 break;
336 case DataPilotFieldReferenceItemType::NEXT:
337 mxLbBaseItem->set_active( SC_BASEITEM_NEXT_POS );
338 break;
339 default:
341 if( mbEmptyItem && rFuncData.maFieldRef.ReferenceItemName.isEmpty() )
343 // select special "(empty)" entry added before other items
344 mxLbBaseItem->set_active( SC_BASEITEM_USER_POS );
346 else
348 sal_Int32 nStartPos = mbEmptyItem ? (SC_BASEITEM_USER_POS + 1) : SC_BASEITEM_USER_POS;
349 sal_Int32 nPos = FindBaseItemPos( rFuncData.maFieldRef.ReferenceItemName, nStartPos );
350 if( nPos == -1)
351 nPos = (mxLbBaseItem->get_count() > SC_BASEITEM_USER_POS) ? SC_BASEITEM_USER_POS : SC_BASEITEM_PREV_POS;
352 mxLbBaseItem->set_active( nPos );
358 const OUString& ScDPFunctionDlg::GetBaseFieldName(const OUString& rLayoutName) const
360 NameMapType::const_iterator itr = maBaseFieldNameMap.find(rLayoutName);
361 return itr == maBaseFieldNameMap.end() ? rLayoutName : itr->second;
364 const OUString& ScDPFunctionDlg::GetBaseItemName(const OUString& rLayoutName) const
366 NameMapType::const_iterator itr = maBaseItemNameMap.find(rLayoutName);
367 return itr == maBaseItemNameMap.end() ? rLayoutName : itr->second;
370 sal_Int32 ScDPFunctionDlg::FindBaseItemPos( std::u16string_view rEntry, sal_Int32 nStartPos ) const
372 sal_Int32 nPos = nStartPos;
373 bool bFound = false;
374 while (nPos < mxLbBaseItem->get_count())
376 // translate the displayed field name back to its original field name.
377 const OUString& rInName = mxLbBaseItem->get_text(nPos);
378 const OUString& rName = GetBaseItemName(rInName);
379 if (rName == rEntry)
381 bFound = true;
382 break;
384 ++nPos;
386 return bFound ? nPos : -1;
389 IMPL_LINK( ScDPFunctionDlg, SelectHdl, weld::ComboBox&, rLBox, void )
391 if (&rLBox == mxLbType.get())
393 bool bEnableField, bEnableItem;
394 switch (ToDataPilotFieldReferenceType(mxLbType->get_active()))
396 case DataPilotFieldReferenceType::ITEM_DIFFERENCE:
397 case DataPilotFieldReferenceType::ITEM_PERCENTAGE:
398 case DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
399 bEnableField = bEnableItem = true;
400 break;
402 case DataPilotFieldReferenceType::RUNNING_TOTAL:
403 bEnableField = true;
404 bEnableItem = false;
405 break;
407 default:
408 bEnableField = bEnableItem = false;
411 bEnableField &= (mxLbBaseField->get_count() > 0);
412 mxFtBaseField->set_sensitive( bEnableField );
413 mxLbBaseField->set_sensitive( bEnableField );
415 bEnableItem &= bEnableField;
416 mxFtBaseItem->set_sensitive( bEnableItem );
417 mxLbBaseItem->set_sensitive( bEnableItem );
419 else if (&rLBox == mxLbBaseField.get())
421 // keep "previous" and "next" entries
422 while (mxLbBaseItem->get_count() > SC_BASEITEM_USER_POS)
423 mxLbBaseItem->remove(SC_BASEITEM_USER_POS);
425 // update item list for current base field
426 mbEmptyItem = false;
427 size_t nBasePos = mxLbBaseField->get_active();
428 if (nBasePos < mrLabelVec.size())
430 const vector<ScDPLabelData::Member>& rMembers = mrLabelVec[nBasePos]->maMembers;
431 mbEmptyItem = lclFillListBox(*mxLbBaseItem, rMembers, SC_BASEITEM_USER_POS);
432 // build cache for base names.
433 NameMapType aMap;
434 for (const auto& rMember : rMembers)
435 aMap.emplace(rMember.getDisplayName(), rMember.maName);
436 maBaseItemNameMap.swap(aMap);
439 // select base item
440 sal_uInt16 nItemPos = (mxLbBaseItem->get_count() > SC_BASEITEM_USER_POS) ? SC_BASEITEM_USER_POS : SC_BASEITEM_PREV_POS;
441 mxLbBaseItem->set_active( nItemPos );
445 IMPL_LINK(ScDPFunctionDlg, ButtonClicked, weld::Button&, rButton, void)
447 if (&rButton == mxBtnOk.get())
448 response(RET_OK);
449 else
450 response(RET_CANCEL);
453 IMPL_LINK_NOARG(ScDPFunctionDlg, DblClickHdl, weld::TreeView&, bool)
455 m_xDialog->response(RET_OK);
456 return true;
459 ScDPSubtotalDlg::ScDPSubtotalDlg(weld::Widget* pParent, ScDPObject& rDPObj,
460 const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData,
461 const ScDPNameVec& rDataFields, bool bEnableLayout)
462 : GenericDialogController(pParent, "modules/scalc/ui/pivotfielddialog.ui", "PivotFieldDialog")
463 , mrDPObj(rDPObj)
464 , mrDataFields(rDataFields)
465 , maLabelData(rLabelData)
466 , mbEnableLayout(bEnableLayout)
467 , mxRbNone(m_xBuilder->weld_radio_button("none"))
468 , mxRbAuto(m_xBuilder->weld_radio_button("auto"))
469 , mxRbUser(m_xBuilder->weld_radio_button("user"))
470 , mxLbFunc(new ScDPFunctionListBox(m_xBuilder->weld_tree_view("functions")))
471 , mxFtName(m_xBuilder->weld_label("name"))
472 , mxCbShowAll(m_xBuilder->weld_check_button("showall"))
473 , mxBtnOk(m_xBuilder->weld_button("ok"))
474 , mxBtnCancel(m_xBuilder->weld_button("cancel"))
475 , mxBtnOptions(m_xBuilder->weld_button("options"))
477 mxLbFunc->set_selection_mode(SelectionMode::Multiple);
478 mxLbFunc->set_size_request(-1, mxLbFunc->get_height_rows(8));
479 Init(rLabelData, rFuncData);
482 ScDPSubtotalDlg::~ScDPSubtotalDlg()
484 CloseSubdialog();
487 void ScDPSubtotalDlg::CloseSubdialog()
489 if (mxOptionsDlg && mxOptionsDlg->getDialog())
491 mxOptionsDlg->getDialog()->response(RET_CANCEL);
492 mxOptionsDlg = nullptr;
496 PivotFunc ScDPSubtotalDlg::GetFuncMask() const
498 PivotFunc nFuncMask = PivotFunc::NONE;
500 if (mxRbAuto->get_active())
501 nFuncMask = PivotFunc::Auto;
502 else if (mxRbUser->get_active())
503 nFuncMask = mxLbFunc->GetSelection();
505 return nFuncMask;
508 void ScDPSubtotalDlg::FillLabelData( ScDPLabelData& rLabelData ) const
510 rLabelData.mnFuncMask = GetFuncMask();
511 rLabelData.mnUsedHier = maLabelData.mnUsedHier;
512 rLabelData.mbShowAll = mxCbShowAll->get_active();
513 rLabelData.maMembers = maLabelData.maMembers;
514 rLabelData.maSortInfo = maLabelData.maSortInfo;
515 rLabelData.maLayoutInfo = maLabelData.maLayoutInfo;
516 rLabelData.maShowInfo = maLabelData.maShowInfo;
517 rLabelData.mbRepeatItemLabels = maLabelData.mbRepeatItemLabels;
520 void ScDPSubtotalDlg::Init( const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData )
522 mxBtnOk->connect_clicked( LINK( this, ScDPSubtotalDlg, ButtonClicked ) );
523 mxBtnCancel->connect_clicked( LINK( this, ScDPSubtotalDlg, ButtonClicked ) );
525 // field name
526 mxFtName->set_label(rLabelData.getDisplayName());
528 // radio buttons
529 mxRbNone->connect_toggled( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) );
530 mxRbAuto->connect_toggled( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) );
531 mxRbUser->connect_toggled( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) );
533 weld::RadioButton* pRBtn = nullptr;
534 switch( rFuncData.mnFuncMask )
536 case PivotFunc::NONE: pRBtn = mxRbNone.get(); break;
537 case PivotFunc::Auto: pRBtn = mxRbAuto.get(); break;
538 default: pRBtn = mxRbUser.get();
540 pRBtn->set_active(true);
541 RadioClickHdl(*pRBtn);
543 // list box
544 mxLbFunc->SetSelection( rFuncData.mnFuncMask );
545 mxLbFunc->connect_row_activated( LINK( this, ScDPSubtotalDlg, DblClickHdl ) );
547 // show all
548 mxCbShowAll->set_active( rLabelData.mbShowAll );
550 // options
551 mxBtnOptions->connect_clicked( LINK( this, ScDPSubtotalDlg, ClickHdl ) );
554 IMPL_LINK(ScDPSubtotalDlg, ButtonClicked, weld::Button&, rButton, void)
556 CloseSubdialog();
558 if (&rButton == mxBtnOk.get())
559 response(RET_OK);
560 else
561 response(RET_CANCEL);
564 IMPL_LINK(ScDPSubtotalDlg, RadioClickHdl, weld::Toggleable&, rBtn, void)
566 if (!rBtn.get_active())
567 return;
568 mxLbFunc->set_sensitive(mxRbUser->get_active());
571 IMPL_LINK_NOARG(ScDPSubtotalDlg, DblClickHdl, weld::TreeView&, bool)
573 m_xDialog->response(RET_OK);
574 return true;
577 IMPL_LINK(ScDPSubtotalDlg, ClickHdl, weld::Button&, rBtn, void)
579 if (&rBtn == mxBtnOptions.get())
581 mxOptionsDlg = std::make_shared<ScDPSubtotalOptDlg>(m_xDialog.get(), mrDPObj, maLabelData, mrDataFields, mbEnableLayout);
583 weld::DialogController::runAsync(mxOptionsDlg, [this](int nResult) {
584 if (nResult == RET_OK)
585 mxOptionsDlg->FillLabelData(maLabelData);
586 mxOptionsDlg = nullptr;
591 namespace
593 int FromDataPilotFieldLayoutMode(int eMode)
595 switch (eMode)
597 case DataPilotFieldLayoutMode::TABULAR_LAYOUT:
598 return 0;
599 case DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_TOP:
600 return 1;
601 case DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_BOTTOM:
602 return 2;
603 case DataPilotFieldLayoutMode::COMPACT_LAYOUT:
604 return 3;
606 return -1;
609 int ToDataPilotFieldLayoutMode(int nPos)
611 switch (nPos)
613 case 0:
614 return DataPilotFieldLayoutMode::TABULAR_LAYOUT;
615 case 1:
616 return DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_TOP;
617 case 2:
618 return DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_BOTTOM;
619 case 3:
620 return DataPilotFieldLayoutMode::COMPACT_LAYOUT;
622 return DataPilotFieldLayoutMode::TABULAR_LAYOUT;
625 int FromDataPilotFieldShowItemsMode(int eMode)
627 switch (eMode)
629 case DataPilotFieldShowItemsMode::FROM_TOP:
630 return 0;
631 case DataPilotFieldShowItemsMode::FROM_BOTTOM:
632 return 1;
634 return -1;
637 int ToDataPilotFieldShowItemsMode(int nPos)
639 switch (nPos)
641 case 0:
642 return DataPilotFieldShowItemsMode::FROM_TOP;
643 case 1:
644 return DataPilotFieldShowItemsMode::FROM_BOTTOM;
646 return DataPilotFieldShowItemsMode::FROM_TOP;
650 ScDPSubtotalOptDlg::ScDPSubtotalOptDlg(weld::Window* pParent, ScDPObject& rDPObj,
651 const ScDPLabelData& rLabelData, const ScDPNameVec& rDataFields,
652 bool bEnableLayout )
653 : GenericDialogController(pParent, "modules/scalc/ui/datafieldoptionsdialog.ui",
654 "DataFieldOptionsDialog")
655 , m_xLbSortBy(m_xBuilder->weld_combo_box("sortby"))
656 , m_xRbSortAsc(m_xBuilder->weld_radio_button("ascending"))
657 , m_xRbSortDesc(m_xBuilder->weld_radio_button("descending"))
658 , m_xRbSortMan(m_xBuilder->weld_radio_button("manual"))
659 , m_xLayoutFrame(m_xBuilder->weld_widget("layoutframe"))
660 , m_xLbLayout(m_xBuilder->weld_combo_box("layout"))
661 , m_xCbLayoutEmpty(m_xBuilder->weld_check_button("emptyline"))
662 , m_xCbRepeatItemLabels(m_xBuilder->weld_check_button("repeatitemlabels"))
663 , m_xCbShow(m_xBuilder->weld_check_button("show"))
664 , m_xNfShow(m_xBuilder->weld_spin_button("items"))
665 , m_xFtShow(m_xBuilder->weld_label("showft"))
666 , m_xFtShowFrom(m_xBuilder->weld_label("showfromft"))
667 , m_xLbShowFrom(m_xBuilder->weld_combo_box("from"))
668 , m_xFtShowUsing(m_xBuilder->weld_label("usingft"))
669 , m_xLbShowUsing(m_xBuilder->weld_combo_box("using"))
670 , m_xHideFrame(m_xBuilder->weld_widget("hideframe"))
671 , m_xLbHide(m_xBuilder->weld_tree_view("hideitems"))
672 , m_xFtHierarchy(m_xBuilder->weld_label("hierarchyft"))
673 , m_xLbHierarchy(m_xBuilder->weld_combo_box("hierarchy"))
674 , m_xBtnOk(m_xBuilder->weld_button("ok"))
675 , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
676 , mrDPObj(rDPObj)
677 , maLabelData(rLabelData)
679 m_xLbHide->enable_toggle_buttons(weld::ColumnToggleType::Check);
681 m_xLbSortBy->set_size_request(m_xLbSortBy->get_approximate_digit_width() * 18, -1);
682 m_xLbHide->set_size_request(-1, m_xLbHide->get_height_rows(5));
683 Init(rDataFields, bEnableLayout);
686 ScDPSubtotalOptDlg::~ScDPSubtotalOptDlg()
690 void ScDPSubtotalOptDlg::FillLabelData( ScDPLabelData& rLabelData ) const
692 // *** SORTING ***
694 if (m_xRbSortMan->get_active())
695 rLabelData.maSortInfo.Mode = DataPilotFieldSortMode::MANUAL;
696 else if (m_xLbSortBy->get_active() == SC_SORTNAME_POS)
697 rLabelData.maSortInfo.Mode = DataPilotFieldSortMode::NAME;
698 else
699 rLabelData.maSortInfo.Mode = DataPilotFieldSortMode::DATA;
701 ScDPName aFieldName = GetFieldName(m_xLbSortBy->get_active_text());
702 if (!aFieldName.maName.isEmpty())
704 rLabelData.maSortInfo.Field =
705 ScDPUtil::createDuplicateDimensionName(aFieldName.maName, aFieldName.mnDupCount);
708 if (rLabelData.maSortInfo.Mode != DataPilotFieldSortMode::MANUAL)
709 rLabelData.maSortInfo.IsAscending = m_xRbSortAsc->get_active();
711 // *** LAYOUT MODE ***
713 rLabelData.maLayoutInfo.LayoutMode = ToDataPilotFieldLayoutMode(m_xLbLayout->get_active());
714 rLabelData.maLayoutInfo.AddEmptyLines = m_xCbLayoutEmpty->get_active();
715 rLabelData.mbRepeatItemLabels = m_xCbRepeatItemLabels->get_active();
717 // *** AUTO SHOW ***
719 aFieldName = GetFieldName(m_xLbShowUsing->get_active_text());
720 if (!aFieldName.maName.isEmpty())
722 rLabelData.maShowInfo.IsEnabled = m_xCbShow->get_active();
723 rLabelData.maShowInfo.ShowItemsMode = ToDataPilotFieldShowItemsMode(m_xLbShowFrom->get_active());
724 rLabelData.maShowInfo.ItemCount = sal::static_int_cast<sal_Int32>( m_xNfShow->get_value() );
725 rLabelData.maShowInfo.DataField =
726 ScDPUtil::createDuplicateDimensionName(aFieldName.maName, aFieldName.mnDupCount);
729 // *** HIDDEN ITEMS ***
731 rLabelData.maMembers = maLabelData.maMembers;
732 int nVisCount = m_xLbHide->n_children();
733 for (int nPos = 0; nPos < nVisCount; ++nPos)
734 rLabelData.maMembers[nPos].mbVisible = m_xLbHide->get_toggle(nPos) == TRISTATE_FALSE;
736 // *** HIERARCHY ***
738 rLabelData.mnUsedHier = m_xLbHierarchy->get_active() != -1 ? m_xLbHierarchy->get_active() : 0;
741 void ScDPSubtotalOptDlg::Init( const ScDPNameVec& rDataFields, bool bEnableLayout )
743 m_xBtnOk->connect_clicked(LINK(this, ScDPSubtotalOptDlg, ButtonClicked));
744 m_xBtnCancel->connect_clicked(LINK(this, ScDPSubtotalOptDlg, ButtonClicked));
746 // *** SORTING ***
748 sal_Int32 nSortMode = maLabelData.maSortInfo.Mode;
750 // sort fields list box
751 m_xLbSortBy->append_text(maLabelData.getDisplayName());
753 for( const auto& rDataField : rDataFields )
755 // Cache names for later lookup.
756 maDataFieldNameMap.emplace(rDataField.maLayoutName, rDataField);
758 m_xLbSortBy->append_text(rDataField.maLayoutName);
759 m_xLbShowUsing->append_text(rDataField.maLayoutName); // for AutoShow
762 sal_Int32 nSortPos = SC_SORTNAME_POS;
763 if( nSortMode == DataPilotFieldSortMode::DATA )
765 nSortPos = FindListBoxEntry( *m_xLbSortBy, maLabelData.maSortInfo.Field, SC_SORTDATA_POS );
766 if( nSortPos == -1 )
768 nSortPos = SC_SORTNAME_POS;
769 nSortMode = DataPilotFieldSortMode::MANUAL;
772 m_xLbSortBy->set_active(nSortPos);
774 weld::RadioButton* pRBtn = nullptr;
775 switch( nSortMode )
777 case DataPilotFieldSortMode::NONE:
778 case DataPilotFieldSortMode::MANUAL:
779 pRBtn = m_xRbSortMan.get();
780 break;
781 default:
782 pRBtn = maLabelData.maSortInfo.IsAscending ? m_xRbSortAsc.get() : m_xRbSortDesc.get();
784 pRBtn->set_active(true);
786 // *** LAYOUT MODE ***
788 m_xLayoutFrame->set_sensitive(bEnableLayout);
790 m_xLbLayout->set_active(FromDataPilotFieldLayoutMode(maLabelData.maLayoutInfo.LayoutMode));
791 m_xCbLayoutEmpty->set_active( maLabelData.maLayoutInfo.AddEmptyLines );
792 m_xCbRepeatItemLabels->set_active( maLabelData.mbRepeatItemLabels );
794 // *** AUTO SHOW ***
796 m_xCbShow->set_active( maLabelData.maShowInfo.IsEnabled );
797 m_xCbShow->connect_toggled( LINK( this, ScDPSubtotalOptDlg, CheckHdl ) );
799 m_xLbShowFrom->set_active(FromDataPilotFieldShowItemsMode(maLabelData.maShowInfo.ShowItemsMode));
800 tools::Long nCount = static_cast< tools::Long >( maLabelData.maShowInfo.ItemCount );
801 if( nCount < 1 )
802 nCount = SC_SHOW_DEFAULT;
803 m_xNfShow->set_value( nCount );
805 // m_xLbShowUsing already filled above
806 m_xLbShowUsing->set_active_text(maLabelData.maShowInfo.DataField);
807 if (m_xLbShowUsing->get_active() == -1)
808 m_xLbShowUsing->set_active(0);
810 CheckHdl(*m_xCbShow); // enable/disable dependent controls
812 // *** HIDDEN ITEMS ***
814 InitHideListBox();
816 // *** HIERARCHY ***
818 if( maLabelData.maHiers.getLength() > 1 )
820 lclFillListBox(*m_xLbHierarchy, maLabelData.maHiers);
821 sal_Int32 nHier = maLabelData.mnUsedHier;
822 if( (nHier < 0) || (nHier >= maLabelData.maHiers.getLength()) ) nHier = 0;
823 m_xLbHierarchy->set_active( nHier );
824 m_xLbHierarchy->connect_changed( LINK( this, ScDPSubtotalOptDlg, SelectHdl ) );
826 else
828 m_xFtHierarchy->set_sensitive(false);
829 m_xLbHierarchy->set_sensitive(false);
833 void ScDPSubtotalOptDlg::InitHideListBox()
835 m_xLbHide->clear();
836 lclFillListBox(*m_xLbHide, maLabelData.maMembers);
837 size_t n = maLabelData.maMembers.size();
838 for (size_t i = 0; i < n; ++i)
839 m_xLbHide->set_toggle(i, maLabelData.maMembers[i].mbVisible ? TRISTATE_FALSE : TRISTATE_TRUE);
840 bool bEnable = m_xLbHide->n_children() > 0;
841 m_xHideFrame->set_sensitive(bEnable);
844 ScDPName ScDPSubtotalOptDlg::GetFieldName(const OUString& rLayoutName) const
846 NameMapType::const_iterator itr = maDataFieldNameMap.find(rLayoutName);
847 return itr == maDataFieldNameMap.end() ? ScDPName() : itr->second;
850 sal_Int32 ScDPSubtotalOptDlg::FindListBoxEntry(
851 const weld::ComboBox& rLBox, std::u16string_view rEntry, sal_Int32 nStartPos ) const
853 sal_Int32 nPos = nStartPos;
854 bool bFound = false;
855 while (nPos < rLBox.get_count())
857 // translate the displayed field name back to its original field name.
858 ScDPName aName = GetFieldName(rLBox.get_text(nPos));
859 OUString aUnoName = ScDPUtil::createDuplicateDimensionName(aName.maName, aName.mnDupCount);
860 if (aUnoName == rEntry)
862 bFound = true;
863 break;
865 ++nPos;
867 return bFound ? nPos : -1;
870 IMPL_LINK(ScDPSubtotalOptDlg, ButtonClicked, weld::Button&, rButton, void)
872 if (&rButton == m_xBtnOk.get())
873 response(RET_OK);
874 else
875 response(RET_CANCEL);
878 IMPL_LINK(ScDPSubtotalOptDlg, CheckHdl, weld::Toggleable&, rCBox, void)
880 if (&rCBox == m_xCbShow.get())
882 bool bEnable = m_xCbShow->get_active();
883 m_xNfShow->set_sensitive( bEnable );
884 m_xFtShow->set_sensitive( bEnable );
885 m_xFtShowFrom->set_sensitive( bEnable );
886 m_xLbShowFrom->set_sensitive( bEnable );
888 bool bEnableUsing = bEnable && (m_xLbShowUsing->get_count() > 0);
889 m_xFtShowUsing->set_sensitive(bEnableUsing);
890 m_xLbShowUsing->set_sensitive(bEnableUsing);
894 IMPL_LINK_NOARG(ScDPSubtotalOptDlg, SelectHdl, weld::ComboBox&, void)
896 mrDPObj.GetMembers(maLabelData.mnCol, m_xLbHierarchy->get_active(), maLabelData.maMembers);
897 InitHideListBox();
900 ScDPShowDetailDlg::ScDPShowDetailDlg(weld::Window* pParent, ScDPObject& rDPObj, css::sheet::DataPilotFieldOrientation nOrient)
901 : GenericDialogController(pParent, "modules/scalc/ui/showdetaildialog.ui", "ShowDetail")
902 , mrDPObj(rDPObj)
903 , mxLbDims(m_xBuilder->weld_tree_view("dimsTreeview"))
905 ScDPSaveData* pSaveData = rDPObj.GetSaveData();
906 tools::Long nDimCount = rDPObj.GetDimCount();
907 for (tools::Long nDim=0; nDim<nDimCount; nDim++)
909 bool bIsDataLayout;
910 sal_Int32 nDimFlags = 0;
911 OUString aName = rDPObj.GetDimName( nDim, bIsDataLayout, &nDimFlags );
912 if ( !bIsDataLayout && !rDPObj.IsDuplicated( nDim ) && ScDPObject::IsOrientationAllowed( nOrient, nDimFlags ) )
914 const ScDPSaveDimension* pDimension = pSaveData ? pSaveData->GetExistingDimensionByName(aName) : nullptr;
915 if ( !pDimension || (pDimension->GetOrientation() != nOrient) )
917 if (pDimension)
919 const std::optional<OUString> & pLayoutName = pDimension->GetLayoutName();
920 if (pLayoutName)
921 aName = *pLayoutName;
923 mxLbDims->append_text(aName);
924 maNameIndexMap.emplace(aName, nDim);
928 if (mxLbDims->n_children())
929 mxLbDims->select(0);
931 mxLbDims->connect_row_activated(LINK(this, ScDPShowDetailDlg, DblClickHdl));
934 ScDPShowDetailDlg::~ScDPShowDetailDlg()
938 short ScDPShowDetailDlg::run()
940 return mxLbDims->n_children() ? GenericDialogController::run() : static_cast<short>(RET_CANCEL);
943 OUString ScDPShowDetailDlg::GetDimensionName() const
945 // Look up the internal dimension name which may be different from the
946 // displayed field name.
947 OUString aSelectedName = mxLbDims->get_selected_text();
948 DimNameIndexMap::const_iterator itr = maNameIndexMap.find(aSelectedName);
949 if (itr == maNameIndexMap.end())
950 // This should never happen!
951 return aSelectedName;
953 tools::Long nDim = itr->second;
954 bool bIsDataLayout = false;
955 return mrDPObj.GetDimName(nDim, bIsDataLayout);
958 IMPL_LINK_NOARG(ScDPShowDetailDlg, DblClickHdl, weld::TreeView&, bool)
960 m_xDialog->response(RET_OK);
961 return true;
964 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */