Fix nepomukindexer usage, add minimal error handling.
[kdepim.git] / kdgantt2 / kdganttgraphicsitem.cpp
blobd0bf7e4d666954f9e637ee1d42c66d1485cf465b
1 /****************************************************************************
2 ** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Gantt library.
5 **
6 ** This file may be distributed and/or modified under the terms of the
7 ** GNU General Public License version 2 as published by the Free Software
8 ** Foundation and appearing in the file LICENSE.GPL included in the
9 ** packaging of this file.
11 ** Licensees holding valid commercial KD Gantt licenses may use this file in
12 ** accordance with the KD Gantt Commercial License Agreement provided with
13 ** the Software.
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 ** See http://www.kdab.net/kdgantt for
19 ** information about KD Gantt Commercial License Agreements.
21 ** Contact info@kdab.net if any conditions of this
22 ** licensing are not clear to you.
24 **********************************************************************/
25 #include "kdganttgraphicsitem.h"
26 #include "kdganttgraphicsscene.h"
27 #include "kdganttgraphicsview.h"
28 #include "kdganttitemdelegate.h"
29 #include "kdganttconstraintgraphicsitem.h"
30 #include "kdganttconstraintmodel.h"
31 #include "kdganttabstractgrid.h"
32 #include "kdganttabstractrowcontroller.h"
34 #include <cassert>
35 #include <cmath>
36 #include <algorithm>
37 #include <iterator>
39 #include <QPainter>
40 #include <QAbstractItemModel>
41 #include <QAbstractProxyModel>
42 #include <QItemSelectionModel>
43 #include <QGraphicsSceneMouseEvent>
44 #include <QGraphicsLineItem>
46 #include <QDebug>
48 /*!\class KDGantt::GraphicsItem
49 * \internal
52 using namespace KDGantt;
54 typedef QGraphicsItem BASE;
56 namespace {
57 class Updater {
58 bool *u_ptr;
59 bool oldval;
60 public:
61 Updater( bool* u ) : u_ptr( u ), oldval( *u ) {
62 *u=true;
64 ~Updater() {
65 *u_ptr = oldval;
70 GraphicsItem::GraphicsItem( QGraphicsItem* parent, GraphicsScene* scene )
71 : BASE( parent, scene ), m_isupdating( false )
73 init();
76 GraphicsItem::GraphicsItem( const QModelIndex& idx, QGraphicsItem* parent,
77 GraphicsScene* scene )
78 : BASE( parent, scene ), m_index( idx ), m_isupdating( false )
80 init();
83 GraphicsItem::~GraphicsItem()
87 void GraphicsItem::init()
89 #if QT_VERSION >= QT_VERSION_CHECK(4,4,0)
90 setCacheMode( QGraphicsItem::DeviceCoordinateCache );
91 #endif
92 setFlags( ItemIsMovable|ItemIsSelectable|ItemIsFocusable );
93 setAcceptsHoverEvents( true );
94 setHandlesChildEvents( true );
95 setZValue( 100. );
96 m_dragline = 0;
99 int GraphicsItem::type() const
101 return Type;
104 StyleOptionGanttItem GraphicsItem::getStyleOption() const
106 StyleOptionGanttItem opt;
107 opt.itemRect = rect();
108 opt.boundingRect = boundingRect();
109 QVariant tp = m_index.model()->data( m_index, TextPositionRole );
110 if(tp.isValid()) {
111 opt.displayPosition = static_cast<StyleOptionGanttItem::Position>(tp.toInt());
112 } else {
113 #if 0
114 qDebug() << "Item" << m_index.model()->data( m_index, Qt::DisplayRole ).toString()
115 << ", ends="<<m_endConstraints.size() << ", starts="<<m_startConstraints.size();
116 #endif
117 opt.displayPosition = m_endConstraints.size()<m_startConstraints.size()?StyleOptionGanttItem::Left:StyleOptionGanttItem::Right;
118 #if 0
119 qDebug() << "choosing" << opt.displayPosition;
120 #endif
122 QVariant da = m_index.model()->data( m_index, Qt::TextAlignmentRole );
123 if ( da.isValid() ) {
124 opt.displayAlignment = static_cast< Qt::Alignment >( da.toInt() );
125 } else {
126 switch( opt.displayPosition ) {
127 case StyleOptionGanttItem::Left: opt.displayAlignment = Qt::AlignLeft|Qt::AlignVCenter; break;
128 case StyleOptionGanttItem::Right: opt.displayAlignment = Qt::AlignRight|Qt::AlignVCenter; break;
129 case StyleOptionGanttItem::Center: opt.displayAlignment = Qt::AlignCenter; break;
132 opt.grid = scene()->grid();
133 opt.text = m_index.model()->data( m_index, Qt::DisplayRole ).toString();
134 if ( isEnabled() ) opt.state |= QStyle::State_Enabled;
135 if ( isSelected() ) opt.state |= QStyle::State_Selected;
136 if ( hasFocus() ) opt.state |= QStyle::State_HasFocus;
137 return opt;
140 GraphicsScene* GraphicsItem::scene() const
142 return qobject_cast<GraphicsScene*>( QGraphicsItem::scene() );
145 void GraphicsItem::setRect( const QRectF& r )
147 #if 0
148 qDebug() << "GraphicsItem::setRect("<<r<<"), txt="<<m_index.model()->data( m_index, Qt::DisplayRole ).toString();
149 if ( m_index.model()->data( m_index, Qt::DisplayRole ).toString() == QLatin1String("Code Freeze" ) ) {
150 qDebug() << "gotcha";
152 #endif
154 prepareGeometryChange();
155 m_rect = r;
156 updateConstraintItems();
157 update();
160 void GraphicsItem::setBoundingRect( const QRectF& r )
162 prepareGeometryChange();
163 m_boundingrect = r;
164 update();
167 bool GraphicsItem::isEditable() const
169 return !scene()->isReadOnly() && m_index.model()->flags( m_index ) & Qt::ItemIsEditable;
172 void GraphicsItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option,
173 QWidget* widget )
175 Q_UNUSED( widget );
176 if ( boundingRect().isValid() && scene() ) {
177 StyleOptionGanttItem opt = getStyleOption();
178 *static_cast<QStyleOption*>(&opt) = *static_cast<const QStyleOption*>( option );
179 //opt.fontMetrics = painter->fontMetrics();
180 scene()->itemDelegate()->paintGanttItem( painter, opt, index() );
184 void GraphicsItem::setIndex( const QPersistentModelIndex& idx )
186 m_index=idx;
187 update();
190 QString GraphicsItem::ganttToolTip() const
192 // TODO: Make delegate handle this
193 const QAbstractItemModel* model = index().model();
194 if ( !model ) return QString();
195 #if 0
196 QString dbgstr;
197 QDebug( &dbgstr ) << m_index;
198 return dbgstr;
199 #endif
200 QString tip = model->data( index(), Qt::ToolTipRole ).toString();
201 if ( !tip.isNull() ) return tip;
202 else return GraphicsScene::tr( "%1 -> %2: %3" )
203 .arg( model->data( index(), StartTimeRole ).toString() )
204 .arg( model->data( index(), EndTimeRole ).toString() )
205 .arg( model->data( index(), Qt::DisplayRole ).toString() );
208 QRectF GraphicsItem::boundingRect() const
210 return m_boundingrect;
213 QPointF GraphicsItem::startConnector() const
215 return mapToScene( m_rect.right(), m_rect.top()+m_rect.height()/2. );
218 QPointF GraphicsItem::endConnector() const
220 return mapToScene( m_rect.left(), m_rect.top()+m_rect.height()/2. );
224 void GraphicsItem::constraintsChanged()
226 if ( !scene() || !scene()->itemDelegate() ) return;
227 const Span bs = scene()->itemDelegate()->itemBoundingSpan( getStyleOption(), index() );
228 const QRectF br = boundingRect();
229 setBoundingRect( QRectF( bs.start(), 0., bs.length(), br.height() ) );
232 void GraphicsItem::addStartConstraint( ConstraintGraphicsItem* item )
234 assert( item );
235 m_startConstraints << item;
236 item->setStart( startConnector() );
237 constraintsChanged();
240 void GraphicsItem::addEndConstraint( ConstraintGraphicsItem* item )
242 assert( item );
243 m_endConstraints << item;
244 item->setEnd( endConnector() );
245 constraintsChanged();
248 void GraphicsItem::removeStartConstraint( ConstraintGraphicsItem* item )
250 assert( item );
251 m_startConstraints.removeAll( item );
252 constraintsChanged();
255 void GraphicsItem::removeEndConstraint( ConstraintGraphicsItem* item )
257 assert( item );
258 m_endConstraints.removeAll( item );
259 constraintsChanged();
262 void GraphicsItem::updateConstraintItems()
264 QPointF s = startConnector();
265 QPointF e = endConnector();
266 { // Workaround for multiple definition error with MSVC6
267 Q_FOREACH( ConstraintGraphicsItem* item, m_startConstraints ) {
268 item->setStart( s );
270 {// Workaround for multiple definition error with MSVC6
271 Q_FOREACH( ConstraintGraphicsItem* item, m_endConstraints ) {
272 item->setEnd( e );
276 void GraphicsItem::updateItem( const Span& rowGeometry, const QPersistentModelIndex& idx )
278 //qDebug() << "GraphicsItem::updateItem("<<rowGeometry<<idx<<")";
279 Updater updater( &m_isupdating );
280 if ( !idx.isValid() || idx.data( ItemTypeRole )==TypeMulti ) {
281 setRect( QRectF() );
282 hide();
283 return;
286 const Span s = scene()->grid()->mapToChart( idx );
287 setPos( QPointF( s.start(), rowGeometry.start() ) );
288 setRect( QRectF( 0., 0., s.length(), rowGeometry.length() ) );
289 setIndex( idx );
290 const Span bs = scene()->itemDelegate()->itemBoundingSpan( getStyleOption(), index() );
291 //qDebug() << "boundingSpan for" << getStyleOption().text << rect() << "is" << bs;
292 setBoundingRect( QRectF( bs.start(), 0., bs.length(), rowGeometry.length() ) );
293 const int maxh = scene()->rowController()->maximumItemHeight();
294 if ( maxh < rowGeometry.length() ) {
295 QRectF r = rect();
296 const Qt::Alignment align = getStyleOption().displayAlignment;
297 if ( align & Qt::AlignTop ) {
298 // Do nothing
299 } else if ( align & Qt::AlignBottom ) {
300 r.setY( rowGeometry.length()-maxh );
301 } else {
302 // Center
303 r.setY( ( rowGeometry.length()-maxh ) / 2. );
305 r.setHeight( maxh );
306 setRect( r );
309 //scene()->setSceneRect( scene()->sceneRect().united( mapToScene( boundingRect() ).boundingRect() ) );
310 //updateConstraintItems();
313 QVariant GraphicsItem::itemChange( GraphicsItemChange change, const QVariant& value )
315 if ( !isUpdating() && change==ItemPositionChange && scene() ) {
316 QPointF newPos=value.toPointF();
317 if ( isEditable() ) {
318 newPos.setY( pos().y() );
319 return newPos;
320 } else {
321 return pos();
323 } else if ( change==QGraphicsItem::ItemSelectedChange ) {
324 if ( index().isValid() && !( index().model()->flags( index() ) & Qt::ItemIsSelectable ) ) {
325 // Reject selection attempt
326 return qVariantFromValue( false );
329 if ( value.toBool() ) {
330 scene()->selectionModel()->select( index(), QItemSelectionModel::Select );
331 } else {
332 scene()->selectionModel()->select( index(), QItemSelectionModel::Deselect );
336 return QGraphicsItem::itemChange( change, value );
339 void GraphicsItem::focusInEvent( QFocusEvent* event )
341 Q_UNUSED( event );
342 scene()->selectionModel()->select( index(), QItemSelectionModel::SelectCurrent );
345 void GraphicsItem::updateModel()
347 //qDebug() << "GraphicsItem::updateModel()";
348 if ( isEditable() ) {
349 QAbstractItemModel* model = const_cast<QAbstractItemModel*>( index().model() );
350 ConstraintModel* cmodel = scene()->constraintModel();
351 assert( model );
352 assert( cmodel );
353 if ( model ) {
354 //ItemType typ = static_cast<ItemType>( model->data( index(),
355 // ItemTypeRole ).toInt() );
356 const QModelIndex sourceIdx = scene()->summaryHandlingModel()->mapToSource( index() );
357 QList<Constraint> constraints;
358 for( QList<ConstraintGraphicsItem*>::iterator it1 = m_startConstraints.begin() ;
359 it1 != m_startConstraints.end() ;
360 ++it1 )
361 constraints.push_back((*it1)->proxyConstraint());
362 for( QList<ConstraintGraphicsItem*>::iterator it2 = m_endConstraints.begin() ;
363 it2 != m_endConstraints.end() ;
364 ++it2 )
365 constraints.push_back((*it2)->proxyConstraint());
366 if ( scene()->grid()->mapFromChart( Span( scenePos().x(), rect().width() ),
367 index(),
368 constraints ) ) {
369 scene()->updateRow( index().parent() );
375 void GraphicsItem::hoverMoveEvent( QGraphicsSceneHoverEvent* event )
377 if ( !isEditable() ) return;
378 StyleOptionGanttItem opt = getStyleOption();
379 ItemDelegate::InteractionState istate = scene()->itemDelegate()->interactionStateFor( event->pos(), opt, index() );
380 switch( istate ) {
381 case ItemDelegate::State_ExtendLeft:
382 #ifndef QT_NO_CURSOR
383 setCursor( Qt::SizeHorCursor );
384 #endif
385 scene()->itemEntered( index() );
386 break;
387 case ItemDelegate::State_ExtendRight:
388 #ifndef QT_NO_CURSOR
389 setCursor( Qt::SizeHorCursor );
390 #endif
391 scene()->itemEntered( index() );
392 break;
393 case ItemDelegate::State_Move:
394 #ifndef QT_NO_CURSOR
395 setCursor( Qt::SplitHCursor );
396 #endif
397 scene()->itemEntered( index() );
398 break;
399 default:
400 #ifndef QT_NO_CURSOR
401 unsetCursor();
402 #endif
403 break;
407 void GraphicsItem::hoverLeaveEvent( QGraphicsSceneHoverEvent* )
409 #ifndef QT_NO_CURSOR
410 unsetCursor();
411 #endif
414 void GraphicsItem::mousePressEvent( QGraphicsSceneMouseEvent* event )
416 //qDebug() << "GraphicsItem::mousePressEvent("<<event<<")";
417 StyleOptionGanttItem opt = getStyleOption();
418 m_istate = scene()->itemDelegate()->interactionStateFor( event->pos(), opt, index() );
419 m_presspos = event->pos();
420 m_pressscenepos = event->scenePos();
421 scene()->itemPressed( index() );
423 switch( m_istate ) {
424 case ItemDelegate::State_ExtendLeft:
425 case ItemDelegate::State_ExtendRight:
426 default: /* None and Move */
427 BASE::mousePressEvent( event );
428 break;
432 void GraphicsItem::mouseReleaseEvent( QGraphicsSceneMouseEvent* event )
434 //qDebug() << "GraphicsItem::mouseReleaseEvent("<<event << ")";
435 if ( !m_presspos.isNull() ) {
436 scene()->itemClicked( index() );
438 delete m_dragline; m_dragline = 0;
439 if ( scene()->dragSource() ) {
440 // Create a new constraint
441 GraphicsItem* other = qgraphicsitem_cast<GraphicsItem*>( scene()->itemAt( event->scenePos() ) );
442 if ( other && scene()->dragSource()!=other &&
443 other->mapToScene( other->rect() ).boundingRect().contains( event->scenePos() )) {
444 GraphicsView* view = qobject_cast<GraphicsView*>( event->widget()->parentWidget() );
445 if ( view ) {
446 view->addConstraint( scene()->summaryHandlingModel()->mapToSource( scene()->dragSource()->index() ),
447 scene()->summaryHandlingModel()->mapToSource( other->index() ), event->modifiers() );
450 scene()->setDragSource( 0 );
451 //scene()->update();
452 } else {
453 if ( isEditable() ) {
454 updateItemFromMouse(event->scenePos());
456 // It is important to set m_presspos to null here because
457 // when the sceneRect updates because we move the item
458 // a MouseMoveEvent will be delivered, and we have to
459 // protect against that
460 m_presspos = QPointF();
461 updateModel();
462 // without this command we sometimes get a white area at the left side of a task item
463 // after we moved that item right-ways into a grey weekend section of the scene:
464 scene()->update();
468 m_presspos = QPointF();
469 BASE::mouseReleaseEvent( event );
472 void GraphicsItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent* event )
474 StyleOptionGanttItem opt = getStyleOption();
475 ItemDelegate::InteractionState istate = scene()->itemDelegate()->interactionStateFor( event->pos(), opt, index() );
476 if ( istate != ItemDelegate::State_None ) {
477 scene()->itemDoubleClicked( index() );
479 BASE::mouseDoubleClickEvent( event );
482 void GraphicsItem::updateItemFromMouse( const QPointF& scenepos )
484 //qDebug() << "GraphicsItem::updateItemFromMouse("<<scenepos<<")";
485 const QPointF p = scenepos - m_presspos;
486 QRectF r = rect();
487 QRectF br = boundingRect();
488 switch( m_istate ) {
489 case ItemDelegate::State_Move:
490 setPos( p.x(), pos().y() );
491 break;
492 case ItemDelegate::State_ExtendLeft: {
493 const qreal brr = br.right();
494 const qreal rr = r.right();
495 const qreal delta = pos().x()-p.x();
496 setPos( p.x(), QGraphicsItem::pos().y() );
497 br.setRight( brr+delta );
498 r.setRight( rr+delta );
499 break;
501 case ItemDelegate::State_ExtendRight: {
502 const qreal rr = r.right();
503 r.setRight( scenepos.x()-pos().x() );
504 br.setWidth( br.width() + r.right()-rr );
505 break;
507 default: return;
509 setRect( r );
510 setBoundingRect( br );
513 void GraphicsItem::mouseMoveEvent( QGraphicsSceneMouseEvent* event )
515 if ( !isEditable() ) return;
516 if ( m_presspos.isNull() ) return;
518 //qDebug() << "GraphicsItem::mouseMoveEvent("<<event<<"), m_istate="<< static_cast<ItemDelegate::InteractionState>( m_istate );
519 //QPointF pos = event->pos() - m_presspos;
520 switch( m_istate ) {
521 case ItemDelegate::State_ExtendLeft:
522 case ItemDelegate::State_ExtendRight:
523 case ItemDelegate::State_Move:
524 // Check for constraint drag
525 if ( qAbs( m_pressscenepos.x()-event->scenePos().x() ) < 10.
526 && qAbs( m_pressscenepos.y()-event->scenePos().y() ) > 5. ) {
527 m_istate = ItemDelegate::State_DragConstraint;
528 m_dragline = new QGraphicsLineItem( this );
529 m_dragline->setPen( QPen( Qt::DashLine ) );
530 m_dragline->setLine(QLineF( rect().center(), event->pos() ));
531 scene()->addItem( m_dragline );
532 scene()->setDragSource( this );
533 break;
536 scene()->selectionModel()->setCurrentIndex( index(), QItemSelectionModel::Current );
537 updateItemFromMouse(event->scenePos());
538 //BASE::mouseMoveEvent(event);
539 break;
540 case ItemDelegate::State_DragConstraint: {
541 QLineF line = m_dragline->line();
542 m_dragline->setLine( QLineF( line.p1(), event->pos() ) );
543 //QGraphicsItem* item = scene()->itemAt( event->scenePos() );
544 break;