Kraxy/EBN: missing Q_OBJECT
[kphotoalbum.git] / ThumbnailView / SelectionInteraction.cpp
blob278ef0a714d969dc45894c063d65fd92e740422b
1 /* Copyright (C) 2003-2009 Jesper K. Pedersen <blackie@kde.org>
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
18 #include "SelectionInteraction.h"
19 #include "Cell.h"
20 #include "ThumbnailModel.h"
21 #include "ThumbnailFactory.h"
22 #include "CellGeometry.h"
24 #include <qtimer.h>
25 #include <QMouseEvent>
26 #include <qcursor.h>
27 #include <qapplication.h>
28 #include <kurl.h>
30 #include "MainWindow/Window.h"
31 #include "ThumbnailWidget.h"
33 ThumbnailView::SelectionInteraction::SelectionInteraction( ThumbnailFactory* factory )
34 : ThumbnailComponent( factory ),
35 _dragInProgress( false ), _dragSelectionInProgress( false )
37 _dragTimer = new QTimer( this );
38 connect( _dragTimer, SIGNAL( timeout() ), this, SLOT( handleDragSelection() ) );
42 void ThumbnailView::SelectionInteraction::mousePressEvent( QMouseEvent* event )
44 _mousePressPos = widget()->viewportToContents( event->pos() );
45 DB::ResultId mediaId = model()->imageAt( event->pos(), ViewportCoordinates );
46 _isMouseDragOperation = isMouseOverIcon( event->pos() ) && model()->isSelected( mediaId );
48 if ( deselectSelection( event ) && !model()->isSelected( mediaId ) )
49 model()->clearSelection();
51 if ( !mediaId.isNull() ) {
52 if ( event->modifiers() & Qt::ShiftModifier )
53 model()->selectRange( model()->currentItem().isNull() ? Cell() : model()->positionForMediaId( model()->currentItem() ),
54 widget()->cellAtCoordinate( event->pos(), ViewportCoordinates ) );
56 _originalSelectionBeforeDragStart = model()->selectionSet();
58 // When control is pressed selection of the file should be
59 // toggled. This is done in the release event, not here.
60 if ( !( event->modifiers() & Qt::ControlModifier ) )
61 // Otherwise add file to selected files.
62 model()->select( mediaId );
64 model()->setCurrentItem( mediaId );
65 widget()->updateCell( mediaId );
70 void ThumbnailView::SelectionInteraction::mouseMoveEvent( QMouseEvent* event )
72 if ( !(event->buttons() & Qt::LeftButton ) )
73 return;
75 if ( _isMouseDragOperation &&
76 (widget()->viewportToContents(event->pos()) - _mousePressPos ).manhattanLength() > QApplication::startDragDistance() )
77 startDrag();
79 else {
80 handleDragSelection();
81 if ( event->pos().y() < 0 || event->pos().y() > widget()->height() )
82 _dragTimer->start( 100 );
83 else
84 _dragTimer->stop();
89 void ThumbnailView::SelectionInteraction::mouseReleaseEvent( QMouseEvent* event )
91 DB::ResultId mediaId = model()->imageAt( event->pos(), ViewportCoordinates );
92 if ( (event->modifiers() & Qt::ControlModifier) &&
93 !(event->modifiers() & Qt::ShiftModifier) ) { // toggle selection of file
94 if ( (event->button() & Qt::LeftButton) )
95 model()->toggleSelection( mediaId );
97 else {
98 if ( !_dragSelectionInProgress &&
99 deselectSelection( event ) && model()->isSelected( mediaId ) ) {
100 model()->clearSelection();
101 model()->select( mediaId );
103 _originalSelectionBeforeDragStart.clear();
104 _originalSelectionBeforeDragStart.insert( mediaId );
108 _dragSelectionInProgress = false;
110 _dragTimer->stop();
114 void ThumbnailView::SelectionInteraction::handleDragSelection()
116 _dragSelectionInProgress = true;
118 Cell pos1;
119 Cell pos2;
120 calculateSelection( &pos1, &pos2 );
122 model()->setCurrentItem( pos2 );
124 // Auto scroll
125 QPoint viewportPos = widget()->viewport()->mapFromGlobal( QCursor::pos() );
126 if ( viewportPos.y() < 0 )
127 widget()->scrollBy( 0, viewportPos.y()/2 );
128 else if ( viewportPos.y() > widget()->height() )
129 widget()->scrollBy( 0, (viewportPos.y() - widget()->height())/3 );
131 model()->setSelection(_originalSelectionBeforeDragStart );
132 model()->selectRange( pos1, pos2 );
136 * Returns whether the point viewportPos is on top of the pixmap
138 bool ThumbnailView::SelectionInteraction::isMouseOverIcon( const QPoint& viewportPos ) const
140 QRect rect = iconRect( viewportPos, ViewportCoordinates );
141 return rect.contains( widget()->viewportToContents(viewportPos) );
144 void ThumbnailView::SelectionInteraction::startDrag()
146 _dragInProgress = true;
147 KUrl::List urls;
148 Q_FOREACH(DB::ImageInfoPtr info, model()->selection().fetchInfos()) {
149 const QString fileName = info->fileName(DB::AbsolutePath);
150 urls.append( fileName );
152 QDrag* drag = new QDrag( MainWindow::Window::theMainWindow() );
153 QMimeData* data = new QMimeData;
154 urls.populateMimeData(data);
155 drag->setMimeData( data );
157 drag->exec(Qt::ActionMask);
159 widget()->_mouseHandler = &(widget()->_mouseTrackingHandler);
160 _dragInProgress = false;
163 bool ThumbnailView::SelectionInteraction::isDragging() const
165 return _dragInProgress;
168 void ThumbnailView::SelectionInteraction::calculateSelection( Cell* pos1, Cell* pos2 )
170 *pos1 = widget()->cellAtCoordinate( _mousePressPos, ContentsCoordinates );
171 QPoint viewportPos = widget()->viewport()->mapFromGlobal( QCursor::pos() );
172 *pos2 = widget()->cellAtCoordinate( viewportPos, ViewportCoordinates );
174 if ( *pos1 < *pos2 ) {
175 if ( atRightSide( _mousePressPos ) )
176 *pos1 = nextCell( *pos1 );
177 if ( atLeftSide( widget()->viewportToContents( viewportPos ) ) )
178 *pos2 = prevCell( *pos2 );
180 else if ( *pos1 > *pos2 ) {
181 if ( atLeftSide( _mousePressPos ) ){
182 *pos1 = prevCell( *pos1 );
184 if ( atRightSide( widget()->viewportToContents( viewportPos ) ) ) {
185 *pos2 = nextCell( *pos2 );
189 // Selecting to the right of the thumbnailview result in a position at cols(), though we only have 0..cols()-1
190 if( pos1->col() == widget()->numCols() )
191 pos1->col()--;
192 if( pos2->col() == widget()->numCols() )
193 pos2->col()--;
196 bool ThumbnailView::SelectionInteraction::atLeftSide( const QPoint& contentCoordinates )
198 QRect rect = iconRect( contentCoordinates, ContentsCoordinates );
199 return contentCoordinates.x() < rect.left();
202 bool ThumbnailView::SelectionInteraction::atRightSide( const QPoint& contentCoordinates )
204 QRect rect = iconRect( contentCoordinates, ContentsCoordinates );
205 return contentCoordinates.x() > rect.right();
208 ThumbnailView::Cell ThumbnailView::SelectionInteraction::prevCell( const Cell& cell )
210 Cell res( cell.row(), cell.col() -1 );
211 if ( res.col() == -1 )
212 res = Cell( cell.row()-1, widget()->numCols()-1 );
213 if ( res < Cell(0,0) )
214 return Cell(0,0);
215 else
216 return res;
219 ThumbnailView::Cell ThumbnailView::SelectionInteraction::nextCell( const Cell& cell )
221 Cell res( cell.row(), cell.col()+1 );
222 if ( res.col() == widget()->numCols() )
223 res = Cell( cell.row()+1, 0 );
224 if ( res > widget()->lastCell() )
225 return widget()->lastCell();
226 else
227 return res;
230 QRect ThumbnailView::SelectionInteraction::iconRect( const QPoint& coordinate, CoordinateSystem system ) const
232 Cell pos = widget()->cellAtCoordinate( coordinate, system );
233 QRect cellRect = const_cast<ThumbnailWidget*>(widget())->cellGeometry(pos.row(), pos.col() );
234 QRect iconRect = cellGeometryInfo()->iconGeometry( pos.row(), pos.col() );
236 // map iconRect from local coordinates within the cell to the coordinates requires
237 iconRect.translate( cellRect.x(), cellRect.y() );
239 return iconRect;
242 bool ThumbnailView::SelectionInteraction::deselectSelection( const QMouseEvent* event ) const
244 // If control or shift is pressed down then do not deselect.
245 if ( event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier) )
246 return false;
248 // right mouse button on a selected image should not clear
249 if ( (event->button() & Qt::RightButton) && model()->isSelected( model()->imageAt( event->pos(), ViewportCoordinates ) ) )
250 return false;
252 // otherwise deselect
253 return true;
257 #include "SelectionInteraction.moc"