xref: /trunk/main/svtools/source/table/mousefunction.cxx (revision 4bb3d789e15445dbe3c012d13e69fce7f27b45dd)
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 #include "precompiled_svtools.hxx"
23 
24 #include "mousefunction.hxx"
25 #include "svtools/table/tablecontrolinterface.hxx"
26 
27 #include <tools/diagnose_ex.h>
28 #include <vcl/window.hxx>
29 
30 //......................................................................................................................
31 namespace svt { namespace table
32 {
33 //......................................................................................................................
34 
35     //==================================================================================================================
36     //= MouseFunction
37     //==================================================================================================================
38     //------------------------------------------------------------------------------------------------------------------
39     oslInterlockedCount MouseFunction::acquire()
40     {
41         return osl_incrementInterlockedCount( &m_refCount );
42     }
43 
44     //------------------------------------------------------------------------------------------------------------------
45     oslInterlockedCount MouseFunction::release()
46     {
47         oslInterlockedCount newCount = osl_decrementInterlockedCount( &m_refCount );
48         if ( newCount == 0 )
49         {
50             delete this;
51             return 0;
52         }
53         return newCount;
54     }
55 
56     //==================================================================================================================
57     //= ColumnResize
58     //==================================================================================================================
59     //------------------------------------------------------------------------------------------------------------------
60     FunctionResult ColumnResize::handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event )
61     {
62         Point const aPoint = i_event.GetPosPixel();
63 
64         if ( m_nResizingColumn == COL_INVALID )
65         {
66             // if we hit a column divider, change the mouse pointer accordingly
67             Pointer aNewPointer( POINTER_ARROW );
68             TableCell const tableCell = i_tableControl.hitTest( aPoint );
69             if ( ( tableCell.nRow == ROW_COL_HEADERS ) && ( tableCell.eArea == ColumnDivider ) )
70             {
71                 aNewPointer = Pointer( POINTER_HSPLIT );
72             }
73             i_tableControl.setPointer( aNewPointer );
74 
75             return SkipFunction; // TODO: is this correct?
76         }
77 
78         ::Size const tableSize = i_tableControl.getTableSizePixel();
79 
80         // set proper pointer
81         Pointer aNewPointer( POINTER_ARROW );
82         ColumnMetrics const & columnMetrics( i_tableControl.getColumnMetrics( m_nResizingColumn ) );
83         if  (   ( aPoint.X() > tableSize.Width() )
84             ||  ( aPoint.X() < columnMetrics.nStartPixel )
85             )
86         {
87             aNewPointer = Pointer( POINTER_NOTALLOWED );
88         }
89         else
90         {
91             aNewPointer = Pointer( POINTER_HSPLIT );
92         }
93         i_tableControl.setPointer( aNewPointer );
94 
95         // show tracking line
96         i_tableControl.hideTracking();
97         i_tableControl.showTracking(
98             Rectangle(
99                 Point( aPoint.X(), 0 ),
100                 Size( 1, tableSize.Height() )
101             ),
102             SHOWTRACK_SPLIT | SHOWTRACK_WINDOW
103         );
104 
105         (void)i_event;
106         return ContinueFunction;
107     }
108 
109     //------------------------------------------------------------------------------------------------------------------
110     FunctionResult ColumnResize::handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event )
111     {
112         if ( m_nResizingColumn != COL_INVALID )
113         {
114             OSL_ENSURE( false, "ColumnResize::handleMouseDown: suspicious: MouseButtonDown while still tracking?" );
115             return ContinueFunction;
116         }
117 
118         TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
119         if ( tableCell.nRow == ROW_COL_HEADERS )
120         {
121             if  (   ( tableCell.nColumn != COL_INVALID )
122                 &&  ( tableCell.eArea == ColumnDivider )
123                 )
124             {
125                 m_nResizingColumn = tableCell.nColumn;
126                 i_tableControl.captureMouse();
127                 return ActivateFunction;
128             }
129         }
130 
131         return SkipFunction;
132     }
133 
134     //------------------------------------------------------------------------------------------------------------------
135     FunctionResult ColumnResize::handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event )
136     {
137         if ( m_nResizingColumn == COL_INVALID )
138             return SkipFunction;
139 
140         Point const aPoint = i_event.GetPosPixel();
141 
142         i_tableControl.hideTracking();
143         PColumnModel const pColumn = i_tableControl.getModel()->getColumnModel( m_nResizingColumn );
144         long const maxWidthLogical = pColumn->getMaxWidth();
145         long const minWidthLogical = pColumn->getMinWidth();
146 
147         // new position of mouse
148         long const requestedEnd = aPoint.X();
149 
150         // old position of right border
151         long const oldEnd = i_tableControl.getColumnMetrics( m_nResizingColumn ).nEndPixel;
152 
153         // position of left border if cursor in the to-be-resized column
154         long const columnStart = i_tableControl.getColumnMetrics( m_nResizingColumn ).nStartPixel;
155         long const requestedWidth = requestedEnd - columnStart;
156             // TODO: this is not correct, strictly: It assumes that the mouse was pressed exactly on the "end" pos,
157             // but for a while now, we have relaxed this, and allow clicking a few pixels aside, too
158 
159         if ( requestedEnd >= columnStart )
160         {
161             long requestedWidthLogical = i_tableControl.pixelWidthToAppFont( requestedWidth );
162             // respect column width limits
163             if ( oldEnd > requestedEnd )
164             {
165                 // column has become smaller, check against minimum width
166                 if ( ( minWidthLogical != 0 ) && ( requestedWidthLogical < minWidthLogical ) )
167                     requestedWidthLogical = minWidthLogical;
168             }
169             else if ( oldEnd < requestedEnd )
170             {
171                 // column has become larger, check against max width
172                 if ( ( maxWidthLogical != 0 ) && ( requestedWidthLogical >= maxWidthLogical ) )
173                     requestedWidthLogical = maxWidthLogical;
174             }
175             pColumn->setWidth( requestedWidthLogical );
176             i_tableControl.invalidate( TableAreaAll );
177         }
178 
179         i_tableControl.setPointer( Pointer() );
180         i_tableControl.releaseMouse();
181 
182         m_nResizingColumn = COL_INVALID;
183         return DeactivateFunction;
184     }
185 
186     //==================================================================================================================
187     //= RowSelection
188     //==================================================================================================================
189     //------------------------------------------------------------------------------------------------------------------
190     FunctionResult RowSelection::handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event )
191     {
192         OSL_UNUSED( i_tableControl );
193         OSL_UNUSED( i_event );
194         return SkipFunction;
195     }
196 
197     //------------------------------------------------------------------------------------------------------------------
198     FunctionResult RowSelection::handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event )
199     {
200         bool handled = false;
201 
202         TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
203         if ( tableCell.nRow >= 0 )
204         {
205             if ( i_tableControl.getSelEngine()->GetSelectionMode() == NO_SELECTION )
206             {
207                 i_tableControl.activateCell( tableCell.nColumn, tableCell.nRow );
208                 handled = true;
209             }
210             else
211             {
212                 handled = i_tableControl.getSelEngine()->SelMouseButtonDown( i_event );
213             }
214         }
215 
216         if ( handled )
217             m_bActive = true;
218         return handled ? ActivateFunction : SkipFunction;
219     }
220 
221     //------------------------------------------------------------------------------------------------------------------
222     FunctionResult RowSelection::handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event )
223     {
224         TableCell const tableCell = i_tableControl.hitTest( i_event.GetPosPixel() );
225         if ( tableCell.nRow >= 0 )
226         {
227             if ( i_tableControl.getSelEngine()->GetSelectionMode() != NO_SELECTION )
228             {
229                 i_tableControl.getSelEngine()->SelMouseButtonUp( i_event );
230             }
231         }
232         if ( m_bActive )
233         {
234             m_bActive = false;
235             return DeactivateFunction;
236         }
237         return SkipFunction;
238     }
239 
240     //==================================================================================================================
241     //= ColumnSortHandler
242     //==================================================================================================================
243     //------------------------------------------------------------------------------------------------------------------
244     FunctionResult ColumnSortHandler::handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event )
245     {
246         OSL_UNUSED( i_tableControl );
247         OSL_UNUSED( i_event );
248         return SkipFunction;
249     }
250 
251     //------------------------------------------------------------------------------------------------------------------
252     FunctionResult ColumnSortHandler::handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event )
253     {
254         if ( m_nActiveColumn != COL_INVALID )
255         {
256             OSL_ENSURE( false, "ColumnSortHandler::handleMouseDown: called while already active - suspicious!" );
257             return ContinueFunction;
258         }
259 
260         if ( i_tableControl.getModel()->getSortAdapter() == NULL )
261             // no sorting support at the model
262             return SkipFunction;
263 
264         TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
265         if ( ( tableCell.nRow != ROW_COL_HEADERS ) || ( tableCell.nColumn < 0 ) )
266             return SkipFunction;
267 
268         // TODO: ensure the column header is rendered in some special way, indicating its current state
269 
270         m_nActiveColumn = tableCell.nColumn;
271         return ActivateFunction;
272     }
273 
274     //------------------------------------------------------------------------------------------------------------------
275     FunctionResult ColumnSortHandler::handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event )
276     {
277         if ( m_nActiveColumn == COL_INVALID )
278             return SkipFunction;
279 
280         TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
281         if ( ( tableCell.nRow == ROW_COL_HEADERS ) && ( tableCell.nColumn == m_nActiveColumn ) )
282         {
283             ITableDataSort* pSort = i_tableControl.getModel()->getSortAdapter();
284             ENSURE_OR_RETURN( pSort != NULL, "ColumnSortHandler::handleMouseUp: somebody is mocking with us!", DeactivateFunction );
285                 // in handleMousButtonDown, the model claimed to have sort support...
286 
287             ColumnSortDirection eSortDirection = ColumnSortAscending;
288             ColumnSort const aCurrentSort = pSort->getCurrentSortOrder();
289             if ( aCurrentSort.nColumnPos == m_nActiveColumn )
290                 // invert existing sort order
291                 eSortDirection = ( aCurrentSort.eSortDirection == ColumnSortAscending ) ? ColumnSortDescending : ColumnSortAscending;
292 
293             pSort->sortByColumn( m_nActiveColumn, eSortDirection );
294         }
295 
296         m_nActiveColumn = COL_INVALID;
297         return DeactivateFunction;
298     }
299 
300 //......................................................................................................................
301 } } // namespace svt::table
302 
303 /* vim: set noet sw=4 ts=4: */
304