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