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"
20 #include "ThumbnailModel.h"
21 #include "ThumbnailFactory.h"
22 #include "CellGeometry.h"
25 #include <QMouseEvent>
27 #include <qapplication.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
) )
75 if ( _isMouseDragOperation
&&
76 (widget()->viewportToContents(event
->pos()) - _mousePressPos
).manhattanLength() > QApplication::startDragDistance() )
80 handleDragSelection();
81 if ( event
->pos().y() < 0 || event
->pos().y() > widget()->height() )
82 _dragTimer
->start( 100 );
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
);
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;
114 void ThumbnailView::SelectionInteraction::handleDragSelection()
116 _dragSelectionInProgress
= true;
120 calculateSelection( &pos1
, &pos2
);
122 model()->setCurrentItem( pos2
);
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;
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() )
192 if( pos2
->col() == widget()->numCols() )
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) )
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();
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() );
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
) )
248 // right mouse button on a selected image should not clear
249 if ( (event
->button() & Qt::RightButton
) && model()->isSelected( model()->imageAt( event
->pos(), ViewportCoordinates
) ) )
252 // otherwise deselect
257 #include "SelectionInteraction.moc"