xref: /trunk/main/sc/source/ui/dbgui/fieldwnd.cxx (revision 0f49733d83c767b772ad7a09a1ac70762da0916a)
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