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