From 460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kdgantt/KDGanttMinimizeSplitter.cpp | 1575 +++++++++++ kdgantt/KDGanttMinimizeSplitter.h | 184 ++ kdgantt/KDGanttSemiSizingControl.cpp | 413 +++ kdgantt/KDGanttSemiSizingControl.h | 90 + kdgantt/KDGanttSizingControl.cpp | 150 ++ kdgantt/KDGanttSizingControl.h | 62 + kdgantt/KDGanttView.cpp | 4847 ++++++++++++++++++++++++++++++++++ kdgantt/KDGanttView.h | 502 ++++ kdgantt/KDGanttViewEventItem.cpp | 306 +++ kdgantt/KDGanttViewEventItem.h | 68 + kdgantt/KDGanttViewItem.cpp | 2571 ++++++++++++++++++ kdgantt/KDGanttViewItem.h | 254 ++ kdgantt/KDGanttViewItemDrag.cpp | 140 + kdgantt/KDGanttViewItemDrag.h | 61 + kdgantt/KDGanttViewSubwidgets.cpp | 4048 ++++++++++++++++++++++++++++ kdgantt/KDGanttViewSubwidgets.h | 646 +++++ kdgantt/KDGanttViewSummaryItem.cpp | 377 +++ kdgantt/KDGanttViewSummaryItem.h | 72 + kdgantt/KDGanttViewTaskItem.cpp | 369 +++ kdgantt/KDGanttViewTaskItem.h | 73 + kdgantt/KDGanttViewTaskLink.cpp | 1007 +++++++ kdgantt/KDGanttViewTaskLink.h | 129 + kdgantt/KDGanttViewTaskLinkGroup.cpp | 387 +++ kdgantt/KDGanttViewTaskLinkGroup.h | 88 + kdgantt/KDGanttXMLTools.cpp | 772 ++++++ kdgantt/KDGanttXMLTools.h | 101 + kdgantt/Makefile.am | 44 + kdgantt/README_BEFORE_HACKING | 9 + kdgantt/itemAttributeDialog.ui | 737 ++++++ kdgantt/itemAttributeDialog.ui.h | 535 ++++ kdgantt/qlayoutengine_p.h | 111 + 31 files changed, 20728 insertions(+) create mode 100644 kdgantt/KDGanttMinimizeSplitter.cpp create mode 100644 kdgantt/KDGanttMinimizeSplitter.h create mode 100644 kdgantt/KDGanttSemiSizingControl.cpp create mode 100644 kdgantt/KDGanttSemiSizingControl.h create mode 100644 kdgantt/KDGanttSizingControl.cpp create mode 100644 kdgantt/KDGanttSizingControl.h create mode 100644 kdgantt/KDGanttView.cpp create mode 100644 kdgantt/KDGanttView.h create mode 100644 kdgantt/KDGanttViewEventItem.cpp create mode 100644 kdgantt/KDGanttViewEventItem.h create mode 100644 kdgantt/KDGanttViewItem.cpp create mode 100644 kdgantt/KDGanttViewItem.h create mode 100644 kdgantt/KDGanttViewItemDrag.cpp create mode 100644 kdgantt/KDGanttViewItemDrag.h create mode 100644 kdgantt/KDGanttViewSubwidgets.cpp create mode 100644 kdgantt/KDGanttViewSubwidgets.h create mode 100644 kdgantt/KDGanttViewSummaryItem.cpp create mode 100644 kdgantt/KDGanttViewSummaryItem.h create mode 100644 kdgantt/KDGanttViewTaskItem.cpp create mode 100644 kdgantt/KDGanttViewTaskItem.h create mode 100644 kdgantt/KDGanttViewTaskLink.cpp create mode 100644 kdgantt/KDGanttViewTaskLink.h create mode 100644 kdgantt/KDGanttViewTaskLinkGroup.cpp create mode 100644 kdgantt/KDGanttViewTaskLinkGroup.h create mode 100644 kdgantt/KDGanttXMLTools.cpp create mode 100644 kdgantt/KDGanttXMLTools.h create mode 100644 kdgantt/Makefile.am create mode 100644 kdgantt/README_BEFORE_HACKING create mode 100644 kdgantt/itemAttributeDialog.ui create mode 100644 kdgantt/itemAttributeDialog.ui.h create mode 100644 kdgantt/qlayoutengine_p.h (limited to 'kdgantt') diff --git a/kdgantt/KDGanttMinimizeSplitter.cpp b/kdgantt/KDGanttMinimizeSplitter.cpp new file mode 100644 index 00000000..790b381a --- /dev/null +++ b/kdgantt/KDGanttMinimizeSplitter.cpp @@ -0,0 +1,1575 @@ +/* -*- Mode: C++ -*- + $Id$ +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#include "KDGanttMinimizeSplitter.h" +#ifndef QT_NO_SPLITTER + +#include "qpainter.h" +#include "qdrawutil.h" +#include "qbitmap.h" +#if QT_VERSION >= 300 +#include "qptrlist.h" +#include "qmemarray.h" +#else +#include +#include +#define QPtrList QList +#define QMemArray QArray +#endif +#include "qlayoutengine_p.h" +#include "qobjectlist.h" +#include "qstyle.h" +#include "qapplication.h" //sendPostedEvents +#include +#include +#ifndef KDGANTT_MASTER_CVS +#include "KDGanttMinimizeSplitter.moc" +#endif + + +#ifndef DOXYGEN_SKIP_INTERNAL + +#if QT_VERSION >= 300 +static int mouseOffset; +static int opaqueOldPos = -1; //### there's only one mouse, but this is a bit risky + + +KDGanttSplitterHandle::KDGanttSplitterHandle( Qt::Orientation o, + KDGanttMinimizeSplitter *parent, const char * name ) + : QWidget( parent, name ), _activeButton( 0 ), _collapsed( false ) +{ + s = parent; + setOrientation(o); + setMouseTracking( true ); +} + +QSize KDGanttSplitterHandle::sizeHint() const +{ + return QSize(8,8); +} + +void KDGanttSplitterHandle::setOrientation( Qt::Orientation o ) +{ + orient = o; +#ifndef QT_NO_CURSOR + if ( o == KDGanttMinimizeSplitter::Horizontal ) + setCursor( splitHCursor ); + else + setCursor( splitVCursor ); +#endif +} + + +void KDGanttSplitterHandle::mouseMoveEvent( QMouseEvent *e ) +{ + updateCursor( e->pos() ); + if ( !(e->state()&LeftButton) ) + return; + + if ( _activeButton != 0) + return; + + QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos())) + - mouseOffset; + if ( opaque() ) { + s->moveSplitter( pos, id() ); + } else { + int min = pos; int max = pos; + s->getRange( id(), &min, &max ); + s->setRubberband( QMAX( min, QMIN(max, pos ))); + } + _collapsed = false; +} + +void KDGanttSplitterHandle::mousePressEvent( QMouseEvent *e ) +{ + if ( e->button() == LeftButton ) { + _activeButton = onButton( e->pos() ); + mouseOffset = s->pick(e->pos()); + if ( _activeButton != 0) + repaint(); + updateCursor( e->pos() ); + } +} + +void KDGanttSplitterHandle::updateCursor( const QPoint& p) +{ + if ( onButton( p ) != 0 ) { + setCursor( arrowCursor ); + } + else { + if ( orient == KDGanttMinimizeSplitter::Horizontal ) + setCursor( splitHCursor ); + else + setCursor( splitVCursor ); + } +} + + +void KDGanttSplitterHandle::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( _activeButton != 0 ) { + if ( onButton( e->pos() ) == _activeButton ) + { + int pos; + int min, max; + if ( !_collapsed ) { + s->expandPos( id(), &min, &max ); + if ( s->minimizeDirection() == KDGanttMinimizeSplitter::Left + || s->minimizeDirection() == KDGanttMinimizeSplitter::Up ) { + pos = min; + } + else { + pos = max; + } + + _origPos = s->pick(mapToParent( QPoint( 0,0 ) )); + s->moveSplitter( pos, id() ); + _collapsed = true; + } + else { + s->moveSplitter( _origPos, id() ); + _collapsed = false; + } + + } + _activeButton = 0; + updateCursor( e->pos() ); + } + else { + if ( !opaque() && e->button() == LeftButton ) { + QCOORD pos = s->pick(parentWidget()->mapFromGlobal(e->globalPos())) + - mouseOffset; + s->setRubberband( -1 ); + s->moveSplitter( pos, id() ); + } + } + repaint(); +} + +int KDGanttSplitterHandle::onButton( const QPoint& p ) +{ + QValueList list = buttonRegions(); + int index = 1; + for( QValueList::Iterator it = list.begin(); it != list.end(); ++it ) { + QRect rect = (*it).boundingRect(); + rect.setLeft( rect.left()- 4 ); + rect.setRight( rect.right() + 4); + rect.setTop( rect.top()- 4 ); + rect.setBottom( rect.bottom() + 4); + if ( rect.contains( p ) ) { + return index; + } + index++; + } + return 0; +} + + +QValueList KDGanttSplitterHandle::buttonRegions() +{ + QValueList list; + + int sw = 8; + int voffset[] = { (int) -sw*3, (int) sw*3 }; + for ( int i = 0; i < 2; i++ ) { + QPointArray arr; + if ( !_collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Right || + _collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Left) { + int mid = height()/2 + voffset[i]; + arr.setPoints( 3, + 1, mid - sw + 4, + sw-3, mid, + 1, mid + sw -4); + } + else if ( !_collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Left || + _collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Right ) { + int mid = height()/2 + voffset[i]; + arr.setPoints( 3, + sw-4, mid - sw + 4, + 0, mid, + sw-4, mid + sw - 4); + } + else if ( !_collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Up || + _collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Down) { + int mid = width()/2 + voffset[i]; + arr.setPoints( 3, + mid - sw + 4, sw-4, + mid, 0, + mid + sw - 4, sw-4 ); + } + else if ( !_collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Down || + _collapsed && s->minimizeDirection() == KDGanttMinimizeSplitter::Up ) { + int mid = width()/2 + voffset[i]; + arr.setPoints( 3, + mid - sw + 4, 1, + mid, sw-3, + mid + sw -4, 1); + } + list.append( arr ); + } + return list; +} + +void KDGanttSplitterHandle::paintEvent( QPaintEvent * ) +{ + QPixmap buffer( size() ); + QPainter p( &buffer ); + + // Draw the splitter rectangle + p.setBrush( colorGroup().background() ); + p.setPen( colorGroup().foreground() ); + p.drawRect( rect() ); + parentWidget()->style().drawPrimitive( QStyle::PE_Panel, &p, rect(), + parentWidget()->colorGroup()); + + int sw = 8; // Hardcoded, given I didn't use styles anymore, I didn't like to use their size + + // arrow color + QColor col = colorGroup().background().dark( 200 ); + p.setBrush( col ); + p.setPen( col ); + + QValueList list = buttonRegions(); + int index = 1; + for ( QValueList::Iterator it = list.begin(); it != list.end(); ++it ) { + if ( index == _activeButton ) { + p.save(); + p.translate( parentWidget()->style().pixelMetric( QStyle::PM_ButtonShiftHorizontal ), + parentWidget()->style().pixelMetric( QStyle::PM_ButtonShiftVertical ) ); + p.drawPolygon( *it, true ); + p.restore(); + } + else { + p.drawPolygon( *it, true ); + } + index++; + } + + // Draw the lines between the arrows + if ( s->minimizeDirection() == KDGanttMinimizeSplitter::Left || + s->minimizeDirection() == KDGanttMinimizeSplitter::Right ) { + int mid = height()/2; + p.drawLine ( 2, mid - sw, 2, mid + sw ); + p.drawLine ( 4, mid - sw, 4, mid + sw ); + } + else if ( s->minimizeDirection() == KDGanttMinimizeSplitter::Up || + s->minimizeDirection() == KDGanttMinimizeSplitter::Down ) { + int mid = width()/2; + p.drawLine( mid -sw, 2, mid +sw, 2 ); + p.drawLine( mid -sw, 4, mid +sw, 4 ); + } + bitBlt( this, 0, 0, &buffer ); +} +#endif + +class QSplitterLayoutStruct +{ +public: + KDGanttMinimizeSplitter::ResizeMode mode; + QCOORD sizer; + bool isSplitter; + QWidget *wid; +}; + +class QSplitterData +{ +public: + QSplitterData() : opaque( FALSE ), firstShow( TRUE ) {} + + QPtrList list; + bool opaque; + bool firstShow; +}; + +void kdganttGeomCalc( QMemArray &chain, int start, int count, int pos, + int space, int spacer ); +#endif // DOXYGEN_SKIP_INTERNAL + + +/*! + \class KDGanttMinimizeSplitter KDGanttMinimizeSplitter.h + \brief The KDGanttMinimizeSplitter class implements a splitter + widget with minimize buttons. + + This class (and its documentation) is largely a copy of Qt's + QSplitter; the copying was necessary because QSplitter is not + extensible at all. QSplitter and its documentation are licensed + according to the GPL and the Qt Professional License (if you hold + such a license) and are (C) Trolltech AS. + + A splitter lets the user control the size of child widgets by + dragging the boundary between the children. Any number of widgets + may be controlled. + + To show a QListBox, a QListView and a QTextEdit side by side: + + \code + KDGanttMinimizeSplitter *split = new KDGanttMinimizeSplitter( parent ); + QListBox *lb = new QListBox( split ); + QListView *lv = new QListView( split ); + QTextEdit *ed = new QTextEdit( split ); + \endcode + + In KDGanttMinimizeSplitter, the boundary can be either horizontal or + vertical. The default is horizontal (the children are side by side) + but you can use setOrientation( QSplitter::Vertical ) to set it to + vertical. + + Use setResizeMode() to specify + that a widget should keep its size when the splitter is resized. + + Although KDGanttMinimizeSplitter normally resizes the children only + at the end of a resize operation, if you call setOpaqueResize( TRUE + ) the widgets are resized as often as possible. + + The initial distribution of size between the widgets is determined + by the initial size of each widget. You can also use setSizes() to + set the sizes of all the widgets. The function sizes() returns the + sizes set by the user. + + If you hide() a child, its space will be distributed among the other + children. It will be reinstated when you show() it again. It is also + possible to reorder the widgets within the splitter using + moveToFirst() and moveToLast(). +*/ + + + +static QSize minSize( const QWidget* /*w*/ ) +{ + return QSize(0,0); +} + +// This is the original version of minSize +static QSize minSizeHint( const QWidget* w ) +{ + QSize min = w->minimumSize(); + QSize s; + if ( min.height() <= 0 || min.width() <= 0 ) + s = w->minimumSizeHint(); + if ( min.height() > 0 ) + s.setHeight( min.height() ); + if ( min.width() > 0 ) + s.setWidth( min.width() ); + return s.expandedTo(QSize(0,0)); +} + + + +/*! + Constructs a horizontal splitter with the \a parent and \a + name arguments being passed on to the QFrame constructor. +*/ +KDGanttMinimizeSplitter::KDGanttMinimizeSplitter( QWidget *parent, const char *name ) + :QFrame(parent,name,WPaintUnclipped) +{ +#if QT_VERSION >= 300 + orient = Horizontal; + init(); +#endif +} + +/*! + Constructs a splitter with orientation \a o with the \a parent + and \a name arguments being passed on to the QFrame constructor. +*/ +KDGanttMinimizeSplitter::KDGanttMinimizeSplitter( Orientation o, QWidget *parent, const char *name ) + :QFrame(parent,name,WPaintUnclipped) +{ +#if QT_VERSION >= 300 + orient = o; + init(); +#endif +} + +/*! + Destroys the splitter and any children. +*/ +KDGanttMinimizeSplitter::~KDGanttMinimizeSplitter() +{ +#if QT_VERSION >= 300 + data->list.setAutoDelete( TRUE ); + delete data; +#endif +} + + +#if QT_VERSION >= 300 +void KDGanttMinimizeSplitter::init() +{ + data = new QSplitterData; + if ( orient == Horizontal ) + setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum) ); + else + setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Expanding) ); +} +#endif + + + +/*! + \brief the orientation of the splitter + + By default the orientation is horizontal (the widgets are side by side). + The possible orientations are Qt:Vertical and Qt::Horizontal (the default). +*/ +void KDGanttMinimizeSplitter::setOrientation( Orientation o ) +{ +#if QT_VERSION >= 300 + if ( orient == o ) + return; + orient = o; + + if ( orient == Horizontal ) + setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); + else + setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) ); + + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->isSplitter ) + ((KDGanttSplitterHandle*)s->wid)->setOrientation( o ); + s = data->list.next(); // ### next at end of loop, no iterator + } + recalc( isVisible() ); +#endif +} + + +#if QT_VERSION >= 300 +/*! + Reimplemented from superclass. +*/ +void KDGanttMinimizeSplitter::resizeEvent( QResizeEvent * ) +{ + doResize(); +} + + +/* + Inserts the widget \a w at the end (or at the beginning if \a first + is TRUE) of the splitter's list of widgets. + + It is the responsibility of the caller of this function to make sure + that \a w is not already in the splitter and to call recalcId if + needed. (If \a first is TRUE, then recalcId is very probably + needed.) +*/ +QSplitterLayoutStruct *KDGanttMinimizeSplitter::addWidget( QWidget *w, bool first ) +{ + QSplitterLayoutStruct *s; + KDGanttSplitterHandle *newHandle = 0; + if ( data->list.count() > 0 ) { + s = new QSplitterLayoutStruct; + s->mode = KeepSize; + QString tmp = "qt_splithandle_"; + tmp += w->name(); + newHandle = new KDGanttSplitterHandle( orientation(), this, tmp.latin1() ); + s->wid = newHandle; + newHandle->setId(data->list.count()); + s->isSplitter = TRUE; + s->sizer = pick( newHandle->sizeHint() ); + if ( first ) + data->list.insert( 0, s ); + else + data->list.append( s ); + } + s = new QSplitterLayoutStruct; + s->mode = Stretch; + s->wid = w; + if ( !testWState( WState_Resized ) && w->sizeHint().isValid() ) + s->sizer = pick( w->sizeHint() ); + else + s->sizer = pick( w->size() ); + s->isSplitter = FALSE; + if ( first ) + data->list.insert( 0, s ); + else + data->list.append( s ); + if ( newHandle && isVisible() ) + newHandle->show(); //will trigger sending of post events + return s; +} + + +/*! + Tells the splitter that a child widget has been inserted or removed. + The event is passed in \a c. +*/ +void KDGanttMinimizeSplitter::childEvent( QChildEvent *c ) +{ + if ( c->type() == QEvent::ChildInserted ) { + if ( !c->child()->isWidgetType() ) + return; + + if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) ) + return; + + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->wid == c->child() ) + return; + s = data->list.next(); + } + addWidget( (QWidget*)c->child() ); + recalc( isVisible() ); + + } else if ( c->type() == QEvent::ChildRemoved ) { + QSplitterLayoutStruct *p = 0; + if ( data->list.count() > 1 ) + p = data->list.at(1); //remove handle _after_ first widget. + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->wid == c->child() ) { + data->list.removeRef( s ); + delete s; + if ( p && p->isSplitter ) { + data->list.removeRef( p ); + delete p->wid; //will call childEvent + delete p; + } + recalcId(); + doResize(); + return; + } + p = s; + s = data->list.next(); + } + } +} + + +/*! + Shows a rubber band at position \a p. If \a p is negative, the + rubber band is removed. +*/ +void KDGanttMinimizeSplitter::setRubberband( int p ) +{ + QPainter paint( this ); + paint.setPen( gray ); + paint.setBrush( gray ); + paint.setRasterOp( XorROP ); + QRect r = contentsRect(); + const int rBord = 3; //Themable???? + int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); + if ( orient == Horizontal ) { + if ( opaqueOldPos >= 0 ) + paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(), + 2*rBord, r.height() ); + if ( p >= 0 ) + paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() ); + } else { + if ( opaqueOldPos >= 0 ) + paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord, + r.width(), 2*rBord ); + if ( p >= 0 ) + paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord ); + } + opaqueOldPos = p; +} + + +/*! Reimplemented from superclass. */ +bool KDGanttMinimizeSplitter::event( QEvent *e ) +{ + if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) { + recalc( isVisible() ); + if ( e->type() == QEvent::Show ) + data->firstShow = FALSE; + } + return QWidget::event( e ); +} + + +/*! + \obsolete + + Draws the splitter handle in the rectangle described by \a x, \a y, + \a w, \a h using painter \a p. + \sa QStyle::drawPrimitive() +*/ +void KDGanttMinimizeSplitter::drawSplitter( QPainter *p, + QCOORD x, QCOORD y, QCOORD w, QCOORD h ) +{ + style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(), + (orientation() == Qt::Horizontal ? + QStyle::Style_Horizontal : 0)); +} + + +/*! + Returns the id of the splitter to the right of or below the widget \a w, + or 0 if there is no such splitter + (i.e. it is either not in this KDGanttMinimizeSplitter or it is at the end). +*/ +int KDGanttMinimizeSplitter::idAfter( QWidget* w ) const +{ + QSplitterLayoutStruct *s = data->list.first(); + bool seen_w = FALSE; + while ( s ) { + if ( s->isSplitter && seen_w ) + return data->list.at(); + if ( !s->isSplitter && s->wid == w ) + seen_w = TRUE; + s = data->list.next(); + } + return 0; +} + + +/*! + Moves the left/top edge of the splitter handle with id \a id as + close as possible to position \a p, which is the distance from the + left (or top) edge of the widget. + + For Arabic and Hebrew the layout is reversed, and using this + function to set the position of the splitter might lead to + unexpected results, since in Arabic and Hebrew the position of + splitter one is to the left of the position of splitter zero. + + \sa idAfter() +*/ +void KDGanttMinimizeSplitter::moveSplitter( QCOORD p, int id ) +{ + p = adjustPos( p, id ); + + QSplitterLayoutStruct *s = data->list.at(id); + int oldP = orient == Horizontal ? s->wid->x() : s->wid->y(); + bool upLeft; + if ( QApplication::reverseLayout() && orient == Horizontal ) { + p += s->wid->width(); + upLeft = p > oldP; + } else + upLeft = p < oldP; + + moveAfter( p, id, upLeft ); + moveBefore( p-1, id-1, upLeft ); + + storeSizes(); +} + + +void KDGanttMinimizeSplitter::setG( QWidget *w, int p, int s, bool isSplitter ) +{ + if ( orient == Horizontal ) { + if ( QApplication::reverseLayout() && orient == Horizontal && !isSplitter ) + p = contentsRect().width() - p - s; + w->setGeometry( p, contentsRect().y(), s, contentsRect().height() ); + } else + w->setGeometry( contentsRect().x(), p, contentsRect().width(), s ); +} + + +/* + Places the right/bottom edge of the widget at \a id at position \a pos. + + \sa idAfter() +*/ +void KDGanttMinimizeSplitter::moveBefore( int pos, int id, bool upLeft ) +{ + if( id < 0 ) + return; + QSplitterLayoutStruct *s = data->list.at(id); + if ( !s ) + return; + QWidget *w = s->wid; + if ( w->isHidden() ) { + moveBefore( pos, id-1, upLeft ); + } else if ( s->isSplitter ) { + int pos1, pos2; + int dd = s->sizer; + if( QApplication::reverseLayout() && orient == Horizontal ) { + pos1 = pos; + pos2 = pos + dd; + } else { + pos2 = pos - dd; + pos1 = pos2 + 1; + } + if ( upLeft ) { + setG( w, pos1, dd, TRUE ); + moveBefore( pos2, id-1, upLeft ); + } else { + moveBefore( pos2, id-1, upLeft ); + setG( w, pos1, dd, TRUE ); + } + } else { + int dd, newLeft, nextPos; + if( QApplication::reverseLayout() && orient == Horizontal ) { + dd = w->geometry().right() - pos; + dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); + newLeft = pos+1; + nextPos = newLeft + dd; + } else { + dd = pos - pick( w->pos() ) + 1; + dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); + newLeft = pos-dd+1; + nextPos = newLeft - 1; + } + setG( w, newLeft, dd, TRUE ); + moveBefore( nextPos, id-1, upLeft ); + } +} + + +/* + Places the left/top edge of the widget at \a id at position \a pos. + + \sa idAfter() +*/ +void KDGanttMinimizeSplitter::moveAfter( int pos, int id, bool upLeft ) +{ + QSplitterLayoutStruct *s = id < int(data->list.count()) ? + data->list.at(id) : 0; + if ( !s ) + return; + QWidget *w = s->wid; + if ( w->isHidden() ) { + moveAfter( pos, id+1, upLeft ); + } else if ( pick( w->pos() ) == pos ) { + //No need to do anything if it's already there. + return; + } else if ( s->isSplitter ) { + int dd = s->sizer; + int pos1, pos2; + if( QApplication::reverseLayout() && orient == Horizontal ) { + pos2 = pos - dd; + pos1 = pos2 + 1; + } else { + pos1 = pos; + pos2 = pos + dd; + } + if ( upLeft ) { + setG( w, pos1, dd, TRUE ); + moveAfter( pos2, id+1, upLeft ); + } else { + moveAfter( pos2, id+1, upLeft ); + setG( w, pos1, dd, TRUE ); + } + } else { + int left = pick( w->pos() ); + int right, dd,/* newRight,*/ newLeft, nextPos; + if ( QApplication::reverseLayout() && orient == Horizontal ) { + dd = pos - left + 1; + dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); + newLeft = pos-dd+1; + nextPos = newLeft - 1; + } else { + right = pick( w->geometry().bottomRight() ); + dd = right - pos + 1; + dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); + /*newRight = pos+dd-1;*/ + newLeft = pos; + nextPos = newLeft + dd; + } + setG( w, newLeft, dd, TRUE ); + /*if( right != newRight )*/ + moveAfter( nextPos, id+1, upLeft ); + } +} + + +void KDGanttMinimizeSplitter::expandPos( int id, int* min, int* max ) +{ + QSplitterLayoutStruct *s = data->list.at(id-1); + QWidget* w = s->wid; + *min = pick( w->mapToParent( QPoint(0,0) ) ); + + if ( (uint) id == data->list.count() ) { + pick( size() ); + } + else { + QSplitterLayoutStruct *s = data->list.at(id+1); + QWidget* w = s->wid; + *max = pick( w->mapToParent( QPoint( w->width(), w->height() ) ) ) -8; + } +} + + +/*! + Returns the valid range of the splitter with id \a id in \a *min and \a *max. + + \sa idAfter() +*/ + +void KDGanttMinimizeSplitter::getRange( int id, int *min, int *max ) +{ + int minB = 0; //before + int maxB = 0; + int minA = 0; + int maxA = 0; //after + int n = data->list.count(); + if ( id < 0 || id >= n ) + return; + int i; + for ( i = 0; i < id; i++ ) { + QSplitterLayoutStruct *s = data->list.at(i); + if ( s->wid->isHidden() ) { + //ignore + } else if ( s->isSplitter ) { + minB += s->sizer; + maxB += s->sizer; + } else { + minB += pick( minSize(s->wid) ); + maxB += pick( s->wid->maximumSize() ); + } + } + for ( i = id; i < n; i++ ) { + QSplitterLayoutStruct *s = data->list.at(i); + if ( s->wid->isHidden() ) { + //ignore + } else if ( s->isSplitter ) { + minA += s->sizer; + maxA += s->sizer; + } else { + minA += pick( minSize(s->wid) ); + maxA += pick( s->wid->maximumSize() ); + } + } + QRect r = contentsRect(); + if ( orient == Horizontal && QApplication::reverseLayout() ) { + int splitterWidth = style().pixelMetric(QStyle::PM_SplitterWidth, this); + if ( min ) + *min = pick(r.topRight()) - QMIN( maxB, pick(r.size())-minA ) - splitterWidth; + if ( max ) + *max = pick(r.topRight()) - QMAX( minB, pick(r.size())-maxA ) - splitterWidth; + } else { + if ( min ) + *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA ); + if ( max ) + *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA ); + } +} + + +/*! + Returns the closest legal position to \a p of the splitter with id \a id. + + \sa idAfter() +*/ + +int KDGanttMinimizeSplitter::adjustPos( int p, int id ) +{ + int min = 0; + int max = 0; + getRange( id, &min, &max ); + p = QMAX( min, QMIN( p, max ) ); + + return p; +} + + +void KDGanttMinimizeSplitter::doResize() +{ + QRect r = contentsRect(); + int i; + int n = data->list.count(); + QMemArray a( n ); + for ( i = 0; i< n; i++ ) { + a[i].init(); + QSplitterLayoutStruct *s = data->list.at(i); + if ( s->wid->isHidden() ) { + a[i].stretch = 0; + a[i].sizeHint = a[i].minimumSize = 0; + a[i].maximumSize = 0; + } else if ( s->isSplitter ) { + a[i].stretch = 0; + a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer; + a[i].empty = FALSE; + } else if ( s->mode == KeepSize ) { + a[i].stretch = 0; + a[i].minimumSize = pick( minSize(s->wid) ); + a[i].sizeHint = s->sizer; + a[i].maximumSize = pick( s->wid->maximumSize() ); + a[i].empty = FALSE; + } else if ( s->mode == FollowSizeHint ) { + a[i].stretch = 0; + a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() ); + a[i].maximumSize = pick( s->wid->maximumSize() ); + a[i].empty = FALSE; + } else { //proportional + a[i].stretch = s->sizer; + a[i].maximumSize = pick( s->wid->maximumSize() ); + a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) ); + a[i].empty = FALSE; + } + } + + kdganttGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 ); + + for ( i = 0; i< n; i++ ) { + QSplitterLayoutStruct *s = data->list.at(i); + setG( s->wid, a[i].pos, a[i].size ); + } + +} + + +void KDGanttMinimizeSplitter::recalc( bool update ) +{ + int fi = 2*frameWidth(); + int maxl = fi; + int minl = fi; + int maxt = QWIDGETSIZE_MAX; + int mint = fi; + int n = data->list.count(); + bool first = TRUE; + /* + The splitter before a hidden widget is always hidden. + The splitter before the first visible widget is hidden. + The splitter before any other visible widget is visible. + */ + for ( int i = 0; i< n; i++ ) { + QSplitterLayoutStruct *s = data->list.at(i); + if ( !s->isSplitter ) { + QSplitterLayoutStruct *p = (i > 0) ? data->list.at( i-1 ) : 0; + if ( p && p->isSplitter ) + if ( first || s->wid->isHidden() ) + p->wid->hide(); //may trigger new recalc + else + p->wid->show(); //may trigger new recalc + if ( !s->wid->isHidden() ) + first = FALSE; + } + } + + bool empty=TRUE; + for ( int j = 0; j< n; j++ ) { + QSplitterLayoutStruct *s = data->list.at(j); + if ( !s->wid->isHidden() ) { + empty = FALSE; + if ( s->isSplitter ) { + minl += s->sizer; + maxl += s->sizer; + } else { + QSize minS = minSize(s->wid); + minl += pick( minS ); + maxl += pick( s->wid->maximumSize() ); + mint = QMAX( mint, trans( minS )); + int tm = trans( s->wid->maximumSize() ); + if ( tm > 0 ) + maxt = QMIN( maxt, tm ); + } + } + } + if ( empty ) { + if ( parentWidget() != 0 && parentWidget()->inherits("KDGanttMinimizeSplitter") ) { + // nested splitters; be nice + maxl = maxt = 0; + } else { + // KDGanttMinimizeSplitter with no children yet + maxl = QWIDGETSIZE_MAX; + } + } else { + maxl = QMIN( maxl, QWIDGETSIZE_MAX ); + } + if ( maxt < mint ) + maxt = mint; + + if ( orient == Horizontal ) { + setMaximumSize( maxl, maxt ); + setMinimumSize( minl, mint ); + } else { + setMaximumSize( maxt, maxl ); + setMinimumSize( mint, minl ); + } + if ( update ) + doResize(); +} + +/*! + Sets resize mode of \a w to \a mode. + + \sa ResizeMode +*/ + +void KDGanttMinimizeSplitter::setResizeMode( QWidget *w, ResizeMode mode ) +{ + processChildEvents(); + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->wid == w ) { + s->mode = mode; + return; + } + s = data->list.next(); + } + s = addWidget( w, TRUE ); + s->mode = mode; +} + + +/*! + Returns TRUE if opaque resize is on; otherwise returns FALSE. + + \sa setOpaqueResize() +*/ + +bool KDGanttMinimizeSplitter::opaqueResize() const +{ + return data->opaque; +} + + +/*! + If \a on is TRUE then opaque resizing is turned on; otherwise + opaque resizing is turned off. + Opaque resizing is initially turned off. + + \sa opaqueResize() +*/ + +void KDGanttMinimizeSplitter::setOpaqueResize( bool on ) +{ + data->opaque = on; +} + + +/*! + Moves widget \a w to the leftmost/top position. +*/ + +void KDGanttMinimizeSplitter::moveToFirst( QWidget *w ) +{ + processChildEvents(); + bool found = FALSE; + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->wid == w ) { + found = TRUE; + QSplitterLayoutStruct *p = data->list.prev(); + if ( p ) { // not already at first place + data->list.take(); //take p + data->list.take(); // take s + data->list.insert( 0, p ); + data->list.insert( 0, s ); + } + break; + } + s = data->list.next(); + } + if ( !found ) + addWidget( w, TRUE ); + recalcId(); +} + + +/*! + Moves widget \a w to the rightmost/bottom position. +*/ + +void KDGanttMinimizeSplitter::moveToLast( QWidget *w ) +{ + processChildEvents(); + bool found = FALSE; + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->wid == w ) { + found = TRUE; + data->list.take(); // take s + QSplitterLayoutStruct *p = data->list.current(); + if ( p ) { // the splitter handle after s + data->list.take(); //take p + data->list.append( p ); + } + data->list.append( s ); + break; + } + s = data->list.next(); + } + if ( !found ) + addWidget( w); + recalcId(); +} + + +void KDGanttMinimizeSplitter::recalcId() +{ + int n = data->list.count(); + for ( int i = 0; i < n; i++ ) { + QSplitterLayoutStruct *s = data->list.at(i); + if ( s->isSplitter ) + ((KDGanttSplitterHandle*)s->wid)->setId(i); + } +} + + +/*! Reimplemented from superclass. +*/ +QSize KDGanttMinimizeSplitter::sizeHint() const +{ + constPolish(); + int l = 0; + int t = 0; + if ( children() ) { + const QObjectList * c = children(); + QObjectListIt it( *c ); + QObject * o; + + while( (o=it.current()) != 0 ) { + ++it; + if ( o->isWidgetType() && + !((QWidget*)o)->isHidden() ) { + QSize s = ((QWidget*)o)->sizeHint(); + if ( s.isValid() ) { + l += pick( s ); + t = QMAX( t, trans( s ) ); + } + } + } + } + return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l ); +} + + +/*! +\reimp +*/ + +QSize KDGanttMinimizeSplitter::minimumSizeHint() const +{ + constPolish(); + int l = 0; + int t = 0; + if ( children() ) { + const QObjectList * c = children(); + QObjectListIt it( *c ); + QObject * o; + + while( (o=it.current()) != 0 ) { + ++it; + if ( o->isWidgetType() && + !((QWidget*)o)->isHidden() ) { + QSize s = minSizeHint((QWidget*)o); + if ( s.isValid() ) { + l += pick( s ); + t = QMAX( t, trans( s ) ); + } + } + } + } + return orientation() == Horizontal ? QSize( l, t ) : QSize( t, l ); +} + + +/* + Calculates stretch parameters from current sizes +*/ + +void KDGanttMinimizeSplitter::storeSizes() +{ + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( !s->isSplitter ) + s->sizer = pick( s->wid->size() ); + s = data->list.next(); + } +} + + +#if 0 // ### remove this code ASAP + +/*! + Hides \a w if \a hide is TRUE and updates the splitter. + + \warning Due to a limitation in the current implementation, + calling QWidget::hide() will not work. +*/ + +void KDGanttMinimizeSplitter::setHidden( QWidget *w, bool hide ) +{ + if ( w == w1 ) { + w1show = !hide; + } else if ( w == w2 ) { + w2show = !hide; + } else { +#ifdef QT_CHECK_RANGE + qWarning( "KDGanttMinimizeSplitter::setHidden(), unknown widget" ); +#endif + return; + } + if ( hide ) + w->hide(); + else + w->show(); + recalc( TRUE ); +} + + +/*! + Returns the hidden status of \a w +*/ + +bool KDGanttMinimizeSplitter::isHidden( QWidget *w ) const +{ + if ( w == w1 ) + return !w1show; + else if ( w == w2 ) + return !w2show; +#ifdef QT_CHECK_RANGE + else + qWarning( "KDGanttMinimizeSplitter::isHidden(), unknown widget" ); +#endif + return FALSE; +} +#endif + + +/*! + Returns a list of the size parameters of all the widgets in this + splitter. + + Giving the values to another splitter's setSizes() function will + produce a splitter with the same layout as this one. + + Note that if you want to iterate over the list, you should + iterate over a copy, e.g. + \code + QValueList list = mySplitter.sizes(); + QValueList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + + \sa setSizes() +*/ + +QValueList KDGanttMinimizeSplitter::sizes() const +{ + if ( !testWState(WState_Polished) ) { + QWidget* that = (QWidget*) this; + that->polish(); + } + QValueList list; + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( !s->isSplitter ) + list.append( s->sizer ); + s = data->list.next(); + } + return list; +} + + + +/*! + Sets the size parameters to the values given in \a list. + If the splitter is horizontal, the values set the sizes from + left to right. If it is vertical, the sizes are applied from + top to bottom. + Extra values in \a list are ignored. + + If \a list contains too few values, the result is undefined + but the program will still be well-behaved. + + \sa sizes() +*/ + +void KDGanttMinimizeSplitter::setSizes( QValueList list ) +{ + processChildEvents(); + QValueList::Iterator it = list.begin(); + QSplitterLayoutStruct *s = data->list.first(); + while ( s && it != list.end() ) { + if ( !s->isSplitter ) { + s->sizer = *it; + ++it; + } + s = data->list.next(); + } + doResize(); +} + + +/*! + Gets all posted child events, ensuring that the internal state of + the splitter is consistent. +*/ + +void KDGanttMinimizeSplitter::processChildEvents() +{ + QApplication::sendPostedEvents( this, QEvent::ChildInserted ); +} + + +/*! + Reimplemented from superclass. +*/ + +void KDGanttMinimizeSplitter::styleChange( QStyle& old ) +{ + int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); + QSplitterLayoutStruct *s = data->list.first(); + while ( s ) { + if ( s->isSplitter ) + s->sizer = sw; + s = data->list.next(); + } + doResize(); + QFrame::styleChange( old ); +} + +#endif + +/*! + Specifies the direction of the minimize buttons. + If the orientation of the splitter is horizontal then with + KDGanttMinimizeSplitter::Left or KDGanttMinimizeSplitter::Right should be used, + otherwise either KDGanttMinimizeSplitter::Up or KDGanttMinimizeSplitter::Down + should be used. +*/ +void KDGanttMinimizeSplitter::setMinimizeDirection( Direction direction ) +{ + _direction = direction; +} + +/*! + Returns the direction of the minimize buttons. +*/ +KDGanttMinimizeSplitter::Direction KDGanttMinimizeSplitter::minimizeDirection() const +{ + return _direction; +} + +/* + This is a copy of qGeomCalc() in qlayoutengine.cpp which + unfortunately isn't exported. +*/ +static inline int toFixed( int i ) { return i * 256; } +static inline int fRound( int i ) { + return ( i % 256 < 128 ) ? i / 256 : 1 + i / 256; +} +void kdganttGeomCalc( QMemArray &chain, int start, int count, int pos, + int space, int spacer ) +{ + typedef int fixed; + int cHint = 0; + int cMin = 0; + int cMax = 0; + int sumStretch = 0; + int spacerCount = 0; + + bool wannaGrow = FALSE; // anyone who really wants to grow? + // bool canShrink = FALSE; // anyone who could be persuaded to shrink? + + int i; + for ( i = start; i < start + count; i++ ) { + chain[i].done = FALSE; + cHint += chain[i].sizeHint; + cMin += chain[i].minimumSize; + cMax += chain[i].maximumSize; + sumStretch += chain[i].stretch; + if ( !chain[i].empty ) + spacerCount++; + wannaGrow = wannaGrow || chain[i].expansive; + } + + int extraspace = 0; + if ( spacerCount ) + spacerCount--; // only spacers between things + if ( space < cMin + spacerCount * spacer ) { + // qDebug("not enough space"); + for ( i = start; i < start+count; i++ ) { + chain[i].size = chain[i].minimumSize; + chain[i].done = TRUE; + } + } else if ( space < cHint + spacerCount*spacer ) { + // Less space than sizeHint, but more than minimum. + // Currently take space equally from each, like in Qt 2.x. + // Commented-out lines will give more space to stretchier items. + int n = count; + int space_left = space - spacerCount*spacer; + int overdraft = cHint - space_left; + //first give to the fixed ones: + for ( i = start; i < start+count; i++ ) { + if ( !chain[i].done && chain[i].minimumSize >= chain[i].sizeHint) { + chain[i].size = chain[i].sizeHint; + chain[i].done = TRUE; + space_left -= chain[i].sizeHint; + // sumStretch -= chain[i].stretch; + n--; + } + } + bool finished = n == 0; + while ( !finished ) { + finished = TRUE; + fixed fp_over = toFixed( overdraft ); + fixed fp_w = 0; + + for ( i = start; i < start+count; i++ ) { + if ( chain[i].done ) + continue; + // if ( sumStretch <= 0 ) + fp_w += fp_over / n; + // else + // fp_w += (fp_over * chain[i].stretch) / sumStretch; + int w = fRound( fp_w ); + chain[i].size = chain[i].sizeHint - w; + fp_w -= toFixed( w ); //give the difference to the next + if ( chain[i].size < chain[i].minimumSize ) { + chain[i].done = TRUE; + chain[i].size = chain[i].minimumSize; + finished = FALSE; + overdraft -= chain[i].sizeHint - chain[i].minimumSize; + // sumStretch -= chain[i].stretch; + n--; + break; + } + } + } + } else { //extra space + int n = count; + int space_left = space - spacerCount*spacer; + // first give to the fixed ones, and handle non-expansiveness + for ( i = start; i < start + count; i++ ) { + if ( !chain[i].done && (chain[i].maximumSize <= chain[i].sizeHint + || wannaGrow && !chain[i].expansive) ) { + chain[i].size = chain[i].sizeHint; + chain[i].done = TRUE; + space_left -= chain[i].sizeHint; + sumStretch -= chain[i].stretch; + n--; + } + } + extraspace = space_left; + /* + Do a trial distribution and calculate how much it is off. + If there are more deficit pixels than surplus pixels, give + the minimum size items what they need, and repeat. + Otherwise give to the maximum size items, and repeat. + + I have a wonderful mathematical proof for the correctness + of this principle, but unfortunately this comment is too + small to contain it. + */ + int surplus, deficit; + do { + surplus = deficit = 0; + fixed fp_space = toFixed( space_left ); + fixed fp_w = 0; + for ( i = start; i < start+count; i++ ) { + if ( chain[i].done ) + continue; + extraspace = 0; + if ( sumStretch <= 0 ) + fp_w += fp_space / n; + else + fp_w += (fp_space * chain[i].stretch) / sumStretch; + int w = fRound( fp_w ); + chain[i].size = w; + fp_w -= toFixed( w ); // give the difference to the next + if ( w < chain[i].sizeHint ) { + deficit += chain[i].sizeHint - w; + } else if ( w > chain[i].maximumSize ) { + surplus += w - chain[i].maximumSize; + } + } + if ( deficit > 0 && surplus <= deficit ) { + // give to the ones that have too little + for ( i = start; i < start+count; i++ ) { + if ( !chain[i].done && + chain[i].size < chain[i].sizeHint ) { + chain[i].size = chain[i].sizeHint; + chain[i].done = TRUE; + space_left -= chain[i].sizeHint; + sumStretch -= chain[i].stretch; + n--; + } + } + } + if ( surplus > 0 && surplus >= deficit ) { + // take from the ones that have too much + for ( i = start; i < start+count; i++ ) { + if ( !chain[i].done && + chain[i].size > chain[i].maximumSize ) { + chain[i].size = chain[i].maximumSize; + chain[i].done = TRUE; + space_left -= chain[i].maximumSize; + sumStretch -= chain[i].stretch; + n--; + } + } + } + } while ( n > 0 && surplus != deficit ); + if ( n == 0 ) + extraspace = space_left; + } + + // as a last resort, we distribute the unwanted space equally + // among the spacers (counting the start and end of the chain). + + //### should do a sub-pixel allocation of extra space + int extra = extraspace / ( spacerCount + 2 ); + int p = pos + extra; + for ( i = start; i < start+count; i++ ) { + chain[i].pos = p; + p = p + chain[i].size; + if ( !chain[i].empty ) + p += spacer+extra; + } +} + +#endif + +/*! + \enum KDGanttMinimizeSplitter::Direction + + The values of this enumeration describe into which direction the + splitter will collapse its child widgets. By extension, it also + specifies the orientation of the splitter; collapsing to the left or + to the right results in a horizontal splitter, collapsing to the top + or bottom in a vertical splitter. +*/ + +/*! + \fn Orientation KDGanttMinimizeSplitter::orientation() const + + Returns the orientation of the splitter. +*/ + +/*! \enum KDGanttMinimizeSplitter::ResizeMode + + This enum type describes how KDGanttMinimizeSplitter will resize each of its child widgets. The currently defined values are: + + Stretch: the widget will be resized when the splitter + itself is resized. + + KeepSize: KDGanttMinimizeSplitter will try to keep this widget's size + unchanged. + + FollowSizeHint: KDGanttMinimizeSplitter will resize the widget when the + widget's size hint changes. +*/ + diff --git a/kdgantt/KDGanttMinimizeSplitter.h b/kdgantt/KDGanttMinimizeSplitter.h new file mode 100644 index 00000000..1581d615 --- /dev/null +++ b/kdgantt/KDGanttMinimizeSplitter.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++ -*- + $Id$ +*/ + +/**************************************************************************** + ** Copyright (C) 2001-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef KDGANTTMINIMIZESPLITTER_H +#define KDGANTTMINIMIZESPLITTER_H + +#ifndef QT_H +#include "qframe.h" +#include "qvaluelist.h" +#endif // QT_H + +#ifndef QT_NO_SPLITTER + +class QSplitterData; +class QSplitterLayoutStruct; + +class KDGanttMinimizeSplitter : public QFrame +{ + Q_OBJECT + Q_ENUMS( Direction ) + Q_PROPERTY( Orientation orientation READ orientation WRITE setOrientation ) + Q_PROPERTY( Direction minimizeDirection READ minimizeDirection WRITE setMinimizeDirection ) + +public: + enum ResizeMode { Stretch, KeepSize, FollowSizeHint }; + enum Direction { Left, Right, Up, Down }; + + KDGanttMinimizeSplitter( QWidget* parent=0, const char* name=0 ); + KDGanttMinimizeSplitter( Orientation, QWidget* parent=0, const char* name=0 ); + ~KDGanttMinimizeSplitter(); + + virtual void setOrientation( Orientation ); + Orientation orientation() const { return orient; } + + void setMinimizeDirection( Direction ); + Direction minimizeDirection() const; + +#if QT_VERSION >= 300 + virtual void setResizeMode( QWidget *w, ResizeMode ); + virtual void setOpaqueResize( bool = TRUE ); + bool opaqueResize() const; + + void moveToFirst( QWidget * ); + void moveToLast( QWidget * ); + + void refresh() { recalc( TRUE ); } + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + QValueList sizes() const; + void setSizes( QValueList ); + + void expandPos( int id, int* min, int* max ); +protected: + void childEvent( QChildEvent * ); + + bool event( QEvent * ); + void resizeEvent( QResizeEvent * ); + + int idAfter( QWidget* ) const; + + void moveSplitter( QCOORD pos, int id ); + virtual void drawSplitter( QPainter*, QCOORD x, QCOORD y, + QCOORD w, QCOORD h ); + void styleChange( QStyle& ); + int adjustPos( int , int ); + virtual void setRubberband( int ); + void getRange( int id, int*, int* ); + +private: + void init(); + void recalc( bool update = FALSE ); + void doResize(); + void storeSizes(); + void processChildEvents(); + QSplitterLayoutStruct *addWidget( QWidget*, bool first = FALSE ); + void recalcId(); + void moveBefore( int pos, int id, bool upLeft ); + void moveAfter( int pos, int id, bool upLeft ); + void setG( QWidget *w, int p, int s, bool isSplitter = FALSE ); + + QCOORD pick( const QPoint &p ) const + { return orient == Horizontal ? p.x() : p.y(); } + QCOORD pick( const QSize &s ) const + { return orient == Horizontal ? s.width() : s.height(); } + + QCOORD trans( const QPoint &p ) const + { return orient == Vertical ? p.x() : p.y(); } + QCOORD trans( const QSize &s ) const + { return orient == Vertical ? s.width() : s.height(); } + + QSplitterData *data; +#endif + +private: + Orientation orient; + Direction _direction; +#ifndef DOXYGEN_SKIP_INTERNAL + friend class KDGanttSplitterHandle; +#endif +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + KDGanttMinimizeSplitter( const KDGanttMinimizeSplitter & ); + KDGanttMinimizeSplitter& operator=( const KDGanttMinimizeSplitter & ); +#endif +}; + +#ifndef DOXYGEN_SKIP_INTERNAL +// This class was continued from a verbatim copy of the +// QSplitterHandle pertaining to the Qt Enterprise License and the +// GPL. It has only been renamed to KDGanttSplitterHandler in order to +// avoid a symbol clash on some platforms. +class KDGanttSplitterHandle : public QWidget +{ + Q_OBJECT +#if QT_VERSION >= 300 +public: + KDGanttSplitterHandle( Qt::Orientation o, + KDGanttMinimizeSplitter *parent, const char* name=0 ); + void setOrientation( Qt::Orientation o ); + Qt::Orientation orientation() const { return orient; } + + bool opaque() const { return s->opaqueResize(); } + + QSize sizeHint() const; + + int id() const { return myId; } // data->list.at(id())->wid == this + void setId( int i ) { myId = i; } + +protected: + QValueList buttonRegions(); + void paintEvent( QPaintEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void mousePressEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + int onButton( const QPoint& p ); + void updateCursor( const QPoint& p ); + +private: + Qt::Orientation orient; + bool opaq; + int myId; + + KDGanttMinimizeSplitter *s; + int _activeButton; + bool _collapsed; + int _origPos; +#endif +}; +#endif + +#endif // QT_NO_SPLITTER + +#endif // KDGANTTMINIMIZESPLITTER_H diff --git a/kdgantt/KDGanttSemiSizingControl.cpp b/kdgantt/KDGanttSemiSizingControl.cpp new file mode 100644 index 00000000..91629662 --- /dev/null +++ b/kdgantt/KDGanttSemiSizingControl.cpp @@ -0,0 +1,413 @@ +/* -*- Mode: C++ -*- + $Id$ +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttSemiSizingControl.h" +#include +#include +#include +#include +#include +#include +/*! + \class KDGanttSemiSizingControl KDGanttSemiSizingControl.h + This class provides exactly one child widget with a button for + minimizing and restoring. You can also specify a so-called minimize + widget that will be shown in place of the child widget while the + latter one is minimized. While the child widget is not minimized, + the minimize widget will not be visible. + + If you add more than one child widget (besides the minimize widget), + only the last one added will be visible. +*/ + + +/*! + Constructs an empty semi sizing control with horizontal + orientation and the control arrow button on top of the controlled + widget. + + \param parent the parent widget. This parameter is passed to the + base class. + \param name the internal widget name. This parameter is passed to + the base class. +*/ + +KDGanttSemiSizingControl::KDGanttSemiSizingControl( QWidget* parent, + const char* name ) : + KDGanttSizingControl( parent, name ), _orient( Horizontal ), + _arrowPos( Before ), _minimizedWidget(0), _maximizedWidget(0) +{ + init(); +} + + +/*! + Constructs an empty semi sizing control with the specified + orientation and the control arrow button either on top or left of + the controlled widget (depending on the orientation). + + \param orientation the orientation of the splitter + \param parent the parent widget. This parameter is passed to the + base class. + \param name the internal widget name. This parameter is passed to + the base class. +*/ + +KDGanttSemiSizingControl::KDGanttSemiSizingControl( Orientation orientation, + QWidget* parent, + const char* name ) : + KDGanttSizingControl( parent, name ), _orient( orientation ), + _arrowPos( Before ), _minimizedWidget(0), _maximizedWidget(0) +{ + init(); +} + + +/*! + Constructs an empty semi sizing control with the specified + orientation and position of the control arrow button. + + \param arrowPosition specifies whether the control arrow button + should appear before or after the controlled widget + \param orientation the orientation of the splitter + \param parent the parent widget. This parameter is passed to the + base class. + \param name the internal widget name. This parameter is passed to + the base class. +*/ + +KDGanttSemiSizingControl::KDGanttSemiSizingControl( ArrowPosition arrowPosition, + Orientation orientation, + QWidget* parent, + const char* name ) : + KDGanttSizingControl( parent, name ), _orient( orientation ), + _arrowPos( arrowPosition ), _minimizedWidget(0), _maximizedWidget(0) +{ + init(); +} + + +/*! + Specifies the widget that should be shown while the child widget is + minimized. This so-called minimize widget should be a child widget + of the KDGanttSemiSizingControl. + + \param widget the minimize widget + \sa minimizedWidget() +*/ + +void KDGanttSemiSizingControl::setMinimizedWidget( QWidget* widget ) +{ + _minimizedWidget = widget; + if( _minimizedWidget ) _minimizedWidget->hide(); + setup(); +} + + +/*! + Returns the widget that is shown while the child widget is + minimized. + + \return the minimize widget + \sa setMinimizedWidget() +*/ + +QWidget* KDGanttSemiSizingControl::minimizedWidget() const +{ + return _minimizedWidget; +} + +/*! + Specifies the widget that should be shown while the child widget is + maximized. This so-called maximize widget should be a child widget + of the KDGanttSemiSizingControl. + + \param widget the minimize widget + \sa maximizedWidget() +*/ + +void KDGanttSemiSizingControl::setMaximizedWidget( QWidget* widget ) +{ + _maximizedWidget = widget; + //if( _maximizedWidget ) _maximizedWidget->show(); + setup(); +} + +/*! + Returns the widget that is shown while the child widget is + maximized. + + \return the maximize widget + \sa setMaximizedWidget() +*/ + +QWidget* KDGanttSemiSizingControl::maximizedWidget() const +{ + return _maximizedWidget; +} + + + +/*! + Sets the orientation of the simple sizing control. + + \param orientation the new orientation + \sa orientation() +*/ + +void KDGanttSemiSizingControl::setOrientation( Qt::Orientation orientation ) +{ + if ( _orient != orientation ) { + _orient = orientation; + setup(); + } +} + + +/*! + Returns the orientation of the simple sizing control. + \return the orientation + \sa setOrientation() +*/ + +Qt::Orientation KDGanttSemiSizingControl::orientation() const +{ + return _orient; +} + + +/*! + Returns the position of the control arrow button. + + \param arrowPosition the position of the control arrow button + \sa arrowPosition() +*/ + +void KDGanttSemiSizingControl::setArrowPosition( ArrowPosition arrowPosition ) +{ + if ( _arrowPos != arrowPosition ) { + _arrowPos = arrowPosition; + setup(); + } +} + + +/*! + Returns the position of the control arrow button. + + \return the position of the control arrow button + \sa setArrowPosition() +*/ + +KDGanttSemiSizingControl::ArrowPosition KDGanttSemiSizingControl::arrowPosition() const +{ + return _arrowPos; +} + + +/*! + \enum KDGanttSemiSizingControl::ArrowPosition + + This enum is used for specifying whether the control arrow button + should appear before (on top of, left of) or after (below, right of) + the controlled widget. +*/ + +void KDGanttSemiSizingControl::init() +{ + _but = new QPushButton( this ); + _but->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); + connect( _but, SIGNAL( clicked() ), this, SLOT(changeState()) ); + _layout = 0; + QWhatsThis::add( _but, "Click on this button to show the \nlegend at the bottom of the widget"); + QToolTip::add( _but, "Show / hide legend"); + + +} + +void KDGanttSemiSizingControl::setup() +{ + //-------------------------------------------------- Setup layout + delete _layout; + QBoxLayout* butLayout; // _layout will delete me + + if ( _orient == Horizontal || isMinimized() ) + _layout = new QHBoxLayout( this ); + else + _layout = new QVBoxLayout( this ); + + if ( _orient == Vertical && !isMinimized() ) + butLayout = new QHBoxLayout( _layout ); + else + butLayout = new QVBoxLayout( _layout ); + + + + //---------------------------------------- Set the arrow on the button + if ( !isMinimized() ) { + _but->setPixmap( pixmap( Down ) ); + } + else { + if ( _arrowPos == Before ) { + _but->setPixmap( pixmap( Right ) ); + } + else { + _but->setPixmap( pixmap( Left ) ); + } + } + + //------------------------------ Setup the button at the correct possition + if ( _arrowPos == After && _orient == Vertical && !isMinimized() ) { + butLayout->addStretch( 1 ); + butLayout->addWidget( _but, 0, Qt::AlignLeft ); + } + else { + butLayout->addWidget( _but, 0, Qt::AlignRight ); + butLayout->addStretch( 1 ); + } + + // Set widget in the correct possition + QWidget* widget; + /* ************************** old code *************** + if ( isMinimized() ) + widget = _minimizedWidget; + else + widget = _maximizedWidget; + if( widget ) { + if ( _arrowPos == Before || _orient == Vertical && !isMinimized() ) + _layout->addWidget( widget, 1 ); + else + _layout->insertWidget( 0, widget, 1 ); + } + ************************************************** */ + // hack for the usage in KDGantt as pop-up legend widget + // for this purpose, + // the _maximizedWidget must be a child of the parent of this widget + + if ( isMinimized() ) { + widget = _minimizedWidget; + if( widget ) { + if ( _arrowPos == Before || _orient == Vertical && !isMinimized() ) + _layout->addWidget( widget, 1 ); + else + _layout->insertWidget( 0, widget, 1 ); + } + } + else { + if ( _arrowPos == Before || _orient == Vertical && !isMinimized() ) + _layout->addStretch( 1 ); + else + _layout->insertStretch( 0, 1 ); + widget = _maximizedWidget; + // the following is only the special case + // arrowPos == Before and _orient == Vertical + //widget->move( 0+x(), _but->height()+y()); + } +} + + +/*! + Restores or minimizes the child widget. \a minimize() does exactly the + opposite to this method. + + \param restore true to restore, false to minimize + \sa minimize() +*/ + +void KDGanttSemiSizingControl::restore( bool restore ) +{ + if ( ! restore ) { + minimize( true ); + } + else { + if( _maximizedWidget ) _maximizedWidget->show(); + if( _minimizedWidget ) _minimizedWidget->hide(); + KDGanttSizingControl::restore( restore ); + setup(); + } +} + +/*! + Restores or minimizes the child widget. \a restore() does exactly the + opposite to this method. + + \param minimize true to minimize, false to restore + \sa restore() + +*/ + +void KDGanttSemiSizingControl::minimize( bool minimize ) +{ + if ( ! minimize ) { + restore( true ); + } + else { + if( _minimizedWidget ) _minimizedWidget->show(); + if( _maximizedWidget ) _maximizedWidget->hide(); + KDGanttSizingControl::minimize( minimize ); + setup(); + } +} + +QPixmap KDGanttSemiSizingControl::pixmap( Direction direction ) { + int s = 10; + QPixmap pix( s, s ); + pix.fill( blue ); + + QPointArray arr; + switch ( direction ) { + case Up: arr.setPoints( 3, 0, s-1, s-1, s-1, 0, s/2 ); ;break; + case Down: arr.setPoints( 3, 0, 0, s-1, 0, s/2, s-1 ); break; + case Left: arr.setPoints( 3, s-1, 0, s-1, s-1, 0, s/2 ); break; + case Right: arr.setPoints( 3, 0,0, s-1, s/2, 0, s-1 ); break; + } + + QPainter p( &pix ); + p.setPen( black ); + p.setBrush( colorGroup().button() ); + p.drawPolygon( arr ); + QBitmap bit( s, s ); + bit.fill( color0 ); + + QPainter p2( &bit ); + p2.setPen( color1 ); + p2.setBrush( color1 ); + p2.drawPolygon( arr ); + pix.setMask( bit ); + return pix; +} + +#ifndef KDGANTT_MASTER_CVS +#include "KDGanttSemiSizingControl.moc" +#endif diff --git a/kdgantt/KDGanttSemiSizingControl.h b/kdgantt/KDGanttSemiSizingControl.h new file mode 100644 index 00000000..6fb56e32 --- /dev/null +++ b/kdgantt/KDGanttSemiSizingControl.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++ -*- + $Id$ +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#ifndef KDGANTTSEMISIZINGCONTROL_H +#define KDGANTTSEMISIZINGCONTROL_H + +#include "KDGanttSizingControl.h" +#include +class QPushButton; +class QBoxLayout; + +class KDGanttSemiSizingControl : public KDGanttSizingControl +{ + Q_PROPERTY( ArrowPosition arrowPosition READ arrowPosition WRITE setArrowPosition ) + Q_ENUMS( ArrowPosition ) + Q_OBJECT + +public: + enum ArrowPosition { Before, After }; + + KDGanttSemiSizingControl( QWidget* parent = 0, const char* name = 0 ); + KDGanttSemiSizingControl( Orientation orientation, QWidget* parent = 0, + const char* name = 0 ); + KDGanttSemiSizingControl( ArrowPosition arrowPosition, + Orientation orientation, QWidget* parent = 0, + const char* name = 0 ); + + void setMinimizedWidget( QWidget* widget ); + void setMaximizedWidget( QWidget* widget ); + QWidget* minimizedWidget() const; + QWidget* maximizedWidget() const; + + void setOrientation( Qt::Orientation orientation ); + Qt::Orientation orientation() const; + + void setArrowPosition( ArrowPosition arrowPosition ); + ArrowPosition arrowPosition() const; + +public slots: + virtual void minimize( bool minimize ); + virtual void restore( bool restore ); + +protected: + void setup(); + void init(); + enum Direction {Left, Right, Up, Down }; + QPixmap pixmap( Direction ); + +private: + Orientation _orient; + ArrowPosition _arrowPos; + QWidget* _minimizedWidget; + QWidget* _maximizedWidget; + QBoxLayout* _layout; + QPushButton* _but; +}; + + +#endif diff --git a/kdgantt/KDGanttSizingControl.cpp b/kdgantt/KDGanttSizingControl.cpp new file mode 100644 index 00000000..5f4c004a --- /dev/null +++ b/kdgantt/KDGanttSizingControl.cpp @@ -0,0 +1,150 @@ +/* -*- Mode: C++ -*- + $Id$ +*/ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttSizingControl.h" + +/*! + \class KDGanttSizingControl KDGanttSizingControl.h + This class is a common-base class for all sizing controls in this + library. + + It provides common signals and slots for minimizing and restoring + child widgets. + + This class cannot be instantiated by itself, use one of the + subclasses instead. +*/ + +/*! + Constructs an empty KDGanttSizing Control. + + \param parent the parent widget. This parameter is passed to the + base class. + \param name the internal widget name. This parameter is passed to + the base class. + \param f window flags. This parameter is passed to the base class. + +*/ + +KDGanttSizingControl::KDGanttSizingControl( QWidget* parent, const char* name, WFlags f ) + :QWidget( parent, name, f ), _isMinimized( false ) +{ +} + + +/*! + Restores or minimizes the child widget. \a minimize() does exactly the + opposite to this method. + + \param restore true to restore, false to minimize + \sa minimize() +*/ + +void KDGanttSizingControl::restore( bool restore ) +{ + _isMinimized = !restore; + if ( restore ) + emit restored( this ); + else + emit minimized( this ); +} + + + + +/*! + Restores or minimizes the child widget. \a restore() does exactly the + opposite to this method. + + \param minimize true to minimize, false to restore + \sa restore() + +*/ + +void KDGanttSizingControl::minimize( bool minimize ) +{ + _isMinimized = minimize; + if ( minimize ) + emit minimized( this ); + else + emit restored( this ); +} + + +/*! + Returns whether the widget is minimized. +*/ + +bool KDGanttSizingControl::isMinimized() const +{ + return _isMinimized; +} + +/*! + Change state from either minimized to restored or visa versa. +*/ + +void KDGanttSizingControl::changeState() +{ + restore(_isMinimized); +} + + +/*! + \fn void KDGanttSizingControl::minimized( KDGanttSizingControl* ) + + This signal is emitted when the user hides a controlled widget. The + KDGanttSizingControl pointer given as parameter is a pointer to the widget + itself. Normally the sender should not know the receiver, but in this + case the receiver is likely the widget containing the KDGanttSizingControl, + and when the KDGanttSizingControl widget is minimized/restored it might want + to change stretching for the widget. See the example + test/semisizingcontrol +*/ + + +/*! + \fn void KDGanttSizingControl::restored( KDGanttSizingControl* ) + + This signal is emitted when the user unhides a controlled widget. The + KDGanttSizingControl pointer given as parameter is a pointer to the widget + itself. Normally the sender should not know the receiver, but in this + case the receiver is likely the widget containing the KDGanttSizingControl, + and when the KDGanttSizingControl widget is minimized/restored it might want + to change stretching for the widget. See the example + test/semisizingcontrol +*/ + +#ifndef KDGANTT_MASTER_CVS +#include "KDGanttSizingControl.moc" +#endif diff --git a/kdgantt/KDGanttSizingControl.h b/kdgantt/KDGanttSizingControl.h new file mode 100644 index 00000000..12fa075e --- /dev/null +++ b/kdgantt/KDGanttSizingControl.h @@ -0,0 +1,62 @@ +/* -*- Mode: C++ -*- + $Id$ +*/ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef KDGANTTSIZINGCONTROL_H +#define KDGANTTSIZINGCONTROL_H + +#include + +class KDGanttSizingControl : public QWidget +{ + Q_OBJECT + +public: + bool isMinimized() const; + +protected: + KDGanttSizingControl( QWidget* parent = 0, const char* name = 0, WFlags f = 0 ); + +public slots: + virtual void minimize( bool minimize ); + virtual void restore( bool restore ); + void changeState(); + +signals: + void minimized( KDGanttSizingControl* ); + void restored( KDGanttSizingControl* ); + +private: + bool _isMinimized; +}; + + +#endif diff --git a/kdgantt/KDGanttView.cpp b/kdgantt/KDGanttView.cpp new file mode 100644 index 00000000..0b09ce10 --- /dev/null +++ b/kdgantt/KDGanttView.cpp @@ -0,0 +1,4847 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttView.h" +#include "KDGanttViewSubwidgets.h" +#include "KDGanttMinimizeSplitter.h" +#include "KDGanttViewItem.h" +#include "KDGanttXMLTools.h" +#include "itemAttributeDialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef KDGANTT_MASTER_CVS +#include "KDGanttView.moc" +#endif + +#if defined KDAB_EVAL +#include "../evaldialog/evaldialog.h" +#endif + +/*! + \class KDGanttView KDGanttView.h + This class represents a Gantt view with the Gantt chart, the header, + an optional listview and an optional legend. + + In order to set up a Gantt view, create an object of this class, and + populate it with a number of \a KDGanttViewItem objects. + + If you experience problems with the repainting of the content of the + Gantt View after scrolling, call \a setRepaintMode(). +*/ + +/*! + Constructs an empty KDGanttView. + + \param parent the widget parent + \param name the internal debugging name +*/ + +KDGanttView::KDGanttView( QWidget* parent, const char* name ) + : KDGanttMinimizeSplitter( Qt::Vertical, parent, name ), + myCanvasView(0), + myTimeHeaderScroll(0), + mFixedHorizon( false ) +{ +#if defined KDAB_EVAL + EvalDialog::checkEvalLicense( "KD Gantt" ); +#endif + myCurrentItem = 0; + setMinimizeDirection ( KDGanttMinimizeSplitter::Down ); + mySplitter = new KDGanttMinimizeSplitter( this ); + mySplitter->setMinimizeDirection ( KDGanttMinimizeSplitter::Left ); + leftWidget = new QVBox( mySplitter ); + rightWidget = new QVBox( mySplitter ); + + myLegend = new KDLegendWidget( leftWidget, this ); + spacerLeft = new QHBox( leftWidget ); + myListView = new KDListView(leftWidget, this); + myListView->setVScrollBarMode (QScrollView::AlwaysOff ); + connect( myListView, SIGNAL( selectionChanged( QListViewItem* ) ), + this, SLOT( slotSelectionChanged( QListViewItem* ) ) ); + + connect( myListView, SIGNAL( mouseButtonClicked ( int, QListViewItem * , const QPoint &, int ) ), this, SLOT( slotmouseButtonClicked ( int , QListViewItem * , const QPoint &, int ) ) ); + connect( myListView, SIGNAL( contextMenuRequested ( QListViewItem * , const QPoint &, int ) ), this, SLOT( slotcontextMenuRequested ( QListViewItem * , const QPoint & , int ) ) ); + + connect( myListView, SIGNAL(currentChanged( QListViewItem * ) ), this, SLOT(slotCurrentChanged ( QListViewItem * ) ) ); + connect( myListView, SIGNAL(itemRenamed ( QListViewItem * , int , const QString & ) ), this, SLOT(slotItemRenamed ( QListViewItem *, int , const QString & ) ) ); + connect( myListView, SIGNAL(mouseButtonPressed( int, QListViewItem * , const QPoint &, int ) ), this, SLOT(slotMouseButtonPressed ( int , QListViewItem * , const QPoint & , int ) ) ); + + //connect( myListView, SIGNAL( ), this, SLOT( ) ); + myTimeTable = new KDTimeTableWidget (rightWidget,this); + + spacerRight = new QWidget( rightWidget ); + + myTimeHeaderContainer = new QHBox( rightWidget ); + myTimeHeaderContainer->setFrameStyle( QFrame::NoFrame ); + myTimeHeaderContainer->setMargin( 0 ); + myTimeHeaderScroll = new QScrollView ( myTimeHeaderContainer ); + myTimeHeaderScroll->setHScrollBarMode( QScrollView::AlwaysOff ); + myTimeHeaderScroll->setVScrollBarMode( QScrollView::AlwaysOff ); + timeHeaderSpacerWidget = new QWidget( myTimeHeaderContainer ); + + + /* + myTimeHeaderScroll = new QScrollView ( rightWidget ); + myTimeHeaderScroll->setHScrollBarMode( QScrollView::AlwaysOff ); + myTimeHeaderScroll->setVScrollBarMode( QScrollView::AlwaysOn ); + */ + //myTimeHeader = new KDTimeHeaderWidget (rightWidget,this); + myTimeHeader = new KDTimeHeaderWidget (myTimeHeaderScroll->viewport(),this); + myTimeHeaderScroll->addChild( myTimeHeader ); + myTimeHeaderScroll->viewport()->setBackgroundColor( myTimeHeader->backgroundColor() ); + timeHeaderSpacerWidget->setBackgroundColor( myTimeHeader->backgroundColor() ); + myCanvasView = new KDGanttCanvasView (this,myTimeTable,rightWidget); + myTimeHeaderScroll->setFrameStyle( QFrame::NoFrame ); + // + myCanvasView->setFrameStyle( QFrame::NoFrame ); + myCanvasView->setMargin( 0 ); + // + myTimeHeaderScroll->setMargin( 0 );//myCanvasView->frameWidth() ); + setFrameStyle(myListView->frameStyle()); + setLineWidth( 2 ); + myListView->setFrameStyle( QFrame::NoFrame ); + myListView->setMargin( 0 ); + QObject::connect(myListView, SIGNAL ( expanded ( QListViewItem * ) ) , myTimeTable , SLOT( expandItem(QListViewItem * ))) ; + QObject::connect(myListView, SIGNAL (collapsed ( QListViewItem * ) ) , myTimeTable , SLOT(collapseItem(QListViewItem * ))) ; + + timeHeaderSpacerWidget->setFixedWidth(myCanvasView->verticalScrollBar()->width() ); + listViewIsVisible = true; + chartIsEditable = true; + editorIsEnabled = true; + _displaySubitemsAsGroup = false; + initDefaults(); + _showHeader = false; + + myTextColor = Qt::black; + myLegendItems = new QPtrList; + //QObject::connect( this, SIGNAL (itemDoubleClicked( KDGanttViewItem* ) ) , this, SLOT( editItem( KDGanttViewItem* ))) ; + myItemAttributeDialog = new itemAttributeDialog(); + setRepaintMode( KDGanttView::Medium ); + //setRepaintMode( KDGanttView::Always ); + setShowLegendButton( true ); + setHeaderVisible( false ); + + // now connecting the widgets + connect(myCanvasView->horizontalScrollBar(), SIGNAL ( valueChanged ( int )) ,myTimeHeaderScroll->horizontalScrollBar(), SLOT( setValue ( int))) ; + connect(myCanvasView, SIGNAL ( heightResized( int )) ,myTimeTable, SLOT( checkHeight ( int))) ; + connect(myCanvasView, SIGNAL ( widthResized( int )) ,myTimeHeader, SLOT( checkWidth ( int))) ; + + QObject::connect(myCanvasView->verticalScrollBar(), SIGNAL ( valueChanged ( int ) ) ,myListView->verticalScrollBar(), SLOT( setValue ( int ))) ; + connect(myTimeHeader, SIGNAL ( sizeChanged( int ) ) ,this, SLOT(slotHeaderSizeChanged() )) ; + connect(myTimeHeader, SIGNAL ( sizeChanged( int ) ) ,myTimeTable, SLOT(resetWidth( int ) )) ; + connect(myListView, SIGNAL ( contentsMoving ( int, int ) ) ,myCanvasView, SLOT( moveMyContent( int, int ))) ; + connect(myTimeTable, SIGNAL ( heightComputed ( int ) ) ,myCanvasView, SLOT( setMyContentsHeight( int ))) ; + // the next three are for adding new ticks at left/right + connect( myCanvasView->horizontalScrollBar(), SIGNAL (prevLine () ) ,this, SLOT(addTickLeft())); + connect( myCanvasView->horizontalScrollBar(), SIGNAL (nextLine () ) ,this, SLOT(addTickRight())); + connect( myCanvasView->horizontalScrollBar(), SIGNAL (valueChanged ( int ) ) ,this, SLOT( enableAdding( int ))); + + // now initing + fCenterTimeLineAfterShow = false; + fDragEnabled = false; + fDropEnabled = false; + closingBlocked = false; + myTimeHeader->computeTicks(); + centerTimelineAfterShow( QDateTime::currentDateTime () ); + setDisplayEmptyTasksAsLine( false ); + QValueList list; + list.append(240); + list.append(530); + mySplitter->setSizes( list ); + myTimeTable->setBlockUpdating();// block updating until this->show() is called +} + + + +KDGanttView::~KDGanttView() +{ + setUpdateEnabled(false); + // delete cut item, if there is any + myCanvasView->resetCutPaste( 0 ); + myTimeTable->clearTaskLinks(); +} +/*! + Enables or disables updating of the content of the Gantt view. + To avoid flickering in the Gantt view while inserting large amounts + of Gantt items, you should call + + bool upd = KDGanttView::getUpdateEnabled(); + KDGanttView::settUpdateEnabled( false ); + ... insert items here ... + KDGanttView::settUpdateEnabled( upd ); + + With this code, you avoid unwanted side effects with other parts in + your code, where you disable (and re-enable) the update. + + When calling setUpdateEnabled( true ), + all the content is recomputed, resized, and updated. + + Before calling show() for the first time, updating is disabled. + When calling show(), updating is automatically enabled. + + \param enable if true, the content of the Gantt view is updated after + every insertion of a new item. + \sa getUpdateEnabled() +*/ +void KDGanttView::setUpdateEnabled( bool enable ) +{ + myTimeTable->setBlockUpdating( !enable ); + if ( enable ) { + myTimeTable->updateMyContent(); + myCanvasView->setMyContentsHeight( 0 ); + } +} + +/*! + Returns whether updating is enabled or not. + + \return true, if updating is enabled + \sa setUpdateEnabled() +*/ + +bool KDGanttView::getUpdateEnabled() const +{ + return !myTimeTable->blockUpdating(); +} + + + + +/*! + Sets the maximum width of the Gantt view part widget in pixels. + The largest allowed width is 32767. + \param w the maximum width +*/ + +void KDGanttView::setGanttMaximumWidth( int w ) +{ + myTimeHeader->setMaximumWidth ( w ); +} +/*! + Returns the maximum width of the Gantt view part widget in pixels. + The default maximum width is 32767 pixels. + + \return the maximum width of the Gantt view part widget in pixels. +*/ + +int KDGanttView::ganttMaximumWidth() const +{ + return myTimeHeader->maximumWidth(); +} + +/*! + Updates the content of the GanttView and shows it. + Automatically sets setUpdateEnabled( true ). + \sa setUpdateEnabled() +*/ + +void KDGanttView::show() +{ + myTimeTable->setBlockUpdating( false ); + if (myCanvasView->horizontalScrollBar()->value() > 0 ) + myCanvasView->horizontalScrollBar()->setValue(myCanvasView->horizontalScrollBar()->value()-1 ); + else + myCanvasView->horizontalScrollBar()->setValue(1 ); + myTimeTable->updateMyContent(); + QWidget::show(); + myCanvasView->setMyContentsHeight( 0 ); + if ( fCenterTimeLineAfterShow ) { + fCenterTimeLineAfterShow = false; + centerTimeline (dtCenterTimeLineAfterShow); + } +} +/*! + Closes the widget. + The closing is rejected, if a repainting is currently being done. + \param alsoDelete if true, the widget is deleted + \return true, if the widget was closed +*/ + +bool KDGanttView::close ( bool alsoDelete ) +{ + //qDebug("close "); + if ( closingBlocked ) + return false; + return QWidget::close ( alsoDelete ); +} + + +/*! + Returns a useful size for the view. + Returned width: + sizeHint().width() of the list view + width of TimeTable + Returned height: + height() of TimeHeader + height() of TimeTable + height() of Legend (if shown) +*/ + +QSize KDGanttView::sizeHint() const +{ + bool block = myTimeTable->blockUpdating(); + myTimeTable->setBlockUpdating( false ); + myTimeTable->updateMyContent(); + /* The below causes recursive calls to various size updating methods, which + * cause QCanvas to hide and show items like mad, which is very slow. If + * there is a legitimate gui updating issue here somewhere, it will need + * to be solved differently. + */ + //qApp->processEvents(); + int hintHeight = myTimeHeader->height(); + int legendHeight = 0; + if ( showLegendButton() ) + legendHeight = myLegend->height(); + int listViewHeaderHeight = 0; + if ( headerVisible() ) + listViewHeaderHeight = myListView->header()->height(); + if ( hintHeight < legendHeight+listViewHeaderHeight ) + hintHeight = legendHeight + listViewHeaderHeight; + hintHeight += myListView->horizontalScrollBar()->height(); + if ( myLegend->isShown() ) + hintHeight += myLegend->legendSizeHint().height() +10; + hintHeight += myTimeTable->minimumHeight+myListView->frameWidth()*2+2; + int hintWid = myListView->sizeHint().width(); + //hintWid += myTimeHeader->mySizeHint+myCanvasView->verticalScrollBar()->width(); + hintWid += myCanvasView->sizeHint().width(); + // add 10 for the splitter-bars + // qDebug("sizehint %d %d ",hintWid+10, hintHeight ); + myTimeTable->setBlockUpdating( block ); + return QSize( hintWid+10, hintHeight ); +} + + +/*! + Specifies whether the legend button should be visible. By default, + it is visible. + + \param show true to show the legend button, false to hide it + \sa showLegendButton() +*/ +void KDGanttView::setShowLegendButton( bool show ) +{ + _showLegendButton = show; + if ( show ) + myLegend->show(); + else + myLegend->hide(); + slotHeaderSizeChanged(); +} + + +/*! + Returns whether the legend button is visible. + + \return whether the legend button is visible + \sa setShowLegendButton() +*/ +bool KDGanttView::showLegendButton() const +{ + return _showLegendButton; +} + + +/*! + Specifies whether the listview header should be visible. By default, + it is not visible. + + \param visible true to make the header visible, false to make it invisible +*/ +void KDGanttView::setHeaderVisible( bool visible ) +{ + if( visible ) + myListView->header()->show(); + else + myListView->header()->hide(); + _showHeader = visible; + slotHeaderSizeChanged(); +} + + +/*! + Returns whether the listview header is visible. + + \return whether the header is visible +*/ +bool KDGanttView::headerVisible() const +{ + return _showHeader; +} + + +/*! + Returns the corresponding date and time of the coordinate X in the + Gantt view. + + \param coordX the coordinate to search for + \param global true if coordX is a global position, false otherwise + \return the date and time at coordinate X in the Gantt view. +*/ +QDateTime KDGanttView::getDateTimeForCoordX(int coordX, bool global ) const +{ + // default for myTimeHeader->getDateTimeForIndex() is local + return myTimeHeader->getDateTimeForIndex(coordX, !global ); +} + + +/*! + Implements a casted pass-through of the selectionChanged() signal. +*/ +void KDGanttView::slotSelectionChanged( QListViewItem* item ) +{ + KDGanttViewItem* gItem = static_cast( item ); + Q_ASSERT( gItem ); + emit lvSelectionChanged( gItem ); +} + + +/* + Implements a casted pass-through of the mouseButtonClicked() signal. + Signals itemLeftClicked() , itemMidClicked() are emitted as well. +*/ +void KDGanttView::slotmouseButtonClicked ( int button, QListViewItem * item, + const QPoint & pos, int c ) +{ + KDGanttViewItem* gItem = static_cast( item ); + emit lvMouseButtonClicked ( button , gItem, pos, c ); + if (gItem == 0 && myCurrentItem != 0 ) { + myCurrentItem = 0; + emit lvCurrentChanged( gItem ); + } + if (gItem != 0 && myCurrentItem == 0 ) { + myCurrentItem = gItem; + emit lvCurrentChanged( gItem ); + } + + // removed - makes no sense! + //emit mouseButtonClicked ( button , gItem, pos, c ); + { + switch ( button ) { + case LeftButton: + emit lvItemLeftClicked( gItem ); + emit itemLeftClicked( gItem ); + break; + case MidButton: + emit lvItemMidClicked( gItem ); + emit itemMidClicked( gItem ); + break; + } + } +} + + +/* + Implements a casted pass-through of the contextMenuRequested() signal. + The signal itemRightClicked() is emitted as well; + the position is the global position. +*/ +void KDGanttView::slotcontextMenuRequested ( QListViewItem * item, const QPoint & pos, int col ) +{ + KDGanttViewItem* gItem = static_cast( item ); + emit lvContextMenuRequested ( gItem, pos, col ); + emit lvItemRightClicked( gItem ); + emit itemRightClicked( gItem ); +} + + +void KDGanttView::emptySpaceDoubleClicked( QMouseEvent * e ) +{ + emit dateTimeDoubleClicked( getDateTimeForCoordX( e->x(), false ) ); +} + + +/* + Implements a casted pass-through of the currentChanged() signal. +*/ +void KDGanttView::slotCurrentChanged ( QListViewItem * item ) +{ + KDGanttViewItem* gItem = static_cast( item ); + myCurrentItem = gItem; + emit lvCurrentChanged( gItem ); +} + + +/* + Implements a casted pass-through of the itemRenamed() signal. +*/ +void KDGanttView::slotItemRenamed ( QListViewItem * item , int col, + const QString & text ) +{ + KDGanttViewItem* gItem = static_cast( item ); + emit lvItemRenamed( gItem, col, text ); +} + + +/* + Implements a casted pass-through of the mouseButtonPressed() signal. +*/ +void KDGanttView::slotMouseButtonPressed ( int button, QListViewItem * item, + const QPoint & pos, int c ) +{ + KDGanttViewItem* gItem = static_cast( item ); + emit lvMouseButtonPressed( button, gItem, pos, c ); +} + + +/*! + Specifies whether the content should be repainted after scrolling or + not. + + \param mode If No, there is no repainting after scrolling. This is + the fastest mode. + If Medium, there is extra repainting after releasing the + scrollbar. This provides fast scrolling with updated content + after scrolling. Recommended, when repaint problems occur. + This is the default value after startup. + If Always, there is an extra update after every move of the + scrollbar. This entails slow scrolling with updated + content at all time. +*/ +void KDGanttView::setRepaintMode( RepaintMode mode ) +{ + + QScrollBar *cvh, *cvv; + cvh = myCanvasView->horizontalScrollBar(); + cvv = myCanvasView->verticalScrollBar(); + // first disconnect + cvh->disconnect( this ); + cvv->disconnect( this ); + + switch ( mode ) { + case No: + + break; + case Medium: + connect( cvv, SIGNAL (sliderReleased () ) ,this, SLOT(forceRepaint())); + connect( cvh, SIGNAL (sliderReleased () ) ,this, SLOT(forceRepaint())); + connect( cvv, SIGNAL (nextLine () ) ,this, SLOT(forceRepaint())); + connect( cvh, SIGNAL (nextLine () ) ,this, SLOT(forceRepaint())); + connect( cvv, SIGNAL (prevLine () ) ,this, SLOT(forceRepaint())); + connect( cvh, SIGNAL (prevLine () ) ,this, SLOT(forceRepaint())); + break; + case Always: + connect( cvv, SIGNAL (valueChanged ( int ) ) ,this, SLOT(forceRepaint( int ))); + connect( cvh, SIGNAL (valueChanged ( int ) ) ,this, SLOT(forceRepaint( int ))); + connect( cvv, SIGNAL (sliderReleased () ) ,this, SLOT(forceRepaint())); + connect( cvh, SIGNAL (sliderReleased () ) ,this, SLOT(forceRepaint())); + break; + } +} + + +void KDGanttView::forceRepaint( int ) +{ + if ( myTimeTable->blockUpdating() ) + return; + // qDebug("forceRepaint( int ) "); + myTimeTable->setAllChanged(); + myTimeTable->update(); +} + + +void KDGanttView::slotHeaderSizeChanged() +{ + int legendHeight = 0; + if ( showLegendButton() ) + legendHeight = 24; + int listViewHeaderHeight = 0; + if ( headerVisible() ) + listViewHeaderHeight = myListView->header()->height(); + int timeHeaderHeight = myTimeHeader->height()+myTimeHeaderScroll->frameWidth()*2;; + int diffY = timeHeaderHeight-legendHeight-listViewHeaderHeight; + if ( diffY < 0 ) { + spacerLeft->setFixedHeight( 0 ); + spacerRight->setFixedHeight(-diffY); + } else { + spacerRight->setFixedHeight( 0 ); + spacerLeft->setFixedHeight( diffY ); + } + myLegend->setFixedHeight( legendHeight ); + myTimeHeaderContainer->setFixedHeight( timeHeaderHeight ); +} + + +/*! + Specifies whether the legend should be shown as a dock window or not. + + \param show if true, show legend as a dock window + \sa showLegend(), legendIsDockwindow(), legendDockwindow() +*/void KDGanttView::setLegendIsDockwindow( bool show ) +{ + bool isdock = myLegend->asDockwindow(); + if ( show != isdock ) { + myLegend->setAsDockwindow(show); + // legend is cleared - reinit legend with list + legendItem* li; + for ( li = myLegendItems->first(); li; li = myLegendItems->next() ) { + myLegend->addLegendItem(li->shape, li->color, li->text ); + } + } +} + + +/*! + Returns whether the legend is shown as a dock window + + \return true if the legend is shown as a dock window + \sa setShowLegend(), setLegendIsDockwindow(), legendDockwindow() +*/bool KDGanttView::legendIsDockwindow() const +{ + return myLegend->asDockwindow(); +} + + +/*! + Returns the pointer to the legend dock window. + DO NOT DELETE THIS POINTER! + If the legend is not a dock window, 0 is returned + To set the legend as a dock window, call + KDGanttView::setLegendIsDockwindow( true ); + + \return the pointer to the legend dock window + 0 is returned, if the legend is no dock window + DO NOT DELETE THIS POINTER! + \sa setShowLegend(), setLegendIsDockwindow(),legendIsDockwindow() +*/ +QDockWindow* KDGanttView::legendDockwindow() const +{ + return myLegend->dockwindow(); +} + + +/*! + Specifies whether the legend should be shown or not. Besides setting + this programmatically, the user can also show/hide the legend by + using the button provided for this purpose. + + \param show force legend to be shown + \sa showLegend() +*/ +void KDGanttView::setShowLegend( bool show ) +{ + myLegend->showMe(show); +} + + +/*! + Returns whether the legend is currently shown. The visibility of the + legend can be changed both by \a setShowLegend(), and interactively + by the user. + + \return true if the legend is currently visible + \sa setShowLegend() +*/ +bool KDGanttView::showLegend() const +{ + return myLegend->isShown(); +} + + +/*! + Specifies whether the listview of the Gantt view should be shown or + not. + + \param show pass true in order to show the listview and false in + order to hide it. + \sa showListView() +*/ +void KDGanttView::setShowListView( bool show ) +{ + if(listViewIsVisible == show) return; + listViewIsVisible = show; + if (listViewIsVisible) + myListView->parentWidget()->show(); + else + myListView->parentWidget()->hide(); +} + + +/*! + Returns whether the listview of the Gantt view is shown or not. + + \return true if the listview is shown + \sa setShowListView() +*/ +bool KDGanttView::showListView() const +{ + return listViewIsVisible; +} + + +/*! + Specifies whether it should be possible to edit the appearance of a + Gantt item visually in a dialog by double-clicking the item. + + \param enable pass true in order to enable the visual editor and + false in order to turn it off + \sa editorEnabled() +*/ + +void KDGanttView::setEditorEnabled( bool enable ) +{ + editorIsEnabled = enable; +} + + +/*! + Returns whether it is possible to edit the appearance of a Gantt + item visually in a dialog by double-clicking the item. + + \return true if visual editing is enabled, false otherwise + \sa setEditorEnabled() +*/ + +bool KDGanttView::editorEnabled() const +{ + return editorIsEnabled; +} + + +/*! + Specifies whether the Gantt chart is user-editable. + + \param editable pass true in order to get a user-editable Gantt + chart, pass false in order to get a read-only chart + \sa editable() +*/ + +void KDGanttView::setEditable( bool editable ) +{ + chartIsEditable = editable; +} + + +/*! + Returns whether the Gantt chart is user-editable + + \return true if the Gantt chart is user-editable + \sa setEditable() +*/ + +bool KDGanttView::editable() const +{ + return chartIsEditable; +} + + +/*! + Saves the state of the Gantt view in an IO device in XML format. The saved + data can be reloaded with \a loadProject(). + + \param device a pointer to the IO device in which to store the Gantt + view state. + \return true if the data could be written, false if an error + occurred + \sa loadProject() +*/ + +bool KDGanttView::saveProject( QIODevice* device ) +{ + Q_ASSERT( device ); + + QDomDocument doc = saveXML(); + if( device->isOpen() ) + device->close(); + if( device->open( IO_WriteOnly ) ) { + QTextStream ts( device ); + ts << doc.toString(); + return true; + } else + return false; +} + + +/*! + Loads a previously saved state of the Gantt view. All current + settings and items are discarded before loading the data. + + \param device a pointer to the IO device from which to load the + Gantt view state. + \return true if the file could be read, false if an error + occurred + \sa saveProject() +*/ + +bool KDGanttView::loadProject( QIODevice* device ) +{ + Q_ASSERT( device ); + + if( device->isOpen() ) + device->close(); + if( device->open( IO_ReadOnly ) ) { + QDomDocument doc( "GanttView" ); + QString err; + int errline, errcol; + if ( !doc.setContent( device, &err, &errline, &errcol ) ) { + qDebug("KDGantt::Error parsing XML data at line %d. Message is:", errline ); + qDebug("%s ", err.latin1()); + device->close(); + return false; + } + device->close(); + return loadXML( doc ); + } else + return false; +} + + +/*! + Sends a Gantt view to a printer. The printer should already be set + up for printing (by calling QPrinter::setup()). + If the printer is not set up, QPrinter::setup() is called before printing + + You can specify, whether the ListView, TimeLine, or Legend will be + printed. All combinations of these three widgets are allowed. + + \param printer a pointer to the printer to print on. If printer is + 0, the method creates a temporary printer and discards it when it is + done printing. + \param printListView if true, the list view is printed + \param printTimeLine if true, the time line is printed + \param printLegend if true, the legend is printed + + \sa drawContents() +*/ + +void KDGanttView::print( QPrinter* printer , + bool printListView, bool printTimeLine, + bool printLegend ) +{ + bool deletePrinter = false; + if (! printer ) { + printer = new QPrinter(); + deletePrinter = true; + if ( !printer->setup()) { + delete printer; + return; + } + } + // now we have a printer to print on + QPainter p( printer ); + // get the paper metrics + QPaintDeviceMetrics m = QPaintDeviceMetrics ( printer ); + float dx, dy; + // get the size of the desired output for scaling. + // here we want to print all: ListView, TimeLine, and Legend + // for this purpose, we call drawContents() with a 0 pointer as painter + QSize size = drawContents( 0, printListView, printTimeLine, printLegend ); + + // at the top, we want to print current time/date + QString date = "Printing Time: " + QDateTime::currentDateTime().toString(); + int hei = p.boundingRect(0,0, 5, 5, Qt::AlignLeft, date ).height(); + p.drawText( 0, 0, date ); + + // compute the scale + dx = (float) m.width() / (float)size.width(); + dy = (float)(m.height() - ( 2 * hei )) / (float)size.height(); + float scale; + // scale to fit the width or height of the paper + if ( dx < dy ) + scale = dx; + else + scale = dy; + // set the scale + p.scale( scale, scale ); + // now printing with y offset: 2 hei + p.translate( 0, 2*hei ); + drawContents( &p, printListView, printTimeLine, printLegend ); + // the drawContents() has the side effect, that the painter translation is + // after drawContents() set to the bottom of the painted stuff + // for instance a + // p.drawText(0, 0, "printend"); + // would be painted directly below the paintout of drawContents() + p.end(); + if ( deletePrinter ) + delete printer; +} + + +/*! + Paints a Gantt view on a QPainter. + You can specify, whether the list view, the time line, or the legend + is painted. + All combinations of these three widgets are allowed. + Returns the size of the painted area. + Paints the list view in the top-left corner, the time line to the + right of the list view, and the legend below the list view. + If called with \a p = 0, nothing is painted and only + the size of the painted area is computed. + This is useful for determining only the painted area and setting + the scale of the painter, before calling this method with a painter. + In order to get the output fitted to your paper and your printer, + call first + QSize size = drawContents( 0, printListView, printTimeLine, printLegend ); + //then compute the scale + dx = paper.width() / size.width(); + dy = paper.height() / size.height(); + //then make float scale to fit the width or height of the paper + if ( dx < dy ) + scale = dx; + else + scale = dy; + // then set the scale + p.scale( scale, scale ); + // and now call drawContents with painter p + drawContents( &p, printListView, printTimeLine, printLegend ); + + For a detailed example, please see the commented source code in + KDGanttView::print(...) + + \param p a pointer to the painter to paint on. If p is + 0, nothing is painted and only the size of the painted area is computed + \param drawListView if true, the list view is painted + \param drawTimeLine if true, the time line is painted + \param drawLegend if true, the legend is painted + \return the size of the painted area + \sa print() +*/ +QSize KDGanttView::drawContents( QPainter* p, + bool drawListView , bool drawTimeLine, bool drawLegend ) +{ + QSize size; + int lvX, lvY, thX, thY, tlX, tlY, lwX, lwY, allX, allY; + lvX = myListView->contentsWidth(); + lvY = myCanvasView->canvas()->height() + 20; + thX = myTimeHeader->width(); + thY = myTimeHeader->height(); + tlX = myCanvasView->canvas()->width(); + tlY = lvY; + lwX = myLegend->legendSize().width(); + lwY = myLegend->legendSize().height(); + allX = 0; + allY = 0; + if ( drawListView ) { + allX += lvX; + allY += tlY; + } + if ( drawTimeLine ) { + allX += thX; + allY += thY; + } + if ( drawLegend ) { + allY += lwY; + if ( allX < lwX ) + allX = lwX ; + } + size = QSize( allX, allY ); + int temp = 0; + if ( p ) { + if ( drawListView ) { + if ( drawTimeLine ) + temp = thY; + p->translate( 0, temp ); + //HACK: Only draw list headers if we draw timeline, else + // there is no room for it. This will most probably be changed + // with qt4 anyway, so I think we can live with it atm. + myListView->drawToPainter( p, drawTimeLine ); + p->translate( lvX, -temp); + } + if ( drawTimeLine ) { + p->translate( myCanvasView->frameWidth(), 0); + myTimeHeader->repaintMe( 0, myTimeHeader->width(), p ); + p->translate( -myCanvasView->frameWidth(), thY); + myCanvasView->drawToPainter( p ); + if ( drawListView ) + p->translate( -lvX, tlY); + else + p->translate( 0, tlY); + } else { + if ( drawListView ) + p->translate( -lvX, 0 ); + } + if ( drawLegend ) { + myLegend->drawToPainter( p ); + p->translate( 0, lwY ); + } + } + return size; +} + +/*! + Zooms into the Gantt chart. Values less than 1 mean zooming in, + values greater than 1 mean zooming out. A zooming factor of exactly + 1.0 means original size. + + \param factor the zoom factor + \param absolute if true, factor is interpreted absolutely, if false, + factor is interpreted relatively to the current zoom factor + \sa zoomToFit() + \sa zoomToSelection() + \sa zoomFactor() +*/ + +void KDGanttView::setZoomFactor( double factor, bool absolute ) +{ + myTimeHeader->zoom(factor,absolute); +} + + +/*! + Returns the current zoom factor. + + \return the current zoom factor + \sa zoomToFit(), zoomToSelection(), setZoomFactor() +*/ + +double KDGanttView::zoomFactor() const +{ + return myTimeHeader->zoomFactor(); +} + + +/*! + Zooms such that the Gantt chart is less than the available space of the widget. + + \sa setZoomFactor() + \sa zoomFactor() + \sa zoomToSelection() +*/ + +void KDGanttView::zoomToFit() +{ + myTimeHeader->zoomToFit(); +} + + +/*! + Zooms so that at least the selected time period is visible after the zoom. + + \param start the new font of the widget + \param end the new font of the widget + + \sa setZoomFactor() + \sa zoomFactor() + \sa zoomToFit() +*/ + +void KDGanttView::zoomToSelection( const QDateTime& start, const QDateTime& end ) +{ + + myTimeHeader->zoomToSelection( start, end); + +} + + +/*! + Makes sure that the specified Gantt item is visible without + scrolling. + + \sa center(), centerTimelineAfterShow() +*/ +void KDGanttView::ensureVisible( KDGanttViewItem* item ) +{ + myListView->ensureItemVisible (item); +} + + +/*! + Makes sure that the specified QDateTime is in the center of the + visible Gantt chart (if possible). + If you want to center the timeline when the KDGanttView is hidden, + calling centerTimelineAfterShow() is the better alternative. + + \sa center(), centerTimelineAfterShow() +*/ +void KDGanttView::centerTimeline( const QDateTime& center ) +{ + myTimeHeader->centerDateTime( center ); +} + + +/*! + Makes sure that the specified QDateTime is in the center of the + visible Gantt chart (if possible). If the KDGanttView is currently + hidden, this method resets the center once again after the next + show() call. Use this method if you want to center the timeline when + the KDGanttView is hidden. After calling KDGanttView::show(), there + may be computations of the sizes of the widgets and subwidgets and + of the automatically computed start datetime. This method ensures + that the center of the timeline is to be properly reset after + show(). + + \sa center(), centerTimeline() +*/ +void KDGanttView::centerTimelineAfterShow( const QDateTime& center ) +{ + myTimeHeader->centerDateTime( center ); + if ( ! isVisible() ) { + dtCenterTimeLineAfterShow = center; + fCenterTimeLineAfterShow = true; + } +} + +/*! + Sets the timeline to the horizon start. +*/ + +void KDGanttView::setTimelineToStart() +{ + myCanvasView->horizontalScrollBar()->setValue( 0 ); +} + + +/*! + Sets the timeline to the horizon end. +*/ +void KDGanttView::setTimelineToEnd() +{ + myCanvasView->horizontalScrollBar()->setValue(myCanvasView->horizontalScrollBar()->maxValue()); +} + + +/*! + Add \a num minor ticks of the current scale of the timeline + to the start of the timeline. + The timeline is not set automatically at the start. + Call \a setTimelineToStart() to ensure that the timeline is at the start + after calling this method. + + \param num the number of minor ticks which should be added + \sa addTicksRight(),setTimelineToStart(), setTimelineToEnd() +*/ +void KDGanttView::addTicksLeft( int num ) +{ + myTimeHeader->addTickLeft( num ); +} + + +/*! + Add \a num minor ticks of the current scale of the timeline + to the end of the timeline. + The timeline is not set automatically at the end. + Call \a setTimelineToEnd() to ensure that the timeline is at the end + after calling this method. + \param num the number of minor ticks which should be added + \sa addTicksLeft(),setTimelineToStart(), setTimelineToEnd() +*/ +void KDGanttView::addTicksRight( int num ) +{ + myTimeHeader->addTickRight( num ); +} + + +/*! + Makes sure that the specified Gantt item is in the center of the + visible Gantt chart (if possible). +*/ +void KDGanttView::center( KDGanttViewItem* item ) +{ + ensureVisible(item); + int x = myListView->contentsWidth()/2; + int y = myListView->itemPos (item ); + myListView->center(x,y); +} + + +/*! + Specifies whether task links should be shown. + + \param show true for showing task links, false for not showing them + \sa showTaskLinks(), KDGanttViewTaskLink +*/ +void KDGanttView::setShowTaskLinks( bool show ) +{ + myTimeTable->setShowTaskLinks(show); + +} + + +/*! + Returns whether task links should be shown. + + \return true if task links are shown, false otherwise + \sa setShowTaskLinks(), KDGanttViewTaskLink +*/ +bool KDGanttView::showTaskLinks() const +{ + return myTimeTable->showTaskLinks(); +} + + +/*! + Sets the font in the left list view widget and + in the right time header widget. + The settings of the fonts in the time table widget are not effected. + + \param font the new font of the widget +*/ +void KDGanttView::setFont(const QFont& font) +{ + myListView->setFont(font); + myListView->repaint(); + myTimeHeader->setFont(font); + myLegend->setFont( font ); + QWidget::setFont( font ); + setScale(scale()); +} + + +/*! + Specifies whether the configure popup menu should be shown on + right click on the time header widget. + This menu lets the user quickly change + the zoom factor, + the scale mode (minute, hour, day, week, month, auto) , + the time format, + the year format, + the grid format, + and printing. + The default setting is not to show the popup menu. + This functionality must be enabled explicitly by the application + developer. + You can disable each submenu of the popmenu. + + \param show true in order to show the popup menu, false in order not + to. The default is true. + \param showZoom show the zoom submenu, default: true + \param showScale show the scale submenu, default: true + \param showTime show the time format submenu, default: true + \param showYear show the year format submenu, default: true + \param showGrid show the grid submenu, default: true + \param showPrint show the print submenu, default: false +*/ +void KDGanttView::setShowHeaderPopupMenu( bool show, + bool showZoom, + bool showScale, + bool showTime, + bool showYear, + bool showGrid, + bool showPrint) +{ + myTimeHeader->setShowPopupMenu( show,showZoom,showScale,showTime, + showYear,showGrid,showPrint ); +} + + +/*! + Returns whether the configure popup menu should be shown on right + click on the time header widget. + + \return true if the popup menu should be shown +*/ +bool KDGanttView::showHeaderPopupMenu() const +{ + return myTimeHeader->showPopupMenu(); +} +//**************************************************** + + +/*! + Specifies whether the add item popup menu should be shown on + right click on the time table widget. + This menu lets the user quickly add new items to the Gantt view + (as root, as child or after an item). + It also offers cutting and pasting of items. + + The default setting is that the popup menu is not shown. + It must be enabled by the program. + + \param show true in order to show popup menu, false in order not to + +*/ +void KDGanttView::setShowTimeTablePopupMenu( bool show ) +{ + myCanvasView->setShowPopupMenu( show ); +} + + +/*! + Returns whether the add item popup menu should be shown on right + click on the time table widget. + + \return true if the popup menu should be shown +*/ +bool KDGanttView::showTimeTablePopupMenu() const +{ + return myCanvasView->showPopupMenu(); +} + + +/*! + Sets the shapes for a certain type of Gantt item. Not all items use + all three shapes (e.g., only summary items use the middle shape). + + This setting overrides any shape settings made on individual items. + These settings will be taken as initial values of any newly created + item of this certain type. + See also the documentation of the KDGanttViewItem class. + + \param type the type of Gantt items for which to set the shapes + \param start the shape to use for the beginning of the item + \param middle the shape to use for the middle of the item + \param end the shape to use for the end of the item + \param overwriteExisting if true, overwrites existing shape settings + in the individual items + \sa shapes() +*/ +void KDGanttView::setShapes( KDGanttViewItem::Type type, + KDGanttViewItem::Shape start, + KDGanttViewItem::Shape middle, + KDGanttViewItem::Shape end, + bool overwriteExisting ) +{ + if ( overwriteExisting ) { + QListViewItemIterator it(myListView); + for ( ; it.current(); ++it ) { + if ( ((KDGanttViewItem*)it.current())->type() == type) + ((KDGanttViewItem*)it.current())->setShapes(start,middle, end ); + } + } + int index = getIndex( type ); + myDefaultShape [index*3] = start; + myDefaultShape [index*3+1] = middle; + myDefaultShape [index*3+2] = end; + undefinedShape[index] = false; +} + + +/*! + Queries the shapes for a particular type of Gantt item. + + \param type the type of Gantt items for which to query the shapes + \param start the start shape is returned in this parameter + \param middle the middle shape is returned in this parameter + \param end the end shape is returned in this parameter + \return true if there was a general shape set for the specified + type. If the return value is false, the values of the three shape + parameters are undefined. + \sa setShapes() +*/ +bool KDGanttView::shapes( KDGanttViewItem::Type type, + KDGanttViewItem::Shape& start, + KDGanttViewItem::Shape& middle, + KDGanttViewItem::Shape& end ) const +{ + int index = getIndex( type ); + start = myDefaultShape [index*3]; + middle = myDefaultShape [index*3+1]; + end = myDefaultShape [index*3+2]; + return !undefinedShape[index]; +} + + +/*! + Sets the colors for a certain type of Gantt item. Not all items use + all three colors (e.g., only summary items use the middle color). + + This setting overrides any color settings made on individual items. + These settings will be taken as initial values of any newly created + item of this certain type. + See also the description of the KDGanttViewItem class. + + \param type the type of Gantt items for which to set the colors + \param start the color to use for the beginning of the item + \param middle the color to use for the middle of the item + \param end the color to use for the end of the item + \param overwriteExisting if true, overwrites existing color settings + on invididual items + \sa colors(), setDefaultColors(), defaultColors() +*/ +void KDGanttView::setColors( KDGanttViewItem::Type type, + const QColor& start, const QColor& middle, + const QColor& end, + bool overwriteExisting ) +{ + if ( overwriteExisting ) { + QListViewItemIterator it(myListView); + for ( ; it.current(); ++it ) { + if ( ((KDGanttViewItem*)it.current())->type() == type) + ((KDGanttViewItem*)it.current())->setColors(start,middle, end ); + } + } + int index = getIndex( type ); + myColor [index*3] = start; + myColor [index*3+1] = middle; + myColor [index*3+2] = end; + undefinedColor[index] = false; +} + + +/*! + Queries the colors for a particular type of Gantt item. + + \param type the type of Gantt items for which to query the colors + \param start the start color is returned in this parameter + \param middle the middle color is returned in this parameter + \param end the end color is returned in this parameter + \return true if there was a general color set for the specified + type. If the return value is false, the values of the three color + parameters are undefined. + \sa setColors(), setDefaultColor(), defaultColor() +*/ +bool KDGanttView::colors( KDGanttViewItem::Type type, + QColor& start, QColor& middle, QColor& end ) const +{ + int index = getIndex( type ); + start = myColor [index*3]; + middle = myColor [index*3+1]; + end = myColor [index*3+2]; + return !undefinedColor[index]; +} + + +/*! + Sets the highlight colors for a certain type of Gantt item. Not + all items use all three highlight colors (e.g., only summary items + use the middle highlight color). + + This setting overrides any highlight color settings made on + individual items. + These settings will be taken as initial values of any newly created + item of this certain type. + See also the description of the KDGanttViewItem class. + + \param type the type of Gantt items for which to set the highlight colors + \param start the highlight color to use for the beginning of the item + \param middle the highlight color to use for the middle of the item + \param end the highlight color to use for the end of the item + \param overwriteExisting if true, overwrites existing color settings + in the individual items + \sa highlightColors(), setDefaultHighlightColor(), defaultHighlightColor() +*/ +void KDGanttView::setHighlightColors( KDGanttViewItem::Type type, + const QColor& start, + const QColor& middle, + const QColor& end, + bool overwriteExisting ) +{ + if ( overwriteExisting ) { + QListViewItemIterator it(myListView); + for ( ; it.current(); ++it ) { + if ( ((KDGanttViewItem*)it.current())->type() == type) + ((KDGanttViewItem*)it.current())->setHighlightColors(start,middle, end ); + } + } + int index = getIndex( type ); + myColorHL [index*3] = start; + myColorHL [index*3+1] = middle; + myColorHL [index*3+2] = end; + undefinedColorHL[index] = false; + +} + + +/*! + Queries the highlight colors for a particular type of Gantt item. + + \param type the type of Gantt items for which to query the highlight + colors + \param start the start highlight color is returned in this parameter + \param middle the middle highlight color is returned in this parameter + \param end the end highlight color is returned in this parameter + \return true if there was a general highlight color set for the specified + type. If the return value is false, the values of the three highlight color + parameters are undefined. + \sa setHighlightColors(), setDefaultHighlightColor(), + defaultHighlightColor() +*/ +bool KDGanttView::highlightColors( KDGanttViewItem::Type type, + QColor& start, QColor& middle, + QColor& end ) const +{ + int index = getIndex( type ); + start = myColorHL [index*3]; + middle = myColorHL [index*3+1]; + end = myColorHL [index*3+2]; + return !undefinedColorHL[index]; +} + + +/*! + Sets the color used for texts in the Gantt chart. + Overrides all individual settings of the Gantt items. + + \param color the text color to use + \sa textColor() +*/ +void KDGanttView::setTextColor( const QColor& color ) +{ + QListViewItemIterator it(myListView); + for ( ; it.current(); ++it ) { + ((KDGanttViewItem*)it.current())->setTextColor(color); + } + myTextColor = color; +} + + +/*! + Returns the color used for texts in the Gantt chart. + + \return the color used for texts in the Gantt chart. + \sa setTextColor() +*/ +QColor KDGanttView::textColor() const +{ + return myTextColor; +} + + +/*! + Specifies the brush in which the 'showNoInformation' line of items + should be drawn. + + \param brush the brush of the 'showNoInformation' lines + \sa KDGanttViewItem::showNoInformation(), + KDGanttViewItem::setShowNoInformation(), + KDGanttView::noInformationBrush() + +*/ +void KDGanttView::setNoInformationBrush( const QBrush& brush ) +{ + myTimeTable->setNoInformationBrush( brush ); +} + + +/*! + Returns the brush of the 'showNoInformation' lines + \return the brush of the 'showNoInformation' lines + \sa KDGanttViewItem::showNoInformation(), KDGanttViewItem::setShowNoInformation(), + setNoInformationBrush() +*/ +QBrush KDGanttView::noInformationBrush() const +{ + return myTimeTable->noInformationBrush(); +} + + +/*! + Removes all items from the legend. + + \sa addLegendItem() +*/ +void KDGanttView::clearLegend( ) +{ + myLegend->clearLegend(); + myLegendItems->setAutoDelete( true ); + delete myLegendItems; + myLegendItems = new QPtrList; +} + + +/*! + Adds an item to the legend. + + \param shape the shape to display + \param shapeColor the color in which to display the shape + \param text the text to display + \sa clearLegend() +*/ +void KDGanttView::addLegendItem( KDGanttViewItem::Shape shape, + const QColor& shapeColor, + const QString& text ) +{ + myLegend->addLegendItem( shape,shapeColor,text ); + legendItem* item = new legendItem; + item->shape = shape; + item->color = shapeColor; + item->text = text; + myLegendItems->append( item ); +} + + +/*! + Sets the start of the horizon of the Gantt chart. If \a start is + null, the horizon start is computed automatically. + + \param start the start of the horizon + \sa horizonStart() +*/ +void KDGanttView::setHorizonStart( const QDateTime& start ) +{ + myTimeHeader->setHorizonStart(start); +} + + +/*! + Returns the start of the horizon of the Gantt chart. + + \return the start of the horizon of the Gantt chart + \sa setHorizonStart() +*/ +QDateTime KDGanttView::horizonStart() const +{ + return myTimeHeader->horizonStart(); +} + + +/*! + Sets the end of the horizon of the Gantt chart. If \a end is + null, the horizon end is computed automatically. + + \param end the end of the horizon + \sa setHorizonEnd() +*/ +void KDGanttView::setHorizonEnd( const QDateTime& end ) +{ + myTimeHeader->setHorizonEnd(end); +} + + +/*! + Returns the end of the horizon of the Gantt chart. + + \return the end of the horizon of the Gantt chart + \sa setHorizonEnd() + +*/ +QDateTime KDGanttView::horizonEnd() const +{ + return myTimeHeader->horizonEnd(); +} + + +/*! + Configures the unit of the lower scale of the header. The higher + unit is computed automatically. + + \param unit the unit of the lower scale of the header. + \sa scale() +*/ +void KDGanttView::setScale( Scale unit ) +{ + myTimeHeader->setScale( unit ); +} + + +/*! + Returns the unit of the lower scale of the header. + + \return the unit of the lower scale of the header. + \sa setScale() +*/ +KDGanttView::Scale KDGanttView::scale() const +{ + return myTimeHeader->scale(); +} + + +/*! + Sets the maximum allowed time scale of the lower scale of the header. + + \param unit the unit of the lower scale of the header. + \sa scale() +*/ +void KDGanttView::setMaximumScale( Scale unit ) +{ + myTimeHeader->setMaximumScale( unit ); +} + + +/*! + Returns the maximum allowed time scale of the lower scale of the header. + + \return the unit of the lower scale of the header. + \sa setScale() +*/ +KDGanttView::Scale KDGanttView::maximumScale() const +{ + return myTimeHeader->maximumScale(); +} + + +/*! + Sets the minimum allowed time scale of the lower scale of the header. + + \param unit the unit of the lower scale of the header. + \sa scale() +*/ +void KDGanttView::setMinimumScale( Scale unit ) +{ + myTimeHeader->setMinimumScale( unit ); +} + + +/*! + Returns the minimum allowed time scale of the lower scale of the header. + + \return the unit of the lower scale of the header. + \sa setScale() +*/ +KDGanttView::Scale KDGanttView::minimumScale() const +{ + return myTimeHeader->minimumScale(); +} + + +/*! + Sets the absolute number of minor ticks, if scaling is set to Auto. + If the scale mode is set to Auto, then the actual scale and + the minorScaleCount is automatically computed, such that there are + count minor ticks + + \param count the number of minor ticks + \sa autoScaleMinorTickCount(),setScale(),scale() +*/ +void KDGanttView::setAutoScaleMinorTickCount( int count ) +{ + myTimeHeader->setAutoScaleMinorTickCount( count ); +} + + +/*! + Returns the absolut number of minor ticks, if scaling is set to Auto + + \return the absolut number of minor ticks + \sa setAutoScaleMinorTickCount(),setScale(),scale() +*/ +int KDGanttView::autoScaleMinorTickCount() const +{ + return myTimeHeader->autoScaleMinorTickCount(); +} + + +/*! + Sets the minimum width that a column needs to have. If the size of the + Gantt chart and the scale would make it necessary to go below this + limit otherwise, the chart will automatically be made less exact. + + \param width the minimum column width + \sa minimumColumnWidth() +*/ +void KDGanttView::setMinimumColumnWidth( int width ) +{ + myTimeHeader->setMinimumColumnWidth( width ); +} + + +/*! + Returns the minimum width a column needs to have. + + \return the column minimum width + \sa setMinimumColumnWidth() +*/ +int KDGanttView::minimumColumnWidth() const +{ + return myTimeHeader->minimumColumnWidth(); +} + + +/*! + Specifies the format in which to display years. If no years are + shown, this method has no effect. + + \param format the year format + \sa yearFormat(), setHourFormat(), hourFormat() +*/ +void KDGanttView::setYearFormat( YearFormat format ) +{ + myTimeHeader->setYearFormat(format ); +} + + +/*! + Returns the format in which to display years. + + \return the year format + \sa setYearFormat(), setHourFormat(), hourFormat() +*/ +KDGanttView::YearFormat KDGanttView::yearFormat() const +{ + return myTimeHeader->yearFormat(); +} + + +/*! + Specifies the format in which to display hours. If no hours are + shown, this method has no effect. + + \param format the hour format + \sa hourFormat(), setYearFormat(), yearFormat() + +*/ +void KDGanttView::setHourFormat( HourFormat format ) +{ + myTimeHeader->setHourFormat( format ); +} + + +/*! + Returns the format in which to display hours. + + \return the hour format + \sa setHourFormat(), setYearFormat(), yearFormat() + +*/ +KDGanttView::HourFormat KDGanttView::hourFormat() const +{ + return myTimeHeader->hourFormat(); +} + + +/*! + Hides/shows the grid for the major ticks of the time header in the gantt view. + + \param show true in order to show ticks, false in order to hide them. + If show is true, setShowMinorTicks( false ) is performed automatically + to hide the grid of the minor ticks. + In order to show now grid, call setShowMinorTicks( false ) and + setShowMajorTicks( false ). + \sa showMajorTicks(), setShowMinorTicks(), showMinorTicks() +*/ +void KDGanttView::setShowMajorTicks( bool show ) +{ + myTimeHeader->setShowMajorTicks(show ); +} + + +/*! + Returns whether the grid is shown on the major scale. + + \return true if ticks are shown on the major scale + \sa setShowMajorTicks(), setShowMinorTicks(), showMinorTicks() +*/ +bool KDGanttView::showMajorTicks() const +{ + return myTimeHeader->showMajorTicks(); +} + + +/*! + Hides/shows the grid for the minor ticks of the time header in the gantt view. + + \param show true in order to show ticks, false in order to hide them. + If show is true, setShowMajorTicks( false ) is performed automatically + to hide the grid of the major ticks. + In order to show now grid, call setShowMinorTicks( false ) and + setShowMajorTicks( false ). + + \sa showMinorTicks(), setShowMajorTicks(), showMajorTicks() + +*/ +void KDGanttView::setShowMinorTicks( bool show) +{ + myTimeHeader->setShowMinorTicks( show ); +} + + +/*! + Returns whether ticks are shown on the minor scale. + + \return true if ticks are shown on the minor scale + \sa setShowMinorTicks(), setShowMajorTicks(), showMajorTicks() +*/ +bool KDGanttView::showMinorTicks() const +{ + return myTimeHeader->showMinorTicks(); +} + + +/*! + Sets the background color for the column closest to \a column. + It can be specified whether the color should be shown in all scales or + only in specific scales. + If you want to define the color only for the daily view, specify + mini and maxi as Day. + If there is no value specified for mini and maxi, the color for the column + is shown on all scales. Note that it is possible that there are two + values for a column in a scale. In this case, the shown color is unspecified. + + \param column the column to set the background color for + \param color the background color + \param mini show the colour only in scales greater than this + \param maxi show the colour only in scales lesser than this + \sa columnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor() +*/ +void KDGanttView::setColumnBackgroundColor( const QDateTime& column, + const QColor& color , + Scale mini, Scale maxi ) +{ + myTimeHeader->setColumnBackgroundColor( column, color,mini,maxi ); +} + +#if 0 +/*! + Sets the background color for a time interval given by \a start and + \a end. \a start may be later than \a end. If there is already a + background interval with the same \a start and \a end values + defined, the values (i.e. const QColor& color , Scale mini, Scale + maxi) of this background interval are changed. Change the times of + an already defined interval with \a changeBackgroundInterval(). + Delete an already defined interval with \a + deleteBackgroundInterval(). + + It can be defined, whether the color should be shown in all scales or + only in specific scales. + If you want to define the color only for the daily view, scecify + mini and maxi as Day. + If there is no value for mini/maxi specified, the color for the columns + is shown in all scales. + + \param start start datetime of the time interval + \param end end datetime of the time interval + \param color the background color + \param mini show the color only in scales greater than this + \param maxi show the color only in scales lesser than this + \sa changeBackgroundInterval(), deleteBackgroundInterval(), + columnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor() +*/ +void KDGanttView::setIntervalBackgroundColor( const QDateTime& start, + const QDateTime& end, + const QColor& color , + Scale mini, Scale maxi ) +{ + myTimeHeader->setIntervalBackgroundColor( start, end, color,mini,maxi ); +} + + +/*! + Changes the times of an already defined background color interval. + The new values \a startnew and \a endnew should not be datetime + values of an already defined background color interval. + If that is the case, nothing is changed and false is returned. + + \param oldstart the start date and time of the interval to change + \param oldend the end date and time of the interval to change + \param newstart the new start date and time + \param newend the new end date and time + \return true, if there is a backgroundcolor interval with values + \a start and \a end found and the new values \a startnew and \a endnew + are not datetime values of an already defined background color interval. + Returns false otherwise. + \sa changeBackgroundInterval(), deleteBackgroundInterval(), + columnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor() +*/ +bool KDGanttView::changeBackgroundInterval( const QDateTime& oldstart, + const QDateTime& oldend, + const QDateTime& newstart, + const QDateTime& newend ) +{ + return myTimeHeader->changeBackgroundInterval( oldstart, oldend, + newstart, newend ); +} + +/*! + Deletes an already defined background color interval. + + \param start start datetime of time interval + \param end end datetime of time interval + \return true, if there is a backgroundcolor interval with values + \a start and \a end found (and hence deleted). + \sa changeBackgroundInterval(), columnBackgroundColor() +*/ +bool KDGanttView::deleteBackgroundInterval( const QDateTime& start, + const QDateTime& end) +{ + return myTimeHeader->deleteBackgroundInterval( start, end ); +} +#endif + +/*! + Adds a filled rectangle for a time interval given by \a start and + \a end, across all tasks. \a start may be later than \a end. + \sa KDIntervalColorRectangle +*/ +void KDGanttView::addIntervalBackgroundColor( KDIntervalColorRectangle* newItem ) +{ + myTimeHeader->addIntervalBackgroundColor( newItem ); +} + +/*! + Removes all background color settings set with setColumnBackgroundColor() + and setIntervalBackgroundColor(). + Does not affect the settings of setWeekendBackgroundColor(). + + \sa setColumnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor(), setIntervalBackgroundColor() +*/ +void KDGanttView::clearBackgroundColor() +{ + myTimeHeader->clearBackgroundColor(); +} + + +/*! + Returns the background color for the column closest to \a column. + + \param column the column to query the background color for + \return the background color of the specified color + \sa setColumnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor() +*/ +QColor KDGanttView::columnBackgroundColor( const QDateTime& column ) const +{ + return myTimeHeader->columnBackgroundColor( column ) ; +} + + +/*! + Specifies the background color for weekend days. If no individual + days are visible on the Gantt chart, this method has no visible + effect. + + \param color the background color to use for weekend days. + \sa weekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +void KDGanttView::setWeekendBackgroundColor( const QColor& color ) +{ + myTimeHeader->setWeekendBackgroundColor( color ); +} + + +/*! + Returns the background color for weekend days. + + \return the background color for weekend days + \sa setWeekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +QColor KDGanttView::weekendBackgroundColor() const +{ + return myTimeHeader->weekendBackgroundColor(); +} + + +/*! + Specifies the background color for weekday days. If no individual + days are visible on the Gantt chart, this method has no visible + effect. The days are specified as an intervals of integer values + where 1 means Monday and 7 means Sunday. + + \param color the background color to use for weekend days. + \param weekday the day of the week (Monday = 1, Sunday = 7) + \sa weekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +void KDGanttView::setWeekdayBackgroundColor( const QColor& color, int weekday ) +{ + myTimeHeader->setWeekdayBackgroundColor( color, weekday ); +} + + +/*! + Returns the background color for weekday days. + + \param weekday the day of the week (Monday = 1, Sunday = 7) + \return the background color for weekend days + \sa setWeekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +QColor KDGanttView::weekdayBackgroundColor(int weekday) const +{ + return myTimeHeader->weekdayBackgroundColor( weekday); +} + + + +/*! + Defines which days are considered weekends. The days are specified + as an interval of integer values where 1 means Monday and 7 means + Sunday. In order to define a weekend from Sunday to Monday, specify + (7,1). + + \param start the first day of the weekend + \param end the last day of the weekend + \sa weekendDays(), setWeekendBackgroundColor(), weekendBackgroundColor() +*/ +void KDGanttView::setWeekendDays( int start, int end ) +{ + myTimeHeader->setWeekendDays( start, end ); +} + + +/*! + Returns which days are considered weekends. + + \param start in this parameter, the first day of the weekend is returned + \param end in this parameter, the end day of the weekend is returned + \sa setWeekendDays(), setWeekendBackgroundColor(), weekendBackgroundColor() +*/ +void KDGanttView::weekendDays( int& start, int& end ) const +{ + myTimeHeader->weekendDays( start, end ); +} + + +/*! + \fn void KDGanttView::itemLeftClicked( KDGanttViewItem* ) + + This signal is emitted when the user clicks on an item with the left + mouse button. +*/ + + +/*! + \fn void KDGanttView::itemMidClicked( KDGanttViewItem* ) + + This signal is emitted when the user clicks on an item with the middle + mouse button. +*/ + + +/*! + \fn void KDGanttView::itemRightClicked( KDGanttViewItem* ) + + This signal is emitted when the user clicks on an item with the right + mouse button. +*/ + + +/*! + \fn void KDGanttView::itemDoubleClicked( KDGanttViewItem* ) + + This signal is emitted when the user double-clicks an item. +*/ + + +/*! + \fn void KDGanttView::itemConfigured( KDGanttViewItem* ) + + This signal is emitted when the user has configured an item + visually. +*/ + + + +/*! + \fn void KDGanttView::taskLinkLeftClicked( KDGanttViewTaskLink* ) + + This signal is emitted when the user clicks on a task link with the + left mouse button. +*/ + + +/*! + \fn void KDGanttView::taskLinkMidClicked( KDGanttViewTaskLink* ) + + This signal is emitted when the user clicks on a task link with the + middle mouse button. +*/ + + +/*! + \fn void KDGanttView::taskLinkRightClicked( KDGanttViewTaskLink* ) + + This signal is emitted when the user clicks on a task link with the + right mouse button. +*/ + + +/*! + \fn void KDGanttView::taskLinkDoubleClicked( KDGanttViewTaskLink* ) + + This signal is emitted when the user double-clicks a task link. +*/ + + +/*! + \enum KDGanttView::YearFormat + + This enum is used to specify the year format used in the header. +*/ + + +/*! + \enum KDGanttView::HourFormat + + This enum is used to specify the hour format used in the header. +*/ + + +/*! + \enum KDGanttView::Scale + + This enum is used to specify the units of the scales in the header. +*/ + + + + +/*! + Sets the number of ticks in the major scale. + + \param count the number of ticks in the major scale + \sa majorScaleCount(), setMinorScaleCount(), minorScaleCount() +*/ +void KDGanttView::setMajorScaleCount( int count ) +{ + myTimeHeader->setMajorScaleCount(count ); +} + + +/*! + Returns the number of ticks per unit in the major scale. + + \return the number of ticks in the major scale + \sa setMajorScaleCount(), setMinorScaleCount(), minorScaleCount() +*/ +int KDGanttView::majorScaleCount() const +{ + return myTimeHeader->majorScaleCount(); +} + + +/*! + Sets the number of ticks in the minor scale. + + \param count the number of ticks in the minor scale + \sa minorScaleCount, setMajorScaleCount, majorScaleCount() +*/ +void KDGanttView::setMinorScaleCount( int count ) +{ + myTimeHeader->setMinorScaleCount(count ); +} + + +/*! + Returns the number of ticks per unit in the minor scale. + + \return the number of ticks in the minor scale + \sa setMinorScaleCount(), setMajorScaleCount(), majorScaleCount() +*/ +int KDGanttView::minorScaleCount() const +{ + return myTimeHeader->minorScaleCount(); + +} + + +/*! + Sets the default color for a particular type of Gantt item that is + used for the item if no specific start, middle, or end colors are + set. + + \param type the type of Gantt items for which to query the highlight + colors + \param color the default color to use + \param overwriteExisting if true, existing settings for individual + items are overwritten + \sa defaultColor(), setColors(), colors() +*/ +void KDGanttView::setDefaultColor( KDGanttViewItem::Type type, + const QColor& color, + bool overwriteExisting ) +{ + if ( overwriteExisting ) { + QListViewItemIterator it(myListView); + for ( ; it.current(); ++it ) { + if ( ((KDGanttViewItem*)it.current())->type() == type) + ((KDGanttViewItem*)it.current())->setDefaultColor(color ); + } + } + int index = getIndex( type ); + myDefaultColor [index] = color; +} + + + +/*! + Returns the default color for a particular type of Gantt item that + is used for the item if no specific start, middle, or end colors are + set. + + \param type the type of Gantt items for which to query the highlight + colors + \return color the default color used + \sa setDefaultColor(), setColors(), colors() +*/ +QColor KDGanttView::defaultColor( KDGanttViewItem::Type type ) const +{ + int index = getIndex( type ); + return myDefaultColor [index]; +} + + +/*! + Sets the default highlighting color for a particular type of + Gantt item that is used for the item if no specific start, middle, + or end colors are set. + + \param type the type of Gantt items for which to query the highlight + colors + \param color the default highlighting color to use + \param overwriteExisting if true, existing color settings in + individual items are overwritten + \sa defaultHighlightColor(), setHighlightColors(), highlightColors() +*/ +void KDGanttView::setDefaultHighlightColor( KDGanttViewItem::Type type, + const QColor& color, + bool overwriteExisting ) +{ + if ( overwriteExisting ) { + QListViewItemIterator it(myListView); + for ( ; it.current(); ++it ) { + if ( ((KDGanttViewItem*)it.current())->type() == type) + ((KDGanttViewItem*)it.current())->setDefaultHighlightColor(color ); + } + } + int index = getIndex( type ); + myDefaultColorHL [index] = color; +} + + + +/*! + Returns the default highlighting color for a particular type of + Gantt item that is used for the item if no specific start, middle, + or end colors are set. + + \param type the type of Gantt items for which to query the highlight + colors + \return color the default highlighting color used + \sa setDefaultHighlightColor(), setHighlightColors(), highlightColors() +*/ +QColor KDGanttView::defaultHighlightColor( KDGanttViewItem::Type type ) const +{ + int index = getIndex( type ); + return myDefaultColorHL [index]; +} + + +/*! + Returns the first item in the Gantt view. + + \return the first item in the Gantt view, 0 if there are no items +*/ +KDGanttViewItem* KDGanttView::firstChild() const +{ + return (KDGanttViewItem*)myListView->firstChild(); + +} +/*! + This method turns calendar mode on and off. In calendar mode, only + those items can be opened which have subitems which have + subitems. I.e., if an item contains multiple calendars, it can be + opened, but not a calendar item itself. If you want to use this + GanttView as a calendar view, you have to call + setDisplaySubitemsAsGroup( true ); to use the root items as calendar + items. To create new calendar entries for these root items, create + a new KDGanttViewTaskItem with this root item as a parent. If you + want an item with subitems to behave like a calendar (which is + possibly empty at startup), please call setIsCalendar( true ); for + this item. + + \param mode if true, the calendar view mode is turned on + if false, the calendar view mode is turned off + \sa setDisplaySubitemsAsGroup(), displaySubitemsAsGroup(), calendarMode() +*/ +void KDGanttView::setCalendarMode( bool mode ) +{ + myListView->setCalendarMode( mode ); +} + + +/*! + Returns true, if the Gantt view is in calendar mode. See + setCalendarMode() for the meaning of calendar mode. + + \return returns true, if the Gantt view is in calendermode + \sa setCalendarMode() +*/ +bool KDGanttView::calendarMode() const +{ + return myListView->calendarMode(); +} + + + +/*! + This method specifies whether hidden subitems should be displayed. + It iterates over all KDGanttViewItems in this Gantt view + and sets their displaySubitemsAsGroup() property. + All newly created items will have this setting by default. + \param show if true, the hidden subitems are displayed in all items of + this Gantt view. + \sa KDGanttViewItem::setDisplaySubitemsAsGroup(), KDGanttViewItem::displaySubitemsAsGroup() +*/ +void KDGanttView::setDisplaySubitemsAsGroup( bool show ) +{ + QListViewItemIterator it( myListView ); + for ( ; it.current(); ++it ) { + KDGanttViewItem* currentItem = ( KDGanttViewItem* )it.current(); + currentItem->setDisplaySubitemsAsGroup( show ); + } + _displaySubitemsAsGroup = show; +} + + +/*! + Returns, whether new items are created with the + displayHiddenSubitems property. + \return true, if hidden subitems should be displayed on newly created items. + \sa setDisplaySubitemsAsGroup(), + KDGanttViewItem::setDisplaySubitemsAsGroup(), + KDGanttViewItem::displaySubitemsAsGroup() +*/ +bool KDGanttView::displaySubitemsAsGroup() const +{ + return _displaySubitemsAsGroup; +} + + +/*! + This method specifies whether tasks where the start time and the end + time are the same are displayed + as a line over the full height of the Gantt view. + \param show if true, tasks with starttime == endtime are displayed + as a line +*/ +void KDGanttView::setDisplayEmptyTasksAsLine( bool show ) +{ + _displayEmptyTasksAsLine = show; +} + + +/*! + Returns, whether tasks where the start time and the end time are the + same are displayed + as a line over the full height of the Gantt view. + \return true, if empty tasks are displayed as line. +*/ +bool KDGanttView::displayEmptyTasksAsLine() const +{ + return _displayEmptyTasksAsLine; +} + + +/*! + Defines the horizontal background lines of the Gantt chart. + Call setHorBackgroundLines() + (equivalent to setHorBackgroundLines( 2, QBrush( QColor ( 240,240,240 )) ) ) + to draw a light grey horizontal background line for every second Gantt item. + Call setHorBackgroundLines(0) in order to not show horizontal + background lines. + You may specify the number of lines and the brush of the lines. + + \param count for count >= 2, every count line gets a backgroud + specified by brush + for count < 2, no background lines are drawn + \param brush the brush of the lines +*/ +void KDGanttView::setHorBackgroundLines( int count, QBrush brush ) +{ + myTimeTable->setHorBackgroundLines( count, brush ); +} + + +/*! + Returns the definition of the horizontal background lines of the + Gantt chart. + + \param brush the brush of the lines + \return every nth line gets a background specified by brush + if 0 is returned, no backgroud lines are drawn + +*/ +int KDGanttView::horBackgroundLines( QBrush& brush ) +{ + return myTimeTable->horBackgroundLines( brush ); +} + + +/*! + Returns the last item in the Gantt view + + \return the last item in the Gantt view, 0 if there are no items +*/ +KDGanttViewItem* KDGanttView::lastItem() const +{ + return (KDGanttViewItem*)myListView->lastItem (); +} + + +/*! + Returns the list of task links in the Gantt view. + + \return the list of task links in the Gantt view +*/ +QPtrList KDGanttView::taskLinks() const +{ + + return myTimeTable->taskLinks(); +} + + +/*! + Returns the list of task link groups in the Gantt view. + + \return the list of task link groups in the Gantt view +*/ +QPtrList KDGanttView::taskLinkGroups() const +{ + return myTaskLinkGroupList; +} + + +/** + Reads the parameters of the view from an XML document. + \param doc the XML document to read from + \return true if the parameters could be read, false if a file + format error occurred + \sa saveXML +*/ +bool KDGanttView::loadXML( const QDomDocument& doc ) +{ + QDomElement docRoot = doc.documentElement(); // ChartParams element + QDomNode node = docRoot.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "ShowLegend" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowLegend( value ); + } else if( tagName == "ShowLegendButton" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowLegendButton( value ); + } else if( tagName == "LegendIsDockWindow" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setLegendIsDockwindow( value ); + } else if( tagName == "ShowListView" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowListView( value ); + } else if( tagName == "ShowHeader" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setHeaderVisible( value ); + } else if( tagName == "ShowTaskLinks" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowTaskLinks( value ); + } else if( tagName == "EditorEnabled" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setEditorEnabled( value ); + } else if( tagName == "DisplayEmptyTasksAsLine" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setDisplayEmptyTasksAsLine( value ); + } else if( tagName == "GlobalFont" ) { + QFont font; + if( KDGanttXML::readFontNode( element, font ) ) + setFont( font ); + } else if( tagName == "HorizonStart" ) { + QDateTime value; + if( KDGanttXML::readDateTimeNode( element, value ) ) + setHorizonStart( value ); + } else if( tagName == "HorizonEnd" ) { + QDateTime value; + if( KDGanttXML::readDateTimeNode( element, value ) ) + setHorizonEnd( value ); + } else if( tagName == "Scale" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setScale( stringToScale( value ) ); + } else if( tagName == "MinimumScale" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setMinimumScale( stringToScale( value ) ); + } else if( tagName == "MaximumScale" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setMaximumScale( stringToScale( value ) ); + } else if( tagName == "YearFormat" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setYearFormat( stringToYearFormat( value ) ); + } else if( tagName == "HourFormat" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setHourFormat( stringToHourFormat( value ) ); + } else if( tagName == "ShowMinorTicks" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowMinorTicks( value ); + } else if( tagName == "ShowMajorTicks" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowMajorTicks( value ); + } else if( tagName == "DragEnabled" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setDragEnabled( value ); + } else if( tagName == "DropEnabled" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setDropEnabled( value ); + } else if( tagName == "CalendarMode" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setCalendarMode( value ); + } else if( tagName == "Editable" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setEditable( value ); + } else if( tagName == "TextColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setTextColor( value ); + } else if( tagName == "MajorScaleCount" ) { + int value; + if( KDGanttXML::readIntNode( element, value ) ) + setMajorScaleCount( value ); + } else if( tagName == "MinorScaleCount" ) { + int value; + if( KDGanttXML::readIntNode( element, value ) ) + setMinorScaleCount( value ); + } else if( tagName == "AutoScaleMinorTickCount" ) { + int value; + if( KDGanttXML::readIntNode( element, value ) ) + setAutoScaleMinorTickCount( value ); + } else if( tagName == "MinimumColumnWidth" ) { + int value; + if( KDGanttXML::readIntNode( element, value ) ) + setMinimumColumnWidth( value ); + } else if( tagName == "GanttMaximumWidth" ) { + int value; + if( KDGanttXML::readIntNode( element, value ) ) + setGanttMaximumWidth( value ); + } else if( tagName == "NoInformationBrush" ) { + QBrush value; + if( KDGanttXML::readBrushNode( element, value ) ) + setNoInformationBrush( value ); + } else if( tagName == "GanttViewBackgroundColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setGvBackgroundColor( value ); + } else if( tagName == "ListViewBackgroundColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setLvBackgroundColor( value ); + } else if( tagName == "TimeHeaderBackgroundColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setTimeHeaderBackgroundColor( value ); + } else if( tagName == "LegendHeaderBackgroundColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setLegendHeaderBackgroundColor( value ); + } else if( tagName == "WeekendBackgroundColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setWeekendBackgroundColor( value ); + } else if( tagName == "WeekdayBackgroundColor" ) { + QDomNode node = element.firstChild(); + int day = 0; + QColor color; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Day" ) { + int value; + if( KDGanttXML::readIntNode( element, value ) ) + day = value; + } else if( tagName == "Color" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + color = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + + if( day && color.isValid() ) + setWeekdayBackgroundColor( color, day ); + } else if( tagName == "WeekendDays" ) { + QString startString = element.attribute( "Start" ); + QString endString = element.attribute( "End" ); + bool startOk = false, endOk = false; + int start = startString.toInt( &startOk ); + int end = startString.toInt( &endOk ); + if( startOk && endOk ) + setWeekendDays( start, end ); + } else if( tagName == "ZoomFactor" ) { + double value; + if( KDGanttXML::readDoubleNode( element, value ) ) + setZoomFactor( value, true ); + } else if( tagName == "ShowHeaderPopupMenu" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowHeaderPopupMenu( value ); + } else if( tagName == "ShowTimeTablePopupMenu" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setShowTimeTablePopupMenu( value ); + } else if( tagName == "Shapes" ) { + QDomNode node = element.firstChild(); + bool undefinedShape = false; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Event" ) { + KDGanttViewItem::Shape startShape, middleShape, endShape; + startShape = KDGanttViewItem::TriangleDown; + middleShape = KDGanttViewItem::TriangleDown; + endShape = KDGanttViewItem::TriangleDown; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + startShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else if( tagName == "Middle" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + middleShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else if( tagName == "End" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + endShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + if ( ! undefinedShape ) + setShapes( KDGanttViewItem::Event, startShape, + middleShape, endShape, false ); + undefinedShape = false; + } else if( tagName == "Task" ) { + KDGanttViewItem::Shape startShape, middleShape, endShape; + startShape = KDGanttViewItem::TriangleDown; + middleShape = KDGanttViewItem::TriangleDown; + endShape = KDGanttViewItem::TriangleDown; + QDomNode node = element.firstChild(); + while( !node.isNull()) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + startShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else if( tagName == "Middle" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + middleShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else if( tagName == "End" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + endShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + if ( ! undefinedShape ) + setShapes( KDGanttViewItem::Task, startShape, middleShape, endShape, false ); + undefinedShape = false; + } else if( tagName == "Summary" ) { + KDGanttViewItem::Shape startShape, middleShape, endShape; + startShape = KDGanttViewItem::TriangleDown; + middleShape = KDGanttViewItem::TriangleDown; + endShape = KDGanttViewItem::TriangleDown; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + startShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else if( tagName == "Middle" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + middleShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else if( tagName == "End" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + endShape = KDGanttViewItem::stringToShape( value ); + if ( value == "Undefined" ) + undefinedShape = true; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + if ( ! undefinedShape ) + setShapes( KDGanttViewItem::Summary, startShape, + middleShape, endShape, false ); + undefinedShape = false; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else if( tagName == "Colors" ) { + QDomNode node = element.firstChild(); + while( !node.isNull()) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Event" ) { + QColor startColor, middleColor, endColor; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "Middle" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "End" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + setColors( KDGanttViewItem::Event, startColor, + middleColor, endColor, false ); + } else if( tagName == "Task" ) { + QColor startColor, middleColor, endColor; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "Middle" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "End" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + setColors( KDGanttViewItem::Task, startColor, + middleColor, endColor, false ); + } else if( tagName == "Summary" ) { + QColor startColor, middleColor, endColor; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "Middle" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "End" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + setColors( KDGanttViewItem::Summary, startColor, + middleColor, endColor , false); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else if( tagName == "DefaultColors" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Event" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultColor( KDGanttViewItem::Event, + value, false ); + } else if( tagName == "Task" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultColor( KDGanttViewItem::Task, + value, false ); + } else if( tagName == "Summary" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultColor( KDGanttViewItem::Summary, + value , false); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + } else if( tagName == "HighlightColors" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Event" ) { + QColor startColor, middleColor, endColor; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "Middle" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "End" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + setHighlightColors( KDGanttViewItem::Event, + startColor, + middleColor, endColor, false ); + } else if( tagName == "Task" ) { + QColor startColor, middleColor, endColor; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "Middle" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "End" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + setHighlightColors( KDGanttViewItem::Task, + startColor, + middleColor, endColor , false); + } else if( tagName == "Summary" ) { + QColor startColor, middleColor, endColor; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an elemente + QString tagName = element.tagName(); + if( tagName == "Start" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "Middle" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "End" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + setHighlightColors( KDGanttViewItem::Summary, + startColor, + middleColor, endColor, false ); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else if( tagName == "DefaultHighlightColors" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Event" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultHighlightColor( KDGanttViewItem::Event, + value , false); + } else if( tagName == "Task" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultHighlightColor( KDGanttViewItem::Task, + value, false ); + } else if( tagName == "Summary" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultHighlightColor( KDGanttViewItem::Summary, + value, false ); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + } else if( tagName == "Items" ) { + QDomNode node = element.firstChild(); + KDGanttViewItem* previous = 0; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Item" ) { + KDGanttViewItem* newItem; + if( previous ) + newItem = + KDGanttViewItem::createFromDomElement( this, + previous, + element ); + else + newItem = + KDGanttViewItem::createFromDomElement( this, + element ); + previous = newItem; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + } else if( tagName == "TaskLinks" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "TaskLink" ) + KDGanttViewTaskLink::createFromDomElement( element ); + else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + } else if( tagName == "TaskLinkGroups" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "TaskLink" ) + KDGanttViewTaskLinkGroup::createFromDomElement( element ); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + + node = node.nextSibling(); + } + } else if( tagName == "ColumnBackgroundColors" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "ColumnBackgroundColor" ) { + QDomNode node = element.firstChild(); + QDateTime dateTime; + QColor color; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was + // really an + // element + QString tagName = element.tagName(); + if( tagName == "DateTime" ) { + QDateTime value; + if( KDGanttXML::readDateTimeNode( element, value ) ) + dateTime = value; + } else if( tagName == "Color" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + color = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + setColumnBackgroundColor( dateTime, color ); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else if( tagName == "LegendItems" ) { + clearLegend(); + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "LegendItem" ) { + KDGanttViewItem::Shape tempLegendShape; + tempLegendShape = KDGanttViewItem::TriangleDown; + QColor tempLegendColor; + QString tempLegendString; + bool ok = true; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Shape" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + tempLegendShape = KDGanttViewItem::stringToShape( value ); + else + ok = false; + } else if( tagName == "Color" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + tempLegendColor = value; + else + ok = false; + } else if( tagName == "Text" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + tempLegendString = value; + else + ok = false; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + if( ok ) { + addLegendItem( tempLegendShape, + tempLegendColor, + tempLegendString ); + qDebug( "Adding legend item %s", tempLegendString.latin1() ); + } + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } // while + return true; /* FIXME: Do real error-reporting. The ASSERT's should be "return false" stmnts */ +} // method + + +/** + Saves the parameters of the view parameters to an XML document. + + \param withPI pass true to store processing instructions, false to + leave them out + \return the XML document that represents the parameters + \sa loadXML +*/ +QDomDocument KDGanttView::saveXML( bool withPI ) const +{ + // Create an inital DOM document + QString docstart = ""; + + QDomDocument doc( "GanttView" ); + doc.setContent( docstart ); + if( withPI ) { + QDomProcessingInstruction pin = doc.createProcessingInstruction( "kdgantt", "version=\"1.0\" encoding=\"UTF-8\"" ) ; + doc.appendChild ( pin ); + } + + QDomElement docRoot = doc.documentElement(); + docRoot.setAttribute( "xmlns", "http://www.klaralvdalens-datakonsult.se/kdgantt" ); + docRoot.setAttribute( "xmlns:xsi", "http://www.w3.org/2000/10/XMLSchema-instance" ); + docRoot.setAttribute( "xsi:schemaLocation", "http://www.klaralvdalens-datakonsult.se/kdgantt" ); + + // the ShowLegend element + KDGanttXML::createBoolNode( doc, docRoot, "ShowLegend", showLegend() ); + + // the ShowLegendButton element + KDGanttXML::createBoolNode( doc, docRoot, "ShowLegendButton", + showLegendButton() ); + + // the LegendIsDockWindow element + KDGanttXML::createBoolNode( doc, docRoot, "LegendIsDockWindow", + legendIsDockwindow() ); + + // the ShowListView element + KDGanttXML::createBoolNode( doc, docRoot, "ShowListView", showListView() ); + + // the ShowHeader element + KDGanttXML::createBoolNode( doc, docRoot, "ShowHeader", headerVisible() ); + + // the ShowTaskLinks element + KDGanttXML::createBoolNode( doc, docRoot, "ShowTaskLinks", showTaskLinks() ); + + // the EditorEnabled element + KDGanttXML::createBoolNode( doc, docRoot, "EditorEnabled", editorEnabled() ); + + // the global font element + KDGanttXML::createFontNode( doc, docRoot, "GlobalFont", font() ); + + // the DisplayEmptyTasksAsLine element + KDGanttXML::createBoolNode( doc, docRoot, "DisplayEmptyTasksAsLine", + displayEmptyTasksAsLine() ); + + // the HorizonStart element + KDGanttXML::createDateTimeNode( doc, docRoot, "HorizonStart", horizonStart() ); + + // the HorizonEnd element + KDGanttXML::createDateTimeNode( doc, docRoot, "HorizonEnd", horizonEnd() ); + + // the Scale, MinimumScale, MaximumScale elements + KDGanttXML::createStringNode( doc, docRoot, "Scale", scaleToString( scale() ) ); + KDGanttXML::createStringNode( doc, docRoot, "MinimumScale", + scaleToString( minimumScale() ) ); + KDGanttXML::createStringNode( doc, docRoot, "MaximumScale", + scaleToString( maximumScale() ) ); + + // the YearFormat element + KDGanttXML::createStringNode( doc, docRoot, "YearFormat", + yearFormatToString( yearFormat() ) ); + + // the HourFormat element + KDGanttXML::createStringNode( doc, docRoot, "HourFormat", + hourFormatToString( hourFormat() ) ); + + // the ShowMinorTicks element + KDGanttXML::createBoolNode( doc, docRoot, "ShowMinorTicks", showMinorTicks() ); + + // the ShowMajorTicks element + KDGanttXML::createBoolNode( doc, docRoot, "ShowMajorTicks", showMajorTicks() ); + + // the Editable element + KDGanttXML::createBoolNode( doc, docRoot, "Editable", editable() ); + + // the TextColor element + KDGanttXML::createColorNode( doc, docRoot, "TextColor", textColor() ); + + // the MajorScaleCount element + KDGanttXML::createIntNode( doc, docRoot, "MajorScaleCount", majorScaleCount() ); + + // the MinorScaleCount element + KDGanttXML::createIntNode( doc, docRoot, "MinorScaleCount", minorScaleCount() ); + + // the AutoScaleMinorTickCount element + KDGanttXML::createIntNode( doc, docRoot, "AutoScaleMinorTickCount", + autoScaleMinorTickCount() ); + + // the MinimumColumnWidth element + KDGanttXML::createIntNode( doc, docRoot, "MinimumColumnWidth", + minimumColumnWidth() ); + + // the GanttMaximumWidth element + KDGanttXML::createIntNode( doc, docRoot, "GanttMaximumWidth", + ganttMaximumWidth() ); + + // the NoInformationBrush element + KDGanttXML::createBrushNode( doc, docRoot, "NoInformationBrush", + noInformationBrush() ); + + // the GanttViewBackgroundColor element + KDGanttXML::createColorNode( doc, docRoot, "GanttViewBackgroundColor", + gvBackgroundColor() ); + + // the ListViewBackgroundColor element + KDGanttXML::createColorNode( doc, docRoot, "ListViewBackgroundColor", + lvBackgroundColor() ); + + // the TimeHeaderBackgroundColor element + KDGanttXML::createColorNode( doc, docRoot, "TimeHeaderBackgroundColor", + timeHeaderBackgroundColor() ); + + // the LegendHeaderBackgroundColor element + KDGanttXML::createColorNode( doc, docRoot, "LegendHeaderBackgroundColor", + legendHeaderBackgroundColor() ); + + // the WeekendBackgroundColor element + KDGanttXML::createColorNode( doc, docRoot, "WeekendBackgroundColor", + weekendBackgroundColor() ); + + // the WeekdayBackgroundColor elements + for( int weekday = 1; weekday <= 7; weekday++ ) { + QColor color = weekdayBackgroundColor( weekday ); + if( color.isValid() ) { + QDomElement weekendBackgroundColorElement = doc.createElement( "WeekdayBackgroundColor" ); + docRoot.appendChild( weekendBackgroundColorElement ); + KDGanttXML::createIntNode( doc, weekendBackgroundColorElement, + "Day", weekday ); + KDGanttXML::createColorNode( doc, weekendBackgroundColorElement, + "Color", color ); + } + } + + // the WeekendDays element + QDomElement weekendDaysElement = doc.createElement( "WeekendDays" ); + docRoot.appendChild( weekendDaysElement ); + int weekendStart, weekendEnd; + weekendDays( weekendStart, weekendEnd ); + weekendDaysElement.setAttribute( "Start", weekendStart ); + weekendDaysElement.setAttribute( "End", weekendStart ); + + // the ZoomFactor element + KDGanttXML::createDoubleNode( doc, docRoot, "ZoomFactor", + zoomFactor() ); + + // the ShowHeaderPopupMenu element + KDGanttXML::createBoolNode( doc, docRoot, "ShowHeaderPopupMenu", + showHeaderPopupMenu() ); + + // the ShowTimeTablePopupMenu element + KDGanttXML::createBoolNode( doc, docRoot, "ShowTimeTablePopupMenu", + showTimeTablePopupMenu() ); + + // the Shapes element + QDomElement shapesElement = doc.createElement( "Shapes" ); + docRoot.appendChild( shapesElement ); + QDomElement shapesEventElement = doc.createElement( "Event" ); + shapesElement.appendChild( shapesEventElement ); + KDGanttViewItem::Shape start, middle, end; + if( shapes( KDGanttViewItem::Event, start, middle, end ) ) { + KDGanttXML::createStringNode( doc, shapesEventElement, "Start", + KDGanttViewItem::shapeToString( start ) ); + KDGanttXML::createStringNode( doc, shapesEventElement, "Middle", + KDGanttViewItem::shapeToString( middle ) ); + KDGanttXML::createStringNode( doc, shapesEventElement, "End", + KDGanttViewItem::shapeToString( end ) ); + } else { + KDGanttXML::createStringNode( doc, shapesEventElement, "Start", + "Undefined" ); + KDGanttXML::createStringNode( doc, shapesEventElement, "Middle", + "Undefined" ); + KDGanttXML::createStringNode( doc, shapesEventElement, "End", + "Undefined" ); + } + QDomElement shapesTaskElement = doc.createElement( "Task" ); + shapesElement.appendChild( shapesTaskElement ); + if( shapes( KDGanttViewItem::Task, start, middle, end ) ) { + KDGanttXML::createStringNode( doc, shapesTaskElement, "Start", + KDGanttViewItem::shapeToString( start ) ); + KDGanttXML::createStringNode( doc, shapesTaskElement, "Middle", + KDGanttViewItem::shapeToString( middle ) ); + KDGanttXML::createStringNode( doc, shapesTaskElement, "End", + KDGanttViewItem::shapeToString( end ) ); + } else { + KDGanttXML::createStringNode( doc, shapesTaskElement, "Start", + "Undefined" ); + KDGanttXML::createStringNode( doc, shapesTaskElement, "Middle", + "Undefined" ); + KDGanttXML::createStringNode( doc, shapesTaskElement, "End", + "Undefined" ); + } + QDomElement shapesSummaryElement = doc.createElement( "Summary" ); + shapesElement.appendChild( shapesSummaryElement ); + if( shapes( KDGanttViewItem::Event, start, middle, end ) ) { + KDGanttXML::createStringNode( doc, shapesSummaryElement, "Start", + KDGanttViewItem::shapeToString( start ) ); + KDGanttXML::createStringNode( doc, shapesSummaryElement, "Middle", + KDGanttViewItem::shapeToString( middle ) ); + KDGanttXML::createStringNode( doc, shapesSummaryElement, "End", + KDGanttViewItem::shapeToString( end ) ); + } else { + KDGanttXML::createStringNode( doc, shapesSummaryElement, "Start", + "Undefined" ); + KDGanttXML::createStringNode( doc, shapesSummaryElement, "Middle", + "Undefined" ); + KDGanttXML::createStringNode( doc, shapesSummaryElement, "End", + "Undefined" ); + } + + // the Colors element + QDomElement colorsElement = doc.createElement( "Colors" ); + docRoot.appendChild( colorsElement ); + QDomElement colorsEventElement = doc.createElement( "Event" ); + colorsElement.appendChild( colorsEventElement ); + QColor startColor, middleColor, endColor; + colors( KDGanttViewItem::Event, startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, colorsEventElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, colorsEventElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, colorsEventElement, "End", endColor ); + QDomElement colorsTaskElement = doc.createElement( "Task" ); + colorsElement.appendChild( colorsTaskElement ); + colors( KDGanttViewItem::Task, startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, colorsTaskElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, colorsTaskElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, colorsTaskElement, "End", endColor ); + QDomElement colorsSummaryElement = doc.createElement( "Summary" ); + colorsElement.appendChild( colorsSummaryElement ); + colors( KDGanttViewItem::Event, startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, colorsSummaryElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, colorsSummaryElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, colorsSummaryElement, "End", endColor ); + + // the DefaultColor element + QDomElement defaultColorsElement = doc.createElement( "DefaultColors" ); + docRoot.appendChild( defaultColorsElement ); + KDGanttXML::createColorNode( doc, defaultColorsElement, "Event", + defaultColor( KDGanttViewItem::Event ) ); + KDGanttXML::createColorNode( doc, defaultColorsElement, "Task", + defaultColor( KDGanttViewItem::Task ) ); + KDGanttXML::createColorNode( doc, defaultColorsElement, "Summary", + defaultColor( KDGanttViewItem::Summary ) ); + + + // the HighlightColors element + QDomElement highlightColorsElement = doc.createElement( "HighlightColors" ); + docRoot.appendChild( highlightColorsElement ); + QDomElement highlightColorsEventElement = doc.createElement( "Event" ); + highlightColorsElement.appendChild( highlightColorsEventElement ); + highlightColors( KDGanttViewItem::Event, startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, highlightColorsEventElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, highlightColorsEventElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, highlightColorsEventElement, "End", endColor ); + QDomElement highlightColorsTaskElement = doc.createElement( "Task" ); + highlightColorsElement.appendChild( highlightColorsTaskElement ); + highlightColors( KDGanttViewItem::Task, startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, highlightColorsTaskElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, highlightColorsTaskElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, highlightColorsTaskElement, "End", endColor ); + QDomElement highlightColorsSummaryElement = doc.createElement( "Summary" ); + highlightColorsElement.appendChild( highlightColorsSummaryElement ); + highlightColors( KDGanttViewItem::Event, startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "End", endColor ); + + + /* + if( highlightColors( KDGanttViewItem::Event, startColor, middleColor, endColor ) ) { + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "Start", startColor ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "Middle", middleColor ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "End", endColor ); + } else { + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "Start", QColor() ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "Middle", QColor() ); + KDGanttXML::createColorNode( doc, highlightColorsSummaryElement, "End", QColor() ); + } + */ + // the DefaultHighlightColor element + QDomElement defaultHighlightColorsElement = doc.createElement( "DefaultHighlightColors" ); + docRoot.appendChild( defaultHighlightColorsElement ); + KDGanttXML::createColorNode( doc, defaultHighlightColorsElement, "Event", + defaultHighlightColor( KDGanttViewItem::Event ) ); + KDGanttXML::createColorNode( doc, defaultHighlightColorsElement, "Task", + defaultHighlightColor( KDGanttViewItem::Task ) ); + KDGanttXML::createColorNode( doc, defaultHighlightColorsElement, "Summary", + defaultHighlightColor( KDGanttViewItem::Summary ) ); + + + // the Items element + QDomElement itemsElement = doc.createElement( "Items" ); + docRoot.appendChild( itemsElement ); + KDGanttViewItem* currentItem = firstChild(); + while( currentItem ) { + currentItem->createNode( doc, itemsElement ); + currentItem = currentItem->nextSibling(); + } + + // the TaskLinks element + QDomElement taskLinksElement = doc.createElement( "TaskLinks" ); + docRoot.appendChild( taskLinksElement ); + QPtrList taskLinkList = taskLinks(); + KDGanttViewTaskLink* currentTL = 0; + for( currentTL = taskLinkList.first(); currentTL; + currentTL = taskLinkList.next() ) + currentTL->createNode( doc, taskLinksElement ); + + // the TaskLinkGroups element + QDomElement taskLinkGroupsElement = doc.createElement( "TaskLinkGroups" ); + docRoot.appendChild( taskLinkGroupsElement ); + QPtrList taskLinkGroupList = taskLinkGroups(); + KDGanttViewTaskLinkGroup* currentTLG = 0; + for( currentTLG = taskLinkGroupList.first(); currentTLG; + currentTLG = taskLinkGroupList.next() ) + currentTLG->createNode( doc, taskLinkGroupsElement ); + + // the ColumnBackgroundColors element + QDomElement columnBackgroundColorsElement = + doc.createElement( "ColumnBackgroundColors" ); + docRoot.appendChild( columnBackgroundColorsElement ); + KDTimeHeaderWidget::ColumnColorList ccList = + myTimeHeader->columnBackgroundColorList(); + for( KDTimeHeaderWidget::ColumnColorList::iterator it = ccList.begin(); + it != ccList.end(); ++it ) { + QDomElement columnBackgroundColorElement = + doc.createElement( "ColumnBackgroundColor" ); + columnBackgroundColorsElement.appendChild( columnBackgroundColorElement ); + KDGanttXML::createDateTimeNode( doc, columnBackgroundColorElement, + "DateTime", (*it).datetime ); + KDGanttXML::createColorNode( doc, columnBackgroundColorElement, + "Color", (*it).color ); + } + + // the LegendItems element + QDomElement legendItemsElement = + doc.createElement( "LegendItems" ); + docRoot.appendChild( legendItemsElement ); + legendItem* current; + QPtrListIterator lit( *myLegendItems ); + while( ( current = lit.current() ) ) { + ++lit; + QDomElement legendItemElement = doc.createElement( "LegendItem" ); + legendItemsElement.appendChild( legendItemElement ); + KDGanttXML::createStringNode( doc, legendItemElement, "Shape", + KDGanttViewItem::shapeToString( current->shape ) ); + KDGanttXML::createColorNode( doc, legendItemElement, "Color", + current->color ); + KDGanttXML::createStringNode( doc, legendItemElement, "Text", + current->text ); + } + + // the DragEnabled element + KDGanttXML::createBoolNode( doc, docRoot, "DragEnabled", isDragEnabled() ); + + // the DropEnabled element + KDGanttXML::createBoolNode( doc, docRoot, "DropEnabled", isDropEnabled() ); + + // the CalendarMode element + KDGanttXML::createBoolNode( doc, docRoot, "CalendarMode", calendarMode() ); + + return doc; +} + + + +QString KDGanttView::scaleToString( Scale scale ) +{ + switch( scale ) { + case Minute: + return "Minute"; + case Hour: + return "Hour"; + case Day: + return "Day"; + case Week: + return "Week"; + case Month: + return "Month"; + case Auto: + return "Auto"; + } + return ""; +} + + +KDGanttView::Scale KDGanttView::stringToScale( const QString& string ) +{ + if( string == "Minute" ) + return Minute; + else if( string == "Hour" ) + return Hour; + else if( string == "Day" ) + return Day; + else if( string == "Week" ) + return Week; + else if( string == "Month" ) + return Month; + else if( string == "Auto" ) + return Auto; + + return Auto; +} + + +QString KDGanttView::yearFormatToString( YearFormat format ) +{ + switch( format ) { + case FourDigit: + return "FourDigit"; + case TwoDigit: + return "TwoDigit"; + case TwoDigitApostrophe: + return "TwoDigitApostrophe"; + case NoDate: + return "NoDate"; + } + return ""; +} + + +KDGanttView::YearFormat KDGanttView::stringToYearFormat( const QString& string ) +{ + if( string == "FourDigit" ) + return FourDigit; + else if( string == "TwoDigit" ) + return TwoDigit; + else if( string == "TwoDigitApostrophe" ) + return TwoDigitApostrophe; + else if( string == "NoDate" ) + return NoDate; + else + return FourDigit; +} + + +QString KDGanttView::hourFormatToString( HourFormat format ) +{ + switch( format ) { + case Hour_12: + return "Hour_12"; + case Hour_24: + return "Hour_24"; + case Hour_24_FourDigit: + return "Hour_24_FourDigit"; + } + return ""; +} + + +KDGanttView::HourFormat KDGanttView::stringToHourFormat( const QString& string ) +{ + if( string == "Hour_12" ) + return Hour_12; + else if( string == "Hour_24" ) + return Hour_24; + else + return Hour_24; +} + + +void KDGanttView::addTaskLinkGroup(KDGanttViewTaskLinkGroup* group) +{ + + if (myTaskLinkGroupList.isEmpty()) { + myTaskLinkGroupList.append(group); + return; + } + if (myTaskLinkGroupList.find(group) == -1) + myTaskLinkGroupList.append(group); +} + + +void KDGanttView::removeTaskLinkGroup(KDGanttViewTaskLinkGroup* group) +{ + myTaskLinkGroupList.remove(group); +} + + +/*! + This slot is called when a new item has been added to the Gantt + view. It will show the item attribute dialog in case the item is + editable. \a item is a pointer to the item that has been created. +*/ +void KDGanttView::editItem( KDGanttViewItem* item) +{ + if ( ! item ) + return; + if ( editorEnabled() ) { + if ( item->editable() ) { + myItemAttributeDialog->reset( item ); + myItemAttributeDialog->show(); + } + } +} + + +/*! + This method returns the pixmap used for a certain shape, in the + selected color and size. + + \param shape the shape to generate + \param shapeColor the foreground color of the shape + \param backgroundColor the background color of the shape + \param itemSize the size of the shape + \return the generated shape pixmap +*/ +QPixmap KDGanttView::getPixmap( KDGanttViewItem::Shape shape, + const QColor& shapeColor, + const QColor& backgroundColor, int itemSize) +{ + // 10 is a good value as size + int size = itemSize+2; + int hei = ( itemSize/3 ) / 2; + QPixmap p = QPixmap( size+4, size+4 ); + p.fill( backgroundColor ); + QPainter paint (&p); + QBrush b = QBrush ( Qt::SolidPattern ); + b.setColor( shapeColor ); + paint.setBrush( b ); + QPen pen( Qt::black, 1 ) ; + paint.setPen( pen ); + switch (shape) { + case KDGanttViewItem::TriangleDown:{ + QPointArray arr = QPointArray(3); + arr.setPoint(0,-size/2,-hei); + arr.setPoint(1,size/2,-hei); + arr.setPoint(2,0,((size/2)-hei)); + arr.translate( ( size/2 ) +2 , ( size/2 ) +2); + paint.drawPolygon( arr ); + break; + } + case KDGanttViewItem::TriangleUp :{ + QPointArray arr = QPointArray(3); + arr.setPoint(0,-size/2,hei); + arr.setPoint(1,size/2,hei); + arr.setPoint(2,0,(-size/2)+hei); + arr.translate( ( size/2 ) +2 , ( size/2 ) +2); + paint.drawPolygon( arr ); + break; + } + case KDGanttViewItem::Diamond :{ + QPointArray arr = QPointArray(4); + arr.setPoint(0,0,-size/2); + arr.setPoint(1,size/2,0); + arr.setPoint(2,0,size/2); + arr.setPoint(3,-size/2,0); + arr.translate( ( size/2 ) +2 , ( size/2 ) +2); + paint.drawPolygon( arr ); + break; + } + case KDGanttViewItem::Square :{ + QPointArray arr = QPointArray(4); + arr.setPoint(0,-size/2,-size/2); + arr.setPoint(1,size/2,-size/2); + arr.setPoint(2,size/2,size/2); + arr.setPoint(3,-size/2,size/2); + arr.translate( ( size/2 ) +2 , ( size/2 ) +2); + paint.drawPolygon( arr ); + break; + } + case KDGanttViewItem::Circle :{ + paint.drawEllipse( 2, 2, size, size); + break; + } + } + paint.end(); + return p; +} + +int KDGanttView::getIndex( KDGanttViewItem::Type type) const +{ + int index = -1; + switch (type) { + case (KDGanttViewItem::Event): + index = 0; + break; + case (KDGanttViewItem::Task): + index = 1; + break; + case (KDGanttViewItem::Summary): + index = 2; + break; + } + return index; +} + + +void KDGanttView::initDefaults() +{ + int i; + // We have 3 item types. Set all undefined to true. + for (i = 0;i<3;++i) { + undefinedShape[i] = true; + undefinedColor[i] = true; + undefinedColorHL[i] = true; + } + // setting the default colors + myDefaultColor [ getIndex( KDGanttViewItem::Event ) ] = Qt::blue; //event + myDefaultColorHL [ getIndex( KDGanttViewItem::Event ) ] = Qt::red; + myDefaultColor [ getIndex( KDGanttViewItem::Task ) ] = Qt::green;//task + myDefaultColorHL [ getIndex( KDGanttViewItem::Task ) ] = Qt::red; + myDefaultColor [ getIndex( KDGanttViewItem::Summary ) ] = Qt::cyan;//summary + myDefaultColorHL [ getIndex( KDGanttViewItem::Summary ) ] = Qt::red; + + // setting the default shape types + // currently, we take for each item for all three shapes (start, middle, end) the same default shape + for (i = 0;i<3;++i) { + myDefaultShape [3*getIndex( KDGanttViewItem::Event )+ i] = KDGanttViewItem::Diamond; //event + myDefaultShape [3*getIndex( KDGanttViewItem::Task ) +i] = KDGanttViewItem::Square; //task + myDefaultShape [3*getIndex( KDGanttViewItem::Summary ) +i] = KDGanttViewItem::TriangleDown; //summary + + } +} + + + +/*! + Calls to this method are passed through to the underlying \a QListView. +*/ +int KDGanttView::addColumn( const QString& label, int width ) +{ + return myListView->addColumn( label, width ); +} + + +/*! + Calls to this method are passed through to the underlying \a QListView. +*/ + +int KDGanttView::addColumn( const QIconSet& iconset, const QString& label, + int width ) +{ + return myListView->addColumn( iconset, label, width ); +} + + +/*! + Calls to this method are passed through to the underlying \a QListView. +*/ +void KDGanttView::removeColumn( int index ) +{ + myListView->removeColumn( index ); +} + + +/*! + Calls to this method are passed through to the underlying \a QListView. +*/ +KDGanttViewItem* KDGanttView::selectedItem() const +{ + return static_cast( myListView->selectedItem() ); +} + + +/*! + Calls to this method are passed through to the underlying \a QListView. +*/ +void KDGanttView::setSelected( KDGanttViewItem* item, bool selected ) +{ + myListView->setSelected( item, selected ); +} + + +/*! + Returns the pointer to the Gantt item with the name \a name. + If no item is found, the return value is 0. + If there is more than one item with the same name in the Gantt view, + the first item found will be returned. This may not necessarily be + the first item in the listview. + + \param name the name of the Gantt item + \return the pointer to the item with name \a name. O, if there is no item + in the Gantt view with this name. + +*/ +KDGanttViewItem* KDGanttView::getItemByName( const QString& name ) const +{ + KDGanttViewItem* temp = firstChild(),* ret; + while (temp != 0) { + if ( (ret = temp->getChildByName( name ) ) ) + return ret; + temp = temp->nextSibling(); + } + return 0; +} + + +/*! + Returns the pointer to the Gantt item at the position \a pos in the + list view. + The position \a pos is a global position. + If no item is found, 0 is returned. + + \param pos the (global) position of the Gantt item + \return the pointer to the item with position \a pos. O, if there is + no item in the list view at this position. + +*/ +KDGanttViewItem* KDGanttView::getItemByListViewPos( const QPoint& pos ) const +{ + return static_cast( myListView->itemAt(myListView->mapFromGlobal(pos) )); +} + + +/*! + Returns the pointer to the Gantt item at the position \a pos in the + Gantt view. + The position \a pos is a global position. + If no items are found, or the item is disabled, 0 is returned. + If there is more than one item with the same position in the Gantt view, + the first item found will be returned. This is not necessarily the + first item in the listview. + + \param pos the (global) position of the Gantt item + \return the pointer to the item with position \a pos. O, if there is no item + in the Gantt view at this position. + +*/ +KDGanttViewItem* KDGanttView::getItemByGanttViewPos( const QPoint& pos ) const +{ + KDGanttViewItem* item; + QPoint local = myCanvasView->mapFromGlobal(pos); + + QCanvasItemList il = myTimeTable->collisions( myCanvasView->viewportToContents( local )); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + if ( myCanvasView->getType(*it) == Type_is_KDGanttViewItem) { + item = myCanvasView->getItem(*it); + if ( item->enabled() ) + return item; + } + } + return 0; +} + + +/*! + Returns the pointer to the Gantt item at the position \a pos in the + list view part of the Gantt view. + The position \a pos is a global position if parameter \a global is true. + If the vertical part (y coordinate) of \a pos + (mapped to local coordinates) is less than 0 or + larger than the height of the listview, 0 is returned. + The horizontal part (x coordinate) of \a pos is ignored. + \param pos the position of the Gantt item + \param global if true, pos is assumed to be global + \return the pointer to the item with position \a pos. O, if there is no item + in the Gantt view at this position. + +*/ +KDGanttViewItem* KDGanttView::getItemAt( const QPoint& pos, bool global ) const +{ + /* buggy code - commented out + QPoint myPos; + if ( global ) + myPos = myListView->contentsToViewport( myListView->mapFromGlobal(pos) ); + else + myPos = myListView->contentsToViewport( pos ); + return (KDGanttViewItem*) myListView->itemAt( myPos ); + */ + + KDGanttViewItem* item; + KDGanttViewItem* retItem = 0; + int y; + if ( global ) + y = myCanvasView->mapFromGlobal(pos).y(); + else + y = pos.y(); + item = firstChild(); + while ( item != 0 ) { + int yc = item->itemPos(); + if ( yc <= y && y < yc + item->height()) { + retItem = item; + break; + } + item = item->itemBelow(); + } + return retItem; + +} + + +void KDGanttView::addTickRight() +{ + if ( !mFixedHorizon && _enableAdding && myCanvasView->horizontalScrollBar()->value() == myCanvasView->horizontalScrollBar()->maxValue()) { + //myCanvasView->horizontalScrollBar()->blockSignals( true ); + myTimeHeader->addTickRight(); + //myCanvasView->horizontalScrollBar()->blockSignals( false ); + myCanvasView->updateHorScrollBar(); + setTimelineToEnd(); + } +} + + +void KDGanttView::addTickLeft() +{ + if ( !mFixedHorizon && _enableAdding && myCanvasView->horizontalScrollBar()->value() == 0 ) { + myCanvasView->horizontalScrollBar()->blockSignals( true ); + myTimeHeader->addTickLeft(); + myCanvasView->horizontalScrollBar()->blockSignals( false ); + setTimelineToStart(); + } +} + + +void KDGanttView::enableAdding( int val ) +{ + _enableAdding = ( val == 0 || val == myCanvasView->horizontalScrollBar()->maxValue()); +} + + +/*! + Returns the number of items in the Gantt view. + + \return the number of items in the Gantt view. +*/ +int KDGanttView::childCount() const +{ + return myListView->childCount(); +} + + +/*! + Removes all items from the Gantt view. +*/ +void KDGanttView::clear() +{ + bool block = myTimeTable->blockUpdating(); + myTimeTable->setBlockUpdating( true ); + myListView->clear(); + myTimeTable->setBlockUpdating( false ); + myTimeTable->updateMyContent(); + myTimeTable->setBlockUpdating( block ); +} + + +/*! + Passes on the signal from the list view. +*/ +void KDGanttView::slot_lvDropped(QDropEvent* e, KDGanttViewItem* droppedItem, KDGanttViewItem* itemBelowMouse ) +{ + emit dropped( e, droppedItem, itemBelowMouse); +} + +/*! + Implements a pass-through to the list view. +*/ +QDragObject * KDGanttView::dragObject () +{ + return myListView->dragObject (); +} + + +/*! + Implements a pass-through to the list view. +*/ +void KDGanttView::startDrag () +{ + //myListView->pt_startDrag (); +} + + +/*! + This method is overridden for internal purposes. +*/ +void KDGanttView::setPaletteBackgroundColor( const QColor& col) +{ + QWidget::setPaletteBackgroundColor( col ); + timeHeaderSpacerWidget->setPaletteBackgroundColor( col ); +} + + +/*! + Sets the background color of the Gantt view. + + \param c the background color of the Gantt view. + \sa gvBackgroundColor() +*/ +void KDGanttView::setGvBackgroundColor ( const QColor & c ) +{ + myTimeTable->setBackgroundColor( c ); +} + + +/*! + Sets the background color of the time header. + + \param c the background color of the time header. + \sa timeHeaderBackgroundColor() +*/ +void KDGanttView::setTimeHeaderBackgroundColor ( const QColor & c ) +{ + myTimeHeader->setPaletteBackgroundColor( c ); + //rightWidget->setPaletteBackgroundColor( c ); + timeHeaderSpacerWidget->setPaletteBackgroundColor( c ); +} + + +/*! + Sets the background color of the legend header. + + \param c the background color of the legend header + \sa legendHeaderBackgroundColor() +*/ +void KDGanttView::setLegendHeaderBackgroundColor ( const QColor & c ) +{ + myLegend->setPaletteBackgroundColor( c ); + leftWidget->setPaletteBackgroundColor( c ); +} + + +/*! + Sets the background color of the list view. + + \param c the background color of the list view + \sa lvBackgroundColor() +*/ +void KDGanttView::setLvBackgroundColor ( const QColor & c ) +{ + myListView->viewport()->setPaletteBackgroundColor( c ); +} + + +/*! + Returns the background color of the list view. + + \return the background color of the list view + \sa setLvBackgroundColor() +*/ +QColor KDGanttView::lvBackgroundColor ( )const +{ + return myListView->viewport()->paletteBackgroundColor( ); +} + + +/*! + Returns the background color of the Gantt view. + + \return the background color of the Gantt view + \sa setGvBackgroundColor() +*/ +QColor KDGanttView::gvBackgroundColor () const +{ + return myTimeTable->backgroundColor( ); +} + + +/*! + Returns the background color of the time header. + + \return the background color of the time header + \sa setTimeHeaderBackgroundColor() +*/ +QColor KDGanttView::timeHeaderBackgroundColor () const +{ + return myTimeHeader->paletteBackgroundColor( ); +} + + +/*! + Returns the background color of the legend header. + + \return the background color of the legend header + \sa setLegendHeaderBackgroundColor() +*/ +QColor KDGanttView::legendHeaderBackgroundColor () const +{ + return myLegend->paletteBackgroundColor( ); +} + + +/*! + Adds a widget to the spacer widget above the list view part and + below the ShowLegendButton. To assign all the space above the + Listview to the spacer widget, hide the ShowLegendButton by calling + setShowLegendButton( false ). The spacer widget is a QHBox. You + may add as many widgets as you want. They are ordered horizontally + from left to right. To remove a widget from the spacer widget, call + widget->reparent(newParent,...) or delete the widget. Since the spacer + is a QHBox, the layout of the added widgets is managed by this + QHBox. + + \param w A pointer to the widget to be added. + \sa setShowLegendButton( ) +*/ +void KDGanttView::addUserdefinedLegendHeaderWidget( QWidget * w ) +{ + if ( w ) { + w->reparent ( spacerLeft, 0, QPoint(0,0) ); + } +} + + +/*! + Specifies whether drag operations are allowed in the Gantt + view. Recurses over all items contained in the Gantt view and + enables or disabled them for dragging. + + \param b true if dragging is enabled, false if dragging is disabled + \sa isDragEnabled(), setDropEnabled(), isDropEnabled(), setDragDropEnabled() +*/ +void KDGanttView::setDragEnabled( bool b ) +{ + fDragEnabled = b; + QListViewItemIterator it( myListView ); + for ( ; it.current(); ++it ) { + (( KDGanttViewItem* )it.current())->setDragEnabled(b); + } + +} + + +/*! + Specifies whether drop operations are allowed in the Gantt + view. Recurses over all items contained in the Gantt view and + enables or disabled them for dropping. + + \param b true if dragging is enabled, false if dragging is disabled + \sa setDropEnabled(), setDragEnabled(), isDragEnabled(), setDragDropEnabled() +*/ +void KDGanttView::setDropEnabled( bool b ) +{ + fDropEnabled = b; + + //myListView->setAcceptDrops( b ); + QListViewItemIterator it( myListView ); + for ( ; it.current(); ++it ) { + (( KDGanttViewItem* )it.current())->setDropEnabled(b); + } +} + + +/*! + Combines setDragEnabled() and setDropEnabled() in one convenient + method. + + \param b true if dragging and dropping are enabled, false if + dragging and dropping are disabled + \sa setDragEnabled(), setDropEnabled() +*/ +void KDGanttView::setDragDropEnabled( bool b ) +{ + setDropEnabled( b ); + setDragEnabled( b ); +} + + +/*! + Returns whether dragging is enabled for this Gantt view. + + \return true if dragging is enabled + \sa setDragEnabled(), setDragDropEnabled() +*/ +bool KDGanttView::isDragEnabled() const +{ + return fDragEnabled; +} + + +/*! + Returns whether dropping is enabled for this Gantt view. + + \return true if dropping is enabled + \sa setDropEnabled(), setDragDropEnabled() +*/ +bool KDGanttView::isDropEnabled() const +{ + return fDropEnabled; +} + + +/*! + \deprecated Use isDragEnabled() instead +*/ +bool KDGanttView::dragEnabled() const +{ + return isDragEnabled(); +} + + +/*! + \deprecated Use isDropEnabled() instead +*/ +bool KDGanttView::dropEnabled() const +{ + return isDropEnabled(); +} + + +/*! + This virtual method makes it possible to specify user-defined drop + handling. The method is called directly before the internal drop + handling is executed. Return false to execute internal drop + handling. Return true to not execute internal drop handling. In + order to specify user-defined drop handling, subclass + KDGanttView and reimplement this method. + + \param e The QDropEvent + Note: e->source() is a pointer to the KDGanttView from which the drag started. + I.e., if e->source() == this, this drag is an internal drag. + \param droppedItem 0, if this is a drag operation from another + KDGanttView instance. + If this drag is an internal drag (i.e., within the KDGanttView), + this parameter points to the dropped item. + \param itemBelowMouse a pointer to the item below the dragged + item (i.e., below the mouse). + If you accept, the dragged item may be inserted + in the KDGanttView as a child of this item. + The value is 0 if there is no item below the dragged item, + and the dragged item will be inserted as a root item. + + \return false, when the internal drop handling should be executed + true, when the internal drop handling should not be executed + \sa lvDropEvent(), lvStartDrag() +*/ +bool KDGanttView::lvDropEvent ( QDropEvent* e, + KDGanttViewItem* droppedItem, + KDGanttViewItem* itemBelowMouse ) +{ + Q_UNUSED( e ); + Q_UNUSED( droppedItem ); + Q_UNUSED( itemBelowMouse ); + + // Example code for user defined behaviour: + // we want to accept the usual drags and the drags of files, which may be + // a saved Gantt file. + // Please uncomment the following lines for this behaviour + // You have to uncomment lines in lvDragMoveEvent() and llvDragEnterEvent() as well + + // ************** begin example ************ + /* + if ( QUriDrag::canDecode( e ) ) { + QStrList lst; + QUriDrag::decode( e, lst ); + // we try the first file of icon-url-list + QString str = lst.at ( 0 ); + // remove file: at beginning of string + str = str.right( str.length() - 5 ); + QFileInfo info; + info.setFile( str ) ; + if ( info.isFile() ) { + if (!QMessageBox::information( this, "KDGantt Drag&Drop test", + "Try to insert file: "+ str + " ?", + "&Okay", "&Cancel",0,1 ) ) { + QFile file( str ); + // store current updating status + bool uen = myTimeTable->blockUpdating(); + // block updating while insertion of items + myTimeTable->setBlockUpdating(); + loadProject( &file ) ; + // restore updating status and execute an update via setUpdateEnabled( true ); + if ( !uen ) + setUpdateEnabled( true ); + } + } + return true; + } + */ + // *********** end example **************** + return false; +} + + +/*! + This virtual method specifies whether a drag enter event may be + accepted or not. + To accept a drag enter event, call e->accept( true ); + To not accept a drag enter evente, call e->accept( false ); + This method does nothing but accepting the drag enter event, in case + decoding is possible. + In order to define accepting drops for particular items yourself, + subclass KDGanttView and reimplement this method. + + \param e The QDragMoveEvent + Note: e->source() is a pointer to the KDGanttView, the drag started from. + I.e., if e->source() == this, this drag is an internal drag. + + \sa lvDropEvent(), lvStartDrag(), lvDragMoveEvent() +*/ +void KDGanttView::lvDragEnterEvent ( QDragEnterEvent * e) +{ + // the standard behaviour: + // accept drag enter events, if KDGanttViewItemDrag can decode the event + // e->accept(KDGanttViewItemDrag::canDecode(e) ); + + if ( KDGanttViewItemDrag::canDecode(e) ) { + e->accept( true); + return; + } + + // example code for user defined behaviour: + // we want to accecpt the usual drags and the drags of files, which may be + // a saved Gantt file + // Please uncomment the following lines for this behaviour + // You have to uncomment lines in lvDragMoveEvent() and lvDropEvent () as well + + // if ( QUriDrag::canDecode( e ) ) { + // e->accept(true); + // return; + // } + + e->accept( false ); +} + + +/*! + This virtual method specifies whether a drop event may be accepted or not. + To accept a drop event, call e->accept( true ); + To not accept a drop event, call e->accept( false ); + This method does nothing but allowing to execute the internal + drag move event handling. + + In order to specify user-defined drop acceptance for particular + items, subclass KDGanttView and reimplement this method. + + \param e The QDragMoveEvent + Note: e->source() is a pointer to the KDGanttView, the drag started from. + I.e. if e->source() == this, this drag is an internal drag. + draggedItem 0, if this is a drag operation from another KDGanttView instance. + If this drag is an internal drag (i.e., within the KDGanttView), + this parameter points to the dragged item. + itemBelowMouse a pointer to the item below the dragged item + (i.e., below the mouse). + If you accept the drop, the dragged item will be inserted + in the KDGanttView as a child of this item. + The value is 0 if there is no item below the dragged item, + and the dragged item will be inserted as a root item. + \return false, when the internal drag move event handling should be executed + true, when the internal drag move event handling should not + be executed; usually you should return true, + if you have called e->accept( true ) before. + \sa lvDropEvent(), lvStartDrag() +*/ +bool KDGanttView::lvDragMoveEvent ( QDragMoveEvent* /*e*/, + KDGanttViewItem* /* draggedItem*/, + KDGanttViewItem* /*itemBelowMouse*/) +{ + + // Example code 1: + // To generally block items to be inserted as root items, subclass KDGanttView + // and reimplement this method with to following code uncommented: + + // if ( !itemBelowMouse ) { + // e->accept( false ); + // return true; + //} + //return false; + + // Example code 2: + // To allow the drags of files, which may be + // a saved Gantt file, subclass KDGanttView + // and reimplement this method with to following code uncommented: + + // if ( QUriDrag::canDecode( e ) ) { + // e->accept(true); + // return true; + // } + + + // normal behaviour - the internal drag move event handling should be executed + return false; +} + + +/*! + This virtual method creates a QDragObject and starts a drag for a + KDGanttViewItem. + In order to prevent drags of particular items, subclass from + KDGanttView and reimplement this method. + + \param item the KDGanttViewItem, which should be dragged + \sa lvDropEvent(), lvDragMoveEvent() +*/ +void KDGanttView::lvStartDrag (KDGanttViewItem* item) +{ + QDragObject* d = new KDGanttViewItemDrag(item, this, "itemdrag" ); + // call d->drag() to start the dragging + // d->drag() returns true, if a move was requested as a drag + // if a copy (by pressing the -key) was performed, d->drag() returns false + // In order to avoid starting drags for particular items, subclass KDGanttView + // an reimplement this method. + // insert here some code like + // if ( item->parent() ) + // return; + // This particular code will make it impossible to drag other items but root items. + if ( d->drag() ) { + delete item; + } +} + + +/*! + Sets the width of the list view. Space will be taken from or given + to the Gantt view. + + \param w the width of the list view + \sa listViewWidth() +*/ +void KDGanttView::setListViewWidth( int w ) +{ + int sw = mySplitter->width(); + QValueList list; + list.append(w); + list.append(sw-w); + mySplitter->setSizes( list ); +} + + +/*! + Returns the width of the list view. + + \return the width of the list view + \sa setListViewWidth() +*/ +int KDGanttView::listViewWidth( ) +{ + return leftWidget->width(); +} + + +/*! + Sets the scrollbar mode of the listview. The default is always off. + Possible values are always on, always off and auto. + It only makes sense to set this to always off + if setGvVScrollBarMode() is set to always on. + + \param m the scrollbar mode. + \sa setGvVScrollBarMode( ) +*/ +void KDGanttView::setLvVScrollBarMode( QScrollView::ScrollBarMode m ) +{ + myListView->setVScrollBarMode ( m ); +} + + +/*! + Sets the scrollbar mode of the time table. The default is always on. + Possible values are always on and always off. + It only makes sense to set this to always off + if setLvVScrollBarMode() is set to always on or auto. + + \param m The scrollbar mode. + \sa setLvVScrollBarMode( ) +*/ +void KDGanttView::setGvVScrollBarMode( QScrollView::ScrollBarMode m ) +{ + if ( m == QScrollView::Auto ) + qDebug("KDGanttView::setListViewVScrollBarMode: QScrollView::Auto not supported. Nothing changed. "); + else + { + myCanvasView->setVScrollBarMode ( m ); + if ( m == QScrollView::AlwaysOn ) + timeHeaderSpacerWidget->setFixedWidth(myCanvasView->verticalScrollBar()->width() ); + else + timeHeaderSpacerWidget->setFixedWidth( 0 ); + } +} + + +void KDGanttView::notifyEditdialog( KDGanttViewItem * item) +{ + if (myItemAttributeDialog->getItem() == item ) { + myItemAttributeDialog->reset( 0 ); + } +} + +/*! + \fn void KDGanttView::setLinkItemsEnabled( bool on ); + + This enables/disables the linking ui of KDGanttViewItems in KDGanttView. + A signal linkItems() is emitted when two items shall be linked and can + be used to create the actual link. +*/ +void KDGanttView::setLinkItemsEnabled(bool on) +{ + myCanvasView->linkItemsEnabled = on; + myCanvasView->autoScrollEnabled = true; +} + +/*! + \fn void KDGanttView::isLinkItemsEnabled(); + + Returns if the linking functionallity is enabled or disabled. +*/ +bool KDGanttView::isLinkItemsEnabled() const +{ + return myCanvasView->linkItemsEnabled; +} + +/*! + \fn void KDGanttView::timeIntervalSelected( const QDateTime& start, const QDateTime& end); + + This signal is emitted when the user selects a time + interval with the mouse on the time header connect this signal to + the slot void zoomToSelection( const QDateTime& start, const + QDateTime& end) to obtain automatic zooming. +*/ + + +/*! + \fn void KDGanttView::timeIntervallSelected( const QDateTime& start, const QDateTime& end); + + \deprecated This signal is deprecated, do not use it in new code; + use timeIntervalSelected() instead. timeIntervallSelected() will be + removed in future versions. +*/ + + +/*! + \fn void KDGanttView::rescaling( Scale ) + + This signal is emitted if another scale is choosen than the + specified one: i.e. if the horizon has a very wide range from + start to end and as scale is choosen minute it may be that the + size of the Gantt widget would become more than 32000 pixels. In + this case the scale is automatically changed to Hour and + rescaling( Hour ) is emitted. If the widget size would be still + more than 32000 pixels, the scale is automatically changed to day + and rescaling( Day ) is emitted. In the new scale, the + minortickcount is increased such that the horizon will fit in the + maximum size of 32000 pixels. +*/ + + +/*! + \fn void KDGanttView::gvCurrentChanged( KDGanttViewItem* item ) + + This signal is emitted whenever the user clicks on the Gantt view + \a item parameter is 0, if no item was clicked +*/ + + +/*! + \fn void KDGanttView::gvItemLeftClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user clicks into the Gantt view + with the left mouse button. +*/ + + +/*! + \fn void KDGanttView::gvItemMidClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user clicks into the Gantt view + with the middle mouse button. +*/ + +/*! + \fn void KDGanttView::gvItemRightClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user clicks into the Gantt view + with the right mouse button. +*/ + +/*! + \fn void KDGanttView::gvMouseButtonClicked ( int button, KDGanttViewItem* item, const QPoint & pos) + + This signal is emitted when the user clicks into the Gantt view with + any mouse button. Notice that \a pos is the absolute mouse position. +*/ + +/*! + \fn void KDGanttView::gvItemDoubleClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user double-clicks into the Gantt view. +*/ + +/*! + \fn void KDGanttView::gvContextMenuRequested ( KDGanttViewItem * item, const QPoint & pos ) + + This signal is emitted when the user requests a context menu in the + Gantt view. Notice that \a pos is the absolute mouse position. +*/ + + +/*! + \fn void KDGanttView::linkItems ( KDGanttViewItem* from, KDGanttViewItem* to, int linkType ) + + This signal is emitted when the user wants to link two items in the Gantt view. +*/ + + +/*! + \fn void KDGanttView::lvCurrentChanged( KDGanttViewItem* item ) + + This signal is emitted whenever the user clicks on the list view + \a item parameter is 0, if no item was clicked +*/ + + +/*! + \fn void KDGanttView::lvItemLeftClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user clicks into the list view + with the left mouse button. +*/ + + +/*! + \fn void KDGanttView::lvItemMidClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user clicks into the list view + with the middle mouse button. +*/ + +/*! + \fn void KDGanttView::lvItemRightClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user clicks into the list view + with the right mouse button. +*/ + +/*! + \fn void KDGanttView::lvMouseButtonPressed ( int button, + KDGanttViewItem* item, const QPoint & pos, int col) + + This signal is emitted when the user presses any mouse button in the + list view. Notice that \a pos is the absolute mouse position. +*/ + +/*! + \fn void KDGanttView::lvMouseButtonClicked ( int button, + KDGanttViewItem* item, const QPoint & pos, int col) + + This signal is emitted when the user clicks into the + list view with any mouse button . Notice that \a pos is the absolute + mouse position. +*/ + +/*! + \fn void KDGanttView::lvItemDoubleClicked( KDGanttViewItem* ) + + This signal is emitted whenever the user double-clicks into the list view. +*/ + +/*! + \fn void KDGanttView::lvItemRenamed( KDGanttViewItem*, int col, + const QString& text ) + + This signal is emitted whenever the user changes the name of an item + in the list view using in-place editing. \a text contains the new + text in the list view. +*/ + +/*! + \fn void KDGanttView::lvContextMenuRequested( KDGanttViewItem * + item, const QPoint & pos, int col ) + + This signal is emitted when the user requests a context menu in the + list view. Notice that \a pos is the absolute mouse position. +*/ + +/*! + \fn void KDGanttView::lvSelectionChanged( KDGanttViewItem* ) + + This signal is emitted whenever the user changes the selection in + the list view. +*/ + + +/*! + \fn void KDGanttView::dropped ( QDropEvent * e, KDGanttViewItem* droppedItem, KDGanttViewItem* itemBelowMouse) + + This signal is emitted whenever a Gantt item is dropped onto the + Gantt view. \a droppedItem is 0, if this is a drag operation from + another KDGanttView instance. If this drag is an internal drag + (i.e. within the KDGanttView), this parameter points to the dropped item. + \a itemBelowMouse is a pointer to the item below the dragged + item (i.e., below the mouse). The dragged item may be inserted + in the KDGanttView as a child of this item. + If The value is 0, if there is no item below the dragged item, + and the dragged item will be inserted as a root item. + + In order to get user-defined behavior for drop events, reimplement + KDGanttView::lvDropEvent() +*/ + + +/*! + \enum KDGanttView::RepaintMode + + Please see setRepaintMode() for a description of the values of this + enumeration. +*/ + diff --git a/kdgantt/KDGanttView.h b/kdgantt/KDGanttView.h new file mode 100644 index 00000000..c0c9bbba --- /dev/null +++ b/kdgantt/KDGanttView.h @@ -0,0 +1,502 @@ +/* -*- Mode: C++ -*- + $Id$ + KDChart - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2001-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef KDGANTTVIEW_H +#define KDGANTTVIEW_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "KDGanttViewItem.h" +#include "KDGanttViewTaskLinkGroup.h" +#include "KDGanttMinimizeSplitter.h" +#include "KDGanttViewItemDrag.h" + +class KDIntervalColorRectangle; +class KDGanttViewTaskLink; +class QPrinter; +class QIODevice; +class itemAttributeDialog; +class KDListView; +class KDGanttViewItem; +class KDGanttViewEventItem; +class KDGanttViewTaskItem; +class KDGanttViewSummaryItem; +class KDTimeTableWidget; +class KDTimeHeaderWidget; +class KDLegendWidget; +class KDGanttCanvasView; +class KDGanttViewTaskLink; +class KDGanttMinimizeSplitter; + +class KDGanttView : public KDGanttMinimizeSplitter +{ + Q_OBJECT + + Q_PROPERTY( bool showLegend READ showLegend WRITE setShowLegend ) + Q_PROPERTY( bool showListView READ showListView WRITE setShowListView ) + Q_PROPERTY( bool showTaskLinks READ showTaskLinks WRITE setShowTaskLinks ) + Q_PROPERTY( bool editorEnabled READ editorEnabled WRITE setEditorEnabled ) + Q_PROPERTY( QDateTime horizonStart READ horizonStart WRITE setHorizonStart ) + Q_PROPERTY( QDateTime horizonEnd READ horizonEnd WRITE setHorizonEnd ) + Q_PROPERTY( Scale scale READ scale WRITE setScale ) + Q_PROPERTY( YearFormat yearFormat READ yearFormat WRITE setYearFormat ) + Q_PROPERTY( HourFormat hourFormat READ hourFormat WRITE setHourFormat ) + Q_PROPERTY( bool showMinorTicks READ showMinorTicks WRITE setShowMinorTicks ) + Q_PROPERTY( bool showMajorTicks READ showMajorTicks WRITE setShowMajorTicks ) + Q_PROPERTY( bool editable READ editable WRITE setEditable ) + Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor ) + Q_PROPERTY( int majorScaleCount READ majorScaleCount WRITE setMajorScaleCount ) + Q_PROPERTY( int minorScaleCount READ minorScaleCount WRITE setMinorScaleCount ) + Q_PROPERTY( int autoScaleMinorTickCount READ autoScaleMinorTickCount WRITE setAutoScaleMinorTickCount ) + Q_PROPERTY( Scale maximumScale READ maximumScale WRITE setMaximumScale ) + Q_PROPERTY( Scale minimumScale READ minimumScale WRITE setMinimumScale ) + Q_PROPERTY( int minimumColumnWidth READ minimumColumnWidth WRITE setMinimumColumnWidth ) + Q_PROPERTY( int ganttMaximumWidth READ ganttMaximumWidth WRITE setGanttMaximumWidth ) + Q_PROPERTY( QColor weekendBackgroundColor READ weekendBackgroundColor WRITE setWeekendBackgroundColor ) + Q_PROPERTY( QColor ganttViewBackgroundColor READ gvBackgroundColor WRITE setGvBackgroundColor ) + Q_PROPERTY( QColor listViewBackgroundColor READ lvBackgroundColor WRITE setLvBackgroundColor ) + Q_PROPERTY( QColor timeHeaderBackgroundColor READ timeHeaderBackgroundColor WRITE setTimeHeaderBackgroundColor ) + Q_PROPERTY( QColor legendHeaderBackgroundColor READ legendHeaderBackgroundColor WRITE setLegendHeaderBackgroundColor ) + Q_PROPERTY( double zoomFactor READ zoomFactor ) + Q_PROPERTY( bool showHeaderPopupMenu READ showHeaderPopupMenu WRITE setShowHeaderPopupMenu ) + Q_PROPERTY( bool showTimeTablePopupMenu READ showTimeTablePopupMenu WRITE setShowTimeTablePopupMenu ) + Q_PROPERTY( bool headerVisible READ headerVisible WRITE setHeaderVisible ) + Q_PROPERTY( bool showLegendButton READ showLegendButton WRITE setShowLegendButton ) + Q_PROPERTY( bool legendIsDockwindow READ legendIsDockwindow WRITE setLegendIsDockwindow ) + Q_PROPERTY( bool displayEmptyTasksAsLine READ displayEmptyTasksAsLine WRITE setDisplayEmptyTasksAsLine ) + Q_PROPERTY( QBrush noInformationBrush READ noInformationBrush WRITE setNoInformationBrush ) + Q_PROPERTY( bool dragEnabled READ dragEnabled WRITE setDragEnabled ) + Q_PROPERTY( bool dropEnabled READ dropEnabled WRITE setDropEnabled ) + Q_PROPERTY( bool calendarMode READ calendarMode WRITE setCalendarMode ) + + Q_ENUMS( Scale ) + Q_ENUMS( YearFormat ) + Q_ENUMS( HourFormat ) + +public: + enum Scale { Minute, Hour, Day, Week, Month, Auto }; + enum YearFormat { FourDigit, TwoDigit, TwoDigitApostrophe, NoDate }; + enum HourFormat { Hour_24, Hour_12, Hour_24_FourDigit }; + enum RepaintMode { No, Medium, Always }; + + KDGanttView( QWidget* parent = 0, const char* name = 0 ); + ~KDGanttView(); + + virtual void show(); + virtual bool close ( bool alsoDelete ); + void setRepaintMode( RepaintMode mode ); + void setUpdateEnabled( bool enable); + bool getUpdateEnabled( )const; + + void setGanttMaximumWidth( int w ); + int ganttMaximumWidth() const; + void setShowLegend( bool show ); + bool showLegend() const; + void setLegendIsDockwindow( bool dock ); + bool legendIsDockwindow( ) const; + QDockWindow* legendDockwindow( ) const; + void setShowListView( bool show ); + bool showListView() const; + void setEditorEnabled( bool enable ); + bool editorEnabled() const; + void setListViewWidth( int ); + int listViewWidth(); + void setEditable( bool editable ); + bool editable() const; + void setCalendarMode( bool mode ); + bool calendarMode() const; + void setDisplaySubitemsAsGroup( bool show ); + bool displaySubitemsAsGroup() const; + void setDisplayEmptyTasksAsLine( bool show ); + bool displayEmptyTasksAsLine() const; + + void setHorBackgroundLines( int count = 2, + QBrush brush = + QBrush( QColor ( 200,200,200 ), + Qt::Dense6Pattern )); + int horBackgroundLines( QBrush& brush ); + bool saveProject( QIODevice* ); + bool loadProject( QIODevice* ); + void print( QPrinter* printer = 0 , + bool printListView = true, bool printTimeLine = true, + bool printLegend = false ); + QSize drawContents( QPainter* p = 0, + bool drawListView = true, bool drawTimeLine = true, + bool drawLegend = false ); + void setZoomFactor( double factor, bool absolute ); + double zoomFactor() const; + void zoomToFit(); + void ensureVisible( KDGanttViewItem* ); + void center( KDGanttViewItem* ); + void centerTimeline( const QDateTime& center ); + void centerTimelineAfterShow( const QDateTime& center ); + void setTimelineToStart(); + void setTimelineToEnd(); + void addTicksLeft( int num = 1 ); + void addTicksRight( int num = 1 ); + void setShowTaskLinks( bool show ); + bool showTaskLinks() const; + + void setFont(const QFont& f); + void setShowHeaderPopupMenu( bool show = true, + bool showZoom = true, + bool showScale = true, + bool showTime = true, + bool showYear = true, + bool showGrid = true, + bool showPrint = false); + bool showHeaderPopupMenu() const; + void setShowTimeTablePopupMenu( bool ); + bool showTimeTablePopupMenu() const; + void setShapes( KDGanttViewItem::Type type, + KDGanttViewItem::Shape start, + KDGanttViewItem::Shape middle, + KDGanttViewItem::Shape end, + bool overwriteExisting = true ); + bool shapes( KDGanttViewItem::Type type, + KDGanttViewItem::Shape& start, + KDGanttViewItem::Shape& middle, + KDGanttViewItem::Shape& end ) const; + void setColors( KDGanttViewItem::Type type, + const QColor& start, const QColor& middle, + const QColor& end, + bool overwriteExisting = true ); + bool colors( KDGanttViewItem::Type type, + QColor& start, QColor& middle, QColor& end ) const; + void setDefaultColor( KDGanttViewItem::Type type, + const QColor&, + bool overwriteExisting = true ); + QColor defaultColor( KDGanttViewItem::Type type ) const; + void setHighlightColors( KDGanttViewItem::Type type, + const QColor& start, const QColor& middle, + const QColor& end, + bool overwriteExisting = true ); + bool highlightColors( KDGanttViewItem::Type type, + QColor& start, QColor& middle, QColor& end ) const; + void setDefaultHighlightColor( KDGanttViewItem::Type type, + const QColor&, + bool overwriteExisting = true ); + QColor defaultHighlightColor( KDGanttViewItem::Type type ) const; + void setTextColor( const QColor& color ); + QColor textColor() const; + + void setNoInformationBrush( const QBrush& brush ); + QBrush noInformationBrush() const; + + // Link-related stuff + QPtrList taskLinks() const; + QPtrList taskLinkGroups() const; + + // Legend-related stuff + void addLegendItem( KDGanttViewItem::Shape shape, const QColor& shapeColor, const QString& text ); + void clearLegend(); + // Header-related stuff + void setHorizonStart( const QDateTime& start ); + QDateTime horizonStart() const; + void setHorizonEnd( const QDateTime& start ); + QDateTime horizonEnd() const; + void setScale( Scale ); + Scale scale() const; + void setMaximumScale( Scale ); + Scale maximumScale() const; + void setMinimumScale( Scale ); + Scale minimumScale() const; + void setAutoScaleMinorTickCount( int count ); + int autoScaleMinorTickCount() const; + void setMajorScaleCount( int count ); + int majorScaleCount() const; + void setMinorScaleCount( int count ); + int minorScaleCount() const; + void setMinimumColumnWidth( int width ); + int minimumColumnWidth() const; + void setYearFormat( YearFormat format ); + YearFormat yearFormat() const; + void setHourFormat( HourFormat format ); + HourFormat hourFormat() const; + void setShowMajorTicks( bool ); + bool showMajorTicks() const; + void setShowMinorTicks( bool ); + bool showMinorTicks() const; + void setColumnBackgroundColor( const QDateTime& column, + const QColor& color, + Scale mini = KDGanttView::Minute , + Scale maxi = KDGanttView::Month); +#if 0 + // This API has been replaced with KDIntervalColorRectangle and addIntervalBackgroundColor + void setIntervalBackgroundColor( const QDateTime& start, + const QDateTime& end, + const QColor& color, + Scale mini = KDGanttView::Minute , + Scale maxi = KDGanttView::Month); + bool changeBackgroundInterval( const QDateTime& oldstart, + const QDateTime& oldend, + const QDateTime& newstart, + const QDateTime& newend ); + bool deleteBackgroundInterval( const QDateTime& start, + const QDateTime& end ); +#endif + void addIntervalBackgroundColor( KDIntervalColorRectangle* newItem ); + void clearBackgroundColor(); + QColor columnBackgroundColor( const QDateTime& column ) const; + void setWeekendBackgroundColor( const QColor& color ); + QColor weekendBackgroundColor() const; + void setWeekdayBackgroundColor( const QColor& color, int weekday ); + QColor weekdayBackgroundColor(int weekday) const; + + + void setPaletteBackgroundColor(const QColor& col); + void setGvBackgroundColor ( const QColor & ); + void setLvBackgroundColor ( const QColor & ); + void setTimeHeaderBackgroundColor ( const QColor & ); + void setLegendHeaderBackgroundColor ( const QColor & ); + QColor gvBackgroundColor () const ; + QColor lvBackgroundColor () const ; + QColor timeHeaderBackgroundColor () const ; + QColor legendHeaderBackgroundColor () const ; + void addUserdefinedLegendHeaderWidget( QWidget * w ); + + void setWeekendDays( int start, int end ); + void weekendDays( int& start, int& end ) const; + + static QPixmap getPixmap( KDGanttViewItem::Shape shape, const QColor& shapeColor,const QColor& backgroundColor, int itemSize); + + void setHeaderVisible( bool ); + bool headerVisible() const; + + void setShowLegendButton( bool show ); + bool showLegendButton() const; + + // Pass-through methods from QListView + virtual int addColumn( const QString& label, int width = -1 ); + virtual int addColumn( const QIconSet& iconset, const QString& label, + int width = -1 ); + virtual void removeColumn( int index ); + KDGanttViewItem* selectedItem() const; + void setSelected( KDGanttViewItem*, bool ); + KDGanttViewItem* firstChild() const; + KDGanttViewItem* lastItem() const; + int childCount() const; + void clear(); + + void setDragEnabled( bool b ); + void setDropEnabled( bool b ); + void setDragDropEnabled( bool b ); + bool dragEnabled() const; + bool dropEnabled() const; + bool isDragEnabled() const; + bool isDropEnabled() const; + + virtual bool lvDropEvent ( QDropEvent *e, KDGanttViewItem*, KDGanttViewItem*); + virtual void lvStartDrag (KDGanttViewItem*); + virtual bool lvDragMoveEvent (QDragMoveEvent * e,KDGanttViewItem*, KDGanttViewItem*); + virtual void lvDragEnterEvent (QDragEnterEvent * e ); + virtual QSize sizeHint() const; + KDGanttViewItem* getItemByName( const QString& name ) const; + QDateTime getDateTimeForCoordX(int coordX, bool global = true ) const; + KDGanttViewItem* getItemByListViewPos( const QPoint& pos ) const; + KDGanttViewItem* getItemByGanttViewPos( const QPoint& pos ) const; + KDGanttViewItem* getItemAt( const QPoint& pos , bool global = true ) const; + + // setting the vertical scrollbars of the listview and the timetable + // default values: always off for the listview, always on for the timetable + void setLvVScrollBarMode( QScrollView::ScrollBarMode ); + void setGvVScrollBarMode( QScrollView::ScrollBarMode ); + + void setLinkItemsEnabled(bool on); + bool isLinkItemsEnabled() const; + + KDTimeTableWidget * timeTableWidget() { return myTimeTable; } + KDTimeHeaderWidget * timeHeaderWidget() { return myTimeHeader; } + + void setFixedHorizon( bool f ) { mFixedHorizon = f; } + +public slots: + void editItem( KDGanttViewItem* ); + void zoomToSelection( const QDateTime& start, const QDateTime& end); + +signals: + void timeIntervallSelected( const QDateTime& start, const QDateTime& end); + void timeIntervalSelected( const QDateTime& start, const QDateTime& end); + void rescaling( KDGanttView::Scale ); + void intervalColorRectangleMoved( const QDateTime& start, const QDateTime& end ); + + // the following signals are emitted if an item is clicked in the + // listview (inclusive) or in the ganttview + void itemLeftClicked( KDGanttViewItem* ); + void itemMidClicked( KDGanttViewItem* ); + void itemRightClicked( KDGanttViewItem* ); + void itemDoubleClicked( KDGanttViewItem* ); + + // The following signal is emitted when two items shall be linked + void linkItems( KDGanttViewItem* from, KDGanttViewItem* to, int linkType ); + + // the following signals are emitted if an item is clicked in the + // listview (exlusive) or in the ganttview + // gv... means item in ganttview clicked + + void gvCurrentChanged( KDGanttViewItem* ); + void gvItemLeftClicked( KDGanttViewItem* ); + void gvItemMidClicked( KDGanttViewItem* ); + void gvItemRightClicked( KDGanttViewItem* ); + // the point is the global position!! + void gvMouseButtonClicked ( int button, KDGanttViewItem* item, const QPoint & pos); + void gvItemDoubleClicked( KDGanttViewItem* ); + // the point is the global position!! + void gvContextMenuRequested ( KDGanttViewItem * item, const QPoint & pos ); + void gvItemMoved( KDGanttViewItem* ); + + // lv... means item in listview clicked + void lvCurrentChanged( KDGanttViewItem* ); + void lvItemRenamed( KDGanttViewItem* , int col, const QString & text ); + void lvMouseButtonPressed( int button, KDGanttViewItem * item, const QPoint & pos, int c ); + void lvItemLeftClicked( KDGanttViewItem* ); + void lvItemMidClicked( KDGanttViewItem* ); + void lvItemRightClicked( KDGanttViewItem* ); + void lvContextMenuRequested ( KDGanttViewItem * item, const QPoint & pos, int col ); + void lvMouseButtonClicked ( int button, KDGanttViewItem* item, const QPoint & pos, int c ); + void lvItemDoubleClicked( KDGanttViewItem* ); + void lvSelectionChanged( KDGanttViewItem* ); + + void itemConfigured( KDGanttViewItem* ); + + void taskLinkLeftClicked( KDGanttViewTaskLink* ); + void taskLinkMidClicked( KDGanttViewTaskLink* ); + void taskLinkRightClicked( KDGanttViewTaskLink* ); + void taskLinkDoubleClicked( KDGanttViewTaskLink* ); + + void dateTimeDoubleClicked (const QDateTime& ); + + void dropped ( QDropEvent * e, KDGanttViewItem* droppedItem, KDGanttViewItem* itemBelowMouse); +private slots: + void forceRepaint( int val = 0 ); + void slotSelectionChanged( QListViewItem* item ); + void slotCurrentChanged ( QListViewItem * item ); + void slotItemRenamed ( QListViewItem * item, int col, const QString & text ); + void slotMouseButtonPressed ( int button, QListViewItem * item, const QPoint & pos, int c ); + void slotmouseButtonClicked ( int button, QListViewItem * item, const QPoint & pos, int c ); + void slotcontextMenuRequested ( QListViewItem * item, const QPoint & pos, int col ); + void slotHeaderSizeChanged(); + void addTickRight(); + void addTickLeft(); + void enableAdding( int ); + void slot_lvDropped(QDropEvent* e, KDGanttViewItem* droppedItem, KDGanttViewItem* itemBelowMouse ); +private: + struct legendItem { + KDGanttViewItem::Shape shape; + QColor color; + QString text; + }; + bool loadXML( const QDomDocument& doc ); + QDomDocument saveXML( bool withPI = true ) const; + + void emptySpaceDoubleClicked( QMouseEvent* e ); + + static QString scaleToString( Scale scale ); + static QString yearFormatToString( YearFormat format ); + static QString hourFormatToString( HourFormat format ); + static Scale stringToScale( const QString& string ); + static YearFormat stringToYearFormat( const QString& string ); + static HourFormat stringToHourFormat( const QString& string ); + + // PENDING(lutz) Review these + friend class KDGanttCanvasView; + friend class KDGanttViewEventItem; + friend class KDGanttViewItem; + friend class KDGanttViewTaskItem; + friend class KDGanttViewSummaryItem; + friend class KDGanttViewTaskLink; + friend class KDGanttViewCalendarItem; + friend class KDTimeTableWidget; + friend class KDTimeHeaderWidget; + friend class KDListView; + friend class KDGanttViewTaskLinkGroup; + friend class KDLegendWidget; + + KDListView * myListView; + KDGanttCanvasView *myCanvasView; + KDTimeHeaderWidget * myTimeHeader; + KDTimeTableWidget * myTimeTable; + KDLegendWidget * myLegend; + itemAttributeDialog* myItemAttributeDialog; + QVBox * leftWidget, * rightWidget; + QHBox * spacerLeft; + QScrollView* myTimeHeaderScroll; + QHBox* myTimeHeaderContainer ; + QWidget* timeHeaderSpacerWidget; + QWidget *spacerRight; + + bool listViewIsVisible; + bool chartIsEditable; + bool editorIsEnabled; + bool _displaySubitemsAsGroup; + bool _displayEmptyTasksAsLine; + bool _showLegendButton; + bool _showHeader; + bool _enableAdding; + bool fCenterTimeLineAfterShow; + bool fDragEnabled; + bool fDropEnabled; + bool closingBlocked; + QDateTime dtCenterTimeLineAfterShow; + KDGanttViewItem::Shape myDefaultShape [9]; + QColor myColor[9],myColorHL[9]; + bool undefinedShape[3],undefinedColor[3],undefinedColorHL[3]; + QColor myTextColor; + QColor myDefaultColor[3],myDefaultColorHL[3]; + QPtrList myTaskLinkGroupList; + QPtrList *myLegendItems; + void addTaskLinkGroup(KDGanttViewTaskLinkGroup*); + void removeTaskLinkGroup(KDGanttViewTaskLinkGroup*); + int getIndex( KDGanttViewItem::Type ) const; + void notifyEditdialog( KDGanttViewItem * ); + void initDefaults(); + KDGanttViewItem* myCurrentItem; + KDGanttMinimizeSplitter *mySplitter; + bool mFixedHorizon; +protected: + virtual QDragObject * dragObject (); + virtual void startDrag (); +}; + + + +#endif diff --git a/kdgantt/KDGanttViewEventItem.cpp b/kdgantt/KDGanttViewEventItem.cpp new file mode 100644 index 00000000..aa6e707d --- /dev/null +++ b/kdgantt/KDGanttViewEventItem.cpp @@ -0,0 +1,306 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewEventItem.h" +#include "KDGanttViewSubwidgets.h" +#include "itemAttributeDialog.h" + +/*! + \class KDGanttViewEventItem KDGanttViewEventItem.h + An event item in a Gantt chart. + + This class represents event items in Gantt charts. +*/ + +/*! + Constructs an empty Gantt item of type event. + + \param view the Gantt view to insert this item into + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewEventItem::KDGanttViewEventItem( KDGanttView* view, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Event, view, lvtext, name ) +{ + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param parent a parent item under which this one goes + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewEventItem::KDGanttViewEventItem( KDGanttViewItem* parent, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Event, parent, lvtext, name ) +{ + initItem(); + +} + + +/*! + Constructs an empty Gantt item of type event. + + \param view the Gantt view to insert this item into + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewEventItem::KDGanttViewEventItem( KDGanttView* view, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Event, view, after, lvtext, name ) +{ + + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param parent a parent item under which this one goes + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewEventItem::KDGanttViewEventItem( KDGanttViewItem* parent, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Event, parent, after, lvtext, name ) +{ + + initItem(); +} + + +/*! + The destructor. Nothing done here. +*/ +KDGanttViewEventItem::~KDGanttViewEventItem() +{ + + +} +/*! + Specifies the start time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + If the start time is less than the lead time, + the lead time is set to this start time automatically. + + \param start the start time + \sa startTime() +*/ +void KDGanttViewEventItem::setStartTime( const QDateTime& start ) +{ + if (! start.isValid() ) { + qDebug("KDGanttViewEventItem::setStartTime():Invalid parameter-no time set"); + return; + } + myStartTime = start; + myEndTime = start; + if ( myStartTime < leadTime() ) + setLeadTime( myStartTime ); + else { + updateCanvasItems(); + } + +} + + +/*! + Specifies whether the event item should be shown with a lead time + line, and if yes, when the lead time starts. + If the start time is less than the lead time, + the start time is set to this lead time automatically. + + \param leadTimeStart the start time of the lead time; pass an + invalid QDateTime object in order to turn the lead time off. + \sa leadTime() +*/ + +void KDGanttViewEventItem::setLeadTime( const QDateTime& leadTimeStart ) +{ + if (!myLeadTime) myLeadTime = new QDateTime; + *myLeadTime = leadTimeStart; + if ( startTime() < leadTime() ) + setStartTime( leadTimeStart ); + else { + updateCanvasItems(); + } + +} + + +/*! + Returns whether the event item is shown with a lead time line and if + yes, when the lead time starts. + + \return if the event item is shown with a lead time line, returns + the QDateTime object representing the start of the lead time, + otherwise returns an invalid QDateTime object + \sa setLeadTime() +*/ +QDateTime KDGanttViewEventItem::leadTime() const +{ + if(myLeadTime) + return *myLeadTime; + return myStartTime; +} + + +void KDGanttViewEventItem::hideMe() +{ + startShape->hide(); + startShapeBack->hide(); + startLine->hide(); + startLineBack->hide(); + textCanvas->hide(); + floatStartShape->hide(); + floatEndShape->hide(); +} + + +void KDGanttViewEventItem::showItem(bool show, int coordY) +{ + isVisibleInGanttView = show; + invalidateHeight () ; + if (!show) { + hideMe(); + return; + } + float prio = ((float) ( priority() - 100 )) / 100.0; + startShape->setZ( prio + 0.0055 ); + startShapeBack->setZ( prio + 0.003 ); + startLine->setZ( prio + 0.0015 ); + floatStartShape->setZ(prio + 0.004); + floatStartShape->hide(); + floatEndShape->setZ(prio + 0.004); + floatEndShape->hide(); + textCanvas->setZ( prio + 0.006 ); + startLineBack->setZ( prio ); + + if ( displaySubitemsAsGroup() && firstChild() ) { + myStartTime = myChildStartTime(); + myEndTime = myChildEndTime(); + } + int startX, endX, allY; + if ( coordY ) + allY = coordY; + else + allY = getCoordY(); + startX = myGanttView->myTimeHeader->getCoordX(myStartTime); + if (myLeadTime) { + endX = myGanttView->myTimeHeader->getCoordX(*myLeadTime); + startLine->setPoints(startX,allY,endX,allY); + startLine->show(); + startLineBack->setPoints(startX+1,allY,endX-1,allY); + startLineBack->show(); + } + else { + startLine->hide(); + startLineBack->hide(); + } + startShape->move(startX,allY); + startShape->show(); + startShapeBack->move(startX,allY); + startShapeBack->show(); + if (myFloatStartTime.isValid()) { + KDCanvasRectangle* floatStartTemp = (KDCanvasRectangle*) floatStartShape; + int floatStartX = myGanttView->myTimeHeader->getCoordX(myFloatStartTime); + int hei = startShape->boundingRect().height(); + // FIXME: Configurable colors + QBrush b(startShape->brush().color(), Dense4Pattern); + floatStartTemp->setBrush(b); + floatStartTemp->setPen(QPen(gray)); + if (floatStartX < startX) { + floatStartTemp->setSize(startX - floatStartX, hei/2); + floatStartTemp->move(floatStartX, allY-hei/4); + } else { + floatStartTemp->setSize(floatStartX - startX, hei/2); + floatStartTemp->move(startX, allY-hei/4); + } + floatStartShape->show(); + } + if (myFloatEndTime.isValid()) { + KDCanvasRectangle* floatEndTemp = (KDCanvasRectangle*) floatEndShape; + int floatEndX = myGanttView->myTimeHeader->getCoordX(myFloatEndTime); + int hei = startShape->boundingRect().height(); + // FIXME: Configurable colors + QBrush b(startShape->brush().color(), Dense4Pattern); + floatEndTemp->setBrush(b); + floatEndTemp->setPen(QPen(gray)); + if (floatEndX > startX) { + floatEndTemp->setSize(floatEndX - startX, hei/2); + floatEndTemp->move(startX, allY-hei/4); + } else { + floatEndTemp->setSize(startX - floatEndX, hei/2); + floatEndTemp->move(floatEndX, allY-hei/4); + } + floatEndShape->show(); + } + + moveTextCanvas(startX,allY); + textCanvas->show(); + if (textCanvas->text().isEmpty()) + textCanvas->hide(); +} + + +void KDGanttViewEventItem::initItem() +{ + isVisibleInGanttView = false; + myLeadTime = 0; + showItem(true); + myGanttView->myTimeTable->updateMyContent(); + setDragEnabled( myGanttView->dragEnabled() ); + setDropEnabled( myGanttView->dropEnabled() ); +} + + + diff --git a/kdgantt/KDGanttViewEventItem.h b/kdgantt/KDGanttViewEventItem.h new file mode 100644 index 00000000..5cd029ee --- /dev/null +++ b/kdgantt/KDGanttViewEventItem.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2001-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef KDGANTTVIEWEVENTITEM_H +#define KDGANTTVIEWEVENTITEM_H + +#include "KDGanttViewItem.h" + +class KDGanttViewEventItem : public KDGanttViewItem +{ +public: + KDGanttViewEventItem( KDGanttView* view, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewEventItem( KDGanttViewItem* parent, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewEventItem( KDGanttView* view, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewEventItem( KDGanttViewItem* parent, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + virtual ~KDGanttViewEventItem(); + + void setLeadTime( const QDateTime& leadTimeStart ); + void setStartTime( const QDateTime& start ); + QDateTime leadTime() const; + +private: + void showItem( bool show = true, int coordY = 0 ); + QDateTime* myLeadTime; + void initItem(); + void hideMe(); +}; + +#endif diff --git a/kdgantt/KDGanttViewItem.cpp b/kdgantt/KDGanttViewItem.cpp new file mode 100644 index 00000000..16665e5a --- /dev/null +++ b/kdgantt/KDGanttViewItem.cpp @@ -0,0 +1,2571 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewSubwidgets.h" +#include "KDGanttViewTaskItem.h" +#include "KDGanttViewSummaryItem.h" +#include "KDGanttViewEventItem.h" +#include "itemAttributeDialog.h" + +#include "qpainter.h" + +#include "KDGanttXMLTools.h" + + +/*! + \class KDGanttViewItem KDGanttViewItem.h + This class represents an item in a Gantt chart. + + This class is an abstract base class, it cannot be instantiated + directly. Instead, you should create items of one of the + subclasses. This class provides methods common to all Gantt items. + + The initialization of the shapes/colors of the item works as follows: + + Shapes: + When a new item is created, the shapes are set to the default values + for items of the type of this item, defined in the KDGanttView class with + void setShapes( KDGanttViewItem::Type type, + KDGanttViewItem::Shape start, + KDGanttViewItem::Shape middle, + KDGanttViewItem::Shape end ); + If there is no default value defined for this type, + the shapes are set as follows: + For TaskViewItems all three shapes are set to Square. + For SummaryViewItems all three shapes are set to TriangleDown. + For EventViewItems all three shapes are set to Diamond. + + Colors: + When a new item is created, the colors are set to the default values + for items of the type of this item, defined in the KDGanttView class with + void setColors( KDGanttViewItem::Type type, + const QColor& start, + const QColor& middle, + const QColor& end ); + If there is no default value defined for this type, + the colors of the shapes are set to the default color for items of this type, + defined in the KDGanttView class with: + void setDefaultColor( KDGanttViewItem::Type type, const QColor& ); + The initial default color in the KDGanttView class is set to + blue for KDGanttViewItem::Event, + green for KDGanttViewItem::Task, + cyan for KDGanttViewItem::Summary. + + Highlight Colors: + When a new item is created, the highlight colors are set to the default + values for items of the type of this item, + defined in the KDGanttView class with: + void setHighlightColors( KDGanttViewItem::Type type, + const QColor& start, + const QColor& middle, + const QColor& end ); + If there is no default value defined for this type, + the highlight colors of the shapes are set to the default color for + items of this type, defined in the KDGanttView class with: + void setDefaultHighlightColor( KDGanttViewItem::Type type, const QColor& ); + The initial default highlight color in the KDGanttView class is set to red + for all types. + + Start/End time: + When a new item is created, the start time and the end time is set + automatically. The time, which is currently displayed in the middle + of the Gantt View, is set as start/end time. At startup of a newly + created Gantt view, this is the current time. + + The Priority: + The priority is set with \a setPriority(). + The priority determines which items are painted over which other items. + The item with the highest priority is painted on top of all others. + The priority for an item can be between 1 and 199. + A priority less than 100 means that the item is painted below the + grid in the Gantt chart. + For Task items, the default priority is 50, for all other items it is 150. + This feature only makes sense for an item which is a child of another item, + for which \a displaySubitemsAsGroup() property is set to true. + + The Display Mode: + The display mode is set with \a setDisplaySubitemsAsGroup(). + In the normal view mode (set with setDisplaySubitemsAsGroup( false ); ), + an item is displayed in the same manner, when its child items are + shown or not. + In the other mode (set with setDisplaySubitemsAsGroup( true ); ), + called "calendar mode", the item is displayed as follows: + If the item has no children, it is displayed as usual. + If the item is opened (i.e., its children are displayed), the + start/end time of this item is computed automatically according to + the earliest start time/latest end time of its children. The item + and its children are displayed as usual. + If the item is closed (i.e., its children are hidden in the left + list view), the item itself is hidden, and its children are displayed + on the timeline of this item instead. To control the painting of + overlapping children, call \a setPriority() for the childs. + + Blocking of user interaction to open item: + If you want to block users to open items used as parents of calendar items, + call \a KDGanttView::setCalendarMode( true ); + + Example 1, Color: + If you create an instance of a KDGanttView class and add a SummaryViewItem + without setting any color/shape values, you get an item with three shapes + of the form TriangleDown in the color magenta. If the item is highlighted, + the color will change to the highlight color red. + + Example 2, Calender View: + To use a Gantt view as a calendar view, call + \a KDGanttView::setCalendarMode( true ); + \a KDGanttView::setDisplaySubitemsAsGroup( true ); + Insert root items in the Gantt view. + Insert items as children of these root item in the Gantt view. + You may use any item type as parent and child; there are no limitations. + It is, however, recommended to use KDGanttViewTaskItems + Actually, you may add child items to the children themselves. + Such a child behaves then like a parent. + Now set the start/end time of the children to specify a time + interval for these items. +*/ + + +QDict KDGanttViewItem::sItemDict; + +/*! + Constructs an empty Gantt item. + + \param type the type of the item to insert + \param view the Gantt view to insert this item into + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewItem::KDGanttViewItem( Type type, KDGanttView* view, + const QString& lvtext, + const QString& name ) : + QListViewItem(view->myListView,lvtext) +{ + initColorAndShapes(type); + generateAndInsertName( name ); +} + + +/*! + Constructs an empty Gantt item. + + \param type the type of the item to insert + \param parentItem a parent item under which this one goes + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ + +KDGanttViewItem::KDGanttViewItem( Type type, KDGanttViewItem* parentItem, + const QString& lvtext, + const QString& name ) : + QListViewItem(parentItem,lvtext) +{ + initColorAndShapes(type); + generateAndInsertName( name ); +} + + +/*! + Constructs an empty Gantt item. + + \param type the type of the item to insert + \param view the Gantt view to insert this item into + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ + +KDGanttViewItem::KDGanttViewItem( Type type, KDGanttView* view, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + QListViewItem(view->myListView,after, lvtext) +{ + initColorAndShapes(type); + generateAndInsertName( name ); +} + + +/*! + Constructs an empty Gantt item. + + \param type the type of the item to insert + \param parentItem a parent item under which this one goes + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ + +KDGanttViewItem::KDGanttViewItem( Type type, KDGanttViewItem* parentItem, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + QListViewItem( parentItem, after, lvtext ) +{ + initColorAndShapes(type); + generateAndInsertName( name ); +} + + +/*! + Destroys the object and frees any allocated resources. +*/ +KDGanttViewItem::~KDGanttViewItem() +{ + myGanttView->notifyEditdialog( this ); + if ( startLine ) delete startLine; + if ( endLine ) delete endLine ; + if ( startLineBack ) delete startLineBack ; + if ( endLineBack ) delete endLineBack ; + if ( actualEnd ) delete actualEnd ; + if ( textCanvas ) delete textCanvas ; + if ( startShape ) delete startShape ; + if ( midShape ) delete midShape ; + if ( endShape ) delete endShape ; + if ( startShapeBack ) delete startShapeBack ; + if ( midShapeBack ) delete midShapeBack ; + if ( endShapeBack ) delete endShapeBack ; + if ( progressShape ) delete progressShape ; + if ( floatStartShape ) delete floatStartShape ; + if ( floatEndShape ) delete floatEndShape ; + myGanttView->myTimeTable->removeItemFromTasklinks( this ); + myGanttView->myCanvasView->resetCutPaste( this ); + if ( listView() ) { + if ( isOpen() ) + setOpen( false ); + if ( parent() ) + parent()->takeItem( this ); + else + myGanttView->myListView->takeItem( this ); + myGanttView->myTimeTable->updateMyContent(); + } + // myGanttView->myTimeTable->removeItemFromTasklinks( this ); + // myGanttView->myCanvasView->resetCutPaste( this ); +} + + +/*! + Generates a unique name if necessary and inserts it into the item + dictionary. +*/ +void KDGanttViewItem::generateAndInsertName( const QString& name ) +{ + // First check if we already had a name. This can be the case if + // the item was reconstructed from an XML file. + if( !_name.isEmpty() ) + // We had a name, remove it + sItemDict.remove( _name ); + + QString newName; + if ( name.isEmpty() || sItemDict.find( name ) ) { + // create unique name + newName.sprintf( "%p", (void* )this ); + while( sItemDict.find( newName ) ) { + newName += "_0"; + } + } else { + newName = name; + } + sItemDict.insert( newName, this ); + _name = newName; +} + + +/*! + Returns the unique name that can identify the item. + + \return the unique item name +*/ +QString KDGanttViewItem::name() const +{ + return _name; +} + + +/*! + Returns the item with the specified name. + + \param name the name to search for + \return the item with the specified name; 0 if no group + with that name exists +*/ + +KDGanttViewItem* KDGanttViewItem::find( const QString& name ) +{ + if (name.isEmpty()) // avoid error msg from QDict + return 0; + return sItemDict.find( name ); +} + + + +/*! + Returns the type of the item. + This may be Event, Task, Summary. + + \return the type of the item +*/ + +KDGanttViewItem::Type KDGanttViewItem::type() const +{ + + return myType; +} + + +/*! + Specifies whether this item is enabled. If disabled, the item stays in the + Gantt view and the item is shown in gray to show that the item is disabled. + All signals of this item (like itemLeftClicked( this )) are blocked. + If the item displays its subitems (childs) as a group, + (displaySubitemsAsGroup() == true) + all changes apply to all subitems as well. + + \param on pass true to make this item editable + \sa enabled () +*/ +void KDGanttViewItem::setEnabled( bool on ) +{ + _enabled = on; + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setEnabled( on ); + temp = temp->nextSibling(); + } + QListViewItem::setEnabled( on ); + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + +/*! + Returns whether this item is enabled. + + \return true if this item is enabled, false otherwise + \sa setEnabled() +*/ +bool KDGanttViewItem::enabled () const +{ + return _enabled; +} + + +// ********************************* +/*! + Specifies whether this item is visible. + + \param on pass true to make this item visible + \sa itemVisible () +*/ +void KDGanttViewItem::setItemVisible( bool on ) +{ + if ( on ) { + resetSubitemVisibility(); + } else + setVisible( false ); + //updateCanvasItems(); + myGanttView->myTimeTable->updateMyContent(); +} + + +/*! + Returns whether this item is visible. + + \return true if this item is visible, false otherwise + \sa setItemVisible() +*/ +bool KDGanttViewItem::itemVisible () const +{ + return QListViewItem::isVisible(); +} + + +// ************************************* + +/*! + Specifies whether this item is editable. The whole Gantt view needs + to be editable as well for this to have any effect. + + \param editable pass true to make this item editable + \sa editable(), KDGanttView::setEditable(), KDGanttView::editable() +*/ +void KDGanttViewItem::setEditable( bool editable ) +{ + isEditable = editable; +} + + +/*! + Returns whether this item is editable. + + \return true if this item is editable, false otherwise + \sa setEditable(), KDGanttView::setEditable(), KDGanttView::editable() +*/ + +bool KDGanttViewItem::editable() const +{ + return isEditable; +} + + +/*! + Specifies whether this item shows hidden subitems on its timeline. + Useful to get a so called "calendar view" with many items in one row. + When \a displaySubitemsAsGroup() is set to true, this item has a normal view, + when it is expanded. If it is not expanded (and has at least one child), + the item itself is hidden, and all children are displayed instead. + To manage the painting priority of the childs (if overlapping), + you may set \a priority() of these items. + + \param show pass true to make this item displaying hidden subitems + \sa editable(), KDGanttView::setEditable(), KDGanttView::editable(), setPriority() +*/ +void KDGanttViewItem::setDisplaySubitemsAsGroup( bool show ) +{ + if ( !show && _displaySubitemsAsGroup) + isVisibleInGanttView = true; + _displaySubitemsAsGroup = show; + if ( parent() ) + if ( parent()->isOpen() ) + parent()->setOpen( true ); + if ( isOpen() ) + setOpen( true ); + updateCanvasItems(); +} + + +/*! + Returns whether this item displays hidden subitems. + Initial set to false. + + \return true if this item displays hidden subitems, false otherwise + \sa setDisplaySubitemsAsGroup() +*/ +bool KDGanttViewItem::displaySubitemsAsGroup() const +{ + return _displaySubitemsAsGroup; +} + + +/*! + Specifies the priority of this item. + Valid values are between 1 and 199. + A priority less than 100 means that the item is painted in the + Gantt chart below the grid. A priority more than 100 means + that the item is painted in the Gantt chart over the grid. + For a value of 100, the behavior is unspecified. + An item with a higher priority is painted over an item with a lower + priority in the Gantt chart. The painting order of items with the + same priority is unspecified. + For Calendar items, the default priority is 50, for all other items + it is 150. + This feature makes only sense for an item which is a child of + another item, which \a displaySubitemsAsGroup() property is set to + true. + + \param prio the new priority of this item. + \sa priority(), displaySubitemsAsGroup() +*/ +void KDGanttViewItem::setPriority( int prio ) +{ + if ( prio < 1 ) + prio = 1; + if (prio > 199 ) + prio = 199; + _priority = prio; + updateCanvasItems(); +} + + +/*! + Returns the priority of this item. + \return the priority of this item + \sa setDisplaySubitemsAsGroup() +*/ +int KDGanttViewItem::priority() +{ + return _priority; +} + + +/*! + Specifies the start time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + Reimplemented in the subclasses. + + \param start the start time + \sa startTime(), setEndTime(), endTime() +*/ +void KDGanttViewItem::setStartTime( const QDateTime& ) +{ +} + + +/*! + Returns the start time of this item. + + \return the start time of this item + \sa setStartTime(), setEndTime(), endTime() +*/ +QDateTime KDGanttViewItem::startTime() const +{ + return myStartTime; +} + + +/*! + Specifies the end time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + Reimplemented in the subclasses + + \param end the end time + \sa endTime(), setStartTime(), startTime() +*/ +void KDGanttViewItem::setEndTime( const QDateTime& end ) +{ + switch( type() ) { + case Event: + qDebug( "KDGantt:Event Item has no end time" ); + break; + case Summary: + ((KDGanttViewSummaryItem*)this)->setEndTime( end ); + break; + case Task: + qDebug( "KDGantt:Task Item has no end time" ); + break; + default: + qDebug( "Unknown type in KDGanttViewItem::typeToString()" ); + } +} + + +/*! + Returns the end time of this item. + + \return the end time of this item + \sa setEndTime(), setStartTime(), startTime() +*/ +QDateTime KDGanttViewItem::endTime() const +{ + return myEndTime; +} + + +/*! + Sets the text to be shown in this item in the Gantt view. + For a KDGanttViewTaskItem witht displaySubitemsAsGroup() == true, + the text is shown in the item itself and + the text is truncated automatically, if it does not fit in the item. + For all other item types, the text is shown to the right of the item. + + \param text the text to be shown + \sa text(), setTextColor(), textColor(), setListViewText(), + listViewText() +*/ +void KDGanttViewItem::setText( const QString& text ) +{ + textCanvas->setText(text); + textCanvasText = text; + updateCanvasItems(); +} + + +/*! + Returns the text to be shown in this item in the Gantt view. + + \return the text to be shown in this item + \sa setText(), setTextColor(), textColor(), setListViewText(), + listViewText() +*/ +QString KDGanttViewItem::text() const +{ + return textCanvasText; +} + + +/*! + \deprecated Use setListViewTest( int, const QString& ) instead +*/ +void KDGanttViewItem::setListViewText( const QString& text, int column ) +{ + QListViewItem::setText( column, text ); +} + + +/*! + Sets the text to be shown in this item in the list view. + + \param column the column in which the text will be shown + \param text the text to be shown + \sa text(), setTextColor(), textColor(), setText(), listViewText() +*/ +void KDGanttViewItem::setListViewText( int column, const QString& text ) +{ + QListViewItem::setText( column, text ); +} + + +/*! + Returns the text to be shown in this item in the list view. + + \param column the column in which the text will be shown + \return the text to be shown in this item + \sa setText(), setTextColor(), textColor(), text(), + setListViewText() +*/ +QString KDGanttViewItem::listViewText( int column ) const +{ + return QListViewItem::text( column ); +} + + +/*! + Sets the font to be used for the text in this item. + + \param font the font to be shown + \sa font() +*/ +void KDGanttViewItem::setFont( const QFont& font ) +{ + textCanvas->setFont(font); + updateCanvasItems(); +} + + +/*! + Returns the font used for the text in this item. + + \return the font used for the text in this item + \sa setFont() +*/ +QFont KDGanttViewItem::font() const +{ + return textCanvas->font(); +} + + +/*! + Sets the text to show in a tooltip for this item. + + \param text the tooltip text + \sa tooltipText() +*/ +void KDGanttViewItem::setTooltipText( const QString& text ) +{ + myToolTipText = text; +} + + +/*! + Returns the tooltip text of this item + + \return the tooltip text + \sa setTooltipText() +*/ +QString KDGanttViewItem::tooltipText() const +{ + + return myToolTipText; +} + + +/*! + Sets the text to show in a What's This window for this item. + + \param text the what's this text + \sa whatsThisText() +*/ +void KDGanttViewItem::setWhatsThisText( const QString& text ) +{ + myWhatsThisText = text; +} + + +/*! + Returns the what's this text of this item + + \return the what's this text + \sa setWhatsThisText() + +*/ +QString KDGanttViewItem::whatsThisText() const +{ + return myWhatsThisText; +} + + +/*! + Specifies whether this item should be shown highlighted. The user + can also highlight items with the mouse. + If the item displays its subitems (children) as a group + (displaySubitemsAsGroup() == true), + all changes apply to all subitems as well. + + \param highlight true in order to highlight, false in order to turn + highlighting off for this item + \sa highlight() +*/ +void KDGanttViewItem::setHighlight( bool highlight ) +{ + isHighlighted = highlight; + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setHighlight( highlight ); + temp = temp->nextSibling(); + } + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + +/*! + Returns whether this item is highlighted, either programmatically + with setHighlight() or by the user with the mouse. + + \return true if the item is highlighted + \sa setHighlight() +*/ +bool KDGanttViewItem::highlight() const +{ + return isHighlighted; +} + + +/*! + Specifies the shapes to be used for this item. + + It is advisable not to use this method, but rather set the shapes + for all items of a type with KDGanttView::setShapes() in order to + get a uniform Gantt view. + + \param start the start shape + \param middle the middle shape + \param end the end shape + \sa shapes(), setColors(), colors() +*/ +void KDGanttViewItem::setShapes( Shape start, Shape middle, Shape end ) +{ + + myStartShape = start; + myMiddleShape= middle; + myEndShape= end; + createShape(startShape,startShapeBack,start); + createShape(midShape,midShapeBack,middle); + midShape->setZ( 4 ); + createShape(endShape,endShapeBack,end); + updateCanvasItems(); +} + + +/*! + Creates shapes of the specified type \a shape. + The background shape color is set to black and the background shape + is slightly bit bigger than the foreground shape to have a black border + around the foreground shape. + + \param itemShape the foreground shape + \param middle itemShapeBack the background shape + \param shape the type of the shape + (may be TriangleDown, TriangleUp, Diamond, Square, Circle) + \sa shapes(), setColors(), colors() +*/ +void KDGanttViewItem::createShape( KDCanvasPolygonItem* &itemShape, + KDCanvasPolygonItem* &itemShapeBack, + Shape shape ) +{ + if ( itemShape && type() == Task ) + return; + if (itemShape) delete itemShape; + if (itemShapeBack) delete itemShapeBack; + + QCanvasPolygonalItem * item; + QCanvasPolygonalItem * itemBack; + int size = myItemSize+2; + int hei = (myItemSize/3)/2; + switch (shape) { + case TriangleDown: + { + item = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + QPointArray arr = QPointArray(3); + arr.setPoint(0,-size/2,-hei); + arr.setPoint(1,size/2,-hei); + arr.setPoint(2,0,((size/2)-hei)); + ((QCanvasPolygon*)item)->setPoints(arr); + size += 4;hei +=1; + itemBack = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + arr.setPoint(0,-size/2,-hei); + arr.setPoint(1,size/2,-hei); + arr.setPoint(2,0,((size/2)-hei)); + ((QCanvasPolygon*)itemBack)->setPoints(arr); + + break; + } + case TriangleUp: + { + // I really do not know why, but we get only an TriangleUp-icon + // of the same size as a TriangleDown-icon, if we increment the size by 2 + size+=2; + item = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + QPointArray arr = QPointArray(3); + arr.setPoint(0,-size/2,hei); + arr.setPoint(1,size/2,hei); + arr.setPoint(2,0,(-size/2)+hei); + ((QCanvasPolygon*)item)->setPoints(arr); + size += 4;hei +=1; + itemBack = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + arr.setPoint(0,-size/2,hei); + arr.setPoint(1,size/2,hei); + arr.setPoint(2,0,(-size/2)+hei); + ((QCanvasPolygon*)itemBack)->setPoints(arr); + + break; + } + + case Diamond: + { + item = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + QPointArray arr = QPointArray(4); + arr.setPoint(0,0,-size/2); + arr.setPoint(1,size/2,0); + arr.setPoint(2,0,size/2); + arr.setPoint(3,-size/2,0); + ((QCanvasPolygon*)item)->setPoints(arr); + size += 2;hei +=1; + itemBack = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + arr.setPoint(0,0,-size/2); + arr.setPoint(1,size/2,0); + arr.setPoint(2,0,size/2); + arr.setPoint(3,-size/2,0); + ((QCanvasPolygon*)itemBack)->setPoints(arr); + break; + } + + case Square: + { + size -=2; + item = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + QPointArray arr = QPointArray(4); + arr.setPoint(0,-size/2,-size/2); + arr.setPoint(1,size/2,-size/2); + arr.setPoint(2,size/2,size/2); + arr.setPoint(3,-size/2,size/2); + ((QCanvasPolygon*)item)->setPoints(arr); + size += 2;hei +=1; + itemBack = new KDCanvasPolygon(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + arr.setPoint(0,-size/2,-size/2); + arr.setPoint(1,size/2,-size/2); + arr.setPoint(2,size/2,size/2); + arr.setPoint(3,-size/2,size/2); + ((QCanvasPolygon*)itemBack)->setPoints(arr); + break; + } + + case Circle: + { + size -= 2; + item = new KDCanvasEllipse(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + ((KDCanvasEllipse*)item)->setSize(size,size); + size += 2;hei +=1; + itemBack = new KDCanvasEllipse(myGanttView->myTimeTable, this,Type_is_KDGanttViewItem); + ((KDCanvasEllipse*)itemBack)->setSize(size,size); + break; + } + default: + // Uninitialized shape, can e.g. be the case with free-busy + // items which don't have any shapes + return; + } + item->setBrush(Qt::SolidPattern); + item->setZ(5); + itemShape = (KDCanvasPolygonItem*) item; + itemBack->setBrush(Qt::SolidPattern); + itemBack->setZ(3); + itemShapeBack = (KDCanvasPolygonItem*) itemBack; + +} + + +/*! + Returns the shapes used for this item + + \param start returns the start shape + \param middle returns the middle shape + \param end returns the end shape + \sa setShapes(), setColors(), colors() +*/ +void KDGanttViewItem::shapes( Shape& start, Shape& middle, Shape& end ) const +{ + start = myStartShape; + middle = myMiddleShape; + end = myEndShape; +} + + +/*! + Specifies the colors in which to draw the shapes of this item. + + It is advisable not to use this method, but rather set the colors + for all items of a type with KDGanttView::setColors() in order to + get a uniform Gantt view. + + \param start the color for the start shape + \param middle the color for the middle shape + \param end the color for the end shape + \sa colors(), setShapes(), shapes(), setDefaultColor(), defaultColor() +*/ +void KDGanttViewItem::setColors( const QColor& start, const QColor& middle, + const QColor& end ) +{ + + myStartColor=start ; + myMiddleColor= middle; + myEndColor= end; + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setColors( start, middle, end ); + temp = temp->nextSibling(); + } + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + +/*! + Returns the colors used for this item + + \param start returns the start color + \param middle returns the middle color + \param end returns the end color + \sa setColors(), setShapes(), shapes(), setDefaultColor(), defaultColor() +*/ +void KDGanttViewItem::colors( QColor& start, QColor& middle, QColor& end ) const +{ + start = myStartColor ; + middle = myMiddleColor; + end = myEndColor; + +} + + +/*! + Specifies the highlight colors in which to draw the shapes of this item. + + It is advisable not to use this method, but rather set the highlight + colors for all items of a type with + KDGanttView::setHighlightColors() in order to get a uniform Gantt + view. + + If the item displays its subitems (children) as a group, + (displaySubitemsAsGroup() == true) + all changes apply to all subitems as well. + + \param start the highlight color for the start shape + \param middle the highlight color for the middle shape + \param end the highlight color for the end shape + \sa highlightColors(), setShapes(), shapes() +*/ +void KDGanttViewItem::setHighlightColors( const QColor& start, const QColor& middle, const QColor& end ) +{ + myStartColorHL=start ; + myMiddleColorHL= middle; + myEndColorHL= end; + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setHighlightColors( start, middle, end ); + temp = temp->nextSibling(); + } + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + +/*! + Returns the highlight colors used for this item + + \param start returns the start highlight color + \param middle returns the middle highlight color + \param end returns the end highlight color + \sa setHighlightColors(), setShapes(), shapes() +*/ +void KDGanttViewItem::highlightColors( QColor& start, QColor& middle, QColor& end ) const +{ + start = myStartColorHL ; + middle = myMiddleColorHL; + end = myEndColorHL; +} + + +/*! + Specifies the color to be used for the text of this item. + + It is advisable not to use this method, but rather set the text color + for all items with KDGanttView::setTextColor() in order to get a + uniform Gantt view. + If the item displays its subitems (children) as a group, + (displaySubitemsAsGroup() == true) + all changes apply to all subitems as well. + \param color the text color + \sa textColor(), setText(), text() +*/ +void KDGanttViewItem::setTextColor( const QColor& color ) +{ + + myTextColor = color; + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setTextColor(color); + temp = temp->nextSibling(); + } + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + +/*! + Returns the color used for the text of this item. + + \return the text color + \sa setTextColor(), setText(), text() +*/ +QColor KDGanttViewItem::textColor() const +{ + return myTextColor; +} + + +/*! + \enum KDGanttViewItem::Shape + + This enum is used in order to specify the shapes of a Gantt chart + item. +*/ + + +/*! + \enum KDGanttViewItem::Type + + This enum is used in order to return the type of a Gantt chart item. +*/ + + +/*! + Sets the pixmap that is shown in the listview. + + \param column the column in which the pixmap is shown + \param pixmap the pixmap to show + \sa pixmap() +*/ +void KDGanttViewItem::setPixmap( int column, const QPixmap& pixmap ) +{ + QListViewItem::setPixmap( column, pixmap ); +} + +/*! + \deprecated use setPixmap( int, const QPixmap& ) instead +*/ +void KDGanttViewItem::setPixmap( const QPixmap& pixmap ) +{ + QListViewItem::setPixmap( 0, pixmap ); +} + + +/*! + Returns a pixmap that is shown in the listview. + + \param column the column for which to query the pixmap + \return a pointer to the pixmap shown + \sa setPixmap() +*/ +const QPixmap* KDGanttViewItem::pixmap( int column ) const +{ + return QListViewItem::pixmap( column ); +} + + +/*! + Sets the default color that is used for the item if no specific + start, middle, or end colors are set. + + It is advisable not to use this method, but rather set the colors + for all items of a type with KDGanttView::setDefaultColor() in order to + get a uniform Gantt view. + + If the item displays its subitems (children) as a group, + (displaySubitemsAsGroup() == true) + all changes apply to all subitems as well. + + \param color the default color to use + \sa defaultColor(), setColors(), colors() +*/ +void KDGanttViewItem::setDefaultColor( const QColor& color ) +{ + myDefaultColor = color; + + + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setDefaultColor( color ); + temp = temp->nextSibling(); + } + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + + +/*! + Returns the default color that is used for the item if no specific + start, middle, or end colors are set. + + \return color the default color used + \sa setDefaultColor(), setColors(), colors() +*/ +QColor KDGanttViewItem::defaultColor() const +{ + return myDefaultColor; +} + + +/*! + Sets the default highlighting color that is used for the item if no + specific start, middle, or end colors are set. + + It is advisable not to use this method, but rather set the colors + for all items of a type with KDGanttView::setDefaultHighlightColor() + in order to get a uniform Gantt view. + + If the item displays its subitems (children) as a group, + (displaySubitemsAsGroup() == true) + all changes apply to all subitems as well. + + \param color the default highlighting color to use + \sa defaultHighlightColor(), setHighlightColors(), highlightColors() +*/ +void KDGanttViewItem::setDefaultHighlightColor( const QColor& color ) +{ + myDefaultColorHL = color; + if ( displaySubitemsAsGroup() ) { + myGanttView->myTimeTable->inc_blockUpdating(); + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + while (temp != 0) { + temp->setDefaultHighlightColor( color ); + temp = temp->nextSibling(); + } + myGanttView->myTimeTable->dec_blockUpdating(); + } + updateCanvasItems(); +} + + +/*! + Returns the default highlighting color that is used for the item if + no specific start, middle, or end colors are set. + + \return color the default highlighting color used + \sa setDefaultHighlightColor(), setHighlightColors(), highlightColors() +*/ +QColor KDGanttViewItem::defaultHighlightColor() const +{ + return myDefaultColorHL; +} + + +/*! + Returns the first child of this item. + + \return the first child of this item, 0 if this item has no children +*/ +KDGanttViewItem* KDGanttViewItem::firstChild() const +{ + + return (KDGanttViewItem* )QListViewItem::firstChild(); +} + + +/*! + Returns the next sibling item of this item + + \return the next sibling item of this item, 0 if this item has no + more siblings +*/ +KDGanttViewItem* KDGanttViewItem::nextSibling() const +{ + return (KDGanttViewItem* )QListViewItem::nextSibling(); +} + + +/*! + Returns the parent item of this item + + \return the parent item of this item, 0 if this item is a top-level + item +*/ +KDGanttViewItem* KDGanttViewItem::parent() const +{ + return (KDGanttViewItem*)QListViewItem::parent(); +} + + +/*! + Returns the item above this item in the listview + + \return the item above this item, 0 if this is the first item +*/ +KDGanttViewItem* KDGanttViewItem::itemAbove() +{ + return (KDGanttViewItem* )QListViewItem::itemAbove(); +} + + +/*! + Returns the item below this item in the listview. + It can be specified whether the disabled items are taken + into account as well. + + \param includeDisabled if true, disabled items are considered as well + \return the item below this item, 0 if this is the last item +*/ +KDGanttViewItem* KDGanttViewItem::itemBelow( bool includeDisabled ) +{ + + KDGanttViewItem* retItem = (KDGanttViewItem* )QListViewItem::itemBelow(); + if ( !includeDisabled ) { + return retItem; + } + if ( retItem ) { + if (itemPos() + height() == retItem->itemPos() ) { + return retItem; + } + } + KDGanttViewItem* Item2 = (KDGanttViewItem* )QListViewItem::listView()->itemAt(QPoint (2, QListViewItem::itemPos() + QListViewItem::height() +2) ); + if ( Item2 != 0 ) + if (!Item2->enabled() ) + return Item2; + return retItem; +} + + +/*! + Updates the colors of the item, but not the coordinates. +*/ +void KDGanttViewItem::updateCanvasItems() +{ + if (blockUpdating) return; + QPen p,pBack; + QBrush b; + b.setStyle(Qt::SolidPattern); + if ( enabled() ) { + textCanvas->setColor(myTextColor); + if (isHighlighted) { + b.setStyle(Qt::SolidPattern); + b.setColor(myStartColorHL); + startShape->setBrush(b); + b.setColor(myMiddleColorHL); + midShape->setBrush(b); + b.setColor(myEndColorHL); + endShape->setBrush(b); + p.setWidth(myItemSize/3 -1); + p.setColor(myStartColorHL); + startLine->setPen(p); + p.setColor(myEndColorHL); + endLine->setPen(p); + } else { + b.setStyle(Qt::SolidPattern); + b.setColor(myStartColor); + // qDebug("update color %s %s", listViewText().latin1(),myStartColor.name().latin1() ); + startShape->setBrush(b); + b.setColor(myMiddleColor); + midShape->setBrush(b); + b.setColor(myEndColor); + endShape->setBrush(b); + p.setWidth(myItemSize/3-1); + p.setColor(myStartColor); + startLine->setPen(p); + p.setColor(myEndColor); + endLine->setPen(p); + } + } else { + //QColor discol = Qt::lightGray; + QColor discol = QColor(232,232,232); + textCanvas->setColor( QColor(150,150,150) ); + b.setStyle(Qt::SolidPattern); + b.setColor(discol); + startShape->setBrush(b); + midShape->setBrush(b); + endShape->setBrush(b); + p.setWidth(myItemSize/3 -1); + p.setColor(discol); + startLine->setPen(p); + endLine->setPen(p); + } + pBack.setWidth((myItemSize/3-1)+2); + startLineBack->setPen(pBack); + endLineBack->setPen(pBack); + QFont f = textCanvas->font(); + f.setPixelSize(myItemSize); + textCanvas->setFont(f); + //if (isvisible) { + myGanttView->myTimeTable->updateMyContent(); + //} +} + + +void KDGanttViewItem::initItem() +{ +} + + +/*! + This method is reimplemented for internal purposes. +*/ +void KDGanttViewItem::setOpen( bool open ) +{ + if ( _callListViewOnSetOpen ) { + // notify the listview about a programatically called setOpen() + if ( listView () ) + listView ()->setOpen( this, open ); + + } else { + + QListViewItem::setOpen( open ); + } +} + + +void KDGanttViewItem::showItem( bool, int ) +{ +} + + +QPoint KDGanttViewItem::getTaskLinkStartCoord(QPoint p) +{ + textCanvas->move(p.x()+myItemSize, itemPos() + height()/2-myItemSize/2); + return QPoint (myGanttView->myTimeHeader->getCoordX(myEndTime) +myItemSize/2,itemPos()+height()/2); +} + + +QPoint KDGanttViewItem::getTaskLinkEndCoord() +{ + return QPoint (myGanttView->myTimeHeader->getCoordX(myStartTime)-myItemSize/2 ,itemPos()-myItemSize/2+height()/2-2); +} + + +void KDGanttViewItem::hideSubtree() +{ + if (firstChild()) + firstChild()->hideSubtree(); + if ( nextSibling () ) + nextSibling ()->hideSubtree(); + showItem(false); +} + + +void KDGanttViewItem::setCallListViewOnSetOpen( bool call ) +{ + _callListViewOnSetOpen = call; +} + + +void KDGanttViewItem::initColorAndShapes(Type t) +{ + _isMoveable = false; + _isResizeable = false; + setTextOffset(QPoint(0,0)); + //_isCalendar = false; + _callListViewOnSetOpen = true; + myType = t; + myProgress = 0; + progressShape = 0; + floatStartShape = 0; + floatEndShape = 0; + blockUpdating = true; + isVisibleInGanttView = false; + startShape = 0; + midShape = 0; + endShape = 0; + startShapeBack = 0; + midShapeBack = 0; + endShapeBack = 0; + + myItemSize = 10; + myGanttView = ((KDListView *)listView())->myGanttView; + myGanttView->myTimeHeader->saveCenterDateTime(); + myStartTime = myGanttView->myTimeHeader->myCenterDateTime; + myEndTime = myStartTime; + myToolTipText =QListViewItem::text(0); + myWhatsThisText = QListViewItem::text(0); + isHighlighted = false; + isEditable = true; + _displaySubitemsAsGroup = myGanttView->displaySubitemsAsGroup(); + startLine = new KDCanvasLine(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem);//KDGanttViewItem ); + endLine = new KDCanvasLine(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + startLine->setZ(2);endLine->setZ(2); + startLineBack = new KDCanvasLine(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem);//KDGanttViewItem ); + endLineBack = new KDCanvasLine(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + startLineBack->setZ(1);endLineBack->setZ(1); + actualEnd = new KDCanvasLine(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + actualEnd->setZ(5); + actualEnd->setPen( QPen ( Qt::red, 3 ) ); + + textCanvas = new KDCanvasText(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + textCanvas->setText(""); + textCanvas->setZ(10); + // set textcolor + setTextColor( myGanttView->textColor()); + // set default color + setDefaultColor( myGanttView->defaultColor(myType)); + // set default highlight color + setDefaultHighlightColor(myGanttView->defaultHighlightColor(myType)); + // set shapes + if (!( shapeDefined = (myGanttView->shapes(myType,myStartShape,myMiddleShape,myEndShape)))) { + + //qDebug("KDGantt::KDGanttViewItem created with not user defined shapes"); + }; + + setShapes(myStartShape,myMiddleShape,myEndShape); + if ( type() == Task ) { + //qDebug("new task %s ", listViewText().latin1()); + if ( startShape ) + delete startShape; + startShape = (KDCanvasPolygonItem*)new KDCanvasRectangle(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + progressShape = (KDCanvasPolygonItem*)new KDCanvasRectangle(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + } + floatStartShape = (KDCanvasPolygonItem*)new KDCanvasRectangle(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + floatEndShape = (KDCanvasPolygonItem*)new KDCanvasRectangle(myGanttView->myTimeTable,this,Type_is_KDGanttViewItem); + + // set color of shapes + if (!( colorDefined = (myGanttView->colors(myType,myStartColor,myMiddleColor,myEndColor)))) { + + }; + setColors(defaultColor(),defaultColor(), defaultColor()); + // set highlight color of shapes + if (!( colorHLDefined = (myGanttView->highlightColors(myType,myStartColorHL,myMiddleColorHL,myEndColorHL)))) { + + }; + setHighlightColors(defaultHighlightColor(),defaultHighlightColor(), defaultHighlightColor()); + setFont(myGanttView->font()); + // if (type() == Task) + //setText(QListViewItem::text(0)); // testing only + //isvisible = true; + _priority = 150; + _showNoInformation = false; + _enabled = true; + blockUpdating = false; + updateCanvasItems(); +} + + +QString KDGanttViewItem::shapeToString( Shape shape ) +{ + switch( shape ) { + case TriangleDown: + return "TriangleDown"; + case TriangleUp: + return "TriangleUp"; + case Diamond: + return "Diamond"; + case Square: + return "Square"; + case Circle: + return "Circle"; + } + return ""; +} + + +KDGanttViewItem::Shape KDGanttViewItem::stringToShape( const QString& string ) +{ + if( string == "TriangleDown" ) + return TriangleDown; + else if( string == "TriangleUp" ) + return TriangleUp; + else if( string == "Diamond" ) + return Diamond; + else if( string == "Square" ) + return Square; + else if( string == "Circle" ) + return Circle; + else + return TriangleDown; +} + + +/*! + Creates a DOM node that describes this item. + + \param doc the DOM document to which the node belongs + \param parentElement the element into which to insert this node +*/ +void KDGanttViewItem::createNode( QDomDocument& doc, + QDomElement& parentElement ) +{ + QDomElement itemElement = doc.createElement( "Item" ); + parentElement.appendChild( itemElement ); + itemElement.setAttribute( "Type", typeToString( type() ) ); + + KDGanttXML::createDateTimeNode( doc, itemElement, "StartTime", startTime() ); + KDGanttXML::createDateTimeNode( doc, itemElement, "EndTime", endTime() ); + KDGanttXML::createFontNode( doc, itemElement, "Font", font() ); + KDGanttXML::createStringNode( doc, itemElement, "Text", text() ); + KDGanttXML::createStringNode( doc, itemElement, "TooltipText", tooltipText() ); + KDGanttXML::createStringNode( doc, itemElement, "WhatsThisText", + whatsThisText() ); + if( pixmap() ) + KDGanttXML::createPixmapNode( doc, itemElement, "Pixmap", *pixmap() ); + if( !listViewText().isNull() ) + KDGanttXML::createStringNode( doc, itemElement, "ListViewText", + listViewText() ); + KDGanttXML::createBoolNode( doc, itemElement, "Open", isOpen() ); + KDGanttXML::createBoolNode( doc, itemElement, "Highlight", highlight() ); + Shape startShape, middleShape, endShape; + shapes( startShape, middleShape, endShape ); + KDGanttXML::createStringNode( doc, itemElement, "StartShape", + shapeToString( startShape ) ); + KDGanttXML::createStringNode( doc, itemElement, "MiddleShape", + shapeToString( middleShape ) ); + KDGanttXML::createStringNode( doc, itemElement, "EndShape", + shapeToString( endShape ) ); + KDGanttXML::createColorNode( doc, itemElement, "DefaultColor", defaultColor() ); + QColor startColor, middleColor, endColor; + colors( startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, itemElement, "StartColor", startColor ); + KDGanttXML::createColorNode( doc, itemElement, "MiddleColor", middleColor ); + KDGanttXML::createColorNode( doc, itemElement, "EndColor", endColor ); + KDGanttXML::createColorNode( doc, itemElement, "DefaultHighlightColor", + defaultHighlightColor() ); + highlightColors( startColor, middleColor, endColor ); + KDGanttXML::createColorNode( doc, itemElement, "StartHighlightColor", + startColor ); + KDGanttXML::createColorNode( doc, itemElement, "MiddleHighlightColor", + middleColor ); + KDGanttXML::createColorNode( doc, itemElement, "EndHighlightColor", endColor ); + KDGanttXML::createColorNode( doc, itemElement, "TextColor", textColor() ); + KDGanttXML::createStringNode( doc, itemElement, "Name", name() ); + QDomElement itemsElement = doc.createElement( "Items" ); + itemElement.appendChild( itemsElement ); + KDGanttViewItem* currentItem = firstChild(); + while( currentItem ) { + currentItem->createNode( doc, itemsElement ); + currentItem = currentItem->nextSibling(); + } + +} + + + +/*! + Creates a KDGanttViewItem according to the specification in a DOM + element. + + \param view the view in which the item will be inserted + \param element the DOM element from which to read the specification + \return the newly created item +*/ +KDGanttViewItem* KDGanttViewItem::createFromDomElement( KDGanttView* view, + QDomElement& element ) +{ + QString typeString = element.attribute( "Type" ); + Q_ASSERT( !typeString.isEmpty() ); + KDGanttViewItem* item; + if( typeString == "Task" ) + item = new KDGanttViewTaskItem( view ); + else if( typeString == "Summary" ) + item = new KDGanttViewSummaryItem( view ); + else if( typeString == "Event" ) + item = new KDGanttViewEventItem( view ); + else { + qDebug( "Unknown item type %s in KDGanttViewItem::createFromDomElement()", typeString.latin1() ); + return 0; + } + + item->loadFromDomElement( element ); + return item; +} + + +/*! + Creates a KDGanttViewItem according to the specification in a DOM + element. + + \param view the view in which the item will be inserted + \param previous to item behind this one should appear + \param element the DOM element from which to read the specification + \return the newly created element +*/ +KDGanttViewItem* KDGanttViewItem::createFromDomElement( KDGanttView* view, + KDGanttViewItem* previous, + QDomElement& element ) +{ + QString typeString = element.attribute( "Type" ); + Q_ASSERT( !typeString.isEmpty() ); + KDGanttViewItem* item; + if( typeString == "Task" ) + item = new KDGanttViewTaskItem( view, previous ); + else if( typeString == "Summary" ) + item = new KDGanttViewSummaryItem( view, previous ); + else if( typeString == "Event" ) + item = new KDGanttViewEventItem( view, previous ); + else { + qDebug( "Unknown item type in KDGanttViewItem::createFromDomElement()" ); + return 0; + } + + item->loadFromDomElement( element ); + return item; +} + + + + +/*! + Creates a KDGanttViewItem according to the specification in a DOM + element. + + \param parent the parent item under which the item will be inserted + \param element the DOM element from which to read the specification + \return the newly created element +*/ +KDGanttViewItem* KDGanttViewItem::createFromDomElement( KDGanttViewItem* parent, + QDomElement& element ) +{ + QString typeString = element.attribute( "Type" ); + Q_ASSERT( !typeString.isEmpty() ); + KDGanttViewItem* item; + if( typeString == "Task" ) + item = new KDGanttViewTaskItem( parent ); + else if( typeString == "Summary" ) + item = new KDGanttViewSummaryItem( parent ); + else if( typeString == "Event" ) + item = new KDGanttViewEventItem( parent ); + else { + qDebug( "Unknown item type in KDGanttViewItem::createFromDomElement()" ); + return 0; + } + + item->loadFromDomElement( element ); + return item; +} + + +/*! + Creates a KDGanttViewItem according to the specification in a DOM + element. + + \param parent the parent item under which the item will be inserted + \param previous to item behind this one should appear + \param element the DOM element from which to read the specification + \return the newly created element +*/ +KDGanttViewItem* KDGanttViewItem::createFromDomElement( KDGanttViewItem* parent, + KDGanttViewItem* previous, + QDomElement& element ) +{ + QString typeString = element.attribute( "Type" ); + Q_ASSERT( !typeString.isEmpty() ); + KDGanttViewItem* item; + if( typeString == "Task" ) + item = new KDGanttViewTaskItem( parent, previous ); + else if( typeString == "Summary" ) + item = new KDGanttViewSummaryItem( parent, previous ); + else if( typeString == "Event" ) + item = new KDGanttViewEventItem( parent, previous ); + else { + qDebug( "Unknown item type in KDGanttViewItem::createFromDomElement()" ); + return 0; + } + + item->loadFromDomElement( element ); + return item; +} + + +/* + Fills in the values in the item by reading the DOM element. +*/ +void KDGanttViewItem::loadFromDomElement( QDomElement& element ) +{ + QDomNode node = element.firstChild(); + Shape startShape = TriangleDown, middleShape = TriangleDown, + endShape = TriangleDown; + QColor startColor, middleColor, endColor; + QColor startHighlightColor, middleHighlightColor, endHighlightColor; + QString tempName; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "StartTime" ) { + QDateTime value; + if( KDGanttXML::readDateTimeNode( element, value ) ) + setStartTime( value ); + } else if( tagName == "EndTime" ) { + QDateTime value; + if( KDGanttXML::readDateTimeNode( element, value ) ) + setEndTime( value ); + } else if( tagName == "Text" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setText( value ); + } else if( tagName == "Font" ) { + QFont value; + if( KDGanttXML::readFontNode( element, value ) ) + setFont( value ); + } else if( tagName == "TooltipText" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setTooltipText( value ); + } else if( tagName == "WhatsThisText" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setWhatsThisText( value ); + } else if( tagName == "Pixmap" ) { + QPixmap value; + if( KDGanttXML::readPixmapNode( element, value ) ) + setPixmap( value ); + } else if( tagName == "ListViewText" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + setListViewText( value ); + } else if( tagName == "Open" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setOpen( value ); + } else if( tagName == "Highlight" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + setHighlight( value ); + } else if( tagName == "StartShape" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + startShape = stringToShape( value ); + } else if( tagName == "MiddleShape" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + middleShape = stringToShape( value ); + } else if( tagName == "EndShape" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + endShape = stringToShape( value ); + } else if( tagName == "DefaultColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultColor( value ); + } else if( tagName == "StartColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startColor = value; + } else if( tagName == "MiddleColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleColor = value; + } else if( tagName == "EndColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endColor = value; + } else if( tagName == "DefaultHighlightColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setDefaultHighlightColor( value ); + } else if( tagName == "StartHighlightColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + startHighlightColor = value; + } else if( tagName == "MiddleHighlightColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + middleHighlightColor = value; + } else if( tagName == "EndHighlightColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + endHighlightColor = value; + } else if( tagName == "TextColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + setTextColor( value ); + } else if( tagName == "Name" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + tempName = value; + } else if( tagName == "Items" ) { + QDomNode node = element.firstChild(); + KDGanttViewItem* previous = 0; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Item" ) { + KDGanttViewItem* newItem; + if( previous ) + newItem = + KDGanttViewItem::createFromDomElement( this, + previous, + element ); + else + newItem = + KDGanttViewItem::createFromDomElement( this, + element ); + previous = newItem; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + + node = node.nextSibling(); + } + + setColors( startColor, middleColor, endColor ); + setHighlightColors( startHighlightColor, middleHighlightColor, + endHighlightColor ); + setShapes( startShape, middleShape, endShape ); + generateAndInsertName( tempName ); +} + + +QString KDGanttViewItem::typeToString( Type type ) +{ + switch( type ) { + case Event: + return "Event"; + case Summary: + return "Summary"; + case Task: + return "Task"; + default: + qDebug( "Unknown type in KDGanttViewItem::typeToString()" ); + return "Summary"; + } + return ""; +} + + +/*! + Returns the y coordinate of this item. + + \return the y coordinate of this item +*/ +int KDGanttViewItem::getCoordY() +{ + return itemPos() + height()/2; +} + + +void KDGanttViewItem::showSubItems() +{ + showSubitemTree( getCoordY() ); +} + + +void KDGanttViewItem::showSubitemTree( int CoordY ) +{ + + KDGanttViewItem* temp = firstChild(); + if (temp) { + while (temp != 0) { + if (temp->isOpen() || !temp->displaySubitemsAsGroup() ) { + temp->showItem( true, CoordY ); + if ( temp->firstChild() ) + temp->firstChild()->hideSubtree(); + } else { + if ( temp->displaySubitemsAsGroup() && temp->firstChild() ) + temp->hideSubtree(); + else { + temp->showSubitemTree( CoordY ); + } + } + temp = temp->nextSibling(); + } + showItem( false ); + } else { + showItem( true, CoordY ); + } +} + + +/*! + Returns the start time of the children of this item. + + \return the start time of the children of this item +*/ +QDateTime KDGanttViewItem::myChildStartTime() +{ + QDateTime ret, tempTime; + bool set = true; + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + if (temp) { + while (temp != 0) { + if ( !temp->displaySubitemsAsGroup() ) { + tempTime = temp->startTime(); + } else { + tempTime = temp->myChildStartTime(); + } + if ( set ) { + set = false; + ret = tempTime; + } else { + if ( tempTime < ret ) { + ret = tempTime; + } + } + temp = temp->nextSibling(); + } + } else { + ret = startTime(); + } + return ret; +} + + +/*! + Returns the end time of the children of this item. + + \return the end time of the children of this item +*/ +QDateTime KDGanttViewItem::myChildEndTime() +{ + QDateTime ret, tempTime; + bool set = true; + KDGanttViewItem* temp = (KDGanttViewItem*) firstChild(); + if (temp) { + while (temp != 0) { + if ( !temp->displaySubitemsAsGroup() ) { + tempTime = temp->endTime(); + } else { + tempTime = temp->myChildEndTime(); + } + if ( set ) { + set = false; + ret = tempTime; + } else { + if ( tempTime > ret ) { + ret = tempTime; + } + } + temp = temp->nextSibling(); + } + } else { + ret = endTime(); + } + return ret; +} + + +/*! + Returns whether the 'showNoInformation' line should be shown for this item + + \return true if showNoInformation line should be shown + \sa setShowNoInformation(), KDGanttView::setNoInformationBrush(), KDGanttView::noInformationBrush() +*/ +bool KDGanttViewItem::showNoInformation() +{ + return _showNoInformation; +} + + +/*! + Specifies whether the 'showNoInformation' line should be shown for + this item. + The 'showNoInformation' line is drawn over the whole timeline. + The height of the line is the height of the item. + The brush of the line is specified by KDGanttView::setNoInformationBrush(). + (i.e. the same brush for all items of the Gantt view). + The default brush is QBrush( QColor ( 100,100,100 ), Qt::FDiagPattern ); + \param show if true, the 'showNoInformation' line is shown for this item + \sa showNoInformation(), KDGanttView::setNoInformationBrush(), KDGanttView::noInformationBrush() +*/ +void KDGanttViewItem::setShowNoInformation( bool show ) +{ + _showNoInformation = show; + myGanttView->myTimeTable->updateMyContent(); +} + + +/*! + If the name of this item is \a name (i.e., listViewText() == name), + the pointer to this item is returned. Otherwise, it looks for an + item with name \a name in the set of children and subchildren of + this item. + \param name the name of the item + \return the pointer to the item with name \a name +*/ +KDGanttViewItem* KDGanttViewItem::getChildByName( const QString& name ) +{ + if ( listViewText() == name ) + return this; + KDGanttViewItem* temp = firstChild(),* ret; + while (temp != 0) { + if ( (ret = temp->getChildByName( name ))) + return ret; + temp = temp->nextSibling(); + } + return 0; +} + + +/* +void KDGanttViewItem::printinfo( QString s ) +{ + KDGanttViewItem* temp = firstChild(); + while (temp != 0) { + temp->printinfo(" "+s ); + temp = temp->nextSibling(); + } +} +*/ + + +/*! + Returns whether this item has at least one subitem that is a calendar. + A subitem is a calendar, if that item has at least one subitem or + displaySubitemAsGroup() is true for that item. + + \return true if the item has at least one subitem that is a calendar. +*/ +bool KDGanttViewItem::subitemIsCalendar() const +{ + KDGanttViewItem* temp = firstChild(); + bool ret = false; + while (temp) { + if (temp->firstChild() || temp->displaySubitemsAsGroup() ) { + ret = true; + break; + } + temp = temp->nextSibling(); + } + return ret; +} + + +int KDGanttViewItem::computeHeight() +{ + int hei = 0; + // if not visible, hide item and all subitems, return height = 0 + if ( !isVisible() ) { + showItem( false ); + if ( firstChild() ) + firstChild()->hideSubtree(); + // qDebug("KDGanttViewItem::computeHeight() %s returns 0 ", QListViewItem::text(0).latin1()); + return 0; + } + + KDGanttViewItem* temp; + bool show = true; + + // explanation of terms: + // display opened item as usual: + // display this item opened, display Gantt part on the timeline of this item. + // the same for all subitems: display all subitems on its own timeline + // display closed item as usual: + // display this item closed, display Gantt part on the timeline of this item. + // do not display any subitem. + + // desired behaviour: + // if not in calendar mode( GanttView is NOT in calendar mode ): + // opened: + // display opened item as usual + // closed: + // if not displaySubitemsAsGroup() + // display closed item as usual + // else ( displaySubitemsAsGroup() == true ) + // display not this item, display subitems on the timeline of this item + // else ( GanttView is in calendar mode ) + // 4 cases: + // opened && displaySubitemsAsGroup(): + // display not this item, display subitems on the timeline of this item, + // which have the property displaySubitemsAsGroup() == false + // display the other items, + // which have the property displaySubitemsAsGroup() == true, + // as usual below this item on their own timeline + // opened && NOT displaySubitemsAsGroup(): + // display opened item as usual + // closed && displaySubitemsAsGroup(): + // display not this item, display subitems on the timeline of this item, + // which have the property displaySubitemsAsGroup() == false + // closed && NOT displaySubitemsAsGroup(): + // display closed item as usual + // + if ( isOpen() ) { + //qDebug("KDGanttViewItem::computeHeight() %s is open ", QListViewItem::text(0).latin1()); + temp = firstChild(); + // if item opened, iterate over all subitems + int tempHeight; + // introduced special for performance reasons + bool special = displaySubitemsAsGroup() && myGanttView->calendarMode(); + while (temp != 0) { + tempHeight = temp->computeHeight(); + if ( special ) { + if ( temp->displaySubitemsAsGroup() ) { + hei += tempHeight; + //qDebug(" hei added "); + } else { + temp->showSubitemTree( getCoordY() ); + + } + } else { + hei += tempHeight; + //qDebug(" hei added "); + } + temp = temp->nextSibling(); + } + } else { // closed! + //qDebug("KDGanttViewItem::computeHeight() %s is closed ", QListViewItem::text(0).latin1()); + + if ( !displaySubitemsAsGroup() ) { + if ( firstChild() ) { + firstChild()->hideSubtree(); + } + } else { + if ( firstChild() ) { + showSubitemTree( getCoordY() ); + show = false ; + } + } + + } + if ( show ) + showItem( true ); + + hei += height(); + //qDebug("KDGanttViewItem::computeHeight() %s returns: %d ", QListViewItem::text(0).latin1(), hei); + return hei; +} + + +// if this item has at least one subitem which has the property displaySubitemsAsGroup(), +// a false is returned +bool KDGanttViewItem::showNoCross() +{ + KDGanttViewItem * temp = firstChild(); + if ( !temp ) + return false; + while ( temp ) { + if ( temp->displaySubitemsAsGroup() ) { + return false; + } + temp = temp->nextSibling(); + } + return true; +} + + +void KDGanttViewItem::paintBranches ( QPainter* p, const QColorGroup& cg, + int w, int y, int h ) +{ + QListViewItem::paintBranches ( p, cg, w, y, h); + if ( !myGanttView->calendarMode() ) + return; + else { + KDGanttViewItem * temp = firstChild(); + while ( temp ) { + if ( temp->showNoCross() ) { + //qDebug("paintNoCross %s ", temp->listViewText(0).latin1()); + int y_coord = temp->itemPos() -height ()- itemPos(); + int hei = temp->height(); + //qDebug(" y %d w %d h %d ", y,w,h); + //qDebug("yc %d hei %d",y_coord,hei ); + myGanttView->myListView->paintemptyarea( p, QRect( 0,y+y_coord,w,hei)); + int x_c = w/2; + int y_c = y+y_coord+ temp->height ()/2; + int y_ce ; + if ( temp->itemBelow() && temp->itemBelow()->parent() == this ) + y_ce =y+y_coord+ temp->height (); + else + y_ce = y_c; + int i; + for (i = y+y_coord+1; i <= y_ce; i+=2 ) { + p->drawPoint( x_c, i ); + } + for (i = x_c+2; i < w; i+=2 ) { + p->drawPoint( i, y_c ); + } + } + temp = temp->nextSibling(); + } + } +} + + +// resets the visibility os the subitems according to the setting of calendar mode +void KDGanttViewItem::resetSubitemVisibility() +{ + KDGanttViewItem* temp; + temp = firstChild(); + bool allow = false; + if ( myGanttView->calendarMode() ) { + // in calendarmode only items can be opened which have subitems which have subitems + if ( ! temp ) { + if ( !parent() ) + // has no parent, has no child : show! + setVisible( true ); + else + // has parent, has no child : hide! + setVisible( false ); + return; + } + setVisible( true ); + while (temp) { + if (temp->firstChild()) { + allow = true; + temp->resetSubitemVisibility(); + } + else { + temp->setVisible(false); + } + temp = temp->nextSibling(); + } + } else { + setVisible( true ); + // all items can be opened + allow = true; + while (temp != 0) { + temp->resetSubitemVisibility(); + temp = temp->nextSibling(); + } + } + if ( !allow && isOpen() ) + setOpen( false ); + +} + + +/*! + Specifies whether this item should behave like a calendar. + In calendar mode, only those items can be opened + which have subitems which have subitems. + An item which has subitems which have no subitems is called a calendar. + I.e., an item that contains + multiple calendars can be opened, while a calendar item itself cannot. + But if all calendars of an item do not have any subitem (e.g at startup), + the program cannot detect automatically that it should be possible to open + this item. + To enable this, call setIsCalendar( true ); for at least one calendar + + \param cal true in order behave this item like a calendar + highlighting off for this item + \sa isCalendar() +*/ + +/* removed +void KDGanttViewItem::setIsCalendar( bool cal ) +{ + _isCalendar = cal; + updateCanvasItems(); +} +*/ + +/*! + Returns whether this item behaves like a calendar, + even though it has no subitem which has subitems; when highlighting + with setHighlight() or by the user with the mouse. + + \return true if the item behaves like a calendar + \sa setIsCalendar() +*/ +/* removed +bool KDGanttViewItem::isCalendar( ) const +{ + return _isCalendar; +} +*/ + + +/*! + \var KDGanttViewItem::startLine + + the line at the beginning of the item +*/ + +/*! + \var KDGanttViewItem::endLine + + the line at the end of the item +*/ + + +/*! + \var KDGanttViewItem::startLineBack + + the background line at the beginning of the item +*/ + +/*! + \var KDGanttViewItem::endLineBack + + the background line at the end of the item +*/ + + +/*! + \var KDGanttViewItem::actualEnd + + the line at the actual end of the item +*/ + +/*! + \var KDGanttViewItem::startShape + + the shape at the beginning of the item +*/ + +/*! + \var KDGanttViewItem::midShape + + the shape in the middle of the item +*/ + +/*! + \var KDGanttViewItem::endShape + + the shape at the end of the item +*/ + +/*! + \var KDGanttViewItem::startShapeBack + + the background shape at the beginning of the item +*/ + +/*! + \var KDGanttViewItem::midShapeBack + + the background shape in the middle of the item +*/ + +/*! + \var KDGanttViewItem::endShapeBack + + the background shape at the end of the item +*/ + + +/*! + \var KDGanttViewItem::myGanttView + + a pointer to the KDGanttView object to which this item belongs +*/ + +/*! + \var KDGanttViewItem::textCanvas + + the text object that is used for this item +*/ + +/*! + \var KDGanttViewItem::textCanvasText + + the actual string that is displayed in the text object for this item +*/ + +/*! + \var KDGanttViewItem::myStartTime + + the starting time of this item +*/ + +/*! + \var KDGanttViewItem::myEndTime + + the ending time of this item +*/ + +/*! + \var KDGanttViewItem::isHighlighted + + whether this item is currently highlighted or not +*/ + +/*! + \var KDGanttViewItem::isEditable + + whether this item is currently editable or not +*/ + +/*! + \var KDGanttViewItem::myItemSize + + the current size of this item +*/ + +/*! + \var KDGanttViewItem::blockUpdating + + if true, updates to this item are currently blocked, to reduce + flicker or speed up redraws +*/ + +/*! + \var KDGanttViewItem::isVisibleInGanttView + + this instance variable is true if the item is visible in the Gantt + view +*/ + + +/*! + Returns the coordinate of this items middle left point +*/ +QPoint KDGanttViewItem::middleLeft() +{ + return QPoint(myGanttView->myTimeHeader->getCoordX(myStartTime), itemPos()+height()/2); +} +/*! + Returns the coordinate of this items middle right point +*/ +QPoint KDGanttViewItem::middleRight() +{ + return QPoint(myGanttView->myTimeHeader->getCoordX(myEndTime), itemPos()+height()/2); +} +/*! + Moves this items text. +*/ +void KDGanttViewItem::moveTextCanvas(int x, int y) +{ + int mx = x + myTextOffset.x(); + int my = y + myTextOffset.y(); + if (myTextOffset.x() != 0) + mx -= 2*myItemSize; // keep old behaviour + + textCanvas->move(mx+2*myItemSize,my-myItemSize/2); + //qDebug("%s: moveTextCanvas(%d,%d) offset: %d,%d moved to %d,%d",listViewText(0).latin1(),x,y,myTextOffset.x(),myTextOffset.y(),mx+2*myItemSize,my-myItemSize/2); +} + +/*! + Moves this items text relative to the middle right end of the item + Used to move text away from link. +*/ +void KDGanttViewItem::moveTextCanvas() +{ + QPoint m = myTextOffset+middleRight(); + textCanvas->move(m.x(), m.y()-myItemSize/2); +} + +/*! + Sets with how much the item text is offset. +*/ +void KDGanttViewItem::setTextOffset(QPoint p) +{ + //qDebug("%s: setTextOffset() offset: %d,%d",listViewText(0).latin1(),p.x(),p.y()); + myTextOffset.setX(p.x()); + myTextOffset.setY(p.y()); +} + +bool KDGanttViewItem::isMyTextCanvas(QCanvasItem *tc) +{ + return tc == textCanvas; +} + +/*! + Specifies the progress of this item in percent. + Progress is limited to minimum 0, maximum 100. + + \param percent the progress in percent. +*/ + +void KDGanttViewItem::setProgress(int percent) +{ + myProgress = QMAX(0, percent); + myProgress = QMIN(100, myProgress); +} + +/*! + Specifies the float start time of this item. + If the time is invalid, the start float is not shown. + + \param start the float start time +*/ +void KDGanttViewItem::setFloatStartTime(const QDateTime &start) +{ + myFloatStartTime = start; +} + +/*! + Specifies the float end time of this item. + If the time is invalid, the end float is not shown. + + \param end the float end time +*/ +void KDGanttViewItem::setFloatEndTime(const QDateTime &end) +{ + myFloatEndTime = end; +} + +void KDGanttViewItem::setMoveable(bool m) +{ + _isMoveable = m; +} + +bool KDGanttViewItem::isMoveable() const +{ + return _isMoveable; +} + +bool KDGanttViewItem::isResizeable() const +{ + return _isResizeable; +} + +void KDGanttViewItem::setResizeable(bool r) +{ + _isResizeable = r; +} diff --git a/kdgantt/KDGanttViewItem.h b/kdgantt/KDGanttViewItem.h new file mode 100644 index 00000000..e296db0a --- /dev/null +++ b/kdgantt/KDGanttViewItem.h @@ -0,0 +1,254 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#ifndef KDGANTTVIEWITEM_H +#define KDGANTTVIEWITEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class KDGanttView; +class KDTimeTableWidget; +class KDTimeHeaderWidget; +class KDGanttViewTaskLink; +class KDCanvasLine; +class KDCanvasText; +class KDCanvasPolygonItem; +class KDGanttViewTaskLinkGroup; + +class KDGanttViewItem : public QListViewItem +{ +public: + enum Type { Event, Task, Summary }; + enum Shape { TriangleDown, TriangleUp, Diamond, Square, Circle }; + +protected: + KDGanttViewItem( Type type, KDGanttView* view, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewItem( Type type, KDGanttViewItem* parent, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewItem( Type type, KDGanttView* view, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewItem( Type type, KDGanttViewItem* parent, + KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + + //bool _isCalendar; + bool isVisibleInGanttView; + void updateCanvasItems(); + int getCoordY(); + QDateTime myChildStartTime(); + QDateTime myChildEndTime(); + void generateAndInsertName( const QString& name ); + KDCanvasLine * startLine, *endLine, + * startLineBack, *endLineBack, *actualEnd ; + KDCanvasPolygonItem* startShape,* midShape, *endShape, *progressShape, + * startShapeBack,* midShapeBack, *endShapeBack, + * floatStartShape, * floatEndShape; + KDGanttView* myGanttView; + KDCanvasText* textCanvas; + QString textCanvasText; + QDateTime myStartTime, myEndTime; + bool isHighlighted, isEditable; + int myItemSize; + bool blockUpdating; + + void moveTextCanvas(int x, int y); + int myProgress; + QDateTime myFloatStartTime; + QDateTime myFloatEndTime; + +public: + virtual ~KDGanttViewItem(); + + Type type() const; + void setEnabled( bool on ); + bool enabled () const; + virtual void setOpen( bool o ); + void setItemVisible( bool on ); + bool itemVisible () const; + void setEditable( bool editable ); + bool editable() const; + void setShowNoInformation( bool show ); + bool showNoInformation(); + void setDisplaySubitemsAsGroup( bool show ); + bool displaySubitemsAsGroup() const; + void setPriority( int prio ); + int priority(); + virtual void setStartTime( const QDateTime& start ); + QDateTime startTime() const; + virtual void setEndTime( const QDateTime& end ); + QDateTime endTime() const; + + void setText( const QString& text ); + QString text() const; + void setListViewText( const QString& text, int column = 0 ); + void setListViewText( int column, const QString& text ); + QString listViewText( int column = 0 ) const; + void setFont( const QFont& font ); + QFont font() const; + void setTooltipText( const QString& text ); + QString tooltipText() const; + void setWhatsThisText( const QString& text ); + QString whatsThisText() const; + void setPixmap( int column, const QPixmap& pixmap ); + void setPixmap( const QPixmap& pixmap ); + const QPixmap* pixmap( int column = 0 ) const; + + void setHighlight( bool ); + bool highlight() const; + + bool subitemIsCalendar() const; + //void setIsCalendar( bool ); + //bool isCalendar( ) const; + + void setShapes( Shape start, Shape middle, Shape end ); + void shapes( Shape& start, Shape& middle, Shape& end ) const; + void setDefaultColor( const QColor& ); + QColor defaultColor() const; + void setColors( const QColor& start, const QColor& middle, + const QColor& end ); + void colors( QColor& start, QColor& middle, QColor& end ) const; + void setDefaultHighlightColor( const QColor& ); + QColor defaultHighlightColor() const; + void setHighlightColors( const QColor& start, const QColor& middle, + const QColor& end ); + void highlightColors( QColor& start, QColor& middle, QColor& end ) const; + void setTextColor( const QColor& color ); + QColor textColor() const; + + void setProgress(int percent); + void setFloatStartTime(const QDateTime &start); + void setFloatEndTime(const QDateTime &end); + + KDGanttViewItem* firstChild() const; + KDGanttViewItem* nextSibling() const; + KDGanttViewItem* parent() const; + KDGanttViewItem* itemAbove(); + KDGanttViewItem* itemBelow( bool includeDisabled = true ); + KDGanttViewItem* getChildByName( const QString& name ); + QString name() const; + static KDGanttViewItem* find( const QString& name ); + + void createNode( QDomDocument& doc, + QDomElement& parentElement ); + static KDGanttViewItem* createFromDomElement( KDGanttView* view, + QDomElement& element ); + static KDGanttViewItem* createFromDomElement( KDGanttView* view, + KDGanttViewItem* previous, + QDomElement& element ); + static KDGanttViewItem* createFromDomElement( KDGanttViewItem* parent, + QDomElement& element ); + static KDGanttViewItem* createFromDomElement( KDGanttViewItem* parent, + KDGanttViewItem* previous, + QDomElement& element ); + + void setMoveable( bool m ); + bool isMoveable() const; + void setResizeable( bool r ); + bool isResizeable() const; + +private: + friend class KDGanttView; + friend class KDTimeTableWidget; + friend class KDTimeHeaderWidget; + friend class KDListView; + friend class KDGanttViewTaskLink; + friend class KDGanttViewTaskLinkGroup; + friend class KDGanttCanvasView; + friend class KDGanttViewItemDrag; + friend class itemAttributeDialog; + + static QString shapeToString( Shape shape ); + static Shape stringToShape( const QString& string ); + static QString typeToString( Type type ); + + Type myType; + void initColorAndShapes(Type t); + void resetSubitemVisibility(); + virtual void showItem( bool show = true, int coordY = 0 ); + virtual void initItem(); + int computeHeight(); + void showSubItems(); + void showSubitemTree( int ); + void hideSubtree(); + void setCallListViewOnSetOpen( bool call ); + bool showNoCross(); + void createShape(KDCanvasPolygonItem* &,KDCanvasPolygonItem* &, Shape); + void loadFromDomElement( QDomElement& element ); + + //QFont myFont; + QString myToolTipText,myWhatsThisText; + void paintBranches ( QPainter * p, const QColorGroup & cg, int w, int y, int h ); + bool _displaySubitemsAsGroup; + bool _showNoInformation; + bool _enabled; + bool _callListViewOnSetOpen; + Shape myStartShape,myMiddleShape,myEndShape; + QColor myStartColor,myMiddleColor,myEndColor; + QColor myStartColorHL,myMiddleColorHL,myEndColorHL; + QColor myDefaultColor,myDefaultColorHL; + QColor myTextColor; + bool colorDefined,colorHLDefined; + QPoint getTaskLinkStartCoord(QPoint); + QPoint getTaskLinkEndCoord(); + QPoint middleLeft(); + QPoint middleRight(); + void moveTextCanvas(); + void setTextOffset(QPoint p); + bool isMyTextCanvas(QCanvasItem *tc); + QPoint myTextOffset; + QString _name; + bool shapeDefined; + int _priority; + static QDict sItemDict; + + bool _isMoveable; + bool _isResizeable; +}; + + +#endif diff --git a/kdgantt/KDGanttViewItemDrag.cpp b/kdgantt/KDGanttViewItemDrag.cpp new file mode 100644 index 00000000..bbc62914 --- /dev/null +++ b/kdgantt/KDGanttViewItemDrag.cpp @@ -0,0 +1,140 @@ + + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include +#include +#include +#include + +/*! + \class KDGanttViewItemDrag KDGanttViewItemDrag.h + \brief Drag and drop of KD Gantt items. + + This class implements drag and drop of KD Gantt items within a Gantt + chart. It is mainly used for internal purposes, but made a part of + the public API nevertheless, as you may want to subclass it for some + specialized functionality. +*/ + + +/*! + The constructor. Creates a KDGanttViewItemDrag object and + initializes the drag data in the form of an XML document. + + \param item the item that is dragged + \param source the source widget + \param name the internal object name +*/ +KDGanttViewItemDrag::KDGanttViewItemDrag( KDGanttViewItem* item , QWidget *source, const char * name ) : QStoredDrag("x-application/x-KDGanttViewItemDrag", source, name ) +{ + myItem = item; + + QPixmap pix; + if (item->pixmap() ) + pix = *(item->pixmap()) ; + else { + KDGanttViewItem::Shape start, middle, end; + item->shapes( start, middle, end ); + QColor st, mi, en; + item->colors( st, mi, en ); + pix =item->myGanttView->getPixmap( start, st, item->myGanttView->lvBackgroundColor(), 11 ); + } + setPixmap( pix , QPoint( -10,-10 )); + QDomDocument doc( "GanttView" ); + QString docstart = ""; + doc.setContent( docstart ); + QDomElement itemsElement = doc.createElement( "Items" ); + doc.documentElement().appendChild( itemsElement ); + item->createNode( doc, itemsElement ); + QDataStream s( array, IO_WriteOnly ); + s << doc.toString(); +} + + +/*! + Returns the encoded data of the drag object. + + \param c the format of the data + \return the encoded data of the drag object +*/ +QByteArray KDGanttViewItemDrag::encodedData( const char * c) const +{ + QString s ( c ); + if ( s == "x-application/x-KDGanttViewItemDrag" ) { + return array; + } + return QByteArray(); +} + +/*! + Returns the dragged item + + \return the dragged item +*/ +KDGanttViewItem* KDGanttViewItemDrag::getItem() +{ + return myItem; +} + + +/*! + Returns whether this drag object class can decode the data passed in \a e. + + \param e the mime source that has been dragged + \return true if KDGanttViewItemDrag can decode the data in \a e. +*/ +bool KDGanttViewItemDrag::canDecode ( const QMimeSource * e ) +{ + if ( QString( e->format() ) == "x-application/x-KDGanttViewItemDrag" ) + return true; + + return false; +} + + +/*! + Decodes the data passed in \a e into an XML string that is written + into \a string. + + \param e the data to decode + \param string the resulting XML string + \return true if the operation succeeded +*/ +bool KDGanttViewItemDrag::decode ( const QMimeSource * e , QString & string) +{ + QByteArray arr; + arr = e->encodedData( "x-application/x-KDGanttViewItemDrag"); + QDataStream s( arr, IO_ReadOnly ); + s >> string; + return true; +} + diff --git a/kdgantt/KDGanttViewItemDrag.h b/kdgantt/KDGanttViewItemDrag.h new file mode 100644 index 00000000..c017720e --- /dev/null +++ b/kdgantt/KDGanttViewItemDrag.h @@ -0,0 +1,61 @@ + +/**************************************************************************** + ** Copyright (C) 2001-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#ifndef KDGANTTVIEWITEMGRAG_H +#define KDGANTTVIEWITEMGRAG_H + +#include +#include +#include + + +class KDGanttViewItem; + +class KDGanttViewItemDrag :public QStoredDrag +{ +public: + KDGanttViewItemDrag(KDGanttViewItem* item, QWidget *source, const char * name ) ; + + QByteArray encodedData( const char * c) const; + KDGanttViewItem* getItem(); + static bool canDecode ( const QMimeSource * e ); + static bool decode ( const QMimeSource * e, QString & ); +protected: + +private: + QByteArray array; + KDGanttViewItem* myItem; +}; + + + + +#endif diff --git a/kdgantt/KDGanttViewSubwidgets.cpp b/kdgantt/KDGanttViewSubwidgets.cpp new file mode 100644 index 00000000..d35f7eba --- /dev/null +++ b/kdgantt/KDGanttViewSubwidgets.cpp @@ -0,0 +1,4048 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewSubwidgets.h" +#include "KDGanttViewEventItem.h" +#include "KDGanttViewSummaryItem.h" +#include "KDGanttViewTaskItem.h" +#ifndef KDGANTT_MASTER_CVS +#include "KDGanttViewSubwidgets.moc" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +KDTimeTableWidget:: KDTimeTableWidget( QWidget* parent,KDGanttView* myGantt) + : QCanvas (parent) +{ + myGanttView = myGantt; + taskLinksVisible = true; + flag_blockUpdating = false; + int_blockUpdating = 0; + gridPen.setStyle(Qt::DotLine); + gridPen.setColor(QColor(100,100,100)); + maximumComputedGridHeight = 0; + denseLineCount = 0; + denseLineBrush = QBrush( QColor ( 240,240,240 )); + noInfoLineBrush = QBrush( QColor ( 100,100,100 ), Qt::FDiagPattern ); + pendingHeight = 0; + pendingWidth = 0; + retune(256); + resize(1,1); +} + +QPtrList KDTimeTableWidget::taskLinks() +{ + return myTaskLinkList; +} + +void KDTimeTableWidget::clearTaskLinks() +{ + // cannot use clear() here, as tasklinks will remove themselves from my list when deleted! + QPtrListIterator it(myTaskLinkList); + while (it.current()) { + delete it.current(); + } + +} + +void KDTimeTableWidget::resetWidth( int wid ) +{ + if ( wid == width() ) { + if (pendingHeight) + pendingWidth = wid; + else + pendingWidth = 0; + return; + } + if ( ! pendingHeight ) + pendingHeight = height(); + pendingWidth = wid; + updateMyContent(); +} + +void KDTimeTableWidget::checkHeight( int hei ) +{ + if( hei < height() ) + return; + if ( pendingHeight < hei+100) + pendingHeight = hei+100; + if ( ! pendingWidth ) + pendingWidth = width(); + maximumComputedGridHeight = 0; //force recomputing all + updateMyContent(); +} + + +void KDTimeTableWidget::setNoInformationBrush( const QBrush& brush ) +{ + noInfoLineBrush = brush; + updateMyContent(); +} +QBrush KDTimeTableWidget::noInformationBrush() const +{ + return noInfoLineBrush; +} + +void KDTimeTableWidget::removeItemFromTasklinks( KDGanttViewItem* item) +{ + QPtrListIterator it((myTaskLinkList)); + for ( ; it.current(); ++it ) { + it.current()->removeItemFromList( item ); + } +} + +void KDTimeTableWidget::expandItem( QListViewItem * item) +{ + item->invalidateHeight () ; + //qApp->processEvents(); + updateMyContent(); +} +void KDTimeTableWidget::collapseItem( QListViewItem * item) +{ + item->invalidateHeight () ; + //qApp->processEvents(); + updateMyContent(); +} + +void KDTimeTableWidget::highlightItem( QListViewItem * item ) +{ + static bool itemwashighlighted; + static KDGanttViewItem* highlightedItem = 0; + if (highlightedItem) + highlightedItem->setHighlight(itemwashighlighted); + highlightedItem = ( KDGanttViewItem*)item; + itemwashighlighted = highlightedItem->highlight(); + highlightedItem->setHighlight(true); + item->invalidateHeight () ; + myGanttView->myListView->contentsY(); + updateMyContent(); +} +int KDTimeTableWidget::computeHeight() +{ + // compute height of ListView + // show only items shown in ListView + int hei = 0; + KDGanttViewItem* temp; + temp = myGanttView->firstChild(); + while (temp) { + hei += temp->computeHeight(); + temp = temp->nextSibling(); + } + // set hei to 1 to avoid canavs to be a null pixmap + if (hei == 0) { + hei = 1; + } + //qDebug("COMPUTED HEI %d ", hei); + emit heightComputed( hei ); + return hei; +} +void KDTimeTableWidget::computeVerticalGrid() +{ + // recompute the vertical grid + // compute the vertical grid + // if we have too much lines, hide them + //qDebug("computeVerticalGrid() "); + int cw = myGanttView->myTimeHeader->myGridMinorWidth; + int i = 0; + int h ; + if (pendingHeight > height() ) + h = pendingHeight; + else + h = height(); + int wid; + if ( pendingWidth ) + wid = pendingWidth; + else + wid = width(); + KDCanvasLine* templine; + KDCanvasRectangle* temprect; + QColor colcol; + QPen colPen; + bool colorIterator = true; + + + if (myGanttView->showMinorTicks()){//minor + colPen.setWidth(cw); + QPtrListIterator itcol(columnColorList); + QPtrListIterator itgrid(verGridList); + for ( ; itgrid.current(); ++itgrid ) { + if (i < wid) { + itgrid.current()->setPoints(i,0,i,h); + itgrid.current()->show(); + + if (myGanttView->myTimeHeader->getColumnColor(colcol,i,i+cw)) + { + + colPen.setColor(colcol); + if (colorIterator) + colorIterator = itcol.current(); + if (colorIterator) + {/* + itcol.current()->setPen(colPen); + itcol.current()->setPoints(i+(cw/2),0,i+(cw/2),h); + */ + + itcol.current()->setPen( QPen::NoPen ); + itcol.current()->setBrush( QBrush( colcol, SolidPattern) ); + itcol.current()->setSize(cw ,h ); + itcol.current()->move( i, 0 ); + itcol.current()->show(); + ++itcol; + } else { + + /* + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(colPen); + templine->setPoints(i+(cw/2),0,i+(cw/2),h); + */ + temprect = new KDCanvasRectangle(this,0,Type_is_KDGanttGridItem); + temprect->setPen( QPen::NoPen ); + temprect->setBrush( QBrush( colcol, SolidPattern) ); + temprect->setSize(cw ,h ); + temprect->move( i, 0 ); + temprect->setZ(-20); + temprect->show(); + columnColorList.append(temprect); + } + } + i += cw; + } else { + itgrid.current()->hide(); + } + } + // create additional Lines for vertical grid + for ( ;i < wid;i += cw) { + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(gridPen); + templine->setPoints(i,0,i,h); + templine->setZ(0); + templine->show(); + verGridList.append(templine); + if (myGanttView->myTimeHeader->getColumnColor(colcol,i,i+cw)) + { + colPen.setColor(colcol); + if (colorIterator) + colorIterator = itcol.current(); + if (colorIterator) + {/* + itcol.current()->setPen(colPen); + itcol.current()->setPoints(i+(cw/2),0,i+(cw/2),h); + */ + itcol.current()->setPen( QPen::NoPen ); + itcol.current()->setBrush( QBrush( colcol, SolidPattern) ); + itcol.current()->setSize(cw ,h ); + itcol.current()->move( i, 0 ); + itcol.current()->show(); + ++itcol; + } else { + temprect = new KDCanvasRectangle(this,0,Type_is_KDGanttGridItem); + temprect->setPen( QPen::NoPen ); + temprect->setBrush( QBrush( colcol, SolidPattern) ); + temprect->setSize(cw ,h ); + temprect->move( i, 0 ); + temprect->setZ(-20); + temprect->show(); + columnColorList.append(temprect); + /* + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(colPen); + templine->setPoints(i+(cw/2),0,i+(cw/2),h); + templine->setZ(-20); + templine->show(); + columnColorList.append(templine); + */ + } + } + } + if (colorIterator) + for ( ; itcol.current(); ++itcol ) + itcol.current()->hide(); + } else {//major + if (myGanttView->showMajorTicks()) { + QValueList::iterator intIt = myGanttView->myTimeHeader->majorTicks.begin(); + QValueList::iterator intItEnd = myGanttView->myTimeHeader->majorTicks.end(); + QPtrListIterator itcol(columnColorList); + QPtrListIterator itgrid(verGridList); + int left = 0; + for ( ; itgrid.current(); ++itgrid ) { + if (intIt != intItEnd) { + left = (*intIt); + ++intIt; + itgrid.current()->setPoints(left,0,left,h); + itgrid.current()->show(); + //int right = (*intIt); + if ((*intIt)) + if (myGanttView->myTimeHeader->getColumnColor(colcol,left,(*intIt) )) + { + int mid = (-left+(*intIt)); + colPen.setColor(colcol); + colPen.setWidth((*intIt)-left); + if (colorIterator) + colorIterator = itcol.current(); + if (colorIterator) + {/* + itcol.current()->setPen(colPen); + itcol.current()->setPoints(i+mid,0,mid,h); + */ + itcol.current()->setPen( QPen::NoPen ); + itcol.current()->setBrush( QBrush( colcol, SolidPattern) ); + itcol.current()->setSize(mid ,h ); + itcol.current()->move( left, 0 ); + itcol.current()->show(); + ++itcol; + } else { + temprect = new KDCanvasRectangle(this,0,Type_is_KDGanttGridItem); + temprect->setPen( QPen::NoPen ); + temprect->setBrush( QBrush( colcol, SolidPattern) ); + temprect->setSize(mid,h ); + temprect->move( left, 0 ); + temprect->setZ(-20); + temprect->show(); + columnColorList.append(temprect); + /* + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(colPen); + templine->setPoints(mid,0,i+mid,h); + templine->setZ(-20); + templine->show(); + columnColorList.append(templine); + */ + + } + } + + } else { + itgrid.current()->hide(); + } + } + KDCanvasLine* templine; + // create additional Lines for vertical grid + for ( ;intIt != intItEnd ;++intIt) { + + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(gridPen); + templine->setPoints((*intIt),0,(*intIt),h); + templine->setZ(0); + templine->show(); + verGridList.append(templine); + if ((*intIt)) + if (myGanttView->myTimeHeader->getColumnColor(colcol,left,(*intIt))) + { + int mid = (-left+(*intIt)); + colPen.setColor(colcol); + colPen.setWidth((*intIt)-left); + if (colorIterator) + colorIterator = itcol.current(); + if (colorIterator) + {/* + itcol.current()->setPen(colPen); + itcol.current()->setPoints(i+mid,0,mid,h); + */ + itcol.current()->setPen( QPen::NoPen ); + itcol.current()->setBrush( QBrush( colcol, SolidPattern) ); + itcol.current()->setSize(mid ,h ); + itcol.current()->move( left, 0 ); + itcol.current()->show(); + ++itcol; + } else { + temprect = new KDCanvasRectangle(this,0,Type_is_KDGanttGridItem); + temprect->setPen( QPen::NoPen ); + temprect->setBrush( QBrush( colcol, SolidPattern) ); + temprect->setSize(mid ,h ); + temprect->move( left, 0 ); + temprect->setZ(-20); + temprect->show(); + columnColorList.append(temprect); + /* + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(colPen); + templine->setPoints(mid,0,i+mid,h); + templine->setZ(-20); + templine->show(); + columnColorList.append(templine); + */ + } + } + left = (*intIt); + } + if (colorIterator) + for ( ; itcol.current(); ++itcol ) { + itcol.current()->hide(); + } + + } + else { + //hideall + QPtrListIterator itgrid(verGridList); + for ( ; itgrid.current(); ++itgrid ) { + itgrid.current()->hide(); + } + QPtrListIterator itcol(columnColorList); + for ( ; itcol.current(); ++itcol ) { + itcol.current()->hide(); + } + } + } +} +void KDTimeTableWidget::computeHorizontalGrid() +{ + // compute horizontal grid + //qDebug("computeHorizontalGrid() "); + KDGanttViewItem* temp = myGanttView->firstChild(); + int wid; + if ( pendingWidth ) + wid = pendingWidth; + else + wid = width(); + KDCanvasLine* templine; + QPtrListIterator ithor(horGridList); + if ( ithor.current() ) { + templine = ithor.current(); + ++ithor; + } else { + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(gridPen); + templine->setZ(0); + horGridList.append(templine); + } + templine->setPoints(0,0,wid,0); + templine->show(); + int posY; + while ( temp ) { + posY = temp->itemPos() + temp->height(); + if ( ithor.current() ) { + templine = ithor.current(); + ++ithor; + } else { + //new vertical grid line + templine = new KDCanvasLine(this,0,Type_is_KDGanttGridItem); + templine->setPen(gridPen); + templine->setZ(0); + horGridList.append(templine); + } + if ( templine->endPoint() != QPoint(wid,posY )) + templine->setPoints(0,posY,wid,posY ); + if ( !templine->isVisible() ) + templine->show(); + //QString ts = "asGroup"; + //if (!temp->displaySubitemsAsGroup() ) + // ts = " NOT asGroup"; + //qDebug("temp name %s %s", temp->listViewText(0).latin1(), ts.latin1()); + + temp = temp->itemBelow (); + } + while ( ithor.current() ) { + if ( ithor.current()->isVisible() ) + ithor.current()->hide(); + ++ithor; + } +} + +void KDTimeTableWidget::computeDenseLines() +{ + KDGanttViewItem* temp = myGanttView->firstChild(); + int wid; + if ( pendingWidth ) + wid = pendingWidth; + else + wid = width(); + QPtrListIterator ithordense(horDenseList); + KDCanvasRectangle* denseLine; + int tempDenseLineCount = 0; + while ( temp ) { + if ( temp->isVisible() ) { + ++tempDenseLineCount; + if ( tempDenseLineCount == denseLineCount ) { + tempDenseLineCount = 0; + if ( ithordense.current() ) { + denseLine = ithordense.current(); + ++ithordense; + } else { + denseLine =new KDCanvasRectangle(this,0,Type_is_KDGanttGridItem); + denseLine->setZ(-2); + horDenseList.append( denseLine ); + } + if ( denseLine->rect() != QRect(0, temp->itemPos(),wid, temp->height()) ) { + denseLine->move( 0, temp->itemPos() ); + denseLine->setSize( wid, temp->height()); + } + if (denseLine->brush() != denseLineBrush ) { + denseLine->setPen( QPen( Qt::NoPen ) ); + denseLine->setBrush( denseLineBrush); + } + if (!denseLine->isVisible() ) + denseLine->show(); + + } else { + ; + } + } + temp = temp->itemBelow (); + } + while ( ithordense.current() ) { + if ( ithordense.current()->isVisible() ) { + ithordense.current()->hide(); + } + ++ithordense; + } +} +void KDTimeTableWidget::computeShowNoInformation() +{ + KDGanttViewItem* temp = myGanttView->firstChild(); + int wid; + if ( pendingWidth ) + wid = pendingWidth; + else + wid = width(); + QPtrListIterator itnoinfo(showNoInfoList); + KDCanvasRectangle* noInfoLine; + while ( temp ) { + if ( temp->showNoInformation() ) { + if ( itnoinfo.current() ) { + noInfoLine = itnoinfo.current(); + ++itnoinfo; + } else { + noInfoLine =new KDCanvasRectangle(this,0,Type_is_KDGanttGridItem); + showNoInfoList.append( noInfoLine ); + noInfoLine->setZ(-1); + } + noInfoLine->move( 0, temp->itemPos() ); + noInfoLine->setSize( wid, temp->height()); + noInfoLine->setPen( QPen( Qt::NoPen ) ); + noInfoLine->setBrush( noInfoLineBrush); + noInfoLine->show(); + } + temp = temp->itemBelow (); + } + while ( itnoinfo.current() ) { + itnoinfo.current()->hide(); + ++itnoinfo; + } + +} + +void KDTimeTableWidget::computeTaskLinks() +{ + //compute and show tasklinks + QPtrListIterator it((myTaskLinkList)); + for ( ; it.current(); ++it ) { + if (it.current()->isVisible()) + it.current()->showMe(true); + else + it.current()->showMe(false); + } +} + +// updateMyContent() can be blocked by blockUpdating( true ) or inc_blockUpdating() +// updateMyContent() is blocked, if the GanttView is hidden after startup + +void KDTimeTableWidget::updateMyContent() +{ + if ( flag_blockUpdating || int_blockUpdating ) { + // qDebug("KDTimeTableWidget::updateMyContent() blocked! "); + return; + } + //qDebug("KDTimeTableWidget::updateMyContent() ********************************* "); + /* + // debug output + KDGanttViewItem* temp = myGanttView->firstChild(); + while (temp != 0) { + temp->printinfo(" " ); + temp = temp->nextSibling(); + } + */ + int hei = computeHeight(); + minimumHeight = hei; + int viewport_hei = myGanttView->myCanvasView->viewport()->height(); + if ( viewport_hei > hei ) + hei = viewport_hei + 100; + if ( myGanttView->myTimeHeader->registerStartTime() ) + return; // try again via timeheader computeTicks(); + if ( myGanttView->myTimeHeader->registerEndTime() ) + return; // try again via timeheader computeTicks(); + if ( hei > height() ) { + if ( ! pendingWidth ) + pendingWidth = width(); + if ( pendingHeight < hei ) + pendingHeight = hei; + } + if (pendingHeight > hei ) + hei = pendingHeight; + if (hei > maximumComputedGridHeight) + { + maximumComputedGridHeight = hei; + // compute the background interval lines + myGanttView->myTimeHeader->computeIntervals( hei ); + //compute VerticalGrid and column color + computeVerticalGrid(); + } + computeTaskLinks(); + computeHorizontalGrid(); + computeDenseLines(); + computeShowNoInformation(); + //setAllChanged(); + update(); + if (pendingWidth && pendingHeight ) { + resize( pendingWidth, pendingHeight ); + pendingWidth = 0; + pendingHeight = 0; + emit heightComputed( 0 ); + + } + pendingWidth = 0; + pendingHeight = 0; + //qDebug("KDTimeTableWidget::updateMyContent() -------------------------"); +} +// used for blocking recursive methods +// e.g. KDGanttViewItem::setHighlight() and displaySubitemsAsGroup() == true + +void KDTimeTableWidget::inc_blockUpdating( ) +{ + ++ int_blockUpdating; +} +// used for blocking recursive methods +void KDTimeTableWidget::dec_blockUpdating( ) +{ + -- int_blockUpdating; +} +// if false(i.e. unblock), sets int_blockUpdating to 0 +void KDTimeTableWidget::setBlockUpdating( bool block ) +{ + if ( !block ) + int_blockUpdating = 0; + flag_blockUpdating = block; +} +bool KDTimeTableWidget::blockUpdating() +{ + return flag_blockUpdating; +} + +void KDTimeTableWidget::setShowTaskLinks( bool show ) +{ + taskLinksVisible = show; + updateMyContent(); +} +bool KDTimeTableWidget::showTaskLinks() +{ + return taskLinksVisible; +} +void KDTimeTableWidget::setHorBackgroundLines( int count, QBrush brush ) +{ + denseLineBrush = brush; + denseLineCount = 0; + if ( count > 1 ) + denseLineCount = count; +} + + +int KDTimeTableWidget::horBackgroundLines( QBrush& brush ) +{ + brush = denseLineBrush; + return denseLineCount; +} + +int KDTimeTableWidget::getCoordX( QDateTime dt ) { + return myGanttView->myTimeHeader->getCoordX(dt); +} + +/* *************************************************************** + KDTimeHeaderWidget:: KDTimeHeaderWidget + ***************************************************************** */ +KDTimeHeaderWidget:: KDTimeHeaderWidget( QWidget* parent,KDGanttView* gant ) + : QWidget (parent) +{ + myToolTip = new KDTimeHeaderToolTip(this,this); + mySizeHint = 0; + myGanttView = gant; + flagDoNotRecomputeAfterChange = true; + QDateTime start = (QDateTime::currentDateTime ()).addSecs(-3600); + setHorizonStart(start); + setHorizonEnd( start.addSecs(3600*2)); + flagStartTimeSet = false; + flagEndTimeSet = false; + myCenterDateTime = QDateTime::currentDateTime (); + setScale(KDGanttView::Auto); + //setScale(KDGanttView::Hour); + myMaxScale = KDGanttView::Month; + myMinScale = KDGanttView::Minute; + myAutoScaleMinorTickcount = 100; + setMajorScaleCount( 1 ); + setMinorScaleCount( 1); + setMinimumColumnWidth( 5 ); + setYearFormat(KDGanttView::FourDigit ); + setHourFormat( KDGanttView::Hour_12 ); + myZoomFactor = 1.0; + setWeekendBackgroundColor(QColor(220,220,220) ); + setWeekendDays( 6, 7 ); + myGridMinorWidth = 0; + myPopupMenu = new QPopupMenu(this); + QPopupMenu * zoomPopupMenu = new QPopupMenu(this); + myPopupMenu->insertItem (i18n("Zoom"),zoomPopupMenu, 1); + zoomPopupMenu->insertItem( i18n("Zoom to 100%"),this, SLOT(setSettings(int)),0 ,21,21 ); + zoomPopupMenu->insertItem( i18n("Zoom to Fit"),this, SLOT(setSettings(int)),0 ,20,20 ); + zoomPopupMenu->insertItem( i18n("Zoom In (x 2)"),this, SLOT(setSettings(int)),0 ,22,22 ); + zoomPopupMenu->insertItem( i18n("Zoom In (x 6)"),this, SLOT(setSettings(int)),0 ,24,24 ); + zoomPopupMenu->insertItem( i18n("Zoom In (x 12)"),this, SLOT(setSettings(int)),0 ,26,26 ); + zoomPopupMenu->insertItem( i18n("Zoom Out (x 1/2)"),this, SLOT(setSettings(int)),0 ,23,23 ); + zoomPopupMenu->insertItem( i18n("Zoom Out (x 1/6)"),this, SLOT(setSettings(int)),0 ,25,25 ); + zoomPopupMenu->insertItem( i18n("Zoom Out (x 1/12)"),this, SLOT(setSettings(int)),0 ,27,27 ); + scalePopupMenu = new QPopupMenu(this); + myPopupMenu->insertItem (i18n("Scale"),scalePopupMenu, 2); + scalePopupMenu->insertItem( i18n("Minute"),this, SLOT(setSettings(int)),0 ,1,1 ); + scalePopupMenu->insertItem( i18n("Hour"),this, SLOT(setSettings(int)),0 ,2,2 ); + scalePopupMenu->insertItem( i18n("Day"),this, SLOT(setSettings(int)),0 ,3,3 ); + scalePopupMenu->insertItem( i18n("Week"),this, SLOT(setSettings(int)),0 ,4,4 ); + scalePopupMenu->insertItem( i18n("Month"),this, SLOT(setSettings(int)),0 ,5,5 ); + scalePopupMenu->insertItem( i18n("Auto"),this, SLOT(setSettings(int)),0 ,6,6 ); + scalePopupMenu->setCheckable ( true ); + timePopupMenu = new QPopupMenu(this); + myPopupMenu->insertItem (i18n("Time Format"),timePopupMenu, 3); + timePopupMenu->insertItem( i18n("24 Hour"),this, SLOT(setSettings(int)),0 ,40,40 ); + timePopupMenu->insertItem( i18n("12 PM Hour"),this, SLOT(setSettings(int)),0 ,41,41 ); + timePopupMenu->insertItem( i18n("24:00 Hour"),this, SLOT(setSettings(int)),0 ,42,42 ); + yearPopupMenu = new QPopupMenu(this); + myPopupMenu->insertItem (i18n("Year Format"),yearPopupMenu, 4); + yearPopupMenu->insertItem( i18n("Four Digit"),this, SLOT(setSettings(int)),0 ,50,50 ); + yearPopupMenu->insertItem( i18n("Two Digit"),this, SLOT(setSettings(int)),0 ,51,51 ); + yearPopupMenu->insertItem( i18n("Two Digit Apostrophe"),this, SLOT(setSettings(int)),0 ,52,52 ); + yearPopupMenu->insertItem( i18n("No Date on Minute/Hour Scale"),this, SLOT(setSettings(int)),0 ,53,53 ); + + gridPopupMenu = new QPopupMenu(this); + myPopupMenu->insertItem (i18n("Grid"),gridPopupMenu,5); + gridPopupMenu->insertItem( i18n("Show Minor Grid"),this, SLOT(setSettings(int)),0 ,10,10 ); + gridPopupMenu->insertItem( i18n("Show Major Grid"),this, SLOT(setSettings(int)),0 ,11,11 ); + gridPopupMenu->insertItem( i18n("Show No Grid"),this, SLOT(setSettings(int)),0 ,12,12 ); + myPopupMenu->insertItem( i18n("Print"),this, SLOT(setSettings(int)),0 ,30,30 ); + connect(myPopupMenu, SIGNAL ( aboutToShow () ) , this, SLOT( preparePopupMenu() )) ; + flagZoomToFit = false; + setShowMinorTicks( true ); + myRealEnd = myHorizonEnd; + myRealStart = myHorizonStart; + autoComputeTimeLine = true; + flagDoNotRecomputeAfterChange = false; + flagDoNotRepaintAfterChange = false; + setShowPopupMenu(false,false,false,false,false,false,false); + for (int j =1;j<8;++j) + weekdayColor[j] = Qt::white; + myMinimumWidth = 0; + mouseDown = false; + beginMouseDown = 0; + endMouseDown = 0; +} + +KDTimeHeaderWidget::~KDTimeHeaderWidget() +{ + delete myToolTip; +} +void KDTimeHeaderWidget::preparePopupMenu() +{ + myPopupMenu->setItemVisible ( 1, flagShowZoom ); + myPopupMenu->setItemVisible ( 2, flagShowScale ); + myPopupMenu->setItemVisible ( 3, flagShowTime ); + myPopupMenu->setItemVisible ( 4, flagShowYear ); + myPopupMenu->setItemVisible ( 5, flagShowGrid); + myPopupMenu->setItemVisible ( 30, flagShowPrint ); + if (flagZoomToFit) + myPopupMenu->changeItem( 1, i18n("Zoom (Fit)")); + else + myPopupMenu->changeItem( 1, i18n("Zoom (%1)").arg( QString::number( zoomFactor(), 'f',3) ) ); + int i = 0; + int id; + while ( ( id = scalePopupMenu->idAt( i++ )) >= 0 ) { + scalePopupMenu->setItemChecked ( id, false ); + } + scalePopupMenu->setItemChecked ( scalePopupMenu->idAt ( (int)( scale()) ), true ); + i = 0; + while ( ( id = timePopupMenu->idAt( i++ )) >= 0 ) { + timePopupMenu->setItemChecked ( id, false ); + } + timePopupMenu->setItemChecked ( timePopupMenu->idAt ( (int)( hourFormat()) ), true ); + i = 0; + while ( ( id = yearPopupMenu->idAt( i++ )) >= 0 ) { + yearPopupMenu->setItemChecked ( id, false ); + } + yearPopupMenu->setItemChecked ( yearPopupMenu->idAt ( (int)( yearFormat()) ), true ); + i = 0; + while ( ( id = gridPopupMenu->idAt( i++ )) >= 0 ) { + gridPopupMenu->setItemChecked ( id, false ); + } + + gridPopupMenu->setItemChecked ( gridPopupMenu->idAt ( 0 ), showMinorTicks() ); + gridPopupMenu->setItemChecked ( gridPopupMenu->idAt ( 1 ), showMajorTicks() ); + gridPopupMenu->setItemChecked ( gridPopupMenu->idAt ( 2 ), + !(showMajorTicks() || showMinorTicks()) ); + + +} + +QString KDTimeHeaderWidget::getToolTipText(QPoint p) +{ + return KGlobal::locale()->formatDateTime(getDateTimeForIndex(p.x())); +} +void KDTimeHeaderWidget::addTickRight( int num ) +{ + int secs = ((num*getTickTime())-30); + setHorizonEnd(getDateTimeForIndex(width()).addSecs(secs)); + //qApp->processEvents(); +} + +void KDTimeHeaderWidget::addTickLeft( int num ) +{ + int secs = ((num*getTickTime())-30); + setHorizonStart(getDateTimeForIndex(0).addSecs(-secs)); + //qApp->processEvents(); +} +// the time in secs of one minor grid tick +int KDTimeHeaderWidget::getTickTime() +{ + return getDateTimeForIndex(0).secsTo(getDateTimeForIndex(myGridMinorWidth)); +} + + +void KDTimeHeaderWidget::checkWidth( int wid ) +{ + // we have to set the minimum width one pixel higher than the + // viewport width of the canvas view in order to + // avoid that the horiz. scrollbar of the canvasview is hidden + myMinimumWidth = wid + 1; + if ( myMinimumWidth > width() || + ( myMinimumWidth > mySizeHint && + myMinimumWidth < (width() - myGridMinorWidth )) ) + computeTicks(); + + // Update (horizontal) scrollbar, + // We probably come from an external resize and then we must + // calculate on basis of myCanvasView. + // (NOTE: we have disconnected the auto QScrollView scrollbar update) + if (myGanttView && myGanttView->myCanvasView) + myGanttView->myCanvasView->updateScrollBars(); +} + +bool KDTimeHeaderWidget::registerStartTime() +{ + + QListViewItemIterator it( myGanttView->myListView ); + if (!flagStartTimeSet) { + QDateTime temp , time; + KDGanttViewItem* item; + bool setNewTime = false; + item = (KDGanttViewItem*)myGanttView->myListView->firstChild(); + if ( item ) { + temp = item->startTime(); + time = temp; + // while ( item != 0) + for ( ; it.current(); ++it ) { + item = ( KDGanttViewItem* )it.current(); + if (item->isVisibleInGanttView) { + if ( !setNewTime ) + temp = item->startTime(); + switch( item->type() ) { + case KDGanttViewItem::Event: + time = ((KDGanttViewEventItem*)item)->leadTime(); + setNewTime = true; + break; + case KDGanttViewItem::Summary: + case KDGanttViewItem::Task: + time = item->startTime(); + setNewTime = true; + break; + default: + time = temp; + } + if ( time < temp) { + temp = time ; + } + } + } + if ( setNewTime ) + if ( myHorizonStart != temp) { + myHorizonStart = temp; + computeTicks(); + return true; + } + } + } + return false; +} + + +bool KDTimeHeaderWidget::registerEndTime() +{ + if (!flagEndTimeSet) { + QDateTime temp , time; + KDGanttViewItem* item; + bool setNewTime = false; + item = (KDGanttViewItem*)myGanttView->myListView->firstChild(); + if ( item ) { + temp = item->startTime(); + time = temp; + QListViewItemIterator it( myGanttView->myListView ); + for ( ; it.current(); ++it ) { + item = ( KDGanttViewItem* )it.current(); + if (item->isVisibleInGanttView) { + if ( !setNewTime ) + temp = item->startTime(); + switch( item->type() ) { + case KDGanttViewItem::Event: + time = ((KDGanttViewEventItem*)item)->startTime(); + setNewTime = true; + break; + case KDGanttViewItem::Summary: + time = item->endTime(); + if ( time < ((KDGanttViewSummaryItem*)item)->actualEndTime()) + time = ((KDGanttViewSummaryItem*)item)->actualEndTime(); + setNewTime = true; + break; + case KDGanttViewItem::Task: + time = item->endTime(); + setNewTime = true; + break; + default: + time = temp; + } + if ( time > temp) + temp = time ; + } + } + + if ( setNewTime ) + if (myHorizonEnd != temp ) { + myHorizonEnd = temp; + computeTicks(); + return true; + } + } + } + return false; +} + + +void KDTimeHeaderWidget::setShowPopupMenu( bool show, + bool showZoom, + bool showScale, + bool showTime, + bool showYear, + bool showGrid, + bool showPrint) +{ + flagShowPopupMenu = show; + flagShowZoom = showZoom; + flagShowScale = showScale; + flagShowTime = showTime; + flagShowYear = showYear; + flagShowGrid = showGrid; + flagShowPrint = showPrint; +} + + +bool KDTimeHeaderWidget::showPopupMenu() const +{ + return flagShowPopupMenu; +} + +void KDTimeHeaderWidget::setSettings(int i) +{ + + switch (i) { + case 1: + setScale(KDGanttView::Minute ); + break; + case 2: + setScale(KDGanttView::Hour ); + break; + case 3: + setScale(KDGanttView::Day ); + break; + case 4: + setScale(KDGanttView::Week ); + break; + case 5: + setScale(KDGanttView::Month ); + break; + case 6: + setScale(KDGanttView::Auto ); + break; + case 10: + setShowMinorTicks( true ); + break; + case 11: + setShowMajorTicks( true );{ + + } + break; + case 12: + setShowMajorTicks( false ); + setShowMinorTicks( false); + break; + case 20: + zoomToFit(); + break; + case 21: + zoom(1.0); + break; + case 22: + zoom(2.0,false); + break; + case 23: + zoom(0.5,false); + break; + case 24: + zoom(6.0,false); + break; + case 25: + zoom(0.16666,false); + break; + case 26: + zoom(12.0,false); + break; + case 27: + zoom(0.08333,false); + break; + case 30: + myGanttView->print(); + break; + case 40: + case 41: + case 42: + setHourFormat( (KDGanttView::HourFormat) (i - 40) ); + break; + case 50: + case 51: + case 52: + case 53: + setYearFormat( (KDGanttView::YearFormat) ( i - 50) ); + break; + + case 60: + + break; + + case 61: + + break; + + case 62: + + break; + + case 63: + + break; + + case 64: + + break; + } + // myGanttView->myTimeTable->updateMyContent(); +} +void KDTimeHeaderWidget::zoomToFit() +{ + flagZoomToFit = true; + computeTicks(); + // Since we have disconnected autoupdate of scrollbars, we must do it ourselves + if (myGanttView && myGanttView->myCanvasView) + myGanttView->myCanvasView->updateScrollBars(); +} +double KDTimeHeaderWidget::zoomFactor() +{ + return myZoomFactor; +} +double KDTimeHeaderWidget::secsFromTo( QDateTime begin, QDateTime end ) +{ + QDateTime temp; + double secs, days; + days = begin.daysTo(end); + temp = begin.addDays((int) days); + secs = temp.secsTo(end); + secs += days * 86400.0; + return secs; +} + + +void KDTimeHeaderWidget::zoomToSelection( QDateTime start, QDateTime end) +{ + if (start < myHorizonStart) { + myHorizonStart = start; + flagStartTimeSet = true; + //qDebug("myHorizonStart reset"); + } + if (end > myHorizonEnd) { + myHorizonEnd = end; + flagEndTimeSet = true; + //qDebug("myHorizonEnd reset "); + } + flagDoNotRepaintAfterChange = true;//avoid flicker + zoom(1.0); // set to 100% + int viewWid = myGanttView->myCanvasView->viewport()->width(); + int timeWid = getCoordX(end)-getCoordX(start); + double fac; + fac = ( (double)viewWid)/((double) timeWid ); + zoom (fac); + timeWid = getCoordX(end)-getCoordX(start); + int count = 0; + int lastScaleCount = 0; + while (timeWid >viewWid || ( ( myRealMinorScaleCount != lastScaleCount) && timeWid*2 < viewWid ) ) { + lastScaleCount = myRealMinorScaleCount; + fac = (fac * (double)viewWid)/(double)timeWid; + zoom (fac); + timeWid = getCoordX(end)-getCoordX(start); + if ( count++ > 10 ) { + //qDebug("Exiting while loop in zoomToSelection "); + break; + } + } + flagDoNotRepaintAfterChange = false; + updateTimeTable(); + repaint(); + moveTimeLineTo((getCoordX(start)-(viewWid-timeWid)/2)); + // Since we have disconnected autoupdate of scrollbars, we must do it ourselves + if (myGanttView && myGanttView->myCanvasView) + myGanttView->myCanvasView->updateScrollBars(); +} +void KDTimeHeaderWidget::moveTimeLineTo(int X) +{ + int Y = myGanttView->myCanvasView->contentsY (); + myGanttView->myCanvasView->setContentsPos (X, Y ); +} + +void KDTimeHeaderWidget::zoom(double factor, bool absolute) +{ + flagZoomToFit = false; + if ( factor < 0.000001 ) { + qDebug("KDGanttView::zoom() : Zoom factor to low. Nothing zoomed. "); + return; + } + double newZoom; + if (absolute) + newZoom = factor; + else + newZoom = myZoomFactor * factor; + double relativeZoom; + relativeZoom = newZoom / myZoomFactor; + + //qDebug("zooming relative %f ", relativeZoom); + //qDebug("zooming absolute %f ", newZoom); + int viewWid = myGanttView->myCanvasView->viewport()->width(); + if ( width() * relativeZoom < viewWid && ( newZoom > 1.01 || newZoom < 0.99 ) ) { + qDebug("KDGanttView::zoom() : Zoom factor to low for current horizon. "); + // qDebug("zooming relative %f, zooming absolute %f, viewWidth %d width %d ", relativeZoom, newZoom, viewWid, width() ); + return; + } + myZoomFactor = newZoom; + computeTicks(); + // Since we have disconnected autoupdate of scrollbars, we must do it ourselves + if (myGanttView && myGanttView->myCanvasView) + myGanttView->myCanvasView->updateScrollBars(); +} + +/*! + Sets the start of the horizon of the Gantt chart. If \a start is + null, the horizon start is computed automatically. + + \param start the start of the horizon + \sa horizonStart() +*/ +void KDTimeHeaderWidget::setHorizonStart( const QDateTime& start ) +{ + myHorizonStart = start; + flagStartTimeSet = true; + computeTicks(); +} + + +/*! + Returns the start of the horizon of the Gantt chart. + + \return the start of the horizon of the Gantt chart + \sa setHorizonStart() +*/ +QDateTime KDTimeHeaderWidget::horizonStart() const +{ + return myHorizonStart; +} + + +/*! + Sets the end of the horizon of the Gantt chart. If \a end is + null, the horizon end is computed automatically. + + \param end the end of the horizon + \sa setHorizonEnd() +*/ +void KDTimeHeaderWidget::setHorizonEnd( const QDateTime& start ) +{ + myHorizonEnd = start; + flagEndTimeSet = true; + computeTicks(); + +} + + +/*! + Returns the end of the horizon of the Gantt chart. + + \return the end of the horizon of the Gantt chart + \sa setHorizonEnd() +*/ +QDateTime KDTimeHeaderWidget::horizonEnd() const +{ + return myHorizonEnd; +} + + +/*! + Configures the unit of the lower scale of the header. The higher + unit is computed automatically. + Resets the zoomng factor to 1 (i.e. 100%). + + \param unit the unit of the lower scale of the header. + \sa scale() +*/ +void KDTimeHeaderWidget::setScale(Scale unit ) +{ + myScale = unit; + myZoomFactor = 1.0; + computeTicks(); + // Since we have disconnected autoupdate of scrollbars, we must do it ourselves + if (myGanttView && myGanttView->myCanvasView) + myGanttView->myCanvasView->updateHorScrollBar(); +} + + +/*! + Returns the unit of the lower scale of the header. + + \return the unit of the lower scale of the header. + \sa setScale() +*/ +KDTimeHeaderWidget::Scale KDTimeHeaderWidget::scale() const +{ + return myScale; +} + + +/*! + Sets the maximal allowed time scale of the lower scale of the header. + + \param unit the unit of the lower scale of the header. + \sa scale() +*/ +void KDTimeHeaderWidget::setMaximumScale( Scale unit ) +{ + myMaxScale = unit; + computeTicks(); +} + + +/*! + Returns the maximal allowed time scale of the lower scale of the header. + + \return the unit of the lower scale of the header. + \sa setScale() +*/ +KDTimeHeaderWidget::Scale KDTimeHeaderWidget::maximumScale() const +{ + return myMaxScale; +} + + +/*! + Sets the minimal allowed time scale of the lower scale of the header. + + \param unit the unit of the lower scale of the header. + \sa scale() +*/ +void KDTimeHeaderWidget::setMinimumScale( Scale unit ) +{ + myMinScale = unit; + computeTicks(); +} + + +/*! + Returns the minimal allowed time scale of the lower scale of the header. + + \return the unit of the lower scale of the header. + \sa setScale() +*/ +KDTimeHeaderWidget::Scale KDTimeHeaderWidget::minimumScale() const +{ + return myMinScale; +} + + +/*! + Sets the minimum width a column needs to have. If the size of the + Gantt chart and the scale would make it necessary to go below this + limit otherwise, the chart will automatically be made less exact. + + \param width the minimum column width + \sa minimumColumnWidth() +*/ +void KDTimeHeaderWidget::setMinimumColumnWidth( int width ) +{ + myMinimumColumWidth = width; + computeTicks(); +} + + +/*! + Returns the minimum width a column needs to have. + + \return the column minimum width + \sa setMinimumColumnWidth() +*/ +int KDTimeHeaderWidget::minimumColumnWidth() const +{ + return myMinimumColumWidth; +} + + +/*! + Specifies the format in which to display years. If no years are + shown, this method has no effect. + + \param format the year format + \sa yearFormat(), setHourFormat(), hourFormat() +*/ +void KDTimeHeaderWidget::setYearFormat( YearFormat format ) +{ + myYearFormat = format; + computeTicks(); +} + + +/*! + Returns the format in which to display years. + + \return the year format + \sa setYearFormat(), setHourFormat(), hourFormat() +*/ +KDTimeHeaderWidget::YearFormat KDTimeHeaderWidget::yearFormat() const +{ + return myYearFormat; +} + + +/*! + Specifies the format in which to display hours. If no hours are + shown, this method has no effect. + + \param format the hour format + \sa hourFormat(), setYearFormat(), yearFormat() +*/ +void KDTimeHeaderWidget::setHourFormat( HourFormat format ) +{ + myHourFormat = format; + computeTicks(); +} + + +/*! + Returns the format in which to display hours. + + \return the hour format + \sa setHourFormat(), setYearFormat(), yearFormat() +*/ +KDTimeHeaderWidget::HourFormat KDTimeHeaderWidget::hourFormat() const +{ + return myHourFormat; +} + + +/*! + Specifies whether ticks should be shown on the major scale. + + \param show true in order to show ticks, false in order to hide them + \sa showMajorTicks(), setShowMinorTicks(), showMinorTicks() +*/ +void KDTimeHeaderWidget::setShowMajorTicks( bool show ) +{ + flagShowMajorTicks = show; + if (show) { + setShowMinorTicks(false); + } + updateTimeTable(); +} + + +/*! + Returns whether ticks are shown on the major scale. + + \return true if ticks are shown on the major scale + \sa setShowMajorTicks(), setShowMinorTicks(), showMinorTicks() +*/ +bool KDTimeHeaderWidget::showMajorTicks() const +{ + return flagShowMajorTicks; +} + + +/*! + Specifies whether ticks should be shown on the minor scale. + + \param show true in order to show ticks, false in order to hide them + \sa showMinorTicks(), setShowMajorTicks(), showMajorTicks() +*/ +void KDTimeHeaderWidget::setShowMinorTicks( bool show ) +{ + flagShowMinorTicks = show; + if (show) + setShowMajorTicks(false ); + //repaintMe(); + updateTimeTable(); +} + + +/*! + Returns whether ticks are shown on the minor scale. + + \return true if ticks are shown on the minor scale + \sa setShowMinorTicks(), setShowMajorTicks(), showMajorTicks() +*/ +bool KDTimeHeaderWidget::showMinorTicks() const +{ + return flagShowMinorTicks; +} + + +/*! + Sets the background color for the column closest to \a column. + + \param column the column to set the background color for + \param color the background color + \sa columnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor() +*/ +void KDTimeHeaderWidget::setColumnBackgroundColor( const QDateTime& column, + const QColor& color, + Scale mini, Scale maxi ) +{ + ColumnColorList::iterator it; + for ( it = ccList.begin(); it != ccList.end(); ++it ) { + if ((*it).datetime == column) { + (*it).color = color; + (*it).minScaleView = mini; + (*it).maxScaleView = maxi; + return; + } + } + DateTimeColor newItem; + newItem.datetime = column; + newItem.color = color; + newItem.minScaleView = mini; + newItem.maxScaleView = maxi; + ccList.append(newItem); + updateTimeTable(); +} + +void KDTimeHeaderWidget::computeIntervals( int height ) +{ + IntervalColorList::const_iterator it; + for ( it = icList.begin(); it != icList.end(); ++it ) { + (*it)->layout( this, height ); + } +} + +void KDTimeHeaderWidget::addIntervalBackgroundColor( KDIntervalColorRectangle* newItem ) +{ + icList.append(newItem); + updateTimeTable(); +} + +#if 0 +bool KDTimeHeaderWidget::changeBackgroundInterval( const QDateTime& oldstart, + const QDateTime& oldend, + const QDateTime& newstart, + const QDateTime& newend ) +{ + IntervalColorList::iterator it; + for ( it = icList.begin(); it != icList.end(); ++it ) { + if ((*it).datetime == oldstart && (*it).end == oldend ) { + IntervalColorList::iterator it2; + for ( it2 = icList.begin(); it2 != icList.end(); ++it2 ) { + if ((*it2).datetime == newstart && (*it2).end == newend ) + return false; + } + (*it).datetime = newstart; + (*it).end = newend; + updateTimeTable(); + return true; + } + } + return false; +} +bool KDTimeHeaderWidget::deleteBackgroundInterval( const QDateTime& start, + const QDateTime& end) +{ + IntervalColorList::iterator it; + for ( it = icList.begin(); it != icList.end(); ++it ) { + if ((*it).datetime == start && (*it).end == end ) { + //delete (*it).canvasLine; + delete (*it).canvasRect; + icList.remove(it); + updateTimeTable(); + return true; + } + } + return false; +} + +void KDTimeHeaderWidget::setIntervalBackgroundColor( const QDateTime& start, + const QDateTime& end, + const QColor& color, + Scale mini , + Scale maxi ) +{ + + IntervalColorList::iterator it; + for ( it = icList.begin(); it != icList.end(); ++it ) { + if ((*it).datetime == start && (*it).end == end ) { + (*it).color = color; + (*it).minScaleView = mini; + (*it).maxScaleView = maxi; + return; + } + } + DateTimeColor newItem; + if ( start <= end ) { + newItem.datetime = start; + newItem.end = end; + } else { + newItem.datetime = end; + newItem.end = start; + } + newItem.color = color; + newItem.minScaleView = mini; + newItem.maxScaleView = maxi; + //newItem.canvasLine = new KDCanvasLine(myGanttView->myTimeTable,0,Type_is_KDGanttGridItem); + newItem.canvasRect = new KDCanvasRectangle(myGanttView->myTimeTable,0,Type_is_KDGanttGridItem); + newItem.canvasRect->setZ(-19); + icList.append(newItem); + updateTimeTable(); +} +#endif + +void KDTimeHeaderWidget::clearBackgroundColor() +{ + + IntervalColorList::iterator itic; + for ( itic = icList.begin(); itic != icList.end(); ++itic ) { + delete (*itic); + } + ccList.clear(); + icList.clear(); + updateTimeTable(); +} +QDateTime KDTimeHeaderWidget::getDateTimeForIndex(int X, bool local ) +{ + int coordX = X; + if ( !local ) { + QPoint p = QPoint ( X, 1 ); + coordX = myGanttView->myTimeHeaderScroll->viewportToContents(myGanttView->myTimeHeaderScroll->mapFromGlobal( p )).x(); + + } + double secs = (secsFromTo( myRealStart, myRealEnd ) * ((double)coordX))/(double)width(); + double days = secs/86400.0; + secs = secs - ( ((int) days) *86400.0 ); + return (myRealStart.addDays ( (int) days )).addSecs( (int) secs); +} + +//FIXME: This doesn't work quite intuitively (imho) when scale is day +// and each column containes more than 1 day: +// 1) If a column includes a weekend day, the whole column gets weekend color, +// 2) If a column includes 7 days, either *all* columns get weekend color, or +// *none* get weekend color (haven't figured out why) +// Proposal: Only use weekend color if the whole column is a weekend. +// Alt: Color the area that actually is the weekend. +bool KDTimeHeaderWidget::getColumnColor(QColor& col,int coordLow, int coordHigh) +{ + if (!flagShowMajorTicks && !flagShowMinorTicks) + return false; + QDateTime start,end; + start = getDateTimeForIndex(coordLow); + end = getDateTimeForIndex(coordHigh).addSecs(-1); + Scale tempScale = myRealScale; + if (flagShowMajorTicks) + switch (myRealScale) + { + case KDGanttView::Minute: tempScale = KDGanttView::Hour; break; + case KDGanttView::Hour: tempScale = KDGanttView::Day ; break; + case KDGanttView::Day: tempScale = KDGanttView::Week ; break; + case KDGanttView::Week: tempScale = KDGanttView::Month ; break; + case KDGanttView::Month: return false ; break; + case KDGanttView::Auto: return false ; break; + } + //check defined column color + ColumnColorList::iterator it; + for ( it = ccList.begin(); it != ccList.end(); ++it ) { + if ((*it).datetime >= start && (*it).datetime <= end) { + if (tempScale >= (*it).minScaleView && tempScale <= (*it).maxScaleView ) { + col = (*it).color; + return true; + } + } + } + + if (tempScale > KDGanttView::Day) return false; + + start = getDateTimeForIndex((coordLow+coordHigh)/2); + int day = start.date().dayOfWeek (); + //checkweekdaycolor + if (weekdayColor[day] != Qt::white) { + col = weekdayColor[day]; + return true; + } + //checkweekendcolor + int endday = myWeekendDaysEnd; + col = myWeekendBackgroundColor; + if (myWeekendDaysStart > myWeekendDaysEnd) + endday +=7; + if (day >= myWeekendDaysStart && day <= endday) { + return true; + } else { + if (day+7 >= myWeekendDaysStart && day+7 <= endday) { + return true; + } + } + return false; +} + +/*! + Returns the background color for the column closes to \a column. + + \param column the column to query the background color for + \return the background color of the specified column + \sa setColumnBackgroundColor(), setWeekendBackgroundColor(), + weekendBackgroundColor() +*/ +QColor KDTimeHeaderWidget::columnBackgroundColor( const QDateTime& column ) const +{ + QColor c; + c = white; + ColumnColorList::const_iterator ite; + for ( ite = ccList.begin(); ite != ccList.end(); ++ite ) { + if ((*ite).datetime == column) { + c = (*ite).color; + } + } + return c; +} + + +/*! + Specifies the background color for weekend days. If no individual + days are visible on the Gantt chart, this method has no visible + effect. + + \param color the background color to use for weekend days. + \sa weekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +void KDTimeHeaderWidget::setWeekendBackgroundColor( const QColor& color ) +{ + myWeekendBackgroundColor = color ; + updateTimeTable(); +} + + +/*! + Returns the background color for weekend days. + + \return the background color for weekend days + \sa setWeekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +QColor KDTimeHeaderWidget::weekendBackgroundColor() const +{ + return myWeekendBackgroundColor; +} + +/*! + Specifies the background color for week days. If no individual + days are visible on the Gantt chart, this method has no visible + effect. The days are specified as an interval of integer values + where 1 means Monday and 7 means Sunday. + + \param color the background color to use for weekend days. + \param weekday the day of the week (Monday = 1, Sunday = 7) + \sa weekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +void KDTimeHeaderWidget::setWeekdayBackgroundColor( const QColor& color, int weekday ) +{ + weekdayColor[weekday] = color; + updateTimeTable(); +} + + +/*! + Returns the background color for weekday days. + + \param the day of the week (Monday = 1, Sunday = 7) + \return the background color for weekend days + \sa setWeekendBackgroundColor(), setWeekendDays(), weekendDays() +*/ +QColor KDTimeHeaderWidget::weekdayBackgroundColor(int weekday) const +{ + return weekdayColor[weekday]; +} + + +/*! + Defines which days are considered weekends. The days are specified + as an interval of integer values where 1 means Monday and 7 means + Sunday. In order to define a weekend from Sunday to Monday, specify + (7,1). + + \param start the first day of the weekend + \param end the last day of the weekend + \sa weekendDays(), setWeekendBackgroundColor(), weekendBackgroundColor() +*/ +void KDTimeHeaderWidget::setWeekendDays( int start, int end ) +{ + myWeekendDaysStart = start; + myWeekendDaysEnd = end; + updateTimeTable(); +} + + +/*! + Returns which days are considered weekends. + + \param start in this parameter, the first day of the weekend is returned + \param end in this parameter, the end day of the weekend is returned + \sa setWeekendDays(), setWeekendBackgroundColor(), weekendBackgroundColor() +*/ +void KDTimeHeaderWidget::weekendDays( int& start, int& end ) const +{ + start = myWeekendDaysStart; + end = myWeekendDaysEnd ; +} + + + +/*! + Sets the number of ticks in the major scale. + + \param count the number of ticks in the major scale + \sa majorScaleCount(), setMinorScaleCount(), minorScaleCount() +*/ +void KDTimeHeaderWidget::setMajorScaleCount( int count ) +{ + myMajorScaleCount=count; + computeTicks(); +} + + +/*! + Returns the number of ticks per unit in the major scale. + + \return the number of ticks in the major scale + \sa setMajorScaleCount(), setMinorScaleCount(), minorScaleCount() +*/ +int KDTimeHeaderWidget::majorScaleCount() const +{ + return myMajorScaleCount; +} + + +/*! + Sets the number of ticks in the minor scale. + + \param count the number of ticks in the minor scale + \sa minorScaleCount, setMajorScaleCount, majorScaleCount() +*/ +void KDTimeHeaderWidget::setMinorScaleCount( int count ) +{ + myMinorScaleCount = count; + computeTicks(); +} + + +/*! + Returns the number of ticks per unit in the minor scale. + + \return the number of ticks in the minor scale + \sa setMinorScaleCount(), setMajorScaleCount(), majorScaleCount() +*/ +int KDTimeHeaderWidget::minorScaleCount() const +{ + return myMinorScaleCount ; + +} + + +void KDTimeHeaderWidget::resizeEvent ( QResizeEvent * ) +{ + // qDebug("KDTimeHeaderWidget:: resizeEvent "); + paintPix.resize( 800, height () ); +} + + +void KDTimeHeaderWidget::updateTimeTable() +{ + //qDebug("KDTimeHeaderWidget::updateTimeTable() "); + if (flagDoNotRecomputeAfterChange) return; + // setting the scrolling steps + int scrollLineStep = myGridMinorWidth; + if (showMajorTicks()) { + QValueList::iterator intIt = majorTicks.begin(); + scrollLineStep = 5 * myGridMinorWidth; + if (intIt != majorTicks.end()) { + int left = *intIt; + ++intIt; + if (intIt != majorTicks.end()) { + scrollLineStep = *intIt-left; + } + } + } + myGanttView->myCanvasView->horizontalScrollBar()->setLineStep(scrollLineStep); + myGanttView->myTimeTable->maximumComputedGridHeight = 0; + myGanttView->myTimeTable->updateMyContent(); +} + + +void KDTimeHeaderWidget::setAutoScaleMinorTickCount( int count ) +{ + myAutoScaleMinorTickcount = count; + computeTicks(); + +} + + +int KDTimeHeaderWidget::autoScaleMinorTickCount() +{ + return myAutoScaleMinorTickcount; +} + + +void KDTimeHeaderWidget::repaintMe(int left,int paintwid, QPainter* painter) +{ + if (flagDoNotRecomputeAfterChange) return; + QColorGroup qcg =QColorGroup( white, black,white, darkGray,black,gray,gray) ; + QPainter* p; + int offsetLeft = 0; + if ( paintwid > paintPix.width()-100 ) + paintPix.resize( paintwid+100, height () ); + if ( painter ) + p = painter; + else { + p = new QPainter( &paintPix ); + offsetLeft = left-50; + } + if ( mouseDown ) { + p->fillRect( left-offsetLeft, 0, paintwid, height(), QBrush(paletteBackgroundColor()) ); + int start ; + int wid; + if ( beginMouseDown < endMouseDown ) { + start = beginMouseDown ; + wid = endMouseDown - beginMouseDown ; + } else { + start = endMouseDown ; + wid = -endMouseDown + beginMouseDown ; + } + p->fillRect( start-offsetLeft, 0, wid, height(), QBrush(paletteBackgroundColor().dark()) ); + } else { + if (! painter ) + p->fillRect( left-offsetLeft, 0, paintwid, height(), QBrush(paletteBackgroundColor()) ); + } + p->setPen(QColor(40,40,40)); + QFont tempFont = p->font(); + tempFont.setWeight(63); + p->setFont(tempFont); + int hei1 = myMajorGridHeight, + hei2 = height(), + wid1 = myGridMinorWidth; + int xCoord; + int lwid = 1; + + QValueList::iterator it; + QValueList::iterator intIt = majorTicks.begin(); + for ( it = majorText.begin(); it != majorText.end(); ++it ) { + xCoord = (*intIt++); + if (((*intIt)>= left && xCoord <= left+paintwid)) { + qDrawShadeLine ( p,xCoord-offsetLeft ,hei1+1, xCoord-offsetLeft, -2, qcg, true, lwid, 1 ); + p->drawText(xCoord+4-offsetLeft,hei1-4,(*it)); + } + } + qDrawShadeLine ( p,left-offsetLeft ,hei1, left+paintwid-offsetLeft, hei1, qcg, true, lwid, 1 ); + int i = 0; + for ( it = minorText.begin(); it != minorText.end(); ++it ) { + if (i*wid1 >= left-wid1 && i*wid1 <= left+paintwid) { + qDrawShadeLine ( p,i*wid1-offsetLeft ,hei1-1, i*wid1-offsetLeft, hei2, qcg, true, lwid, 1 ); + p->drawText(i*wid1+1-offsetLeft,hei1+1,wid1-1,hei2-hei1,Qt::AlignCenter,(*it)); + } + ++i; + } + p->setPen(black); + p->drawLine(left-offsetLeft,hei1,left+paintwid-offsetLeft,hei1); + qDrawShadeLine ( p,left-offsetLeft ,hei2-1, left+paintwid-offsetLeft, hei2-1, qcg, true, lwid, 1 ); + p->drawLine(left-offsetLeft,hei2-1,left+paintwid-offsetLeft,hei2-1); + if ( !painter ) { + p->end(); + delete p; + bitBlt ( this, left, 0, &paintPix, 50, 0, paintwid, height() ); + } +} + +// cuts the secs in the DateTime if scale is Minute , +// the minutes and secs if scale is Hour and so on + +QDateTime KDTimeHeaderWidget::getEvenTimeDate(QDateTime tempdatetime ,Scale sc) +{ + QDate tempdate; + int min, hour; + int tempMinorScaleCount = myRealMinorScaleCount; + switch (sc) + { + case KDGanttView::Month: + tempdate = tempdatetime.date(); + while (tempdate.day ()!= 1 ) + tempdate = tempdate.addDays(-1); + //while (tempdate.month ()!= 1 ) + //tempdate = tempdate.addMonths(-1); + tempdatetime = QDateTime (tempdate, QTime (0,0)); + break; + case KDGanttView::Week: + tempdate = tempdatetime.date(); + while (tempdate.dayOfWeek ()!= KGlobal::locale()->weekStartDay()) + tempdate = tempdate.addDays(-1); + //tempdate = tempdate.addDays(-7); + tempdatetime = QDateTime (tempdate, QTime (0,0)); + break; + case KDGanttView::Day: + tempdatetime = QDateTime (tempdatetime.date(), QTime ( 0,0 ) ); + break; + case KDGanttView::Hour: + hour = tempdatetime.time().hour(); + while (24%tempMinorScaleCount > 0 && 24%tempMinorScaleCount < 24) + ++tempMinorScaleCount; + hour = ( hour /tempMinorScaleCount)*tempMinorScaleCount; + tempdatetime = QDateTime (tempdatetime.date(), QTime (hour, 0 )); + break; + case KDGanttView::Minute: + min = tempdatetime.time().minute(); + while (60%tempMinorScaleCount > 0 && 60%tempMinorScaleCount < 60) + ++tempMinorScaleCount; + // qDebug("myMinorScaleCount %d %d %d",myMinorScaleCount, myRealMinorScaleCount, tempMinorScaleCount); + min = (min /tempMinorScaleCount)*tempMinorScaleCount; + tempdatetime = QDateTime (tempdatetime.date(), QTime (tempdatetime.time().hour(),min )); + + break; + case KDGanttView::Auto: + break; + } + return tempdatetime; +} + + +void KDTimeHeaderWidget::computeRealScale(QDateTime start) +{ + + if (myScale ==KDGanttView::Auto) { + //qDebug("Autoscale "); + //double secsPerMinor = (((double)start.daysTo(myHorizonEnd))* 86400.00)/((double)myAutoScaleMinorTickcount); + double secsPerMinor = (((double)start.secsTo(myHorizonEnd)))/((double)myAutoScaleMinorTickcount); + secsPerMinor /= myZoomFactor; + if (secsPerMinor <= 1800) { + myRealScale = KDGanttView::Minute; + myRealMinorScaleCount = (int) secsPerMinor/60; + } else { + if (secsPerMinor <= 12*3600) { + myRealScale = KDGanttView::Hour; + myRealMinorScaleCount = (int) secsPerMinor/3600; + } else { + if (secsPerMinor <= 24*3600*3) { + myRealScale = KDGanttView::Day; + myRealMinorScaleCount = (int) secsPerMinor/(3600*24); + } else { + if (secsPerMinor <= 24*3600*14) { + myRealScale = KDGanttView::Week; + myRealMinorScaleCount = (int) secsPerMinor/(3600*24*7); + } else { + myRealScale = KDGanttView::Month; + myRealMinorScaleCount = (int) secsPerMinor/(3600*24*30); + + } + } + } + } + if(myRealMinorScaleCount == 0) + myRealMinorScaleCount = 1; + myRealMajorScaleCount = 1; + } + else { + //qDebug("Fixed scale "); + myRealScale = myScale; + if (myRealScale > myMaxScale) + myRealScale = myMaxScale; + if (myRealScale < myMinScale) + myRealScale = myMinScale; + myRealMinorScaleCount = (int) ( ((double)myMinorScaleCount) /myZoomFactor ); + double tempZoom = myZoomFactor; + myRealMajorScaleCount = myMajorScaleCount; + while (myRealMinorScaleCount == 0) { + if (myRealScale == myMinScale) { + myRealMinorScaleCount = 1; + break; + } + switch (myRealScale) + { + case KDGanttView::Minute: + myRealMinorScaleCount = 1; + return; + break; + case KDGanttView::Hour: + myRealScale = KDGanttView::Minute; + tempZoom = tempZoom/60; + break; + case KDGanttView::Day: + myRealScale = KDGanttView::Hour; + tempZoom = tempZoom/24; + break; + case KDGanttView::Week: + myRealScale = KDGanttView::Day; + tempZoom = tempZoom/7; + break; + case KDGanttView::Month: + myRealScale = KDGanttView::Week ; + tempZoom = tempZoom*7/30; + break; + case KDGanttView::Auto: + break; + } + myRealMinorScaleCount = (int) ( myMinorScaleCount /tempZoom ); + } + } +} + + +void KDTimeHeaderWidget::computeTicks(bool doNotComputeRealScale) +{ + if (flagDoNotRecomputeAfterChange) return; + bool block = myGanttView->myTimeTable->blockUpdating(); + myGanttView->myTimeTable->setBlockUpdating( true ); + //qDebug("computeticks "); + majorTicks.clear(); + minorText.clear(); + majorText.clear(); + if ( !doNotComputeRealScale ) + saveCenterDateTime(); + if (!doNotComputeRealScale) + computeRealScale(myHorizonStart); + myRealStart = getEvenTimeDate(myHorizonStart ,myRealScale); + if (!doNotComputeRealScale) + computeRealScale(myRealStart); + int tempMinorScaleCount = myRealMinorScaleCount, + tempMajorScaleCount = myRealMajorScaleCount; + int minorItems,minorPerMajor = 1; + minorItems = (int) (secsFromTo( myRealStart, myHorizonEnd)/60.0); + //qDebug("tempMinorScaleCount %d ", tempMinorScaleCount); + QPainter p(this); + int Width, Height; + QString testTextMinor,testTextMajor, tempStr; + QRect itemRectMinor, itemRectMajor; + QDate tempDate = myRealStart.date(); + myRealEnd = myRealStart; + // preparing the testtext for the differennt scales + switch (myRealScale) + { + // the x in testTextMajor is added to reserve a little bit more space + case KDGanttView::Minute: + testTextMinor = "60"; + if (myHourFormat == KDGanttView::Hour_12) + testTextMajor = "Mon Aug 30, 12 AMx"; + else + testTextMajor = "Mon Aug 30, 24:00x"; + minorPerMajor = 6000; + break; + case KDGanttView::Hour: + minorItems = minorItems/60; + if (myHourFormat == KDGanttView::Hour_24) + testTextMinor = "24x"; + else + testTextMinor = "12 AM"; + testTextMajor = "Mon Aug 30, x"; + if ( yearFormat() != KDGanttView::NoDate ) + testTextMajor += getYear(QDate::currentDate()); + minorPerMajor = 2400; + break; + case KDGanttView::Day: + minorItems = minorItems/(60*24); + testTextMinor = "88"; + testTextMajor = "Aug 30, x"+getYear(QDate::currentDate()); + minorPerMajor = 700; + break; + case KDGanttView::Week: + minorItems = minorItems/(60*24*7); + testTextMinor = "88"; + testTextMajor = "Aug x"+getYear(QDate::currentDate()); + minorPerMajor = 435; // 435 = 365days/12months/7days * 100 + break; + case KDGanttView::Month: + minorItems = (minorItems*12)/(60*24*365); + testTextMinor = "M"; + testTextMajor = "x"+getYear(QDate::currentDate()); + minorPerMajor = 1200; + break; + case KDGanttView::Auto: + qDebug("KDGanttView::Internal Error in KDTimeHeaderWidget::computeTicks() "); + qDebug(" RealScale == Auto : This may not be! "); + break; + } + itemRectMinor = p.boundingRect ( 10, 10, 2, 2, Qt::AlignLeft,testTextMinor); + itemRectMajor = p.boundingRect ( 10, 10, 2, 2, Qt::AlignLeft,testTextMajor); + p.end(); + //qDebug(" tempMinorScaleCount %d ", tempMinorScaleCount); + Height = itemRectMinor.height()+itemRectMajor.height()+11; + Width = (itemRectMinor.width()+5); + if (Width < minimumColumnWidth()) Width = minimumColumnWidth(); + // if the desired width is greater than the maximum width of this widget + // increase the minorscalecount + int maxWid = myGanttView->myCanvasView->viewport()->width(); + if (!flagZoomToFit) + maxWid = maximumWidth(); + while((minorItems/tempMinorScaleCount+1)*Width > maxWid) + ++tempMinorScaleCount; + //qDebug(" tempMinorScaleCount %d ", tempMinorScaleCount); + mySizeHint = (minorItems/tempMinorScaleCount+1)*Width; + switch (myRealScale) + { + case KDGanttView::Minute: + if (tempMinorScaleCount < 60) + while (60%tempMinorScaleCount > 0 && 60%tempMinorScaleCount < 60) + ++tempMinorScaleCount; + if (tempMinorScaleCount >= 60) { + myRealScale = KDGanttView::Hour; + myRealMinorScaleCount = tempMinorScaleCount/ 60; + // myRealMinorScaleCount = 1; + myRealMajorScaleCount = 1; + qDebug("KDGantt::Overzoom:Rescaling from Minute to Hour"); + myGanttView->myTimeTable->setBlockUpdating( block ); + emit myGanttView->rescaling( KDGanttView::Hour ); + computeTicks(true); + return; + } + break; + case KDGanttView::Hour: + while (24%tempMinorScaleCount > 0 && 24%tempMinorScaleCount < 24) + ++tempMinorScaleCount; + if (tempMinorScaleCount >= 24) { + myRealScale = KDGanttView::Day; + myRealMinorScaleCount = tempMinorScaleCount/ 24; + //myRealMinorScaleCount = 1; + myRealMajorScaleCount = 1; + qDebug("KDGantt::Overzoom:Rescaling from Hour to Day"); + myGanttView->myTimeTable->setBlockUpdating( block ); + emit myGanttView->rescaling( KDGanttView::Day ); + computeTicks(true); + return; + } + break; + default: + break; + } + //flagZoomToFit = false; + while((minorItems/tempMinorScaleCount+1)*Width < myMinimumWidth ) { + ++minorItems; + } + minorItems = (minorItems/tempMinorScaleCount)+1; + // if not enough space for the text of the major scale, increase majorscalecount + minorPerMajor = (minorPerMajor*tempMajorScaleCount)/tempMinorScaleCount; + // checking, if enough space for majorscale + // if not, increasing MajorScaleCount + + while ((minorPerMajor*Width)/100 < itemRectMajor.width()) { + minorPerMajor = minorPerMajor/tempMajorScaleCount; + ++tempMajorScaleCount; + minorPerMajor = minorPerMajor*tempMajorScaleCount; + + } + // now we have the fixed width of the minorscale computed + myGridMinorWidth = Width; + // the width of this widget is the gridwidth * the amount of items + Width *= minorItems; + // if size changed, reset geometry + if (width() != Width || height() != Height ) + { + resize( Width, Height ); + emit sizeChanged( Width ); + } + myMajorGridHeight = itemRectMajor.height()+5; + QTime tempTime = myRealStart.time(); + QDateTime tempDateTime; + int i; + const KCalendarSystem * calendar = KGlobal::locale()->calendar(); + switch (myRealScale) + { + case KDGanttView::Minute: + myRealEnd = myRealEnd.addSecs((minorItems)*tempMinorScaleCount*60); + for ( i = 0; i < minorItems;++i) { + tempStr.setNum(tempTime.minute()); + minorText.append(tempStr); + tempTime = tempTime.addSecs(60*tempMinorScaleCount); + } + tempDateTime = myRealStart; + while (tempDateTime.time().minute() != 0) + tempDateTime = tempDateTime.addSecs(60); + while (tempDateTime < myRealEnd) { + majorTicks.append( getCoordX(tempDateTime)); + tempStr.setNum(tempDateTime.date().day()); + if ( yearFormat() == KDGanttView::NoDate ) { + tempStr = calendar->weekDayName( tempDateTime.date() )+", " + +getHour(tempDateTime.time()); + } else { + tempStr = calendar->weekDayName( tempDateTime.date(), true )+" "+ + calendar->monthName( tempDateTime.date().month(), tempDateTime.date().year(), true)+ " "+ + tempStr+", "+getHour(tempDateTime.time()); + } + + majorText.append(tempStr); + tempDateTime = tempDateTime.addSecs(3600*tempMajorScaleCount); + } + majorTicks.append( getCoordX(tempDateTime)); + break; + + case KDGanttView::Hour: + myRealEnd = myRealEnd.addSecs(minorItems*tempMinorScaleCount*60*60); + + for ( i = 0; i < minorItems;++i) { + tempStr = getHour(tempTime); + minorText.append(tempStr); + tempTime = tempTime.addSecs(3600*tempMinorScaleCount); + } + tempDateTime = myRealStart; + while (tempDateTime.time().hour() != 0) + tempDateTime = tempDateTime.addSecs(3600); + while (tempDateTime < myRealEnd) { + majorTicks.append( getCoordX(tempDateTime)); + tempStr.setNum(tempDateTime.date().day()); + if ( yearFormat() == KDGanttView::NoDate ) { + tempStr = calendar->weekDayName( tempDateTime.date() ); + } else { + tempStr = calendar->weekDayName( tempDateTime.date(), true )+" "+ + calendar->monthName( tempDateTime.date().month(), tempDateTime.date().year(), true)+ " "+ + tempStr+", "+getYear(tempDateTime.date()); + } + majorText.append(tempStr); + tempDateTime = tempDateTime.addDays(tempMajorScaleCount); + } + majorTicks.append( getCoordX(tempDateTime)); + break; + case KDGanttView::Day: + myRealEnd = myRealEnd.addDays(minorItems*tempMinorScaleCount); + for ( i = 0; i < minorItems;++i) { + if (tempMinorScaleCount == 1) + minorText.append((calendar->weekDayName(tempDate, true)).left(1)); //TODO: BIDI + else + minorText.append(QString::number(tempDate.day())); + tempDate = tempDate.addDays(tempMinorScaleCount); + } + tempDate = myRealStart.date(); + while (tempDate.dayOfWeek() != KGlobal::locale()->weekStartDay()) + tempDate = tempDate.addDays(1); + while (tempDate < myRealEnd.date()) { + majorTicks.append( getCoordX(tempDate)); + tempStr.setNum(tempDate.day()); + tempStr = calendar->monthName(tempDate.month(), tempDate.year(), true)+ " "+ + tempStr+", "+getYear(tempDate); + majorText.append(tempStr); + tempDate = tempDate.addDays(7*tempMajorScaleCount); + } + majorTicks.append( getCoordX(tempDate)); + break; + case KDGanttView::Week: + myRealEnd = myRealEnd.addDays(minorItems*tempMinorScaleCount*7); + for ( i = 0; i < minorItems;++i) { + tempStr.setNum(tempDate.day()); + minorText.append(tempStr); + tempDate = tempDate.addDays(7*tempMinorScaleCount); + } + tempDate = myRealStart.date(); + while (tempDate.day() != KGlobal::locale()->weekStartDay()) + tempDate = tempDate.addDays(1); + while (tempDate < myRealEnd.date()) { + majorTicks.append( getCoordX(tempDate)); + tempStr = calendar->monthName(tempDate.month(), tempDate.year(), true)+ " "+getYear(tempDate); + majorText.append(tempStr); + tempDate = tempDate.addMonths(tempMajorScaleCount); + } + majorTicks.append( getCoordX(tempDate)); + break; + case KDGanttView::Month: + myRealEnd = myRealEnd.addMonths(minorItems*tempMinorScaleCount); + for ( i = 0; i < minorItems;++i) { + minorText.append((calendar->monthName(tempDate.month(), tempDate.year(), true)).left(1)); //TODO: BIDI + tempDate = tempDate.addMonths(tempMinorScaleCount); + } + tempDate = myRealStart.date(); + while (tempDate.month() != 1) + tempDate = tempDate.addMonths(1); + while (tempDate < myRealEnd.date()) { + majorTicks.append( getCoordX(tempDate)); + tempStr = getYear(tempDate); + majorText.append(tempStr); + tempDate = tempDate.addYears(tempMajorScaleCount); + } + majorTicks.append( getCoordX(tempDate)); + break; + case KDGanttView::Auto: + break; + } + + if (flagDoNotRepaintAfterChange) { + myGanttView->myTimeTable->setBlockUpdating( block ); + return; + } + //qDebug("KDTimeHeaderWidget width %d, viewport width %d ",width (), myGanttView->myCanvasView->viewport()->width()); + myGanttView->myTimeTable->setBlockUpdating( block ); + updateTimeTable(); + centerDateTime(myCenterDateTime); + repaint(); +} + + +void KDTimeHeaderWidget::saveCenterDateTime() +{ + double wid = width(); + double allsecs = secsFromTo( myRealStart, myRealEnd ); + double center = myGanttView->myCanvasView->viewport()->width(); + center = center / 2; + center = center + myGanttView->myCanvasView->contentsX(); + double secs = (allsecs*center)/wid; + double days = secs/86400.0; + secs = secs - ( (int) days *86400.0 ); + myCenterDateTime = (myRealStart.addDays ( (int) days )).addSecs( (int) secs); +} + + +void KDTimeHeaderWidget::centerDateTime( const QDateTime& center ) +{ + moveTimeLineTo(getCoordX( center )-(myGanttView->myCanvasView->viewport()->width() /2)); + // qDebug("centerDateTime %s %d %d", center.toString().latin1(),getCoordX( center ),(myGanttView->myCanvasView->viewport()->width() /2) ); + +} + + +void KDTimeHeaderWidget::paintEvent(QPaintEvent *p) +{ + repaintMe(p->rect().x(),p->rect().width()); +} + + +int KDTimeHeaderWidget::getCoordX(QDate date) +{ + int wid = width(); + int daysAll = myRealStart.daysTo(myRealEnd); + if (daysAll == 0) return 0; + int days = myRealStart.daysTo(QDateTime(date)); + return (wid *days) /daysAll; +} + + +int KDTimeHeaderWidget::getCoordX(QDateTime datetime) +{ + double wid = width(); + double secsAll = secsFromTo( myRealStart, myRealEnd ); + if (secsAll == 0.0) return 0; + double secs = secsFromTo( myRealStart, datetime); + return ((int)((wid *(secs /secsAll))+0.5)); +} + + +QString KDTimeHeaderWidget::getYear(QDate date) +{ + QString ret; + ret.setNum(date.year()); + switch (yearFormat()) { + case KDGanttView::FourDigit: + // nothing to do + break; + case KDGanttView::TwoDigit: + ret = ret.right(2); + break; + case KDGanttView::TwoDigitApostrophe: + ret = "'"+ret.right(2); + break; + case KDGanttView::NoDate: + // nothing to do + break; + } + return ret; +} + + +QString KDTimeHeaderWidget::getHour(QTime time) +{ + QString ret; + int hour = time.hour(); + if (myHourFormat == KDGanttView::Hour_12) { + if (hour >= 12) { + if (hour > 12) hour -=12; + ret.setNum(hour); + ret = ret +" PM"; + } else { + if (hour == 0) hour = 12; + ret.setNum(hour); + ret = ret +" AM"; + } + } else { + if (myHourFormat == KDGanttView::Hour_24) + ret.setNum(hour); + else { + ret.setNum(hour); + ret += ":00"; + } + } + return ret; +} + + +void KDTimeHeaderWidget::mousePressEvent ( QMouseEvent * e ) +{ + mouseDown = false; + switch ( e->button() ) { + case LeftButton: + mouseDown = true; + beginMouseDown = e->pos().x(); + endMouseDown = e->pos().x(); + break; + case RightButton: + if (flagShowPopupMenu) + myPopupMenu->popup(e->globalPos()); + break; + case MidButton: + break; + default: + break; + } + +} + + +void KDTimeHeaderWidget::mouseReleaseEvent ( QMouseEvent * ) +{ + if ( mouseDown ) { + mouseDown = false; + // zoom to selection getDateTimeForIndex( + int start, end; + if ( beginMouseDown < endMouseDown ) { + start = beginMouseDown; + end = endMouseDown; + } else { + start = endMouseDown; + end = beginMouseDown; + } + if (start < 0 ) + start = 0; + if ( end > width() ) + end = width(); + //qDebug("start %s ",getDateTimeForIndex(start).toString().latin1() ); + //qDebug("end %s ",getDateTimeForIndex(end).toString().latin1() ); + emit myGanttView->timeIntervalSelected( getDateTimeForIndex(start),getDateTimeForIndex(end) ); + emit myGanttView->timeIntervallSelected( getDateTimeForIndex(start),getDateTimeForIndex(end) ); + //zoomToSelection( getDateTimeForIndex(start),getDateTimeForIndex(end) ); + } + mouseDown = false; + repaint(); +} + + +void KDTimeHeaderWidget::mouseDoubleClickEvent ( QMouseEvent * ) +{ + +} + + +void KDTimeHeaderWidget::mouseMoveEvent ( QMouseEvent * e ) +{ + if ( mouseDown ) { + if ( e->pos().y() < -height() || e->pos().y() > 2* height() ) { + mouseDown = false; + repaint(); + return; + } + endMouseDown = e->pos().x(); + //repaint; + int val = -1; + if (endMouseDown < -x() ) { + val = myGanttView->myCanvasView->horizontalScrollBar()->value() - + myGanttView->myCanvasView->horizontalScrollBar()->lineStep(); + if ( val < 0 ) { + val = 0; + } + } + if (endMouseDown > -x() +parentWidget()->width() ) { + val = myGanttView->myCanvasView->horizontalScrollBar()->value() + + myGanttView->myCanvasView->horizontalScrollBar()->lineStep(); + + } + repaintMe(-x(),parentWidget()->width()); + if ( val > -1 ) { + if ( val > myGanttView->myCanvasView->horizontalScrollBar()->maxValue() ) { + val = myGanttView->myCanvasView->horizontalScrollBar()->maxValue(); + } + myGanttView->myCanvasView->horizontalScrollBar()->setValue( val ); + } + //qDebug("mousemove %d %d %d %d",endMouseDown, -x(),parentWidget()->width() , e->pos().y()); + } +} + + +/* *************************************************************** + KDLegendWidget:: KDLegendWidget + ***************************************************************** */ +KDLegendWidget:: KDLegendWidget( QWidget* parent, + KDGanttMinimizeSplitter* legendParent ) : + KDGanttSemiSizingControl ( KDGanttSemiSizingControl::Before, Vertical, + parent) +{ + myLegendParent = legendParent; + dock = 0; + scroll = new QScrollView( legendParent ); + setMaximizedWidget( scroll ); + + setMinimizedWidget( myLabel = new QLabel( i18n( " Legend is hidden" ), this) ); + setGeometry( 0, 0, 50, 50 ); + myLegend = 0; + clearLegend(); + showMe ( false ); +} +void KDLegendWidget::setAsDockwindow( bool dockwin ) +{ + if ( (dock == 0 && !dockwin) || ( dock && dockwin ) ) + return; + if ( dockwin ) + { + setMaximizedWidget( 0 ); + showMe ( false ); + if ( dock ) delete dock; + dock = new QDockWindow(QDockWindow:: OutsideDock,0 ); + dock->resize( 200, 100 ); + dock->setHorizontallyStretchable( true ); + dock->setVerticallyStretchable( true ); + dock->setCaption(i18n("Legend: ") ); + dock->setResizeEnabled (true ); + delete myLegend; + myLegend = 0; + delete scroll; + scroll = new QScrollView( dock ); + clearLegend(); + dock->setWidget(scroll); + setMaximizedWidget( dock ); + showMe ( false ); + + } else { + setMaximizedWidget( 0 ); + showMe ( false ); + delete myLegend; + myLegend = 0; + delete scroll; + delete dock; + dock = 0; + scroll = new QScrollView( myLegendParent ); + clearLegend(); + setMaximizedWidget( scroll ); + showMe ( false ); + } + +} + + +bool KDLegendWidget::asDockwindow( ) +{ + if ( dock ) + return true; + return false; +} + + +QDockWindow* KDLegendWidget::dockwindow( ) +{ + return dock; +} + + +void KDLegendWidget::setFont( QFont font) +{ + myLegend->setFont( font); + myLabel->setFont( font); + QWidget::setFont( font ); +} + + +void KDLegendWidget::drawToPainter( QPainter *p ) +{ + p->drawPixmap( 0, 0, QPixmap::grabWidget( myLegend ) ); +} + + +QSize KDLegendWidget::legendSize() +{ + return myLegend->size(); +} + + +QSize KDLegendWidget::legendSizeHint() +{ + QApplication::sendPostedEvents( 0, QEvent::LayoutHint ); + return QSize( myLegend->sizeHint().width(), myLegend->sizeHint().height()+scroll->horizontalScrollBar()->height()); +} + + +void KDLegendWidget::showMe ( bool show ) +{ + minimize( !show ); +} + + +void KDLegendWidget::clearLegend ( ) +{ + if ( myLegend ) delete myLegend; + if ( dock ) + myLegend = new QGroupBox( 1, Qt::Horizontal, scroll->viewport() ); + else + myLegend = new QGroupBox( 1, Qt::Horizontal, i18n( "Legend" ), scroll->viewport() ); + myLegend->setBackgroundColor( Qt::white ); + myLegend->setFont( font() ); + scroll->addChild( myLegend ); + scroll->setResizePolicy( QScrollView::AutoOneFit ); + myLegend->layout()->setMargin( 11 ); + myLegend->setFrameStyle( QFrame::NoFrame ); + if ( dock ) + scroll->setMaximumHeight( 32000 ); + else + scroll->setMaximumHeight( legendSizeHint().height() ); +} + + +void KDLegendWidget::addLegendItem( KDGanttViewItem::Shape shape, const QColor& shapeColor, const QString& text ) +{ + QLabel * temp; + QPixmap p = KDGanttView::getPixmap( shape, shapeColor, Qt::white, 10); + QWidget *w = new QWidget( myLegend ); + w->setBackgroundColor( Qt::white ); + QHBoxLayout *lay = new QHBoxLayout( w ,0, 6); + temp = new QLabel ( w ); + lay->addWidget( temp, 0, Qt:: AlignRight); + temp->setPixmap(p); + temp = new QLabel ( text, w ); + temp->setBackgroundColor( Qt::white ); + lay->addWidget( temp, 0, Qt:: AlignLeft); + lay->addStretch(); + if ( dock ) + scroll->setMaximumHeight( 32000 ); + else + scroll->setMaximumHeight( legendSizeHint().height() ); +} + + +bool KDLegendWidget::isShown ( ) +{ + return !isMinimized(); +} + + +KDListView::KDListView(QWidget* parent, KDGanttView* gantView):QListView (parent) +{ + myGanttView = gantView; + setAcceptDrops(true); + new KDListViewWhatsThis(viewport(),this); + setRootIsDecorated( true ); + setAllColumnsShowFocus( true ); + addColumn( i18n( "Task Name" ) ); + setSorting( -1 ); + //setVScrollBarMode (QScrollView::AlwaysOn ); + setHScrollBarMode (QScrollView::AlwaysOn ); + setDefaultRenameAction(QListView::Accept); + setColumnWidthMode ( 0,Maximum ); + _calendarMode = false; + // QObject::connect(this, SIGNAL ( pressed ( QListViewItem * )) , this, SLOT( dragItem( QListViewItem *))) ; +} + + +void KDListView::dragItem( QListViewItem * ) +{ + // qDebug("drag "); + // startDrag(); +} +QString KDListView::getWhatsThisText(QPoint p) +{ + KDGanttViewItem* item = ( KDGanttViewItem* ) itemAt( p ); + if ( item ) + return item->whatsThisText(); + return i18n( "No item Found" ); +} + +void KDListView::setCalendarMode( bool mode ) +{ + _calendarMode = mode; + // setRootIsDecorated ( ! mode ); +} + +void KDListView::setOpen(QListViewItem * item, bool open ) +{ + if (! _calendarMode || ! open ) { + (( KDGanttViewItem*)item)->setCallListViewOnSetOpen( false ); + QListView::setOpen ( item, open ); + (( KDGanttViewItem*)item)->setCallListViewOnSetOpen( true ); + return; + } + // we are in calendarmode + // in calendarmode only items can be opened which have subitems which have subitems + + QListViewItem* temp; + temp = item->firstChild(); + bool openItem = false; + while (temp) { + if ( (( KDGanttViewItem*)temp)->displaySubitemsAsGroup() ) { + temp->setVisible( true ); + openItem = true; + } + else { + temp->setVisible( false ); + //qDebug(" temp->setVisible( false );"); + } + temp = temp->nextSibling(); + } + if ( openItem ) { + (( KDGanttViewItem*)item)->setCallListViewOnSetOpen( false ); + QListView::setOpen ( item, open ); + (( KDGanttViewItem*)item)->setCallListViewOnSetOpen( true ); + } +} + + +void KDListView::contentsMouseDoubleClickEvent ( QMouseEvent * e ) +{ + QListView::contentsMouseDoubleClickEvent ( e ); + //if ( ! _calendarMode ) + // QListView::contentsMouseDoubleClickEvent ( e ); + // else + { + + emit myGanttView->lvItemDoubleClicked ( (KDGanttViewItem*) itemAt(e->pos() ) ); + emit myGanttView->itemDoubleClicked ( (KDGanttViewItem*) itemAt(e->pos() ) ); + } + +} + + +void KDListView::drawToPainter ( QPainter * p, bool drawHeader ) +{ + // Draw list + drawAllContents ( p, 0, 0, contentsWidth(), contentsHeight() ); + if (!drawHeader) { + return; + } + // Draw headers + QPen pen = QPen(Qt::lightGray, 1); + p->save(); + QHeader *h = header(); + for (int s = 0; s < h->count(); ++s) { + QRect r = h->sectionRect(s); + if (s==0) { + p->translate(0, -r.height()); + } + //kdDebug()<label(s)<<" "<drawText(r.x()+2, r.y(), r.width()-2, r.height(), columnAlignment(s)|Qt::AlignVCenter, h->label(s), -1); + p->save(); + p->setPen(pen); + p->drawRect(r.x(), r.y()+1, r.width(), r.height()-2); + p->restore(); + + } + p->restore(); +} + +int KDListView::buildDrawables(QPtrList &lst, int level, int ypos, QListViewItem *item, int ymin, int ymax) const { + int y = ypos; + int ih = item->height(); + if (y < ymin && y+ih > ymin) { + y = ymin; // include partial item at top + } + if (y >= ymin && y < ymax) { // include partial item at bottom + KDListView::DrawableItem *dr = new KDListView::DrawableItem(level, y, item); + lst.append(dr); + //kdDebug()<text(0)<isOpen()) { + QListViewItem *child = item->firstChild(); + for (; child; child = child->nextSibling()) { + y = buildDrawables(lst, level+1, y, child, ymin, ymax); + } + } + return y; +} +// This is a copy of QListView::drawContentsOffset(), with a few changes +// because drawContentsOffset() only draws *visible* items, +// we want to draw *all* items. +// FIXME: Haven't got paintBraches() to work, atm live without it. +void KDListView::drawAllContents(QPainter * p, int cx, int cy, int cw, int ch) { + if ( columns() == 0 ) { + paintEmptyArea( p, QRect( cx, cy, cw, ch ) ); + return; + } + //kdDebug()< drawables; + drawables.setAutoDelete(true); + QListViewItem *child = firstChild(); + int level = 0; + int ypos = 0; + for (; child; child = child->nextSibling()) { + ypos = buildDrawables(drawables, level, ypos, child, cy, cy+ch); + } + + p->setFont( font() ); + + QPtrListIterator it(drawables); + + QRect r; + int fx = -1, x, fc = 0, lc = 0; + int tx = -1; + KDListView::DrawableItem * current; + + while ( (current = it.current()) != 0 ) { + ++it; + int ih = current->i->height(); + int ith = current->i->totalHeight(); + int c; + int cs; + + // need to paint current? + if ( ih > 0 && current->y < cy+ch && current->y+ih > cy ) { + //kdDebug()<i->text(0)<<" y="<y<cellSize( 0 ); + while ( x + cs <= cx && c < header()->count() ) { + x += cs; + c++; + if ( c < header()->count() ) + cs = header()->cellSize( c ); + } + fx = x; + fc = c; + while( x < cx + cw && c < header()->count() ) { + x += cs; + c++; + if ( c < header()->count() ) + cs = header()->cellSize( c ); + } + lc = c; + } + + x = fx; + c = fc; + // draw to last interesting column + + const QColorGroup &cg = ( palette().inactive() ); + + while ( c < lc && !drawables.isEmpty() ) { + int i = header()->mapToLogical( c ); + cs = header()->cellSize( c ); + r.setRect( x, current->y-cy, cs, ih ); + if ( i == 0 ) + r.setLeft( r.left() + current->l * treeStepSize() ); + + p->save(); + // No need to paint if the cell isn't technically visible + if ( !( r.width() == 0 || r.height() == 0 ) ) { + p->translate( r.left(), r.top() ); + int ac = header()->mapToLogical( c ); + // map to Left currently. This should change once we + // can really reverse the listview. + int align = columnAlignment( ac ); + if ( align == AlignAuto ) align = AlignLeft; + bool sel = current->i->isSelected(); + if (sel) + current->i->setSelected(false); + current->i->paintCell( p, cg, ac, r.width(), align ); + if (sel) + current->i->setSelected(sel); + } + p->restore(); + x += cs; + c++; + } + + } + + const int cell = header()->mapToActual( 0 ); + + if ( tx < 0 ) + tx = header()->cellPos( cell ); + + // do any children of current need to be painted? +/* FIXME: painting branches doesn't work for some reason... + if ( ih != ith && + rootIsDecorated() && + current->y + ith > cy && + current->y + ih < cy + ch && + tx + current->l * treeStepSize() < cx + cw && + tx + (current->l+1) * treeStepSize() > cx ) { + // compute the clip rectangle the safe way + + int rtop = current->y + ih; + int rbottom = current->y + ith; + int rleft = tx + current->l*treeStepSize(); + int rright = rleft + treeStepSize(); + + int crtop = QMAX( rtop, cy ); + int crbottom = QMIN( rbottom, cy+ch ); + int crleft = QMAX( rleft, cx ); + int crright = QMIN( rright, cx+cw ); + + r.setRect( crleft, crtop, + crright-crleft, crbottom-crtop ); + + if ( r.isValid() ) { + p->save(); + p->translate( rleft, crtop ); + //kdDebug()<i->text(0)<i->paintBranches( p, colorGroup(), treeStepSize(), + rtop - crtop, r.height() ); + p->restore(); + } + }*/ + } +} + +void KDListView::resizeEvent(QResizeEvent *) +{ + triggerUpdate (); +} +void KDListView::dragEnterEvent ( QDragEnterEvent * e) +{ + if ( !myGanttView->dropEnabled() ) { + e->accept( false ); + return; + } + myGanttView->lvDragEnterEvent(e); + //e->accept(KDGanttViewItemDrag::canDecode(e) ); +} + +void KDListView::dragMoveEvent ( QDragMoveEvent * e) +{ + if ( !myGanttView->dropEnabled() ) { + e->accept( false ); + return; + } + KDGanttViewItem* draggedItem = 0; + KDGanttViewItem* gItem = (KDGanttViewItem*)itemAt( e->pos()) ; + setCurrentItem( gItem ); + if ( e->source() == myGanttView ) + draggedItem = myGanttView->myCanvasView->lastClickedItem; + // execute user defined dragMoveEvent handling + if (myGanttView->lvDragMoveEvent ( e , draggedItem, gItem ) ) + return; + if ( !KDGanttViewItemDrag::canDecode(e) ) { + e->accept( false ); + return; + } + if ( e->source() == myGanttView && gItem ){ + // internal drag - do not allow to drag the item to a subitem of itself + KDGanttViewItem* pItem = gItem->parent(); + while ( pItem ) { + if ( pItem == myGanttView->myCanvasView->lastClickedItem ) { + e->accept( false ); + return; + } + pItem = pItem->parent(); + } + if ( gItem == myGanttView->myCanvasView->lastClickedItem ) { + e->accept( false ); + return; + } + } + e->accept( true ); +} + +void KDListView::dragLeaveEvent ( QDragLeaveEvent * ) +{ + //qDebug("contentsDragLeaveEvent "); +} +void KDListView::dropEvent ( QDropEvent *e ) +{ + if ( !myGanttView->dropEnabled() ) { + e->accept( false ); + return; + } + KDGanttViewItem* gItem = (KDGanttViewItem*)itemAt( e->pos()) ; + KDGanttViewItem* draggedItem = 0; + if ( e->source() == myGanttView ) + draggedItem = myGanttView->myCanvasView->lastClickedItem; + if (myGanttView->lvDropEvent ( e, draggedItem, gItem )) + return; + QString string; + KDGanttViewItemDrag::decode( e, string ); + KDGanttViewItem* newItem = 0; + + if ( gItem == myGanttView->myCanvasView->lastClickedItem && gItem != 0 ) { + qDebug("KDGanttView::Possible bug in drag&drop code "); + return; + } + + QDomDocument doc( "GanttView" ); + doc.setContent( string ); + QDomElement docRoot = doc.documentElement(); // ChartParams element + QDomNode node = docRoot.firstChild(); + bool enable = myGanttView->myTimeTable->blockUpdating( ); + myGanttView->myTimeTable->setBlockUpdating( true ); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Items" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Item" ) { + if ( gItem ) + newItem = KDGanttViewItem::createFromDomElement( gItem, + element ); + else + newItem = KDGanttViewItem::createFromDomElement( myGanttView, + element ); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + //qDebug("next node1 "); + node = node.nextSibling(); + } + } + } + //qDebug("next node2 "); + node = node.nextSibling(); + } + newItem->setDisplaySubitemsAsGroup(myGanttView->displaySubitemsAsGroup()); + newItem->resetSubitemVisibility(); + myGanttView->slot_lvDropped(e, draggedItem, gItem); + myGanttView->myTimeTable->setBlockUpdating( enable ); + myGanttView->myTimeTable->updateMyContent(); + return; +} + +QDragObject * KDListView::dragObject () +{ + return QListView::dragObject (); +} + +void KDListView::startDrag () +{ + if ( ! myGanttView->dragEnabled() ) + return; + KDGanttViewItem* cItem = (KDGanttViewItem*) currentItem (); + myGanttView->myCanvasView->lastClickedItem = cItem; + myGanttView->lvStartDrag (cItem); +} + +KDCanvasText::KDCanvasText( KDTimeTableWidget* canvas, + void* parentItem, + int type ) : + QCanvasText(canvas) +{ + myParentType = type; + myParentItem = parentItem; +} + + +KDCanvasLine::KDCanvasLine( KDTimeTableWidget* canvas, + void* parentItem, + int type ) : + QCanvasLine(canvas) +{ + myParentType = type; + myParentItem = parentItem; +} + + +KDCanvasPolygonItem::KDCanvasPolygonItem( KDTimeTableWidget* canvas, + void* parentItem, + int type ) : + QCanvasPolygonalItem( canvas ) +{ + myParentType = type; + myParentItem = parentItem; +} + + +KDCanvasPolygon::KDCanvasPolygon( KDTimeTableWidget* canvas, + void* parentItem, + int type ) : + QCanvasPolygon( canvas ) +{ + myParentType = type; + myParentItem = parentItem; +} + + +KDCanvasEllipse::KDCanvasEllipse( KDTimeTableWidget* canvas, + void* parentItem, + int type ) : + QCanvasEllipse( canvas ) +{ + myParentType = type; + myParentItem = parentItem; +} + + +KDCanvasRectangle::KDCanvasRectangle( KDTimeTableWidget* canvas, + void* parentItem, + int type ) : + QCanvasRectangle( canvas ) +{ + myParentType = type; + myParentItem = parentItem; +} + + + + +KDGanttCanvasView::KDGanttCanvasView( KDGanttView* sender,QCanvas* canvas, QWidget* parent, const + char* name ) : QCanvasView ( canvas, parent, name ), + movingGVItem( 0 ), + scrollBarTimer( 0, "scrollBarTimer" ) +{ + setHScrollBarMode (QScrollView::AlwaysOn ); + setVScrollBarMode( QScrollView::AlwaysOn ); + myToolTip = new KDCanvasToolTip(viewport(),this); + mySignalSender = sender; + currentItem = 0; + currentLink = 0; + cuttedItem = 0; + fromItem = 0; + fromArea = 0; + linkItemsEnabled = false; + mouseDown = false; + linkLine = new QCanvasLine(canvas); + linkLine->hide(); + linkLine->setZ(1000); + set_Mouse_Tracking(true); // mouse cursor changes over KDIntervalColorRectangle borders + new KDCanvasWhatsThis(viewport(),this); + onItem = new QPopupMenu( this ); + QPopupMenu * newMenu = new QPopupMenu( this ); + QPopupMenu * onView = new QPopupMenu( this ); + onView->insertItem( i18n( "Summary" ), this, + SLOT ( newRootItem( int ) ), 0, 0 ); + onView->insertItem( i18n( "Event" ), this, + SLOT ( newRootItem( int ) ), 0, 1); + onView->insertItem( i18n( "Task" ), this, + SLOT ( newRootItem( int ) ), 0, 2 ); + + onItem->insertItem( i18n( "New Root" ), onView ); + newMenu->insertItem( i18n( "Summary" ), + this, SLOT ( newChildItem( int) ), 0, 0 ); + newMenu->insertItem( i18n( "Event" ), + this, SLOT ( newChildItem( int ) ), 0, 1 ); + newMenu->insertItem( i18n( "Task" ), + this, SLOT ( newChildItem( int ) ), 0, 2 ); + + onItem->insertItem( i18n( "New Child" ), newMenu ); + QPopupMenu * afterMenu = new QPopupMenu( this ); + afterMenu->insertItem( i18n( "Summary" ), + this, SLOT ( newChildItem( int) ), 0, 0+4 ); + afterMenu->insertItem( i18n( "Event" ), + this, SLOT ( newChildItem( int ) ), 0, 1+4 ); + afterMenu->insertItem( i18n( "Task" ), + this, SLOT ( newChildItem( int ) ), 0, 2+4 ); + onItem->insertItem( i18n( "New After" ), afterMenu ); + QPopupMenu *pasteMenu = new QPopupMenu( this ); + pasteMenu->insertItem( i18n( "As Root" ), + this, SLOT ( pasteItem( int ) ), 0, 0 ); + pasteMenu->insertItem( i18n( "As Child" ), + this, SLOT ( pasteItem( int ) ), 0, 1 ); + pasteMenu->insertItem( i18n( "After" ), + this, SLOT ( pasteItem( int ) ), 0, 2 ); + onItem->insertItem( i18n( "Paste" ), pasteMenu, 3 ); + onItem->insertItem( i18n( "Cut Item" ), this, SLOT ( cutItem() ) ); + onItem->setItemEnabled( 3, false ); + myMyContentsHeight = 0; + _showItemAddPopupMenu = false; + + QObject *scrollViewTimer = child( "scrollview scrollbar timer", "QTimer", false ); + Q_ASSERT( scrollViewTimer ); + if ( scrollViewTimer ) { + disconnect( scrollViewTimer, SIGNAL(timeout()), this, SLOT(updateScrollBars() ) ); + } + // If they needed a scrollbar timer in scrollview... + connect( &scrollBarTimer, SIGNAL(timeout()), this, SLOT(myUpdateScrollBars() ) ); + + myScrollTimer = new QTimer( this, "myScrollTimer" ); + connect( myScrollTimer, SIGNAL( timeout() ), SLOT( slotScrollTimer() ) ); + autoScrollEnabled = false; +} + + +KDGanttCanvasView::~KDGanttCanvasView() +{ + delete myToolTip; +} + + +void KDGanttCanvasView::setShowPopupMenu( bool show ) +{ + _showItemAddPopupMenu = show; +} +bool KDGanttCanvasView::showPopupMenu() +{ + return _showItemAddPopupMenu; +} + + +void KDGanttCanvasView::moveMyContent( int, int y) +{ + setContentsPos(contentsX(), y); +} + +void KDGanttCanvasView::resizeEvent ( QResizeEvent * e ) +{ + int ho = e->oldSize().height(); + int wo = e->oldSize().width(); + int hi = height(); + int wi = width(); + //QScrollView::blockSignals( true ); + + verticalScrollBar()->setUpdatesEnabled( false ); + QScrollView::resizeEvent ( e ) ; + if ( ho != hi ) + emit heightResized( viewport()->height()); + if ( wo != wi ) + emit widthResized( viewport()->width() ); + //setMyContentsHeight( 0 ); // via timer + //QScrollView::blockSignals( false ); + scrollBarTimer.start(0, true); +} + +void KDGanttCanvasView::myUpdateScrollBars() +{ + setMyContentsHeight( 0 ); +} +void KDGanttCanvasView::setMyContentsHeight( int hei ) +{ + //qDebug("setMyContentsHeight %d %d ", hei, myMyContentsHeight); + if ( hei > 0 ) + myMyContentsHeight = hei; + verticalScrollBar()->setUpdatesEnabled( true ); // set false in resizeEvent() + if ( viewport()->height() <= myMyContentsHeight ) + verticalScrollBar()->setRange( 0, myMyContentsHeight- viewport()->height()+1); + else + verticalScrollBar()->setRange( 0,0 ); + // testing for unmatching ScrollBar values of timeheader and timetable + // may happen after external resizing + if ( horizontalScrollBar()->value() != mySignalSender->myTimeHeaderScroll->horizontalScrollBar()->value() ) { + // I am the Boss! + mySignalSender->myTimeHeaderScroll->horizontalScrollBar()->setValue(horizontalScrollBar()->value() ); + + } + +} + +// Call after *internal* resizing (like addTickRight()) +// Then the new scrollbar maxValue is in myTimeHeader. +void KDGanttCanvasView::updateHorScrollBar() { + //qDebug("horizontalScrollBar max=%d, myTimeHeaderScroll=%d", horizontalScrollBar()->maxValue(), mySignalSender->myTimeHeaderScroll->horizontalScrollBar()->value()); + + horizontalScrollBar()->setRange(mySignalSender->myTimeHeaderScroll->horizontalScrollBar()->minValue(), mySignalSender->myTimeHeaderScroll->horizontalScrollBar()->maxValue()); + +} + +void KDGanttCanvasView::cutItem( KDGanttViewItem* item ) +{ + lastClickedItem = item; + cutItem(); +} +void KDGanttCanvasView::insertItemAsRoot( KDGanttViewItem* item ) +{ + mySignalSender->myListView->insertItem( item ); + if ( item == cuttedItem ) + cuttedItem = 0; +} +void KDGanttCanvasView::insertItemAsChild( KDGanttViewItem* parent, KDGanttViewItem* item ) +{ + parent->insertItem( cuttedItem ); + if ( item == cuttedItem ) + cuttedItem = 0; +} +void KDGanttCanvasView::insertItemAfter( KDGanttViewItem* parent , KDGanttViewItem* item ) +{ + if ( parent->parent() ) { + parent->parent()->insertItem( item ); + } + else + mySignalSender->myListView->insertItem( item ); + item->moveItem( parent ); + if ( item == cuttedItem ) + cuttedItem = 0; +} + +void KDGanttCanvasView::cutItem() +{ + lastClickedItem->hideSubtree(); + //qDebug("last clicked %d parent %d ", lastClickedItem , lastClickedItem->parent()); + if ( lastClickedItem->parent() ) + lastClickedItem->parent()->takeItem(lastClickedItem); + else + mySignalSender->myListView->takeItem( lastClickedItem ); + mySignalSender->myTimeTable->updateMyContent(); + if ( cuttedItem ) + delete cuttedItem; + cuttedItem = lastClickedItem; + onItem->setItemEnabled( 3, true ); + +} +// called from the destructor in KDGanttViewItem or KDGanttView + +void KDGanttCanvasView::resetCutPaste( KDGanttViewItem* item ) +{ + if ( item == 0 && cuttedItem ) { + delete cuttedItem; + cuttedItem = 0; + } + if (item == cuttedItem) { + onItem->setItemEnabled( 3, false ); + cuttedItem = 0; + } +} + +void KDGanttCanvasView::pasteItem( int type ) +{ + if ( !cuttedItem ) + return; + switch( type ) { + case 0://root + mySignalSender->myListView->insertItem( cuttedItem ); + break; + case 1://child + lastClickedItem->insertItem( cuttedItem ); + break; + case 2://after + if ( lastClickedItem->parent() ) { + lastClickedItem->parent()->insertItem( cuttedItem ); + } + else + mySignalSender->myListView->insertItem( cuttedItem ); + cuttedItem->moveItem( lastClickedItem ); + break; + default: + ; + } + cuttedItem = 0; + onItem->setItemEnabled( 3, false ); + mySignalSender->myTimeTable->updateMyContent(); +} +void KDGanttCanvasView::newRootItem(int type) +{ + KDGanttViewItem* temp = 0; + switch( type ) { + case 1: + temp = new KDGanttViewEventItem( mySignalSender, i18n( "New Event" ) ); + break; + case 0: + temp = new KDGanttViewSummaryItem( mySignalSender, i18n( "New Summary" ) ); + break; + case 2: + temp = new KDGanttViewTaskItem( mySignalSender, i18n( "New Task" ) ); + break; + default: + ; + } + if ( temp ) + mySignalSender->editItem( temp ); +} + +void KDGanttCanvasView::newChildItem( int type ) +{ + KDGanttViewItem* temp = 0; + switch( type ) { + case 1: + temp = new KDGanttViewEventItem( lastClickedItem, i18n( "New Event" ) ); + break; + case 0: + temp = new KDGanttViewSummaryItem( lastClickedItem, i18n( "New Summary" ) ); + break; + case 2: + temp = new KDGanttViewTaskItem( lastClickedItem, i18n( "New Task" ) ); + break; + case 5: + if ( lastClickedItem->parent() ) + temp = new KDGanttViewEventItem( lastClickedItem->parent(), lastClickedItem, i18n( "New Event" ) ); + else + temp = new KDGanttViewEventItem( mySignalSender, lastClickedItem, i18n( "New Event" ) ); + break; + case 4: + if ( lastClickedItem->parent() ) + temp = new KDGanttViewSummaryItem( lastClickedItem->parent(), lastClickedItem, i18n( "New Summary" ) ); + else + temp = new KDGanttViewSummaryItem( mySignalSender, lastClickedItem, i18n( "New Summary" ) ); + break; + case 6: + if ( lastClickedItem->parent() ) + temp = new KDGanttViewTaskItem( lastClickedItem->parent(), lastClickedItem, i18n( "New Task" ) ); + else + temp = new KDGanttViewTaskItem( mySignalSender, lastClickedItem, i18n( "New Task" ) ); + break; + + + default: + ; + } + if ( temp ) + mySignalSender->editItem( temp ); +} + +void KDGanttCanvasView::drawToPainter ( QPainter * p ) +{ + drawContents ( p, 0, 0, canvas()->width(), canvas()->height() ); +} +QString KDGanttCanvasView::getToolTipText(QPoint p) +{ + QCanvasItemList il = canvas()->collisions ( viewportToContents( p )); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + return (getItem(*it))->tooltipText(); + break; + case Type_is_KDGanttTaskLink: + return (getLink(*it))->tooltipText(); + break; + default: + break; + } + } + return ""; +} + +QString KDGanttCanvasView::getWhatsThisText(QPoint p) +{ + QCanvasItemList il = canvas() ->collisions (viewportToContents( p )); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + return (getItem(*it))->whatsThisText(); + break; + case Type_is_KDGanttTaskLink: + return (getLink(*it))->whatsThisText(); + break; + default: + break; + } + } + return ""; +} + + +KDGanttCanvasView::MovingOperation KDGanttCanvasView::gvItemHitTest( KDGanttViewItem *item, KDTimeHeaderWidget* timeHeader, const QPoint &pos ) +{ + const int left = timeHeader->getCoordX( item->startTime() ); + const int right = timeHeader->getCoordX( item->endTime() ); + const int width = right - left + 1; + const int x = pos.x(); + if ( x < left + width / 10 ) + return KDGanttCanvasView::ResizingLeft; + if ( x > right - width / 10 ) + return KDGanttCanvasView::ResizingRight; + return KDGanttCanvasView::Moving; +} + +/** + Handles the mouseevent if a mousekey is pressed + + \param e the mouseevent + +*/ + +void KDGanttCanvasView::contentsMousePressEvent ( QMouseEvent * e ) +{ + //qDebug("mousepress! %d ", this); + //qDebug("focus %d ",qApp->focusWidget()); + setFocus(); + currentLink = 0; + currentItem = 0; + movingItem = 0; + mouseDown = true; + if (e->button() == RightButton && mySignalSender->editable()) { + lastClickedItem = (KDGanttViewItem*) mySignalSender->myListView->itemAt( QPoint(2,e->pos().y())); + if ( lastClickedItem ) { + if ( lastClickedItem->displaySubitemsAsGroup() && ! lastClickedItem->isOpen() ) { + // findSub subitem + QCanvasItemList il = canvas() ->collisions ( e->pos() ); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + if ( getType(*it) == Type_is_KDGanttViewItem ) { + lastClickedItem = getItem(*it); + } + } + } + if ( _showItemAddPopupMenu ) + onItem->popup(e->globalPos()); + } + } + QCanvasItemList il = canvas() ->collisions ( e->pos() ); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + switch ( e->button() ) { + case LeftButton: + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + currentItem = getItem(*it); + if (! currentItem->enabled() ) { + currentItem = 0; + } else if (linkItemsEnabled && + !currentItem->isMyTextCanvas(*it)) { + fromArea = getItemArea(currentItem, e->pos().x()); + if (fromArea > 0) { + fromItem = currentItem; + linkLine->setPoints(e->pos().x(), e->pos().y(), e->pos().x(), e->pos().y()); + linkLine->show(); + } + } + { + KDCanvasRectangle *rect = dynamic_cast( *it ); + if ( rect ) { + movingGVItem = dynamic_cast( getItem( rect ) ); + if ( movingGVItem ) { + movingStart = e->pos(); + movingStartDate = movingGVItem->startTime(); + movingOperation = gvItemHitTest( movingGVItem, mySignalSender->myTimeHeader, e->pos() ); + if ( movingOperation == Moving && !movingGVItem->isMoveable() ) + movingGVItem = 0; + else if ( movingOperation != Moving && !movingGVItem->isResizeable() ) + movingOperation = Moving; + } else { + movingGVItem = 0; + } + } + } + break; + case Type_is_KDGanttTaskLink: + currentLink = getLink(*it); + break; + case Type_is_KDGanttGridItem: + if ( (*it)->rtti() == KDIntervalColorRectangle::RTTI ) { + // Cleaner would be isMovable()/isResizeable() in an interface + // implemented by all movable objects... + movingItem = static_cast(*it); + movingStart = e->pos(); + KDIntervalColorRectangle* icr = static_cast( movingItem ); + KDIntervalColorRectangle::HitTest hitTest = icr->hitTest( mySignalSender->myTimeHeader, movingStart ); + movingOperation = hitTest == KDIntervalColorRectangle::Start ? ResizingLeft : + hitTest == KDIntervalColorRectangle::End ? ResizingRight : + Moving; + } + break; + default: + break; + } + break; + case RightButton: + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + currentItem = getItem(*it); + if (! currentItem->enabled() ) + currentItem = 0; + break; + case Type_is_KDGanttTaskLink: + currentLink = getLink(*it); + break; + } + break; + case MidButton: + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + currentItem = getItem(*it); + if (! currentItem->enabled() ) + currentItem = 0; + break; + case Type_is_KDGanttTaskLink: + currentLink = getLink(*it); + break; + } + break; + default: + break; + } + } + if (e->button() == RightButton ) { + mySignalSender->gvContextMenuRequested( currentItem, e->globalPos() ); + } + if (autoScrollEnabled && e->button() == LeftButton) { + myScrollTimer->start(50); + } +} +/** + Handles the mouseevent if a mousekey is released + + \param e the mouseevent + +*/ + +void KDGanttCanvasView::contentsMouseReleaseEvent ( QMouseEvent * e ) +{ + mouseDown = false; + static KDGanttViewItem* lastClicked = 0; + mySignalSender->gvMouseButtonClicked( e->button(), currentItem , e->globalPos() ); + //qDebug("datetime %s ",mySignalSender->getDateTimeForCoordX(e->globalPos().x(), true ).toString().latin1() ); + //qDebug("mousepos %d %d ",e->pos().x(),e->pos().y() ); + //qDebug("mouseup "); + // if ( currentLink || currentItem ) + { + switch ( e->button() ) { + case LeftButton: + myScrollTimer->stop(); + { + mySignalSender->itemLeftClicked( currentItem ); + mySignalSender->gvItemLeftClicked( currentItem ); + } + if ( currentLink ) + mySignalSender->taskLinkLeftClicked( currentLink ); + if (linkItemsEnabled && fromItem) { + linkLine->hide(); + canvas()->update(); + QCanvasItemList il = canvas() ->collisions ( e->pos() ); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + if (getType(*it) == Type_is_KDGanttViewItem) { + KDGanttViewItem *toItem = getItem(*it); + if (!toItem->isMyTextCanvas(*it)) { + int toArea = getItemArea(toItem, e->pos().x()); + if (toArea > 0 && toItem && fromItem != toItem) { + mySignalSender->linkItems(fromItem, toItem, getLinkType(fromArea, toArea)); + } + } + break; + } + } + } + fromItem = 0; + if ( movingGVItem ) { + mySignalSender->gvItemMoved( movingGVItem ); + movingGVItem = 0; + } + break; + case RightButton: + { + mySignalSender->itemRightClicked( currentItem ); + mySignalSender->gvItemRightClicked( currentItem ); + + } + if ( currentLink ) + mySignalSender->taskLinkRightClicked( currentLink ); + break; + case MidButton: + { + mySignalSender->itemMidClicked( currentItem ); + mySignalSender->gvItemMidClicked( currentItem ); + } + if ( currentLink ) + mySignalSender->taskLinkRightClicked( currentLink ); + break; + default: + break; + } + } + if ( lastClicked != currentItem ) + mySignalSender->gvCurrentChanged( currentItem ); + lastClicked = currentItem; + currentLink = 0; + currentItem = 0; +} +/** + Handles the mouseevent if a mousekey is doubleclicked + + \param e the mouseevent + +*/ + +void KDGanttCanvasView::contentsMouseDoubleClickEvent ( QMouseEvent * e ) +{ + QCanvasItemList il = canvas() ->collisions ( e->pos() ); + + if ( il.isEmpty() && e->button() == LeftButton ) { + //not directly sending a signal here (encapsulation and whatnot) + mySignalSender->emptySpaceDoubleClicked(e); + return; + } + + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + switch ( e->button() ) { + case LeftButton: + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + if ( getItem(*it)->enabled() ) + mySignalSender->itemDoubleClicked(getItem(*it)); + mySignalSender->gvItemDoubleClicked(getItem(*it)); + return; + break; + case Type_is_KDGanttTaskLink: + mySignalSender->taskLinkDoubleClicked(getLink(*it)); + return; + break; + default: + break; + } + break; + /* + case RightButton: + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + mySignalSender->itemRightClicked(getItem(*it)); + return; + break; + case Type_is_KDGanttTaskLink: + mySignalSender->taskLinkRightClicked(getLink(*it)); + return; + break; + } + break; + case MidButton: + switch (getType(*it)) { + case Type_is_KDGanttViewItem: + mySignalSender->itemMidClicked(getItem(*it)); + return; + break; + case Type_is_KDGanttTaskLink: + mySignalSender->taskLinkMidClicked(getLink(*it)); + return; + break; + } + break; + */ + default: + break; + } + } +} +/** + Handles the mouseevent if a mouse button is pressed an the mouse is moved + + \param e the mouseevent + +*/ + +void KDGanttCanvasView::contentsMouseMoveEvent ( QMouseEvent *e ) +{ + if ( !mouseDown ) { + // Update cursor + bool found = false; + QCanvasItemList il = canvas() ->collisions ( e->pos() ); + QCanvasItemList::Iterator it; + for ( it = il.begin(); it != il.end(); ++it ) { + if ( (*it)->rtti() == KDIntervalColorRectangle::RTTI ) { + found = true; + KDIntervalColorRectangle* icr = static_cast( *it ); + KDIntervalColorRectangle::HitTest hitTest = icr->hitTest( mySignalSender->myTimeHeader, e->pos() ); + switch ( hitTest ) { + case KDIntervalColorRectangle::Start: + case KDIntervalColorRectangle::End: + setCursor( splitHCursor ); + break; + default: + unsetCursor(); + } + } + KDGanttViewItem *gvItem = getItem( *it ); + if ( dynamic_cast( gvItem ) ) { + found = true; + MovingOperation op = gvItemHitTest( gvItem, mySignalSender->myTimeHeader, e->pos() ); + switch ( op ) { + case ResizingLeft: + case ResizingRight: + if ( gvItem->isResizeable() ) + setCursor( splitHCursor ); + break; + default: + unsetCursor(); + } + } + } + if ( !found ) + unsetCursor(); + return; + } + + const QPoint p = e->pos(); + if ( movingItem ) { + int x = qRound( movingItem->x() ); + int width = movingItem->width(); + switch( movingOperation ) { + case Moving: + x += p.x() - movingStart.x(); + break; + case ResizingLeft: { + width = qRound( movingItem->x() + movingItem->width() - p.x() ); + x = p.x(); + break; + } + case ResizingRight: + width = p.x() - x; + break; + } + movingStart = p; + if ( movingItem->rtti() == KDIntervalColorRectangle::RTTI ) { + KDIntervalColorRectangle* icr = static_cast(movingItem); + const QDateTime newStart = mySignalSender->myTimeHeader->getDateTimeForIndex(x); + const QDateTime newEnd = mySignalSender->myTimeHeader->getDateTimeForIndex(x + width); + icr->setDateTimes( newStart, newEnd ); + emit mySignalSender->intervalColorRectangleMoved( newStart, newEnd ); + mySignalSender->myTimeHeader->computeIntervals( movingItem->height() ); + } + canvas()->update(); + } + + if ( movingGVItem ) { + int dx = movingStart.x() - e->pos().x(); + int x = movingGVItem->middleLeft().x() - dx; + QDateTime dt = mySignalSender->getDateTimeForCoordX( x, false ); + int duration = movingGVItem->startTime().secsTo( movingGVItem->endTime() ); + if ( movingOperation == Moving ) { + movingGVItem->setStartTime( dt ); + movingGVItem->setEndTime( dt.addSecs( duration ) ); + } else if ( movingOperation == ResizingLeft ) { + movingGVItem->setStartTime( dt ); + } else if ( movingOperation == ResizingRight ) { + movingGVItem->setEndTime( dt.addSecs( duration ) ); + } + movingStart = e->pos(); + } + + static int moves = 0; + if ( (currentLink || currentItem) && (moves < 3) ) { + ++moves; + } else { + moves = 0; + currentLink = 0; + currentItem = 0; + } + if (autoScrollEnabled) + mousePos = e->pos()- QPoint(contentsX(),contentsY()); // make mousePos relative 0 + if (fromItem) { + //qDebug("mousemove: linking %s: %d,%d ",fromItem->listViewText().latin1(), e->pos().x(), e->pos().y()); + linkLine->setPoints(linkLine->startPoint().x(), linkLine->startPoint().y(), e->pos().x(), e->pos().y()); + canvas()->update(); + } + // no action implemented +} +void KDGanttCanvasView::viewportPaintEvent ( QPaintEvent * pe ) +{ + QCanvasView::viewportPaintEvent ( pe ); +} +void KDGanttCanvasView::set_Mouse_Tracking(bool on) +{ + viewport()->setMouseTracking(on); +} +int KDGanttCanvasView::getType(QCanvasItem* it) +{ + switch (it->rtti()) { + case QCanvasItem::Rtti_Line: return ((KDCanvasLine*)it)->myParentType; + case QCanvasItem::Rtti_Ellipse: return ((KDCanvasEllipse *)it)->myParentType; + case QCanvasItem::Rtti_Text: return ((KDCanvasText *)it)->myParentType; + case QCanvasItem::Rtti_Polygon: return ((KDCanvasPolygon *)it)->myParentType; + case QCanvasItem::Rtti_Rectangle: + case KDIntervalColorRectangle::RTTI: + return ((KDCanvasRectangle *)it)->myParentType; + } + return -1; +} +KDGanttViewItem* KDGanttCanvasView::getItem(QCanvasItem* it) +{ + switch (it->rtti()) { + case QCanvasItem::Rtti_Line: return (KDGanttViewItem*) ((KDCanvasLine*)it)->myParentItem; + case QCanvasItem::Rtti_Ellipse: return (KDGanttViewItem*) ((KDCanvasEllipse *)it)->myParentItem; + case QCanvasItem::Rtti_Text: return (KDGanttViewItem*) ((KDCanvasText *)it)->myParentItem; + case QCanvasItem::Rtti_Polygon: return (KDGanttViewItem*) ((KDCanvasPolygon *)it)->myParentItem; + case QCanvasItem::Rtti_Rectangle: return (KDGanttViewItem*) ((KDCanvasRectangle *)it)->myParentItem; + + } + return 0; +} +KDGanttViewTaskLink* KDGanttCanvasView::getLink(QCanvasItem* it) +{ + switch (it->rtti()) { + case QCanvasItem::Rtti_Line: return (KDGanttViewTaskLink*) ((KDCanvasLine*)it)->myParentItem; + case QCanvasItem::Rtti_Ellipse: return (KDGanttViewTaskLink*) ((KDCanvasEllipse *)it)->myParentItem; + case QCanvasItem::Rtti_Text: return (KDGanttViewTaskLink*) ((KDCanvasText *)it)->myParentItem; + case QCanvasItem::Rtti_Polygon: return (KDGanttViewTaskLink*) ((KDCanvasPolygon *)it)->myParentItem; + } + return 0; +} + +void KDGanttCanvasView::slotScrollTimer() { + int mx = mousePos.x(); + int my = mousePos.y(); + int dx = 0; + int dy = 0; + if (mx < 0) + dx = -5; + else if (mx > visibleWidth()) + dx = 5; + if (my < 0) + dy = -5; + else if (my > visibleHeight()) + dy = QMIN(5, verticalScrollBar()->maxValue()-verticalScrollBar()->value()); + + if (dx != 0 || dy != 0) + scrollBy(dx, dy); +} + +int KDGanttCanvasView::getItemArea(KDGanttViewItem *item, int x) { + // area can be: no area = 0, Start = 1, Finish = 2 + // TODO: middle (move, dnd), front, back (resize) + KDTimeTableWidget *tt = dynamic_cast(canvas()); + if (!tt) { + qWarning("Cannot cast canvas to KDTimeTableWidget"); + return 0; + } + int area = 0; + int start = tt->getCoordX(item->startTime()); + int end = start; + if (item->type() == KDGanttViewItem::Event) { + x > start ? area = 2 : area = 1; + } else { + end = tt->getCoordX(item->endTime()); + if ((end - start)/2 > (x - start)) + area = 1; + else + area = 2; + } + return area; +} + +int KDGanttCanvasView::getLinkType(int from, int to) { + // from, to should be Start = 1 or Finish = 2 + if ((from == 1) && (to == 1)) { + return KDGanttViewTaskLink::StartStart; + } + if ((from == 1) && (to == 2)) { + return KDGanttViewTaskLink::StartFinish; + } + if ((from == 2) && (to == 1)) { + return KDGanttViewTaskLink::FinishStart; + } + if ((from == 2) && (to == 2)) { + return KDGanttViewTaskLink::FinishFinish; + } + return KDGanttViewTaskLink::None; +} + +/*! + Represents the background color for a given interval of time (across all tasks). + \sa KDGanttView::addIntervalBackgroundColor + \param view parent view + */ +KDIntervalColorRectangle::KDIntervalColorRectangle( KDGanttView* view ) + : KDCanvasRectangle( view->timeTableWidget(), 0, Type_is_KDGanttGridItem ), + mStart(), mEnd() +{ + setZ( -19 ); +} + +/*! + \param start start datetime of the time interval + \param end end datetime of the time interval + */ +void KDIntervalColorRectangle::setDateTimes( const QDateTime& start, + const QDateTime& end ) +{ + mStart = start; + mEnd = end; + if ( mEnd < mStart ) + qSwap( mStart, mEnd ); +} + +/*! + Sets the background color + \param color the background color +*/ +void KDIntervalColorRectangle::setColor( const QColor& color ) +{ + mColor = color; +} + +/*! + \internal +*/ +void KDIntervalColorRectangle::layout( KDTimeHeaderWidget* timeHeader, int height ) +{ + int left = timeHeader->getCoordX(mStart); + int right = timeHeader->getCoordX(mEnd); + if ( right == left ) + ++right; + setPen( QPen::NoPen ); + setBrush( QBrush(mColor, SolidPattern) ); + setSize( right - left, height ); + move( left, 0 ); + show(); +} + +/*! + \internal +*/ +KDIntervalColorRectangle::HitTest KDIntervalColorRectangle::hitTest( KDTimeHeaderWidget* timeHeader, const QPoint& pos ) const +{ + const int left = timeHeader->getCoordX(mStart); + const int right = timeHeader->getCoordX(mEnd); + const int width = right - left + 1; + const int x = pos.x(); + if ( x < left + width / 10 ) + return Start; + if ( x > right - width / 10 ) + return End; + return Middle; +} diff --git a/kdgantt/KDGanttViewSubwidgets.h b/kdgantt/KDGanttViewSubwidgets.h new file mode 100644 index 00000000..b8d9d57a --- /dev/null +++ b/kdgantt/KDGanttViewSubwidgets.h @@ -0,0 +1,646 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#ifndef KDGANTTVIEWSUBWIDGETS_H +#define KDGANTTVIEWSUBWIDGETS_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "KDGanttView.h" +#include "KDGanttViewTaskLink.h" +#include "KDGanttViewTaskLinkGroup.h" +#include "KDGanttViewSummaryItem.h" +#include "KDGanttSemiSizingControl.h" +#include "KDGanttViewItemDrag.h" + +#define Type_is_KDGanttGridItem 1 +#define Type_is_KDGanttViewItem 2 +#define Type_is_KDGanttTaskLink 3 + +class KDIntervalColorRectangle; +class KDCanvasWhatsThis; +class KDToolTip; +class KDCanvasRectangle; +class KDTimeHeaderToolTip; + +class KDTimeHeaderWidget : public QWidget +{ + Q_OBJECT + +public: + typedef KDGanttView::Scale Scale; + typedef KDGanttView::YearFormat YearFormat; + typedef KDGanttView::HourFormat HourFormat; + struct DateTimeColor { + QDateTime datetime; + QDateTime end; + QColor color; + Scale minScaleView; + Scale maxScaleView; + //KDCanvasLine* canvasLine; + KDCanvasRectangle* canvasRect; + }; + typedef QValueList ColumnColorList; + typedef QValueList IntervalColorList; + /* + enum Scale { Minute, Hour, Day, Week, Month, Auto }; + enum YearFormat { FourDigit, TwoDigit, TwoDigitApostrophe }; + enum HourFormat { Hour_24, Hour_12 }; + */ + + KDTimeHeaderWidget (QWidget* parent,KDGanttView* gant); + ~KDTimeHeaderWidget(); + + QString getToolTipText(QPoint p); + void zoomToFit(); + void zoom(double, bool absolute = true); + void zoomToSelection( QDateTime startTime, QDateTime endTime); + double zoomFactor(); + void setAutoScaleMinorTickCount( int count ); + int autoScaleMinorTickCount(); + void setHorizonStart( const QDateTime& start ); + QDateTime horizonStart() const; + void setHorizonEnd( const QDateTime& start ); + QDateTime horizonEnd() const; + + void setMaximumScale( Scale ); + KDTimeHeaderWidget::Scale maximumScale() const; + void setMinimumScale( Scale ); + KDTimeHeaderWidget::Scale minimumScale() const; + KDTimeHeaderWidget::Scale scale() const; + void setMajorScaleCount( int count ); + int majorScaleCount() const; + void setMinorScaleCount( int count ); + int minorScaleCount() const; + void setMinimumColumnWidth( int width ); + int minimumColumnWidth() const; + void setYearFormat( YearFormat format ); + KDTimeHeaderWidget::YearFormat yearFormat() const; + void setHourFormat( HourFormat format ); + KDTimeHeaderWidget::HourFormat hourFormat() const; + void setShowMajorTicks( bool ); + bool showMajorTicks() const; + void setShowMinorTicks( bool ); + void setScale( Scale unit); + bool showMinorTicks() const; + void setColumnBackgroundColor( const QDateTime& column, + const QColor& color, + Scale mini = KDGanttView::Minute , + Scale maxi = KDGanttView::Month); +#if 0 + // This API has been replaced with KDIntervalColorRectangle and addIntervalBackgroundColor + void setIntervalBackgroundColor( const QDateTime& start, + const QDateTime& end, + const QColor& color, + Scale mini = KDGanttView::Minute , + Scale maxi = KDGanttView::Month); + bool changeBackgroundInterval( const QDateTime& oldstart, + const QDateTime& oldend, + const QDateTime& newstart, + const QDateTime& newend ); + bool deleteBackgroundInterval( const QDateTime& start, + const QDateTime& end ); +#endif + void addIntervalBackgroundColor( KDIntervalColorRectangle* newItem ); + void clearBackgroundColor(); + QColor columnBackgroundColor( const QDateTime& column ) const; + void setWeekendBackgroundColor( const QColor& color ); + QColor weekendBackgroundColor() const; + void setWeekdayBackgroundColor( const QColor& color, int weekday ); + QColor weekdayBackgroundColor(int weekday) const; + void setWeekendDays( int start, int end ); + void weekendDays( int& start, int& end ) const; + void computeTicks(bool doNotComputeRealScale = false); + void paintEvent(QPaintEvent *); + int getCoordX(QDate); + int getCoordX(QDateTime); + QDateTime getDateTimeForIndex(int coordX, bool local = true ); + void setShowPopupMenu( bool show, bool showZoom, bool showScale,bool showTime, + bool showYear,bool showGrid, bool showPrint); + bool registerStartTime(); + bool registerEndTime(); + bool showPopupMenu() const; + ColumnColorList columnBackgroundColorList() const { + return ccList; + } + QColor weekdayColor[8]; + void repaintMe(int left, int wid, QPainter *p = 0); + + void centerDateTime( const QDateTime& center ); + +public slots: + void setSettings(int); + void checkWidth( int ); + void addTickRight( int num = 1 ); + void addTickLeft( int num = 1 ); + void preparePopupMenu(); +signals: + void sizeChanged( int ); + +private: + friend class KDTimeTableWidget; + friend class KDGanttViewItem; + friend class KDGanttView; + friend class KDGanttCanvasView; // calls computeIntervals + virtual void mousePressEvent ( QMouseEvent * e ); + virtual void mouseReleaseEvent ( QMouseEvent * e ); + virtual void mouseDoubleClickEvent ( QMouseEvent * e ); + virtual void mouseMoveEvent ( QMouseEvent * e ); + double secsFromTo( QDateTime begin, QDateTime end ); + void updateTimeTable(); + void computeIntervals( int height ); + bool getColumnColor(QColor& col,int coordLow, int coordHigh); + void moveTimeLineTo(int x); + //void mousePressEvent ( QMouseEvent * ) ; + void resizeEvent ( QResizeEvent * ) ; + QValueList majorTicks; + QValueList minorText; + QValueList majorText; + QDateTime myHorizonStart, myHorizonEnd, myRealEnd,myRealStart; + QDateTime myCenterDateTime; + void saveCenterDateTime(); + Scale myScale,myRealScale,myMaxScale,myMinScale; + YearFormat myYearFormat; + HourFormat myHourFormat; + int myMinimumColumWidth; + bool flagShowMajorTicks, flagShowMinorTicks, flagShowPopupMenu; + bool flagShowZoom, flagShowScale ,flagShowTime ,flagShowYear; + bool flagShowGrid ,flagShowPrint; + bool flagStartTimeSet,flagEndTimeSet; + QColor myWeekendBackgroundColor; + int myWeekendDaysStart, myWeekendDaysEnd; + ColumnColorList ccList; + IntervalColorList icList; + int myMinorScaleCount,myMajorScaleCount; + int myRealMinorScaleCount,myRealMajorScaleCount; + bool flagDoNotRecomputeAfterChange,flagDoNotRepaintAfterChange; + QString getYear(QDate); + QString getHour(QTime); + QDateTime getEvenTimeDate(QDateTime ,Scale); + void computeRealScale(QDateTime start); + int myGridMinorWidth; + int myMajorGridHeight; + QPopupMenu * myPopupMenu, *scalePopupMenu, *timePopupMenu; + QPopupMenu * yearPopupMenu, *gridPopupMenu; + KDGanttView* myGanttView; + double myZoomFactor; + int myAutoScaleMinorTickcount; + bool flagZoomToFit; + int mySizeHint; + int myMinimumWidth; + int getTickTime(); + KDTimeHeaderToolTip* myToolTip; + bool mouseDown; + int beginMouseDown; + int endMouseDown; + bool autoComputeTimeLine; + QPixmap paintPix; +}; + +/* KDTimeTableWidget */ +class KDListView ; + +class KDTimeTableWidget : public QCanvas +{ + Q_OBJECT + +public: + KDTimeTableWidget (QWidget* parent,KDGanttView* my); + + void setBlockUpdating( bool block = true ); + bool blockUpdating(); + void inc_blockUpdating(); + void dec_blockUpdating(); + void setShowTaskLinks( bool show ); + bool showTaskLinks(); + QPtrListtaskLinks(); + void clearTaskLinks(); + void updateMyContent(); + void removeItemFromTasklinks( KDGanttViewItem * ); + void setHorBackgroundLines( int count, QBrush brush ); + int horBackgroundLines( QBrush& brush ); + + void setNoInformationBrush( const QBrush& brush ); + QBrush noInformationBrush() const; + + int getCoordX( QDateTime dt ); + +signals: + void heightComputed( int ); + +public slots: + void expandItem(QListViewItem * ); + void collapseItem(QListViewItem * ); + void highlightItem(QListViewItem * ); + void resetWidth( int ); + void checkHeight( int ); +private: + friend class KDGanttViewTaskLink; + friend class KDTimeHeaderWidget; + friend class KDGanttView; + friend class KDGanttViewTaskItem; + KDGanttView* myGanttView; + + bool taskLinksVisible; + + QPtrList myTaskLinkList; + + QPtrList verGridList; + QPtrList horGridList; + QPtrList horDenseList; + QPtrList showNoInfoList; + int denseLineCount; + QBrush denseLineBrush, noInfoLineBrush; + QPtrList columnColorList; + + int computeHeight(); + void computeVerticalGrid(); + void computeHorizontalGrid(); + void computeDenseLines(); + void computeShowNoInformation(); + void computeTaskLinks(); + void computeMinorGrid(); + void computeMajorGrid(); + + void showMajorGrid(); + void showMinorGrid(); + void hideGrid(); + + QPen gridPen; + int maximumComputedGridHeight; + int minimumHeight; + int int_blockUpdating; + bool flag_blockUpdating; + int pendingHeight; + int pendingWidth; + +}; + +class KDLegendWidget : public KDGanttSemiSizingControl +{ + Q_OBJECT + +public: + KDLegendWidget ( QWidget* parent, KDGanttMinimizeSplitter* legendParent ); + void showMe(bool); + bool isShown(); + void addLegendItem( KDGanttViewItem::Shape shape, const QColor& shapeColor, const QString& text ); + void clearLegend(); + void setFont( QFont ); + void drawToPainter( QPainter *p ); + void setAsDockwindow( bool dockwin ); + bool asDockwindow(); + QDockWindow* dockwindow(); + QSize legendSize(); + QSize legendSizeHint(); + private: + QGroupBox * myLegend; + QLabel* myLabel; + QScrollView * scroll; + QDockWindow* dock; + KDGanttMinimizeSplitter* myLegendParent; +}; + +class KDGanttView; +class KDListView : public QListView +{ + Q_OBJECT + +public: + KDListView (QWidget* parent,KDGanttView* gv ); + KDGanttView* myGanttView; + void drawToPainter( QPainter *p, bool drawHeader=false ); + void setCalendarMode( bool mode ); + bool calendarMode() { return _calendarMode; }; + QString getWhatsThisText(QPoint p); + void setOpen ( QListViewItem * item, bool open ); + void dragEnterEvent ( QDragEnterEvent * ); + void dragMoveEvent ( QDragMoveEvent * ); + void dragLeaveEvent ( QDragLeaveEvent * ); + void dropEvent ( QDropEvent * ); + QDragObject * dragObject (); + void startDrag (); + void paintemptyarea ( QPainter * p, const QRect & rect ){ QListView::paintEmptyArea( p, rect );}; + +public: + class DrawableItem { + public: + DrawableItem(int level, int ypos, QListViewItem *item ) { y = ypos; l = level; i = item; }; + int y; + int l; + QListViewItem * i; + }; +protected: + void drawAllContents(QPainter * p, int cx, int cy, int cw, int ch); + int buildDrawables(QPtrList &lst, int level, int ypos, QListViewItem *item, int ymin, int ymax) const; + +private slots: + void dragItem( QListViewItem * ); + private: + void resizeEvent ( QResizeEvent * ) ; + void contentsMouseDoubleClickEvent ( QMouseEvent * e ); + bool _calendarMode; + + + +}; + + +class KDCanvasText : public QCanvasText +{ +public: + KDCanvasText( KDTimeTableWidget* canvas, void* parentItem, int type ); + int myParentType; + void* myParentItem; +}; + + +class KDCanvasLine : public QCanvasLine +{ +public: + KDCanvasLine( KDTimeTableWidget* canvas, void* parentItem, int type ); + int myParentType; + void* myParentItem; +}; + + +class KDCanvasPolygonItem: public QCanvasPolygonalItem +{ +public: + KDCanvasPolygonItem( KDTimeTableWidget* canvas, void* parentItem, + int type ); + int myParentType; + void* myParentItem; +}; + + +class KDCanvasPolygon: public QCanvasPolygon +{ +public: + KDCanvasPolygon( KDTimeTableWidget* canvas, void* parentItem, int type ); + int myParentType; + void* myParentItem; +}; + + +class KDCanvasEllipse: public QCanvasEllipse +{ +public: + KDCanvasEllipse( KDTimeTableWidget* canvas, void* parentItem, int type ); + int myParentType; + void* myParentItem; +}; + + +class KDCanvasRectangle: public QCanvasRectangle +{ +public: + KDCanvasRectangle( KDTimeTableWidget* canvas, void* parentItem, int type ); + int myParentType; + void* myParentItem; +}; + + +// Interval-color-rectangle, such as the one used in the freebusy view for the current event +class KDIntervalColorRectangle: public KDCanvasRectangle +{ +public: + KDIntervalColorRectangle( KDGanttView* view ); + + void setDateTimes( const QDateTime& start, + const QDateTime& end ); + QDateTime start() const { return mStart; } + QDateTime end() const { return mEnd; } + + void setColor( const QColor& color ); + + enum HitTest { Start, Middle, End }; + HitTest hitTest( KDTimeHeaderWidget* timeHeader, const QPoint& pos ) const; + + void layout( KDTimeHeaderWidget* timeHeader, int height ); + + static const int RTTI = 0x0c58; + /*reimp*/ int rtti() const { return RTTI; } + +private: + QColor mColor; + QDateTime mStart; + QDateTime mEnd; +}; + +class KDCanvasToolTip; + +class KDGanttCanvasView : public QCanvasView +{ + Q_OBJECT + +public: + KDGanttCanvasView(KDGanttView* sender, QCanvas* canvas = 0, QWidget* parent = 0, const char* name = 0 ); + ~KDGanttCanvasView(); + QString getToolTipText(QPoint p); + QString getWhatsThisText(QPoint p); + void drawToPainter ( QPainter * p ); + void resetCutPaste( KDGanttViewItem* ); + void setShowPopupMenu( bool show ); + bool showPopupMenu(); + void cutItem ( KDGanttViewItem* ); + void insertItemAsRoot( KDGanttViewItem* ); + void insertItemAsChild( KDGanttViewItem* , KDGanttViewItem* ); + void insertItemAfter( KDGanttViewItem* , KDGanttViewItem* ); +protected: + friend class KDGanttView; + friend class KDListView; + virtual void contentsMousePressEvent ( QMouseEvent * ) ; + virtual void contentsMouseReleaseEvent ( QMouseEvent * ); + virtual void contentsMouseDoubleClickEvent ( QMouseEvent * ); + virtual void contentsMouseMoveEvent ( QMouseEvent * ) ; + virtual void viewportPaintEvent ( QPaintEvent * pe ); + void resizeEvent ( QResizeEvent * ) ; + void set_MouseTracking(bool on); + int getType(QCanvasItem*); + KDGanttViewItem* getItem(QCanvasItem*); + KDGanttViewTaskLink* getLink(QCanvasItem*); + int getItemArea(KDGanttViewItem *item, int x); + int getLinkType(int from, int to); + + KDGanttView* mySignalSender; + KDGanttViewItem* currentItem, *lastClickedItem, *cuttedItem; + QCanvasRectangle* movingItem; + KDGanttViewTaskItem* movingGVItem; + QPoint movingStart; + QDateTime movingStartDate; + enum MovingOperation { Moving, ResizingLeft, ResizingRight }; + MovingOperation movingOperation; + KDGanttViewTaskLink* currentLink; + KDCanvasWhatsThis* myWhatsThis; + QPopupMenu* onItem; + bool _showItemAddPopupMenu; + int myMyContentsHeight; + KDGanttViewItem *fromItem; + bool linkItemsEnabled; + QCanvasLine *linkLine; + int fromArea; + bool autoScrollEnabled; + bool mouseDown; + +signals: + void heightResized( int ); + void widthResized( int ); + +public slots: + void set_Mouse_Tracking(bool on); + void moveMyContent( int, int ); + void setMyContentsHeight( int ); + void updateHorScrollBar(); +private slots: + void cutItem(); + void pasteItem( int ); + void newRootItem( int ); + void newChildItem( int ); + void slotScrollTimer(); + void myUpdateScrollBars(); + +private: + MovingOperation gvItemHitTest( KDGanttViewItem *item, KDTimeHeaderWidget* timeHeader, const QPoint &pos ); +private: + KDCanvasToolTip* myToolTip; + QTimer *myScrollTimer; + QPoint mousePos; + QTimer scrollBarTimer; +}; + +class KDTimeHeaderToolTip :public QToolTip +{ + +public: + KDTimeHeaderToolTip( QWidget *wid, KDTimeHeaderWidget* header ) : QToolTip( wid ), _wid(wid),_header (header) { + +}; + +protected: + virtual void maybeTip( const QPoint& p) + { + static bool ishidden = true; + if (QToolTip::isGloballyEnabled () ) { + if (ishidden) { + tip( QRect( p.x(),p.y(),5,5), _header->getToolTipText(p)); + } + else + hide(); + ishidden = !ishidden; + } + } +private: + QWidget* _wid; + KDTimeHeaderWidget * _header; +}; + +class KDCanvasToolTip :public QToolTip +{ + +public: + KDCanvasToolTip( QWidget *wid, KDGanttCanvasView* canview ) : QToolTip( wid ), _wid(wid),_canview (canview) { + +}; + +protected: + virtual void maybeTip( const QPoint& p) + { + static bool ishidden = true; + if (QToolTip::isGloballyEnabled () ) { + if (ishidden) { + tip( QRect( p.x()-2,p.y()-2,5,5), _canview->getToolTipText(p)); + } + else + hide(); + ishidden = !ishidden; + } + } +private: + QWidget* _wid; + KDGanttCanvasView * _canview; +}; + +class KDCanvasWhatsThis :public QWhatsThis +{ +public: + KDCanvasWhatsThis( QWidget *wid, KDGanttCanvasView* canview ) : QWhatsThis( wid ), _wid(wid),_canview (canview) { }; + +protected: + virtual QString text( const QPoint& p) + { + return _canview->getWhatsThisText(p) ; + } +private: + QWidget* _wid; + KDGanttCanvasView * _canview; +}; + +class KDListViewWhatsThis :public QWhatsThis +{ +public: + KDListViewWhatsThis( QWidget *wid, KDListView* view ) : QWhatsThis( wid ), _wid(wid),_view (view) { }; + +protected: + virtual QString text( const QPoint& p) + { + return _view->getWhatsThisText(p) ; + } +private: + QWidget* _wid; + KDListView * _view; +}; + + + +#endif diff --git a/kdgantt/KDGanttViewSummaryItem.cpp b/kdgantt/KDGanttViewSummaryItem.cpp new file mode 100644 index 00000000..a9cf23c6 --- /dev/null +++ b/kdgantt/KDGanttViewSummaryItem.cpp @@ -0,0 +1,377 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewSummaryItem.h" +#include "KDGanttViewSubwidgets.h" + +#include "itemAttributeDialog.h" + +/*! + \class KDGanttViewSummaryItem KDGanttViewSummaryItem.h + A summary item in a Gantt chart. + + This class represents summary items in Gantt charts. +*/ + + +/*! + Constructs an empty Gantt item of type event. + + \param view the Gantt view to insert this item into + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewSummaryItem::KDGanttViewSummaryItem( KDGanttView* view, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Summary, view, lvtext, name ) +{ + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param parent a parent item under which this one goes + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewSummaryItem::KDGanttViewSummaryItem( KDGanttViewItem* parent, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Summary, parent, lvtext, name ) +{ + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param view the Gantt view to insert this item into + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewSummaryItem::KDGanttViewSummaryItem( KDGanttView* view, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Summary, view, after, lvtext, name ) +{ + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param parent a parent item under which this one goes + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewSummaryItem::KDGanttViewSummaryItem( KDGanttViewItem* parent, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Summary, parent, after, lvtext, name ) +{ + + initItem(); + +} + + +/*! + The destructor. Does nothing for the moment. +*/ +KDGanttViewSummaryItem::~KDGanttViewSummaryItem() +{ + +} + + +/*! + Specifies the middle time of this summary item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + + \param dateTime the middle time + \sa middleTime() +*/ +void KDGanttViewSummaryItem::setMiddleTime( const QDateTime& dateTime ) +{ + if (! dateTime.isValid() ) { + qDebug("KDGanttViewSummaryItem::setMiddleTime():Invalid parameter-no time set"); + return; + } + if (!myMiddleTime) myMiddleTime = new QDateTime; + *myMiddleTime = dateTime; + if ( myEndTime < middleTime() ) + setEndTime( middleTime() ); + if ( myStartTime > middleTime() ) + setStartTime( middleTime() ); + updateCanvasItems(); +} + + +/*! + Returns the middle time of this summary item. If there is no middle + time defined, the start time is returned. + + \return the middle time of this summary item. + If there is no middle time defined, the start time is returned. +*/ +QDateTime KDGanttViewSummaryItem::middleTime() const +{ + if(myMiddleTime) + return *myMiddleTime; + return myStartTime; +} + + +/*! + Specifies the end time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + If the end time is less the mid time, + the mid time is set to this end time automatically. + \param end the end time + \sa endTime(), setStartTime(), startTime() +*/ +void KDGanttViewSummaryItem::setEndTime( const QDateTime& end ) +{ + if (! end.isValid() ) { + qDebug("KDGanttViewSummaryItem::setEndTime():Invalid parameter-no time set"); + return; + } + myEndTime = end; + if ( myEndTime < middleTime() ) + setMiddleTime( myEndTime ); + else + updateCanvasItems(); +} + + +/*! + Specifies the start time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + If the start time is less the mid time, + the mid time is set to this start time automatically. + + \param start the start time + \sa startTime(), setEndTime(), endTime() +*/ +void KDGanttViewSummaryItem::setStartTime( const QDateTime& start ) +{ + if (! start.isValid() ) { + qDebug("KDGanttViewSummaryItem::setStartTime():Invalid parameter-no time set"); + return; + } + myStartTime = start; + if ( myStartTime > middleTime() ) { + setMiddleTime( myStartTime ); + } + else + updateCanvasItems(); +} + + +/*! + Specifies the actual end time of this item. The parameter must be valid + and non-null. Items with undefined start or end times lead to + undefined visual results. + + \param end the actual end time + \sa actualEndTime() + startTime() +*/ +void KDGanttViewSummaryItem::setActualEndTime( const QDateTime& end ) +{ + if (!myActualEndTime) myActualEndTime = new QDateTime; + *myActualEndTime = end; + + updateCanvasItems(); + +} + + +/*! + Returns the actual end time of this item. + + \return the actual end time of this item + \sa setActualEndTime() + +*/ +QDateTime KDGanttViewSummaryItem::actualEndTime() const +{ + if(myActualEndTime) + return *myActualEndTime; + return myEndTime; +} + + +void KDGanttViewSummaryItem::hideMe() +{ + startShape->hide(); + midShape->hide(); + endShape->hide(); + startShapeBack->hide(); + midShapeBack->hide(); + endShapeBack->hide(); + startLine->hide(); + endLine->hide(); + textCanvas->hide(); + startLineBack->hide(); + endLineBack->hide(); + actualEnd->hide(); +} + +// shows the item +// if coordY >0, this is taken as the middle y-coordinate +void KDGanttViewSummaryItem::showItem( bool show, int coordY ) +{ + isVisibleInGanttView = show; + invalidateHeight () ; + if (!show) { + hideMe(); + return; + } + if ( displaySubitemsAsGroup() && !parent() && !isOpen() ) { + hideMe(); + return; + } + float prio = ((float) ( priority() - 100 )) / 100.0; + startShape->setZ( prio + 0.0055 ); + midShape->setZ( prio + 0.004 ); + endShape->setZ( prio + 0.005 ); + startShapeBack->setZ( prio + 0.003 ); + midShapeBack->setZ( prio + 0.003 ); + endShapeBack->setZ( prio + 0.003 ); + startLine->setZ( prio + 0.0015 ); + endLine->setZ( prio + 0.001 ); + textCanvas->setZ( prio + 0.006 ); + startLineBack->setZ( prio ); + endLineBack->setZ( prio ); + actualEnd->setZ( prio + 0.007 ); + if ( displaySubitemsAsGroup() && firstChild() ) { + myStartTime = myChildStartTime(); + myEndTime = myChildEndTime(); + } + int startX, endX, midX = 0,allY; + if ( coordY ) + allY = coordY; + else + allY = getCoordY(); + startX = myGanttView->myTimeHeader->getCoordX(myStartTime); + endX = myGanttView->myTimeHeader->getCoordX(myEndTime); + if (myMiddleTime) + midX = myGanttView->myTimeHeader->getCoordX(*myMiddleTime); + else + midX = endX; + + startLine->setPoints(startX,allY,midX,allY); + startLine->show(); + startLineBack->setPoints(startX-1,allY,midX+1,allY); + startLineBack->show(); + startShape->move(startX,allY); + startShapeBack->move(startX,allY); + + endShape->move(endX,allY); + endShapeBack->move(endX,allY); + moveTextCanvas(endX,allY); + startShape->show(); + startShapeBack->show(); + endShape->show(); + endShapeBack->show(); + textCanvas->show(); + if (myMiddleTime) { + endLine->setPoints(midX,allY,endX,allY); + endLine->show(); + endLineBack->setPoints(midX,allY,endX+1,allY); + endLineBack->show(); + midShape->move(midX,allY); + midShape->show(); + midShapeBack->move(midX,allY); + midShapeBack->show(); + } + else { + endLine->hide(); + endLineBack->hide(); + midShape->hide(); + midShapeBack->hide(); + } + if (myActualEndTime) { + if ( *myActualEndTime == myEndTime ) { + actualEnd->hide(); + } + else { + int actendX = myGanttView->myTimeHeader->getCoordX(*myActualEndTime); + actualEnd->setPoints(actendX,allY-5,actendX,allY+5); + actualEnd->show(); + } + } + else { + actualEnd->hide(); + } + if(myStartTime == myEndTime) + { + endShape->moveBy(myItemSize+4,0); + endShapeBack->moveBy(myItemSize+4,0); + textCanvas->moveBy(myItemSize+4,0); + midShape->hide(); + midShapeBack->hide(); + startLine->hide(); + endLine->hide(); + startLineBack->hide(); + endLineBack->hide(); + } + if (textCanvas->text().isEmpty()) + textCanvas->hide(); +} +void KDGanttViewSummaryItem::initItem() +{ + isVisibleInGanttView = false; + myActualEndTime = 0; + myMiddleTime = 0; + showItem(true); + myGanttView->myTimeTable->updateMyContent(); + setDragEnabled( myGanttView->dragEnabled() ); + setDropEnabled( myGanttView->dropEnabled() ); +} + diff --git a/kdgantt/KDGanttViewSummaryItem.h b/kdgantt/KDGanttViewSummaryItem.h new file mode 100644 index 00000000..e8fcd618 --- /dev/null +++ b/kdgantt/KDGanttViewSummaryItem.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#ifndef KDGANTTVIEWSUMMARYITEM_H +#define KDGANTTVIEWSUMMARYITEM_H + +#include "KDGanttViewItem.h" + +class KDGanttViewSummaryItem : public KDGanttViewItem +{ +public: + KDGanttViewSummaryItem( KDGanttView* view, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewSummaryItem( KDGanttViewItem* parent, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewSummaryItem( KDGanttView* view, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewSummaryItem( KDGanttViewItem* parent, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + virtual ~KDGanttViewSummaryItem(); + + void setMiddleTime( const QDateTime& ); + QDateTime middleTime() const; + void setActualEndTime( const QDateTime& end ); + QDateTime actualEndTime() const; + void setStartTime( const QDateTime& start ); + void setEndTime( const QDateTime& end ); +private: + void showItem( bool show = true, int coordY = 0 ); + QDateTime* myActualEndTime,*myMiddleTime; + void initItem(); + void hideMe(); + + +}; + +#endif diff --git a/kdgantt/KDGanttViewTaskItem.cpp b/kdgantt/KDGanttViewTaskItem.cpp new file mode 100644 index 00000000..a9f1bec9 --- /dev/null +++ b/kdgantt/KDGanttViewTaskItem.cpp @@ -0,0 +1,369 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewTaskItem.h" +#include "KDGanttViewSubwidgets.h" + +#include "itemAttributeDialog.h" + +/*! + \class KDGanttViewTaskItem KDGanttViewTaskItem.h + + This class represents calendar items in Gantt charts. + + A calendar item in a Gantt chart has no start/end shape, + it is displayed as a rectangle. + You can set the colors as usual, where only the first argument of + setColors( col, col, col ) + is important. + If the start time is equal to the end time, the item is displayed as + ø, showing that there is no time interval set. + + For a KDGanttViewTaskItem, the text, setted by \a setText(), + is shown in the item itself and the text is truncated automatically + to fit in the item. + For all other item types, the text is shown right of the item. +*/ + + +/*! + Constructs an empty Gantt item of type event. + + \param view the Gantt view to insert this item into + \param lvtext the text to show in the listview + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewTaskItem::KDGanttViewTaskItem( KDGanttView* view, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Task, view, lvtext, name ) +{ + + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param parent a parent item under which this one goes + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewTaskItem::KDGanttViewTaskItem( KDGanttViewItem* parent, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Task, parent, lvtext, name ) +{ + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param view the Gantt view to insert this item into + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the list view + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewTaskItem::KDGanttViewTaskItem( KDGanttView* view, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Task, view, after, lvtext, name ) +{ + initItem(); +} + + +/*! + Constructs an empty Gantt item of type event. + + \param parent a parent item under which this one goes + \param after another item at the same level behind which this one should go + \param lvtext the text to show in the listview + \param name the name by which the item can be identified. If no name + is specified, a unique name will be generated +*/ +KDGanttViewTaskItem::KDGanttViewTaskItem( KDGanttViewItem* parent, + KDGanttViewItem* after, + const QString& lvtext, + const QString& name ) : + KDGanttViewItem( Task, parent, after, lvtext, name ) +{ + initItem(); +} + + +/*! + The destructor. +*/ +KDGanttViewTaskItem::~KDGanttViewTaskItem() +{ + +} + + +/*! + Specifies the end time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + If the end time is less the start time, + the start time is set to this end time automatically. + + \param end the end time + \sa setStartTime(), startTime(), endTime() +*/ +void KDGanttViewTaskItem::setEndTime( const QDateTime& end ) +{ + myEndTime = end; + if ( myEndTime < startTime() ) + setStartTime( myEndTime ); + else + updateCanvasItems(); +} + + +/*! + Specifies the start time of this item. The parameter must be valid + and non-null. If the parameter is invalid or null, no value is set. + If the start time is greater than the end time, + the end time is set to this start time automatically. + + \param start the start time + \sa startTime(), setEndTime(), endTime() +*/ +void KDGanttViewTaskItem::setStartTime( const QDateTime& start ) +{ + if (! start.isValid() ) { + qDebug("KDGanttViewTaskItem::setStartTime():Invalid parameter-no time set"); + return; + } + myStartTime = start; + if ( myStartTime > endTime() ) + setEndTime( myStartTime ); + else + updateCanvasItems(); +} + + +/*! + Hides all canvas items of this Gantt item + \sa showItem() +*/ +void KDGanttViewTaskItem::hideMe() +{ + startShape->hide(); + progressShape->hide(); + textCanvas->hide(); + floatStartShape->hide(); + floatEndShape->hide(); +} + + +void KDGanttViewTaskItem::showItem(bool show, int coordY) +{ + + //qDebug("KDGanttViewTaskItem::showItem() %d %s ", (int) show, listViewText().latin1()); + isVisibleInGanttView = show; + invalidateHeight () ; + if (!show) { + hideMe(); + return; + } + bool takedefaultHeight = true ; // pending: make configureable + float prio = ((float) ( priority() - 100 )) / 100.0; + startShape->setZ( prio ); + progressShape->setZ(startShape->z()+0.002); // less than textCanvas + progressShape->hide(); + floatStartShape->setZ(startShape->z()+0.003); // less than textCanvas + floatStartShape->hide(); + floatEndShape->setZ(startShape->z()+0.003); // less than textCanvas + floatEndShape->hide(); + textCanvas->setZ( prio + 0.005 ); + if ( displaySubitemsAsGroup() && !parent() && !isOpen() ) { + hideMe(); + return; + } + if ( displaySubitemsAsGroup() && ( firstChild() || myGanttView->calendarMode() ) ) { + hideMe();//new + return;//new + myStartTime = myChildStartTime(); + myEndTime = myChildEndTime(); + } + //setExpandable(false); + KDCanvasRectangle* temp = (KDCanvasRectangle*) startShape; + KDCanvasRectangle* progtemp = (KDCanvasRectangle*) progressShape; + int startX, endX, midX = 0,allY, progX=0; + if ( coordY ) + allY = coordY; + else + allY = getCoordY(); + startX = myGanttView->myTimeHeader->getCoordX(myStartTime); + endX = myGanttView->myTimeHeader->getCoordX(myEndTime); + midX = endX; + if (myProgress > 0) { + progX = (endX - startX) * myProgress / 100; + } + int hei = height(); + if ( ! isVisible() ) { + KDGanttViewItem * par = parent(); + while ( par != 0 && !par->isVisible() ) + par = par->parent(); + if ( par ) + hei = par->height(); + } + if (myGanttView->myListView->itemAt( QPoint(2, allY))) + hei = myGanttView->myListView->itemAt( QPoint(2, allY))->height(); + if ( takedefaultHeight ) + hei = 16; + if ( myStartTime == myEndTime ) { + textCanvas->hide(); + if ( showNoInformation() ) { + startShape->hide(); + } else { + startShape->setZ( 1.01 ); + if (myGanttView->displayEmptyTasksAsLine() ) { + hei = myGanttView->myTimeTable->height(); + if (hei < myGanttView->myTimeTable->pendingHeight ) + hei = myGanttView->myTimeTable->pendingHeight; + temp->setSize(5, hei ); + temp->move(startX, 0); + temp->show(); + } else { + temp->setSize( 1, hei -3 ); + temp->move(startX, allY-hei/2 +2); + temp->show(); + } + } + return; + } + if ( startX +3 >= endX ) + temp->setSize( 3, hei-3 ); + else + temp->setSize(endX-startX, hei-3 ); + temp->move(startX, allY-hei/2 +2); + temp->show(); + if (progX > 0) { + // FIXME: For now, just use inverted color for progress + QColor c = temp->brush().color(); + int h, s, v; + c.getHsv(&h, &s, &v); + h > 359/2 ? h -= 359/2 : h += 359/2; + c.setHsv(h, s, v); + progtemp->setBrush(QBrush(c)); + + progtemp->setSize(progX, hei-3); + progtemp->move(temp->x(), temp->y()); + progtemp->show(); + } + if (myFloatStartTime.isValid()) { + KDCanvasRectangle* floatStartTemp = (KDCanvasRectangle*) floatStartShape; + int floatStartX = myGanttView->myTimeHeader->getCoordX(myFloatStartTime); + // FIXME: Configurable colors + QBrush b(temp->brush().color(), Dense4Pattern); + floatStartTemp->setBrush(b); + floatStartTemp->setPen(QPen(gray)); + if (floatStartX < startX) { + floatStartTemp->setSize(startX - floatStartX, temp->size().height()/2); + floatStartTemp->move(floatStartX, temp->y() + temp->size().height()/4); + } else { + floatStartTemp->setSize(floatStartX - startX, temp->size().height()/2); + floatStartTemp->move(startX, temp->y() + temp->size().height()/4); + } + floatStartTemp->show(); + } + if (myFloatEndTime.isValid()) { + KDCanvasRectangle* floatEndTemp = (KDCanvasRectangle*) floatEndShape; + int floatEndX = myGanttView->myTimeHeader->getCoordX(myFloatEndTime); + // FIXME: Configurable colors + QBrush b(temp->brush().color(), Dense4Pattern); + floatEndTemp->setBrush(b); + floatEndTemp->setPen(QPen(gray)); + int ex = startX + temp->size().width(); + if (floatEndX > ex) { + floatEndTemp->setSize(floatEndX - ex, temp->size().height()/2); + floatEndTemp->move(ex, temp->y() + temp->size().height()/4); + } else { + floatEndTemp->setSize(ex - floatEndX, temp->size().height()/2); + floatEndTemp->move(floatEndX, temp->y() + temp->size().height()/4); + } + floatEndTemp->show(); + } + + int wid = endX-startX - 4; + if ( !displaySubitemsAsGroup() && !myGanttView->calendarMode()) { + moveTextCanvas(endX,allY); + textCanvas->show(); + } else { + if ( textCanvasText.isEmpty() || wid < 5) + textCanvas->hide(); + else { + textCanvas->move(startX+3, allY-textCanvas->boundingRect().height()/2); + QString temp = textCanvasText; + textCanvas->setText(temp); + int len = temp.length(); + while ( textCanvas->boundingRect().width() > wid ) { + temp.truncate(--len); + textCanvas->setText(temp); + } + if ( temp.isEmpty()) + textCanvas->hide(); + else { + textCanvas->show(); + } + } + } +} + + +void KDGanttViewTaskItem::initItem() +{ + isVisibleInGanttView = false; + + if ( myGanttView->calendarMode() && parent() ) { + setVisible( false ); + parent()->setVisible( true ); + } else + showItem(true); + //qDebug("initItem %s %s", listViewText().latin1(),startShape->brush().color().name().latin1() ); + myGanttView->myTimeTable->updateMyContent(); + setDragEnabled( myGanttView->dragEnabled() ); + setDropEnabled( myGanttView->dropEnabled() ); +} + diff --git a/kdgantt/KDGanttViewTaskItem.h b/kdgantt/KDGanttViewTaskItem.h new file mode 100644 index 00000000..d4a73cf0 --- /dev/null +++ b/kdgantt/KDGanttViewTaskItem.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#ifndef KDGANTTVIEWTASKITEM_H +#define KDGANTTVIEWTASKITEM_H + +#include "KDGanttViewItem.h" +class KDCanvasRectangle; +class QBrush; + +class KDGanttViewTaskItem : public KDGanttViewItem +{ +public: + KDGanttViewTaskItem( KDGanttView* view, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewTaskItem( KDGanttViewItem* parent, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewTaskItem( KDGanttView* view, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + KDGanttViewTaskItem( KDGanttViewItem* parent, KDGanttViewItem* after, + const QString& lvtext = QString::null, + const QString& name = QString::null ); + virtual ~KDGanttViewTaskItem(); + + void setStartTime( const QDateTime& start ); + void setEndTime( const QDateTime& end ); + +protected: + void showItem( bool show = true, int coordY = 0 ); + +private: + void initItem(); + void hideMe(); + QBrush myBrush, undefinedBrush; + bool _showUndefinedBrush; +}; + +#endif diff --git a/kdgantt/KDGanttViewTaskLink.cpp b/kdgantt/KDGanttViewTaskLink.cpp new file mode 100644 index 00000000..22a50b8a --- /dev/null +++ b/kdgantt/KDGanttViewTaskLink.cpp @@ -0,0 +1,1007 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewTaskLink.h" +#include "KDGanttViewTaskLinkGroup.h" +#include "KDGanttViewSubwidgets.h" +#include "KDGanttXMLTools.h" + + +/*! \class KDGanttViewTaskLink KDGanttViewTaskLink.h + This class represents a link between a number of Gantt chart items. + + It always connects source items with target items. Task links can + be grouped into KDGanttViewTaskLinkGroup objects. + If a Gantt view item is deleted, it is removed from the fromList or + from the toList. + If one of the lists becomes empty, the complete task link is deleted + as well. + + The task link is deleted by KDGanttViews d'tor. + You may delete the task link yourself, if you do it + _before_ KDGanttViews d'tor is called. +*/ + + +/*! + Creates a task link that connects all items in the source item list from + to all items in the destination item list to. + + \param from the source items + \param to the target items + \param type the link type for the connection +*/ +KDGanttViewTaskLink::KDGanttViewTaskLink( QPtrList from, + QPtrList to, + LinkType type ) +{ + fromList= from; + toList = to; + myGroup = 0; + setLinkType(type); + initTaskLink(); +} + + +/*! + \overload + + Creates a task link that connects two items. + Note, that the from() and to() functions are returning a list, + in this case containing only one item. + + \param from the source item + \param to the target item + \param type the link type for the connection +*/ +KDGanttViewTaskLink::KDGanttViewTaskLink( KDGanttViewItem* from, + KDGanttViewItem* to, + LinkType type ) +{ + fromList.append(from); + toList.append(to); + myGroup = 0; + setLinkType(type); + initTaskLink(); + +} + +/*! + Creates a task link that connects all items in the source item list from + to all items in the destination item list to. + Inserts the link directly into a link group. + + \param group the link group to insert this link into + \param from the source items + \param to the target items + \param type the link type for the connection +*/ + +KDGanttViewTaskLink::KDGanttViewTaskLink( KDGanttViewTaskLinkGroup* group, + QPtrList from, + QPtrList to, + LinkType type ) +{ + fromList = from; + toList = to; + myGroup = 0; + setLinkType(type); + initTaskLink(); + setGroup(group); +} + +/*! + \overload + + Creates a task link that connects two items and inserts the link + directly into a link group. + Note, that the from() and to() functions are returning a list, + in this case containing only one item. + + \param group the link group to insert this link into + \param from the source item + \param to the target item + \param type the link type for the connection +*/ + +KDGanttViewTaskLink::KDGanttViewTaskLink( KDGanttViewTaskLinkGroup* group, + KDGanttViewItem* from, + KDGanttViewItem* to, + LinkType type ) +{ + fromList.append(from); + toList.append(to); + myGroup = 0; + setLinkType(type); + initTaskLink(); + setGroup(group); +} + + +KDGanttViewTaskLink::~KDGanttViewTaskLink( ) +{ + setGroup(0); + myTimeTable->myTaskLinkList.remove(this); + delete horLineList; + delete verLineList; + delete horLineList2; + delete verLineList2; + delete horLineList3; + delete topList; + delete topLeftList; + delete topRightList; +} + + +void KDGanttViewTaskLink::initTaskLink() +{ + horLineList = new QPtrList; + verLineList = new QPtrList; + horLineList2 = new QPtrList; + verLineList2 = new QPtrList; + horLineList3 = new QPtrList; + topList = new QPtrList; + topLeftList = new QPtrList; + topRightList = new QPtrList; + horLineList->setAutoDelete( true ); + verLineList->setAutoDelete( true ); + horLineList2->setAutoDelete( true ); + verLineList2->setAutoDelete( true ); + horLineList3->setAutoDelete( true ); + topList->setAutoDelete( true ); + topLeftList->setAutoDelete( true ); + topRightList->setAutoDelete( true ); + myTimeTable = fromList.getFirst()->myGanttView->myTimeTable; + KDCanvasLine* horLine,*verLine; + KDCanvasLine* horLine2,*verLine2; + KDCanvasLine* horLine3; + KDCanvasPolygon* top; + KDCanvasPolygon* topLeft; + KDCanvasPolygon* topRight; + unsigned int i, j; + for ( i = 0;i < fromList.count();++i) { + for ( j = 0;j < toList.count();++j) { + horLine = new KDCanvasLine(myTimeTable,this,Type_is_KDGanttTaskLink); + verLine = new KDCanvasLine(myTimeTable,this,Type_is_KDGanttTaskLink); + horLine2 = new KDCanvasLine(myTimeTable,this,Type_is_KDGanttTaskLink); + verLine2 = new KDCanvasLine(myTimeTable,this,Type_is_KDGanttTaskLink); + horLine3 = new KDCanvasLine(myTimeTable,this,Type_is_KDGanttTaskLink); + top = new KDCanvasPolygon(myTimeTable,this,Type_is_KDGanttTaskLink); + topLeft = new KDCanvasPolygon(myTimeTable,this,Type_is_KDGanttTaskLink); + topRight = new KDCanvasPolygon(myTimeTable,this,Type_is_KDGanttTaskLink); + QPointArray arr = QPointArray(3); + arr.setPoint(0,-4,-5); + arr.setPoint(1,4,-5); + arr.setPoint(2,0,0); + top->setPoints(arr); + arr.setPoint(0,5,-5); // need an extra y pixel, canvas bug? + arr.setPoint(1,5,5); // need an extra y pixel, canvas bug? + arr.setPoint(2,0,0); + topLeft->setPoints(arr); + arr.setPoint(0,-5,-4); + arr.setPoint(1,-5,4); + arr.setPoint(2,0,0); + topRight->setPoints(arr); + horLineList->append(horLine); + verLineList->append(verLine); + horLineList2->append(horLine2); + verLineList2->append(verLine2); + horLineList3->append(horLine3); + topList->append(top); + topLeftList->append(topLeft); + topRightList->append(topRight); + horLine->setZ(1); + verLine->setZ(1); + horLine2->setZ(1); + verLine2->setZ(1); + horLine3->setZ(1); + top->setZ(1); + topLeft->setZ(1); + topRight->setZ(1); + } + } + + setTooltipText( "Tasklink" ); + setWhatsThisText( "Tasklink" ); + myTimeTable->myTaskLinkList.append(this); + setHighlight( false); + setHighlightColor(Qt::red ); + setColor(Qt::black); + setVisible(true); +} + + +/*! + Specifies whether this task link should be visible or not. + + \param visible pass true to make this task link visible, and false + to hide it + \sa isVisible() +*/ + +void KDGanttViewTaskLink::setVisible( bool visible ) +{ + showMe ( visible ); + myTimeTable->updateMyContent(); +} +void KDGanttViewTaskLink::showMe( bool visible ) +{ + if (linkType() != None) { + showMeType(visible); + return; + } + hide(); + + isvisible = visible; + int wid = 1; + QPen p; + QBrush b; + p.setWidth(wid); + b.setStyle(Qt::SolidPattern); + if (ishighlighted) { + b.setColor(myColorHL); + p.setColor(myColorHL); + + } else { + b.setColor(myColor); + p.setColor(myColor); + } + QPoint start, end; + QPtrListIterator horIt(*horLineList); + QPtrListIterator verIt(*verLineList); + QPtrListIterator topIt(*topList); + QPtrListIterator fromIt(fromList); + QPtrListIterator toIt(toList); + for ( ; fromIt.current(); ++fromIt ) { + (*fromIt)->setTextOffset(QPoint(0,0)); + toIt.toFirst(); + for ( ; toIt.current(); ++toIt ) { + (*toIt)->setTextOffset(QPoint(0,0)); + if (!isvisible || ! (*fromIt)->isVisibleInGanttView || !(*toIt)->isVisibleInGanttView || !myTimeTable->taskLinksVisible) { + (*horIt)->hide(); + (*verIt)->hide(); + (*topIt)->hide(); + ++horIt; + ++verIt; + ++topIt; + } else { + (*horIt)->setPen(p); + (*verIt)->setPen(p); + (*topIt)->setBrush(b); + end = (*toIt)->getTaskLinkEndCoord(); + start = (*fromIt)->getTaskLinkStartCoord(end); + (*horIt)->setPoints(start.x(),start.y(),end.x()+wid,start.y()); + (*verIt)->setPoints(end.x()+wid/2,start.y(),end.x()+wid/2,end.y()-2); + (*topIt)->move(end.x()+wid/2,end.y()); + (*horIt)->show(); + (*verIt)->show(); + (*topIt)->show(); + ++horIt; + ++verIt; + ++topIt; + + } + } + } + while ( horIt.current() ) { + (*horIt)->hide(); + (*verIt)->hide(); + (*topIt)->hide(); + ++horIt; + ++verIt; + ++topIt; + } +} + +void KDGanttViewTaskLink::showMeType( bool visible ) +{ + //qDebug("KDGanttViewTaskLink::showMeType %d",linkType()); + hide(); + isvisible = visible; + int wid = 1; + QPen p; + QBrush b; + p.setWidth(wid); + b.setStyle(Qt::SolidPattern); + if (ishighlighted) { + b.setColor(myColorHL); + p.setColor(myColorHL); + + } else { + b.setColor(myColor); + p.setColor(myColor); + } + QPoint start, end; + QPtrListIterator horIt(*horLineList); + QPtrListIterator verIt(*verLineList); + QPtrListIterator horIt2(*horLineList2); + QPtrListIterator verIt2(*verLineList2); + QPtrListIterator horIt3(*horLineList3); + QPtrListIterator topIt(*topList); + QPtrListIterator topLeftIt(*topLeftList); + QPtrListIterator topRightIt(*topRightList); + QPtrListIterator fromIt(fromList); + QPtrListIterator toIt(toList); + for ( ; fromIt.current(); ++fromIt ) { + (*fromIt)->setTextOffset(QPoint(30,0)); + (*fromIt)->moveTextCanvas(); + toIt.toFirst(); + for ( ; toIt.current(); ++toIt ) { + if (isvisible && (*fromIt)->isVisibleInGanttView && + (*toIt)->isVisibleInGanttView && myTimeTable->taskLinksVisible) { + (*horIt)->setPen(p); + (*verIt)->setPen(p); + (*horIt2)->setPen(p); + (*verIt2)->setPen(p); + (*horIt3)->setPen(p); + (*topIt)->setBrush(b); + (*topLeftIt)->setBrush(b); + (*topRightIt)->setBrush(b); + (*toIt)->setTextOffset(QPoint(30,0)); + (*toIt)->moveTextCanvas(); + switch (linkType()) { + case StartStart: { + start = (*fromIt)->middleLeft(); + end = (*toIt)->middleLeft()-QPoint(12,0); + bool down = start.y() < end.y(); + (*horIt)->setPoints(start.x()-xOffset(*fromIt),start.y(), + start.x()-10, start.y()); + (*verIt)->setPoints( + (*horIt)->endPoint().x(), + (*horIt)->endPoint().y(), + (*horIt)->endPoint().x(), + (down ? (*toIt)->itemPos()+1 + : (*toIt)->itemPos()+(*toIt)->height()-1)); + (*horIt2)->setPoints((*verIt)->endPoint().x(), + (*verIt)->endPoint().y(), + end.x()-12, + (*verIt)->endPoint().y()); + (*verIt2)->setPoints((*horIt2)->endPoint().x(), + (*horIt2)->endPoint().y(), + (*horIt2)->endPoint().x(), + end.y()); + (*horIt3)->setPoints((*verIt2)->endPoint().x(), + (*verIt2)->endPoint().y(), + end.x(), + end.y()); + (*topRightIt)->move(end.x(),end.y()); + (*topRightIt)->show(); + break; + } + case FinishFinish: { + start = (*fromIt)->middleRight(); + end = (*toIt)->middleRight()+QPoint(12,0); + bool down = start.y() < end.y(); + (*horIt)->setPoints(start.x()+xOffset(*fromIt),start.y(), + start.x()+10, start.y()); + (*verIt)->setPoints( + (*horIt)->endPoint().x(), + (*horIt)->endPoint().y(), + (*horIt)->endPoint().x(), + (down ? (*toIt)->itemPos()+1 + : (*toIt)->itemPos()+(*toIt)->height()-1)); + (*horIt2)->setPoints((*verIt)->endPoint().x(), + (*verIt)->endPoint().y(), + end.x()+12, + (*verIt)->endPoint().y()); + (*verIt2)->setPoints((*horIt2)->endPoint().x(), + (*horIt2)->endPoint().y(), + (*horIt2)->endPoint().x(), + end.y()); + (*horIt3)->setPoints((*verIt2)->endPoint().x(), + (*verIt2)->endPoint().y(), + end.x(), + end.y()); + (*topLeftIt)->move(end.x(),end.y()); + (*topLeftIt)->show(); + break; + } + case FinishStart: { + start = (*fromIt)->middleRight(); + end = (*toIt)->middleLeft() - QPoint(12,0); + bool down = start.y() < end.y(); + (*horIt)->setPoints(start.x()+xOffset(*fromIt),start.y(), + start.x()+10,start.y()); + (*verIt)->setPoints( + (*horIt)->endPoint().x(), + (*horIt)->endPoint().y(), + (*horIt)->endPoint().x(), + (down ? (*toIt)->itemPos()+1 + : (*toIt)->itemPos()+(*toIt)->height()-1)); + (*horIt2)->setPoints((*verIt)->endPoint().x(), + (*verIt)->endPoint().y(), + end.x()-12, + (*verIt)->endPoint().y()); + (*verIt2)->setPoints((*horIt2)->endPoint().x(), + (*horIt2)->endPoint().y(), + (*horIt2)->endPoint().x(), + end.y()); + (*horIt3)->setPoints((*verIt2)->endPoint().x(), + (*verIt2)->endPoint().y(), + end.x(), + end.y()); + (*topRightIt)->move(end.x(),end.y()); + + (*topRightIt)->show(); + + break; + } + case StartFinish: { + start = (*fromIt)->middleRight(); + end = (*toIt)->middleRight()+QPoint(12,0); + bool down = start.y() < end.y(); + (*horIt)->setPoints(start.x()+xOffset(*fromIt),start.y(), + start.x()+10, start.y()); + (*verIt)->setPoints( + (*horIt)->endPoint().x(), + (*horIt)->endPoint().y(), + (*horIt)->endPoint().x(), + (down ? (*toIt)->itemPos()+1 + : (*toIt)->itemPos()+(*toIt)->height()-1)); + (*horIt2)->setPoints((*verIt)->endPoint().x(), + (*verIt)->endPoint().y(), + end.x()-12, + (*verIt)->endPoint().y()); + (*verIt2)->setPoints((*horIt2)->endPoint().x(), + (*horIt2)->endPoint().y(), + (*horIt2)->endPoint().x(), + end.y()); + (*horIt3)->setPoints((*verIt2)->endPoint().x(), + (*verIt2)->endPoint().y(), + end.x(), + end.y()); + (*topRightIt)->move(end.x(),end.y()); + (*topRightIt)->show(); + break; + } + default: + qWarning("KDGanttViewTaskLink: Unknown link type"); + break; + } + (*horIt)->show(); + (*verIt)->show(); + (*horIt2)->show(); + (*verIt2)->show(); + (*horIt3)->show(); + } + ++horIt; + ++verIt; + ++horIt2; + ++verIt2; + ++horIt3; + ++topIt; + ++topLeftIt; + ++topRightIt; + } + } +} + +/*! + Returns whether this task link should be visible or not. + + \return true if the task link is visible + \sa setVisible() +*/ +bool KDGanttViewTaskLink::isVisible() const +{ + + return isvisible; +} + + +/*! + Returns the group (if any) to which this task link belongs. + + \return the group to which this task link belongs; 0 if it does not + belong to any group. + \sa KDGanttViewTaskLinkGroup +*/ +KDGanttViewTaskLinkGroup* KDGanttViewTaskLink::group() +{ + return myGroup; +} + + +/*! + Inserts this task link in a group. + If the parameter is 0, the task link is removed from any group + + \param group the group, this task link has to be inserted + + \sa KDGanttViewTaskLinkGroup +*/ +void KDGanttViewTaskLink::setGroup(KDGanttViewTaskLinkGroup* group) +{ + + myTimeTable->myGanttView->addTaskLinkGroup(group); + if(myGroup == group) + return; + if (myGroup != 0) + myGroup->removeItem(this); + myGroup = group; + if (myGroup != 0) + myGroup->insertItem(this); +} + + +/*! + Specifies whether this task link should be shown highlighted. The + user can also highlight a task link with the mouse. + + \param highlight pass true in order to highlight this task link + \sa highlight() +*/ +void KDGanttViewTaskLink::setHighlight( bool highlight ) +{ + ishighlighted = highlight ; + // if ( isvisible) setVisible(true ); + myTimeTable->updateMyContent(); +} + + +/*! + Returns whether this task link is highlighted, either + programmatically by setHighlight() or by the user with the mouse. + + \return true if the task link is highlighted + \sa setHighlight() +*/ +bool KDGanttViewTaskLink::highlight() const +{ + return ishighlighted; +} + + +/*! + Specifies the color to draw this task link in. + + \param color the color to draw this task link in + \sa color() +*/ +void KDGanttViewTaskLink::setColor( const QColor& color ) +{ + myColor = color; + //if ( isvisible) setVisible(true ); + myTimeTable->updateMyContent(); +} + + +/*! + Returns the color in which this task link is drawn. + + \return the color in which this task link is drawn + \sa setColor() +*/ +QColor KDGanttViewTaskLink::color() const +{ + return myColor; +} + + +/*! + Specifies the highlight color to draw this task link in. + + \param color the highlight color to draw this task link in + \sa highlightColor() +*/ +void KDGanttViewTaskLink::setHighlightColor( const QColor& color ) +{ + myColorHL = color; + //if ( isvisible) setVisible(true ); + myTimeTable->updateMyContent(); +} + + +/*! + Returns the highlight color in which this task link is drawn. + + \return the highlight color in which this task link is drawn + \sa setHighlightColor() +*/ +QColor KDGanttViewTaskLink::highlightColor() const +{ + return myColorHL; +} + + +/*! + Specifies the text to be shown as a tooltip for this task link. + + \param text the tooltip text + \sa tooltipText() +*/ +void KDGanttViewTaskLink::setTooltipText( const QString& text ) +{ + myToolTipText = text; +} + + +/*! + Returns the tooltip text of this task link. + + \return the tooltip text of this task link + \sa setTooltipText() +*/ +QString KDGanttViewTaskLink::tooltipText() const +{ + return myToolTipText; +} + + +/*! + Specifies the text to be shown in a what's this window for this task link. + + \param text the what's this text + \sa whatsThisText() +*/ +void KDGanttViewTaskLink::setWhatsThisText( const QString& text ) +{ + myWhatsThisText = text; + +} + + +/*! + Returns the what's this text of this task link. + + \return the what's this text of this task link + \sa setWhatsThisText() +*/ +QString KDGanttViewTaskLink::whatsThisText() const +{ + return myWhatsThisText; +} + + +/*! + Returns the list of source item of this task link. + + \return the ist of source item of this task link + \sa to() +*/ +QPtrList KDGanttViewTaskLink::from() const +{ + return fromList; +} + + +/*! + Removes a KDGanttViewItem from the lists. + + \sa to() from() +*/ +void KDGanttViewTaskLink::removeItemFromList( KDGanttViewItem* item ) +{ + bool itemremoved = false; + if (fromList.remove( item )) { + itemremoved = true; + } + if ( toList.remove( item )) { + itemremoved = true; + } + if ( itemremoved ) { + setVisible( isvisible ); + } +} + + +/*! + Returns the list of target items of this task link. + + \return the list of target item of this task link + \sa from() +*/ +QPtrList KDGanttViewTaskLink::to() const +{ + return toList; +} + + +/*! + Creates a DOM node that describes this task link. + + \param doc the DOM document to which the node belongs + \param parentElement the element into which to insert this node +*/ +void KDGanttViewTaskLink::createNode( QDomDocument& doc, + QDomElement& parentElement ) +{ + QDomElement taskLinkElement = doc.createElement( "TaskLink" ); + parentElement.appendChild( taskLinkElement ); + + QDomElement fromItemsElement = doc.createElement( "FromItems" ); + taskLinkElement.appendChild( fromItemsElement ); + QPtrList fromList = from(); + KDGanttViewItem* item; + for( item = fromList.first(); item; + item = fromList.next() ) + KDGanttXML::createStringNode( doc, fromItemsElement, "Item", item->name() ); + + QDomElement toItemsElement = doc.createElement( "ToItems" ); + taskLinkElement.appendChild( toItemsElement ); + QPtrList toList = to(); + for( item = toList.first(); item; + item = toList.next() ) + KDGanttXML::createStringNode( doc, toItemsElement, "Item", item->name() ); + + KDGanttXML::createBoolNode( doc, taskLinkElement, "Highlight", highlight() ); + KDGanttXML::createColorNode( doc, taskLinkElement, "Color", color() ); + KDGanttXML::createColorNode( doc, taskLinkElement, "HighlightColor", + highlightColor() ); + KDGanttXML::createStringNode( doc, taskLinkElement, "TooltipText", + tooltipText() ); + KDGanttXML::createStringNode( doc, taskLinkElement, "WhatsThisText", + whatsThisText() ); + if( group() ) + KDGanttXML::createStringNode( doc, taskLinkElement, "Group", + group()->name() ); + KDGanttXML::createBoolNode( doc, taskLinkElement, "Visible", + isVisible() ); + KDGanttXML::createStringNode( doc, taskLinkElement, "Linktype", + linkTypeToString( myLinkType ) ); +} + + +/*! + Creates a KDGanttViewTaskLink according to the specification in a DOM + element. + + \param element the DOM element from which to read the specification + \return the newly created task link +*/ +KDGanttViewTaskLink* KDGanttViewTaskLink::createFromDomElement( QDomElement& element ) +{ + QDomNode node = element.firstChild(); + QStringList fromList, toList; + bool highlight = false, visible = false; + QColor color, highlightColor; + QString tooltipText, whatsThisText, group; + LinkType linktype=None; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "FromItems" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Item" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + fromList << value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else if( tagName == "ToItems" ) { + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Item" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + toList << value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + } else if( tagName == "Highlight" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + highlight = value; + } else if( tagName == "Visible" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + visible = value; + } else if( tagName == "Color" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + color = value; + } else if( tagName == "HighlightColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + highlightColor = value; + } else if( tagName == "TooltipText" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + tooltipText = value; + } else if( tagName == "WhatsThisText" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + whatsThisText = value; + } else if( tagName == "Group" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + group = value; + } else if( tagName == "Linktype" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + linktype = stringToLinkType( value ); + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + + QPtrList fromItemList; + QPtrList toItemList; + for( QStringList::const_iterator fromIt = fromList.begin(); + fromIt != fromList.end(); ++fromIt ) { + KDGanttViewItem* item = KDGanttViewItem::find( *fromIt ); + if( item ) + fromItemList.append( item ); + } + for( QStringList::const_iterator toIt = toList.begin(); + toIt != toList.end(); ++toIt ) { + KDGanttViewItem* item = KDGanttViewItem::find( *toIt ); + if( item ) + toItemList.append( item ); + } + // safeguard aginst incorrect names + if (fromItemList.isEmpty()) { + qDebug("Cannot create link: fromItemList is empty"); + return 0; + } + if (toItemList.isEmpty()) { + qDebug("Cannot create link: toItemList is empty"); + return 0; + } + KDGanttViewTaskLink* tl = new KDGanttViewTaskLink( fromItemList, + toItemList ); + tl->setLinkType( linktype ); + tl->setVisible( visible ); + tl->setHighlight( highlight ); + tl->setColor( color ); + tl->setHighlightColor( highlightColor ); + tl->setTooltipText( tooltipText ); + tl->setWhatsThisText( whatsThisText ); + KDGanttViewTaskLinkGroup* gr = KDGanttViewTaskLinkGroup::find( group ); + if( gr ) + tl->setGroup( gr ); + + return tl; +} + +int KDGanttViewTaskLink::linkType() +{ + return myLinkType; +} + +void KDGanttViewTaskLink::setLinkType(int type) +{ + myLinkType = static_cast(type); +} + +int KDGanttViewTaskLink::xOffset(KDGanttViewItem *item) +{ + switch (item->type()) { + case KDGanttViewItem::Task: + return 0; + break; + case KDGanttViewItem::Event: + return 4; + break; + case KDGanttViewItem::Summary: + return 4; + break; + default: + break; + } + return 0; +} + +void KDGanttViewTaskLink::hide() +{ + QPtrListIterator horIt(*horLineList); + QPtrListIterator verIt(*verLineList); + QPtrListIterator horIt2(*horLineList2); + QPtrListIterator verIt2(*verLineList2); + QPtrListIterator horIt3(*horLineList3); + QPtrListIterator topIt(*topList); + QPtrListIterator topLeftIt(*topLeftList); + QPtrListIterator topRightIt(*topRightList); + QPtrListIterator fromIt(fromList); + QPtrListIterator toIt(toList); + for ( ; fromIt.current(); ++fromIt ) { + toIt.toFirst(); + for ( ; toIt.current(); ++toIt ) { + (*horIt)->hide(); + (*verIt)->hide(); + (*horIt2)->hide(); + (*verIt2)->hide(); + (*horIt3)->hide(); + (*topIt)->hide(); + (*topLeftIt)->hide(); + (*topRightIt)->hide(); + ++horIt; + ++verIt; + ++horIt2; + ++verIt2; + ++horIt3; + ++topIt; + ++topLeftIt; + ++topRightIt; + } + } +} + +QString KDGanttViewTaskLink::linkTypeToString( LinkType type ) +{ + switch( type ) { + case None: + return "None"; + break; + case FinishStart: + return "FinishStart"; + break; + case FinishFinish: + return "FinishFinish"; + break; + case StartStart: + return "StartStart"; + break; + case StartFinish: + return "StartFinish"; + break; + default: + break; + } + return ""; +} + +KDGanttViewTaskLink::LinkType KDGanttViewTaskLink::stringToLinkType( const QString type ) +{ + if (type == "FinishStart") + return FinishStart; + if (type == "FinishFinish") + return FinishFinish; + if (type == "StartStart") + return StartStart; + if (type == "StartFinish") + return StartFinish; + + return None; +} diff --git a/kdgantt/KDGanttViewTaskLink.h b/kdgantt/KDGanttViewTaskLink.h new file mode 100644 index 00000000..efafb50f --- /dev/null +++ b/kdgantt/KDGanttViewTaskLink.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef KDGANTTVIEWTASKLINK_H +#define KDGANTTVIEWTASKLINK_H + +#include +#include +#include +#include + +#include "KDGanttViewItem.h" +class KDGanttViewTaskLinkGroup; +class KDCanvasPolygon; +class KDCanvasLine; + +class KDGanttViewTaskLink +{ +public: + enum LinkType { None, FinishStart, StartStart, FinishFinish, StartFinish }; + + KDGanttViewTaskLink( QPtrList from, + QPtrList to, + LinkType type=None ); + KDGanttViewTaskLink( KDGanttViewTaskLinkGroup* group, + QPtrList from, + QPtrList to, + LinkType type=None ); + KDGanttViewTaskLink( KDGanttViewTaskLinkGroup* group, + KDGanttViewItem* from, + KDGanttViewItem* to, + LinkType type=None ); + KDGanttViewTaskLink( KDGanttViewItem* from, + KDGanttViewItem* to, + LinkType type=None ); + ~KDGanttViewTaskLink(); + QPtrList from() const; + QPtrList to() const; + void removeItemFromList( KDGanttViewItem* ); + + void setVisible( bool ); + bool isVisible() const; + + KDGanttViewTaskLinkGroup* group(); + void setGroup( KDGanttViewTaskLinkGroup*) ; + + void setHighlight( bool highlight ); + bool highlight() const; + + void setColor( const QColor& color ); + QColor color() const; + void setHighlightColor( const QColor& color ); + QColor highlightColor() const; + + void setTooltipText( const QString& text ); + QString tooltipText() const; + void setWhatsThisText( const QString& text ); + QString whatsThisText() const; + + void createNode( QDomDocument& doc, + QDomElement& parentElement ); + static KDGanttViewTaskLink* createFromDomElement( QDomElement& ); + + int linkType(); + void setLinkType(int type); + +private: + friend class KDGanttViewTaskLinkGroup; + friend class KDTimeTableWidget; + QPtrList fromList,toList; + QPtrList* horLineList; + QPtrList* verLineList; + QPtrList* topList; + + // also used when linkType != None + QPtrList* horLineList2; + QPtrList* verLineList2; + QPtrList* horLineList3; + QPtrList* topLeftList; + QPtrList* topRightList; + + KDGanttViewTaskLinkGroup* myGroup; + bool isvisible,ishighlighted; + QColor myColor, myColorHL; + QString myToolTipText,myWhatsThisText; + KDTimeTableWidget* myTimeTable; + void initTaskLink(); + void showMe( bool ); + void showMeType( bool ); + void hide(); + int xOffset(KDGanttViewItem *item); + + LinkType myLinkType; + static QString linkTypeToString( LinkType type ); + static LinkType stringToLinkType( const QString type ); +}; + +#endif diff --git a/kdgantt/KDGanttViewTaskLinkGroup.cpp b/kdgantt/KDGanttViewTaskLinkGroup.cpp new file mode 100644 index 00000000..c7142f67 --- /dev/null +++ b/kdgantt/KDGanttViewTaskLinkGroup.cpp @@ -0,0 +1,387 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +#include "KDGanttViewTaskLinkGroup.h" +#include "KDGanttXMLTools.h" +#include "KDGanttView.h" + +QDict KDGanttViewTaskLinkGroup::sGroupDict; + +/*! \class KDGanttViewTaskLinkGroup KDGanttViewTaskLinkGroup.h + A group of task links. + + This class groups a number of task links together in order to + manipulate them uniformly. +*/ + +/*! + Constructs an empty task link group +*/ +KDGanttViewTaskLinkGroup::KDGanttViewTaskLinkGroup() +{ + generateAndInsertName(QString()); +} + +/*! + Destructor + Removes this task link group from the list of task link groups in the + KDGanttView class. +*/ +KDGanttViewTaskLinkGroup::~KDGanttViewTaskLinkGroup() +{ + if (!myTaskLinkList.isEmpty()) { + myTaskLinkList.first()->from().first()->myGanttView->removeTaskLinkGroup(this); + } +} + + + +/*! + Constructs an empty task link group and records it under the name \a + name so that it can later be found again with + KDGanttViewTaskLinkGroup::find(). + + \param name the search name of this task link group +*/ +KDGanttViewTaskLinkGroup::KDGanttViewTaskLinkGroup( const QString& name ) +{ + generateAndInsertName( name ); +} + +/*! + Adds a task link LINK to this group. If the task link is already a member of + another group, it will be removed from it. + This function is equivalent to LINK->setGroup(this), where this is + a pointer to this TaskLinkGroup. + \param link a pointer to the task link to add to this task link group + visible, and false to hide them + \sa remove() +*/ +void KDGanttViewTaskLinkGroup::insert (KDGanttViewTaskLink* link) +{ + link->setGroup(this); +} + + +/*! + Removes a task link LINK from this group. + You may remove a tasklink LINK from its group with LINK->setGroup(0). + + \param link a pointer to the task link to remove from this task link group + \return true if the task link was a member of this group + \sa insert() +*/ +bool KDGanttViewTaskLinkGroup::remove (KDGanttViewTaskLink* link) +{ + KDGanttViewTaskLinkGroup* g = link->group(); + if ((g == this)) + link->setGroup(0); + return (g == this); +} + + +/*! + Specifies whether the task links of this group should be visible or not. + + \param show visible pass true to make the task links of this group + visible, and false to hide them + \sa isVisible() +*/ +void KDGanttViewTaskLinkGroup::setVisible( bool show ) +{ + isvisible = show; + QPtrListIterator it(myTaskLinkList); + for ( ; it.current(); ++it ) { + it.current()->setVisible(show); + } +} + + +/*! + Returns whether the task links of this group should be visible or not. + + \return true if the task links of this group are visible + \sa setVisible() +*/ +bool KDGanttViewTaskLinkGroup::visible() const +{ + return isvisible; +} + + +/*! + Specifies whether the task links of this group should be shown + highlighted. The user can also highlight a task link with the mouse. + + \param highlight pass true in order to highlight the task links in + this group + \sa highlight() +*/ +void KDGanttViewTaskLinkGroup::setHighlight( bool highlight ) +{ + ishighlighted= highlight; + QPtrListIterator it(myTaskLinkList); + for ( ; it.current(); ++it ) + it.current()->setHighlight(highlight ); + +} + + +/*! + Returns whether all task links in this group are highlighted, either + programmatically by setHighlight() or by the user with the + mouse. This method is not particularly useful and is mainly provided + for API uniformity reasons. + + \return true if all the task links in this group are highlighted + \sa setHighlight() +*/ +bool KDGanttViewTaskLinkGroup::highlight() const +{ + return ishighlighted; +} + + +/*! + Specifies the color to draw the task links in this group in. + + \param color the color to draw the task links in this group in + \sa color() +*/ +void KDGanttViewTaskLinkGroup::setColor( const QColor& color ) +{ + myColor = color; + QPtrListIterator it(myTaskLinkList); + for ( ; it.current(); ++it ) + it.current()->setColor(color); +} + + +/*! + Returns the color in which the task links in this group are + drawn. If task links have been assigned individual colors, the + return value of this method is undefined. This method is not + particularly useful and is mainly provided for API uniformity + reasons. + + \return the color in which the task links in this group are drawn + \sa setColor() +*/ +QColor KDGanttViewTaskLinkGroup::color() const +{ + return myColor; +} + + +/*! + Specifies the highlight color to draw the task links in this group in. + + \param color the highlight color to draw the task links in this group in + \sa color() +*/ +void KDGanttViewTaskLinkGroup::setHighlightColor( const QColor& color ) +{ + + myColorHL = color; + QPtrListIterator it(myTaskLinkList); + for ( ; it.current(); ++it ) + it.current()->setHighlightColor(color); +} + + +/*! + Returns the highlight color in which the task links in this group are + drawn. If task links have been assigned individual highlight colors, + the return value of this method is undefined. This method is not + particularly useful and is mainly provided for API uniformity reasons. + + \return the highlight color in which the task links in this group + are drawn + \sa setColor() +*/ +QColor KDGanttViewTaskLinkGroup::highlightColor() const +{ + return myColorHL; +} + + +/*! + Adds a task link LINK to this group. If the task link is already a member of + another group, it will not be removed from it. + \param a pointer to the task link to add to this task link group + visible, and false to hide them + \sa removeItem() +*/ +void KDGanttViewTaskLinkGroup::insertItem (KDGanttViewTaskLink* link) +{ + myTaskLinkList.append (link); +} + + +/*! + Removes a task link LINK from this group. + + \param a pointer to the task link to remove from this task link group + \sa insertItem() +*/ +void KDGanttViewTaskLinkGroup::removeItem (KDGanttViewTaskLink* link) +{ + myTaskLinkList.remove(link); +} + + +/*! + Returns the task link group with the specified name. + + \param name the name to search for + \return the task link group with the specified name; 0 if no group + with that name exists +*/ +KDGanttViewTaskLinkGroup* KDGanttViewTaskLinkGroup::find( const QString& name ) +{ + if (name.isEmpty()) // avoid error msg from QDict + return 0; + return sGroupDict.find( name ); +} + + +/*! + Creates a DOM node that describes this task link group. + + \param doc the DOM document to which the node belongs + \param parentElement the element into which to insert this node +*/ +void KDGanttViewTaskLinkGroup::createNode( QDomDocument& doc, + QDomElement& parentElement ) +{ + QDomElement taskLinkGroupElement = doc.createElement( "TaskLink" ); + parentElement.appendChild( taskLinkGroupElement ); + + KDGanttXML::createBoolNode( doc, taskLinkGroupElement, "Highlight", + highlight() ); + KDGanttXML::createColorNode( doc, taskLinkGroupElement, "Color", color() ); + KDGanttXML::createColorNode( doc, taskLinkGroupElement, "HighlightColor", + highlightColor() ); + KDGanttXML::createBoolNode( doc, taskLinkGroupElement, "Visible", + visible() ); + KDGanttXML::createStringNode( doc, taskLinkGroupElement, "Name", _name ); +} + + +/*! + Creates a KDGanttViewTaskLinkGroup according to the specification in a DOM + element. + + \param element the DOM element from which to read the specification + \return the newly created task link group +*/ +KDGanttViewTaskLinkGroup* KDGanttViewTaskLinkGroup::createFromDomElement( QDomElement& element ) +{ + QDomNode node = element.firstChild(); + bool highlight = false, visible = false; + QColor color, highlightColor; + QString name; + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Highlight" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + highlight = value; + } else if( tagName == "Visible" ) { + bool value; + if( KDGanttXML::readBoolNode( element, value ) ) + visible = value; + } else if( tagName == "Color" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + color = value; + } else if( tagName == "HighlightColor" ) { + QColor value; + if( KDGanttXML::readColorNode( element, value ) ) + highlightColor = value; + } else if( tagName == "Name" ) { + QString value; + if( KDGanttXML::readStringNode( element, value ) ) + name = value; + } else { + qDebug( "Unrecognized tag name: %s", tagName.latin1() ); + Q_ASSERT( false ); + } + } + node = node.nextSibling(); + } + + KDGanttViewTaskLinkGroup* tlg; + if( !name.isEmpty() ) + tlg = new KDGanttViewTaskLinkGroup( name ); + else + tlg = new KDGanttViewTaskLinkGroup(); + + tlg->setHighlight( highlight ); + tlg->setVisible( visible ); + tlg->setHighlightColor( highlightColor ); + tlg->setColor( color ); + + return tlg; +} + +/*! + Generates a unique name if necessary and inserts it into the group + dictionary. +*/ +void KDGanttViewTaskLinkGroup::generateAndInsertName( const QString& name ) +{ + // First check if we already had a name. This can be the case if + // the item was reconstructed from an XML file. + if( !_name.isEmpty() ) + // We had a name, remove it + sGroupDict.remove( _name ); + + QString newName; + if ( name.isEmpty() || sGroupDict.find( name ) ) { + // create unique name + newName.sprintf( "%p", (void* )this ); + while( sGroupDict.find( newName ) ) { + newName += "_0"; + } + } else { + newName = name; + } + sGroupDict.insert( newName, this ); + _name = newName; + //qDebug("KDGanttViewTaskLinkGroup::generateAndInsertName: inserted '%s'",newName.latin1()); +} + diff --git a/kdgantt/KDGanttViewTaskLinkGroup.h b/kdgantt/KDGanttViewTaskLinkGroup.h new file mode 100644 index 00000000..2b0f31b3 --- /dev/null +++ b/kdgantt/KDGanttViewTaskLinkGroup.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef KDGANTTVIEWTASKLINKGROUP_H +#define KDGANTTVIEWTASKLINKGROUP_H + +#include "KDGanttViewTaskLink.h" +#include +#include + +class KDTimeTableWidget; +class KDGanttView; + +class KDGanttViewTaskLinkGroup : public QObject +{ +public: + KDGanttViewTaskLinkGroup( const QString& name ); + KDGanttViewTaskLinkGroup(); + ~KDGanttViewTaskLinkGroup(); + void insert (KDGanttViewTaskLink*) ; + bool remove (KDGanttViewTaskLink*); + + void setVisible( bool show ); + bool visible() const; + + void setHighlight( bool highlight ); + bool highlight() const; + + void setColor( const QColor& color ); + QColor color() const; + void setHighlightColor( const QColor& color ); + QColor highlightColor() const; + + static KDGanttViewTaskLinkGroup* find( const QString& name ); + + void createNode( QDomDocument& doc, + QDomElement& parentElement ); + static KDGanttViewTaskLinkGroup* createFromDomElement( QDomElement& ); + + void generateAndInsertName( const QString& name ); + +private: + friend class KDTimeTableWidget; + friend class KDGanttViewTaskLink; + + bool isvisible,ishighlighted; + QColor myColor, myColorHL; + QPtrList myTaskLinkList; + QString _name; + + void insertItem(KDGanttViewTaskLink*); + void removeItem (KDGanttViewTaskLink*); + + static QDict sGroupDict; +}; + +#endif diff --git a/kdgantt/KDGanttXMLTools.cpp b/kdgantt/KDGanttXMLTools.cpp new file mode 100644 index 00000000..68c83207 --- /dev/null +++ b/kdgantt/KDGanttXMLTools.cpp @@ -0,0 +1,772 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#include "KDGanttXMLTools.h" +#include +#include +#include +#include + +namespace KDGanttXML { + +void createBoolNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, bool value ) +{ + QDomElement newElement = + doc.createElement( elementName ); + parent.appendChild( newElement ); + QDomText elementContent = + doc.createTextNode( value ? "true" : "false" ); + newElement.appendChild( elementContent ); +} + + + +void createSizeNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QSize& value ) +{ + QDomElement newElement = + doc.createElement( elementName ); + parent.appendChild( newElement ); + newElement.setAttribute( "Width", value.width() ); + newElement.setAttribute( "Height", value.height() ); +} + + +void createIntNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, int value ) +{ + QDomElement newElement = + doc.createElement( elementName ); + parent.appendChild( newElement ); + QDomText elementContent = + doc.createTextNode( QString::number( value ) ); + newElement.appendChild( elementContent ); +} + + +void createDoubleNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, double value ) +{ + QDomElement newElement = + doc.createElement( elementName ); + parent.appendChild( newElement ); + QDomText elementContent = + doc.createTextNode( QString::number( value ) ); + newElement.appendChild( elementContent ); +} + + +void createStringNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, + const QString& text ) +{ + QDomElement newElement = + doc.createElement( elementName ); + parent.appendChild( newElement ); + QDomText elementContent = + doc.createTextNode( text ); + newElement.appendChild( elementContent ); +} + + +void createColorNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QColor& color ) +{ + QDomElement colorElement = doc.createElement( elementName ); + parent.appendChild( colorElement ); + colorElement.setAttribute( "Red", + QString::number( color.red() ) ); + colorElement.setAttribute( "Green", + QString::number( color.green() ) ); + colorElement.setAttribute( "Blue", + QString::number( color.blue() ) ); +} + + +void createBrushNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QBrush& brush ) + +{ + QDomElement brushElement = doc.createElement( elementName ); + parent.appendChild( brushElement ); + createColorNode( doc, brushElement, "Color", brush.color() ); + createStringNode( doc, brushElement, "Style", + KDGanttXML::brushStyleToString( brush.style() ) ); + if( brush.style() == Qt::CustomPattern && brush.pixmap() ) + createPixmapNode( doc, brushElement, "Pixmap", *brush.pixmap() ); +} + + +void createPixmapNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QPixmap& pixmap ) +{ + QDomElement pixmapElement = doc.createElement( elementName ); + parent.appendChild( pixmapElement ); + + // Convert the pixmap to an image, save that image to an in-memory + // XPM representation and compress this representation. This + // conforms to the file format Qt Designer uses. + QByteArray ba; + QBuffer buffer( ba ); + buffer.open( IO_WriteOnly ); + QImageIO imgio( &buffer, "XPM" ); + QImage image = pixmap.convertToImage(); + imgio.setImage( image ); + imgio.write(); + buffer.close(); + ulong len = ba.size() * 2; + QByteArray bazip( len ); + ::compress( (uchar*) bazip.data(), &len, (uchar*) ba.data(), ba.size() ); + QString dataString; + static const char hexchars[] = "0123456789abcdef"; + for ( int i = 0; i < (int)len; ++i ) { + uchar c = (uchar) bazip[i]; + dataString += hexchars[c >> 4]; + dataString += hexchars[c & 0x0f]; + } + + createStringNode( doc, pixmapElement, "Format", "XPM.GZ" ); + createIntNode( doc, pixmapElement, "Length", ba.size() ); + createStringNode( doc, pixmapElement, "Data", dataString ); +} + + +void createRectNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QRect& rect ) +{ + QDomElement rectElement = doc.createElement( elementName ); + parent.appendChild( rectElement ); + QDomElement xElement = doc.createElement( "X" ); + rectElement.appendChild( xElement ); + QDomText xContent = doc.createTextNode( QString::number( rect.x() ) ); + xElement.appendChild( xContent ); + QDomElement yElement = doc.createElement( "Y" ); + rectElement.appendChild( yElement ); + QDomText yContent = doc.createTextNode( QString::number( rect.y() ) ); + yElement.appendChild( yContent ); + QDomElement widthElement = doc.createElement( "Width" ); + rectElement.appendChild( widthElement ); + QDomText widthContent = doc.createTextNode( QString::number( rect.width() ) ); + widthElement.appendChild( widthContent ); + QDomElement heightElement = doc.createElement( "Height" ); + rectElement.appendChild( heightElement ); + QDomText heightContent = doc.createTextNode( QString::number( rect.height() ) ); + heightElement.appendChild( heightContent ); +} + + +void createStringListNodes( QDomDocument& doc, QDomNode& parent, + const QString& elementName, + const QStringList* list ) +{ + if( !list ) + return; + + for( QStringList::ConstIterator it = list->begin(); + it != list->end(); ++it ) { + QDomElement element = doc.createElement( elementName ); + parent.appendChild( element ); + QDomText elementContent = doc.createTextNode( *it ); + element.appendChild( elementContent ); + } +} + + +void createFontNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QFont& font ) +{ + QDomElement fontElement = doc.createElement( elementName ); + parent.appendChild( fontElement ); + createStringNode( doc, fontElement, "Family", font.family() ); + createIntNode( doc, fontElement, "PointSize", font.pointSize() ); + createIntNode( doc, fontElement, "PixelSize", font.pixelSize() ); + createIntNode( doc, fontElement, "Weight", font.weight() ); + createBoolNode( doc, fontElement, "Italic", font.italic() ); +#if QT_VERSION < 300 + // Qt 3 handles the charset internally. + createIntNode( doc, fontElement, "CharSet", font.charSet() ); +#endif +} + + +void createPenNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QPen& pen ) +{ + QDomElement penElement = doc.createElement( elementName ); + parent.appendChild( penElement ); + createIntNode( doc, penElement, "Width", pen.width() ); + createColorNode( doc, penElement, "Color", pen.color() ); + createStringNode( doc, penElement, "Style", penStyleToString( pen.style() ) ); +} + + +void createDateTimeNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, + const QDateTime& datetime ) +{ + QDomElement dateTimeElement = doc.createElement( elementName ); + parent.appendChild( dateTimeElement ); + createDateNode( doc, dateTimeElement, "Date", datetime.date() ); + createTimeNode( doc, dateTimeElement, "Time", datetime.time() ); +} + + +void createDateNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QDate& date ) +{ + QDomElement dateElement = doc.createElement( elementName ); + parent.appendChild( dateElement ); + dateElement.setAttribute( "Year", QString::number( date.year() ) ); + dateElement.setAttribute( "Month", QString::number( date.month() ) ); + dateElement.setAttribute( "Day", QString::number( date.day() ) ); +} + + +void createTimeNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QTime& time ) +{ + QDomElement timeElement = doc.createElement( elementName ); + parent.appendChild( timeElement ); + timeElement.setAttribute( "Hour", + QString::number( time.hour() ) ); + timeElement.setAttribute( "Minute", + QString::number( time.minute() ) ); + timeElement.setAttribute( "Second", + QString::number( time.second() ) ); + timeElement.setAttribute( "Millisecond", + QString::number( time.msec() ) ); +} + + +QString penStyleToString( Qt::PenStyle style ) +{ + switch( style ) { + case Qt::NoPen: + return "NoPen"; + case Qt::SolidLine: + return "SolidLine"; + case Qt::DashLine: + return "DashLine"; + case Qt::DotLine: + return "DotLine"; + case Qt::DashDotLine: + return "DashDotLine"; + case Qt::DashDotDotLine: + return "DashDotDotLine"; + default: // should not happen + return "SolidLine"; + } +} + + + +QString brushStyleToString( Qt::BrushStyle style ) +{ + // PENDING(kalle) Support custom patterns + switch( style ) { + case Qt::NoBrush: + return "NoBrush"; + case Qt::SolidPattern: + return "SolidPattern"; + case Qt::Dense1Pattern: + return "Dense1Pattern"; + case Qt::Dense2Pattern: + return "Dense2Pattern"; + case Qt::Dense3Pattern: + return "Dense3Pattern"; + case Qt::Dense4Pattern: + return "Dense4Pattern"; + case Qt::Dense5Pattern: + return "Dense5Pattern"; + case Qt::Dense6Pattern: + return "Dense6Pattern"; + case Qt::Dense7Pattern: + return "Dense7Pattern"; + case Qt::HorPattern: + return "HorPattern"; + case Qt::VerPattern: + return "VerPattern"; + case Qt::CrossPattern: + return "CrossPattern"; + case Qt::BDiagPattern: + return "BDiagPattern"; + case Qt::FDiagPattern: + return "FDiagPattern"; + case Qt::DiagCrossPattern: + return "DiagCrossPattern"; + default: // should not happen (but can for a custom pattern) + return "SolidPattern"; + } +} + + +bool readStringNode( const QDomElement& element, QString& value ) +{ + value = element.text(); + return true; +} + + +bool readIntNode( const QDomElement& element, int& value ) +{ + bool ok = false; + int temp = element.text().toInt( &ok ); + if( ok ) + value = temp; + return ok; +} + + +bool readDoubleNode( const QDomElement& element, double& value ) +{ + bool ok = false; + double temp = element.text().toDouble( &ok ); + if( ok ) + value = temp; + return ok; +} + + +bool readBoolNode( const QDomElement& element, bool& value ) +{ + if( element.text() == "true" ) { + value = true; + return true; + } else if( element.text() == "false" ) { + value = false; + return true; + } else + return false; +} + + +bool readColorNode( const QDomElement& element, QColor& value ) +{ + bool ok = true; + int red, green, blue; + if( element.hasAttribute( "Red" ) ) { + bool redOk = false; + red = element.attribute( "Red" ).toInt( &redOk ); + ok = ok & redOk; + } + if( element.hasAttribute( "Green" ) ) { + bool greenOk = false; + green = element.attribute( "Green" ).toInt( &greenOk ); + ok = ok & greenOk; + } + if( element.hasAttribute( "Blue" ) ) { + bool blueOk = false; + blue = element.attribute( "Blue" ).toInt( &blueOk ); + ok = ok & blueOk; + } + + if( ok ) + value.setRgb( red, green, blue ); + + return ok; +} + + +bool readBrushNode( const QDomElement& element, QBrush& brush ) +{ + bool ok = true; + QColor tempColor; + Qt::BrushStyle tempStyle; + QPixmap tempPixmap; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Color" ) { + ok = ok & readColorNode( element, tempColor ); + } else if( tagName == "Style" ) { + QString value; + ok = ok & readStringNode( element, value ); + tempStyle = stringToBrushStyle( value ); + } else if( tagName == "Pixmap" ) { + ok = ok & readPixmapNode( element, tempPixmap ); + } else { + qDebug( "Unknown tag in brush" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + brush.setColor( tempColor ); + brush.setStyle( tempStyle ); + if( !tempPixmap.isNull() ) + brush.setPixmap( tempPixmap ); + } + + return ok; +} + + +bool readPixmapNode( const QDomElement& element, QPixmap& pixmap ) +{ + bool ok = true; + int tempLengthi; + QString tempData; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Format" ) { + QString formatName; + ok = ok & readStringNode( element, formatName ); +#ifndef NDEBUG + if( formatName != "XPM.GZ" ) + qDebug( "Unsupported pixmap format in XML file" ); +#endif + } else if( tagName == "Length" ) { + ok = ok & readIntNode( element, tempLengthi ); + } else if( tagName == "Data" ) { + ok = ok & readStringNode( element, tempData ); + } else { + qDebug( "Unknown tag in Pixmap" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + if( 0 < tempLengthi ) { + // Decode the image file format in the same way Qt Designer does. + char *ba = new char[ tempData.length() / 2 ]; + for ( int i = 0; i < (int)tempData.length() / 2; ++i ) { + char h = tempData[ 2 * i ].latin1(); + char l = tempData[ 2 * i + 1 ].latin1(); + uchar r = 0; + if ( h <= '9' ) + r += h - '0'; + else + r += h - 'a' + 10; + r = r << 4; + if ( l <= '9' ) + r += l - '0'; + else + r += l - 'a' + 10; + ba[ i ] = r; + } + + if( tempLengthi < (int)tempData.length() * 5 ) + tempLengthi = tempData.length() * 5; + unsigned long tempLength = tempLengthi; + QByteArray baunzip( tempLength ); + ::uncompress( (uchar*) baunzip.data(), &tempLength, + (uchar*) ba, tempData.length()/2 ); + QImage image; + image.loadFromData( (const uchar*)baunzip.data(), tempLength, "XPM" ); + + if( image.isNull() ) + pixmap.resize( 0, 0 ); // This is _not_ an error, we just read a NULL pixmap! + else + ok = ok & pixmap.convertFromImage( image, 0 ); + } else + pixmap.resize( 0, 0 ); // This is _not_ an error, we just read a empty pixmap! + } + + return ok; +} + + +bool readPenNode( const QDomElement& element, QPen& pen ) +{ + bool ok = true; + int tempWidth; + QColor tempColor; + Qt::PenStyle tempStyle; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Width" ) { + ok = ok & readIntNode( element, tempWidth ); + } else if( tagName == "Color" ) { + ok = ok & readColorNode( element, tempColor ); + } else if( tagName == "Style" ) { + QString value; + ok = ok & readStringNode( element, value ); + tempStyle = stringToPenStyle( value ); + } else { + qDebug( "Unknown tag in brush" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + pen.setWidth( tempWidth ); + pen.setColor( tempColor ); + pen.setStyle( tempStyle ); + } + + return ok; +} + +bool readFontNode( const QDomElement& element, QFont& font ) +{ + bool ok = true; + QString family; + int pointSize, pixelSize, weight; + bool italic; + int charSet; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Family" ) { + ok = ok & readStringNode( element, family ); + } else if( tagName == "PointSize" ) { + ok = ok & readIntNode( element, pointSize ); + } else if( tagName == "PixelSize" ) { + ok = ok & readIntNode( element, pixelSize ); + } else if( tagName == "Weight" ) { + ok = ok & readIntNode( element, weight ); + } else if( tagName == "Italic" ) { + ok = ok & readBoolNode( element, italic ); + } else if( tagName == "CharSet" ) { + ok = ok & readIntNode( element, charSet ); + } else { + qDebug( "Unknown tag in color map" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + font.setFamily( family ); + if ( pointSize > 0 ) font.setPointSize( pointSize ); + if ( pixelSize > 0 ) font.setPixelSize( pixelSize ); + font.setWeight( weight ); + font.setItalic( italic ); +#if QT_VERSION < 300 + // Qt 3 handles charsets internally. + font.setCharSet( (QFont::CharSet)charSet ); +#endif + } + + return ok; +} + +bool readRectNode( const QDomElement& element, QRect& value ) +{ + bool ok = true; + int width, height, x, y; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Width" ) { + ok = ok & readIntNode( element, width ); + } else if( tagName == "Height" ) { + ok = ok & readIntNode( element, height ); + } else if( tagName == "X" ) { + ok = ok & readIntNode( element, x ); + } else if( tagName == "Y" ) { + ok = ok & readIntNode( element, y ); + } else { + qDebug( "Unknown tag in rect" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + value.setX( x ); + value.setY( y ); + value.setWidth( width ); + value.setHeight( height ); + } + + return ok; +} + + + +bool readDateTimeNode( const QDomElement& element, QDateTime& datetime ) +{ + bool ok = true; + QDate tempDate; + QTime tempTime; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Date" ) { + ok = ok & readDateNode( element, tempDate ); + } else if( tagName == "Time" ) { + ok = ok & readTimeNode( element, tempTime ); + } else { + qDebug( "Unknown tag in datetime" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + datetime.setDate( tempDate ); + datetime.setTime( tempTime ); + } + + return ok; +} + + +bool readDateNode( const QDomElement& element, QDate& value ) +{ + bool ok = true; + int year, month, day; + if( element.hasAttribute( "Year" ) ) { + bool yearOk = false; + year = element.attribute( "Year" ).toInt( &yearOk ); + ok = ok & yearOk; + } + if( element.hasAttribute( "Month" ) ) { + bool monthOk = false; + month = element.attribute( "Month" ).toInt( &monthOk ); + ok = ok & monthOk; + } + if( element.hasAttribute( "Day" ) ) { + bool dayOk = false; + day = element.attribute( "Day" ).toInt( &dayOk ); + ok = ok & dayOk; + } + + if( ok ) + value.setYMD( year, month, day ); + + return ok; +} + + + +bool readTimeNode( const QDomElement& element, QTime& value ) +{ + bool ok = true; + int hour, minute, second, msec; + if( element.hasAttribute( "Hour" ) ) { + bool hourOk = false; + hour = element.attribute( "Hour" ).toInt( &hourOk ); + ok = ok & hourOk; + } + if( element.hasAttribute( "Minute" ) ) { + bool minuteOk = false; + minute = element.attribute( "Minute" ).toInt( &minuteOk ); + ok = ok & minuteOk; + } + if( element.hasAttribute( "Second" ) ) { + bool secondOk = false; + second = element.attribute( "Second" ).toInt( &secondOk ); + ok = ok & secondOk; + } + if( element.hasAttribute( "Millisecond" ) ) { + bool msecOk = false; + msec = element.attribute( "Millisecond" ).toInt( &msecOk ); + ok = ok & msecOk; + } + + if( ok ) + value.setHMS( hour, minute, second, msec ); + + return ok; +} + + + +Qt::PenStyle stringToPenStyle( const QString& style ) +{ + if( style == "NoPen" ) + return Qt::NoPen; + else if( style == "SolidLine" ) + return Qt::SolidLine; + else if( style == "DashLine" ) + return Qt::DashLine; + else if( style == "DotLine" ) + return Qt::DotLine; + else if( style == "DashDotLine" ) + return Qt::DashDotLine; + else if( style == "DashDotDotLine" ) + return Qt::DashDotDotLine; + else // should not happen + return Qt::SolidLine; +} + + +Qt::BrushStyle stringToBrushStyle( const QString& style ) +{ + // PENDING(kalle) Support custom patterns + if( style == "NoBrush" ) + return Qt::NoBrush; + else if( style == "SolidPattern" ) + return Qt::SolidPattern; + else if( style == "Dense1Pattern" ) + return Qt::Dense1Pattern; + else if( style == "Dense2Pattern" ) + return Qt::Dense2Pattern; + else if( style == "Dense3Pattern" ) + return Qt::Dense3Pattern; + else if( style == "Dense4Pattern" ) + return Qt::Dense4Pattern; + else if( style == "Dense5Pattern" ) + return Qt::Dense5Pattern; + else if( style == "Dense6Pattern" ) + return Qt::Dense6Pattern; + else if( style == "Dense7Pattern" ) + return Qt::Dense7Pattern; + else if( style == "HorPattern" ) + return Qt::HorPattern; + else if( style == "VerPattern" ) + return Qt::VerPattern; + else if( style == "CrossPattern" ) + return Qt::CrossPattern; + else if( style == "BDiagPattern" ) + return Qt::BDiagPattern; + else if( style == "FDiagPattern" ) + return Qt::FDiagPattern; + else if( style == "DiagCrossPattern" ) + return Qt::DiagCrossPattern; + else // should not happen (but can with custom patterns) + return Qt::SolidPattern; +} + +} diff --git a/kdgantt/KDGanttXMLTools.h b/kdgantt/KDGanttXMLTools.h new file mode 100644 index 00000000..67865b96 --- /dev/null +++ b/kdgantt/KDGanttXMLTools.h @@ -0,0 +1,101 @@ +/* -*- Mode: C++ -*- + $Id$ + KDGantt - a multi-platform charting engine +*/ + +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + +#ifndef __KDGANTTXMLTOOLS_H__ +#define __KDGANTTXMLTOOLS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KDGanttXML { + QString penStyleToString( Qt::PenStyle style ); + Qt::PenStyle stringToPenStyle( const QString& style ); + QString brushStyleToString( Qt::BrushStyle style ); + Qt::BrushStyle stringToBrushStyle( const QString& style ); + + void createBoolNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, bool value ); + void createSizeNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QSize& value ); + void createIntNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, int value ); + void createDoubleNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, double value ); + void createStringNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, + const QString& text ); + void createColorNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QColor& color ); + void createBrushNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QBrush& brush ); + void createPixmapNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QPixmap& pixmap ); + void createRectNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QRect& rect ); + void createStringListNodes( QDomDocument& doc, QDomNode& parent, + const QString& elementName, + const QStringList* list ); + void createFontNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QFont& font ); + + void createPenNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QPen& pen ); + void createDateTimeNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, + const QDateTime& datetime ); + void createDateNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QDate& date ); + void createTimeNode( QDomDocument& doc, QDomNode& parent, + const QString& elementName, const QTime& time ); + bool readIntNode( const QDomElement& element, int& value ); + bool readStringNode( const QDomElement& element, QString& value ); + bool readDoubleNode( const QDomElement& element, double& value ); + bool readBoolNode( const QDomElement& element, bool& value ); + bool readColorNode( const QDomElement& element, QColor& value ); + bool readBrushNode( const QDomElement& element, QBrush& brush ); + bool readPixmapNode( const QDomElement& element, QPixmap& pixmap ); + bool readRectNode( const QDomElement& element, QRect& value ); + bool readFontNode( const QDomElement& element, QFont& font ); + bool readPenNode( const QDomElement& element, QPen& pen ); + bool readDateTimeNode( const QDomElement& element, QDateTime& datetime ); + bool readDateNode( const QDomElement& element, QDate& date ); + bool readTimeNode( const QDomElement& element, QTime& time ); +} +#endif diff --git a/kdgantt/Makefile.am b/kdgantt/Makefile.am new file mode 100644 index 00000000..de319d12 --- /dev/null +++ b/kdgantt/Makefile.am @@ -0,0 +1,44 @@ +noinst_LTLIBRARIES = libkdgantt.la + +libkdgantt_la_SOURCES = \ + KDGanttView.cpp \ + KDGanttViewEventItem.cpp \ + KDGanttViewItem.cpp \ + KDGanttViewItemDrag.cpp \ + KDGanttViewSubwidgets.cpp \ + KDGanttViewSummaryItem.cpp \ + KDGanttViewTaskItem.cpp \ + KDGanttViewTaskLink.cpp \ + KDGanttViewTaskLinkGroup.cpp \ + KDGanttMinimizeSplitter.cpp \ + KDGanttSemiSizingControl.cpp \ + KDGanttSizingControl.cpp \ + KDGanttXMLTools.cpp \ + itemAttributeDialog.ui +libkdgantt_la_LDFLAGS = $(all_libraries) -no-undefined +libkdgantt_la_LIBADD = $(LIB_KDEUI) + +noinst_HEADERS = \ + KDGanttViewSubwidgets.h \ + KDGanttMinimizeSplitter.h \ + KDGanttSemiSizingControl.h \ + KDGanttSizingControl.h \ + KDGanttViewEventItem.h \ + KDGanttView.h \ + KDGanttViewItem.h \ + KDGanttViewItemDrag.h \ + KDGanttViewSummaryItem.h \ + KDGanttViewTaskItem.h \ + KDGanttViewTaskLinkGroup.h \ + KDGanttViewTaskLink.h \ + KDGanttXMLTools.h \ + itemAttributeDialog.ui.h \ + qlayoutengine_p.h + +METASOURCES = AUTO + +INCLUDES = $(all_includes) + +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kdgantt.pot +include $(top_srcdir)/admin/Doxyfile.am diff --git a/kdgantt/README_BEFORE_HACKING b/kdgantt/README_BEFORE_HACKING new file mode 100644 index 00000000..96832134 --- /dev/null +++ b/kdgantt/README_BEFORE_HACKING @@ -0,0 +1,9 @@ +This is a mostly verbatim copy of KDGantt, Klarälvdalens Datakonsult +AB's gantt charting engine. We are developing KDGantt at a rapid pace +and will update the version here quite often, so in order to avoid +clashes, we would like to ask you to get in contact with us first +before changing, adding or removing anything here. You can reach us at +kalle@klaralvdalens-datakonsult.se or +lutz@klaralvdalens-datakonsult.se + +Thanks! diff --git a/kdgantt/itemAttributeDialog.ui b/kdgantt/itemAttributeDialog.ui new file mode 100644 index 00000000..8b8d5518 --- /dev/null +++ b/kdgantt/itemAttributeDialog.ui @@ -0,0 +1,737 @@ + +itemAttributeDialog + + + itemAttributeDialog + + + + 0 + 0 + 744 + 319 + + + + Edit Item Attributes + + + + unnamed + + + 11 + + + 6 + + + + Layout4 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel1_2 + + + Item name: + + + + + itemName + + + + + + + Spacer2 + + + Vertical + + + Expanding + + + + 0 + 16 + + + + + + Layout5 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel4 + + + ShapeType: + + + + + TextLabel8 + + + Highlight color: + + + + + TimeEdit5 + + + + + TextLabel1 + + + Lead + + + + + TextLabel5 + + + ShapeColor: + + + + + DateEdit1 + + + true + + + + + + TriangleDown + + + + + TriangleUp + + + + + Diamond + + + + + Square + + + + + Circle + + + + MiddleBox + + + + + DateEdit2 + + + true + + + + + StartShape + + + Start + + + + + ChangeStart + + + Change + + + + + TextLabel2 + + + Middle + + + + + + TriangleDown + + + + + TriangleUp + + + + + Diamond + + + + + Square + + + + + Circle + + + + StartBox + + + + + TextLabel3 + + + End + + + + + DateEdit4 + + + + + DateEdit3 + + + true + + + + + TextLabel2_2 + + + Actual End + + + + + HighMiddle + + + Change + + + + + HighStart + + + Change + + + + + ChangeMiddle + + + Change + + + + + TimeEdit3 + + + true + + + + + ChangeEnd + + + Change + + + + + TextLabel6 + + + Date: + + + + + HighEnd + + + Change + + + + + + TriangleDown + + + + + TriangleUp + + + + + Diamond + + + + + Square + + + + + Circle + + + + EndBox + + + + + TimeEdit4 + + + + + DateEdit5 + + + + + TimeEdit1 + + + true + + + + + TimeEdit2 + + + true + + + + + TextLabel10 + + + Time: + + + + + + + Spacer3 + + + Vertical + + + Expanding + + + + 0 + 16 + + + + + + Layout3 + + + + unnamed + + + 0 + + + 6 + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel7 + + + Displayed text: + + + + + LineEdit1 + + + + 3 + 0 + 0 + 0 + + + + + + + + Layout2 + + + + unnamed + + + 0 + + + 6 + + + + TextLabel9 + + + Text color: + + + AlignVCenter|AlignRight + + + + + ChangeText + + + Change + + + + + + + + + Layout8 + + + + unnamed + + + 0 + + + 6 + + + + PrioLabel + + + Priority: + + + + + PrioSpinBox + + + 199 + + + 1 + + + + + PrioSlider + + + 1 + + + 199 + + + Horizontal + + + + + CalBox + + + Display subitems as group + + + + + + + + + ChangeText + clicked() + itemAttributeDialog + ChangeText_clicked() + + + ChangeStart + clicked() + itemAttributeDialog + ChangeStart_clicked() + + + ChangeMiddle + clicked() + itemAttributeDialog + ChangeMiddle_clicked() + + + ChangeEnd + clicked() + itemAttributeDialog + ChangeEnd_clicked() + + + HighStart + clicked() + itemAttributeDialog + HighStart_clicked() + + + HighMiddle + clicked() + itemAttributeDialog + HighMiddle_clicked() + + + HighEnd + clicked() + itemAttributeDialog + HighEnd_clicked() + + + DateEdit1 + valueChanged(const QDate&) + itemAttributeDialog + DateEdit1_valueChanged(const QDate&) + + + TimeEdit1 + valueChanged(const QTime&) + itemAttributeDialog + TimeEdit1_valueChanged(const QTime&) + + + DateEdit2 + valueChanged(const QDate&) + itemAttributeDialog + DateEdit2_valueChanged(const QDate&) + + + TimeEdit2 + valueChanged(const QTime&) + itemAttributeDialog + TimeEdit2_valueChanged(const QTime&) + + + DateEdit3 + valueChanged(const QDate&) + itemAttributeDialog + DateEdit3_valueChanged(const QDate&) + + + TimeEdit3 + valueChanged(const QTime&) + itemAttributeDialog + TimeEdit3_valueChanged(const QTime&) + + + LineEdit1 + textChanged(const QString&) + itemAttributeDialog + LineEdit1_textChanged(const QString&) + + + StartBox + activated(const QString&) + itemAttributeDialog + StartBox_activated(const QString&) + + + MiddleBox + activated(const QString&) + itemAttributeDialog + MiddleBox_activated(const QString&) + + + EndBox + activated(const QString&) + itemAttributeDialog + EndBox_activated(const QString&) + + + DateEdit4 + valueChanged(const QDate&) + itemAttributeDialog + DateEdit4_valueChanged(const QDate&) + + + TimeEdit4 + valueChanged(const QTime&) + itemAttributeDialog + TimeEdit4_valueChanged(const QTime&) + + + DateEdit5 + valueChanged(const QDate&) + itemAttributeDialog + DateEdit5_valueChanged(const QDate&) + + + TimeEdit5 + valueChanged(const QTime&) + itemAttributeDialog + TimeEdit5_valueChanged(const QTime&) + + + itemName + textChanged(const QString&) + itemAttributeDialog + itemName_textChanged(const QString&) + + + PrioSpinBox + valueChanged(int) + itemAttributeDialog + PrioSpinBox_valueChanged(int) + + + CalBox + toggled(bool) + itemAttributeDialog + CalBox_toggled(bool) + + + PrioSlider + valueChanged(int) + itemAttributeDialog + PrioSlider_valueChanged(int) + + + + KDGanttViewSummaryItem.h + KDGanttViewItem.h + KDGanttView.h + KDGanttViewEventItem.h + KDGanttViewEventItem.h + KDGanttViewItem.h + KDGanttViewSummaryItem.h + itemAttributeDialog.ui.h + + + KDGanttViewItem * myItem + + + init() + ChangeText_clicked() + ChangeStart_clicked() + ChangeMiddle_clicked() + ChangeEnd_clicked() + resetTime( KDGanttViewItem * item ) + reset( KDGanttViewItem * item ) + HighStart_clicked() + HighMiddle_clicked() + HighEnd_clicked() + DateEdit1_valueChanged( const QDate & ) + TimeEdit1_valueChanged( const QTime & ) + DateEdit2_valueChanged( const QDate & ) + TimeEdit2_valueChanged( const QTime & ) + DateEdit3_valueChanged( const QDate & ) + TimeEdit3_valueChanged( const QTime & ) + LineEdit1_textChanged( const QString & ) + StartBox_activated( const QString & s ) + MiddleBox_activated( const QString & s ) + EndBox_activated( const QString & s ) + DateEdit4_valueChanged( const QDate & ) + TimeEdit4_valueChanged( const QTime & ) + DateEdit5_valueChanged( const QDate & ) + TimeEdit5_valueChanged( const QTime & ) + itemName_textChanged( const QString & ) + PrioSpinBox_valueChanged( int val ) + CalBox_toggled( bool mode ) + PrioSlider_valueChanged( int val ) + getItem() + + + diff --git a/kdgantt/itemAttributeDialog.ui.h b/kdgantt/itemAttributeDialog.ui.h new file mode 100644 index 00000000..9ce60bdb --- /dev/null +++ b/kdgantt/itemAttributeDialog.ui.h @@ -0,0 +1,535 @@ +/**************************************************************************** + ** Copyright (C) 2002-2004 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDGantt library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDGantt licenses may use this file in + ** accordance with the KDGantt Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for + ** information about KDGantt Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + ** As a special exception, permission is given to link this program + ** with any edition of Qt, and distribute the resulting executable, + ** without including the source code for Qt in the source distribution. + ** + **********************************************************************/ + + +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename slots use Qt Designer which will +** update this file, preserving your code. Create an init() slot in place of +** a constructor, and a destroy() slot in place of a destructor. +*****************************************************************************/ + +#include +void itemAttributeDialog::init( ) +{ + + myItem = 0; +} + + + + +void itemAttributeDialog::ChangeText_clicked() +{ + if ( !myItem) return; + QColor c = QColorDialog::getColor( myItem->textColor(), this ); + if ( c.isValid() ) + myItem->setTextColor( c ); + QPixmap * pix = (QPixmap *)ChangeText->pixmap(); + pix->fill( myItem->textColor() ); + ChangeText->repaint(); +} + + +void itemAttributeDialog::ChangeStart_clicked() +{ + if ( !myItem) return; + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + QColor st, mi, en; + myItem->colors( st, mi, en ); + QColor c = QColorDialog::getColor( st, this ); + if ( c.isValid() ) { + st = c; + ChangeStart->setPixmap( KDGanttView::getPixmap( start, st, backgroundColor(), 10 ) ); + myItem->setColors( st, mi, en ); + } + +} + + +void itemAttributeDialog::ChangeMiddle_clicked() +{ + if ( !myItem) return; + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + QColor st, mi, en; + myItem->colors( st, mi, en ); + QColor c = QColorDialog::getColor( mi, this ); + if ( c.isValid() ) { + mi = c; + ChangeMiddle->setPixmap( KDGanttView::getPixmap( middle, mi, backgroundColor(), 10 ) ); + myItem->setColors( st, mi, en ); + } +} + + +void itemAttributeDialog::ChangeEnd_clicked() +{ + if ( !myItem) return; + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + QColor st, mi, en; + myItem->colors( st, mi, en ); + QColor c = QColorDialog::getColor( en, this ); + if ( c.isValid() ) { + en = c; + ChangeEnd->setPixmap( KDGanttView::getPixmap( end, en, backgroundColor(), 10 ) ); + myItem->setColors( st, mi, en ); + } +} +void itemAttributeDialog::resetTime( KDGanttViewItem * item ) +{ + if ( !item ) return; + myItem = 0; + DateEdit1->setDate( item->startTime().date() ); + TimeEdit1->setTime( item->startTime().time() ); + switch( item->type() ) { + case KDGanttViewItem::Event: + + DateEdit4->setDate( ((KDGanttViewEventItem*)item)->leadTime().date() ); + TimeEdit4->setTime( ((KDGanttViewEventItem*)item)->leadTime().time() ); + + break; + case KDGanttViewItem::Summary: + + + DateEdit3->setDate( item->endTime().date() ); + TimeEdit3->setTime( item->endTime().time() ); + DateEdit2->setDate(((KDGanttViewSummaryItem*)item) ->middleTime().date() ); + TimeEdit2->setTime( ((KDGanttViewSummaryItem*)item)->middleTime().time() ); + DateEdit5->setDate(((KDGanttViewSummaryItem*)item) ->actualEndTime().date() ); + TimeEdit5->setTime( ((KDGanttViewSummaryItem*)item)->actualEndTime().time() ); + break; + case KDGanttViewItem::Task: + + + DateEdit3->setDate( item->endTime().date() ); + TimeEdit3->setTime( item->endTime().time() ); + break; + default: + ; + } + myItem = item; +} + +void itemAttributeDialog::reset( KDGanttViewItem * item ) +{ + myItem = 0; + if ( !item ) { + hide(); + return; + } + StartBox->setEnabled( true ); + switch( item->type() ) { + case KDGanttViewItem::Event: + MiddleBox->setEnabled( false ); + EndBox->setEnabled( false ); + ChangeMiddle->setEnabled( false ); + ChangeEnd->setEnabled( false ); + HighMiddle->setEnabled( false ); + HighEnd->setEnabled( false ); + DateEdit2->setEnabled( false ); + TimeEdit2->setEnabled( false ); + DateEdit3->setEnabled( false ); + TimeEdit3->setEnabled( false ); + DateEdit4->setEnabled( true ); + TimeEdit4->setEnabled( true ); + DateEdit5->setEnabled( false ); + TimeEdit5->setEnabled( false ); + DateEdit4->setDate( ((KDGanttViewEventItem*)item)->leadTime().date() ); + TimeEdit4->setTime( ((KDGanttViewEventItem*)item)->leadTime().time() ); + + break; + case KDGanttViewItem::Summary: + MiddleBox->setEnabled( true ); + EndBox->setEnabled( true ); + ChangeMiddle->setEnabled( true ); + ChangeEnd->setEnabled( true ); + HighMiddle->setEnabled( true ); + HighEnd->setEnabled( true ); + + DateEdit2->setEnabled( true ); + TimeEdit2->setEnabled( true ); + DateEdit3->setEnabled( true ); + TimeEdit3->setEnabled( true ); + DateEdit4->setEnabled( false ); + TimeEdit4->setEnabled( false ); + DateEdit5->setEnabled( true ); + TimeEdit5->setEnabled( true ); + + DateEdit3->setDate( item->endTime().date() ); + TimeEdit3->setTime( item->endTime().time() ); + DateEdit2->setDate(((KDGanttViewSummaryItem*)item) ->middleTime().date() ); + TimeEdit2->setTime( ((KDGanttViewSummaryItem*)item)->middleTime().time() ); + DateEdit5->setDate(((KDGanttViewSummaryItem*)item) ->actualEndTime().date() ); + TimeEdit5->setTime( ((KDGanttViewSummaryItem*)item)->actualEndTime().time() ); + break; + case KDGanttViewItem::Task: + MiddleBox->setEnabled( false ); + StartBox->setEnabled( false ); + EndBox->setEnabled( false ); + ChangeMiddle->setEnabled( false ); + ChangeEnd->setEnabled( false ); + HighMiddle->setEnabled( false ); + HighEnd->setEnabled( false ); + + DateEdit2->setEnabled( false ); + TimeEdit2->setEnabled( false ); + DateEdit3->setEnabled( true ); + TimeEdit3->setEnabled( true ); + DateEdit4->setEnabled( false ); + TimeEdit4->setEnabled( false ); + DateEdit5->setEnabled( false ); + TimeEdit5->setEnabled( false ); + + DateEdit3->setDate( item->endTime().date() ); + TimeEdit3->setTime( item->endTime().time() ); + break; + default: + ; + } + if (item->firstChild() && item->displaySubitemsAsGroup() ) { + + DateEdit2->setEnabled( false ); + TimeEdit2->setEnabled( false ); + DateEdit3->setEnabled( false ); + TimeEdit3->setEnabled( false ); + DateEdit4->setEnabled( false ); + TimeEdit4->setEnabled( false ); + DateEdit5->setEnabled( false ); + TimeEdit5->setEnabled( false ); + DateEdit1->setEnabled( false ); + TimeEdit1->setEnabled( false ); + + } else { + DateEdit1->setEnabled( true ); + TimeEdit1->setEnabled( true ); + } + DateEdit1->setDate( item->startTime().date() ); + TimeEdit1->setTime( item->startTime().time() ); + if ( item->pixmap() != 0 ) + setIcon( *(item->pixmap()) ); + setCaption( "Properties of " + ((QListViewItem*)item)->text(0) ); + itemName->setText(((QListViewItem*)item)->text(0) ); + +// DateEdit1->setRange(item->startTime().date().addYears(-10), item->endTime().date() ); + // DateEdit3->setRange(item->startTime().date(), item->endTime().date().addYears(10)); + LineEdit1->setText( item->text() ); + KDGanttViewItem::Shape start, middle, end; + item->shapes( start, middle, end ); + QColor st, mi, en; + item->colors( st, mi, en ); + ChangeStart->setPixmap( KDGanttView::getPixmap( start, st, backgroundColor(), 10 ) ); + ChangeMiddle->setPixmap( KDGanttView::getPixmap( middle, mi, backgroundColor(), 10 ) ); + ChangeEnd->setPixmap( KDGanttView::getPixmap( end, en, backgroundColor(), 10 ) ); + item->highlightColors( st, mi, en ); + HighStart->setPixmap( KDGanttView::getPixmap( start, st, backgroundColor(), 10 ) ); + HighMiddle->setPixmap( KDGanttView::getPixmap( middle, mi, backgroundColor(), 10 ) ); + HighEnd->setPixmap( KDGanttView::getPixmap( end, en, backgroundColor(), 10 ) ); + ChangeText->setPixmap(QPixmap( 16,16 )); + QPixmap * pix; + pix = (QPixmap *)ChangeText->pixmap(); + pix->fill( item->textColor() ); + StartBox->setCurrentItem((int)start ); + MiddleBox->setCurrentItem((int)middle ); + EndBox->setCurrentItem( (int) end ); + CalBox->setChecked( item-> displaySubitemsAsGroup() ); + PrioSpinBox->setValue( item->priority() ); + PrioSlider->setValue( item->priority() ); + myItem = item; + +} + +void itemAttributeDialog::HighStart_clicked() +{ + if ( !myItem) return; + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + QColor st, mi, en; + myItem->highlightColors( st, mi, en ); + QColor c = QColorDialog::getColor( st, this ); + if ( c.isValid() ) { + st = c; + HighStart->setPixmap( KDGanttView::getPixmap( start, st, backgroundColor(), 10 ) ); + myItem->setHighlightColors( st, mi, en ); + } + +} + + +void itemAttributeDialog::HighMiddle_clicked() +{ + if ( !myItem) return; + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + QColor st, mi, en; + myItem->highlightColors( st, mi, en ); + QColor c = QColorDialog::getColor( mi, this ); + if ( c.isValid() ) { + mi = c; + HighMiddle->setPixmap( KDGanttView::getPixmap( middle, mi, backgroundColor(), 10 ) ); + myItem->setHighlightColors( st, mi, en ); + } + +} + + +void itemAttributeDialog::HighEnd_clicked() +{ + if ( !myItem) return; + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + QColor st, mi, en; + myItem->highlightColors( st, mi, en ); + QColor c = QColorDialog::getColor( en, this ); + if ( c.isValid() ) { + en = c; + HighEnd->setPixmap( KDGanttView::getPixmap( end, en, backgroundColor(), 10 ) ); + myItem->setHighlightColors( st, mi, en ); + } + +} + + +void itemAttributeDialog::DateEdit1_valueChanged( const QDate & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit1->date() ); + dt.setTime( TimeEdit1->time() ); + if ( dt.isValid() ) + { + myItem->setStartTime( dt ); + resetTime( myItem ); + } +} + + +void itemAttributeDialog::TimeEdit1_valueChanged( const QTime & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit1->date() ); + dt.setTime( TimeEdit1->time() ); + if ( dt.isValid() ) { + myItem->setStartTime( dt ); + + resetTime( myItem ); +} +} + + +void itemAttributeDialog::DateEdit2_valueChanged( const QDate & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit2->date() ); + dt.setTime( TimeEdit2->time() ); + if ( dt.isValid() ) { + ((KDGanttViewSummaryItem*)myItem)->setMiddleTime( dt ); + resetTime( myItem ); +} +} + + +void itemAttributeDialog::TimeEdit2_valueChanged( const QTime & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit2->date() ); + dt.setTime( TimeEdit2->time() ); + if ( dt.isValid() ) { + ((KDGanttViewSummaryItem*)myItem)->setMiddleTime( dt ); + resetTime( myItem ); +} +} + + +void itemAttributeDialog::DateEdit3_valueChanged( const QDate & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit3->date() ); + dt.setTime( TimeEdit3->time() ); + if ( dt.isValid() ) { + myItem->setEndTime( dt ); + resetTime( myItem ); +} +} + + +void itemAttributeDialog::TimeEdit3_valueChanged( const QTime & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit3->date() ); + dt.setTime( TimeEdit3->time() ); + if ( dt.isValid() ) { + myItem->setEndTime( dt ); + resetTime( myItem ); +} +} + + +void itemAttributeDialog::LineEdit1_textChanged( const QString & ) +{ + if ( !myItem) return; + myItem->setText(LineEdit1->text()); +} + + +void itemAttributeDialog::StartBox_activated( const QString & s ) +{ + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + start = KDGanttViewItem::stringToShape( s ); + myItem->setShapes( start, middle, end ); + reset( myItem ); +} + + +void itemAttributeDialog::MiddleBox_activated( const QString & s ) +{ + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + middle = KDGanttViewItem::stringToShape( s ); + myItem->setShapes( start, middle, end ); + reset( myItem ); + +} + + +void itemAttributeDialog::EndBox_activated( const QString & s ) +{ + KDGanttViewItem::Shape start, middle, end; + myItem->shapes( start, middle, end ); + end = KDGanttViewItem::stringToShape( s ); + myItem->setShapes( start, middle, end ); + reset( myItem ); + +} + + +void itemAttributeDialog::DateEdit4_valueChanged( const QDate & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit4->date() ); + dt.setTime( TimeEdit4->time() ); + if ( dt.isValid() ) { + ((KDGanttViewEventItem*)myItem)->setLeadTime( dt ); + resetTime( myItem ); + } +} + + +void itemAttributeDialog::TimeEdit4_valueChanged( const QTime & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit4->date() ); + dt.setTime( TimeEdit4->time() ); + if ( dt.isValid() ) { + ((KDGanttViewEventItem*)myItem)->setLeadTime( dt ); + resetTime( myItem ); +} +} + + +void itemAttributeDialog::DateEdit5_valueChanged( const QDate & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit5->date() ); + dt.setTime( TimeEdit5->time() ); + if ( dt.isValid() ) { + ((KDGanttViewSummaryItem*)myItem)->setActualEndTime( dt ); + resetTime( myItem ); +} +} + + +void itemAttributeDialog::TimeEdit5_valueChanged( const QTime & ) +{ + if ( !myItem) return; + QDateTime dt; + dt.setDate( DateEdit5->date() ); + dt.setTime( TimeEdit5->time() ); + if ( dt.isValid() ) { + ((KDGanttViewSummaryItem*)myItem)->setActualEndTime( dt ); + resetTime( myItem ); +} +} + + + +void itemAttributeDialog::itemName_textChanged( const QString & ) +{ + if ( !myItem) return; + ((QListViewItem*)myItem)->setText( 0, itemName->text() ); + setCaption( "Properties of " + itemName->text() ); +} + + +void itemAttributeDialog::PrioSpinBox_valueChanged( int val ) +{ + if ( !myItem) return; + myItem->setPriority( val ); + PrioSlider->blockSignals( true ); + PrioSlider->setValue( val ); + PrioSlider->blockSignals( false ); + +} + + +void itemAttributeDialog::CalBox_toggled( bool mode ) +{ + if ( !myItem) return; + myItem->setDisplaySubitemsAsGroup( mode ); + if (myItem->firstChild() ) + reset(myItem); +} + + +void itemAttributeDialog::PrioSlider_valueChanged( int val ) +{ +if ( !myItem) return; + myItem->setPriority( val ); + PrioSpinBox->blockSignals( true ); + PrioSpinBox->setValue( val ); + PrioSpinBox->blockSignals( false ); +} + + +KDGanttViewItem* itemAttributeDialog::getItem() +{ + return myItem; +} diff --git a/kdgantt/qlayoutengine_p.h b/kdgantt/qlayoutengine_p.h new file mode 100644 index 00000000..2d6a5568 --- /dev/null +++ b/kdgantt/qlayoutengine_p.h @@ -0,0 +1,111 @@ +// THIS IS A COPY OF THE FILE FOUND IN $QTDIR/src/kernel. Needed to modify qsplitter + +/**************************************************************************** +** $Id$ +** +** Internal header file. +** +** Created : 981027 +** +** Copyright (C) 1998-99 by Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QLAYOUTENGINE_P_H +#define QLAYOUTENGINE_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qlayout.cpp, qlayoutengine.cpp, qmainwindow.cpp and qsplitter.cpp. +// This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// +// + + +#ifndef QT_H +#include "qabstractlayout.h" +#endif // QT_H + +#ifndef QT_NO_LAYOUT +struct QLayoutStruct +{ + void initParameters() { minimumSize = sizeHint = 0; + maximumSize = QWIDGETSIZE_MAX; expansive = FALSE; empty = TRUE; } + void init() { stretch = 0; initParameters(); } + //permanent storage: + int stretch; + //parameters: + QCOORD sizeHint; + QCOORD maximumSize; + QCOORD minimumSize; + bool expansive; + bool empty; + //temporary storage: + bool done; + //result: + int pos; + int size; +}; + + +void qGeomCalc( QMemArray &chain, int start, int count, int pos, + int space, int spacer ); + + + +/* + Modify total maximum (max) and total expansion (exp) + when adding boxmax/boxexp. + + Expansive boxes win over non-expansive boxes. +*/ +static inline void qMaxExpCalc( QCOORD & max, bool &exp, + QCOORD boxmax, bool boxexp ) +{ + if ( exp ) { + if ( boxexp ) + max = QMAX( max, boxmax ); + } else { + if ( boxexp ) + max = boxmax; + else + max = QMIN( max, boxmax ); + } + exp = exp || boxexp; +} + +#endif //QT_NO_LAYOUT +#endif -- cgit v1.2.3