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