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