diff options
Diffstat (limited to 'sc/source/ui/dbgui/pvfundlg.cxx')
-rw-r--r-- | sc/source/ui/dbgui/pvfundlg.cxx | 973 |
1 files changed, 973 insertions, 0 deletions
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: */ |