2 kopetelistview.cpp - List View providing support for ListView::Items
4 Copyright (c) 2004 by Engin AYDOGAN <engin@bzzzt.biz>
5 Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
7 Kopete (c) 2004 by the Kopete developers <kopete-devel@kde.org>
9 *************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 *************************************************************************
19 #include "kopetelistview.h"
20 #include "kopetelistviewitem.h"
21 #include "kopeteuiglobal.h"
22 #include "kopeteglobal.h"
23 #include "kopetebehaviorsettings.h"
25 #include <QApplication>
26 #include <QStyleOptionSlider>
28 #include <QWheelEvent>
32 #include <QDragMoveEvent>
33 #include <QTimerEvent>
34 #include <QMouseEvent>
49 class ListView::Private
53 //! The status of smooth scrolling, enabled or disabled.
54 bool smoothScrollingEnabled
;
55 //! This will be the QTimer's ID which will be updating smooth scrolling animation.
56 double smoothScrollingTimer
;
57 //! The time interval which the smooth scrolling will be updated.
58 double smoothScrollingTimerInterval
;
59 //! This will be the target scroll bar position. Note that this value is in the sense of contents height in
60 //! in the scroll bar, not the regular XY coordinates in the widget.
61 double targetScrollBarValue
;
62 //! Meta current scroll bar value, this will be used to make precise calculation, note that data type is double
63 //! Otherwise extra coding would be necessary to workaround lost precisions all around.
64 double metaScrollBarCurrentValue
;
65 //! Acceleration constant. Actually deceleration.
66 double scrollBarAccelerationConstant
;
67 //! Scroll line step size to emulate
68 int smoothScrollingLineStep
;
69 //! Scroll page step size to emulate
70 int smoothScrollingPageStep
;
71 //! The mouse position where the slider dragging began
72 int scrollBarSliderDragStartY
;
73 //! True when the mouse is pressed
75 //! This will be used to save drag auto scroll status of the scrollview
76 //! we will need to restore it later.
77 bool smoothScrollDragAutoScroll
;
78 //! Auto scroll offset, the list will automatically start scrolling when the mouse gets this much pixel closer
79 //! to the upper or bottom edges of the listview.
80 int smoothAutoScrollOffset
;
81 //! The last pressed control of one of the scrollbars
82 //! (next page, previous line)
83 QStyle::SubControl pressedControl
;
84 //! Counter we'll use when waiting.This amount of timeouts is required before beginning to emulate continuous
85 //! scrollbar button presses
86 int smoothScrollContinuousCounter
;
87 //! The timer which will simulate continuous button press for line step buttons in scrollview
88 int continuousLinePressTimer
;
89 //! How many timeouts should we wait before beginning continuous line step simulates
90 int continuousLinePressTimerWait
;
91 //! Continuous press timer interval for next line buttton
92 int continuousLinePressTimerInterval
;
93 //! The timer which will simulate continuous page step in scrollview
94 int continuousPagePressTimer
;
95 //! How many timeouts should we wait before beginning continuous page step simulates
96 int continuousPagePressTimerWait
;
97 //! Continuous press timer interval for next page clicks
98 int continuousPagePressTimerInterval
;
99 //! The timer that will manage scroll bar auto-hiding
100 int scrollAutoHideTimer
;
101 //! Timeout counter for scroll bar auto-hiding
102 int scrollAutoHideCounter
;
103 //! Timeout for scroll bar auto-hiding
104 int scrollAutoHideTimeout
;
105 //! State of scroll auto hide
107 //! State of always hide scrollbar feature
109 //! Muse navigation offset, we will ignore this much offset to the up/bottom edges
110 int mouseNavigationOffset
;
111 //! State of mouse navigation feature
112 bool mouseNavigation
;
115 : smoothScrollingEnabled(false),
116 smoothScrollingTimer(0),
117 smoothScrollingTimerInterval(30),
118 targetScrollBarValue(0),
119 metaScrollBarCurrentValue(0.0),
120 scrollBarAccelerationConstant(6.0),
121 smoothScrollingLineStep(0),
122 smoothScrollingPageStep(0),
123 scrollBarSliderDragStartY(0),
125 smoothScrollDragAutoScroll(false),
126 smoothAutoScrollOffset(60),
127 pressedControl( QStyle::SC_None
),
128 smoothScrollContinuousCounter(0),
129 continuousLinePressTimer(0),
130 continuousLinePressTimerWait(10),
131 continuousLinePressTimerInterval(40),
132 continuousPagePressTimer(0),
133 continuousPagePressTimerWait(2),
134 continuousPagePressTimerInterval(200),
135 scrollAutoHideTimer(0),
136 scrollAutoHideCounter(10),
137 scrollAutoHideTimeout(10),
138 scrollAutoHide(false),
140 mouseNavigationOffset(20),
141 mouseNavigation(false)
145 ListView::ListView( QWidget
*parent
)
146 : K3ListView( parent
), d( new Private
)
148 connect( &d
->sortTimer
, SIGNAL( timeout() ), this, SLOT( slotSort() ) );
150 // We have our own tooltips, don't use the default QListView ones
151 setShowToolTips( false );
153 connect( this, SIGNAL( contextMenu( K3ListView
*, Q3ListViewItem
*, const QPoint
& ) ),
154 SLOT( slotContextMenu( K3ListView
*, Q3ListViewItem
*, const QPoint
& ) ) );
155 connect( this, SIGNAL( doubleClicked( Q3ListViewItem
* ) ),
156 SLOT( slotDoubleClicked( Q3ListViewItem
* ) ) );
158 // set up flags for nicer painting
159 setAttribute( Qt::WA_StaticContents
, false );
162 // clear the appropriate flags from the viewport - qt docs say we have to mask
163 // these flags out of the QListView to make weirdly painted list items work, but
164 // that doesn't do the job. masking them out of the viewport does.
165 // class MyWidget : public QWidget { public: using QWidget::clearWFlags; };
166 // static_cast<MyWidget*>( viewport() )->clearWFlags( WStaticContents );
167 // static_cast<MyWidget*>( viewport() )->setWFlags( WNoAutoErase );
169 // The above causes compiler errors with the (broken) native TRU64 and IRIX compilers.
170 // This should make it compile for both platforms and still seems to work.
171 // This is, of course, a nasty hack, but it works, so...
172 static_cast<ListView
*>(viewport())->setAttribute( Qt::WA_StaticContents
, false );
174 // init smooth scrolling
175 // NOTE: Disabled smooth scrolling in KDE4 because it is buggy -DarkShock
176 setSmoothScrolling( false );
179 ListView::~ListView()
184 void ListView::slotDoubleClicked( Q3ListViewItem
*item
)
189 setOpen( item
, !isOpen( item
) );
192 void ListView::slotContextMenu( K3ListView
* /*listview*/,
193 Q3ListViewItem
*item
, const QPoint
&/*point*/ )
195 if ( item
&& !item
->isSelected() )
198 item
->setSelected( true );
203 // if( Item *myItem = dynamic_cast<Item*>( item ) )
204 // TODO: myItem->contextMenu( point );
207 void ListView::setShowTreeLines( bool bShowAsTree
)
211 setRootIsDecorated( true );
212 setTreeStepSize( 20 );
216 setRootIsDecorated( false );
217 setTreeStepSize( 0 );
219 // TODO: relayout all items. their width may have changed, but they won't know about it.
222 /* This is a small hack ensuring that only F2 triggers inline
223 * renaming. Won't win a beauty award, but whoever wrote it thinks
224 * relying on the fact that QListView intercepts and processes the
225 * F2 event through this event filter is sorta safe.
227 * Also use enter to execute the item since executed is not usually
228 * called when enter is pressed.
230 void ListView::keyPressEvent( QKeyEvent
*e
)
232 Q3ListViewItem
*item
= currentItem();
233 if ( (e
->key() == Qt::Key_F2
) && item
&& item
->isVisible() )
235 else if ( (e
->key() == Qt::Key_Enter
|| e
->key() == Qt::Key_Return
) && item
&& item
->isVisible() )
237 // must provide a point within the item; emitExecute checks for this
238 QPoint p
= viewport()->mapToGlobal(itemRect(item
).center());
239 emitExecute( currentItem(), p
, 0 );
242 K3ListView::keyPressEvent(e
);
245 void ListView::delayedSort()
247 if ( !d
->sortTimer
.isActive() )
249 d
->sortTimer
.setSingleShot( true );
250 d
->sortTimer
.start( 500 );
254 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
255 // Here begins the smooth scrolling hack
256 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
257 // What is this: This hack enables smooth scrolling, and intercepts all events that goes to scrollbar. Unless we do so, scrollbar
258 // will react to the mouse clicks and go _immedietly_ to the target value (i.e. next page) then when the smoothscroll
259 // takes effect the scrollbar slider will start to scroll smoothly, so the first slider movement due to scrollbar
260 // click causes a flickery. So we avoid all scrollbar events, and emulate them smoothly.
261 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
262 // Bugs: * Scroll bar loses it's onMouseOver color when we drag the scroll bar and move the mouse outside of the slider
263 // * Next/Prev page areas don't get mouse clicks, some styles gives some feedback on such an event
264 // and that feedback is unintentionally avoided by this hack. Many many contraints caused this choice.
265 // * Horizontal scroll bar seems to flicker when the scrollbars are being showed in auto-hide mode
266 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
268 void ListView::setSmoothScrolling( bool b
)
270 if( d
->smoothScrollingEnabled
== b
) // Is setting changed?
271 return; // If no, just return
273 d
->smoothScrollingEnabled
= b
; // update the setting
275 if( d
->smoothScrollingEnabled
) // If enabled
277 // Intercept scrollbar's events
278 verticalScrollBar()->installEventFilter( this );
280 d
->smoothScrollingTimer
= startTimer( (int)d
->smoothScrollingTimerInterval
);
281 // If we want to enable smooth scrolling when item has changed with keypresses etc, we need this
282 connect( this, SIGNAL( currentChanged( Q3ListViewItem
* ) ), this, SLOT( slotCurrentChanged(Q3ListViewItem
*) ) );
283 // Disable autoscroll, we will do it the smooth way.
284 d
->smoothScrollDragAutoScroll
= dragAutoScroll();
285 setDragAutoScroll( false );
286 // Init the timers to simulate continuous press
287 d
->continuousLinePressTimer
= startTimer( d
->continuousLinePressTimerInterval
);
288 d
->continuousPagePressTimer
= startTimer( d
->continuousPagePressTimerInterval
);
293 // Uninstall the event interception from the scroll bar
294 verticalScrollBar()->removeEventFilter( this );
295 // Restore line/page step sizes
296 verticalScrollBar()->setSingleStep( d
->smoothScrollingLineStep
);
297 // Kill the already started timer
298 killTimer( (int)d
->smoothScrollingTimer
);
299 d
->smoothScrollingTimer
= 0;
300 // We don't need to list currentChanged anymore
301 disconnect( this, SIGNAL( currentChanged( Q3ListViewItem
* ) ), this, SLOT( slotCurrentChanged(Q3ListViewItem
*) ) );
302 // Restore the autoscroll
303 setDragAutoScroll( d
->smoothScrollDragAutoScroll
);
304 // Kill the continuous press timers
305 killTimer( d
->continuousLinePressTimer
);
306 d
->continuousLinePressTimer
= 0;
307 killTimer( d
->continuousPagePressTimer
);
308 d
->continuousPagePressTimer
= 0;
312 bool ListView::smoothScrolling() const
314 return d
->smoothScrollingEnabled
;
317 void ListView::setSmoothScrollingTimerInterval( double i
)
319 d
->smoothScrollingTimerInterval
= i
;
322 double ListView::smoothScrollingTimerInterval() const
324 return d
->smoothScrollingTimerInterval
;
327 void ListView::setScrollAutoHide( bool b
)
329 // If no change, just bail
330 if( d
->scrollAutoHide
== b
) return;
334 // Set scrollbar auto-hiding state true
335 d
->scrollAutoHide
= true;
336 // Turn of the bar now
337 setVScrollBarMode( AlwaysOff
);
338 // Start the timer to handle auto-hide
339 killTimer( d
->scrollAutoHideTimer
);
340 d
->scrollAutoHideTimer
= startTimer( 1000 );
344 d
->scrollAutoHide
= false;
345 setVScrollBarMode( Auto
);
346 killTimer( d
->scrollAutoHideTimer
);
350 bool ListView::scrollAutoHide() const
352 return d
->scrollAutoHide
;
355 void ListView::setScrollAutoHideTimeout( int t
)
357 d
->scrollAutoHideTimeout
= t
;
360 int ListView::scrollAutoHideTimeout() const
362 return d
->scrollAutoHideTimeout
;
365 void ListView::setScrollHide( bool b
)
367 // if no change, just bail
368 if( d
->scrollHide
== b
) return;
372 setVScrollBarMode( AlwaysOff
);
374 setVScrollBarMode( Auto
);
377 bool ListView::scrollHide() const
379 return d
->scrollHide
;
382 void ListView::setMouseNavigation( bool b
)
384 d
->mouseNavigation
= b
;
387 bool ListView::mouseNavigation() const
389 return d
->mouseNavigation
;
392 void ListView::timerEvent( QTimerEvent
*e
)
394 if( e
->timerId() == d
->smoothScrollingTimer
)
395 { // This is a smooth scroll update
396 // Find how war we are away from the target scroll bar value and divide it by our constant (it can be both negative/positive)
397 double offset
= static_cast<double>( ( d
->targetScrollBarValue
- d
->metaScrollBarCurrentValue
) / d
->scrollBarAccelerationConstant
);
398 // Add the offset to our meta current value, this is the desired precise value
399 d
->metaScrollBarCurrentValue
+= offset
;
400 // Cast it to integer and update the vertical scroll bar value
401 verticalScrollBar()->setValue( static_cast<int>( d
->metaScrollBarCurrentValue
) );
403 else if( e
->timerId() == d
->continuousLinePressTimer
)
405 // If the button is being pressed for a longer time, get faster
406 // X = time spent untill continuous button press begins to take effect
407 // Wait for X more amount of time after the continuous button press actually begins, the start to accelerate the scrolling linearly
408 double acceleration
= static_cast<double>( ( d
->smoothScrollContinuousCounter
- d
->continuousLinePressTimerWait
* 2 ) ) /
409 static_cast<double>( d
->continuousLinePressTimerWait
);
410 // Let's make sure if the acceleration coefficient is between 1 and 3
411 acceleration
= qMax( 1.0, acceleration
);
412 acceleration
= qMin( 3.0, acceleration
);
414 // Check if any scrollbar buttons are being pressed right, if any, honor them
415 if( d
->pressedControl
== QStyle::SC_ScrollBarSubLine
)
416 { // Check if the user has pressed for long enough to activate continuous mouse press effect
417 if( d
->smoothScrollContinuousCounter
++ > d
->continuousLinePressTimerWait
) // pressed long enough ?
419 d
->targetScrollBarValue
-= d
->smoothScrollingLineStep
* acceleration
; // if so start continuous scrolling
420 // Make sure the target value is not below the minimum range.
421 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double ) verticalScrollBar()->minimum() );
424 else if( d
->pressedControl
== QStyle::SC_ScrollBarAddLine
)
426 if( d
->smoothScrollContinuousCounter
++ > d
->continuousLinePressTimerWait
) // pressed long enough ?
428 d
->targetScrollBarValue
+= d
->smoothScrollingLineStep
* acceleration
; // if so start continuous scrolling
429 // Make sure the target value is not aboce the maximum range.
430 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )verticalScrollBar()->maximum() );
434 else if( e
->timerId() == d
->continuousPagePressTimer
)
436 // If the button is being pressed for a longer time, get faster
437 // X = time spent untill continuous button press begins to take effect
438 // Wait for X more amount of time after the continuous button press actually begins, the start to accelerate the scrolling linearly
439 double acceleration
= static_cast<double>( ( d
->smoothScrollContinuousCounter
- d
->continuousPagePressTimerWait
* 2 ) ) /
440 static_cast<double>( d
->continuousPagePressTimerWait
);
441 // Let's make sure if the acceleration coefficient is between 1 and 3
442 acceleration
= qMax( 1.0, acceleration
);
443 acceleration
= qMin( 3.0, acceleration
);
445 if( d
->pressedControl
== QStyle::SC_ScrollBarSubPage
)
447 if( d
->smoothScrollContinuousCounter
++ > d
->continuousPagePressTimerWait
) // pressed long enough ?
449 d
->targetScrollBarValue
-= d
->smoothScrollingPageStep
+ acceleration
; // if so start continuous scrolling
450 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )verticalScrollBar()->minimum() );
453 else if( d
->pressedControl
== QStyle::SC_ScrollBarAddPage
)
455 if( d
->smoothScrollContinuousCounter
++ > d
->continuousPagePressTimerWait
) // pressed long enough ?
457 d
->targetScrollBarValue
+= d
->smoothScrollingPageStep
* acceleration
; // if so start continuous scrolling
458 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )verticalScrollBar()->maximum() );
462 else if( e
->timerId() == d
->scrollAutoHideTimer
)
464 if( !d
->scrollAutoHideCounter
-- )
465 setVScrollBarMode( AlwaysOff
);
469 bool ListView::eventFilter( QObject
*o
, QEvent
*e
)
471 if( o
== verticalScrollBar() ) // Event's to scroll bar
474 QScrollBar
*bar
= static_cast<QScrollBar
*>(o
);
475 if( e
->type() == QEvent::Wheel
)
477 // OK, this is a wheel event, let's get our QWheelEvent in an unsafe way, due to a bug in RTTI of QT.
478 QWheelEvent
*event
= static_cast<QWheelEvent
*>(e
);
479 // Set new target value
480 d
->targetScrollBarValue
-= event
->delta();
481 // Make sure it's in the boundaries of scroll bar
482 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )bar
->minimum() );
483 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )bar
->maximum() );
484 return true; // Ignore the event
486 else if( e
->type() == QEvent::MouseButtonPress
|| e
->type() == QEvent::MouseButtonDblClick
)
488 QMouseEvent
* event
= static_cast<QMouseEvent
*>(e
);
489 // We are intercepting all clicks and double clicks on the scrollbar. Unless we do so
490 // scroll bar immediately goes to the point wherever user's click requests it to.
491 // Then smooth scroll begins, and animates the scrolling, but since the scrollbar
492 // goes to the destionation point for a very small amount of time at the very beginning of
493 // the click, this causes flickering. So we intercept each click, and make the scroll bar
494 // go to it's destination by smoothly.
496 //// Start masking the scrollbar so that we can detect where the mouse clicks on
497 // The slider handle's starting position.
498 QStyleOptionSlider qsos
;
500 QRect sliderRect
= style()->subControlRect( QStyle::CC_ScrollBar
, &qsos
, QStyle::SC_ScrollBarSlider
, 0 );
501 int sliderStart
= sliderRect
.y();
502 // The slider handle's ending position
503 int sliderEnd
= sliderStart
+ sliderRect
.height();
504 // The slider handle's width
505 int width
= sliderRect
.width();
506 // This is masking the upper previous line button
507 QRect
prevLineUpper( 0, 0, width
, 15 );
508 // This is masking the previous page, which is between the upper previous line button and the slider
509 QRect
prevPage( 0, 15, width
, sliderStart
- 15 );
510 // This is masking the next page, which is between bottom previous line and the slider
511 QRect
nextPage( 0, sliderEnd
, width
, bar
->height() - sliderEnd
- 30 );
512 // This is masking the bottom previous line button
513 QRect
prevLineBottom( 0, bar
->height() - 30, width
, 15 );
514 // This is masking the next line button
515 QRect
nextLine( 0, bar
->height() - 15, width
, 30 );
517 // Get page/line step sizes. You may ask, why we are not doing this in setSmoothScrolling
518 // the reason is, scroll bar might not be initialized at that moment. When we are receiving
519 // MouseButtonPress or such event, we're sure that it's initialized!
520 if( d
->smoothScrollingLineStep
== 0 && d
->smoothScrollingPageStep
== 0 ){
521 d
->smoothScrollingLineStep
= bar
->singleStep();
522 d
->smoothScrollingPageStep
= bar
->pageStep();
523 // Set page/line steps of the scroll bar to zero, we'll emulate them, smoothly!
524 // If we don't set this to 0, when we pass the event to the button, the scollbar
525 // will scroll the list too.
526 verticalScrollBar()->setSingleStep( 0 );
529 // OK, now we can understand which partion of the scroll bar is clicked, and do the requested thing
530 // animated. Then set the step sizes to zero, and pass the event to the slider, so that user can
531 // feel like he/she really pressed the buttons (on click color change).
533 switch( d
->pressedControl
)
535 case QStyle::SC_ScrollBarSlider
:
536 d
->scrollBarSliderDragStartY
= event
->y();
538 case QStyle::SC_ScrollBarSubLine
:
539 d
->targetScrollBarValue
-= d
->smoothScrollingLineStep
;
540 // Make sure if the targetScrollBarValue is in the scroll bar values range
541 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )verticalScrollBar()->minimum() );
542 return false; // pass the event to the scroll bar so the button gets "clicked"
544 case QStyle::SC_ScrollBarSubPage
:
545 d
->targetScrollBarValue
-= d
->smoothScrollingPageStep
;
546 // Make sure if the targetScrollBarValue is in the scroll bar values range
547 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )verticalScrollBar()->minimum() );
549 case QStyle::SC_ScrollBarAddPage
:
550 d
->targetScrollBarValue
+= d
->smoothScrollingPageStep
;
551 // Make sure if the targetScrollBarValue is in the scroll bar values range
552 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )verticalScrollBar()->maximum() );
554 case QStyle::SC_ScrollBarAddLine
:
555 d
->targetScrollBarValue
+= d
->smoothScrollingLineStep
;
556 // Make sure if the targetScrollBarValue is in the scroll bar values range
557 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )verticalScrollBar()->maximum() );
558 return false; // pass the event to the scroll bar so the button gets "clicked"
561 kDebug( 14010 ) << "Unhandled sub control";
563 return true; // Now, ignore the event.
565 else if( e
->type() == QEvent::MouseMove
)
567 // Get our QMouseEvent so that we can have our relative mouse position
568 QMouseEvent
*event
= static_cast<QMouseEvent
*>(e
);
569 if( d
->pressedControl
== QStyle::SC_ScrollBarSlider
)
571 // Mouse movement distance for this MouseMove event
572 double delta
= event
->y() - d
->scrollBarSliderDragStartY
;
573 // Update the drag start value so in the next MouseMove event we can calculate new movement distance
574 d
->scrollBarSliderDragStartY
= event
->y();
575 // The length which we can move the mouse over the bar
576 QStyleOptionSlider qsos
;
578 QRect sliderRect
= style()->subControlRect( QStyle::CC_ScrollBar
, &qsos
, QStyle::SC_ScrollBarSlider
, 0 );
579 double scale
= bar
->geometry().height() - sliderRect
.height() - 45;
580 // Scale it to scroll bar value
581 d
->targetScrollBarValue
+= static_cast<int>( static_cast<double>( ( bar
->maximum() / scale
) * delta
) );
584 if( d
->scrollAutoHide
) // If auto-hide scroll bar is enabled
586 d
->scrollAutoHideCounter
= 9999; // Mouse is dragging the scrollbar slider
589 else if( e
->type() == QEvent::Enter
)
591 if( d
->scrollAutoHide
) // If auto-hide scroll bar is enabled
593 d
->scrollAutoHideCounter
= 9999; // Mouse is on the scroll bar
596 else if( e
->type() == QEvent::Leave
)
598 if( d
->scrollAutoHide
) // If auto-hide scroll bar is enabled
599 { // show the scroll bar
600 d
->scrollAutoHideCounter
= d
->scrollAutoHideTimeout
; // Mouse is on the scroll bar
603 else if( e
->type() == QEvent::MouseButtonRelease
)
605 // Reset waiting counter. This is used to wait before simulating continuous mouse press
606 d
->smoothScrollContinuousCounter
= 0;
607 // Mark all buttons as not pressed now
608 d
->pressedControl
= QStyle::SC_None
;
609 // Make sure if the targetScrollBarValue is in the scroll bar values range
610 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )bar
->minimum() );
611 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )bar
->maximum() );
612 return false; // Pass the release event to the scroll bar, which will put the buttons in off-state
616 return false; // Pass the event to the scroll bar
619 else if( o
== viewport() )
621 if( e
->type() == QEvent::MouseButtonPress
)
623 // Mark that we have pressed the button. This will prevent the list from scrolling when
624 // the current item has changed due to mouse click. It's fine when the keypresses cause
625 // it scroll, but not mouse.
626 d
->mousePressed
= true;
628 else if( e
->type() == QEvent::MouseButtonRelease
)
630 d
->mousePressed
= false;
632 else if( e
->type() == QEvent::DragMove
)
634 // OK, user is dragging something in the list
635 QDragMoveEvent
*event
= static_cast<QDragMoveEvent
*>(e
);
636 if( event
->pos().y() < d
->smoothAutoScrollOffset
)
637 { // If he's too close to the upper edge, let's smootly scroll up
638 d
->targetScrollBarValue
-= ( d
->smoothAutoScrollOffset
- event
->pos().y() ) * d
->scrollBarAccelerationConstant
/ 3;
640 else if( event
->pos().y() > ( visibleHeight() - d
->smoothAutoScrollOffset
) )
641 { // If he's too close to the bottom edege, then let's smoothle scroll down
642 d
->targetScrollBarValue
+= ( event
->pos().y() - visibleHeight() + d
->smoothAutoScrollOffset
) * d
->scrollBarAccelerationConstant
/ 3;
644 // Make sure if the targetScrollBarValue is in the scroll bar values range
645 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )verticalScrollBar()->minimum() );
646 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )verticalScrollBar()->maximum() );
648 else if( e
->type() == QEvent::MouseMove
) // Activity detected ( used to aut-hide scroll bar )
650 // Get our QMouseEvent so that we can have our relative mouse position
651 QMouseEvent
*event
= static_cast<QMouseEvent
*>(e
);
653 if( d
->scrollAutoHide
) // If auto-hide scroll bar is enabled
655 setVScrollBarMode( Auto
); // show the scroll bar
656 d
->scrollAutoHideCounter
= 9999; // Mouse is on the contact list, so don't hide it
659 if( d
->mouseNavigation
)
661 const double offset
= static_cast<double>(visibleHeight())/50.0 + d
->mouseNavigationOffset
;
662 d
->targetScrollBarValue
= ( event
->y() - offset
) * ( static_cast<double>(verticalScrollBar()->maximum()) /
663 ( static_cast<double>(visibleHeight()) - offset
* 2 ) );
666 else if( e
->type() == QEvent::Leave
)
668 if( d
->scrollAutoHide
) // If auto-hide scroll bar is enabled
670 d
->scrollAutoHideCounter
= d
->scrollAutoHideTimeout
; // Mouse left the contact list, hide it after timeout
673 else if( e
->type() == QEvent::ToolTip
)
675 QHelpEvent
*helpEvent
= static_cast<QHelpEvent
*>(e
);
676 if( Item
*item
= dynamic_cast<Item
*>( itemAt( helpEvent
->pos() ) ) )
678 QRect itemRegion
= this->itemRect( item
);
680 uint leftMargin
= this->treeStepSize() * ( item
->depth() + ( this->rootIsDecorated() ? 1 : 0 ) ) + itemMargin();
682 uint xAdjust
= itemRegion
.left() + leftMargin
;
683 uint yAdjust
= itemRegion
.top();
684 QPoint
relativePosition( helpEvent
->pos().x() - xAdjust
, helpEvent
->pos().y() - yAdjust
);
686 std::pair
<QString
,QRect
> toolTip
= item
->toolTip( relativePosition
);
687 if ( toolTip
.first
.isEmpty() )
690 toolTip
.second
.translate( xAdjust
, yAdjust
);
692 QToolTip::showText( helpEvent
->globalPos(), toolTip
.first
);
696 return K3ListView::eventFilter( o
, e
); // Pass the event to K3ListView
700 // kDebug( 14000 ) << "Unhandled event: [" << o << "][" << o->name() << "][" << o->metaObject()->className() << "][" << e->type() << "]";
701 return K3ListView::eventFilter( o
, e
); // Pass the event to K3ListView
707 void ListView::slotCurrentChanged( Q3ListViewItem
*item
)
710 // If the current item changed due to mouse click then don't center it in the listview. Do this just for key presses.
711 if( d
->mousePressed
){ d
->mousePressed
= false; return; }
712 d
->targetScrollBarValue
= itemPos(item
) - static_cast<double>(visibleHeight()/2.0) + item
->height();
713 // Make sure it's in the boundaries of scroll bar
714 d
->targetScrollBarValue
= qMax( d
->targetScrollBarValue
, ( double )verticalScrollBar()->minimum() );
715 d
->targetScrollBarValue
= qMin( d
->targetScrollBarValue
, ( double )verticalScrollBar()->maximum() );
719 } // END namespace ListView
720 } // END namespace UI
721 } // END namespace Kopete
723 #include "kopetelistview.moc"
725 // vim: set noet ts=4 sts=4 sw=4: