xref: /aoo41x/main/sc/source/ui/dbgui/pvlaydlg.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 #include "pvlaydlg.hxx"
32 
33 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
34 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
35 
36 #include <sfx2/dispatch.hxx>
37 #include <vcl/mnemonic.hxx>
38 #include <vcl/msgbox.hxx>
39 
40 #include "dbdocfun.hxx"
41 #include "uiitems.hxx"
42 #include "rangeutl.hxx"
43 #include "document.hxx"
44 #include "viewdata.hxx"
45 #include "tabvwsh.hxx"
46 #include "reffact.hxx"
47 #include "scresid.hxx"
48 #include "globstr.hrc"
49 #include "pivot.hrc"
50 #include "dpobject.hxx"
51 #include "dpsave.hxx"
52 #include "dpshttab.hxx"
53 #include "scmod.hxx"
54 
55 #include "sc.hrc" //CHINA001
56 #include "scabstdlg.hxx" //CHINA001
57 
58 // ============================================================================
59 
60 using namespace ::com::sun::star;
61 using ::rtl::OUString;
62 
63 // ============================================================================
64 
65 namespace {
66 
67 const sal_uInt16 STD_FORMAT = sal_uInt16( SCA_VALID | SCA_TAB_3D | SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE );
68 
69 OUString lclGetNameWithoutMnemonic( const FixedText& rFixedText )
70 {
71     return MnemonicGenerator::EraseAllMnemonicChars( rFixedText.GetText() );
72 }
73 
74 } // namespace
75 
76 // ============================================================================
77 
78 ScPivotLayoutDlg::ScPivotLayoutDlg( SfxBindings* pB, SfxChildWindow* pCW, Window* pParent, const ScDPObject& rDPObject ) :
79 
80 	ScAnyRefDlg( pB, pCW, pParent, RID_SCDLG_PIVOT_LAYOUT ),
81 
82     maFlLayout( this, ScResId( FL_LAYOUT ) ),
83 	maScrPage( this, ScResId( SCROLL_PAGE ) ),
84     maFtPage( this, ScResId( FT_PAGE ) ),
85     maWndPage( this, ScResId( WND_PAGE ), maScrPage, &maFtPage, lclGetNameWithoutMnemonic( maFtPage ), PIVOTFIELDTYPE_PAGE, HID_SC_DPLAY_PAGE, POINTER_PIVOT_FIELD, 5, 2, 1, 0 ),
86 	maScrCol( this, ScResId( SCROLL_COL ) ),
87     maFtCol( this, ScResId( FT_COL ) ),
88     maWndCol( this, ScResId( WND_COL ), maScrCol, &maFtCol, lclGetNameWithoutMnemonic( maFtCol ), PIVOTFIELDTYPE_COL, HID_SC_DPLAY_COLUMN, POINTER_PIVOT_COL, 4, 2, 1, 0 ),
89 	maScrRow( this, ScResId( SCROLL_ROW ) ),
90     maFtRow( this, ScResId( FT_ROW ) ),
91     maWndRow( this, ScResId( WND_ROW ), maScrRow, &maFtRow, lclGetNameWithoutMnemonic( maFtRow ), PIVOTFIELDTYPE_ROW, HID_SC_DPLAY_ROW, POINTER_PIVOT_ROW, 1, 8, 1, 0 ),
92 	maScrData( this, ScResId( SCROLL_DATA ) ),
93     maFtData( this, ScResId( FT_DATA ) ),
94     maWndData( this, ScResId( WND_DATA ), maScrData, &maFtData, lclGetNameWithoutMnemonic( maFtData ), PIVOTFIELDTYPE_DATA, HID_SC_DPLAY_DATA, POINTER_PIVOT_FIELD, 1, 8, 4, 0 ),
95     maFlSelect( this, ScResId( FL_SELECT ) ),
96 	maScrSelect( this, ScResId( WND_HSCROLL ) ),
97     maWndSelect( this, ScResId( WND_SELECT ), maScrSelect, 0, String( ScResId( STR_SELECT ) ), PIVOTFIELDTYPE_SELECT, HID_SC_DPLAY_SELECT, POINTER_PIVOT_FIELD, 2, 10, 1, 2 ),
98 	maFtInfo( this, ScResId( FT_INFO ) ),
99 
100     maFlAreas( this, ScResId( FL_OUTPUT ) ),
101     maFtInArea( this, ScResId( FT_INAREA) ),
102     maEdInPos( this, this, ScResId( ED_INAREA) ),
103     maRbInPos( this, ScResId( RB_INAREA ), &maEdInPos, this ),
104 	maLbOutPos( this, ScResId( LB_OUTAREA ) ),
105 	maFtOutArea( this, ScResId( FT_OUTAREA ) ),
106     maEdOutPos( this, this, ScResId( ED_OUTAREA ) ),
107 	maRbOutPos( this, ScResId( RB_OUTAREA ), &maEdOutPos, this ),
108 	maBtnIgnEmptyRows( this, ScResId( BTN_IGNEMPTYROWS ) ),
109 	maBtnDetectCat( this, ScResId( BTN_DETECTCAT ) ),
110 	maBtnTotalCol( this, ScResId( BTN_TOTALCOL ) ),
111 	maBtnTotalRow( this, ScResId( BTN_TOTALROW ) ),
112     maBtnFilter( this, ScResId( BTN_FILTER ) ),
113     maBtnDrillDown( this, ScResId( BTN_DRILLDOWN ) ),
114 
115 	maBtnOk( this, ScResId( BTN_OK ) ),
116 	maBtnCancel( this, ScResId( BTN_CANCEL ) ),
117 	maBtnHelp( this, ScResId( BTN_HELP ) ),
118     maBtnRemove( this, ScResId( BTN_REMOVE ) ),
119     maBtnOptions( this, ScResId( BTN_OPTIONS ) ),
120 	maBtnMore( this, ScResId( BTN_MORE ) ),
121 
122     mxDlgDPObject( new ScDPObject( rDPObject ) ),
123 	mpViewData( ((ScTabViewShell*)SfxViewShell::Current())->GetViewData() ),
124 	mpDoc( ((ScTabViewShell*)SfxViewShell::Current())->GetViewData()->GetDocument() ),
125 	mpFocusWindow( 0 ),
126 	mpTrackingWindow( 0 ),
127     mpDropWindow( 0 ),
128     mpActiveEdit( 0 ),
129 	mbRefInputMode( false )
130 {
131 	DBG_ASSERT( mpViewData && mpDoc, "ScPivotLayoutDlg::ScPivotLayoutDlg - missing document or view data" );
132 
133     mxDlgDPObject->SetAlive( true );     // needed to get structure information
134     mxDlgDPObject->FillOldParam( maPivotData );
135     mxDlgDPObject->FillLabelData( maPivotData );
136 
137     maBtnRemove.SetClickHdl( LINK( this, ScPivotLayoutDlg, ClickHdl ) );
138     maBtnOptions.SetClickHdl( LINK( this, ScPivotLayoutDlg, ClickHdl ) );
139 
140     // PIVOT_MAXFUNC defined in sc/inc/dpglobal.hxx
141     maFuncNames.reserve( PIVOT_MAXFUNC );
142     for( sal_uInt16 i = 1; i <= PIVOT_MAXFUNC; ++i )
143         maFuncNames.push_back( String( ScResId( i ) ) );
144 
145     maBtnMore.AddWindow( &maFlAreas );
146     maBtnMore.AddWindow( &maFtInArea );
147     maBtnMore.AddWindow( &maEdInPos );
148     maBtnMore.AddWindow( &maRbInPos );
149 	maBtnMore.AddWindow( &maFtOutArea );
150 	maBtnMore.AddWindow( &maLbOutPos );
151 	maBtnMore.AddWindow( &maEdOutPos );
152     maBtnMore.AddWindow( &maRbOutPos );
153 	maBtnMore.AddWindow( &maBtnIgnEmptyRows );
154 	maBtnMore.AddWindow( &maBtnDetectCat );
155 	maBtnMore.AddWindow( &maBtnTotalCol );
156 	maBtnMore.AddWindow( &maBtnTotalRow );
157     maBtnMore.AddWindow( &maBtnFilter );
158     maBtnMore.AddWindow( &maBtnDrillDown );
159     maBtnMore.SetClickHdl( LINK( this, ScPivotLayoutDlg, MoreClickHdl ) );
160 
161     if( mxDlgDPObject->GetSheetDesc() )
162 	{
163         maEdInPos.Enable();
164         maRbInPos.Enable();
165         ScRange aRange = mxDlgDPObject->GetSheetDesc()->aSourceRange;
166         String aString;
167         aRange.Format( aString, SCR_ABS_3D, mpDoc, mpDoc->GetAddressConvention() );
168         maEdInPos.SetText( aString );
169 	}
170 	else
171     {
172         // data is not reachable, so could be a remote database
173         maEdInPos.Disable();
174         maRbInPos.Disable();
175     }
176 
177     // #i29203# align right border of page window with data window
178     long nPagePosX = maWndData.GetPosPixel().X() + maWndData.GetSizePixel().Width() - maWndPage.GetSizePixel().Width();
179     maWndPage.SetPosPixel( Point( nPagePosX, maWndPage.GetPosPixel().Y() ) );
180     maScrPage.SetPosPixel( Point( maScrData.GetPosPixel().X(), maScrPage.GetPosPixel().Y() ) );
181 
182     InitFieldWindows();
183 
184     maLbOutPos.SetSelectHdl( LINK( this, ScPivotLayoutDlg, SelAreaHdl ) );
185     maEdOutPos.SetModifyHdl( LINK( this, ScPivotLayoutDlg, EdOutModifyHdl ) );
186     maEdInPos.SetModifyHdl( LINK( this, ScPivotLayoutDlg, EdInModifyHdl ) );
187     maBtnOk.SetClickHdl( LINK( this, ScPivotLayoutDlg, OkHdl ) );
188     maBtnCancel.SetClickHdl( LINK( this, ScPivotLayoutDlg, CancelHdl ) );
189 
190 	if( mpViewData && mpDoc )
191 	{
192 		/*
193 		 * Aus den RangeNames des Dokumentes werden nun die
194 		 * in einem Zeiger-Array gemerkt, bei denen es sich
195 		 * um sinnvolle Bereiche handelt
196 		 */
197 
198 		maLbOutPos.Clear();
199 		maLbOutPos.InsertEntry( String( ScResId( SCSTR_UNDEFINED ) ), 0 );
200 		maLbOutPos.InsertEntry( String( ScResId( SCSTR_NEWTABLE ) ), 1 );
201 
202 		ScAreaNameIterator aIter( mpDoc );
203 		String aName;
204 		ScRange aRange;
205 		String aRefStr;
206 		while ( aIter.Next( aName, aRange ) )
207 		{
208 			if ( !aIter.WasDBName() )		// hier keine DB-Bereiche !
209 			{
210 				sal_uInt16 nInsert = maLbOutPos.InsertEntry( aName );
211 
212 				aRange.aStart.Format( aRefStr, SCA_ABS_3D, mpDoc, mpDoc->GetAddressConvention() );
213 				maLbOutPos.SetEntryData( nInsert, new String( aRefStr ) );
214 			}
215 		}
216 	}
217 
218 	if ( maPivotData.nTab != MAXTAB+1 )
219 	{
220 		String aStr;
221 		ScAddress( maPivotData.nCol,
222 				   maPivotData.nRow,
223 				   maPivotData.nTab ).Format( aStr, STD_FORMAT, mpDoc, mpDoc->GetAddressConvention() );
224 		maEdOutPos.SetText( aStr );
225 		EdOutModifyHdl( 0 );
226 	}
227 	else
228 	{
229 		maLbOutPos.SelectEntryPos( maLbOutPos.GetEntryCount()-1 );
230 		SelAreaHdl(NULL);
231 	}
232 
233 	maBtnIgnEmptyRows.Check( maPivotData.bIgnoreEmptyRows );
234 	maBtnDetectCat.Check( maPivotData.bDetectCategories );
235 	maBtnTotalCol.Check( maPivotData.bMakeTotalCol );
236 	maBtnTotalRow.Check( maPivotData.bMakeTotalRow );
237 
238     const ScDPSaveData* pSaveData = mxDlgDPObject->GetSaveData();
239     maBtnFilter.Check( !pSaveData || pSaveData->GetFilterButton() );
240     maBtnDrillDown.Check( !pSaveData || pSaveData->GetDrillDown() );
241 
242     // child event listener handles field movement when keyboard shortcut is pressed
243     AddChildEventListener( LINK( this, ScPivotLayoutDlg, ChildEventListener ) );
244     GrabFieldFocus( maWndSelect );
245 
246 	FreeResource();
247 }
248 
249 ScPivotLayoutDlg::~ScPivotLayoutDlg()
250 {
251     RemoveChildEventListener( LINK( this, ScPivotLayoutDlg, ChildEventListener ) );
252 
253 	for( sal_uInt16 i = 2, nEntries = maLbOutPos.GetEntryCount();  i < nEntries; ++i )
254 		delete (String*)maLbOutPos.GetEntryData( i );
255 }
256 
257 ScDPLabelData* ScPivotLayoutDlg::GetLabelData( SCCOL nCol, size_t* pnIndex )
258 {
259     ScDPLabelData* pLabelData = 0;
260     for( ScDPLabelDataVector::iterator aIt = maLabelData.begin(), aEnd = maLabelData.end(); !pLabelData && (aIt != aEnd); ++aIt )
261     {
262         if( aIt->mnCol == nCol )
263         {
264             pLabelData = &*aIt;
265             if( pnIndex )
266                 *pnIndex = aIt - maLabelData.begin();
267         }
268     }
269     return pLabelData;
270 }
271 
272 String ScPivotLayoutDlg::GetFuncString( sal_uInt16& rnFuncMask, bool bIsValue )
273 {
274 	String aStr;
275 
276 	if( (rnFuncMask == PIVOT_FUNC_NONE) || (rnFuncMask == PIVOT_FUNC_AUTO) )
277 	{
278 		if( bIsValue )
279 		{
280 			aStr = GetFuncName( PIVOTSTR_SUM );
281 			rnFuncMask = PIVOT_FUNC_SUM;
282 		}
283 		else
284 		{
285 			aStr = GetFuncName( PIVOTSTR_COUNT );
286 			rnFuncMask = PIVOT_FUNC_COUNT;
287 		}
288 	}
289     else if( rnFuncMask == PIVOT_FUNC_SUM )         aStr = GetFuncName( PIVOTSTR_SUM );
290     else if( rnFuncMask == PIVOT_FUNC_COUNT )       aStr = GetFuncName( PIVOTSTR_COUNT );
291     else if( rnFuncMask == PIVOT_FUNC_AVERAGE )     aStr = GetFuncName( PIVOTSTR_AVG );
292     else if( rnFuncMask == PIVOT_FUNC_MAX )         aStr = GetFuncName( PIVOTSTR_MAX );
293     else if( rnFuncMask == PIVOT_FUNC_MIN )         aStr = GetFuncName( PIVOTSTR_MIN );
294     else if( rnFuncMask == PIVOT_FUNC_PRODUCT )     aStr = GetFuncName( PIVOTSTR_PROD );
295     else if( rnFuncMask == PIVOT_FUNC_COUNT_NUM )   aStr = GetFuncName( PIVOTSTR_COUNT2 );
296     else if( rnFuncMask == PIVOT_FUNC_STD_DEV )     aStr = GetFuncName( PIVOTSTR_DEV );
297     else if( rnFuncMask == PIVOT_FUNC_STD_DEVP )    aStr = GetFuncName( PIVOTSTR_DEV2 );
298     else if( rnFuncMask == PIVOT_FUNC_STD_VAR )     aStr = GetFuncName( PIVOTSTR_VAR );
299     else if( rnFuncMask == PIVOT_FUNC_STD_VARP )    aStr = GetFuncName( PIVOTSTR_VAR2 );
300     else
301 	{
302 		aStr = ScGlobal::GetRscString( STR_TABLE_ERGEBNIS );
303 		aStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " - " ) );
304 	}
305 
306 	return aStr;
307 }
308 
309 void ScPivotLayoutDlg::NotifyStartTracking( ScPivotFieldWindow& rSourceWindow )
310 {
311     mpTrackingWindow = &rSourceWindow;
312     mpDropWindow = 0;
313     rSourceWindow.NotifyStartTracking();
314     StartTracking( STARTTRACK_BUTTONREPEAT );
315     SetPointer( Pointer( rSourceWindow.GetDropPointerStyle() ) );
316 }
317 
318 void ScPivotLayoutDlg::NotifyDoubleClick( ScPivotFieldWindow& rSourceWindow )
319 {
320     // nothing to do on double-click in selection window
321     if( rSourceWindow.GetType() == PIVOTFIELDTYPE_SELECT )
322         return;
323 
324     const ScPivotFuncData* pFuncData = rSourceWindow.GetSelectedFuncData();
325     DBG_ASSERT( pFuncData, "ScPivotLayoutDlg::NotifyDoubleClick - invalid selection" );
326     if( !pFuncData )
327         return;
328 
329     ScDPLabelData* pLabelData = GetLabelData( pFuncData->mnCol );
330     DBG_ASSERT( pLabelData, "ScPivotLayoutDlg::NotifyDoubleClick - missing label data" );
331     if( !pLabelData )
332         return;
333 
334     ScAbstractDialogFactory* pFactory = ScAbstractDialogFactory::Create();
335     DBG_ASSERT( pFactory, "ScPivotLayoutDlg::NotifyDoubleClick - ScAbstractDialogFactory creation failed" );
336     if( !pFactory )
337         return;
338 
339     if( rSourceWindow.GetType() == PIVOTFIELDTYPE_DATA )
340     {
341         ::std::auto_ptr< AbstractScDPFunctionDlg > xDlg( pFactory->CreateScDPFunctionDlg(
342             this, RID_SCDLG_DPDATAFIELD, maLabelData, *pLabelData, *pFuncData ) );
343         if( xDlg->Execute() == RET_OK )
344         {
345             ScPivotFuncData aFuncData( *pFuncData );
346             aFuncData.mnFuncMask = pLabelData->mnFuncMask = xDlg->GetFuncMask();
347             aFuncData.maFieldRef = xDlg->GetFieldRef();
348             rSourceWindow.ModifySelectedField( aFuncData );
349         }
350     }
351     else
352     {
353         // list of plain names of all data fields
354         ScDPNameVec aDataFieldNames;
355         maWndData.WriteFieldNames( aDataFieldNames );
356         // allow to modify layout options for row fields, if multiple data fields exist, or if it is not the last row field
357         bool bLayout = (rSourceWindow.GetType() == PIVOTFIELDTYPE_ROW) && ((aDataFieldNames.size() > 1) || (rSourceWindow.GetSelectedIndex() + 1 < rSourceWindow.GetFieldCount()));
358 
359         ::std::auto_ptr< AbstractScDPSubtotalDlg > xDlg( pFactory->CreateScDPSubtotalDlg(
360             this, RID_SCDLG_PIVOTSUBT, *mxDlgDPObject, *pLabelData, *pFuncData, aDataFieldNames, bLayout ) );
361         if( xDlg->Execute() == RET_OK )
362         {
363             xDlg->FillLabelData( *pLabelData );
364             ScPivotFuncData aFuncData( *pFuncData );
365             aFuncData.mnFuncMask = pLabelData->mnFuncMask;
366             rSourceWindow.ModifySelectedField( aFuncData );
367         }
368     }
369 }
370 
371 void ScPivotLayoutDlg::NotifyFieldRemoved( ScPivotFieldWindow& rSourceWindow )
372 {
373     // update focus: move to selection window, if source window is empty now
374     GrabFieldFocus( rSourceWindow );
375 }
376 
377 // protected ------------------------------------------------------------------
378 
379 void ScPivotLayoutDlg::Tracking( const TrackingEvent& rTEvt )
380 {
381 	DBG_ASSERT( mpTrackingWindow, "ScPivotLayoutDlg::Tracking - missing tracking source window" );
382     if( !mpTrackingWindow )
383         return;
384 
385     // find target window
386     const Point& rDialogPos = rTEvt.GetMouseEvent().GetPosPixel();
387     ScPivotFieldWindow* pTargetWindow = dynamic_cast< ScPivotFieldWindow* >( FindWindow( rDialogPos ) );
388 
389     // check if the target orientation is allowed for this field
390     if( pTargetWindow && (mpTrackingWindow != pTargetWindow) && !IsInsertAllowed( *mpTrackingWindow, *pTargetWindow ) )
391         pTargetWindow = 0;
392 
393     // tracking from selection window: do not show "delete" mouse pointer
394     PointerStyle eTargetPointer = pTargetWindow ? pTargetWindow->GetDropPointerStyle() :
395         ((mpTrackingWindow->GetType() == PIVOTFIELDTYPE_SELECT) ? POINTER_NOTALLOWED : POINTER_PIVOT_DELETE);
396 
397     // after calculating pointer style, check if target is selection window
398     if( pTargetWindow && (pTargetWindow->GetType() == PIVOTFIELDTYPE_SELECT) )
399         pTargetWindow = 0;
400 
401     // notify windows about tracking
402     if( mpDropWindow != pTargetWindow )
403     {
404         // tracking window changed
405         if( mpDropWindow )
406             mpDropWindow->NotifyEndTracking( ENDTRACKING_SUSPEND );
407         if( pTargetWindow )
408             pTargetWindow->NotifyStartTracking();
409         mpDropWindow = pTargetWindow;
410     }
411     if( mpDropWindow )
412         mpDropWindow->NotifyTracking( rDialogPos - pTargetWindow->GetPosPixel() );
413 
414     // end tracking: move or remove field
415     if( rTEvt.IsTrackingEnded() )
416     {
417         bool bCancelled = rTEvt.IsTrackingCanceled();
418         if( mpDropWindow )
419         {
420             mpDropWindow->NotifyEndTracking( bCancelled ? ENDTRACKING_CANCEL : ENDTRACKING_DROP );
421             if( !bCancelled )
422             {
423                 size_t nInsertIndex = mpDropWindow->GetDropIndex( rDialogPos - mpDropWindow->GetPosPixel() );
424                 bool bMoved = MoveField( *mpTrackingWindow, *mpDropWindow, nInsertIndex, true );
425                 // focus drop window, if move was successful, otherwise back to source window
426                 GrabFieldFocus( bMoved ? *mpDropWindow : *mpTrackingWindow );
427             }
428         }
429         else
430         {
431             // drop target invalid (outside field windows): remove tracked field
432             if( !bCancelled )
433                 mpTrackingWindow->RemoveSelectedField();
434             // focus source window (or another window, if it is empty now)
435             GrabFieldFocus( *mpTrackingWindow );
436         }
437         eTargetPointer = POINTER_ARROW;
438         if( mpTrackingWindow != mpDropWindow )
439             mpTrackingWindow->NotifyEndTracking( ENDTRACKING_CANCEL );
440         mpTrackingWindow = mpDropWindow = 0;
441     }
442     SetPointer( eTargetPointer );
443 }
444 
445 void ScPivotLayoutDlg::SetReference( const ScRange& rRef, ScDocument* pDocP )
446 {
447     if( !mbRefInputMode || !mpActiveEdit )
448         return;
449 
450     if( rRef.aStart != rRef.aEnd )
451         RefInputStart( mpActiveEdit );
452 
453     if( mpActiveEdit == &maEdInPos )
454     {
455         String aRefStr;
456         rRef.Format( aRefStr, SCR_ABS_3D, pDocP, pDocP->GetAddressConvention() );
457         mpActiveEdit->SetRefString( aRefStr );
458     }
459     else if( mpActiveEdit == &maEdOutPos )
460     {
461         String aRefStr;
462         rRef.aStart.Format( aRefStr, STD_FORMAT, pDocP, pDocP->GetAddressConvention() );
463         mpActiveEdit->SetRefString( aRefStr );
464     }
465 }
466 
467 sal_Bool ScPivotLayoutDlg::IsRefInputMode() const
468 {
469     return mbRefInputMode;
470 }
471 
472 void ScPivotLayoutDlg::SetActive()
473 {
474 	if( mbRefInputMode )
475 	{
476         if( mpActiveEdit )
477             mpActiveEdit->GrabFocus();
478 
479         if( mpActiveEdit == &maEdInPos )
480             EdInModifyHdl( 0 );
481         else if( mpActiveEdit == &maEdOutPos )
482             EdOutModifyHdl( 0 );
483 	}
484 	else
485 	{
486 		GrabFocus();
487 	}
488 
489 	RefInputDone();
490 }
491 
492 sal_Bool ScPivotLayoutDlg::Close()
493 {
494 	return DoClose( ScPivotLayoutWrapper::GetChildWindowId() );
495 }
496 
497 // private --------------------------------------------------------------------
498 
499 ScPivotFieldWindow& ScPivotLayoutDlg::GetFieldWindow( ScPivotFieldType eFieldType )
500 {
501     switch( eFieldType )
502     {
503         case PIVOTFIELDTYPE_PAGE:   return maWndPage;
504         case PIVOTFIELDTYPE_ROW:    return maWndRow;
505         case PIVOTFIELDTYPE_COL:    return maWndCol;
506         case PIVOTFIELDTYPE_DATA:   return maWndData;
507         default:;
508     }
509     return maWndSelect;
510 }
511 
512 bool ScPivotLayoutDlg::IsInsertAllowed( const ScPivotFieldWindow& rSourceWindow, const ScPivotFieldWindow& rTargetWindow )
513 {
514     if( rTargetWindow.GetType() != PIVOTFIELDTYPE_SELECT )
515     {
516         const ScPivotFuncData* pSourceData = rSourceWindow.GetSelectedFuncData();
517         ScDPLabelData* pLabelData = pSourceData ? GetLabelData( pSourceData->mnCol ) : 0;
518         DBG_ASSERT( pLabelData, "ScPivotLayoutDlg::IsInsertAllowed - label data not found" );
519         if( pLabelData )
520         {
521             sheet::DataPilotFieldOrientation eOrient = sheet::DataPilotFieldOrientation_HIDDEN;
522             switch( rTargetWindow.GetType() )
523             {
524                 case PIVOTFIELDTYPE_PAGE:   eOrient = sheet::DataPilotFieldOrientation_PAGE;    break;
525                 case PIVOTFIELDTYPE_COL:    eOrient = sheet::DataPilotFieldOrientation_COLUMN;  break;
526                 case PIVOTFIELDTYPE_ROW:    eOrient = sheet::DataPilotFieldOrientation_ROW;     break;
527                 case PIVOTFIELDTYPE_DATA:   eOrient = sheet::DataPilotFieldOrientation_DATA;    break;
528                 default:                    return false;
529             }
530             return ScDPObject::IsOrientationAllowed( static_cast< sal_uInt16 >( eOrient ), pLabelData->mnFlags );
531         }
532     }
533     return false;
534 }
535 
536 void ScPivotLayoutDlg::InitFieldWindows()
537 {
538     maLabelData = maPivotData.maLabelArray;
539     maWndSelect.ReadDataLabels( maLabelData );
540     maWndPage.ReadPivotFields( maPivotData.maPageArr );
541     maWndCol.ReadPivotFields( maPivotData.maColArr );
542     maWndRow.ReadPivotFields( maPivotData.maRowArr );
543     maWndData.ReadPivotFields( maPivotData.maDataArr );
544 }
545 
546 void ScPivotLayoutDlg::GrabFieldFocus( ScPivotFieldWindow& rFieldWindow )
547 {
548     if( rFieldWindow.IsEmpty() )
549     {
550         if( maWndSelect.IsEmpty() )
551             maBtnOk.GrabFocus();
552         else
553             maWndSelect.GrabFocus();
554     }
555     else
556         rFieldWindow.GrabFocus();
557 }
558 
559 namespace {
560 
561 void lclFindFieldWindow( ScPivotFieldWindow*& rpFieldWindow, const ScPivotFuncData*& rpFuncData, size_t& rnFieldIndex, ScPivotFieldWindow& rFieldWindow )
562 {
563     ScPivotFuncDataEntry aEntry = rFieldWindow.FindFuncDataByCol( rpFuncData->mnCol );
564     if( aEntry.first )
565     {
566         rpFieldWindow = &rFieldWindow;
567         rpFuncData = aEntry.first;
568         rnFieldIndex = aEntry.second;
569     }
570 }
571 
572 } // namespace
573 
574 bool ScPivotLayoutDlg::MoveField( ScPivotFieldWindow& rSourceWindow, ScPivotFieldWindow& rTargetWindow, size_t nInsertIndex, bool bMoveExisting )
575 {
576     // move inside the same window
577     if( &rSourceWindow == &rTargetWindow )
578         return bMoveExisting && rTargetWindow.MoveSelectedField( nInsertIndex );
579 
580     // do not insert if not supported by target window
581     if( !IsInsertAllowed( rSourceWindow, rTargetWindow ) )
582     {
583         rSourceWindow.RemoveSelectedField();
584         return false;
585     }
586 
587     // move from one window to another window
588     if( const ScPivotFuncData* pSourceData = rSourceWindow.GetSelectedFuncData() )
589     {
590         // move to page/col/row window: try to find existing field in another window
591         ScPivotFieldWindow* pSourceWindow = &rSourceWindow;
592         size_t nSourceIndex = rSourceWindow.GetSelectedIndex();
593         if( rTargetWindow.GetType() != PIVOTFIELDTYPE_DATA )
594         {
595             lclFindFieldWindow( pSourceWindow, pSourceData, nSourceIndex, maWndPage );
596             lclFindFieldWindow( pSourceWindow, pSourceData, nSourceIndex, maWndCol );
597             lclFindFieldWindow( pSourceWindow, pSourceData, nSourceIndex, maWndRow );
598         }
599 
600         // found in target window: move to new position
601         if( pSourceWindow == &rTargetWindow )
602             return bMoveExisting && pSourceWindow->MoveField( nSourceIndex, nInsertIndex );
603 
604         // insert field into target window
605         rTargetWindow.InsertField( nInsertIndex, *pSourceData );
606         // remove field from source window
607         pSourceWindow->RemoveField( nSourceIndex );
608         // remove field from data window, if it is the original source
609         if( (rSourceWindow.GetType() == PIVOTFIELDTYPE_DATA) && (pSourceWindow->GetType() != PIVOTFIELDTYPE_DATA) )
610             rSourceWindow.RemoveSelectedField();
611 
612         return true;
613     }
614 
615     return false;
616 }
617 
618 // handlers -------------------------------------------------------------------
619 
620 IMPL_LINK( ScPivotLayoutDlg, ClickHdl, PushButton *, pBtn )
621 {
622     if( mpFocusWindow )
623     {
624         /*  Raising sub dialogs (from the NotifyDoubleClick function) triggers
625             VCL child window focus events from this sub dialog which may
626             invalidate the member mpFocusWindow pointing to the target field
627             window. This would cause a crash with the following call to the
628             GrabFieldFocus function, if mpFocusWindow is used directly. */
629         ScPivotFieldWindow& rTargetWindow = *mpFocusWindow;
630 
631         if( pBtn == &maBtnRemove )
632         {
633             rTargetWindow.RemoveSelectedField();
634             // focus back to field window
635             GrabFieldFocus( rTargetWindow );
636         }
637         else if( pBtn == &maBtnOptions )
638     	{
639             NotifyDoubleClick( rTargetWindow );
640             // focus back to field window
641             GrabFieldFocus( rTargetWindow );
642         }
643     }
644     return 0;
645 }
646 
647 IMPL_LINK( ScPivotLayoutDlg, OkHdl, OKButton *, EMPTYARG )
648 {
649 	String aOutPosStr = maEdOutPos.GetText();
650 	ScAddress aAdrDest;
651 	bool bToNewTable = maLbOutPos.GetSelectEntryPos() == 1;
652 	sal_uInt16 nResult = !bToNewTable ? aAdrDest.Parse( aOutPosStr, mpDoc, mpDoc->GetAddressConvention() ) : 0;
653 
654 	if( bToNewTable || ((aOutPosStr.Len() > 0) && ((nResult & SCA_VALID) == SCA_VALID)) )
655 	{
656         ScPivotFieldVector aPageFields, aColFields, aRowFields, aDataFields;
657         maWndPage.WritePivotFields( aPageFields );
658         maWndCol.WritePivotFields( aColFields );
659         maWndRow.WritePivotFields( aRowFields );
660         maWndData.WritePivotFields( aDataFields );
661 
662         // TODO: handle data field in dialog field windows?
663         aRowFields.resize( aRowFields.size() + 1 );
664         aRowFields.back().nCol = PIVOT_DATA_FIELD;
665 
666         ScDPSaveData* pOldSaveData = mxDlgDPObject->GetSaveData();
667 
668 		ScRange aOutRange( aAdrDest );		// bToNewTable is passed separately
669 
670 		ScDPSaveData aSaveData;
671 		aSaveData.SetIgnoreEmptyRows( maBtnIgnEmptyRows.IsChecked() );
672 		aSaveData.SetRepeatIfEmpty( maBtnDetectCat.IsChecked() );
673 		aSaveData.SetColumnGrand( maBtnTotalCol.IsChecked() );
674 		aSaveData.SetRowGrand( maBtnTotalRow.IsChecked() );
675         aSaveData.SetFilterButton( maBtnFilter.IsChecked() );
676         aSaveData.SetDrillDown( maBtnDrillDown.IsChecked() );
677 
678         uno::Reference< sheet::XDimensionsSupplier > xSource = mxDlgDPObject->GetSource();
679 
680         ScDPObject::ConvertOrientation( aSaveData, aPageFields, sheet::DataPilotFieldOrientation_PAGE,   0, 0, 0, xSource, false );
681 		ScDPObject::ConvertOrientation( aSaveData, aColFields,  sheet::DataPilotFieldOrientation_COLUMN, 0, 0, 0, xSource, false );
682 		ScDPObject::ConvertOrientation( aSaveData, aRowFields,  sheet::DataPilotFieldOrientation_ROW,    0, 0, 0, xSource, false );
683 		ScDPObject::ConvertOrientation( aSaveData, aDataFields, sheet::DataPilotFieldOrientation_DATA,   0, 0, 0, xSource, false, &aColFields, &aRowFields, &aPageFields );
684 
685         for( ScDPLabelDataVector::const_iterator aIt = maLabelData.begin(), aEnd = maLabelData.end(); aIt != aEnd; ++aIt )
686         {
687             if( ScDPSaveDimension* pDim = aSaveData.GetExistingDimensionByName( aIt->maName ) )
688             {
689                 pDim->SetUsedHierarchy( aIt->mnUsedHier );
690                 pDim->SetShowEmpty( aIt->mbShowAll );
691                 pDim->SetSortInfo( &aIt->maSortInfo );
692                 pDim->SetLayoutInfo( &aIt->maLayoutInfo );
693                 pDim->SetAutoShowInfo( &aIt->maShowInfo );
694                 ScDPSaveDimension* pOldDim = NULL;
695                 if (pOldSaveData)
696                 {
697                     // Transfer the existing layout names to new dimension instance.
698                     pOldDim = pOldSaveData->GetExistingDimensionByName(aIt->maName);
699                     if (pOldDim)
700                     {
701                         const OUString* pLayoutName = pOldDim->GetLayoutName();
702                         if (pLayoutName)
703                             pDim->SetLayoutName(*pLayoutName);
704 
705                         const OUString* pSubtotalName = pOldDim->GetSubtotalName();
706                         if (pSubtotalName)
707                             pDim->SetSubtotalName(*pSubtotalName);
708                     }
709                 }
710 
711                 bool bManualSort = ( aIt->maSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL );
712 
713                 // visibility of members
714                 for (::std::vector<ScDPLabelData::Member>::const_iterator itr = aIt->maMembers.begin(), itrEnd = aIt->maMembers.end();
715                       itr != itrEnd; ++itr)
716                 {
717                     ScDPSaveMember* pMember = pDim->GetMemberByName(itr->maName);
718 
719                     // #i40054# create/access members only if flags are not default
720                     // (or in manual sorting mode - to keep the order)
721                     if (bManualSort || !itr->mbVisible || !itr->mbShowDetails)
722                     {
723                         pMember->SetIsVisible(itr->mbVisible);
724                         pMember->SetShowDetails(itr->mbShowDetails);
725                     }
726                     if (pOldDim)
727                     {
728                         // Transfer the existing layout name.
729                         ScDPSaveMember* pOldMember = pOldDim->GetMemberByName(itr->maName);
730                         if (pOldMember)
731                         {
732                             const OUString* pLayoutName = pOldMember->GetLayoutName();
733                             if (pLayoutName)
734                                 pMember->SetLayoutName(*pLayoutName);
735                         }
736                     }
737                 }
738             }
739         }
740         ScDPSaveDimension* pDim = aSaveData.GetDataLayoutDimension();
741         if (pDim && pOldSaveData)
742         {
743             ScDPSaveDimension* pOldDim = pOldSaveData->GetDataLayoutDimension();
744             if (pOldDim)
745             {
746                 const OUString* pLayoutName = pOldDim->GetLayoutName();
747                 if (pLayoutName)
748                     pDim->SetLayoutName(*pLayoutName);
749             }
750         }
751 
752         // also transfer grand total name
753         if (pOldSaveData)
754         {
755             const OUString* pGrandTotalName = pOldSaveData->GetGrandTotalName();
756             if (pGrandTotalName)
757                 aSaveData.SetGrandTotalName(*pGrandTotalName);
758         }
759 
760 		sal_uInt16 nWhichPivot = SC_MOD()->GetPool().GetWhich( SID_PIVOT_TABLE );
761 		ScPivotItem aOutItem( nWhichPivot, &aSaveData, &aOutRange, bToNewTable );
762 
763 		mbRefInputMode = false;		// to allow deselecting when switching sheets
764 
765 		SetDispatcherLock( false );
766 		SwitchToDocument();
767 
768 		//	#95513# don't hide the dialog before executing the slot, instead it is used as
769 		//	parent for message boxes in ScTabViewShell::GetDialogParent
770 
771         const SfxPoolItem* pRet = GetBindings().GetDispatcher()->Execute(
772             SID_PIVOT_TABLE, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD, &aOutItem, 0L, 0L );
773 
774         bool bSuccess = true;
775         if (pRet)
776         {
777             const SfxBoolItem* pItem = dynamic_cast<const SfxBoolItem*>(pRet);
778             if (pItem)
779                 bSuccess = pItem->GetValue();
780         }
781         if (bSuccess)
782             // Table successfully inserted.
783             Close();
784         else
785         {
786             // Table insertion failed.  Keep the dialog open.
787             mbRefInputMode = true;
788             SetDispatcherLock(true);
789         }
790 	}
791 	else
792 	{
793 		if( !maBtnMore.GetState() )
794 			maBtnMore.SetState( true );
795 
796 		ErrorBox( this, WinBits( WB_OK | WB_DEF_OK ), ScGlobal::GetRscString( STR_INVALID_TABREF ) ).Execute();
797 		maEdOutPos.GrabFocus();
798 	}
799 	return 0;
800 }
801 
802 IMPL_LINK( ScPivotLayoutDlg, CancelHdl, CancelButton *, EMPTYARG )
803 {
804 	Close();
805 	return 0;
806 }
807 
808 IMPL_LINK( ScPivotLayoutDlg, MoreClickHdl, MoreButton *, EMPTYARG )
809 {
810 	if ( maBtnMore.GetState() )
811 	{
812 		mbRefInputMode = true;
813         if ( maEdInPos.IsEnabled() )
814         {
815             maEdInPos.Enable();
816             maEdInPos.GrabFocus();
817             maEdInPos.Enable();
818         }
819         else
820         {
821     		maEdOutPos.Enable();
822     		maEdOutPos.GrabFocus();
823             maEdOutPos.Enable();
824         }
825 	}
826 	else
827 	{
828 		mbRefInputMode = false;
829 	}
830 	return 0;
831 }
832 
833 IMPL_LINK( ScPivotLayoutDlg, EdOutModifyHdl, Edit *, EMPTYARG )
834 {
835 	String theCurPosStr = maEdOutPos.GetText();
836 	sal_uInt16 nResult = ScAddress().Parse( theCurPosStr, mpDoc, mpDoc->GetAddressConvention() );
837 
838 	if ( SCA_VALID == (nResult & SCA_VALID) )
839 	{
840 		String*	pStr = 0;
841 		bool bFound	= false;
842 		sal_uInt16 i = 0;
843 		sal_uInt16 nCount = maLbOutPos.GetEntryCount();
844 
845 		for ( i=2; i<nCount && !bFound; i++ )
846 		{
847 			pStr = (String*)maLbOutPos.GetEntryData( i );
848 			bFound = (theCurPosStr == *pStr);
849 		}
850 
851 		if ( bFound )
852 			maLbOutPos.SelectEntryPos( --i );
853 		else
854 			maLbOutPos.SelectEntryPos( 0 );
855 	}
856 	return 0;
857 }
858 
859 
860 IMPL_LINK( ScPivotLayoutDlg, EdInModifyHdl, Edit *, EMPTYARG )
861 {
862     String theCurPosStr = maEdInPos.GetText();
863     sal_uInt16 nResult = ScRange().Parse( theCurPosStr, mpDoc, mpDoc->GetAddressConvention() );
864 
865     // invalid source range
866     if( SCA_VALID != (nResult & SCA_VALID) )
867         return 0;
868 
869     ScRefAddress start, end;
870     ConvertDoubleRef( mpDoc, theCurPosStr, 1, start, end, mpDoc->GetAddressConvention() );
871     ScRange aNewRange( start.GetAddress(), end.GetAddress() );
872     ScSheetSourceDesc inSheet = *mxDlgDPObject->GetSheetDesc();
873 
874     // new range is identical to the current range
875     if( inSheet.aSourceRange == aNewRange )
876         return 0;
877 
878     ScTabViewShell* pTabViewShell = mpViewData->GetViewShell();
879     inSheet.aSourceRange = aNewRange;
880     mxDlgDPObject->SetSheetDesc( inSheet );
881     mxDlgDPObject->FillOldParam( maPivotData );
882     mxDlgDPObject->FillLabelData( maPivotData );
883 
884     // SetDialogDPObject does not take ownership but makes a copy internally
885     pTabViewShell->SetDialogDPObject( mxDlgDPObject.get() );
886 
887     // re-initialize the field windows from the new data
888     InitFieldWindows();
889 
890     return 0;
891 }
892 
893 IMPL_LINK( ScPivotLayoutDlg, SelAreaHdl, ListBox *, EMPTYARG )
894 {
895 	String aString;
896 	sal_uInt16 nSelPos = maLbOutPos.GetSelectEntryPos();
897 	if( nSelPos > 1 )
898 	{
899 		aString = *(String*)maLbOutPos.GetEntryData( nSelPos );
900 	}
901 	else
902 	{
903         // do not allow to specify output position, if target is "new sheet"
904         bool bNewSheet = nSelPos == 1;
905 		maEdOutPos.Enable( !bNewSheet );
906         maRbOutPos.Enable( !bNewSheet );
907 	}
908 
909 	maEdOutPos.SetText( aString );
910 	return 0;
911 }
912 
913 IMPL_LINK( ScPivotLayoutDlg, ChildEventListener, VclWindowEvent*, pEvent )
914 {
915     Window* pWindow = pEvent->GetWindow();
916     // check that this dialog is the parent of the window, to ignore focus events from sub dialogs
917     if( (pEvent->GetId() == VCLEVENT_WINDOW_GETFOCUS) && pWindow && (pWindow->GetParent() == this) )
918     {
919         // check if old window and/or new window are field windows
920         ScPivotFieldWindow* pSourceWindow = mpFocusWindow;
921         ScPivotFieldWindow* pTargetWindow = dynamic_cast< ScPivotFieldWindow* >( pWindow );
922 
923         /*  Enable or disable the Remove/Options buttons. Do nothing if the
924             buttons themselves get the focus.
925             #128113# The TestTool may set the focus into an empty window. Then
926             the Remove/Options buttons must be disabled. */
927         if( (pWindow != &maBtnRemove) && (pWindow != &maBtnOptions) )
928         {
929             bool bEnableButtons = pTargetWindow && (pTargetWindow->GetType() != PIVOTFIELDTYPE_SELECT) && !pTargetWindow->IsEmpty();
930             maBtnRemove.Enable( bEnableButtons );
931             maBtnOptions.Enable( bEnableButtons );
932             /*  Remember the new focus window (will not be changed, if
933                 Remove/Option buttons are getting focus, because they need to
934                 know the field window they are working on). */
935             mpFocusWindow = pTargetWindow;
936         }
937 
938         /*  Move the last selected field to target window, if focus changes via
939             keyboard shortcut. */
940         if( pSourceWindow && pTargetWindow && (pSourceWindow != pTargetWindow) && ((pTargetWindow->GetGetFocusFlags() & GETFOCUS_MNEMONIC) != 0) )
941         {
942             // append field in target window
943             MoveField( *pSourceWindow, *pTargetWindow, pTargetWindow->GetFieldCount(), false );
944             // move cursor in selection window to next field
945             if( pSourceWindow->GetType() == PIVOTFIELDTYPE_SELECT )
946                 pSourceWindow->SelectNextField();
947             // return focus to source window (if it is not empty)
948             GrabFieldFocus( pSourceWindow->IsEmpty() ? *pTargetWindow : *pSourceWindow );
949         }
950 
951         mpActiveEdit = dynamic_cast< ::formula::RefEdit* >( pEvent->GetWindow() );
952     }
953     return 0;
954 }
955 
956 // ============================================================================
957