Show invite menu in wlm chat window immediately
[kdenetwork.git] / kopete / libkopete / ui / kopetelistview.cpp
blob136853e2646ab6e6273732ab45fd15cd55f6705e
1 /*
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 *************************************************************************
10 * *
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. *
15 * *
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>
27 #include <QStyle>
28 #include <QWheelEvent>
29 #include <QKeyEvent>
30 #include <QEvent>
31 #include <QHelpEvent>
32 #include <QDragMoveEvent>
33 #include <QTimerEvent>
34 #include <QMouseEvent>
35 #include <QTimer>
36 #include <QToolTip>
38 #include <kdebug.h>
39 #include <kde_file.h>
41 #include <utility>
42 #include <memory>
44 namespace Kopete {
45 namespace UI {
46 namespace ListView {
49 class ListView::Private
51 public:
52 QTimer sortTimer;
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
74 bool mousePressed;
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
106 bool scrollAutoHide;
107 //! State of always hide scrollbar feature
108 bool scrollHide;
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;
113 //! C-tor
114 Private()
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),
124 mousePressed(false),
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),
139 scrollHide(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()
181 delete d;
184 void ListView::slotDoubleClicked( Q3ListViewItem *item )
186 kDebug( 14000 ) ;
188 if ( item )
189 setOpen( item, !isOpen( item ) );
192 void ListView::slotContextMenu( K3ListView * /*listview*/,
193 Q3ListViewItem *item, const QPoint &/*point*/ )
195 if ( item && !item->isSelected() )
197 clearSelection();
198 item->setSelected( true );
200 if ( !item )
201 clearSelection();
203 // if( Item *myItem = dynamic_cast<Item*>( item ) )
204 // TODO: myItem->contextMenu( point );
207 void ListView::setShowTreeLines( bool bShowAsTree )
209 if ( bShowAsTree )
211 setRootIsDecorated( true );
212 setTreeStepSize( 20 );
214 else
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() )
234 rename( item, 0 );
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 );
241 else
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
272 else // else
273 d->smoothScrollingEnabled = b; // update the setting
275 if( d->smoothScrollingEnabled ) // If enabled
277 // Intercept scrollbar's events
278 verticalScrollBar()->installEventFilter( this );
279 // Install the timer
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 );
291 else // If disabled
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;
332 if( b )
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 );
342 else
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;
370 d->scrollHide = b;
371 if( b )
372 setVScrollBarMode( AlwaysOff );
373 else
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
473 // Our 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;
499 qsos.init( bar );
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();
537 break;
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"
543 break;
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() );
548 break;
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() );
553 break;
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"
559 break;
560 default:
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;
577 qsos.init( bar );
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
614 else
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() )
688 return false;
690 toolTip.second.translate( xAdjust, yAdjust );
692 QToolTip::showText( helpEvent->globalPos(), toolTip.first );
696 return K3ListView::eventFilter( o, e ); // Pass the event to K3ListView
698 else
700 // kDebug( 14000 ) << "Unhandled event: [" << o << "][" << o->name() << "][" << o->metaObject()->className() << "][" << e->type() << "]";
701 return K3ListView::eventFilter( o, e ); // Pass the event to K3ListView
704 return false;
707 void ListView::slotCurrentChanged( Q3ListViewItem *item )
709 if( !item ) return;
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: