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