/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include "tabvwsh.hxx" #include "uiitems.hxx" #include "dbdata.hxx" #include "rangenam.hxx" #include "rangeutl.hxx" #include "reffact.hxx" #include "document.hxx" #include "scresid.hxx" #include "globstr.hrc" #include "sc.hrc" #include "consdlg.hxx" #include #define INFOBOX(id) ScopedVclPtr::Create(this, ScGlobal::GetRscString(id))->Execute() class ScAreaData { public: ScAreaData() : bIsDbArea(false) { } ~ScAreaData() {} void Set( const OUString& rName, const OUString& rArea, bool bDb ) { aStrName = rName; aStrArea = rArea; bIsDbArea = bDb; } OUString aStrName; OUString aStrArea; bool bIsDbArea; }; ScConsolidateDlg::ScConsolidateDlg( SfxBindings* pB, SfxChildWindow* pCW, vcl::Window* pParent, const SfxItemSet& rArgSet ) : ScAnyRefDlg ( pB, pCW, pParent, "ConsolidateDialog" , "modules/scalc/ui/consolidatedialog.ui" ), aStrUndefined ( ScResId( SCSTR_UNDEFINED ) ), theConsData ( static_cast( rArgSet.Get( rArgSet.GetPool()-> GetWhich( SID_CONSOLIDATE ) ) ).GetData() ), rViewData ( static_cast(SfxViewShell::Current())-> GetViewData() ), pDoc ( static_cast(SfxViewShell::Current())-> GetViewData().GetDocument() ), pRangeUtil ( new ScRangeUtil ), pAreaData ( nullptr ), nAreaDataCount ( 0 ), nWhichCons ( rArgSet.GetPool()->GetWhich( SID_CONSOLIDATE ) ), bDlgLostFocus ( false ) { get(pLbFunc,"func"); get(pLbConsAreas,"consareas"); get(pLbDataArea,"lbdataarea"); get(pEdDataArea,"eddataarea"); get(pRbDataArea,"rbdataarea"); pRefInputEdit = pEdDataArea; get(pLbDestArea,"lbdestarea"); get(pEdDestArea,"eddestarea"); get(pRbDestArea,"rbdestarea"); get(pExpander,"more"); get(pBtnByRow,"byrow"); get(pBtnByCol,"bycol"); get(pBtnRefs,"refs"); get(pBtnOk,"ok"); get(pBtnCancel,"cancel"); get(pBtnAdd,"add"); get(pBtnRemove,"delete"); Init(); } ScConsolidateDlg::~ScConsolidateDlg() { disposeOnce(); } void ScConsolidateDlg::dispose() { delete [] pAreaData; delete pRangeUtil; pLbFunc.clear(); pLbConsAreas.clear(); pLbDataArea.clear(); pEdDataArea.clear(); pRbDataArea.clear(); pLbDestArea.clear(); pEdDestArea.clear(); pRbDestArea.clear(); pExpander.clear(); pBtnByRow.clear(); pBtnByCol.clear(); pBtnRefs.clear(); pBtnOk.clear(); pBtnCancel.clear(); pBtnAdd.clear(); pBtnRemove.clear(); pRefInputEdit.clear(); ScAnyRefDlg::dispose(); } void ScConsolidateDlg::Init() { OSL_ENSURE( pDoc && pRangeUtil, "Error in Ctor" ); OUString aStr; sal_uInt16 i=0; pRbDataArea->SetReferences(this, pEdDataArea); pEdDataArea->SetReferences(this, get("ftdataarea")); pRbDestArea->SetReferences(this, pEdDestArea); pEdDestArea->SetReferences(this, get("ftdestarea")); pEdDataArea ->SetGetFocusHdl( LINK( this, ScConsolidateDlg, GetFocusHdl ) ); pEdDestArea ->SetGetFocusHdl( LINK( this, ScConsolidateDlg, GetFocusHdl ) ); pLbDataArea ->SetGetFocusHdl( LINK( this, ScConsolidateDlg, GetFocusHdl ) ); pLbDestArea ->SetGetFocusHdl( LINK( this, ScConsolidateDlg, GetFocusHdl ) ); pEdDataArea ->SetModifyHdl ( LINK( this, ScConsolidateDlg, ModifyHdl ) ); pEdDestArea ->SetModifyHdl ( LINK( this, ScConsolidateDlg, ModifyHdl ) ); pLbConsAreas->SetSelectHdl ( LINK( this, ScConsolidateDlg, SelectHdl ) ); pLbDataArea ->SetSelectHdl ( LINK( this, ScConsolidateDlg, SelectHdl ) ); pLbDestArea ->SetSelectHdl ( LINK( this, ScConsolidateDlg, SelectHdl ) ); pBtnOk ->SetClickHdl ( LINK( this, ScConsolidateDlg, OkHdl ) ); pBtnCancel ->SetClickHdl ( LINK( this, ScConsolidateDlg, ClickHdl ) ); pBtnAdd ->SetClickHdl ( LINK( this, ScConsolidateDlg, ClickHdl ) ); pBtnRemove ->SetClickHdl ( LINK( this, ScConsolidateDlg, ClickHdl ) ); pBtnAdd->Disable(); pBtnRemove->Disable(); pBtnByRow->Check( theConsData.bByRow ); pBtnByCol->Check( theConsData.bByCol ); pBtnRefs->Check( theConsData.bReferenceData ); pLbFunc->SelectEntryPos( FuncToLbPos( theConsData.eFunction ) ); // Hack: pLbConsAreas used to be MultiLB. We don't have VCL builder equivalent // of it yet. So enable selecting multiple items here pLbConsAreas->EnableMultiSelection( true ); pLbConsAreas->set_width_request(pLbConsAreas->approximate_char_width() * 16); pLbConsAreas->SetDropDownLineCount(5); // read consolidation areas pLbConsAreas->Clear(); const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); for ( i=0; iGetTableCount() ) { aStr = ScRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab ).Format( ScRefFlags::RANGE_ABS_3D, pDoc, eConv ); pLbConsAreas->InsertEntry( aStr ); } } if ( theConsData.nTab < pDoc->GetTableCount() ) { aStr = ScAddress( theConsData.nCol, theConsData.nRow, theConsData.nTab ).Format( ScRefFlags::ADDR_ABS_3D, pDoc, eConv ); pEdDestArea->SetText( aStr ); } else pEdDestArea->SetText(OUString()); // Use the ScAreaData helper class to save those range names from the // RangeNames and database ranges that appear in the ListBoxes. ScRangeName* pRangeNames = pDoc->GetRangeName(); ScDBCollection* pDbNames = pDoc->GetDBCollection(); size_t nRangeCount = pRangeNames ? pRangeNames->size() : 0; size_t nDbCount = pDbNames ? pDbNames->getNamedDBs().size() : 0; nAreaDataCount = nRangeCount+nDbCount; pAreaData = nullptr; if ( nAreaDataCount > 0 ) { pAreaData = new ScAreaData[nAreaDataCount]; OUString aStrName; sal_uInt16 nAt = 0; ScRange aRange; ScAreaNameIterator aIter( pDoc ); while ( aIter.Next( aStrName, aRange ) ) { OUString aStrArea(aRange.Format(ScRefFlags::ADDR_ABS_3D, pDoc, eConv)); pAreaData[nAt++].Set( aStrName, aStrArea, aIter.WasDBName() ); } } FillAreaLists(); ModifyHdl( *pEdDestArea ); pLbDataArea->SelectEntryPos( 0 ); pEdDataArea->SetText(OUString()); pEdDataArea->GrabFocus(); //aFlSep.SetStyle( aFlSep.GetStyle() | WB_VERT ); //@BugID 54702 enable/disable only in base class //SFX_APPWINDOW->Enable(); } void ScConsolidateDlg::FillAreaLists() { pLbDataArea->Clear(); pLbDestArea->Clear(); pLbDataArea->InsertEntry( aStrUndefined ); pLbDestArea->InsertEntry( aStrUndefined ); if ( pRangeUtil && pAreaData && (nAreaDataCount > 0) ) { for ( size_t i=0; (iInsertEntry( pAreaData[i].aStrName, i+1 ); // if ( !pAreaData[i].bIsDbArea ) pLbDestArea->InsertEntry( pAreaData[i].aStrName, i+1 ); } } } // Handover of a range within a table that has been selected by the mouse. // This range is then shown in the reference window as new selection. void ScConsolidateDlg::SetReference( const ScRange& rRef, ScDocument* pDocP ) { if ( pRefInputEdit ) { if ( rRef.aStart != rRef.aEnd ) RefInputStart( pRefInputEdit ); OUString aStr; ScRefFlags nFmt = ScRefFlags::RANGE_ABS_3D; //!!! nCurTab is still missing const formula::FormulaGrammar::AddressConvention eConv = pDocP->GetAddressConvention(); if ( rRef.aStart.Tab() != rRef.aEnd.Tab() ) nFmt |= ScRefFlags::TAB2_3D; if ( pRefInputEdit == pEdDataArea) aStr = rRef.Format(nFmt, pDocP, eConv); else if ( pRefInputEdit == pEdDestArea ) aStr = rRef.aStart.Format(nFmt, pDocP, eConv); pRefInputEdit->SetRefString( aStr ); ModifyHdl( *pRefInputEdit ); } } bool ScConsolidateDlg::Close() { return DoClose( ScConsolidateDlgWrapper::GetChildWindowId() ); } void ScConsolidateDlg::SetActive() { if ( bDlgLostFocus ) { bDlgLostFocus = false; if ( pRefInputEdit ) { pRefInputEdit->GrabFocus(); ModifyHdl( *pRefInputEdit ); } } else GrabFocus(); RefInputDone(); } void ScConsolidateDlg::Deactivate() { bDlgLostFocus = true; } bool ScConsolidateDlg::VerifyEdit( formula::RefEdit* pEd ) { if ( !pRangeUtil || !pDoc || ((pEd != pEdDataArea) && (pEd != pEdDestArea)) ) return false; SCTAB nTab = rViewData.GetTabNo(); bool bEditOk = false; OUString theCompleteStr; const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); if ( pEd == pEdDataArea ) { bEditOk = ScRangeUtil::IsAbsArea( pEd->GetText(), pDoc, nTab, &theCompleteStr, nullptr, nullptr, eConv ); } else if ( pEd == pEdDestArea ) { OUString aPosStr; ScRangeUtil::CutPosString( pEd->GetText(), aPosStr ); bEditOk = ScRangeUtil::IsAbsPos( aPosStr, pDoc, nTab, &theCompleteStr, nullptr, eConv ); } if ( bEditOk ) pEd->SetText( theCompleteStr ); return bEditOk; } // Handler: IMPL_LINK_TYPED( ScConsolidateDlg, GetFocusHdl, Control&, rControl, void ) { if ( &rControl ==static_cast(pEdDataArea) || &rControl ==static_cast(pEdDestArea)) { pRefInputEdit = static_cast(&rControl); } else if(&rControl ==static_cast(pLbDataArea) ) { pRefInputEdit = pEdDataArea; } else if(&rControl ==static_cast(pLbDestArea) ) { pRefInputEdit = pEdDestArea; } } IMPL_LINK_NOARG_TYPED(ScConsolidateDlg, OkHdl, Button*, void) { const sal_Int32 nDataAreaCount = pLbConsAreas->GetEntryCount(); if ( nDataAreaCount > 0 ) { ScRefAddress aDestAddress; SCTAB nTab = rViewData.GetTabNo(); OUString aDestPosStr( pEdDestArea->GetText() ); const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); if ( ScRangeUtil::IsAbsPos( aDestPosStr, pDoc, nTab, nullptr, &aDestAddress, eConv ) ) { ScConsolidateParam theOutParam( theConsData ); ScArea** ppDataAreas = new ScArea*[nDataAreaCount]; ScArea* pArea; for ( sal_Int32 i=0; iGetEntry( i ), *pArea, pDoc, nTab, eConv ); ppDataAreas[i] = pArea; } theOutParam.nCol = aDestAddress.Col(); theOutParam.nRow = aDestAddress.Row(); theOutParam.nTab = aDestAddress.Tab(); theOutParam.eFunction = LbPosToFunc( pLbFunc->GetSelectEntryPos() ); theOutParam.bByCol = pBtnByCol->IsChecked(); theOutParam.bByRow = pBtnByRow->IsChecked(); theOutParam.bReferenceData = pBtnRefs->IsChecked(); theOutParam.SetAreas( ppDataAreas, nDataAreaCount ); for ( sal_Int32 i=0; iExecute( SID_CONSOLIDATE, SfxCallMode::SLOT | SfxCallMode::RECORD, &aOutItem, 0L, 0L ); Close(); } else { INFOBOX( STR_INVALID_TABREF ); pEdDestArea->GrabFocus(); } } else Close(); // no area defined -> Cancel } IMPL_LINK_TYPED( ScConsolidateDlg, ClickHdl, Button*, pBtn, void ) { if ( pBtn == pBtnCancel ) Close(); else if ( pBtn == pBtnAdd ) { if ( !pEdDataArea->GetText().isEmpty() ) { OUString aNewEntry( pEdDataArea->GetText() ); ScArea** ppAreas = nullptr; sal_uInt16 nAreaCount = 0; const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); if ( ScRangeUtil::IsAbsTabArea( aNewEntry, pDoc, &ppAreas, &nAreaCount, true, eConv ) ) { // IsAbsTabArea() creates an array of ScArea pointers, // which have been created dynamically as well. // These objects need to be deleted here. for ( sal_uInt16 i=0; iGetEntryPos( aNewArea ) == LISTBOX_ENTRY_NOTFOUND ) { pLbConsAreas->InsertEntry( aNewArea ); } delete ppAreas[i]; } } delete [] ppAreas; } else if ( VerifyEdit( pEdDataArea ) ) { OUString aNewArea( pEdDataArea->GetText() ); if ( pLbConsAreas->GetEntryPos( aNewArea ) == LISTBOX_ENTRY_NOTFOUND ) pLbConsAreas->InsertEntry( aNewArea ); else INFOBOX( STR_AREA_ALREADY_INSERTED ); } else { INFOBOX( STR_INVALID_TABREF ); pEdDataArea->GrabFocus(); } } } else if ( pBtn == pBtnRemove ) { while ( pLbConsAreas->GetSelectEntryCount() ) pLbConsAreas->RemoveEntry( pLbConsAreas->GetSelectEntryPos() ); pBtnRemove->Disable(); } } IMPL_LINK_TYPED( ScConsolidateDlg, SelectHdl, ListBox&, rLb, void ) { if ( &rLb == pLbConsAreas ) { if ( pLbConsAreas->GetSelectEntryCount() > 0 ) pBtnRemove->Enable(); else pBtnRemove->Disable(); } else if ( (&rLb == pLbDataArea) || (&rLb == pLbDestArea) ) { Edit* pEd = (&rLb == pLbDataArea) ? pEdDataArea : pEdDestArea; const sal_Int32 nSelPos = rLb.GetSelectEntryPos(); if ( pRangeUtil && (nSelPos > 0) && (nAreaDataCount > 0) && (pAreaData != nullptr) ) { if ( static_cast(nSelPos) <= nAreaDataCount ) { OUString aString( pAreaData[nSelPos-1].aStrArea ); if ( &rLb == pLbDestArea ) ScRangeUtil::CutPosString( aString, aString ); pEd->SetText( aString ); if ( pEd == pEdDataArea ) pBtnAdd->Enable(); } } else { pEd->SetText( EMPTY_OUSTRING ); if ( pEd == pEdDataArea ) pBtnAdd->Enable(); } } } IMPL_LINK_TYPED( ScConsolidateDlg, ModifyHdl, Edit&, rEd, void ) { if ( &rEd == pEdDataArea ) { OUString aAreaStr( rEd.GetText() ); if ( !aAreaStr.isEmpty() ) { pBtnAdd->Enable(); } else pBtnAdd->Disable(); } else if ( &rEd == pEdDestArea ) { pLbDestArea->SelectEntryPos(0); } } // TODO: generalize! // Resource of the ListBox and these two conversion methods are also in // tpsubt and everywhere, where StarCalc functions are selectable. ScSubTotalFunc ScConsolidateDlg::LbPosToFunc( sal_Int32 nPos ) { switch ( nPos ) { case 2: return SUBTOTAL_FUNC_AVE; case 6: return SUBTOTAL_FUNC_CNT; case 1: return SUBTOTAL_FUNC_CNT2; case 3: return SUBTOTAL_FUNC_MAX; case 4: return SUBTOTAL_FUNC_MIN; case 5: return SUBTOTAL_FUNC_PROD; case 7: return SUBTOTAL_FUNC_STD; case 8: return SUBTOTAL_FUNC_STDP; case 9: return SUBTOTAL_FUNC_VAR; case 10: return SUBTOTAL_FUNC_VARP; case 0: default: return SUBTOTAL_FUNC_SUM; } } sal_Int32 ScConsolidateDlg::FuncToLbPos( ScSubTotalFunc eFunc ) { switch ( eFunc ) { case SUBTOTAL_FUNC_AVE: return 2; case SUBTOTAL_FUNC_CNT: return 6; case SUBTOTAL_FUNC_CNT2: return 1; case SUBTOTAL_FUNC_MAX: return 3; case SUBTOTAL_FUNC_MIN: return 4; case SUBTOTAL_FUNC_PROD: return 5; case SUBTOTAL_FUNC_STD: return 7; case SUBTOTAL_FUNC_STDP: return 8; case SUBTOTAL_FUNC_VAR: return 9; case SUBTOTAL_FUNC_VARP: return 10; case SUBTOTAL_FUNC_NONE: case SUBTOTAL_FUNC_SUM: default: return 0; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */