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 65 OUString lclGetNameWithoutMnemonic( const FixedText& rFixedText ) 66 { 67 return MnemonicGenerator::EraseAllMnemonicChars( rFixedText.GetText() ); 68 } 69 70 } // namespace 71 72 // ============================================================================ 73 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 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 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 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 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 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 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 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 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 463 sal_Bool ScPivotLayoutDlg::IsRefInputMode() const 464 { 465 return mbRefInputMode; 466 } 467 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 488 sal_Bool ScPivotLayoutDlg::Close() 489 { 490 return DoClose( ScPivotLayoutWrapper::GetChildWindowId() ); 491 } 492 493 // private -------------------------------------------------------------------- 494 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 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 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 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 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 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 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 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 798 IMPL_LINK( ScPivotLayoutDlg, CancelHdl, CancelButton *, EMPTYARG ) 799 { 800 Close(); 801 return 0; 802 } 803 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 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 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 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 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