diff options
Diffstat (limited to 'sc/source/ui/dbgui/pvlaydlg.cxx')
-rw-r--r-- | sc/source/ui/dbgui/pvlaydlg.cxx | 1928 |
1 files changed, 1928 insertions, 0 deletions
diff --git a/sc/source/ui/dbgui/pvlaydlg.cxx b/sc/source/ui/dbgui/pvlaydlg.cxx new file mode 100644 index 000000000000..f280af43f7e0 --- /dev/null +++ b/sc/source/ui/dbgui/pvlaydlg.cxx @@ -0,0 +1,1928 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +//---------------------------------------------------------------------------- + +#include "pvlaydlg.hxx" +#include "dbdocfun.hxx" +#include "dpuiglobal.hxx" + +#include <sfx2/dispatch.hxx> +#include <vcl/msgbox.hxx> + +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> +#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp> + +#include "uiitems.hxx" +#include "rangeutl.hxx" +#include "document.hxx" +#include "viewdata.hxx" +#include "tabvwsh.hxx" +#include "reffact.hxx" +#include "scresid.hxx" +#include "globstr.hrc" +#include "pivot.hrc" +#include "dpobject.hxx" +#include "dpsave.hxx" +#include "dpshttab.hxx" +#include "scmod.hxx" + +#include "sc.hrc" +#include "scabstdlg.hxx" + +using namespace com::sun::star; +using ::rtl::OUString; +using ::std::vector; +using ::std::for_each; + +//---------------------------------------------------------------------------- + +#define FSTR(index) aFuncNameArr[index-1] +#define STD_FORMAT SCA_VALID | SCA_TAB_3D \ + | SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE + +//============================================================================ + +namespace { + +PointerStyle lclGetPointerForField( ScDPFieldType eType ) +{ + switch( eType ) + { + case TYPE_PAGE: return POINTER_PIVOT_FIELD; + case TYPE_COL: return POINTER_PIVOT_COL; + case TYPE_ROW: return POINTER_PIVOT_ROW; + case TYPE_DATA: return POINTER_PIVOT_FIELD; + case TYPE_SELECT: return POINTER_PIVOT_FIELD; + } + return POINTER_ARROW; +} + +} // namespace + +//============================================================================ + +//---------------------------------------------------------------------------- + +ScDPLayoutDlg::ScDPLayoutDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent, + const ScDPObject& rDPObject, bool bNewOutput ) + : ScAnyRefDlg ( pB, pCW, pParent, RID_SCDLG_PIVOT_LAYOUT ), + aFlLayout ( this, ScResId( FL_LAYOUT ) ), + aFtPage ( this, ScResId( FT_PAGE ) ), + aWndPage ( this, ScResId( WND_PAGE ), &aFtPage ), + aFtCol ( this, ScResId( FT_COL ) ), + aWndCol ( this, ScResId( WND_COL ), &aFtCol ), + aFtRow ( this, ScResId( FT_ROW ) ), + aWndRow ( this, ScResId( WND_ROW ), &aFtRow ), + aFtData ( this, ScResId( FT_DATA ) ), + aWndData ( this, ScResId( WND_DATA ), &aFtData ), + aWndSelect ( this, ScResId( WND_SELECT ), NULL ), + aFtInfo ( this, ScResId( FT_INFO ) ), + + aFlAreas ( this, ScResId( FL_OUTPUT ) ), + + aFtInArea ( this, ScResId( FT_INAREA) ), + aEdInPos ( this, ScResId( ED_INAREA) ), + aRbInPos ( this, ScResId( RB_INAREA ), &aEdInPos, this ), + + aLbOutPos ( this, ScResId( LB_OUTAREA ) ), + aFtOutArea ( this, ScResId( FT_OUTAREA ) ), + aEdOutPos ( this, this, ScResId( ED_OUTAREA ) ), + aRbOutPos ( this, ScResId( RB_OUTAREA ), &aEdOutPos, this ), + aBtnIgnEmptyRows( this, ScResId( BTN_IGNEMPTYROWS ) ), + aBtnDetectCat ( this, ScResId( BTN_DETECTCAT ) ), + aBtnTotalCol ( this, ScResId( BTN_TOTALCOL ) ), + aBtnTotalRow ( this, ScResId( BTN_TOTALROW ) ), + aBtnFilter ( this, ScResId( BTN_FILTER ) ), + aBtnDrillDown ( this, ScResId( BTN_DRILLDOWN ) ), + + aBtnOk ( this, ScResId( BTN_OK ) ), + aBtnCancel ( this, ScResId( BTN_CANCEL ) ), + aBtnHelp ( this, ScResId( BTN_HELP ) ), + aBtnRemove ( this, ScResId( BTN_REMOVE ) ), + aBtnOptions ( this, ScResId( BTN_OPTIONS ) ), + aBtnMore ( this, ScResId( BTN_MORE ) ), + + aStrUndefined ( ScResId( SCSTR_UNDEFINED ) ), + aStrNewTable ( ScResId( SCSTR_NEWTABLE ) ), + + bIsDrag ( false ), + + pEditActive ( NULL ), + + eLastActiveType ( TYPE_SELECT ), + nOffset ( 0 ), + // + xDlgDPObject ( new ScDPObject( rDPObject ) ), + pViewData ( ((ScTabViewShell*)SfxViewShell::Current())-> + GetViewData() ), + pDoc ( ((ScTabViewShell*)SfxViewShell::Current())-> + GetViewData()->GetDocument() ), + bRefInputMode (false) +{ + xDlgDPObject->SetAlive( true ); // needed to get structure information + xDlgDPObject->FillOldParam( thePivotData ); + xDlgDPObject->FillLabelData( thePivotData ); + + Init(bNewOutput); + FreeResource(); +} + +//---------------------------------------------------------------------------- + +ScDPLayoutDlg::~ScDPLayoutDlg() +{ + sal_uInt16 nEntries = aLbOutPos.GetEntryCount(); + sal_uInt16 i; + + for ( i=2; i<nEntries; i++ ) + delete (String*)aLbOutPos.GetEntryData( i ); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::Init(bool bNewOutput) +{ + DBG_ASSERT( pViewData && pDoc, + "Ctor-Initialisierung fehlgeschlagen!" ); + + aBtnRemove.SetClickHdl( LINK( this, ScDPLayoutDlg, ClickHdl ) ); + aBtnOptions.SetClickHdl( LINK( this, ScDPLayoutDlg, ClickHdl ) ); + + aFuncNameArr.reserve( PIVOT_MAXFUNC ); + for ( sal_uInt16 i = 0; i < PIVOT_MAXFUNC; ++i ) + aFuncNameArr.push_back( String( ScResId( i + 1 ) ) ); + + aBtnMore.AddWindow( &aFlAreas ); + aBtnMore.AddWindow( &aFtInArea ); + aBtnMore.AddWindow( &aEdInPos ); + aBtnMore.AddWindow( &aRbInPos ); + aBtnMore.AddWindow( &aFtOutArea ); + aBtnMore.AddWindow( &aLbOutPos ); + aBtnMore.AddWindow( &aEdOutPos ); + aBtnMore.AddWindow( &aRbOutPos ); + aBtnMore.AddWindow( &aBtnIgnEmptyRows ); + aBtnMore.AddWindow( &aBtnDetectCat ); + aBtnMore.AddWindow( &aBtnTotalCol ); + aBtnMore.AddWindow( &aBtnTotalRow ); + aBtnMore.AddWindow( &aBtnFilter ); + aBtnMore.AddWindow( &aBtnDrillDown ); + aBtnMore.SetClickHdl( LINK( this, ScDPLayoutDlg, MoreClickHdl ) ); + + CalcWndSizes(); + + ScRange inRange; + String inString; + if (xDlgDPObject->GetSheetDesc()) + { + aEdInPos.Enable(); + aRbInPos.Enable(); + const ScSheetSourceDesc* p = xDlgDPObject->GetSheetDesc(); + OUString aRangeName = p->GetRangeName(); + if (aRangeName.getLength()) + aEdInPos.SetText(aRangeName); + else + { + aOldRange = p->GetSourceRange(); + aOldRange.Format( inString, SCR_ABS_3D, pDoc, pDoc->GetAddressConvention() ); + aEdInPos.SetText(inString); + } + } + else + { + /* Data is not reachable, so could be a remote database */ + aEdInPos.Disable(); + aRbInPos.Disable(); + } + + InitFields(); + + aLbOutPos .SetSelectHdl( LINK( this, ScDPLayoutDlg, SelAreaHdl ) ); + aEdOutPos .SetModifyHdl( LINK( this, ScDPLayoutDlg, EdModifyHdl ) ); + aEdInPos .SetModifyHdl( LINK( this, ScDPLayoutDlg, EdInModifyHdl ) ); + aBtnOk .SetClickHdl ( LINK( this, ScDPLayoutDlg, OkHdl ) ); + aBtnCancel.SetClickHdl ( LINK( this, ScDPLayoutDlg, CancelHdl ) ); + Link aLink = LINK( this, ScDPLayoutDlg, GetFocusHdl ); + if ( aEdInPos.IsEnabled() ) + // Once disabled it will never get enabled, so no need to handle focus. + aEdInPos.SetGetFocusHdl( aLink ); + aEdOutPos.SetGetFocusHdl( aLink ); + + if ( pViewData && pDoc ) + { + /* + * Aus den RangeNames des Dokumentes werden nun die + * in einem Zeiger-Array gemerkt, bei denen es sich + * um sinnvolle Bereiche handelt + */ + + aLbOutPos.Clear(); + aLbOutPos.InsertEntry( aStrUndefined, 0 ); + aLbOutPos.InsertEntry( aStrNewTable, 1 ); + + ScAreaNameIterator aIter( pDoc ); + String aName; + ScRange aRange; + String aRefStr; + while ( aIter.Next( aName, aRange ) ) + { + if ( !aIter.WasDBName() ) // hier keine DB-Bereiche ! + { + sal_uInt16 nInsert = aLbOutPos.InsertEntry( aName ); + + aRange.aStart.Format( aRefStr, SCA_ABS_3D, pDoc, pDoc->GetAddressConvention() ); + aLbOutPos.SetEntryData( nInsert, new String( aRefStr ) ); + } + } + } + + if (bNewOutput) + { + // Output to a new sheet by default for a brand-new output. + aLbOutPos.SelectEntryPos(1); + aEdOutPos.Disable(); + aRbOutPos.Disable(); + } + else + { + // Modifying an existing dp output. + + if ( thePivotData.nTab != MAXTAB+1 ) + { + String aStr; + ScAddress( thePivotData.nCol, + thePivotData.nRow, + thePivotData.nTab ).Format( aStr, STD_FORMAT, pDoc, pDoc->GetAddressConvention() ); + aEdOutPos.SetText( aStr ); + EdModifyHdl(0); + } + else + { + aLbOutPos.SelectEntryPos( aLbOutPos.GetEntryCount()-1 ); + SelAreaHdl(NULL); + } + } + + aBtnIgnEmptyRows.Check( thePivotData.bIgnoreEmptyRows ); + aBtnDetectCat .Check( thePivotData.bDetectCategories ); + aBtnTotalCol .Check( thePivotData.bMakeTotalCol ); + aBtnTotalRow .Check( thePivotData.bMakeTotalRow ); + + if( const ScDPSaveData* pSaveData = xDlgDPObject->GetSaveData() ) + { + aBtnFilter.Check( pSaveData->GetFilterButton() ); + aBtnDrillDown.Check( pSaveData->GetDrillDown() ); + } + else + { + aBtnFilter.Check(); + aBtnDrillDown.Check(); + } + + aWndPage.SetHelpId( HID_SC_DPLAY_PAGE ); + aWndCol.SetHelpId( HID_SC_DPLAY_COLUMN ); + aWndRow.SetHelpId( HID_SC_DPLAY_ROW ); + aWndData.SetHelpId( HID_SC_DPLAY_DATA ); + aWndSelect.SetHelpId( HID_SC_DPLAY_SELECT ); + + InitFocus(); +} + +//---------------------------------------------------------------------------- + +sal_Bool ScDPLayoutDlg::Close() +{ + return DoClose( ScPivotLayoutWrapper::GetChildWindowId() ); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::StateChanged( StateChangedType nStateChange ) +{ + ScAnyRefDlg::StateChanged( nStateChange ); + + if ( nStateChange == STATE_CHANGE_INITSHOW ) + { + // Hiding the FixedTexts and clearing the tab stop style bits + // has to be done after assigning the mnemonics, but Paint is too late, + // because the test tool may send key events to the dialog when it isn't visible. + // Mnemonics are assigned in the Dialog::StateChanged for STATE_CHANGE_INITSHOW, + // so this can be done immediately afterwards. + + aWndPage.UseMnemonic(); + aWndCol.UseMnemonic(); + aWndRow.UseMnemonic(); + aWndData.UseMnemonic(); + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::InitWndSelect( const vector<ScDPLabelDataRef>& rLabels ) +{ + size_t nLabelCount = rLabels.size(); + if (nLabelCount > MAX_LABELS) + nLabelCount = MAX_LABELS; + + aLabelDataArr.clear(); + aLabelDataArr.reserve( nLabelCount ); + for ( size_t i=0; i < nLabelCount; i++ ) + { + aLabelDataArr.push_back(*rLabels[i]); + aWndSelect.AddField(aLabelDataArr[i].getDisplayName(), i); + ScDPFuncDataRef p(new ScDPFuncData(aLabelDataArr[i].mnCol, aLabelDataArr[i].mnFuncMask)); + aSelectArr.push_back(p); + } + aWndSelect.ResetScrollBar(); + aWndSelect.Paint(Rectangle()); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::InitFieldWindow( const vector<PivotField>& rFields, ScDPFieldType eType ) +{ + ScDPFuncDataVec* pInitArr = GetFieldDataArray(eType); + ScDPFieldControlBase* pInitWnd = GetFieldWindow(eType); + + if (!pInitArr || !pInitWnd) + return; + + vector<PivotField>::const_iterator itr = rFields.begin(), itrEnd = rFields.end(); + for (; itr != itrEnd; ++itr) + { + SCCOL nCol = itr->nCol; + sal_uInt16 nMask = itr->nFuncMask; + if (nCol == PIVOT_DATA_FIELD) + continue; + + size_t nFieldIndex = pInitArr->size(); + ScDPFuncDataRef p(new ScDPFuncData(nCol, nMask, itr->maFieldRef)); + pInitArr->push_back(p); + + if (eType == TYPE_DATA) + { + // data field - we need to concatenate function name with the field name. + ScDPLabelData* pData = GetLabelData(nCol); + DBG_ASSERT( pData, "ScDPLabelData not found" ); + if (pData) + { + OUString aStr = pData->maLayoutName; + if (!aStr.getLength()) + { + sal_uInt16 nInitMask = pInitArr->back()->mnFuncMask; + aStr = GetFuncString(nInitMask, pData->mbIsValue); + aStr += pData->maName; + } + + pInitWnd->AddField(aStr, nFieldIndex); + pData->mnFuncMask = nMask; + } + } + else + pInitWnd->AddField(GetLabelString(nCol), nFieldIndex); + } + pInitWnd->ResetScrollBar(); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::InitFocus() +{ + if( aWndSelect.IsEmpty() ) + { + aBtnOk.GrabFocus(); + NotifyFieldFocus( TYPE_SELECT, false ); + } + else + aWndSelect.GrabFocus(); +} + +void ScDPLayoutDlg::InitFields() +{ + InitWndSelect(thePivotData.maLabelArray); + InitFieldWindow(thePivotData.maPageFields, TYPE_PAGE); + InitFieldWindow(thePivotData.maColFields, TYPE_COL); + InitFieldWindow(thePivotData.maRowFields, TYPE_ROW); + InitFieldWindow(thePivotData.maDataFields, TYPE_DATA); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::AddField( size_t nFromIndex, ScDPFieldType eToType, const Point& rAtPos ) +{ + ScDPFuncData fData( *(aSelectArr[nFromIndex]) ); + size_t nAt = 0; + ScDPFieldControlBase* toWnd = GetFieldWindow(eToType); + ScDPFieldControlBase* rmWnd1 = NULL; + ScDPFieldControlBase* rmWnd2 = NULL; + GetOtherFieldWindows(eToType, rmWnd1, rmWnd2); + + ScDPFuncDataVec* toArr = GetFieldDataArray(eToType); + ScDPFuncDataVec* rmArr1 = NULL; + ScDPFuncDataVec* rmArr2 = NULL; + GetOtherDataArrays(eToType, rmArr1, rmArr2); + + bool bDataArr = eToType == TYPE_DATA; + + bool bAllowed = IsOrientationAllowed( fData.mnCol, eToType ); + if ( bAllowed && (!Contains( toArr, fData.mnCol, nAt )) ) + { + // ggF. in anderem Fenster entfernen + if ( rmArr1 ) + { + if ( Contains( rmArr1, fData.mnCol, nAt ) ) + { + rmWnd1->DelField( nAt ); + Remove( rmArr1, nAt ); + } + } + if ( rmArr2 ) + { + if ( Contains( rmArr2, fData.mnCol, nAt ) ) + { + rmWnd2->DelField( nAt ); + Remove( rmArr2, nAt ); + } + } + + ScDPLabelData& rData = aLabelDataArr[nFromIndex+nOffset]; + size_t nAddedAt = 0; + + if ( !bDataArr ) + { + if ( toWnd->AddField( rData.getDisplayName(), + DlgPos2WndPos( rAtPos, *toWnd ), + nAddedAt ) ) + { + Insert( toArr, fData, nAddedAt ); + toWnd->GrabFocus(); + } + } + else + { + ScDPLabelData* p = GetLabelData(fData.mnCol); + OUString aStr = p->maLayoutName; + sal_uInt16 nMask = fData.mnFuncMask; + if (!aStr.getLength()) + { + aStr = GetFuncString(nMask); + aStr += p->maName; + } + + if ( toWnd->AddField( aStr, + DlgPos2WndPos( rAtPos, *toWnd ), + nAddedAt ) ) + { + fData.mnFuncMask = nMask; + Insert( toArr, fData, nAddedAt ); + toWnd->GrabFocus(); + } + } + + } +} + +void ScDPLayoutDlg::AppendField(size_t nFromIndex, ScDPFieldType eToType) +{ + ScDPFuncData aFuncData = *aSelectArr[nFromIndex]; + + size_t nAt = 0; + ScDPFieldControlBase* toWnd = GetFieldWindow(eToType); + ScDPFieldControlBase* rmWnd1 = NULL; + ScDPFieldControlBase* rmWnd2 = NULL; + GetOtherFieldWindows(eToType, rmWnd1, rmWnd2); + + ScDPFuncDataVec* toArr = GetFieldDataArray(eToType); + ScDPFuncDataVec* rmArr1 = NULL; + ScDPFuncDataVec* rmArr2 = NULL; + GetOtherDataArrays(eToType, rmArr1, rmArr2); + + bool bDataArr = eToType == TYPE_DATA; + + if ( (!Contains( toArr, aFuncData.mnCol, nAt )) ) + { + // ggF. in anderem Fenster entfernen + if ( rmArr1 ) + { + if ( Contains( rmArr1, aFuncData.mnCol, nAt ) ) + { + rmWnd1->DelField( nAt ); + Remove( rmArr1, nAt ); + } + } + if ( rmArr2 ) + { + if ( Contains( rmArr2, aFuncData.mnCol, nAt ) ) + { + rmWnd2->DelField( nAt ); + Remove( rmArr2, nAt ); + } + } + + ScDPLabelData& rData = aLabelDataArr[nFromIndex+nOffset]; + size_t nAddedAt = 0; + + if ( !bDataArr ) + { + if ( toWnd->AppendField(rData.getDisplayName(), nAddedAt) ) + { + Insert( toArr, aFuncData, nAddedAt ); + toWnd->GrabFocus(); + } + } + else + { + ScDPLabelData* p = GetLabelData(aFuncData.mnCol); + OUString aStr = p->maLayoutName; + sal_uInt16 nMask = aFuncData.mnFuncMask; + if (!aStr.getLength()) + { + aStr = GetFuncString(nMask); + aStr += p->maName; + } + + if ( toWnd->AppendField(aStr, nAddedAt) ) + { + aFuncData.mnFuncMask = nMask; + Insert( toArr, aFuncData, nAddedAt ); + toWnd->GrabFocus(); + } + } + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::MoveField( ScDPFieldType eFromType, size_t nFromIndex, ScDPFieldType eToType, const Point& rAtPos ) +{ + if ( eFromType == TYPE_SELECT ) + AddField( nFromIndex, eToType, rAtPos ); + else if ( eFromType != eToType ) + { + ScDPFieldControlBase* fromWnd = GetFieldWindow(eFromType); + ScDPFieldControlBase* toWnd = GetFieldWindow(eToType); + + ScDPFieldControlBase* rmWnd1 = NULL; + ScDPFieldControlBase* rmWnd2 = NULL; + GetOtherFieldWindows(eToType, rmWnd1, rmWnd2); + + ScDPFuncDataVec* fromArr = GetFieldDataArray(eFromType); + ScDPFuncDataVec* toArr = GetFieldDataArray(eToType); + + ScDPFuncDataVec* rmArr1 = NULL; + ScDPFuncDataVec* rmArr2 = NULL; + GetOtherDataArrays(eToType, rmArr1, rmArr2); + + bool bDataArr = eToType == TYPE_DATA; + + if ( fromArr && toArr && fromWnd && toWnd ) + { + ScDPFuncData fData( *((*fromArr)[nFromIndex]) ); + bool bAllowed = IsOrientationAllowed( fData.mnCol, eToType ); + + size_t nAt = 0; + if ( bAllowed && Contains( fromArr, fData.mnCol, nAt ) ) + { + fromWnd->DelField( nAt ); + Remove( fromArr, nAt ); + + if (!Contains( toArr, fData.mnCol, nAt )) + { + size_t nAddedAt = 0; + if ( !bDataArr ) + { + // ggF. in anderem Fenster entfernen + if ( rmArr1 ) + { + if ( Contains( rmArr1, fData.mnCol, nAt ) ) + { + rmWnd1->DelField( nAt ); + Remove( rmArr1, nAt ); + } + } + if ( rmArr2 ) + { + if ( Contains( rmArr2, fData.mnCol, nAt ) ) + { + rmWnd2->DelField( nAt ); + Remove( rmArr2, nAt ); + } + } + + if ( toWnd->AddField( GetLabelString( fData.mnCol ), + DlgPos2WndPos( rAtPos, *toWnd ), + nAddedAt ) ) + { + Insert( toArr, fData, nAddedAt ); + toWnd->GrabFocus(); + } + } + else + { + ScDPLabelData* p = GetLabelData(fData.mnCol); + OUString aStr = p->maLayoutName; + sal_uInt16 nMask = fData.mnFuncMask; + if (!aStr.getLength()) + { + aStr = GetFuncString(nMask); + aStr += p->maName; + } + + if ( toWnd->AddField( aStr, + DlgPos2WndPos( rAtPos, *toWnd ), + nAddedAt ) ) + { + fData.mnFuncMask = nMask; + Insert( toArr, fData, nAddedAt ); + toWnd->GrabFocus(); + } + } + } + } + } + } + else // -> eFromType == eToType + { + ScDPFieldControlBase* theWnd = GetFieldWindow(eFromType); + ScDPFuncDataVec* theArr = GetFieldDataArray(eFromType); + size_t nAt = 0; + Point aToPos; + sal_Bool bDataArr = eFromType == TYPE_DATA; + + ScDPFuncData fData( *((*theArr)[nFromIndex]) ); + + if ( Contains( theArr, fData.mnCol, nAt ) ) + { + size_t nToIndex = 0; + aToPos = DlgPos2WndPos( rAtPos, *theWnd ); + theWnd->GetExistingIndex( aToPos, nToIndex ); + + if ( nToIndex != nAt ) + { + size_t nAddedAt = 0; + + theWnd->DelField( nAt ); + Remove( theArr, nAt ); + + if ( !bDataArr ) + { + if ( theWnd->AddField( GetLabelString( fData.mnCol ), + aToPos, + nAddedAt ) ) + { + Insert( theArr, fData, nAddedAt ); + } + } + else + { + ScDPLabelData* p = GetLabelData(fData.mnCol); + OUString aStr = p->maLayoutName; + sal_uInt16 nMask = fData.mnFuncMask; + if (!aStr.getLength()) + { + aStr = GetFuncString(nMask); + aStr += p->maName; + } + + if ( theWnd->AddField( aStr, + DlgPos2WndPos( rAtPos, *theWnd ), + nAddedAt ) ) + { + fData.mnFuncMask = nMask; + Insert( theArr, fData, nAddedAt ); + } + } + } + } + } +} + +void ScDPLayoutDlg::MoveFieldToEnd( ScDPFieldType eFromType, size_t nFromIndex, ScDPFieldType eToType ) +{ + if ( eFromType == TYPE_SELECT ) + AppendField( nFromIndex, eToType ); + else if ( eFromType != eToType ) + { + ScDPFieldControlBase* fromWnd = GetFieldWindow(eFromType); + ScDPFieldControlBase* toWnd = GetFieldWindow(eToType); + + ScDPFieldControlBase* rmWnd1 = NULL; + ScDPFieldControlBase* rmWnd2 = NULL; + GetOtherFieldWindows(eToType, rmWnd1, rmWnd2); + + ScDPFuncDataVec* fromArr = GetFieldDataArray(eFromType); + ScDPFuncDataVec* toArr = GetFieldDataArray(eToType); + + ScDPFuncDataVec* rmArr1 = NULL; + ScDPFuncDataVec* rmArr2 = NULL; + GetOtherDataArrays(eToType, rmArr1, rmArr2); + + bool bDataArr = eToType == TYPE_DATA; + + if ( fromArr && toArr && fromWnd && toWnd ) + { + ScDPFuncData fData( *((*fromArr)[nFromIndex]) ); + + size_t nAt = 0; + if ( Contains( fromArr, fData.mnCol, nAt ) ) + { + fromWnd->DelField( nAt ); + Remove( fromArr, nAt ); + + if (!Contains( toArr, fData.mnCol, nAt )) + { + size_t nAddedAt = 0; + if ( !bDataArr ) + { + // ggF. in anderem Fenster entfernen + if ( rmArr1 ) + { + if ( Contains( rmArr1, fData.mnCol, nAt ) ) + { + rmWnd1->DelField( nAt ); + Remove( rmArr1, nAt ); + } + } + if ( rmArr2 ) + { + if ( Contains( rmArr2, fData.mnCol, nAt ) ) + { + rmWnd2->DelField( nAt ); + Remove( rmArr2, nAt ); + } + } + + if ( toWnd->AppendField( GetLabelString( fData.mnCol ), nAddedAt ) ) + { + Insert( toArr, fData, nAddedAt ); + toWnd->GrabFocus(); + } + } + else + { + ScDPLabelData* p = GetLabelData(fData.mnCol); + OUString aStr = p->maLayoutName; + sal_uInt16 nMask = fData.mnFuncMask; + if (!aStr.getLength()) + { + aStr = GetFuncString(nMask); + aStr += p->maName; + } + + if ( toWnd->AppendField(aStr, nAddedAt) ) + { + fData.mnFuncMask = nMask; + Insert( toArr, fData, nAddedAt ); + toWnd->GrabFocus(); + } + } + } + } + } + } + else // -> eFromType == eToType + { + ScDPFieldControlBase* theWnd = GetFieldWindow(eFromType); + ScDPFuncDataVec* theArr = GetFieldDataArray(eFromType); + size_t nAt = 0; + Point aToPos; + sal_Bool bDataArr = eFromType == TYPE_DATA; + + ScDPFuncData fData( *((*theArr)[nFromIndex]) ); + + if ( Contains( theArr, fData.mnCol, nAt ) ) + { + size_t nToIndex = 0; + theWnd->GetExistingIndex( aToPos, nToIndex ); + + if ( nToIndex != nAt ) + { + size_t nAddedAt = 0; + + theWnd->DelField( nAt ); + Remove( theArr, nAt ); + + if ( !bDataArr ) + { + if ( theWnd->AppendField(GetLabelString( fData.mnCol ), nAddedAt) ) + { + Insert( theArr, fData, nAddedAt ); + } + } + else + { + ScDPLabelData* p = GetLabelData(fData.mnCol); + OUString aStr = p->maLayoutName; + sal_uInt16 nMask = fData.mnFuncMask; + if (!aStr.getLength()) + { + aStr = GetFuncString(nMask); + aStr += p->maName; + } + + if ( theWnd->AppendField(aStr, nAddedAt) ) + { + fData.mnFuncMask = nMask; + Insert( theArr, fData, nAddedAt ); + } + } + } + } + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::RemoveField( ScDPFieldType eFromType, size_t nIndex ) +{ + ScDPFuncDataVec* pArr = GetFieldDataArray(eFromType); + + if( pArr ) + { + ScDPFieldControlBase* pWnd = GetFieldWindow( eFromType ); + if (pWnd) + { + pWnd->DelField( nIndex ); + Remove( pArr, nIndex ); + if( pWnd->IsEmpty() ) InitFocus(); + } + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::NotifyMouseButtonUp( const Point& rAt ) +{ + if ( bIsDrag ) + { + bIsDrag = false; + + ScDPFieldType eDnDToType = TYPE_SELECT; + Point aPos = ScreenToOutputPixel( rAt ); + bool bDel = false; + + if ( aRectPage.IsInside( aPos ) ) + { + eDnDToType = TYPE_PAGE; + } + else if ( aRectCol.IsInside( aPos ) ) + { + eDnDToType = TYPE_COL; + } + else if ( aRectRow.IsInside( aPos ) ) + { + eDnDToType = TYPE_ROW; + } + else if ( aRectData.IsInside( aPos ) ) + { + eDnDToType = TYPE_DATA; + } + else if ( aRectSelect.IsInside( aPos ) ) + { + eDnDToType = TYPE_SELECT; + } + else + bDel = true; + + if (bDel) + { + // We don't remove any buttons from the select field. + if (eDnDFromType != TYPE_SELECT) + RemoveField( eDnDFromType, nDnDFromIndex ); + } + else + MoveField( eDnDFromType, nDnDFromIndex, eDnDToType, aPos ); + } +} + +//---------------------------------------------------------------------------- + +PointerStyle ScDPLayoutDlg::NotifyMouseMove( const Point& rAt ) +{ + PointerStyle ePtr = POINTER_ARROW; + + if ( bIsDrag ) + { + Point aPos = ScreenToOutputPixel( rAt ); + ScDPFieldType eCheckTarget = TYPE_SELECT; + + if ( aRectPage.IsInside( aPos ) ) + eCheckTarget = TYPE_PAGE; + else if ( aRectCol.IsInside( aPos ) ) + eCheckTarget = TYPE_COL; + else if ( aRectRow.IsInside( aPos ) ) + eCheckTarget = TYPE_ROW; + else if ( aRectData.IsInside( aPos ) ) + eCheckTarget = TYPE_DATA; + else if ( eDnDFromType != TYPE_SELECT ) + ePtr = POINTER_PIVOT_DELETE; + else if ( aRectSelect.IsInside( aPos ) ) + ePtr = lclGetPointerForField( TYPE_SELECT ); + else + ePtr = POINTER_NOTALLOWED; + + if ( eCheckTarget != TYPE_SELECT ) + { + // check if the target orientation is allowed for this field + ScDPFuncDataVec* fromArr = NULL; + switch ( eDnDFromType ) + { + case TYPE_PAGE: fromArr = &aPageArr; break; + case TYPE_COL: fromArr = &aColArr; break; + case TYPE_ROW: fromArr = &aRowArr; break; + case TYPE_DATA: fromArr = &aDataArr; break; + case TYPE_SELECT: fromArr = &aSelectArr; break; + } + ScDPFuncData fData( *((*fromArr)[nDnDFromIndex]) ); + if (IsOrientationAllowed( fData.mnCol, eCheckTarget )) + ePtr = lclGetPointerForField( eCheckTarget ); + else + ePtr = POINTER_NOTALLOWED; + } + } + + return ePtr; +} + +//---------------------------------------------------------------------------- + +PointerStyle ScDPLayoutDlg::NotifyMouseButtonDown( ScDPFieldType eType, size_t nFieldIndex ) +{ + bIsDrag = true; + eDnDFromType = eType; + nDnDFromIndex = nFieldIndex; + return lclGetPointerForField( eType ); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::NotifyDoubleClick( ScDPFieldType eType, size_t nFieldIndex ) +{ + ScDPFuncDataVec* pArr = GetFieldDataArray(eType); + + if ( pArr ) + { + if ( nFieldIndex >= pArr->size() ) + { + OSL_FAIL("invalid selection"); + return; + } + + size_t nArrPos = 0; + if( ScDPLabelData* pData = GetLabelData( (*pArr)[nFieldIndex]->mnCol, &nArrPos ) ) + { + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!"); + + switch ( eType ) + { + case TYPE_PAGE: + case TYPE_COL: + case TYPE_ROW: + { + // list of names of all data fields + vector<ScDPName> aDataFieldNames; + for( ScDPFuncDataVec::const_iterator aIt = aDataArr.begin(), aEnd = aDataArr.end(); + (aIt != aEnd) && aIt->get(); ++aIt ) + { + ScDPLabelData* pDFData = GetLabelData((*aIt)->mnCol); + if (!pDFData) + continue; + + if (!pDFData->maName.getLength()) + continue; + + OUString aLayoutName = pDFData->maLayoutName; + if (!aLayoutName.getLength()) + { + // No layout name exists. Use the stock name. + sal_uInt16 nMask = (*aIt)->mnFuncMask; + OUString aFuncStr = GetFuncString(nMask); + aLayoutName = aFuncStr + pDFData->maName; + } + aDataFieldNames.push_back(ScDPName(pDFData->maName, aLayoutName)); + } + + bool bLayout = (eType == TYPE_ROW) && + ((aDataFieldNames.size() > 1) || ((nFieldIndex + 1 < pArr->size()) && (*pArr)[nFieldIndex+1].get())); + + AbstractScDPSubtotalDlg* pDlg = pFact->CreateScDPSubtotalDlg( + this, RID_SCDLG_PIVOTSUBT, + *xDlgDPObject, *pData, *(*pArr)[nFieldIndex], aDataFieldNames, bLayout ); + + if ( pDlg->Execute() == RET_OK ) + { + pDlg->FillLabelData( *pData ); + (*pArr)[nFieldIndex]->mnFuncMask = pData->mnFuncMask; + } + delete pDlg; + } + break; + + case TYPE_DATA: + { + AbstractScDPFunctionDlg* pDlg = pFact->CreateScDPFunctionDlg( + this, RID_SCDLG_DPDATAFIELD, + aLabelDataArr, *pData, *(*pArr)[nFieldIndex] ); + + if ( pDlg->Execute() == RET_OK ) + { + (*pArr)[nFieldIndex]->mnFuncMask = pData->mnFuncMask = pDlg->GetFuncMask(); + (*pArr)[nFieldIndex]->maFieldRef = pDlg->GetFieldRef(); + + ScDPLabelData* p = GetLabelData(aDataArr[nFieldIndex]->mnCol); + OUString aStr = p->maLayoutName; + if (!aStr.getLength()) + { + // Layout name is not available. Use default name. + aStr = GetFuncString (aDataArr[nFieldIndex]->mnFuncMask); + aStr += p->maName; + } + aWndData.SetFieldText( aStr, nFieldIndex ); + } + delete pDlg; + } + break; + + default: + { + // added to avoid warnings + } + } + } + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::NotifyFieldFocus( ScDPFieldType eType, sal_Bool bGotFocus ) +{ + /* Enable Remove/Options buttons on GetFocus in field window. + Enable them also, if dialog is deactivated (click into document). + The !IsActive() condition handles the case that a LoseFocus event of a + field window would follow the Deactivate event of this dialog. */ + sal_Bool bEnable = (bGotFocus || !IsActive()) && (eType != TYPE_SELECT); + + // The TestTool may set the focus into an empty field. + // Then the Remove/Options buttons must be disabled. + ScDPFieldControlBase* pWnd = GetFieldWindow(eType); + if ( bEnable && bGotFocus && pWnd && pWnd->IsEmpty() ) + bEnable = false; + + aBtnRemove.Enable( bEnable ); + aBtnOptions.Enable( bEnable ); + if( bGotFocus ) + eLastActiveType = eType; +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::NotifyMoveFieldToEnd( ScDPFieldType eToType ) +{ + ScDPFieldControlBase* pWnd = GetFieldWindow(eLastActiveType); + ScDPFieldControlBase* pToWnd = GetFieldWindow(eToType); + if (pWnd && pToWnd && (eToType != TYPE_SELECT) && !pWnd->IsEmpty()) + { + MoveFieldToEnd(eLastActiveType, pWnd->GetSelectedField(), eToType); + + if( pWnd->IsEmpty() ) + NotifyFieldFocus( eToType, true ); + else + pWnd->GrabFocus(); + if( eLastActiveType == TYPE_SELECT ) + aWndSelect.SelectNext(); + } + else + InitFocus(); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::NotifyRemoveField( ScDPFieldType eType, size_t nFieldIndex ) +{ + if( eType != TYPE_SELECT ) + RemoveField( eType, nFieldIndex ); +} + +Size ScDPLayoutDlg::GetStdFieldBtnSize() const +{ + // This size is static but is platform dependent. The field button size + // is calculated relative to the size of the OK button. + double w = static_cast<double>(aBtnOk.GetSizePixel().Width()) * 0.70; + return Size(static_cast<long>(w), FIELD_BTN_HEIGHT); +} + +void ScDPLayoutDlg::Deactivate() +{ + /* If the dialog has been deactivated (click into document), the LoseFocus + event from field window disables Remove/Options buttons. Re-enable them here by + simulating a GetFocus event. Event order of LoseFocus and Deactivate is not important. + The last event will enable the buttons in both cases (see NotifyFieldFocus). */ + NotifyFieldFocus( eLastActiveType, true ); +} + +//---------------------------------------------------------------------------- + +sal_Bool ScDPLayoutDlg::Contains( ScDPFuncDataVec* pArr, SCsCOL nCol, size_t& nAt ) +{ + if (!pArr || pArr->empty()) + return false; + + ScDPFuncDataVec::const_iterator itr, itrBeg = pArr->begin(), itrEnd = pArr->end(); + for (itr = itrBeg; itr != itrEnd; ++itr) + { + if ((*itr)->mnCol == nCol) + { + // found! + nAt = ::std::distance(itrBeg, itr); + return true; + } + } + return false; +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::Remove( ScDPFuncDataVec* pArr, size_t nAt ) +{ + if ( !pArr || (nAt>=pArr->size()) ) + return; + + pArr->erase( pArr->begin() + nAt ); +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::Insert( ScDPFuncDataVec* pArr, const ScDPFuncData& rFData, size_t nAt ) +{ + if (!pArr) + return; + + ScDPFuncDataRef p (new ScDPFuncData(rFData)); + if (nAt >= pArr->size()) + pArr->push_back(p); + else + pArr->insert(pArr->begin() + nAt, p); +} + +//---------------------------------------------------------------------------- + +ScDPLabelData* ScDPLayoutDlg::GetLabelData( SCsCOL nCol, size_t* pnPos ) +{ + ScDPLabelData* pData = 0; + for( ScDPLabelDataVec::iterator aIt = aLabelDataArr.begin(), aEnd = aLabelDataArr.end(); !pData && (aIt != aEnd); ++aIt ) + { + if( aIt->mnCol == nCol ) + { + pData = &*aIt; + if( pnPos ) *pnPos = aIt - aLabelDataArr.begin(); + } + } + return pData; +} + +//---------------------------------------------------------------------------- + +String ScDPLayoutDlg::GetLabelString( SCsCOL nCol ) +{ + ScDPLabelData* pData = GetLabelData( nCol ); + DBG_ASSERT( pData, "LabelData not found" ); + if (pData) + return pData->getDisplayName(); + return String(); +} + +//---------------------------------------------------------------------------- + +bool ScDPLayoutDlg::IsOrientationAllowed( SCsCOL nCol, ScDPFieldType eType ) +{ + bool bAllowed = true; + ScDPLabelData* pData = GetLabelData( nCol ); + DBG_ASSERT( pData, "LabelData not found" ); + if (pData) + { + sheet::DataPilotFieldOrientation eOrient = sheet::DataPilotFieldOrientation_HIDDEN; + switch (eType) + { + case TYPE_PAGE: eOrient = sheet::DataPilotFieldOrientation_PAGE; break; + case TYPE_COL: eOrient = sheet::DataPilotFieldOrientation_COLUMN; break; + case TYPE_ROW: eOrient = sheet::DataPilotFieldOrientation_ROW; break; + case TYPE_DATA: eOrient = sheet::DataPilotFieldOrientation_DATA; break; + case TYPE_SELECT: eOrient = sheet::DataPilotFieldOrientation_HIDDEN; break; + } + bAllowed = ScDPObject::IsOrientationAllowed( (sal_uInt16)eOrient, pData->mnFlags ); + } + return bAllowed; +} + +//---------------------------------------------------------------------------- + +String ScDPLayoutDlg::GetFuncString( sal_uInt16& rFuncMask, sal_Bool bIsValue ) +{ + String aStr; + + if ( rFuncMask == PIVOT_FUNC_NONE + || rFuncMask == PIVOT_FUNC_AUTO ) + { + if ( bIsValue ) + { + aStr = FSTR(PIVOTSTR_SUM); + rFuncMask = PIVOT_FUNC_SUM; + } + else + { + aStr = FSTR(PIVOTSTR_COUNT); + rFuncMask = PIVOT_FUNC_COUNT; + } + } + else if ( rFuncMask == PIVOT_FUNC_SUM ) aStr = FSTR(PIVOTSTR_SUM); + else if ( rFuncMask == PIVOT_FUNC_COUNT ) aStr = FSTR(PIVOTSTR_COUNT); + else if ( rFuncMask == PIVOT_FUNC_AVERAGE ) aStr = FSTR(PIVOTSTR_AVG); + else if ( rFuncMask == PIVOT_FUNC_MAX ) aStr = FSTR(PIVOTSTR_MAX); + else if ( rFuncMask == PIVOT_FUNC_MIN ) aStr = FSTR(PIVOTSTR_MIN); + else if ( rFuncMask == PIVOT_FUNC_PRODUCT ) aStr = FSTR(PIVOTSTR_PROD); + else if ( rFuncMask == PIVOT_FUNC_COUNT_NUM ) aStr = FSTR(PIVOTSTR_COUNT2); + else if ( rFuncMask == PIVOT_FUNC_STD_DEV ) aStr = FSTR(PIVOTSTR_DEV); + else if ( rFuncMask == PIVOT_FUNC_STD_DEVP ) aStr = FSTR(PIVOTSTR_DEV2); + else if ( rFuncMask == PIVOT_FUNC_STD_VAR ) aStr = FSTR(PIVOTSTR_VAR); + else if ( rFuncMask == PIVOT_FUNC_STD_VARP ) aStr = FSTR(PIVOTSTR_VAR2); + else + { + aStr = ScGlobal::GetRscString( STR_TABLE_ERGEBNIS ); + aStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " - " )); + } + + return aStr; +} + +//---------------------------------------------------------------------------- + +Point ScDPLayoutDlg::DlgPos2WndPos( const Point& rPt, Window& rWnd ) +{ + Point aWndPt( rPt ); + aWndPt.X() = rPt.X()-rWnd.GetPosPixel().X(); + aWndPt.Y() = rPt.Y()-rWnd.GetPosPixel().Y(); + + return aWndPt; +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::CalcWndSizes() +{ + // The pivot.src file only specifies the positions of the controls. Here, + // we calculate appropriate size of each control based on how they are + // positioned relative to each other. + + // row/column/data area sizes + long nFldW = GetStdFieldBtnSize().Width(); + long nFldH = GetStdFieldBtnSize().Height(); + + aWndData.SetSizePixel( + Size(aWndSelect.GetPosPixel().X() - aWndData.GetPosPixel().X() - FIELD_AREA_GAP*4, + 185)); + + aWndPage.SetSizePixel( + Size(aWndData.GetSizePixel().Width() + 85, + aWndCol.GetPosPixel().Y() - aWndPage.GetPosPixel().Y() - FIELD_AREA_GAP)); + aWndRow.SetSizePixel( + Size(aWndData.GetPosPixel().X()-aWndRow.GetPosPixel().X() - FIELD_AREA_GAP, + aWndData.GetSizePixel().Height())); + aWndCol.SetSizePixel( + Size(aWndData.GetPosPixel().X() - aWndCol.GetPosPixel().X() + aWndData.GetSizePixel().Width(), + aWndData.GetPosPixel().Y() - aWndCol.GetPosPixel().Y() - FIELD_AREA_GAP)); + + // #i29203# align right border of page window with data window + long nDataPosX = aWndData.GetPosPixel().X() + aWndData.GetSizePixel().Width(); + aWndPage.SetPosPixel( + Point(nDataPosX - aWndPage.GetSizePixel().Width(), + aWndPage.GetPosPixel().Y())); + + // selection area + long nLineSize = 10; // number of fields per column. + long nH = OUTER_MARGIN_VER + nLineSize* nFldH + nLineSize * ROW_FIELD_BTN_GAP; + nH += ROW_FIELD_BTN_GAP; + nH += GetSettings().GetStyleSettings().GetScrollBarSize() + OUTER_MARGIN_VER; + aWndSelect.SetSizePixel( + Size(2 * nFldW + ROW_FIELD_BTN_GAP + 10, nH)); + + aRectPage = Rectangle( aWndPage.GetPosPixel(), aWndPage.GetSizePixel() ); + aRectRow = Rectangle( aWndRow.GetPosPixel(), aWndRow.GetSizePixel() ); + aRectCol = Rectangle( aWndCol.GetPosPixel(), aWndCol.GetSizePixel() ); + aRectData = Rectangle( aWndData.GetPosPixel(), aWndData.GetSizePixel() ); + aRectSelect = Rectangle( aWndSelect.GetPosPixel(), aWndSelect.GetSizePixel() ); + + aWndPage.CalcSize(); + aWndRow.CalcSize(); + aWndCol.CalcSize(); + aWndData.CalcSize(); + aWndSelect.CalcSize(); +} + +namespace { + +class PivotFieldInserter : public ::std::unary_function<void, boost::shared_ptr<ScDPFuncData> > +{ + vector<PivotField>& mrFields; +public: + explicit PivotFieldInserter(vector<PivotField>& r, size_t nSize) : mrFields(r) + { + mrFields.reserve(nSize); + } + + PivotFieldInserter(const PivotFieldInserter& r) : mrFields(r.mrFields) {} + + void operator() (const ::boost::shared_ptr<ScDPFuncData>& p) + { + PivotField aField; + aField.nCol = p->mnCol; + aField.nFuncMask = p->mnFuncMask; + aField.maFieldRef = p->maFieldRef; + mrFields.push_back(aField); + } +}; + +} + +bool ScDPLayoutDlg::GetPivotArrays( + vector<PivotField>& rPageFields, vector<PivotField>& rColFields, + vector<PivotField>& rRowFields, vector<PivotField>& rDataFields ) +{ + vector<PivotField> aPageFields; + for_each(aPageArr.begin(), aPageArr.end(), PivotFieldInserter(aPageFields, aPageArr.size())); + + vector<PivotField> aColFields; + for_each(aColArr.begin(), aColArr.end(), PivotFieldInserter(aColFields, aColArr.size())); + + // default data pilot table always has an extra row field as a data layout field. + vector<PivotField> aRowFields; + for_each(aRowArr.begin(), aRowArr.end(), PivotFieldInserter(aRowFields, aRowArr.size()+1)); + aRowFields.push_back(PivotField(PIVOT_DATA_FIELD, 0)); + + vector<PivotField> aDataFields; + for_each(aDataArr.begin(), aDataArr.end(), PivotFieldInserter(aDataFields, aDataArr.size())); + + rPageFields.swap(aPageFields); + rColFields.swap(aColFields); + rRowFields.swap(aRowFields); + rDataFields.swap(aDataFields); + + return true; +} + +void ScDPLayoutDlg::UpdateSrcRange() +{ + String aSrcStr = aEdInPos.GetText(); + sal_uInt16 nResult = ScRange().Parse(aSrcStr, pDoc, pDoc->GetAddressConvention()); + DataSrcType eSrcType = SRC_INVALID; + ScRange aNewRange; + + if (SCA_VALID == (nResult & SCA_VALID)) + { + // Valid source range. Take it. + ScRefAddress start, end; + ConvertDoubleRef(pDoc, aSrcStr, 1, start, end, pDoc->GetAddressConvention()); + aNewRange.aStart = start.GetAddress(); + aNewRange.aEnd = end.GetAddress(); + aEdInPos.SetRefValid(true); + eSrcType = SRC_REF; + } + else + { + // invalid source range. Check if this is a valid range name. + bool bValid = false; + ScRangeName* pRangeName = pDoc->GetRangeName(); + if (pRangeName) + { + OUString aUpper = ScGlobal::pCharClass->upper(aSrcStr); + const ScRangeData* pData = pRangeName->findByUpperName(aUpper); + if (pData) + { + // range name found. Check if this is a valid reference. + bValid = pData->IsReference(aNewRange); + } + } + + aEdInPos.SetRefValid(bValid); + if (!bValid) + { + // All attempts have failed. Give up. + aBtnOk.Disable(); + return; + } + + eSrcType = SRC_NAME; + } + + aBtnOk.Enable(); + + // Now update the data src range or range name with the dp object. + ScSheetSourceDesc inSheet = *xDlgDPObject->GetSheetDesc(); + + switch (eSrcType) + { + case SRC_REF: + // data source is a range reference. + if (inSheet.GetSourceRange() == aNewRange) + // new range is identical to the current range. Nothing to do. + return; + inSheet.SetSourceRange(aNewRange); + break; + case SRC_NAME: + // data source is a range name. + inSheet.SetRangeName(aSrcStr); + break; + default: + OSL_FAIL( "Unknown source type."); + return; + } + + xDlgDPObject->SetSheetDesc(inSheet); + xDlgDPObject->FillOldParam( thePivotData ); + xDlgDPObject->FillLabelData(thePivotData); + + aLabelDataArr.clear(); + aWndSelect.ClearFields(); + aWndData.ClearFields(); + aWndRow.ClearFields(); + aWndCol.ClearFields(); + aWndPage.ClearFields(); + + aSelectArr.clear(); + aRowArr.clear(); + aColArr.clear(); + aDataArr.clear(); + aPageArr.clear(); + + InitFields(); + RepaintFieldWindows(); +} + +void ScDPLayoutDlg::RepaintFieldWindows() +{ + Rectangle aRect; // currently has no effect whatsoever. + aWndPage.Paint(aRect); + aWndCol.Paint(aRect); + aWndRow.Paint(aRect); + aWndData.Paint(aRect); +} + +ScDPFieldControlBase* ScDPLayoutDlg::GetFieldWindow(ScDPFieldType eType) +{ + switch (eType) + { + case TYPE_PAGE: + return &aWndPage; + case TYPE_COL: + return &aWndCol; + case TYPE_ROW: + return &aWndRow; + case TYPE_DATA: + return &aWndData; + case TYPE_SELECT: + return &aWndSelect; + default: + ; + } + return NULL; +} + +void ScDPLayoutDlg::GetOtherFieldWindows(ScDPFieldType eType, ScDPFieldControlBase*& rpWnd1, ScDPFieldControlBase*& rpWnd2) +{ + rpWnd1 = NULL; + rpWnd2 = NULL; + switch (eType) + { + case TYPE_PAGE: + rpWnd1 = &aWndRow; + rpWnd2 = &aWndCol; + break; + case TYPE_COL: + rpWnd1 = &aWndPage; + rpWnd2 = &aWndRow; + break; + case TYPE_ROW: + rpWnd1 = &aWndPage; + rpWnd2 = &aWndCol; + break; + default: + ; + } +} + +ScDPLayoutDlg::ScDPFuncDataVec* ScDPLayoutDlg::GetFieldDataArray(ScDPFieldType eType) +{ + switch (eType) + { + case TYPE_PAGE: + return &aPageArr; + case TYPE_COL: + return &aColArr; + case TYPE_ROW: + return &aRowArr; + case TYPE_DATA: + return &aDataArr; + case TYPE_SELECT: + return &aSelectArr; + default: + ; + } + return NULL; +} + +void ScDPLayoutDlg::GetOtherDataArrays( + ScDPFieldType eType, ScDPFuncDataVec*& rpArr1, ScDPFuncDataVec*& rpArr2) +{ + rpArr1 = NULL; + rpArr2 = NULL; + switch (eType) + { + case TYPE_PAGE: + rpArr1 = &aRowArr; + rpArr2 = &aColArr; + break; + case TYPE_COL: + rpArr1 = &aPageArr; + rpArr2 = &aRowArr; + break; + case TYPE_ROW: + rpArr1 = &aPageArr; + rpArr2 = &aColArr; + break; + default: + ; + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::SetReference( const ScRange& rRef, ScDocument* pDocP ) +{ + if ( !bRefInputMode || !pEditActive ) + return; + + if ( rRef.aStart != rRef.aEnd ) + RefInputStart( pEditActive ); + + if ( pEditActive == &aEdInPos ) + { + String aRefStr; + rRef.Format( aRefStr, SCR_ABS_3D, pDocP, pDocP->GetAddressConvention() ); + pEditActive->SetRefString( aRefStr ); + } + else if ( pEditActive == &aEdOutPos ) + { + String aRefStr; + rRef.aStart.Format( aRefStr, STD_FORMAT, pDocP, pDocP->GetAddressConvention() ); + pEditActive->SetRefString( aRefStr ); + } +} + +//---------------------------------------------------------------------------- + +void ScDPLayoutDlg::SetActive() +{ + if ( bRefInputMode ) + { + if ( pEditActive ) + pEditActive->GrabFocus(); + + if ( pEditActive == &aEdInPos ) + EdInModifyHdl( NULL ); + else if ( pEditActive == &aEdOutPos ) + EdModifyHdl( NULL ); + } + else + { + GrabFocus(); + } + + RefInputDone(); +} + +//---------------------------------------------------------------------------- +// Handler: +//---------------------------------------------------------------------------- + +IMPL_LINK( ScDPLayoutDlg, ClickHdl, PushButton *, pBtn ) +{ + ScDPFieldControlBase* pWnd = GetFieldWindow( eLastActiveType ); + if (!pWnd) + return 0; + + if( pBtn == &aBtnRemove ) + { + RemoveField( eLastActiveType, pWnd->GetSelectedField() ); + if( !pWnd->IsEmpty() ) pWnd->GrabFocus(); + } + else if( pBtn == &aBtnOptions ) + { + NotifyDoubleClick( eLastActiveType, pWnd->GetSelectedField() ); + pWnd->GrabFocus(); + } + return 0; +} + +//---------------------------------------------------------------------------- + +IMPL_LINK( ScDPLayoutDlg, OkHdl, OKButton *, EMPTYARG ) +{ + String aOutPosStr( aEdOutPos.GetText() ); + ScAddress aAdrDest; + sal_Bool bToNewTable = (aLbOutPos.GetSelectEntryPos() == 1); + sal_uInt16 nResult = !bToNewTable ? aAdrDest.Parse( aOutPosStr, pDoc, pDoc->GetAddressConvention() ) : 0; + + if (!bToNewTable && (aOutPosStr.Len() == 0 || (nResult & SCA_VALID) != SCA_VALID)) + { + // Invalid reference. Bail out. + if ( !aBtnMore.GetState() ) + aBtnMore.SetState(true); + + ErrorBox(this, WinBits(WB_OK | WB_DEF_OK), ScGlobal::GetRscString(STR_INVALID_TABREF)).Execute(); + aEdOutPos.GrabFocus(); + return 0; + } + + ScPivotParam theOutParam; + vector<PivotField> aPageFields; + vector<PivotField> aColFields; + vector<PivotField> aRowFields; + vector<PivotField> aDataFields; + + // Convert an array of function data into an array of pivot field data. + bool bFit = GetPivotArrays(aPageFields, aColFields, aRowFields, aDataFields); + + if (!bFit) + { + // General data pilot table error. Bail out. + ErrorBox(this, WinBits(WB_OK | WB_DEF_OK), ScGlobal::GetRscString(STR_PIVOT_ERROR)).Execute(); + return 0; + } + + ScDPSaveData* pOldSaveData = xDlgDPObject->GetSaveData(); + + ScRange aOutRange( aAdrDest ); // bToNewTable is passed separately + + ScDPSaveData aSaveData; + aSaveData.SetIgnoreEmptyRows( aBtnIgnEmptyRows.IsChecked() ); + aSaveData.SetRepeatIfEmpty( aBtnDetectCat.IsChecked() ); + aSaveData.SetColumnGrand( aBtnTotalCol.IsChecked() ); + aSaveData.SetRowGrand( aBtnTotalRow.IsChecked() ); + aSaveData.SetFilterButton( aBtnFilter.IsChecked() ); + aSaveData.SetDrillDown( aBtnDrillDown.IsChecked() ); + + uno::Reference<sheet::XDimensionsSupplier> xSource = xDlgDPObject->GetSource(); + + ScDPObject::ConvertOrientation( + aSaveData, aPageFields, sheet::DataPilotFieldOrientation_PAGE, xSource ); + ScDPObject::ConvertOrientation( + aSaveData, aColFields, sheet::DataPilotFieldOrientation_COLUMN, xSource ); + ScDPObject::ConvertOrientation( + aSaveData, aRowFields, sheet::DataPilotFieldOrientation_ROW, xSource ); + ScDPObject::ConvertOrientation( + aSaveData, aDataFields, sheet::DataPilotFieldOrientation_DATA, xSource, + &aColFields, &aRowFields, &aPageFields ); + + for( ScDPLabelDataVec::const_iterator aIt = aLabelDataArr.begin(), aEnd = aLabelDataArr.end(); aIt != aEnd; ++aIt ) + { + if( ScDPSaveDimension* pDim = aSaveData.GetExistingDimensionByName( aIt->maName ) ) + { + pDim->SetUsedHierarchy( aIt->mnUsedHier ); + pDim->SetShowEmpty( aIt->mbShowAll ); + pDim->SetSortInfo( &aIt->maSortInfo ); + pDim->SetLayoutInfo( &aIt->maLayoutInfo ); + pDim->SetAutoShowInfo( &aIt->maShowInfo ); + ScDPSaveDimension* pOldDim = NULL; + if (pOldSaveData) + { + // Transfer the existing layout names to new dimension instance. + pOldDim = pOldSaveData->GetExistingDimensionByName(aIt->maName); + if (pOldDim) + { + const OUString* pLayoutName = pOldDim->GetLayoutName(); + if (pLayoutName) + pDim->SetLayoutName(*pLayoutName); + + const OUString* pSubtotalName = pOldDim->GetSubtotalName(); + if (pSubtotalName) + pDim->SetSubtotalName(*pSubtotalName); + } + } + + bool bManualSort = ( aIt->maSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL ); + + // visibility of members + for (vector<ScDPLabelData::Member>::const_iterator itr = aIt->maMembers.begin(), itrEnd = aIt->maMembers.end(); + itr != itrEnd; ++itr) + { + ScDPSaveMember* pMember = pDim->GetMemberByName(itr->maName); + + // #i40054# create/access members only if flags are not default + // (or in manual sorting mode - to keep the order) + if (bManualSort || !itr->mbVisible || !itr->mbShowDetails) + { + pMember->SetIsVisible(itr->mbVisible); + pMember->SetShowDetails(itr->mbShowDetails); + } + if (pOldDim) + { + // Transfer the existing layout name. + ScDPSaveMember* pOldMember = pOldDim->GetMemberByName(itr->maName); + if (pOldMember) + { + const OUString* pLayoutName = pOldMember->GetLayoutName(); + if (pLayoutName) + pMember->SetLayoutName(*pLayoutName); + } + } + } + } + } + ScDPSaveDimension* pDim = aSaveData.GetDataLayoutDimension(); + if (pDim && pOldSaveData) + { + ScDPSaveDimension* pOldDim = pOldSaveData->GetDataLayoutDimension(); + if (pOldDim) + { + const OUString* pLayoutName = pOldDim->GetLayoutName(); + if (pLayoutName) + pDim->SetLayoutName(*pLayoutName); + } + } + + sal_uInt16 nWhichPivot = SC_MOD()->GetPool().GetWhich( SID_PIVOT_TABLE ); + ScPivotItem aOutItem( nWhichPivot, &aSaveData, &aOutRange, bToNewTable ); + + bRefInputMode = false; // to allow deselecting when switching sheets + + SetDispatcherLock( false ); + SwitchToDocument(); + + ScTabViewShell* pTabViewShell = pViewData->GetViewShell(); + pTabViewShell->SetDialogDPObject(xDlgDPObject.get()); + + // don't hide the dialog before executing the slot, instead it is used as + // parent for message boxes in ScTabViewShell::GetDialogParent + + const SfxPoolItem* pRet = GetBindings().GetDispatcher()->Execute( + SID_PIVOT_TABLE, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD, &aOutItem, 0L, 0L ); + + bool bSuccess = true; + if (pRet) + { + const SfxBoolItem* pItem = dynamic_cast<const SfxBoolItem*>(pRet); + if (pItem) + bSuccess = pItem->GetValue(); + } + if (bSuccess) + // Table successfully inserted. + Close(); + else + { + // Table insertion failed. Keep the dialog open. + bRefInputMode = true; + SetDispatcherLock(true); + } + + return 0; +} + +//---------------------------------------------------------------------------- + +IMPL_LINK( ScDPLayoutDlg, CancelHdl, CancelButton *, EMPTYARG ) +{ + Close(); + return 0; +} + +//---------------------------------------------------------------------------- + +IMPL_LINK( ScDPLayoutDlg, MoreClickHdl, MoreButton *, EMPTYARG ) +{ + if ( aBtnMore.GetState() ) + { + bRefInputMode = true; + //@BugID 54702 Enablen/Disablen nur noch in Basisklasse + //SFX_APPWINDOW->Enable(); + if ( aEdInPos.IsEnabled() ) + { + aEdInPos.Enable(); + aEdInPos.GrabFocus(); + aEdInPos.Enable(); + } + else + { + aEdOutPos.Enable(); + aEdOutPos.GrabFocus(); + aEdOutPos.Enable(); + } + } + else + { + bRefInputMode = false; + //@BugID 54702 Enablen/Disablen nur noch in Basisklasse + //SFX_APPWINDOW->Disable(false); //! allgemeine Methode im ScAnyRefDlg + } + return 0; +} + +//---------------------------------------------------------------------------- + +IMPL_LINK( ScDPLayoutDlg, EdModifyHdl, Edit *, EMPTYARG ) +{ + String theCurPosStr = aEdOutPos.GetText(); + sal_uInt16 nResult = ScAddress().Parse( theCurPosStr, pDoc, pDoc->GetAddressConvention() ); + + if ( SCA_VALID == (nResult & SCA_VALID) ) + { + String* pStr = NULL; + sal_Bool bFound = false; + sal_uInt16 i = 0; + sal_uInt16 nCount = aLbOutPos.GetEntryCount(); + + for ( i=2; i<nCount && !bFound; i++ ) + { + pStr = (String*)aLbOutPos.GetEntryData( i ); + bFound = (theCurPosStr == *pStr); + } + + if ( bFound ) + aLbOutPos.SelectEntryPos( --i ); + else + aLbOutPos.SelectEntryPos( 0 ); + } + return 0; +} + +IMPL_LINK( ScDPLayoutDlg, EdInModifyHdl, Edit *, EMPTYARG ) +{ + UpdateSrcRange(); + return 0; +} + +//---------------------------------------------------------------------------- + +IMPL_LINK( ScDPLayoutDlg, SelAreaHdl, ListBox *, EMPTYARG ) +{ + String aString; + sal_uInt16 nSelPos = aLbOutPos.GetSelectEntryPos(); + + if ( nSelPos > 1 ) + { + aString = *(String*)aLbOutPos.GetEntryData( nSelPos ); + } + else if ( nSelPos == aLbOutPos.GetEntryCount()-1 ) // auf neue Tabelle? + { + aEdOutPos.Disable(); + aRbOutPos.Disable(); + } + else + { + aEdOutPos.Enable(); + aRbOutPos.Enable(); + } + + aEdOutPos.SetText( aString ); + return 0; +} + +IMPL_LINK( ScDPLayoutDlg, GetFocusHdl, Control*, pCtrl ) +{ + pEditActive = NULL; + if ( pCtrl == &aEdInPos ) + pEditActive = &aEdInPos; + else if ( pCtrl == &aEdOutPos ) + pEditActive = &aEdOutPos; + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |