/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this 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 #include #include #include #include #include #include #include #include #include #include #include #include #include // 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; iset_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 pFunctions; std::unique_ptr 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(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; iget_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 && iGetSheetLimits()); 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; nn_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 ScTpSubTotalGroup1::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet ) { return std::make_unique( pPage, pController, *rArgSet ); } std::unique_ptr ScTpSubTotalGroup2::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet ) { return std::make_unique( pPage, pController, *rArgSet ); } std::unique_ptr ScTpSubTotalGroup3::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet ) { return std::make_unique( 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 ScTpSubTotalOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet) { return std::make_unique(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; iappend_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: */