1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef SVTOOLS_TABLECONTROL_IMPL_HXX
25 #define SVTOOLS_TABLECONTROL_IMPL_HXX
26 
27 #include "svtools/table/tablemodel.hxx"
28 #include "svtools/table/tablecontrolinterface.hxx"
29 
30 #include "svtaccessiblefactory.hxx"
31 
32 #include <vcl/seleng.hxx>
33 
34 #include <vector>
35 
36 #include <boost/scoped_ptr.hpp>
37 
38 class ScrollBar;
39 class ScrollBarBox;
40 
41 //........................................................................
42 namespace svt { namespace table
43 {
44 //........................................................................
45 
46     struct MutableColumnMetrics : protected ColumnMetrics
47     {
48         MutableColumnMetrics()
49             :ColumnMetrics()
50         {
51         }
52 
53         MutableColumnMetrics( long const i_startPixel, long const i_endPixel )
54             :ColumnMetrics( i_startPixel, i_endPixel )
55         {
56         }
57 
58         long getStart() const { return nStartPixel; }
59         long getEnd() const { return nEndPixel; }
60 
61         void setEnd( long const i_end ) { nEndPixel = i_end; }
62         void move( long const i_offset ) { nStartPixel += i_offset; nEndPixel += i_offset; }
63 
64         long getWidth() const { return nEndPixel - nStartPixel; }
65 
66         ColumnMetrics const & operator()() { return *this; }
67     };
68 
69     struct ColumnInfoPositionLess
70     {
71         bool operator()( MutableColumnMetrics const& i_colInfo, long const i_position )
72         {
73             return i_colInfo.getEnd() < i_position;
74         }
75         bool operator()( long const i_position, MutableColumnMetrics const& i_colInfo )
76         {
77             return i_position < i_colInfo.getStart();
78         }
79     };
80 
81     typedef ::std::vector< MutableColumnMetrics >    ColumnPositions;
82 
83     class TableControl;
84     class TableDataWindow;
85     class TableFunctionSet;
86 
87     //====================================================================
88 	//= TableControl_Impl
89 	//====================================================================
90     class TableControl_Impl :public ITableControl
91                             ,public ITableModelListener
92     {
93         friend class TableGeometry;
94         friend class TableRowGeometry;
95         friend class TableColumnGeometry;
96         friend class SuspendInvariants;
97 
98     private:
99         /// the control whose impl-instance we implemnt
100         TableControl&       	m_rAntiImpl;
101         /// the model of the table control
102         PTableModel         	m_pModel;
103         /// the input handler to use, usually the input handler as provided by ->m_pModel
104         PTableInputHandler  	m_pInputHandler;
105         /// info about the widths of our columns
106         ColumnPositions         m_aColumnWidths;
107 
108         /// the height of a single row in the table, measured in pixels
109         long                	m_nRowHeightPixel;
110         /// the height of the column header row in the table, measured in pixels
111         long                	m_nColHeaderHeightPixel;
112         /// the width of the row header column in the table, measured in pixels
113         long                	m_nRowHeaderWidthPixel;
114 
115         /// the number of columns in the table control. Cached model value.
116         TableSize           	m_nColumnCount;
117 
118         /// the number of rows in the table control. Cached model value.
119         TableSize           	m_nRowCount;
120 
121         /// denotes whether or not the columns fitted into the available width, last time we checked
122         long                    m_bColumnsFit;
123 
124         ColPos              	m_nCurColumn;
125         RowPos              	m_nCurRow;
126         ColPos              	m_nLeftColumn;
127         RowPos              	m_nTopRow;
128 
129         sal_Int32           	m_nCursorHidden;
130 
131         /** the window to contain all data content, including header bars
132 
133             The window's upper left corner is at position (0,0), relative to the
134             table control, which is the direct parent of the data window.
135         */
136         ::boost::scoped_ptr< TableDataWindow >
137                                 m_pDataWindow;
138         /// the vertical scrollbar, if any
139         ScrollBar*          	m_pVScroll;
140         /// the horizontal scrollbar, if any
141         ScrollBar*              m_pHScroll;
142         ScrollBarBox*       	m_pScrollCorner;
143 	    //selection engine - for determining selection range, e.g. single, multiple
144 	    SelectionEngine*    	m_pSelEngine;
145 	    //vector which contains the selected rows
146 	    std::vector<RowPos> 	m_aSelectedRows;
147 	    //part of selection engine
148 	    TableFunctionSet*   	m_pTableFunctionSet;
149 	    //part of selection engine
150 	    RowPos		    	    m_nAnchor;
151         bool                    m_bUpdatingColWidths;
152 
153     	Link                    m_aSelectHdl;
154 
155 	    AccessibleFactoryAccess     m_aFactoryAccess;
156 	    IAccessibleTableControl*    m_pAccessibleTable;
157 
158 #if DBG_UTIL
159     #define INV_SCROLL_POSITION     1
160         /** represents a bitmask of invariants to check
161 
162             Actually, impl_checkInvariants checks more invariants than denoted in this
163             bit mask, but only those present here can be disabled temporarily.
164         */
165         sal_Int32           m_nRequiredInvariants;
166 #endif
167 
168     public:
169         void        setModel( PTableModel _pModel );
170 
171         inline  const PTableInputHandler&   getInputHandler() const { return m_pInputHandler; }
172 
173 		inline	RowPos  getCurRow() const           { return m_nCurRow; }
174 		inline	void	setCurRow( RowPos i_curRow ){ m_nCurRow = i_curRow; }
175 
176         RowPos  getAnchor() const { return m_nAnchor; }
177         void    setAnchor( RowPos const i_anchor ) { m_nAnchor = i_anchor; }
178 
179         inline  RowPos  getTopRow() const       { return m_nTopRow; }
180         inline  ColPos  getLeftColumn() const { return m_nLeftColumn; }
181 
182         inline  const TableControl&   getAntiImpl() const { return m_rAntiImpl; }
183         inline        TableControl&   getAntiImpl()       { return m_rAntiImpl; }
184 
185     public:
186         TableControl_Impl( TableControl& _rAntiImpl );
187         ~TableControl_Impl();
188 
189 #if DBG_UTIL
190         const sal_Char* impl_checkInvariants() const;
191 #endif
192         /** to be called when the anti-impl instance has been resized
193         */
194         void    onResize();
195 
196         /** paints the table control content which intersects with the given rectangle
197         */
198         void    doPaintContent( const Rectangle& _rUpdateRect );
199 
200         /** moves the cursor to the cell with the given coordinates
201 
202             To ease the caller's code, the coordinates must not necessarily denote a
203             valid position. If they don't, <FALSE/> will be returned.
204         */
205         bool    goTo( ColPos _nColumn, RowPos _nRow );
206 
207         /** ensures that the given coordinate is visible
208             @param _nColumn
209                 the column position which should be visible. Must be non-negative, and smaller
210                 than the column count.
211             @param _nRow
212                 the row position which should be visibleMust be non-negative, and smaller
213                 than the row count.
214             @param _bAcceptPartialVisibility
215                 <TRUE/> if it's okay that the given cooordinate is only partially visible
216         */
217         void    ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility );
218 
219         /** retrieves the content of the given cell, converted to a string
220         */
221         ::rtl::OUString getCellContentAsString( RowPos const i_row, ColPos const i_col );
222 
223         /** returns the position of the current row in the selection vector */
224 	    int	getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current);
225 
226         /** ??? */
227 	    void    invalidateSelectedRegion( RowPos _nPrevRow, RowPos _nCurRow );
228 
229         /** invalidates the part of the data window which is covered by the given rows
230             @param i_firstRow
231                 the index of the first row to include in the invalidation
232             @param i_lastRow
233                 the index of the last row to include in the invalidation, or ROW_INVALID if the invalidation
234                 should happen down to the bottom of the data window.
235         */
236         void    invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow );
237 
238         /** invalidates the part of the data window which is covered by the given row
239         */
240         void    invalidateRow( RowPos const i_row ) { invalidateRowRange( i_row, i_row ); }
241 
242         /** invalidates all selected rows
243         */
244         void    invalidateSelectedRows();
245 
246 	    void    checkCursorPosition();
247 
248         bool    hasRowSelection() const { return !m_aSelectedRows.empty(); }
249         size_t  getSelectedRowCount() const { return m_aSelectedRows.size(); }
250         RowPos  getSelectedRowIndex( size_t const i_selectionIndex ) const;
251 
252         /** removes the given row index from m_aSelectedRows
253 
254             @return
255                 <TRUE/> if and only if the row was previously marked as selected
256         */
257         bool        markRowAsDeselected( RowPos const i_rowIndex );
258 
259         /** marks the given row as selectged, by putting it into m_aSelectedRows
260             @return
261                 <TRUE/> if and only if the row was previously <em>not</em> marked as selected
262         */
263         bool        markRowAsSelected( RowPos const i_rowIndex );
264 
265         /** marks all rows as deselected
266             @return
267                 <TRUE/> if and only if the selection actually changed by this operation
268         */
269         bool        markAllRowsAsDeselected();
270 
271         /** marks all rows as selected
272             @return
273                 <FALSE/> if and only if all rows were selected already.
274         */
275         bool        markAllRowsAsSelected();
276 
277         void        setSelectHandler( Link const & i_selectHandler ) { m_aSelectHdl = i_selectHandler; }
278         Link const& getSelectHandler() const { return m_aSelectHdl; }
279 
280         void commitAccessibleEvent( sal_Int16 const i_eventID, const com::sun::star::uno::Any& i_newValue, const com::sun::star::uno::Any& i_oldValue );
281         void commitCellEvent( sal_Int16 const i_eventID, const com::sun::star::uno::Any& i_newValue, const com::sun::star::uno::Any& i_oldValue );
282         void commitTableEvent( sal_Int16 const i_eventID, const com::sun::star::uno::Any& i_newValue, const com::sun::star::uno::Any& i_oldValue );
283 
284         // ITableControl
285         virtual void                hideCursor();
286         virtual void                showCursor();
287         virtual bool                dispatchAction( TableControlAction _eAction );
288 	    virtual SelectionEngine*    getSelEngine();
289         virtual PTableModel         getModel() const;
290         virtual ColPos              getCurrentColumn() const;
291         virtual RowPos              getCurrentRow() const;
292         virtual bool                activateCell( ColPos const i_col, RowPos const i_row );
293         virtual ::Size              getTableSizePixel() const;
294         virtual void                setPointer( Pointer const & i_pointer );
295         virtual void                captureMouse();
296         virtual void                releaseMouse();
297         virtual void                invalidate( TableArea const i_what );
298         virtual long                pixelWidthToAppFont( long const i_pixels ) const;
299         virtual void                hideTracking();
300         virtual void                showTracking( Rectangle const & i_location, sal_uInt16 const i_flags );
301 	    virtual RowPos	            getRowAtPoint( const Point& rPoint ) const;
302         virtual ColPos              getColAtPoint( const Point& rPoint ) const;
303         virtual TableCell           hitTest( const Point& rPoint ) const;
304         virtual ColumnMetrics       getColumnMetrics( ColPos const i_column ) const;
305 	    virtual bool                isRowSelected( RowPos i_row ) const;
306 
307 
308         long                        appFontWidthToPixel( long const i_appFontUnits ) const;
309 
310         TableDataWindow&        getDataWindow()       { return *m_pDataWindow; }
311         const TableDataWindow&  getDataWindow() const { return *m_pDataWindow; }
312 	    ScrollBar* getHorzScrollbar();
313 	    ScrollBar* getVertScrollbar();
314 
315 	    Rectangle calcHeaderRect( bool bColHeader );
316         Rectangle calcHeaderCellRect( bool bColHeader, sal_Int32 nPos );
317 	    Rectangle calcTableRect();
318         Rectangle calcCellRect( sal_Int32 nRow, sal_Int32 nCol );
319 
320         // A11Y
321         ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >
322                         getAccessible( Window& i_parentWindow );
323         void            disposeAccessible();
324 
325         inline bool     isAccessibleAlive() const { return impl_isAccessibleAlive(); }
326 
327         // ITableModelListener
328         virtual void    rowsInserted( RowPos first, RowPos last );
329         virtual void    rowsRemoved( RowPos first, RowPos last );
330         virtual void    columnInserted( ColPos const i_colIndex );
331         virtual void    columnRemoved( ColPos const i_colIndex );
332         virtual void    allColumnsRemoved();
333         virtual void    cellsUpdated( ColPos const i_firstCol, ColPos i_lastCol, RowPos const i_firstRow, RowPos const i_lastRow );
334         virtual void    columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup );
335         virtual void    tableMetricsChanged();
336 
337     private:
338         bool            impl_isAccessibleAlive() const;
339         void            impl_commitAccessibleEvent(
340                             sal_Int16 const i_eventID,
341                             ::com::sun::star::uno::Any const & i_newValue,
342                             ::com::sun::star::uno::Any const & i_oldValue
343                         );
344 
345         /** toggles the cursor visibility
346 
347             The method is not bound to the classes public invariants, as it's used in
348             situations where the they must not necessarily be fullfilled.
349         */
350         void        impl_ni_doSwitchCursor( bool _bOn );
351 
352         /** returns the number of visible rows.
353 
354             @param _bAcceptPartialRow
355                 specifies whether a possible only partially visible last row is
356                 counted, too.
357         */
358         TableSize   impl_getVisibleRows( bool _bAcceptPartialRow ) const;
359 
360         /** returns the number of visible columns
361 
362             The value may change with different horizontal scroll positions, as
363             different columns have different widths. For instance, if your control is
364             100 pixels wide, and has three columns of width 50, 50, 100, respectively,
365             then this method will return either "2" or "1", depending on which column
366             is the first visible one.
367 
368             @param _bAcceptPartialRow
369                 specifies whether a possible only partially visible last row is
370                 counted, too.
371         */
372         TableSize   impl_getVisibleColumns( bool _bAcceptPartialCol ) const;
373 
374         /** determines the rectangle occupied by the given cell
375         */
376         void        impl_getCellRect( ColPos _nColumn, RowPos _nRow, Rectangle& _rCellRect ) const;
377 
378         /** updates all cached model values
379 
380             The method is not bound to the classes public invariants, as it's used in
381             situations where the they must not necessarily be fullfilled.
382         */
383         void        impl_ni_updateCachedModelValues();
384 
385         /** updates the cached table metrics (row height etc.)
386         */
387         void        impl_ni_updateCachedTableMetrics();
388 
389         /** does a relayout of the table control
390 
391             Column widths, and consequently the availability of the vertical and horizontal scrollbar, are updated
392             with a call to this method.
393 
394             @param i_assumeInflexibleColumnsUpToIncluding
395                 the index of a column up to which all columns should be considered as inflexible, or
396                 <code>COL_INVALID</code>.
397         */
398         void        impl_ni_relayout( ColPos const i_assumeInflexibleColumnsUpToIncluding = COL_INVALID );
399 
400         /** calculates the new width of our columns, taking into account their min and max widths, and their relative
401             flexibility.
402 
403             @param i_assumeInflexibleColumnsUpToIncluding
404                 the index of a column up to which all columns should be considered as inflexible, or
405                 <code>COL_INVALID</code>.
406 
407             @param i_assumeVerticalScrollbar
408                 controls whether or not we should assume the presence of a vertical scrollbar. If <true/>, and
409                 if the model has a VerticalScrollbarVisibility != ScrollbarShowNever, the method will leave
410                 space for a vertical scrollbar.
411 
412             @return
413                 the overall width of the grid, which is available for columns
414         */
415         long        impl_ni_calculateColumnWidths(
416                         ColPos const i_assumeInflexibleColumnsUpToIncluding,
417                         bool const i_assumeVerticalScrollbar,
418                         ::std::vector< long >& o_newColWidthsPixel
419                     ) const;
420 
421         /** positions all child windows, e.g. the both scrollbars, the corner window, and the data window
422         */
423         void        impl_ni_positionChildWindows(
424                         Rectangle const & i_dataCellPlayground,
425                         bool const i_verticalScrollbar,
426                         bool const i_horizontalScrollbar
427                     );
428 
429         /** scrolls the view by the given number of rows
430 
431             The method is not bound to the classes public invariants, as it's used in
432             situations where the they must not necessarily be fullfilled.
433 
434             @return
435                 the number of rows by which the viewport was scrolled. This may differ
436                 from the given numbers to scroll in case the begin or the end of the
437                 row range were reached.
438         */
439         TableSize   impl_ni_ScrollRows( TableSize _nRowDelta );
440 
441         /** equivalent to impl_ni_ScrollRows, but checks the instances invariants beforehand (in a non-product build only)
442         */
443         TableSize   impl_scrollRows( TableSize const i_rowDelta );
444 
445         /** scrolls the view by the given number of columns
446 
447             The method is not bound to the classes public invariants, as it's used in
448             situations where the they must not necessarily be fullfilled.
449 
450             @return
451                 the number of columns by which the viewport was scrolled. This may differ
452                 from the given numbers to scroll in case the begin or the end of the
453                 column range were reached.
454         */
455         TableSize   impl_ni_ScrollColumns( TableSize _nColumnDelta );
456 
457         /** equivalent to impl_ni_ScrollColumns, but checks the instances invariants beforehand (in a non-product build only)
458         */
459         TableSize   impl_scrollColumns( TableSize const i_columnDelta );
460 
461         /** retrieves the area occupied by the totality of (at least partially) visible cells
462 
463             The returned area includes row and column headers. Also, it takes into
464             account the the fact that there might be less columns than would normally
465             find room in the control.
466 
467             As a result of respecting the partial visibility of rows and columns,
468             the returned area might be larger than the data window's output size.
469         */
470         Rectangle   impl_getAllVisibleCellsArea() const;
471 
472         /** retrieves the area occupied by all (at least partially) visible data cells.
473 
474             Effectively, the returned area is the same as returned by ->impl_getAllVisibleCellsArea,
475             minus the row and column header areas.
476         */
477         Rectangle   impl_getAllVisibleDataCellArea() const;
478 
479         /** retrieves the column which covers the given ordinate
480         */
481         ColPos      impl_getColumnForOrdinate( long const i_ordinate ) const;
482 
483         /** retrieves the row which covers the given abscissa
484         */
485         RowPos      impl_getRowForAbscissa( long const i_abscissa ) const;
486 
487         /// invalidates the window area occupied by the given column
488         void        impl_invalidateColumn( ColPos const i_column );
489 
490         DECL_LINK( OnScroll, ScrollBar* );
491         DECL_LINK( OnUpdateScrollbars, void* );
492     };
493 
494 	//see seleng.hxx, seleng.cxx, FunctionSet overridables, part of selection engine
495 	class TableFunctionSet : public FunctionSet
496 	{
497 	private:
498 		TableControl_Impl*  m_pTableControl;
499 		RowPos              m_nCurrentRow;
500 
501 	public:
502 		TableFunctionSet(TableControl_Impl* _pTableControl);
503 		virtual ~TableFunctionSet();
504 
505 	   virtual void BeginDrag();
506 	   virtual void CreateAnchor();
507 	   virtual void DestroyAnchor();
508 	   virtual sal_Bool SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor);
509 	   virtual sal_Bool IsSelectionAtPoint( const Point& rPoint );
510 	   virtual void DeselectAtPoint( const Point& rPoint );
511 	   virtual void DeselectAll();
512 	};
513 
514 
515 //........................................................................
516 } } // namespace svt::table
517 //........................................................................
518 
519 #endif // SVTOOLS_TABLECONTROL_IMPL_HXX
520