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