1cdf0e10cSrcweir /************************************************************************* 2cdf0e10cSrcweir * 3cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4cdf0e10cSrcweir * 5cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6cdf0e10cSrcweir * 7cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8cdf0e10cSrcweir * 9cdf0e10cSrcweir * This file is part of OpenOffice.org. 10cdf0e10cSrcweir * 11cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14cdf0e10cSrcweir * 15cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20cdf0e10cSrcweir * 21cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25cdf0e10cSrcweir * 26cdf0e10cSrcweir ************************************************************************/ 27cdf0e10cSrcweir 28cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29cdf0e10cSrcweir #include "precompiled_sc.hxx" 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include "fieldwnd.hxx" 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <tools/debug.hxx> 34cdf0e10cSrcweir #include <vcl/decoview.hxx> 35cdf0e10cSrcweir #include <vcl/help.hxx> 36cdf0e10cSrcweir #include <vcl/svapp.hxx> 37cdf0e10cSrcweir #include <vcl/virdev.hxx> 38cdf0e10cSrcweir 39cdf0e10cSrcweir #include "pvlaydlg.hxx" 40cdf0e10cSrcweir #include "AccessibleDataPilotControl.hxx" 41cdf0e10cSrcweir #include "scresid.hxx" 42cdf0e10cSrcweir #include "sc.hrc" 43cdf0e10cSrcweir 44cdf0e10cSrcweir // ============================================================================ 45cdf0e10cSrcweir 46cdf0e10cSrcweir using namespace ::com::sun::star; 47cdf0e10cSrcweir using ::rtl::OUString; 48cdf0e10cSrcweir 49cdf0e10cSrcweir // ============================================================================ 50cdf0e10cSrcweir 51cdf0e10cSrcweir namespace { 52cdf0e10cSrcweir 53cdf0e10cSrcweir /** Line width for insertion cursor in pixels. */ 54cdf0e10cSrcweir const long CURSOR_WIDTH = 3; 55cdf0e10cSrcweir 56cdf0e10cSrcweir /** Number of tracking events before auto scrolling starts. */ 57cdf0e10cSrcweir const size_t INITIAL_TRACKING_DELAY = 20; 58cdf0e10cSrcweir 59cdf0e10cSrcweir } // namespace 60cdf0e10cSrcweir 61cdf0e10cSrcweir // ============================================================================ 62cdf0e10cSrcweir 63cdf0e10cSrcweir ScPivotFieldWindow::ScPivotWindowField::ScPivotWindowField( const ScDPLabelData& rLabelData ) : 64cdf0e10cSrcweir maFuncData( rLabelData.mnCol, rLabelData.mnFuncMask ), 65cdf0e10cSrcweir maFieldName( rLabelData.getDisplayName() ) 66cdf0e10cSrcweir { 67cdf0e10cSrcweir } 68cdf0e10cSrcweir 69cdf0e10cSrcweir ScPivotFieldWindow::ScPivotWindowField::ScPivotWindowField( ScPivotLayoutDlg& rDialog, const ScPivotField& rField, bool bDataWindow ) : 70cdf0e10cSrcweir maFuncData( rField.nCol, rField.nFuncMask, rField.maFieldRef ) 71cdf0e10cSrcweir { 72cdf0e10cSrcweir InitFieldName( rDialog, bDataWindow ); 73cdf0e10cSrcweir } 74cdf0e10cSrcweir 75cdf0e10cSrcweir ScPivotFieldWindow::ScPivotWindowField::ScPivotWindowField( ScPivotLayoutDlg& rDialog, const ScPivotFuncData& rFuncData, bool bDataWindow ) : 76cdf0e10cSrcweir maFuncData( rFuncData ) 77cdf0e10cSrcweir { 78cdf0e10cSrcweir InitFieldName( rDialog, bDataWindow ); 79cdf0e10cSrcweir } 80cdf0e10cSrcweir 81cdf0e10cSrcweir void ScPivotFieldWindow::ScPivotWindowField::InitFieldName( ScPivotLayoutDlg& rDialog, bool bDataWindow ) 82cdf0e10cSrcweir { 83cdf0e10cSrcweir if( maFuncData.mnCol != PIVOT_DATA_FIELD ) 84cdf0e10cSrcweir { 85cdf0e10cSrcweir ScDPLabelData* pLabelData = rDialog.GetLabelData( maFuncData.mnCol ); 86cdf0e10cSrcweir DBG_ASSERT( pLabelData, "ScPivotWindowField::InitFieldName - no label data found" ); 87cdf0e10cSrcweir if( pLabelData ) 88cdf0e10cSrcweir { 89cdf0e10cSrcweir if( bDataWindow ) 90cdf0e10cSrcweir { 91cdf0e10cSrcweir // write original nFuncMask to label data 92cdf0e10cSrcweir pLabelData->mnFuncMask = maFuncData.mnFuncMask; 93cdf0e10cSrcweir // GetFuncString() modifies nFuncMask (e.g. auto to sum or count) 94cdf0e10cSrcweir maFieldName = rDialog.GetFuncString( maFuncData.mnFuncMask, pLabelData->mbIsValue ); 95cdf0e10cSrcweir } 96*0f49733dSMichael Stahl else 97*0f49733dSMichael Stahl maFieldName = OUString(); // #i118111# don't append to previous string 98cdf0e10cSrcweir maFieldName += pLabelData->getDisplayName(); 99cdf0e10cSrcweir } 100cdf0e10cSrcweir } 101cdf0e10cSrcweir } 102cdf0e10cSrcweir 103cdf0e10cSrcweir // ============================================================================ 104cdf0e10cSrcweir 105cdf0e10cSrcweir ScPivotFieldWindow::ScPivotFieldWindow( ScPivotLayoutDlg* pDialog, const ResId& rResId, 106cdf0e10cSrcweir ScrollBar& rScrollBar, FixedText* pFtCaption, const OUString& rName, 107cdf0e10cSrcweir ScPivotFieldType eFieldType, const sal_Char* pcHelpId, PointerStyle eDropPointer, 108cdf0e10cSrcweir size_t nColCount, size_t nRowCount, long nFieldWidthFactor, long nSpaceSize ) : 109cdf0e10cSrcweir Control( pDialog, rResId ), 110cdf0e10cSrcweir mpDialog( pDialog ), 111cdf0e10cSrcweir mpAccessible( 0 ), 112cdf0e10cSrcweir mrScrollBar( rScrollBar ), 113cdf0e10cSrcweir mpFtCaption( pFtCaption ), 114cdf0e10cSrcweir maName( rName ), 115cdf0e10cSrcweir meFieldType( eFieldType ), 116cdf0e10cSrcweir meDropPointer( eDropPointer ), 117cdf0e10cSrcweir mnColCount( nColCount ), 118cdf0e10cSrcweir mnRowCount( nRowCount ), 119cdf0e10cSrcweir mnFirstVisIndex( 0 ), 120cdf0e10cSrcweir mnSelectIndex( 0 ), 121cdf0e10cSrcweir mnInsCursorIndex( PIVOTFIELD_INVALID ), 122cdf0e10cSrcweir mnOldFirstVisIndex( 0 ), 123cdf0e10cSrcweir mnAutoScrollDelay( 0 ), 124cdf0e10cSrcweir mbVertical( eFieldType == PIVOTFIELDTYPE_SELECT ), 125cdf0e10cSrcweir mbIsTrackingSource( false ) 126cdf0e10cSrcweir { 127cdf0e10cSrcweir SetHelpId( pcHelpId ); 128cdf0e10cSrcweir 129cdf0e10cSrcweir mnLineSize = mbVertical ? mnRowCount : mnColCount; 130cdf0e10cSrcweir mnPageSize = mnColCount * mnRowCount; 131cdf0e10cSrcweir 132cdf0e10cSrcweir // a single field is 36x12 appfont units 133cdf0e10cSrcweir maFieldSize = LogicToPixel( Size( 36, 12 ), MapMode( MAP_APPFONT ) ); 134cdf0e10cSrcweir maFieldSize.Width() *= nFieldWidthFactor; 135cdf0e10cSrcweir maSpaceSize = LogicToPixel( Size( nSpaceSize, nSpaceSize ), MapMode( MAP_APPFONT ) ); 136cdf0e10cSrcweir 137cdf0e10cSrcweir // set window size 138cdf0e10cSrcweir long nWinWidth = static_cast< long >( mnColCount * maFieldSize.Width() + (mnColCount - 1) * maSpaceSize.Width() ); 139cdf0e10cSrcweir long nWinHeight = static_cast< long >( mnRowCount * maFieldSize.Height() + (mnRowCount - 1) * maSpaceSize.Height() ); 140cdf0e10cSrcweir SetSizePixel( Size( nWinWidth, nWinHeight ) ); 141cdf0e10cSrcweir 142cdf0e10cSrcweir // scroll bar 143cdf0e10cSrcweir Point aScrollBarPos = GetPosPixel(); 144cdf0e10cSrcweir Size aScrollBarSize( nWinWidth, nWinHeight ); 145cdf0e10cSrcweir if( mbVertical ) 146cdf0e10cSrcweir { 147cdf0e10cSrcweir aScrollBarPos.Y() += nWinHeight + maSpaceSize.Height(); 148cdf0e10cSrcweir aScrollBarSize.Height() = GetSettings().GetStyleSettings().GetScrollBarSize(); 149cdf0e10cSrcweir } 150cdf0e10cSrcweir else 151cdf0e10cSrcweir { 152cdf0e10cSrcweir aScrollBarPos.X() += nWinWidth + maSpaceSize.Width(); 153cdf0e10cSrcweir aScrollBarSize.Width() = GetSettings().GetStyleSettings().GetScrollBarSize(); 154cdf0e10cSrcweir } 155cdf0e10cSrcweir mrScrollBar.SetPosSizePixel( aScrollBarPos, aScrollBarSize ); 156cdf0e10cSrcweir mrScrollBar.SetLineSize( 1 ); 157cdf0e10cSrcweir mrScrollBar.SetPageSize( static_cast< long >( mbVertical ? mnColCount : mnRowCount ) ); 158cdf0e10cSrcweir mrScrollBar.SetVisibleSize( static_cast< long >( mbVertical ? mnColCount : mnRowCount ) ); 159cdf0e10cSrcweir mrScrollBar.SetScrollHdl( LINK( this, ScPivotFieldWindow, ScrollHdl ) ); 160cdf0e10cSrcweir mrScrollBar.SetEndScrollHdl( LINK( this, ScPivotFieldWindow, ScrollHdl ) ); 161cdf0e10cSrcweir } 162cdf0e10cSrcweir 163cdf0e10cSrcweir ScPivotFieldWindow::~ScPivotFieldWindow() 164cdf0e10cSrcweir { 165cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAcc = GetAccessibleControl(); 166cdf0e10cSrcweir if( xAcc.is() ) 167cdf0e10cSrcweir xAcc->dispose(); 168cdf0e10cSrcweir } 169cdf0e10cSrcweir 170cdf0e10cSrcweir void ScPivotFieldWindow::ReadDataLabels( const ScDPLabelDataVector& rLabels ) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir maFields.clear(); 173cdf0e10cSrcweir maFields.reserve( rLabels.size() ); 174cdf0e10cSrcweir for( ScDPLabelDataVector::const_iterator aIt = rLabels.begin(), aEnd = rLabels.end(); aIt != aEnd; ++aIt ) 175cdf0e10cSrcweir { 176cdf0e10cSrcweir ScPivotWindowField aField( *aIt ); 177cdf0e10cSrcweir if( aField.maFieldName.getLength() > 0 ) 178cdf0e10cSrcweir maFields.push_back( aField ); 179cdf0e10cSrcweir } 180cdf0e10cSrcweir Invalidate(); 181cdf0e10cSrcweir } 182cdf0e10cSrcweir 183cdf0e10cSrcweir void ScPivotFieldWindow::ReadPivotFields( const ScPivotFieldVector& rPivotFields ) 184cdf0e10cSrcweir { 185cdf0e10cSrcweir maFields.clear(); 186cdf0e10cSrcweir maFields.reserve( rPivotFields.size() ); 187cdf0e10cSrcweir for( ScPivotFieldVector::const_iterator aIt = rPivotFields.begin(), aEnd = rPivotFields.end(); aIt != aEnd; ++aIt ) 188cdf0e10cSrcweir { 189cdf0e10cSrcweir ScPivotWindowField aField( *mpDialog, *aIt, meFieldType == PIVOTFIELDTYPE_DATA ); 190cdf0e10cSrcweir if( aField.maFieldName.getLength() > 0 ) 191cdf0e10cSrcweir maFields.push_back( aField ); 192cdf0e10cSrcweir } 193cdf0e10cSrcweir Invalidate(); 194cdf0e10cSrcweir } 195cdf0e10cSrcweir 196cdf0e10cSrcweir void ScPivotFieldWindow::WriteFieldNames( ScDPNameVec& rFieldNames ) const 197cdf0e10cSrcweir { 198cdf0e10cSrcweir rFieldNames.clear(); 199cdf0e10cSrcweir rFieldNames.reserve( maFields.size() ); 200cdf0e10cSrcweir // do not use the names stored in maFields, but generate plain display names from label data 201cdf0e10cSrcweir for( ScPivotWindowFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt ) 202cdf0e10cSrcweir { 203cdf0e10cSrcweir if( ScDPLabelData* pLabelData = mpDialog->GetLabelData( aIt->maFuncData.mnCol ) ) 204cdf0e10cSrcweir { 205cdf0e10cSrcweir OUString aDisplayName = pLabelData->getDisplayName(); 206cdf0e10cSrcweir if( aDisplayName.getLength() > 0 ) 207cdf0e10cSrcweir rFieldNames.push_back( aDisplayName ); 208cdf0e10cSrcweir } 209cdf0e10cSrcweir } 210cdf0e10cSrcweir } 211cdf0e10cSrcweir 212cdf0e10cSrcweir void ScPivotFieldWindow::WritePivotFields( ScPivotFieldVector& rPivotFields ) const 213cdf0e10cSrcweir { 214cdf0e10cSrcweir rPivotFields.resize( maFields.size() ); 215cdf0e10cSrcweir ScPivotFieldVector::iterator aOutIt = rPivotFields.begin(); 216cdf0e10cSrcweir for( ScPivotWindowFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt, ++aOutIt ) 217cdf0e10cSrcweir { 218cdf0e10cSrcweir aOutIt->nCol = aIt->maFuncData.mnCol; 219cdf0e10cSrcweir aOutIt->nFuncMask = aIt->maFuncData.mnFuncMask; 220cdf0e10cSrcweir aOutIt->maFieldRef = aIt->maFuncData.maFieldRef; 221cdf0e10cSrcweir } 222cdf0e10cSrcweir } 223cdf0e10cSrcweir 224cdf0e10cSrcweir OUString ScPivotFieldWindow::GetDescription() const 225cdf0e10cSrcweir { 226cdf0e10cSrcweir switch( meFieldType ) 227cdf0e10cSrcweir { 228cdf0e10cSrcweir case PIVOTFIELDTYPE_COL: return String( ScResId( STR_ACC_DATAPILOT_COL_DESCR ) ); 229cdf0e10cSrcweir case PIVOTFIELDTYPE_ROW: return String( ScResId( STR_ACC_DATAPILOT_ROW_DESCR ) ); 230cdf0e10cSrcweir case PIVOTFIELDTYPE_DATA: return String( ScResId( STR_ACC_DATAPILOT_DATA_DESCR ) ); 231cdf0e10cSrcweir case PIVOTFIELDTYPE_SELECT: return String( ScResId( STR_ACC_DATAPILOT_SEL_DESCR ) ); 232cdf0e10cSrcweir default:; 233cdf0e10cSrcweir } 234cdf0e10cSrcweir return OUString(); 235cdf0e10cSrcweir } 236cdf0e10cSrcweir 237cdf0e10cSrcweir OUString ScPivotFieldWindow::GetFieldText( size_t nFieldIndex ) const 238cdf0e10cSrcweir { 239cdf0e10cSrcweir return (nFieldIndex < maFields.size()) ? maFields[ nFieldIndex ].maFieldName : OUString(); 240cdf0e10cSrcweir } 241cdf0e10cSrcweir 242cdf0e10cSrcweir ScPivotFuncDataEntry ScPivotFieldWindow::FindFuncDataByCol( SCCOL nCol ) const 243cdf0e10cSrcweir { 244cdf0e10cSrcweir for( ScPivotWindowFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt ) 245cdf0e10cSrcweir if( aIt->maFuncData.mnCol == nCol ) 246cdf0e10cSrcweir return ScPivotFuncDataEntry( &aIt->maFuncData, aIt - maFields.begin() ); 247cdf0e10cSrcweir return ScPivotFuncDataEntry( 0, PIVOTFIELD_INVALID ); 248cdf0e10cSrcweir } 249cdf0e10cSrcweir 250cdf0e10cSrcweir Point ScPivotFieldWindow::GetFieldPosition( size_t nFieldIndex ) const 251cdf0e10cSrcweir { 252cdf0e10cSrcweir long nRelIndex = static_cast< long >( nFieldIndex ) - mnFirstVisIndex; 253cdf0e10cSrcweir long nCol = static_cast< long >( mbVertical ? (nRelIndex / mnRowCount) : (nRelIndex % mnColCount) ); 254cdf0e10cSrcweir long nRow = static_cast< long >( mbVertical ? (nRelIndex % mnRowCount) : (nRelIndex / mnColCount) ); 255cdf0e10cSrcweir return Point( nCol * (maFieldSize.Width() + maSpaceSize.Width()), nRow * (maFieldSize.Height() + maSpaceSize.Height()) ); 256cdf0e10cSrcweir } 257cdf0e10cSrcweir 258cdf0e10cSrcweir size_t ScPivotFieldWindow::GetFieldIndex( const Point& rWindowPos ) const 259cdf0e10cSrcweir { 260cdf0e10cSrcweir if( (rWindowPos.X() >= 0) && (rWindowPos.Y() >= 0) ) 261cdf0e10cSrcweir { 262cdf0e10cSrcweir long nGridWidth = maFieldSize.Width() + maSpaceSize.Width(); 263cdf0e10cSrcweir long nGridHeight = maFieldSize.Height() + maSpaceSize.Height(); 264cdf0e10cSrcweir size_t nCol = static_cast< size_t >( rWindowPos.X() / nGridWidth ); 265cdf0e10cSrcweir size_t nRow = static_cast< size_t >( rWindowPos.Y() / nGridHeight ); 266cdf0e10cSrcweir if( (nCol < mnColCount) && (nRow < mnRowCount) ) 267cdf0e10cSrcweir { 268cdf0e10cSrcweir long nColOffset = rWindowPos.X() % nGridWidth; 269cdf0e10cSrcweir long nRowOffset = rWindowPos.Y() % nGridHeight; 270cdf0e10cSrcweir // check that passed position is not in the space between the fields 271cdf0e10cSrcweir if( (nColOffset < maFieldSize.Width()) && (nRowOffset < maFieldSize.Height()) ) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir size_t nFieldIndex = mnFirstVisIndex + (mbVertical ? (nCol * mnRowCount + nRow) : (nRow * mnColCount + nCol)); 274cdf0e10cSrcweir return (nFieldIndex < maFields.size()) ? nFieldIndex : PIVOTFIELD_INVALID; 275cdf0e10cSrcweir } 276cdf0e10cSrcweir } 277cdf0e10cSrcweir } 278cdf0e10cSrcweir return PIVOTFIELD_INVALID; 279cdf0e10cSrcweir } 280cdf0e10cSrcweir 281cdf0e10cSrcweir size_t ScPivotFieldWindow::GetDropIndex( const Point& rWindowPos ) const 282cdf0e10cSrcweir { 283cdf0e10cSrcweir if( (rWindowPos.X() >= 0) && (rWindowPos.Y() >= 0) ) 284cdf0e10cSrcweir { 285cdf0e10cSrcweir long nGridWidth = maFieldSize.Width() + maSpaceSize.Width(); 286cdf0e10cSrcweir long nGridHeight = maFieldSize.Height() + maSpaceSize.Height(); 287cdf0e10cSrcweir size_t nCol = static_cast< size_t >( rWindowPos.X() / nGridWidth ); 288cdf0e10cSrcweir size_t nRow = static_cast< size_t >( rWindowPos.Y() / nGridHeight ); 289cdf0e10cSrcweir if( (nCol < mnColCount) && (nRow < mnRowCount) ) 290cdf0e10cSrcweir { 291cdf0e10cSrcweir size_t nFieldIndex = mnFirstVisIndex + (mbVertical ? (nCol * mnRowCount + nRow) : (nRow * mnColCount + nCol)); 292cdf0e10cSrcweir long nColOffset = rWindowPos.X() % nGridWidth; 293cdf0e10cSrcweir long nRowOffset = rWindowPos.Y() % nGridHeight; 294cdf0e10cSrcweir // take next field, if position is in right/lower third 295cdf0e10cSrcweir if( (mnColCount == 1) ? (nRowOffset * 3 > nGridHeight * 2) : (nColOffset * 3 > nGridWidth * 2) ) 296cdf0e10cSrcweir ++nFieldIndex; 297cdf0e10cSrcweir return ::std::min( nFieldIndex, maFields.size() ); 298cdf0e10cSrcweir } 299cdf0e10cSrcweir } 300cdf0e10cSrcweir return maFields.size(); 301cdf0e10cSrcweir } 302cdf0e10cSrcweir 303cdf0e10cSrcweir void ScPivotFieldWindow::GrabFocusAndSelect( size_t nSelectIndex ) 304cdf0e10cSrcweir { 305cdf0e10cSrcweir if( !HasFocus() ) GrabFocus(); 306cdf0e10cSrcweir MoveSelection( nSelectIndex ); 307cdf0e10cSrcweir } 308cdf0e10cSrcweir 309cdf0e10cSrcweir void ScPivotFieldWindow::SelectNextField() 310cdf0e10cSrcweir { 311cdf0e10cSrcweir MoveSelection( NEXT_FIELD ); 312cdf0e10cSrcweir } 313cdf0e10cSrcweir 314cdf0e10cSrcweir void ScPivotFieldWindow::InsertField( size_t nInsertIndex, const ScPivotFuncData& rFuncData ) 315cdf0e10cSrcweir { 316cdf0e10cSrcweir if( (meFieldType != PIVOTFIELDTYPE_SELECT) && (nInsertIndex <= maFields.size()) ) 317cdf0e10cSrcweir { 318cdf0e10cSrcweir size_t nFieldIndex = FindFuncDataByCol( rFuncData.mnCol ).second; 319cdf0e10cSrcweir if( nFieldIndex < maFields.size() ) 320cdf0e10cSrcweir { 321cdf0e10cSrcweir // field exists already in this window, move it to the specified position 322cdf0e10cSrcweir MoveField( nFieldIndex, nInsertIndex ); 323cdf0e10cSrcweir } 324cdf0e10cSrcweir else 325cdf0e10cSrcweir { 326cdf0e10cSrcweir // insert the field into the vector and notify accessibility object 327cdf0e10cSrcweir ScPivotWindowField aField( *mpDialog, rFuncData, meFieldType == PIVOTFIELDTYPE_DATA ); 328cdf0e10cSrcweir if( aField.maFieldName.getLength() > 0 ) 329cdf0e10cSrcweir { 330cdf0e10cSrcweir InsertFieldUnchecked( nInsertIndex, aField ); 331cdf0e10cSrcweir // adjust selection and scroll position 332cdf0e10cSrcweir MoveSelection( nInsertIndex ); 333cdf0e10cSrcweir Invalidate(); 334cdf0e10cSrcweir } 335cdf0e10cSrcweir } 336cdf0e10cSrcweir } 337cdf0e10cSrcweir } 338cdf0e10cSrcweir 339cdf0e10cSrcweir bool ScPivotFieldWindow::RemoveField( size_t nRemoveIndex ) 340cdf0e10cSrcweir { 341cdf0e10cSrcweir if( (meFieldType != PIVOTFIELDTYPE_SELECT) && (nRemoveIndex < maFields.size()) ) 342cdf0e10cSrcweir { 343cdf0e10cSrcweir // remove the field from the vector and notify accessibility object 344cdf0e10cSrcweir RemoveFieldUnchecked( nRemoveIndex ); 345cdf0e10cSrcweir // adjust selection and scroll position, if last field is removed 346cdf0e10cSrcweir if( !maFields.empty() ) 347cdf0e10cSrcweir MoveSelection( (mnSelectIndex < maFields.size()) ? mnSelectIndex : (maFields.size() - 1) ); 348cdf0e10cSrcweir Invalidate(); 349cdf0e10cSrcweir return true; 350cdf0e10cSrcweir } 351cdf0e10cSrcweir return false; 352cdf0e10cSrcweir } 353cdf0e10cSrcweir 354cdf0e10cSrcweir bool ScPivotFieldWindow::MoveField( size_t nFieldIndex, size_t nInsertIndex ) 355cdf0e10cSrcweir { 356cdf0e10cSrcweir /* If field is moved behind current position, insertion index needs to be 357cdf0e10cSrcweir adjusted, because the field is first removed from the vector. This is 358cdf0e10cSrcweir done before nFieldIndex and nInsertIndex are checked for equality, to 359cdf0e10cSrcweir catch the cases "move before ourselves" and "move bedind ourselves" 360cdf0e10cSrcweir which are both no-ops. */ 361cdf0e10cSrcweir if( nFieldIndex < nInsertIndex ) 362cdf0e10cSrcweir --nInsertIndex; 363cdf0e10cSrcweir 364cdf0e10cSrcweir if( (meFieldType != PIVOTFIELDTYPE_SELECT) && (nFieldIndex != nInsertIndex) && (nFieldIndex < maFields.size()) && (nInsertIndex < maFields.size()) ) 365cdf0e10cSrcweir { 366cdf0e10cSrcweir // move the field in the vector and notify accessibility object 367cdf0e10cSrcweir ScPivotWindowField aField = maFields[ nFieldIndex ]; 368cdf0e10cSrcweir RemoveFieldUnchecked( nFieldIndex ); 369cdf0e10cSrcweir InsertFieldUnchecked( nInsertIndex, aField ); 370cdf0e10cSrcweir // adjust selection and scroll position 371cdf0e10cSrcweir MoveSelection( nInsertIndex ); 372cdf0e10cSrcweir Invalidate(); 373cdf0e10cSrcweir return true; 374cdf0e10cSrcweir } 375cdf0e10cSrcweir return false; 376cdf0e10cSrcweir } 377cdf0e10cSrcweir 378cdf0e10cSrcweir const ScPivotFuncData* ScPivotFieldWindow::GetSelectedFuncData() const 379cdf0e10cSrcweir { 380cdf0e10cSrcweir return (mnSelectIndex < maFields.size()) ? &maFields[ mnSelectIndex ].maFuncData : 0; 381cdf0e10cSrcweir } 382cdf0e10cSrcweir 383cdf0e10cSrcweir void ScPivotFieldWindow::ModifySelectedField( const ScPivotFuncData& rFuncData ) 384cdf0e10cSrcweir { 385cdf0e10cSrcweir if( mnSelectIndex < maFields.size() ) 386cdf0e10cSrcweir { 387cdf0e10cSrcweir maFields[ mnSelectIndex ].maFuncData = rFuncData; 388cdf0e10cSrcweir maFields[ mnSelectIndex ].InitFieldName( *mpDialog, meFieldType == PIVOTFIELDTYPE_DATA ); 389cdf0e10cSrcweir Invalidate(); 390cdf0e10cSrcweir } 391cdf0e10cSrcweir } 392cdf0e10cSrcweir 393cdf0e10cSrcweir bool ScPivotFieldWindow::RemoveSelectedField() 394cdf0e10cSrcweir { 395cdf0e10cSrcweir return RemoveField( mnSelectIndex ); 396cdf0e10cSrcweir } 397cdf0e10cSrcweir 398cdf0e10cSrcweir bool ScPivotFieldWindow::MoveSelectedField( size_t nInsertIndex ) 399cdf0e10cSrcweir { 400cdf0e10cSrcweir return MoveField( mnSelectIndex, nInsertIndex ); 401cdf0e10cSrcweir } 402cdf0e10cSrcweir 403cdf0e10cSrcweir void ScPivotFieldWindow::NotifyStartTracking() 404cdf0e10cSrcweir { 405cdf0e10cSrcweir // rescue old scrolling index, to be able to restore it when tracking is cancelled 406cdf0e10cSrcweir mnOldFirstVisIndex = mnFirstVisIndex; 407cdf0e10cSrcweir } 408cdf0e10cSrcweir 409cdf0e10cSrcweir void ScPivotFieldWindow::NotifyTracking( const Point& rWindowPos ) 410cdf0e10cSrcweir { 411cdf0e10cSrcweir size_t nFieldIndex = GetDropIndex( rWindowPos ); 412cdf0e10cSrcweir 413cdf0e10cSrcweir // insertion index changed: draw new cursor and exit 414cdf0e10cSrcweir if( nFieldIndex != mnInsCursorIndex ) 415cdf0e10cSrcweir { 416cdf0e10cSrcweir mnInsCursorIndex = nFieldIndex; 417cdf0e10cSrcweir mnAutoScrollDelay = INITIAL_TRACKING_DELAY; 418cdf0e10cSrcweir Invalidate(); 419cdf0e10cSrcweir return; 420cdf0e10cSrcweir } 421cdf0e10cSrcweir 422cdf0e10cSrcweir // insertion index unchanged: countdown for auto scrolling 423cdf0e10cSrcweir if( mnAutoScrollDelay > 0 ) 424cdf0e10cSrcweir { 425cdf0e10cSrcweir --mnAutoScrollDelay; 426cdf0e10cSrcweir return; 427cdf0e10cSrcweir } 428cdf0e10cSrcweir 429cdf0e10cSrcweir // check if tracking happens on first or last field 430cdf0e10cSrcweir long nScrollDelta = 0; 431cdf0e10cSrcweir if( (mnInsCursorIndex > 0) && (mnInsCursorIndex == mnFirstVisIndex) ) 432cdf0e10cSrcweir nScrollDelta = -static_cast< long >( mnLineSize ); 433cdf0e10cSrcweir else if( (mnInsCursorIndex < maFields.size()) && (mnInsCursorIndex == mnFirstVisIndex + mnPageSize) ) 434cdf0e10cSrcweir nScrollDelta = static_cast< long >( mnLineSize ); 435cdf0e10cSrcweir if( nScrollDelta != 0 ) 436cdf0e10cSrcweir { 437cdf0e10cSrcweir // update mnInsCursorIndex, so it will be drawn at the same position after scrolling 438cdf0e10cSrcweir mnInsCursorIndex += nScrollDelta; 439cdf0e10cSrcweir mnFirstVisIndex += nScrollDelta; 440cdf0e10cSrcweir // delay auto scroll by line size, to slow down scrolling in column/page windows 441cdf0e10cSrcweir mnAutoScrollDelay = mnLineSize - 1; 442cdf0e10cSrcweir Invalidate(); 443cdf0e10cSrcweir } 444cdf0e10cSrcweir } 445cdf0e10cSrcweir 446cdf0e10cSrcweir void ScPivotFieldWindow::NotifyEndTracking( ScPivotFieldEndTracking eEndType ) 447cdf0e10cSrcweir { 448cdf0e10cSrcweir if( eEndType != ENDTRACKING_DROP ) 449cdf0e10cSrcweir mnFirstVisIndex = mnOldFirstVisIndex; 450cdf0e10cSrcweir if( eEndType != ENDTRACKING_SUSPEND ) 451cdf0e10cSrcweir { 452cdf0e10cSrcweir mnOldFirstVisIndex = PIVOTFIELD_INVALID; 453cdf0e10cSrcweir mbIsTrackingSource = false; 454cdf0e10cSrcweir } 455cdf0e10cSrcweir mnInsCursorIndex = PIVOTFIELD_INVALID; 456cdf0e10cSrcweir Invalidate(); 457cdf0e10cSrcweir } 458cdf0e10cSrcweir 459cdf0e10cSrcweir // protected ------------------------------------------------------------------ 460cdf0e10cSrcweir 461cdf0e10cSrcweir void ScPivotFieldWindow::Paint( const Rectangle& /*rRect*/ ) 462cdf0e10cSrcweir { 463cdf0e10cSrcweir // prepare a virtual device for buffered painting 464cdf0e10cSrcweir VirtualDevice aVirDev; 465cdf0e10cSrcweir // #i97623# VirtualDevice is always LTR on construction while other windows derive direction from parent 466cdf0e10cSrcweir aVirDev.EnableRTL( IsRTLEnabled() ); 467cdf0e10cSrcweir aVirDev.SetMapMode( MAP_PIXEL ); 468cdf0e10cSrcweir aVirDev.SetOutputSizePixel( GetSizePixel() ); 469cdf0e10cSrcweir Font aFont = GetFont(); 470cdf0e10cSrcweir aFont.SetTransparent( true ); 471cdf0e10cSrcweir aVirDev.SetFont( aFont ); 472cdf0e10cSrcweir 473cdf0e10cSrcweir // draw the background and all fields 474cdf0e10cSrcweir DrawBackground( aVirDev ); 475cdf0e10cSrcweir for( size_t nFieldIndex = mnFirstVisIndex, nEndIndex = mnFirstVisIndex + mnPageSize; nFieldIndex < nEndIndex; ++nFieldIndex ) 476cdf0e10cSrcweir DrawField( aVirDev, nFieldIndex ); 477cdf0e10cSrcweir DrawInsertionCursor( aVirDev ); 478cdf0e10cSrcweir DrawBitmap( Point( 0, 0 ), aVirDev.GetBitmap( Point( 0, 0 ), GetSizePixel() ) ); 479cdf0e10cSrcweir 480cdf0e10cSrcweir // draw field text focus 481cdf0e10cSrcweir if( HasFocus() && (mnSelectIndex < maFields.size()) && (mnFirstVisIndex <= mnSelectIndex) && (mnSelectIndex < mnFirstVisIndex + mnPageSize) ) 482cdf0e10cSrcweir { 483cdf0e10cSrcweir long nFieldWidth = maFieldSize.Width(); 484cdf0e10cSrcweir long nSelectionWidth = Min( GetTextWidth( maFields[ mnSelectIndex ].maFieldName ) + 4, nFieldWidth - 6 ); 485cdf0e10cSrcweir Rectangle aSelection( 486cdf0e10cSrcweir GetFieldPosition( mnSelectIndex ) + Point( (nFieldWidth - nSelectionWidth) / 2, 3 ), 487cdf0e10cSrcweir Size( nSelectionWidth, maFieldSize.Height() - 6 ) ); 488cdf0e10cSrcweir InvertTracking( aSelection, SHOWTRACK_SMALL | SHOWTRACK_WINDOW ); 489cdf0e10cSrcweir } 490cdf0e10cSrcweir 491cdf0e10cSrcweir // update scrollbar 492cdf0e10cSrcweir size_t nFieldCount = maFields.size(); 493cdf0e10cSrcweir /* Already show the scrollbar if window is full but no fields are hidden 494cdf0e10cSrcweir (yet). This gives the user the hint that it is now possible to add more 495cdf0e10cSrcweir fields to the window. */ 496cdf0e10cSrcweir mrScrollBar.Show( nFieldCount >= mnPageSize ); 497cdf0e10cSrcweir mrScrollBar.Enable( nFieldCount > mnPageSize ); 498cdf0e10cSrcweir if( mrScrollBar.IsVisible() ) 499cdf0e10cSrcweir { 500cdf0e10cSrcweir mrScrollBar.SetRange( Range( 0, static_cast< long >( (nFieldCount - 1) / mnLineSize + 1 ) ) ); 501cdf0e10cSrcweir mrScrollBar.SetThumbPos( static_cast< long >( mnFirstVisIndex / mnLineSize ) ); 502cdf0e10cSrcweir } 503cdf0e10cSrcweir 504cdf0e10cSrcweir /* Exclude empty fields from tab chain, but do not disable them. They need 505cdf0e10cSrcweir to be enabled because they still act as target for field movement via 506cdf0e10cSrcweir keyboard shortcuts. */ 507cdf0e10cSrcweir WinBits nMask = ~(WB_TABSTOP | WB_NOTABSTOP); 508cdf0e10cSrcweir SetStyle( (GetStyle() & nMask) | (IsEmpty() ? WB_NOTABSTOP : WB_TABSTOP) ); 509cdf0e10cSrcweir } 510cdf0e10cSrcweir 511cdf0e10cSrcweir void ScPivotFieldWindow::StateChanged( StateChangedType nStateChange ) 512cdf0e10cSrcweir { 513cdf0e10cSrcweir Control::StateChanged( nStateChange ); 514cdf0e10cSrcweir 515cdf0e10cSrcweir if( nStateChange == STATE_CHANGE_INITSHOW ) 516cdf0e10cSrcweir { 517cdf0e10cSrcweir /* After the fixed text associated to this control has received its 518cdf0e10cSrcweir unique mnemonic from VCL dialog initialization code, put this text 519cdf0e10cSrcweir into the field windows. 520cdf0e10cSrcweir #124828# Hiding the FixedTexts and clearing the tab stop style bits 521cdf0e10cSrcweir has to be done after assigning the mnemonics, but Paint() is too 522cdf0e10cSrcweir late, because the test tool may send key events to the dialog when 523cdf0e10cSrcweir it isn't visible. Mnemonics are assigned in Dialog::StateChanged() 524cdf0e10cSrcweir for STATE_CHANGE_INITSHOW, so this can be done immediately 525cdf0e10cSrcweir afterwards. */ 526cdf0e10cSrcweir if( mpFtCaption ) 527cdf0e10cSrcweir { 528cdf0e10cSrcweir SetText( mpFtCaption->GetText() ); 529cdf0e10cSrcweir mpFtCaption->Hide(); 530cdf0e10cSrcweir } 531cdf0e10cSrcweir } 532cdf0e10cSrcweir } 533cdf0e10cSrcweir 534cdf0e10cSrcweir void ScPivotFieldWindow::DataChanged( const DataChangedEvent& rDCEvt ) 535cdf0e10cSrcweir { 536cdf0e10cSrcweir Control::DataChanged( rDCEvt ); 537cdf0e10cSrcweir if( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) 538cdf0e10cSrcweir Invalidate(); 539cdf0e10cSrcweir } 540cdf0e10cSrcweir 541cdf0e10cSrcweir void ScPivotFieldWindow::KeyInput( const KeyEvent& rKEvt ) 542cdf0e10cSrcweir { 543cdf0e10cSrcweir bool bKeyEvaluated = false; 544cdf0e10cSrcweir 545cdf0e10cSrcweir if( !maFields.empty() ) 546cdf0e10cSrcweir { 547cdf0e10cSrcweir const KeyCode& rKeyCode = rKEvt.GetKeyCode(); 548cdf0e10cSrcweir sal_uInt16 nCode = rKeyCode.GetCode(); 549cdf0e10cSrcweir 550cdf0e10cSrcweir // do not move fields in selection window 551cdf0e10cSrcweir if( rKeyCode.IsMod1() && (meFieldType != PIVOTFIELDTYPE_SELECT) ) 552cdf0e10cSrcweir { 553cdf0e10cSrcweir bKeyEvaluated = true; 554cdf0e10cSrcweir switch( nCode ) 555cdf0e10cSrcweir { 556cdf0e10cSrcweir case KEY_UP: MoveSelectedField( mbVertical ? PREV_FIELD : PREV_LINE ); break; 557cdf0e10cSrcweir case KEY_DOWN: MoveSelectedField( mbVertical ? NEXT_FIELD : NEXT_LINE ); break; 558cdf0e10cSrcweir case KEY_LEFT: MoveSelectedField( mbVertical ? PREV_LINE : PREV_FIELD ); break; 559cdf0e10cSrcweir case KEY_RIGHT: MoveSelectedField( mbVertical ? NEXT_LINE : NEXT_FIELD ); break; 560cdf0e10cSrcweir case KEY_HOME: MoveSelectedField( FIRST_FIELD ); break; 561cdf0e10cSrcweir case KEY_END: MoveSelectedField( LAST_FIELD ); break; 562cdf0e10cSrcweir default: bKeyEvaluated = false; 563cdf0e10cSrcweir } 564cdf0e10cSrcweir } 565cdf0e10cSrcweir else 566cdf0e10cSrcweir { 567cdf0e10cSrcweir bKeyEvaluated = true; 568cdf0e10cSrcweir switch( nCode ) 569cdf0e10cSrcweir { 570cdf0e10cSrcweir case KEY_UP: MoveSelection( mbVertical ? PREV_FIELD : PREV_LINE ); break; 571cdf0e10cSrcweir case KEY_DOWN: MoveSelection( mbVertical ? NEXT_FIELD : NEXT_LINE ); break; 572cdf0e10cSrcweir case KEY_LEFT: MoveSelection( mbVertical ? PREV_LINE : PREV_FIELD ); break; 573cdf0e10cSrcweir case KEY_RIGHT: MoveSelection( mbVertical ? NEXT_LINE : NEXT_FIELD ); break; 574cdf0e10cSrcweir case KEY_PAGEUP: MoveSelection( PREV_PAGE ); break; 575cdf0e10cSrcweir case KEY_PAGEDOWN: MoveSelection( NEXT_PAGE ); break; 576cdf0e10cSrcweir case KEY_HOME: MoveSelection( FIRST_FIELD ); break; 577cdf0e10cSrcweir case KEY_END: MoveSelection( LAST_FIELD ); break; 578cdf0e10cSrcweir // delete field per DEL key - dialog needs to change focus if window becomes empty 579cdf0e10cSrcweir case KEY_DELETE: RemoveSelectedField(); mpDialog->NotifyFieldRemoved( *this ); break; 580cdf0e10cSrcweir default: bKeyEvaluated = false; 581cdf0e10cSrcweir } 582cdf0e10cSrcweir } 583cdf0e10cSrcweir } 584cdf0e10cSrcweir 585cdf0e10cSrcweir if( !bKeyEvaluated ) 586cdf0e10cSrcweir Control::KeyInput( rKEvt ); 587cdf0e10cSrcweir } 588cdf0e10cSrcweir 589cdf0e10cSrcweir void ScPivotFieldWindow::MouseButtonDown( const MouseEvent& rMEvt ) 590cdf0e10cSrcweir { 591cdf0e10cSrcweir if( rMEvt.IsLeft() ) 592cdf0e10cSrcweir { 593cdf0e10cSrcweir size_t nNewSelectIndex = GetFieldIndex( rMEvt.GetPosPixel() ); 594cdf0e10cSrcweir if( nNewSelectIndex < maFields.size() ) 595cdf0e10cSrcweir { 596cdf0e10cSrcweir // grabbing after GetFieldIndex() will prevent to focus empty window 597cdf0e10cSrcweir GrabFocusAndSelect( nNewSelectIndex ); 598cdf0e10cSrcweir if( rMEvt.GetClicks() == 1 ) 599cdf0e10cSrcweir { 600cdf0e10cSrcweir // one click: start tracking 601cdf0e10cSrcweir mbIsTrackingSource = true; 602cdf0e10cSrcweir mnOldFirstVisIndex = mnFirstVisIndex; 603cdf0e10cSrcweir mpDialog->NotifyStartTracking( *this ); 604cdf0e10cSrcweir } 605cdf0e10cSrcweir else 606cdf0e10cSrcweir { 607cdf0e10cSrcweir // two clicks: open field options dialog 608cdf0e10cSrcweir mpDialog->NotifyDoubleClick( *this ); 609cdf0e10cSrcweir } 610cdf0e10cSrcweir } 611cdf0e10cSrcweir } 612cdf0e10cSrcweir } 613cdf0e10cSrcweir 614cdf0e10cSrcweir void ScPivotFieldWindow::RequestHelp( const HelpEvent& rHEvt ) 615cdf0e10cSrcweir { 616cdf0e10cSrcweir if( (rHEvt.GetMode() & HELPMODE_QUICK) != 0 ) 617cdf0e10cSrcweir { 618cdf0e10cSrcweir // show a tooltip with full field name, if field text is clipped 619cdf0e10cSrcweir size_t nFieldIndex = GetFieldIndex( rHEvt.GetMousePosPixel() - GetPosPixel() ); 620cdf0e10cSrcweir if( (nFieldIndex < maFields.size()) && maFields[ nFieldIndex ].mbClipped ) 621cdf0e10cSrcweir { 622cdf0e10cSrcweir Rectangle aRect( rHEvt.GetMousePosPixel(), GetSizePixel() ); 623cdf0e10cSrcweir Help::ShowQuickHelp( this, aRect, maFields[ nFieldIndex ].maFieldName ); 624cdf0e10cSrcweir return; 625cdf0e10cSrcweir } 626cdf0e10cSrcweir } 627cdf0e10cSrcweir Control::RequestHelp( rHEvt ); 628cdf0e10cSrcweir } 629cdf0e10cSrcweir 630cdf0e10cSrcweir void ScPivotFieldWindow::GetFocus() 631cdf0e10cSrcweir { 632cdf0e10cSrcweir Control::GetFocus(); 633cdf0e10cSrcweir Invalidate(); 634cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAcc = GetAccessibleControl(); 635cdf0e10cSrcweir if( xAcc.is() ) 636cdf0e10cSrcweir xAcc->GotFocus(); 637cdf0e10cSrcweir } 638cdf0e10cSrcweir 639cdf0e10cSrcweir void ScPivotFieldWindow::LoseFocus() 640cdf0e10cSrcweir { 641cdf0e10cSrcweir Control::LoseFocus(); 642cdf0e10cSrcweir Invalidate(); 643cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAcc = GetAccessibleControl(); 644cdf0e10cSrcweir if( xAcc.is() ) 645cdf0e10cSrcweir xAcc->LostFocus(); 646cdf0e10cSrcweir } 647cdf0e10cSrcweir 648cdf0e10cSrcweir uno::Reference< accessibility::XAccessible > ScPivotFieldWindow::CreateAccessible() 649cdf0e10cSrcweir { 650cdf0e10cSrcweir mpAccessible = new ScAccessibleDataPilotControl( GetAccessibleParentWindow()->GetAccessible(), this ); 651cdf0e10cSrcweir uno::Reference< accessibility::XAccessible > xReturn( mpAccessible ); 652cdf0e10cSrcweir mpAccessible->Init(); 653cdf0e10cSrcweir mxAccessible = xReturn; 654cdf0e10cSrcweir return xReturn; 655cdf0e10cSrcweir } 656cdf0e10cSrcweir 657cdf0e10cSrcweir // private -------------------------------------------------------------------- 658cdf0e10cSrcweir 659cdf0e10cSrcweir size_t ScPivotFieldWindow::RecalcVisibleIndex( size_t nSelectIndex ) const 660cdf0e10cSrcweir { 661cdf0e10cSrcweir // calculate a scrolling offset that shows the selected field 662cdf0e10cSrcweir size_t nNewFirstVisIndex = mnFirstVisIndex; 663cdf0e10cSrcweir if( nSelectIndex < nNewFirstVisIndex ) 664cdf0e10cSrcweir nNewFirstVisIndex = static_cast< size_t >( (nSelectIndex / mnLineSize) * mnLineSize ); 665cdf0e10cSrcweir else if( nSelectIndex >= nNewFirstVisIndex + mnPageSize ) 666cdf0e10cSrcweir nNewFirstVisIndex = static_cast< size_t >( (nSelectIndex / mnLineSize + 1) * mnLineSize ) - mnPageSize; 667cdf0e10cSrcweir // check if there are complete empty lines in the bottom/right 668cdf0e10cSrcweir size_t nMaxFirstVisIndex = (maFields.size() <= mnPageSize) ? 0 : (((maFields.size() - 1) / mnLineSize + 1) * mnLineSize - mnPageSize); 669cdf0e10cSrcweir return ::std::min( nNewFirstVisIndex, nMaxFirstVisIndex ); 670cdf0e10cSrcweir } 671cdf0e10cSrcweir 672cdf0e10cSrcweir void ScPivotFieldWindow::SetSelectionUnchecked( size_t nSelectIndex, size_t nFirstVisIndex ) 673cdf0e10cSrcweir { 674cdf0e10cSrcweir if( !maFields.empty() && (nSelectIndex < maFields.size()) ) 675cdf0e10cSrcweir { 676cdf0e10cSrcweir bool bScrollPosChanged = mnFirstVisIndex != nFirstVisIndex; 677cdf0e10cSrcweir bool bSelectionChanged = mnSelectIndex != nSelectIndex; 678cdf0e10cSrcweir 679cdf0e10cSrcweir sal_Int32 nOldSelected = static_cast< sal_Int32 >( mnSelectIndex ); 680cdf0e10cSrcweir mnFirstVisIndex = nFirstVisIndex; 681cdf0e10cSrcweir mnSelectIndex = nSelectIndex; 682cdf0e10cSrcweir 683cdf0e10cSrcweir if( bScrollPosChanged || bSelectionChanged ) 684cdf0e10cSrcweir Invalidate(); 685cdf0e10cSrcweir 686cdf0e10cSrcweir // TODO: accessibility action for changed scrolling position? 687cdf0e10cSrcweir 688cdf0e10cSrcweir // notify accessibility object about changed selection 689cdf0e10cSrcweir if( bSelectionChanged && HasFocus() ) 690cdf0e10cSrcweir { 691cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAcc = GetAccessibleControl(); 692cdf0e10cSrcweir if( xAcc.is() ) 693cdf0e10cSrcweir xAcc->FieldFocusChange( nOldSelected, static_cast< sal_Int32 >( mnSelectIndex ) ); 694cdf0e10cSrcweir } 695cdf0e10cSrcweir } 696cdf0e10cSrcweir } 697cdf0e10cSrcweir 698cdf0e10cSrcweir void ScPivotFieldWindow::MoveSelection( size_t nSelectIndex ) 699cdf0e10cSrcweir { 700cdf0e10cSrcweir if( nSelectIndex < maFields.size() ) 701cdf0e10cSrcweir SetSelectionUnchecked( nSelectIndex, RecalcVisibleIndex( nSelectIndex ) ); 702cdf0e10cSrcweir } 703cdf0e10cSrcweir 704cdf0e10cSrcweir void ScPivotFieldWindow::MoveSelection( MoveType eMoveType ) 705cdf0e10cSrcweir { 706cdf0e10cSrcweir if( maFields.empty() ) 707cdf0e10cSrcweir return; 708cdf0e10cSrcweir 709cdf0e10cSrcweir size_t nLastIndex = maFields.size() - 1; 710cdf0e10cSrcweir size_t nNewSelectIndex = mnSelectIndex; 711cdf0e10cSrcweir switch( eMoveType ) 712cdf0e10cSrcweir { 713cdf0e10cSrcweir case PREV_FIELD: 714cdf0e10cSrcweir nNewSelectIndex = (nNewSelectIndex > 0) ? (nNewSelectIndex - 1) : 0; 715cdf0e10cSrcweir break; 716cdf0e10cSrcweir case NEXT_FIELD: 717cdf0e10cSrcweir nNewSelectIndex = (nNewSelectIndex < nLastIndex) ? (nNewSelectIndex + 1) : nLastIndex; 718cdf0e10cSrcweir break; 719cdf0e10cSrcweir case PREV_LINE: 720cdf0e10cSrcweir nNewSelectIndex = (nNewSelectIndex > mnLineSize) ? (nNewSelectIndex - mnLineSize) : 0; 721cdf0e10cSrcweir break; 722cdf0e10cSrcweir case NEXT_LINE: 723cdf0e10cSrcweir nNewSelectIndex = (nNewSelectIndex + mnLineSize < nLastIndex) ? (nNewSelectIndex + mnLineSize) : nLastIndex; 724cdf0e10cSrcweir break; 725cdf0e10cSrcweir case PREV_PAGE: 726cdf0e10cSrcweir nNewSelectIndex = (nNewSelectIndex > mnPageSize) ? (nNewSelectIndex - mnPageSize) : 0; 727cdf0e10cSrcweir break; 728cdf0e10cSrcweir case NEXT_PAGE: 729cdf0e10cSrcweir nNewSelectIndex = (nNewSelectIndex + mnPageSize < nLastIndex) ? (nNewSelectIndex + mnPageSize) : nLastIndex; 730cdf0e10cSrcweir break; 731cdf0e10cSrcweir case FIRST_FIELD: 732cdf0e10cSrcweir nNewSelectIndex = 0; 733cdf0e10cSrcweir break; 734cdf0e10cSrcweir case LAST_FIELD: 735cdf0e10cSrcweir nNewSelectIndex = nLastIndex; 736cdf0e10cSrcweir break; 737cdf0e10cSrcweir } 738cdf0e10cSrcweir 739cdf0e10cSrcweir // SetSelectionUnchecked() redraws the control and updates the scrollbar 740cdf0e10cSrcweir SetSelectionUnchecked( nNewSelectIndex, RecalcVisibleIndex( nNewSelectIndex ) ); 741cdf0e10cSrcweir } 742cdf0e10cSrcweir 743cdf0e10cSrcweir void ScPivotFieldWindow::MoveSelectedField( MoveType eMoveType ) 744cdf0e10cSrcweir { 745cdf0e10cSrcweir if( mnSelectIndex < maFields.size() ) 746cdf0e10cSrcweir { 747cdf0e10cSrcweir // find position to insert the field by changing the selection first 748cdf0e10cSrcweir size_t nOldSelectIndex = mnSelectIndex; 749cdf0e10cSrcweir MoveSelection( eMoveType ); 750cdf0e10cSrcweir MoveField( nOldSelectIndex, (nOldSelectIndex < mnSelectIndex) ? (mnSelectIndex + 1) : mnSelectIndex ); 751cdf0e10cSrcweir } 752cdf0e10cSrcweir } 753cdf0e10cSrcweir 754cdf0e10cSrcweir void ScPivotFieldWindow::InsertFieldUnchecked( size_t nInsertIndex, const ScPivotWindowField& rField ) 755cdf0e10cSrcweir { 756cdf0e10cSrcweir maFields.insert( maFields.begin() + nInsertIndex, rField ); 757cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAcc = GetAccessibleControl(); 758cdf0e10cSrcweir if( xAcc.is() ) 759cdf0e10cSrcweir xAcc->AddField( static_cast< sal_Int32 >( nInsertIndex ) ); 760cdf0e10cSrcweir } 761cdf0e10cSrcweir 762cdf0e10cSrcweir void ScPivotFieldWindow::RemoveFieldUnchecked( size_t nRemoveIndex ) 763cdf0e10cSrcweir { 764cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAcc = GetAccessibleControl(); 765cdf0e10cSrcweir if( xAcc.is() ) 766cdf0e10cSrcweir xAcc->RemoveField( static_cast< sal_Int32 >( nRemoveIndex ) ); 767cdf0e10cSrcweir maFields.erase( maFields.begin() + nRemoveIndex ); 768cdf0e10cSrcweir } 769cdf0e10cSrcweir 770cdf0e10cSrcweir void ScPivotFieldWindow::DrawBackground( OutputDevice& rDev ) 771cdf0e10cSrcweir { 772cdf0e10cSrcweir Size aDevSize = rDev.GetOutputSizePixel(); 773cdf0e10cSrcweir const StyleSettings& rStyleSett = GetSettings().GetStyleSettings(); 774cdf0e10cSrcweir 775cdf0e10cSrcweir if( meFieldType == PIVOTFIELDTYPE_SELECT ) 776cdf0e10cSrcweir { 777cdf0e10cSrcweir rDev.SetLineColor(); 778cdf0e10cSrcweir rDev.SetFillColor( rStyleSett.GetFaceColor() ); 779cdf0e10cSrcweir rDev.DrawRect( Rectangle( Point( 0, 0 ), aDevSize ) ); 780cdf0e10cSrcweir } 781cdf0e10cSrcweir else 782cdf0e10cSrcweir { 783cdf0e10cSrcweir rDev.SetLineColor( rStyleSett.GetWindowTextColor() ); 784cdf0e10cSrcweir rDev.SetFillColor( rStyleSett.GetWindowColor() ); 785cdf0e10cSrcweir rDev.DrawRect( Rectangle( Point( 0, 0 ), aDevSize ) ); 786cdf0e10cSrcweir 787cdf0e10cSrcweir /* Draw the caption text. This needs some special handling, because we 788cdf0e10cSrcweir support hard line breaks here. This part will draw each line of the 789cdf0e10cSrcweir text for itself. */ 790cdf0e10cSrcweir rDev.SetTextColor( rStyleSett.GetWindowTextColor() ); 791cdf0e10cSrcweir xub_StrLen nTokenCnt = GetText().GetTokenCount( '\n' ); 792cdf0e10cSrcweir long nY = (aDevSize.Height() - nTokenCnt * rDev.GetTextHeight()) / 2; 793cdf0e10cSrcweir for( xub_StrLen nToken = 0, nStringIx = 0; nToken < nTokenCnt; ++nToken ) 794cdf0e10cSrcweir { 795cdf0e10cSrcweir String aLine = GetText().GetToken( 0, '\n', nStringIx ); 796cdf0e10cSrcweir Point aLinePos( (aDevSize.Width() - rDev.GetCtrlTextWidth( aLine )) / 2, nY ); 797cdf0e10cSrcweir rDev.DrawCtrlText( aLinePos, aLine ); 798cdf0e10cSrcweir nY += rDev.GetTextHeight(); 799cdf0e10cSrcweir } 800cdf0e10cSrcweir } 801cdf0e10cSrcweir } 802cdf0e10cSrcweir 803cdf0e10cSrcweir void ScPivotFieldWindow::DrawField( OutputDevice& rDev, size_t nFieldIndex ) 804cdf0e10cSrcweir { 805cdf0e10cSrcweir if( (nFieldIndex < maFields.size()) && (mnFirstVisIndex <= nFieldIndex) && (nFieldIndex < mnFirstVisIndex + mnPageSize) ) 806cdf0e10cSrcweir { 807cdf0e10cSrcweir // draw the button 808cdf0e10cSrcweir Point aFieldPos = GetFieldPosition( nFieldIndex ); 809cdf0e10cSrcweir bool bFocus = HasFocus() && (nFieldIndex == mnSelectIndex); 810cdf0e10cSrcweir DecorationView aDecoView( &rDev ); 811cdf0e10cSrcweir aDecoView.DrawButton( Rectangle( aFieldPos, maFieldSize ), bFocus ? BUTTON_DRAW_DEFAULT : 0 ); 812cdf0e10cSrcweir 813cdf0e10cSrcweir // #i31600# if text is too long, cut and add ellipsis 814cdf0e10cSrcweir const OUString& rFullText = maFields[ nFieldIndex ].maFieldName; 815cdf0e10cSrcweir OUString aClippedText = rFullText; 816cdf0e10cSrcweir long nLabelWidth = rDev.GetTextWidth( rFullText ); 817cdf0e10cSrcweir if( (maFields[ nFieldIndex ].mbClipped = nLabelWidth + 6 > maFieldSize.Width()) == true ) 818cdf0e10cSrcweir { 819cdf0e10cSrcweir sal_Int32 nMinLen = 0; 820cdf0e10cSrcweir sal_Int32 nMaxLen = rFullText.getLength(); 821cdf0e10cSrcweir bool bFits = false; 822cdf0e10cSrcweir do 823cdf0e10cSrcweir { 824cdf0e10cSrcweir sal_Int32 nCurrLen = (nMinLen + nMaxLen) / 2; 825cdf0e10cSrcweir aClippedText = rFullText.copy( 0, nCurrLen ) + OUString( RTL_CONSTASCII_USTRINGPARAM( "..." ) ); 826cdf0e10cSrcweir nLabelWidth = rDev.GetTextWidth( aClippedText ); 827cdf0e10cSrcweir bFits = nLabelWidth + 6 <= maFieldSize.Width(); 828cdf0e10cSrcweir (bFits ? nMinLen : nMaxLen) = nCurrLen; 829cdf0e10cSrcweir } 830cdf0e10cSrcweir while( !bFits || (nMinLen + 1 < nMaxLen) ); 831cdf0e10cSrcweir } 832cdf0e10cSrcweir 833cdf0e10cSrcweir // draw the button text 834cdf0e10cSrcweir Point aLabelOffset( (maFieldSize.Width() - nLabelWidth) / 2, ::std::max< long >( (maFieldSize.Height() - rDev.GetTextHeight()) / 2, 3 ) ); 835cdf0e10cSrcweir rDev.SetTextColor( GetSettings().GetStyleSettings().GetButtonTextColor() ); 836cdf0e10cSrcweir rDev.DrawText( aFieldPos + aLabelOffset, aClippedText ); 837cdf0e10cSrcweir } 838cdf0e10cSrcweir } 839cdf0e10cSrcweir 840cdf0e10cSrcweir void ScPivotFieldWindow::DrawInsertionCursor( OutputDevice& rDev ) 841cdf0e10cSrcweir { 842cdf0e10cSrcweir if( (mnInsCursorIndex <= maFields.size()) && (mnFirstVisIndex <= mnInsCursorIndex) && (mnInsCursorIndex <= mnFirstVisIndex + mnPageSize) && 843cdf0e10cSrcweir (!mbIsTrackingSource || (mnInsCursorIndex < mnSelectIndex) || (mnInsCursorIndex > mnSelectIndex + 1)) ) 844cdf0e10cSrcweir { 845cdf0e10cSrcweir Color aTextColor = GetSettings().GetStyleSettings().GetButtonTextColor(); 846cdf0e10cSrcweir rDev.SetLineColor( aTextColor ); 847cdf0e10cSrcweir rDev.SetFillColor( aTextColor ); 848cdf0e10cSrcweir 849cdf0e10cSrcweir bool bVerticalCursor = mnColCount > 1; 850cdf0e10cSrcweir long nCursorLength = bVerticalCursor ? maFieldSize.Height() : maFieldSize.Width(); 851cdf0e10cSrcweir 852cdf0e10cSrcweir bool bEndOfLastField = mnInsCursorIndex == mnFirstVisIndex + mnPageSize; 853cdf0e10cSrcweir Point aMainLinePos = GetFieldPosition( bEndOfLastField ? (mnInsCursorIndex - 1) : mnInsCursorIndex ); 854cdf0e10cSrcweir if( bEndOfLastField ) 855cdf0e10cSrcweir (bVerticalCursor ? aMainLinePos.X() : aMainLinePos.Y()) += ((bVerticalCursor ? maFieldSize.Width() : maFieldSize.Height()) - CURSOR_WIDTH); 856cdf0e10cSrcweir else if( (bVerticalCursor ? aMainLinePos.X() : aMainLinePos.Y()) > 0 ) 857cdf0e10cSrcweir (bVerticalCursor ? aMainLinePos.X() : aMainLinePos.Y()) -= ((CURSOR_WIDTH + 1) / 2); 858cdf0e10cSrcweir Size aMainLineSize( bVerticalCursor ? CURSOR_WIDTH : nCursorLength, bVerticalCursor ? nCursorLength : CURSOR_WIDTH ); 859cdf0e10cSrcweir rDev.DrawRect( Rectangle( aMainLinePos, aMainLineSize ) ); 860cdf0e10cSrcweir 861cdf0e10cSrcweir Point aSubLinePos = aMainLinePos; 862cdf0e10cSrcweir (bVerticalCursor ? aSubLinePos.X() : aSubLinePos.Y()) -= CURSOR_WIDTH; 863cdf0e10cSrcweir Size aSubLineSize( bVerticalCursor ? (3 * CURSOR_WIDTH) : CURSOR_WIDTH, bVerticalCursor ? CURSOR_WIDTH : (3 * CURSOR_WIDTH) ); 864cdf0e10cSrcweir rDev.DrawRect( Rectangle( aSubLinePos, aSubLineSize ) ); 865cdf0e10cSrcweir 866cdf0e10cSrcweir (bVerticalCursor ? aSubLinePos.Y() : aSubLinePos.X()) += (nCursorLength - CURSOR_WIDTH); 867cdf0e10cSrcweir rDev.DrawRect( Rectangle( aSubLinePos, aSubLineSize ) ); 868cdf0e10cSrcweir } 869cdf0e10cSrcweir } 870cdf0e10cSrcweir 871cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > ScPivotFieldWindow::GetAccessibleControl() 872cdf0e10cSrcweir { 873cdf0e10cSrcweir ::rtl::Reference< ScAccessibleDataPilotControl > xAccImpl; 874cdf0e10cSrcweir if( mpAccessible ) 875cdf0e10cSrcweir { 876cdf0e10cSrcweir // try to resolve the weak reference mxAccessible 877cdf0e10cSrcweir uno::Reference< accessibility::XAccessible > xAcc = mxAccessible; 878cdf0e10cSrcweir if( xAcc.is() ) 879cdf0e10cSrcweir xAccImpl.set( mpAccessible ); // the rtl reference keeps the object alive 880cdf0e10cSrcweir else 881cdf0e10cSrcweir mpAccessible = 0; // object is dead, forget the pointer 882cdf0e10cSrcweir } 883cdf0e10cSrcweir return xAccImpl; 884cdf0e10cSrcweir } 885cdf0e10cSrcweir 886cdf0e10cSrcweir // handlers ------------------------------------------------------------------- 887cdf0e10cSrcweir 888cdf0e10cSrcweir IMPL_LINK( ScPivotFieldWindow, ScrollHdl, ScrollBar*, pScrollBar ) 889cdf0e10cSrcweir { 890cdf0e10cSrcweir // scrollbar may return negative values, if it is too small 891cdf0e10cSrcweir long nThumbPos = pScrollBar->GetThumbPos(); 892cdf0e10cSrcweir if( nThumbPos >= 0 ) 893cdf0e10cSrcweir { 894cdf0e10cSrcweir size_t nNewFirstVisIndex = static_cast< size_t >( nThumbPos * mnLineSize ); 895cdf0e10cSrcweir // keep the selection index on same relative position inside row/column 896cdf0e10cSrcweir size_t nSelectLineOffset = mnSelectIndex % mnLineSize; 897cdf0e10cSrcweir size_t nNewSelectIndex = mnSelectIndex; 898cdf0e10cSrcweir if( nNewSelectIndex < nNewFirstVisIndex ) 899cdf0e10cSrcweir nNewSelectIndex = nNewFirstVisIndex + nSelectLineOffset; 900cdf0e10cSrcweir else if( nNewSelectIndex >= nNewFirstVisIndex + mnPageSize ) 901cdf0e10cSrcweir nNewSelectIndex = nNewFirstVisIndex + mnPageSize - mnLineSize + nSelectLineOffset; 902cdf0e10cSrcweir nNewSelectIndex = ::std::min( nNewSelectIndex, maFields.size() - 1 ); 903cdf0e10cSrcweir SetSelectionUnchecked( nNewSelectIndex, nNewFirstVisIndex ); 904cdf0e10cSrcweir } 905cdf0e10cSrcweir GrabFocus(); 906cdf0e10cSrcweir return 0; 907cdf0e10cSrcweir } 908cdf0e10cSrcweir 909cdf0e10cSrcweir // ============================================================================ 910