diff --git a/examples/Gantt/project/mainwindow.cpp b/examples/Gantt/project/mainwindow.cpp
index 961a4a5..3038082 100644
--- a/examples/Gantt/project/mainwindow.cpp
+++ b/examples/Gantt/project/mainwindow.cpp
@@ -1,497 +1,478 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "mainwindow.h"
#include "projectmodel.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
-#include
#include
#include
#include
#include
#include
#include
#include
class ItemTypeComboBox : public QComboBox {
Q_OBJECT
Q_PROPERTY( KGantt::ItemType itemType READ itemType WRITE setItemType )
public:
explicit ItemTypeComboBox( QWidget* parent = nullptr );
KGantt::ItemType itemType() const;
public slots:
void setItemType( KGantt::ItemType typ );
};
ItemTypeComboBox::ItemTypeComboBox( QWidget* parent )
: QComboBox( parent )
{
addItem( tr( "Task" ), QVariant( KGantt::TypeTask ) );
addItem( tr( "Event" ), QVariant( KGantt::TypeEvent ) );
addItem( tr( "Summary" ), QVariant( KGantt::TypeSummary ) );
}
KGantt::ItemType ItemTypeComboBox::itemType() const
{
return static_cast( itemData( currentIndex() ).toInt() );
}
void ItemTypeComboBox::setItemType( KGantt::ItemType typ )
{
setCurrentIndex( typ-1 );
}
class MyItemDelegate : public KGantt::ItemDelegate {
public:
explicit MyItemDelegate( QObject* parent = nullptr );
/*reimp*/ QWidget* createEditor( QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& idx ) const Q_DECL_OVERRIDE;
/*reimp*/ void setEditorData( QWidget* editor, const QModelIndex& index ) const Q_DECL_OVERRIDE;
/*reimp*/ void setModelData( QWidget* editor, QAbstractItemModel* model,
const QModelIndex & index ) const Q_DECL_OVERRIDE;
protected:
/*reimp*/void drawDisplay( QPainter* painter, const QStyleOptionViewItem & option,
const QRect& rect, const QString& text ) const Q_DECL_OVERRIDE;
};
MyItemDelegate::MyItemDelegate( QObject* parent )
: KGantt::ItemDelegate( parent )
{
}
QWidget* MyItemDelegate::createEditor( QWidget* parent,
const QStyleOptionViewItem& option,
const QModelIndex& idx ) const
{
qDebug() << "MyItemDelegate::createEditor("<(editor)) && index.isValid() ) {
c->setItemType(static_cast(index.data(Qt::EditRole).toInt()));
} else {
ItemDelegate::setEditorData(editor,index);
}
}
void MyItemDelegate::setModelData ( QWidget* editor, QAbstractItemModel* model,
const QModelIndex & index ) const
{
ItemTypeComboBox* c;
if ( (c = qobject_cast(editor)) && index.isValid() ) {
model->setData(index,c->itemType());
} else {
ItemDelegate::setModelData(editor,model,index);
}
}
void MyItemDelegate::drawDisplay( QPainter* painter, const QStyleOptionViewItem& option,
const QRect& rect, const QString& text ) const
{
//qDebug() << "MyItemDelegate::drawDisplay(" <(text.toInt());
QString str;
switch (typ) {
case KGantt::TypeTask: str = tr("Task"); break;
case KGantt::TypeEvent: str = tr("Event"); break;
case KGantt::TypeSummary: str = tr("Summary"); break;
default: str = tr("None"); break;
}
ItemDelegate::drawDisplay(painter,option,rect,str);
}
///////////////////////////////////////////////////////////////////////////////
// Provide custom background and foreground
///////////////////////////////////////////////////////////////////////////////
class DateTimeGrid : public KGantt::DateTimeGrid
{
public:
DateTimeGrid(QObject* parent = nullptr) {
setParent(parent);
setFreeDays( QSet() );
setFreeDaysBrush( QBrush( Qt::NoBrush ) );
}
~DateTimeGrid() { }
//virtual void paintUserDefinedHeader(QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect, qreal offset, const KGantt::DateTimeScaleFormatter* formatter, QWidget* widget = 0);
void drawBackground(QPainter* painter, const QRectF& rect) Q_DECL_OVERRIDE;
void drawForeground(QPainter* painter, const QRectF& rect) Q_DECL_OVERRIDE;
};
void DateTimeGrid::drawBackground(QPainter* painter, const QRectF& rect)
{
QLinearGradient grad;
grad.setCoordinateMode( QGradient::ObjectBoundingMode );
grad.setStart( 0.5, 0.5 );
grad.setFinalStop( 0.5, 0.0 );
grad.setSpread( QGradient::ReflectSpread );
// grad.setCenter( 0.5, 0.5 );
// grad.setFocalPoint( 0.5, 0.5 );
// grad.setRadius( 0.5 );
QColor currentColor = Qt::blue;
for ( qreal i = 0; i <= 1.0; i += 0.1 )
{
currentColor = currentColor.lighter( 100 + 20 * i );
grad.setColorAt( i, currentColor );
}
QBrush brush( grad);
//brush.setColor(Qt::lightGray);
QRectF r = computeRect(QDateTime::currentDateTime(),
QDateTime::currentDateTime().addDays(2),
rect);
painter->fillRect(r, brush);
- KGantt::DateTimeGrid::drawBackground(painter, rect);
}
void DateTimeGrid::drawForeground(QPainter* painter, const QRectF& rect)
{
painter->save();
QRectF r = computeRect(QDateTime::currentDateTime(),
QDateTime::currentDateTime().addDays(2),
rect);
static QString text("Holiday");
QFont font = painter->font();
font.setPixelSize(r.width()/5);
QFontMetrics fm(font);
int width = fm.width(text);
int height = fm.boundingRect(text).height();
painter->translate(r.center());
painter->translate(-width/2, height/2);
painter->setFont(font);
painter->drawText(0, 0, text);
painter->restore();
-
- KGantt::DateTimeGrid::drawForeground(painter, rect);
}
/*
void DateTimeGrid::paintUserDefinedHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect, qreal offset, const KGantt::DateTimeScaleFormatter* formatter, QWidget* widget)
{
const QStyle* const style = widget ? widget->style() : QApplication::style();
QDateTime dt = formatter->currentRangeBegin( mapToDateTime( offset + exposedRect.left() ) ).toUTC();
qreal x = mapFromDateTime( dt );
while ( x < exposedRect.right() + offset ) {
const QDateTime next = formatter->nextRangeBegin( dt );
const qreal nextx = mapFromDateTime( next );
QStyleOptionHeader opt;
if ( widget ) opt.init( widget );
opt.rect = QRectF( x - offset+1, headerRect.top(), qMax( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
//opt.state = QStyle::State_Raised | QStyle::State_Enabled;
opt.textAlignment = formatter->alignment();
opt.text = formatter->text( dt );
// use white text on black background
opt.palette.setColor(QPalette::Window, QColor("black"));
opt.palette.setColor(QPalette::ButtonText, QColor("white"));
style->drawControl( QStyle::CE_Header, &opt, painter, widget );
dt = next;
x = nextx;
}
}
*/
MainWindow::MainWindow( QWidget* parent )
: QMainWindow( parent ),
m_model( new ProjectModel( this ) ),
m_view( new KGantt::View )
{
m_view->setModel( m_model );
m_view->setSelectionModel( new QItemSelectionModel(m_model));
// slotToolsNewItem();
m_view->leftView()->setItemDelegateForColumn( 1, new MyItemDelegate( this ) );
m_view->leftView()->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
m_view->graphicsView()->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
m_view->setGrid(new DateTimeGrid(this));
- // Display timeline
- KGantt::DateTimeGrid *grid = static_cast(m_view->grid());
- grid->setTimelinePen(QPen(Qt::red, 2));
-// grid->setTimelineTime(QDateTime::currentDateTime().addDays(-1));
- grid->setTimelineOptions(KGantt::DateTimeGrid::Background | KGantt::DateTimeGrid::UseCustomPen);
- // Update timeline every 5 seconds
- QTimer *timelineTimer = new QTimer(this);
- timelineTimer->setInterval(5000);
- timelineTimer->start();
- connect(timelineTimer, SIGNAL(timeout()), grid, SLOT(setTimelineTime()));
-
+
//QItemEditorCreatorBase *creator = new QItemEditorCreator("itemType");
//QItemEditorFactory* factory = new QItemEditorFactory;
//factory->registerEditor( QVariant( KGantt::TypeTask ).type(), creator );
//m_view->itemDelegate()->setItemEditorFactory( factory );
setCentralWidget( m_view );
QMenuBar* mb = menuBar();
QMenu* fileMenu = new QMenu( tr( "&File" ) );
#ifndef QT_NO_PRINTER
fileMenu->addAction( tr( "&Save as PDF..." ), this, SLOT(slotFileSavePdf()) );
fileMenu->addAction( tr( "&Print..." ), this, SLOT(slotFilePrint()) );
#endif
fileMenu->addSeparator();
fileMenu->addAction( tr( "&Quit" ), this, SLOT(slotFileQuit()) );
mb->addMenu( fileMenu );
QMenu* toolsMenu = new QMenu( tr( "&Tools" ) );
toolsMenu->addAction( tr( "&New Item" ), this, SLOT(slotToolsNewItem()) );
toolsMenu->addAction( tr( "&Add Item" ), this, SLOT(slotToolsAppendItem()) );
toolsMenu->addSeparator();
QMenu *alignMenu = toolsMenu->addMenu( tr( "Ali&gn" ) );
alignMenu->addAction( tr( "&Left" ), this, SLOT(slotAlignLeft()) );
alignMenu->addAction( tr( "&Center" ), this, SLOT(slotAlignCenter()) );
alignMenu->addAction( tr( "&Right" ), this, SLOT(slotAlignRight()) );
alignMenu->addAction( tr( "&Hidden" ), this, SLOT(slotAlignHidden()) );
toolsMenu->addSeparator();
toolsMenu->addAction( tr( "&Collapse All" ), this, SLOT(slotCollapseAll()) );
toolsMenu->addAction( tr( "&Expand All" ), this, SLOT(slotExpandAll()) );
mb->addMenu( toolsMenu );
/*
slotToolsNewItem();
slotToolsNewItem();
slotToolsNewItem();
for (int i = 0; i < 3; ++i) {
m_model->setData(m_model->index(i,2,QModelIndex()), qVariantFromValue(QDateTime::currentDateTime().addDays(i)), KGantt::StartTimeRole);
m_model->setData(m_model->index(i,3,QModelIndex()), qVariantFromValue(QDateTime::currentDateTime().addDays(i+1)), KGantt::EndTimeRole);
}
m_view->setConstraintModel(new KGantt::ConstraintModel(m_view));
m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(0,0,QModelIndex()),m_model->index(1,0,QModelIndex())));
m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(1,0,QModelIndex()),m_model->index(2,0,QModelIndex())));
*/
}
SavePdfDialog::SavePdfDialog(QWidget *parent)
: QDialog(parent)
{
setModal(true);
setWindowTitle(tr("Save as PDF"));
QVBoxLayout *l = new QVBoxLayout(this);
setLayout(l);
QHBoxLayout *fileLayout = new QHBoxLayout(this);
l->addLayout(fileLayout);
QLabel *fileLabel = new QLabel(tr("File:"), this);
fileLayout->addWidget(fileLabel);
m_fileEdit = new QLineEdit(this);
fileLabel->setBuddy(m_fileEdit);
m_fileEdit->setText(QFileInfo(QDir::homePath(), "gantt.pdf").absoluteFilePath());
fileLayout->addWidget(m_fileEdit);
QPushButton *m_fileButton = new QPushButton("...", this);
connect(m_fileButton, SIGNAL(clicked()), this, SLOT(fileButtonClicked()));
fileLayout->addWidget(m_fileButton);
m_rowLabels = new QCheckBox(tr("Row Header"), this);
m_rowLabels->setChecked(true);
l->addWidget(m_rowLabels);
m_columnLabels = new QCheckBox(tr("Column Header"), this);
m_columnLabels->setChecked(true);
l->addWidget(m_columnLabels);
QDialogButtonBox *btnBox = new QDialogButtonBox(this);
btnBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
connect(btnBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(btnBox, SIGNAL(rejected()), this, SLOT(reject()));
l->addWidget(btnBox);
resize(QSize(400, 100).expandedTo(minimumSizeHint()));
}
void SavePdfDialog::fileButtonClicked()
{
const QString file = QFileDialog::getSaveFileName(this, tr("Choose PDF File..."), QString(), tr("PDF files (*.pdf)"));
if (!file.isEmpty())
m_fileEdit->setText(file);
}
void MainWindow::slotFileSavePdf()
{
#ifndef QT_NO_PRINTER
SavePdfDialog dialog(this);
if (dialog.exec() != QDialog::Accepted)
return;
const QString file = dialog.m_fileEdit->text();
if (file.isEmpty())
return;
const bool drawRowLabels = dialog.m_rowLabels->isChecked();
const bool drawColumnLabels = dialog.m_columnLabels->isChecked();
QPrinter printer(QPrinter::HighResolution);
printer.setOrientation(QPrinter::Landscape);
printer.setColorMode(QPrinter::Color);
printer.setPageMargins(0.2, 0.2, 0.2, 0.2, QPrinter::Point);
printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName(file);
m_view->print(&printer, drawRowLabels, drawColumnLabels);
#endif
}
void MainWindow::slotFilePrint()
{
#ifndef QT_NO_PRINTER
QPrinter printer(QPrinter::HighResolution);
printer.setOrientation(QPrinter::Landscape);
printer.setColorMode(QPrinter::Color);
QPrintDialog dialog(&printer, this);
if (dialog.exec() != QDialog::Accepted)
return;
m_view->print(&printer);
#endif
}
void MainWindow::slotFileQuit()
{
// TODO
QApplication::instance()->quit();
}
void MainWindow::slotToolsNewItem()
{
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() ) {
qDebug() << "MainWindow::slotToolsNewItem" << idx;
m_model->insertRows( 0, 1, m_model->index( idx.row(),0,idx.parent() ) );
} else {
m_model->insertRows( 0, 1, m_view->rootIndex() );
}
}
void MainWindow::slotToolsAppendItem()
{
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() ) {
qDebug() << "MainWindow::slotToolsAppendItem" << idx;
m_model->insertRows( m_model->rowCount( idx ), 1, m_model->index( idx.row(),0,idx.parent() ) );
} else {
m_model->insertRows( m_model->rowCount( m_view->rootIndex() ), 1, m_view->rootIndex() );
}
}
void MainWindow::slotCollapseAll()
{
// don't use the treeview's collapseAll/expandAll methods but use the one provided by the
// view cause that one will take care to update everyt6hing as needed.
//QTreeView* view = qobject_cast( m_view->leftView() );
//view->collapseAll();
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() )
m_view->collapseAll();
}
void MainWindow::slotExpandAll()
{
// don't use the treeview's collapseAll/expandAll methods but use the one provided by the
// view cause that one will take care to update everyt6hing as needed.
//QTreeView* view = qobject_cast( m_view->leftView() );
//view->expandAll();
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() )
m_view->expandAll();
}
void MainWindow::slotAlignLeft()
{
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() ) {
m_model->setData( idx, KGantt::StyleOptionGanttItem::Left, KGantt::TextPositionRole );
}
}
void MainWindow::slotAlignCenter()
{
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() ) {
m_model->setData( idx, KGantt::StyleOptionGanttItem::Center, KGantt::TextPositionRole );
}
}
void MainWindow::slotAlignRight()
{
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() ) {
m_model->setData( idx, KGantt::StyleOptionGanttItem::Right, KGantt::TextPositionRole );
}
}
void MainWindow::slotAlignHidden()
{
QModelIndex idx = m_view->selectionModel()->currentIndex();
if ( idx.isValid() ) {
m_model->setData( idx, KGantt::StyleOptionGanttItem::Hidden, KGantt::TextPositionRole );
}
}
-void MainWindow::updateTimeline()
-{
- qobject_cast(m_view->grid())->setTimelineTime(QDateTime::currentDateTime());
-}
-
#include "mainwindow.moc"
diff --git a/examples/Gantt/project/mainwindow.h b/examples/Gantt/project/mainwindow.h
index 1ed5fb5..e74a909 100644
--- a/examples/Gantt/project/mainwindow.h
+++ b/examples/Gantt/project/mainwindow.h
@@ -1,72 +1,71 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
class QLineEdit;
class QCheckBox;
namespace KGantt {
class View;
}
class ProjectModel;
class SavePdfDialog : public QDialog
{
Q_OBJECT
public:
QLineEdit *m_fileEdit;
QCheckBox *m_rowLabels;
QCheckBox *m_columnLabels;
SavePdfDialog(QWidget *parent = nullptr);
private slots:
void fileButtonClicked();
};
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow( QWidget* parent = nullptr );
private slots:
void slotFileSavePdf();
void slotFilePrint();
void slotFileQuit();
void slotToolsNewItem();
void slotToolsAppendItem();
void slotCollapseAll();
void slotExpandAll();
void slotAlignLeft();
void slotAlignCenter();
void slotAlignRight();
void slotAlignHidden();
-
- void updateTimeline();
+
private:
ProjectModel* m_model;
KGantt::View* m_view;
};
#endif /* MAINWINDOW_H */
diff --git a/src/KGantt/kganttabstractgrid.cpp b/src/KGantt/kganttabstractgrid.cpp
index baba3a8..c00e91d 100644
--- a/src/KGantt/kganttabstractgrid.cpp
+++ b/src/KGantt/kganttabstractgrid.cpp
@@ -1,170 +1,168 @@
/*
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "kganttabstractgrid.h"
#include "kganttabstractgrid_p.h"
#include
using namespace KGantt;
/*!\class KGantt::AbstractGrid kganttabstractgrid.h KGanttAbstractGrid
* \ingroup KGantt
* \brief Abstract baseclass for grids. A grid is used to convert between
* QModelIndex'es and gantt chart values (qreals) and to paint the
* background and header of the view.
*
* \see KGantt::DateTimeGrid
*/
/*! Constructor. Creates an AbstractGrid with parent \a parent.
* The QObject parent is not used for anything internally. */
AbstractGrid::AbstractGrid( QObject* parent )
: QObject( parent ),
_d( new Private )
{
}
/*! Destructor. Does nothing */
AbstractGrid::~AbstractGrid()
{
delete _d;
}
#define d d_func()
/*! Sets the QAbstractItemModel used by this grid implementation.
* This is called by the view, you should never need to call this
* from client code. */
void AbstractGrid::setModel( QAbstractItemModel* model )
{
d->model = model;
}
/*!\returns The QAbstractItemModel used by this grid */
QAbstractItemModel* AbstractGrid::model() const
{
return d->model;
}
/*! Sets the root index used by this grid implementation.
* This is called by the view, you should never need to call this
* from client code. */
void AbstractGrid::setRootIndex( const QModelIndex& idx )
{
d->root = idx;
}
/*!\returns the current root index for this grid */
QModelIndex AbstractGrid::rootIndex() const
{
return d->root;
}
/*!\returns true if the startpoint is before the endpoint
* of the constraint \a c.
*/
bool AbstractGrid::isSatisfiedConstraint( const Constraint& c ) const
{
// First check if the data is valid,
// TODO: review if true is the right choice
if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) return true;
Span ss = mapToChart( c.startIndex() );
Span es = mapToChart( c.endIndex() );
return ( ss.end() <= es.start() );
}
/*!
* Implement this to map from \a value to the corresponding location in the view.
* Return a negative value if \a value cannot be mapped.
* The default implementation returns -1.0.
*/
qreal AbstractGrid::mapToChart( const QVariant& value ) const
{
Q_UNUSED( value );
return -1.0;
}
/*!
* Implement this to map from \a x to the corresponding location in the view.
* Return an invalid value if \a x cannot be mapped.
*/
QVariant AbstractGrid::mapFromChart( qreal x ) const
{
Q_UNUSED( x );
return QVariant();
}
/*!\fn virtual Span AbstractGrid::mapToChart( const QModelIndex& idx ) const
* Implement this to map from the data in the model to the location of
* the corresponding item in the view.
*/
/*!\fn virtual bool AbstractGrid::mapFromChart( const Span& span, const QModelIndex& idx, const QList& constraints ) const
* Implement this to update the model data based on the location of the item. Check
* against the \a constraints list to make sure no hard constraints are violated by
* writing back to the model.
* \returns true if the update succeeded.
*/
/*!\fn virtual void AbstractGrid::paintGrid( QPainter* painter, const QRectF& sceneRect, const QRectF& exposedRect, AbstractRowController* rowController=0, QWidget* widget=0 )
*
* Implement this to paint the background of the view -- typically
* with some grid lines.
* \param painter -- the QPainter to paint with.
* \param sceneRect -- the total bounding rectangle of the scene.
* \param exposedRect -- the rectangle that needs to be painted.
* \param rowController -- the row controller used by the view -- may be 0.
* \param widget -- the widget used by the view -- may be 0.
*/
/*!\fn virtual void AbstractGrid::paintHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect, qreal offset, QWidget* widget=0 )
*
* Implement this to paint the header part of the view.
* \param painter -- the QPainter to paint with.
* \param headerRect -- the total rectangle occupied by the header.
* \param exposedRect -- the rectangle that needs to be painted.
* \param offset -- the horizontal scroll offset of the view.
* \param widget -- the widget used by the view -- may be 0.
*/
/*!
\todo document this function
*/
void AbstractGrid::drawBackground(QPainter* paint, const QRectF& rect)
{
- qInfo()<.
*/
#include "kganttdatetimegrid.h"
#include "kganttdatetimegrid_p.h"
#include "kganttabstractrowcontroller.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KGantt;
QDebug operator<<( QDebug dbg, KGantt::DateTimeScaleFormatter::Range range )
{
switch ( range ) {
case KGantt::DateTimeScaleFormatter::Second: dbg << "KGantt::DateTimeScaleFormatter::Second"; break;
case KGantt::DateTimeScaleFormatter::Minute: dbg << "KGantt::DateTimeScaleFormatter::Minute"; break;
case KGantt::DateTimeScaleFormatter::Hour: dbg << "KGantt::DateTimeScaleFormatter::Hour"; break;
case KGantt::DateTimeScaleFormatter::Day: dbg << "KGantt::DateTimeScaleFormatter::Day"; break;
case KGantt::DateTimeScaleFormatter::Week: dbg << "KGantt::DateTimeScaleFormatter::Week"; break;
case KGantt::DateTimeScaleFormatter::Month: dbg << "KGantt::DateTimeScaleFormatter::Month"; break;
case KGantt::DateTimeScaleFormatter::Year: dbg << "KGantt::DateTimeScaleFormatter::Year"; break;
}
return dbg;
}
/*!\class KGantt::DateTimeGrid
* \ingroup KGantt
*
* This implementation of AbstractGrid works with QDateTime
* and shows days and week numbers in the header
*/
qreal DateTimeGrid::Private::dateTimeToChartX( const QDateTime& dt ) const
{
assert( startDateTime.isValid() );
qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
result += startDateTime.time().msecsTo(dt.time())/1000.;
result *= dayWidth/( 24.*60.*60. );
return result;
}
QDateTime DateTimeGrid::Private::chartXtoDateTime( qreal x ) const
{
assert( startDateTime.isValid() );
int days = static_cast( x/dayWidth );
qreal secs = x*( 24.*60.*60. )/dayWidth;
QDateTime dt = startDateTime;
QDateTime result = dt.addDays( days )
.addSecs( static_cast(secs-(days*24.*60.*60.) ) )
.addMSecs( qRound( ( secs-static_cast( secs ) )*1000. ) );
return result;
}
-void DateTimeGrid::Private::drawTimeline(QPainter* painter, const QRectF& rect)
-{
- QDateTime dt = timelineTime.isValid() ? timelineTime : QDateTime::currentDateTime();
- qreal x = dateTimeToChartX(dt);
- if (rect.contains(x, rect.top())) {
- painter->save();
- QPen pen;
- if (timelineOptions & UseCustomPen) {
- pen = timelinePen;
- } else {
- pen = QPen(QApplication::palette().color(QPalette::Highlight), 0);
- }
- painter->setPen(pen);
- painter->drawLine(x, rect.top(), x, rect.bottom());
- painter->restore();
- }
-}
-
#define d d_func()
/*!\class KGantt::DateTimeScaleFormatter
* \ingroup KGantt
*
* This class formats dates and times used in DateTimeGrid follawing a given format.
*
* The format follows the format of QDateTime::toString(), with one addition:
* "w" is replaced with the week number of the date as number without a leading zero (1-53)
* "ww" is replaced with the week number of the date as number with a leading zero (01-53)
*
* For example:
*
* \code
* // formatter to print the complete date over the current week
* // This leads to the first day of the week being printed
* DateTimeScaleFormatter formatter = DateTimeScaleFormatter( DateTimeScaleFormatter::Week, "yyyy-MM-dd" );
* \endcode
*
* Optionally, you can set an user defined text alignment flag. The default value is Qt::AlignCenter.
* \sa DateTimeScaleFormatter::DateTimeScaleFormatter
*
* This class even controls the range of the grid sections.
* \sa KGanttDateTimeScaleFormatter::Range
*/
/*! Creates a DateTimeScaleFormatter using \a range and \a format.
* The text on the header is aligned following \a alignment.
*/
DateTimeScaleFormatter::DateTimeScaleFormatter( Range range, const QString& format,
const QString& templ, Qt::Alignment alignment )
: _d( new Private( range, format, templ, alignment ) )
{
}
DateTimeScaleFormatter::DateTimeScaleFormatter( Range range, const QString& format, Qt::Alignment alignment )
: _d( new Private( range, format, QString::fromLatin1( "%1" ), alignment ) )
{
}
DateTimeScaleFormatter::DateTimeScaleFormatter( const DateTimeScaleFormatter& other )
: _d( new Private( other.range(), other.format(), other.d->templ, other.alignment() ) )
{
}
DateTimeScaleFormatter::~DateTimeScaleFormatter()
{
delete _d;
}
DateTimeScaleFormatter& DateTimeScaleFormatter::operator=( const DateTimeScaleFormatter& other )
{
if ( this == &other )
return *this;
delete _d;
_d = new Private( other.range(), other.format(), other.d->templ, other.alignment() );
return *this;
}
/*! \returns The format being used for formatting dates and times.
*/
QString DateTimeScaleFormatter::format() const
{
return d->format;
}
/*! \returns The \a datetime as string respecting the format.
*/
QString DateTimeScaleFormatter::format( const QDateTime& datetime ) const
{
QString result = d->format;
// additional feature: Weeknumber
const QString shortWeekNumber = QString::number( datetime.date().weekNumber()) + QLatin1String("/")
+ QString::number( datetime.date().year());
const QString longWeekNumber = ( shortWeekNumber.length() == 1 ? QString::fromLatin1( "0" ) : QString() ) + shortWeekNumber;
result.replace( QString::fromLatin1( "ww" ), longWeekNumber );
result.replace( QString::fromLatin1( "w" ), shortWeekNumber );
result = datetime.toLocalTime().toString( result );
return result;
}
QString DateTimeScaleFormatter::text( const QDateTime& datetime ) const
{
return d->templ.arg( format( datetime ) );
}
/*! \returns The range of each item on a DateTimeGrid header.
* \sa DateTimeScaleFormatter::Range */
DateTimeScaleFormatter::Range DateTimeScaleFormatter::range() const
{
return d->range;
}
Qt::Alignment DateTimeScaleFormatter::alignment() const
{
return d->alignment;
}
/*! \returns the QDateTime being the begin of the range after the one containing \a datetime
* \sa currentRangeBegin
*/
QDateTime DateTimeScaleFormatter::nextRangeBegin( const QDateTime& datetime ) const
{
QDateTime result = datetime;
switch ( d->range )
{
case Second:
result = result.addSecs( 60 );
break;
case Minute:
// set it to the begin of the next minute
result.setTime( QTime( result.time().hour(), result.time().minute() ) );
result = result.addSecs( 60 );
break;
case Hour:
// set it to the begin of the next hour
result.setTime( QTime( result.time().hour(), 0 ) );
result = result.addSecs( 60 * 60 );
break;
case Day:
// set it to midnight the next day
result.setTime( QTime( 0, 0 ) );
result = result.addDays( 1 );
break;
case Week:
// set it to midnight
result.setTime( QTime( 0, 0 ) );
// iterate day-wise, until weekNumber changes
{
const int weekNumber = result.date().weekNumber();
while ( weekNumber == result.date().weekNumber() )
result = result.addDays( 1 );
}
break;
case Month:
// set it to midnight
result.setTime( QTime( 0, 0 ) );
// set it to the first of the next month
result.setDate( QDate( result.date().year(), result.date().month(), 1 ).addMonths( 1 ) );
break;
case Year:
// set it to midnight
result.setTime( QTime( 0, 0 ) );
// set it to the first of the next year
result.setDate( QDate( result.date().year(), 1, 1 ).addYears( 1 ) );
break;
}
//result = result.toLocalTime();
assert( result != datetime );
//qDebug() << "DateTimeScaleFormatter::nextRangeBegin("<range<range )
{
case Second:
break; // nothing
case Minute:
// set it to the begin of the current minute
result.setTime( QTime( result.time().hour(), result.time().minute() ) );
break;
case Hour:
// set it to the begin of the current hour
result.setTime( QTime( result.time().hour(), 0 ) );
break;
case Day:
// set it to midnight the current day
result.setTime( QTime( 0, 0 ) );
break;
case Week:
// set it to midnight
result.setTime( QTime( 0, 0 ) );
// iterate day-wise, as long weekNumber is the same
{
const int weekNumber = result.date().weekNumber();
while ( weekNumber == result.date().addDays( -1 ).weekNumber() )
result = result.addDays( -1 );
}
break;
case Month:
// set it to midnight
result.setTime( QTime( 0, 0 ) );
// set it to the first of the current month
result.setDate( QDate( result.date().year(), result.date().month(), 1 ) );
break;
case Year:
// set it to midnight
result.setTime( QTime( 0, 0 ) );
// set it to the first of the current year
result.setDate( QDate( result.date().year(), 1, 1 ) );
break;
}
return result;
}
DateTimeGrid::DateTimeGrid() : AbstractGrid( new Private )
{
}
DateTimeGrid::~DateTimeGrid()
{
}
/*! \returns The QDateTime used as start date for the grid.
*
* The default is three days before the current date.
*/
QDateTime DateTimeGrid::startDateTime() const
{
return d->startDateTime;
}
/*! \param dt The start date of the grid. It is used as the beginning of the
* horizontal scrollbar in the view.
*
* Emits gridChanged() after the start date has changed.
*/
void DateTimeGrid::setStartDateTime( const QDateTime& dt )
{
d->startDateTime = dt;
emit gridChanged();
}
/*! \returns The width in pixels for each day in the grid.
*
* The default is 100 pixels.
*/
qreal DateTimeGrid::dayWidth() const
{
return d->dayWidth;
}
/*! Maps a given point in time \a dt to an X value in the scene.
*/
qreal DateTimeGrid::mapFromDateTime( const QDateTime& dt) const
{
return d->dateTimeToChartX( dt );
}
/*! Maps a given X value \a x in scene coordinates to a point in time.
*/
QDateTime DateTimeGrid::mapToDateTime( qreal x ) const
{
return d->chartXtoDateTime( x );
}
/*! \param w The width in pixels for each day in the grid.
*
* The signal gridChanged() is emitted after the day width is changed.
*/
void DateTimeGrid::setDayWidth( qreal w )
{
assert( w>0 );
d->dayWidth = w;
emit gridChanged();
}
/*! \param s The scale to be used to paint the grid.
*
* The signal gridChanged() is emitted after the scale has changed.
* \sa Scale
*
* Following example demonstrates how to change the format of the header to use
* a date-scaling with the header-label displayed with the ISO date-notation.
* \code
* DateTimeScaleFormatter* formatter = new DateTimeScaleFormatter(DateTimeScaleFormatter::Day, QString::fromLatin1("yyyy-MMMM-dddd"));
* grid->setUserDefinedUpperScale( formatter );
* grid->setUserDefinedLowerScale( formatter );
* grid->setScale( DateTimeGrid::ScaleUserDefined );
* \endcode
*/
void DateTimeGrid::setScale( Scale s )
{
d->scale = s;
emit gridChanged();
}
/*! \returns The scale used to paint the grid.
*
* The default is ScaleAuto, which means the day scale will be used
* as long as the day width is less or equal to 500.
* \sa Scale
*/
DateTimeGrid::Scale DateTimeGrid::scale() const
{
return d->scale;
}
/*! Sets the scale formatter for the lower part of the header to the
* user defined formatter to \a lower. The DateTimeGrid object takes
* ownership of the formatter, which has to be allocated with new.
*
* You have to set the scale to ScaleUserDefined for this setting to take effect.
* \sa DateTimeScaleFormatter
*/
void DateTimeGrid::setUserDefinedLowerScale( DateTimeScaleFormatter* lower )
{
delete d->lower;
d->lower = lower;
emit gridChanged();
}
/*! Sets the scale formatter for the upper part of the header to the
* user defined formatter to \a upper. The DateTimeGrid object takes
* ownership of the formatter, which has to be allocated with new.
*
* You have to set the scale to ScaleUserDefined for this setting to take effect.
* \sa DateTimeScaleFormatter
*/
void DateTimeGrid::setUserDefinedUpperScale( DateTimeScaleFormatter* upper )
{
delete d->upper;
d->upper = upper;
emit gridChanged();
}
/*! \return The DateTimeScaleFormatter being used to render the lower scale.
*/
DateTimeScaleFormatter* DateTimeGrid::userDefinedLowerScale() const
{
return d->lower;
}
/*! \return The DateTimeScaleFormatter being used to render the upper scale.
*/
DateTimeScaleFormatter* DateTimeGrid::userDefinedUpperScale() const
{
return d->upper;
}
/*! \param ws The start day of the week.
*
* A solid line is drawn on the grid to mark the beginning of a new week.
* Emits gridChanged() after the start day has changed.
*/
void DateTimeGrid::setWeekStart( Qt::DayOfWeek ws )
{
d->weekStart = ws;
emit gridChanged();
}
/*! \returns The start day of the week */
Qt::DayOfWeek DateTimeGrid::weekStart() const
{
return d->weekStart;
}
/*! \param fd A set of days to mark as free in the grid.
*
* Free days are filled with the alternate base brush of the
* palette used by the view.
* The signal gridChanged() is emitted after the free days are changed.
*/
void DateTimeGrid::setFreeDays( const QSet& fd )
{
d->freeDays = fd;
emit gridChanged();
}
/*! \returns The days marked as free in the grid. */
QSet DateTimeGrid::freeDays() const
{
return d->freeDays;
}
/*! Sets the brush to use to paint free days.
*/
void DateTimeGrid::setFreeDaysBrush(const QBrush brush)
{
d->freeDaysBrush = brush;
}
/*!
\returns The brush used to paint free days.
*/
QBrush DateTimeGrid::freeDaysBrush() const
{
return d->freeDaysBrush;
}
/*! \returns true if row separators are used. */
bool DateTimeGrid::rowSeparators() const
{
return d->rowSeparators;
}
/*! \param enable Whether to use row separators or not. */
void DateTimeGrid::setRowSeparators( bool enable )
{
d->rowSeparators = enable;
}
/*! Sets the brush used to display rows where no data is found.
* Default is a red pattern. If set to QBrush() rows with no
* information will not be marked.
*/
void DateTimeGrid::setNoInformationBrush( const QBrush& brush )
{
d->noInformationBrush = brush;
emit gridChanged();
}
/*! \returns the brush used to mark rows with no information.
*/
QBrush DateTimeGrid::noInformationBrush() const
{
return d->noInformationBrush;
}
/*!
* \param value The datetime to get the x value for.
* \returns The x value corresponding to \a value or -1.0 if \a value is not a datetime variant.
*/
qreal DateTimeGrid::mapToChart( const QVariant& value ) const
{
if ( ! value.canConvert( QVariant::DateTime ) ||
( value.type() == QVariant::String && value.toString().isEmpty() ) )
{
return -1.0;
}
return d->dateTimeToChartX( value.toDateTime() );
}
/*!
* \param x The x value get the datetime for.
* \returns The datetime corresponding to \a x or an invalid datetime if x cannot be mapped.
*/
QVariant DateTimeGrid::mapFromChart( qreal x ) const
{
return d->chartXtoDateTime( x );
}
/*! \param idx The index to get the Span for.
* \returns The start and end pixels, in a Span, of the specified index.
*/
Span DateTimeGrid::mapToChart( const QModelIndex& idx ) const
{
assert( model() );
if ( !idx.isValid() ) return Span();
assert( idx.model()==model() );
const QVariant sv = model()->data( idx, StartTimeRole );
const QVariant ev = model()->data( idx, EndTimeRole );
if ( sv.canConvert( QVariant::DateTime ) &&
ev.canConvert( QVariant::DateTime ) &&
!(sv.type() == QVariant::String && sv.toString().isEmpty()) &&
!(ev.type() == QVariant::String && ev.toString().isEmpty())
) {
QDateTime st = sv.toDateTime();
QDateTime et = ev.toDateTime();
if ( et.isValid() && st.isValid() ) {
qreal sx = d->dateTimeToChartX( st );
qreal ex = d->dateTimeToChartX( et )-sx;
//qDebug() << "DateTimeGrid::mapToChart("< "<< Span( sx, ex );
return Span( sx, ex);
}
}
// Special case for Events with only a start date
if ( sv.canConvert( QVariant::DateTime ) && !(sv.type() == QVariant::String && sv.toString().isEmpty()) ) {
QDateTime st = sv.toDateTime();
if ( st.isValid() ) {
qreal sx = d->dateTimeToChartX( st );
return Span( sx, 0 );
}
}
return Span();
}
#if 0
static void debug_print_idx( const QModelIndex& idx )
{
if ( !idx.isValid() ) {
qDebug() << "[Invalid]";
return;
}
QDateTime st = idx.data( StartTimeRole ).toDateTime();
QDateTime et = idx.data( EndTimeRole ).toDateTime();
qDebug() << idx << "["<& constraints ) const
{
assert( model() );
if ( !idx.isValid() ) return false;
assert( idx.model()==model() );
QDateTime st = d->chartXtoDateTime(span.start());
QDateTime et = d->chartXtoDateTime(span.start()+span.length());
//qDebug() << "DateTimeGrid::mapFromChart("< "<< st << et;
Q_FOREACH( const Constraint& c, constraints ) {
if ( c.type() != Constraint::TypeHard || !isSatisfiedConstraint( c )) continue;
if ( c.startIndex() == idx ) {
QDateTime tmpst = model()->data( c.endIndex(), StartTimeRole ).toDateTime();
//qDebug() << tmpst << "<" << et <<"?";
if ( tmpstdata( c.startIndex(), EndTimeRole ).toDateTime();
//qDebug() << tmpet << ">" << st <<"?";
if ( tmpet>st ) return false;
}
}
return model()->setData( idx, qVariantFromValue(st), StartTimeRole )
&& model()->setData( idx, qVariantFromValue(et), EndTimeRole );
}
Qt::PenStyle DateTimeGrid::Private::gridLinePenStyle( QDateTime dt, Private::HeaderType headerType ) const
{
switch ( headerType ) {
case Private::HeaderHour:
// Midnight
if ( dt.time().hour() == 0 )
return Qt::SolidLine;
return Qt::DashLine;
case Private::HeaderDay:
// First day of the week
if ( dt.date().dayOfWeek() == weekStart )
return Qt::SolidLine;
return Qt::DashLine;
case Private::HeaderWeek:
// First day of the month
if ( dt.date().day() == 1 )
return Qt::SolidLine;
// First day of the week
if ( dt.date().dayOfWeek() == weekStart )
return Qt::DashLine;
return Qt::NoPen;
case Private::HeaderMonth:
// First day of the year
if ( dt.date().dayOfYear() == 1 )
return Qt::SolidLine;
// First day of the month
if ( dt.date().day() == 1 )
return Qt::DashLine;
return Qt::NoPen;
default:
// Nothing to do here
break;
}
// Default
return Qt::NoPen;
}
QDateTime DateTimeGrid::Private::adjustDateTimeForHeader( QDateTime dt, Private::HeaderType headerType ) const
{
// In any case, set time to 00:00:00:00
dt.setTime( QTime( 0, 0, 0, 0 ) );
switch ( headerType ) {
case Private::HeaderWeek:
// Set day to beginning of the week
while ( dt.date().dayOfWeek() != weekStart )
dt = dt.addDays( -1 );
break;
case Private::HeaderMonth:
// Set day to beginning of the month
dt = dt.addDays( 1 - dt.date().day() );
break;
case Private::HeaderYear:
// Set day to first day of the year
dt = dt.addDays( 1 - dt.date().dayOfYear() );
break;
default:
// In any other case, we don't need to adjust the date time
break;
}
return dt;
}
void DateTimeGrid::Private::paintVerticalLines( QPainter* painter,
const QRectF& sceneRect,
const QRectF& exposedRect,
QWidget* widget,
Private::HeaderType headerType )
{
QDateTime dt = chartXtoDateTime( exposedRect.left() );
dt = adjustDateTimeForHeader( dt, headerType );
int offsetSeconds = 0;
int offsetDays = 0;
// Determine the time step per grid line
if ( headerType == Private::HeaderHour )
offsetSeconds = 60*60;
else
offsetDays = 1;
for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), x = dateTimeToChartX( dt ) ) {
//TODO not the best solution as it might be one paint too much, but i don't know what
//causes the test to fail yet, i think it might be a rounding error
//if ( x >= exposedRect.left() ) {
QPen pen = painter->pen();
pen.setBrush( QApplication::palette().dark() );
pen.setStyle( gridLinePenStyle( dt, headerType ) );
painter->setPen( pen );
if ( freeDays.contains( static_cast( dt.date().dayOfWeek() ) ) ) {
if (freeDaysBrush.style() == Qt::NoBrush)
painter->setBrush( widget?widget->palette().midlight()
:QApplication::palette().midlight() );
else
painter->setBrush(freeDaysBrush);
painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
}
painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
//}
}
}
void DateTimeGrid::Private::paintVerticalUserDefinedLines( QPainter* painter,
const QRectF& sceneRect,
const QRectF& exposedRect,
const DateTimeScaleFormatter* formatter,
QWidget* widget )
{
Q_UNUSED( widget );
QDateTime dt = chartXtoDateTime( exposedRect.left() );
dt = formatter->currentRangeBegin( dt );
QPen pen = painter->pen();
pen.setBrush( QApplication::palette().dark() );
pen.setStyle( Qt::DashLine );
painter->setPen( pen );
for ( qreal x = dateTimeToChartX( dt ); x < exposedRect.right();
dt = formatter->nextRangeBegin( dt ),x=dateTimeToChartX( dt ) ) {
if ( freeDays.contains( static_cast( dt.date().dayOfWeek() ) ) ) {
QBrush oldBrush = painter->brush();
if (freeDaysBrush.style() == Qt::NoBrush)
painter->setBrush( widget?widget->palette().midlight()
:QApplication::palette().midlight() );
else
painter->setBrush(freeDaysBrush);
painter->fillRect( QRectF( x, exposedRect.top(), dayWidth, exposedRect.height() ), painter->brush() );
painter->setBrush( oldBrush );
}
//TODO not the best solution as it might be one paint too much, but i don't know what
//causes the test to fail yet, i think it might be a rounding error
//if ( x >= exposedRect.left() ) {
// FIXME: Also fill area between this and the next vertical line to indicate free days? (Johannes)
painter->drawLine( QPointF( x, sceneRect.top() ), QPointF( x, sceneRect.bottom() ) );
//}
}
}
DateTimeGrid::Private::HeaderType DateTimeGrid::Private::headerTypeForScale( DateTimeGrid::Scale scale )
{
switch ( scale ) {
case ScaleHour:
return Private::HeaderHour;
case ScaleDay:
return Private::HeaderDay;
case ScaleWeek:
return Private::HeaderWeek;
case ScaleMonth:
return Private::HeaderMonth;
default:
// There are no specific header types for any other scale!
assert( false );
break;
}
return Private::HeaderDay;
}
void DateTimeGrid::paintGrid( QPainter* painter,
const QRectF& sceneRect,
const QRectF& exposedRect,
AbstractRowController* rowController,
QWidget* widget )
{
// TODO: Support hours and weeks
switch ( scale() ) {
case ScaleHour:
case ScaleDay:
case ScaleWeek:
case ScaleMonth:
d->paintVerticalLines( painter, sceneRect, exposedRect, widget, d->headerTypeForScale( scale() ) );
break;
case ScaleAuto: {
const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
const qreal dayw = dayWidth();
if ( dayw > 24*60*60*tabw ) {
d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->minute_lower, widget );
} else if ( dayw > 24*60*tabw ) {
d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderHour );
} else if ( dayw > 24*tabw ) {
d->paintVerticalLines( painter, sceneRect, exposedRect, widget, Private::HeaderDay );
} else if ( dayw > tabw ) {
d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->week_lower, widget );
} else if ( 4*dayw > tabw ) {
d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->month_lower, widget );
} else {
d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, &d->year_lower, widget );
}
break;
}
case ScaleUserDefined:
d->paintVerticalUserDefinedLines( painter, sceneRect, exposedRect, d->lower, widget );
break;
}
if ( rowController ) {
// First draw the rows
QPen pen = painter->pen();
pen.setBrush( QApplication::palette().dark() );
pen.setStyle( Qt::DashLine );
painter->setPen( pen );
QModelIndex idx = rowController->indexAt( qRound( exposedRect.top() ) );
if ( rowController->indexAbove( idx ).isValid() ) idx = rowController->indexAbove( idx );
qreal y = 0;
while ( y < exposedRect.bottom() && idx.isValid() ) {
const Span s = rowController->rowGeometry( idx );
y = s.start()+s.length();
if ( d->rowSeparators ) {
painter->drawLine( QPointF( sceneRect.left(), y ),
QPointF( sceneRect.right(), y ) );
}
if ( !idx.data( ItemTypeRole ).isValid() && d->noInformationBrush.style() != Qt::NoBrush ) {
painter->fillRect( QRectF( exposedRect.left(), s.start(), exposedRect.width(), s.length() ), d->noInformationBrush );
}
// Is alternating background better?
//if ( idx.row()%2 ) painter->fillRect( QRectF( exposedRect.x(), s.start(), exposedRect.width(), s.length() ), QApplication::palette().alternateBase() );
idx = rowController->indexBelow( idx );
}
}
}
int DateTimeGrid::Private::tabHeight( const QString& txt, QWidget* widget ) const
{
QStyleOptionHeader opt;
if ( widget ) opt.initFrom( widget );
opt.text = txt;
QStyle* style;
if ( widget ) style = widget->style();
else style = QApplication::style();
QSize s = style->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), widget);
return s.height();
}
void DateTimeGrid::Private::getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper)
{
const qreal tabw = QApplication::fontMetrics().width( QLatin1String( "XXXXX" ) );
const qreal dayw = dayWidth;
if ( dayw > 24*60*60*tabw ) {
*lower = &minute_lower;
*upper = &minute_upper;
} else if ( dayw > 24*60*tabw ) {
*lower = &hour_lower;
*upper = &hour_upper;
} else if ( dayw > 24*tabw ) {
*lower = &day_lower;
*upper = &day_upper;
} else if ( dayw > tabw ) {
*lower = &week_lower;
*upper = &week_upper;
} else if ( 4*dayw > tabw ) {
*lower = &month_lower;
*upper = &month_upper;
} else {
*lower = &year_lower;
*upper = &year_upper;
}
}
void DateTimeGrid::paintHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget )
{
painter->save();
QPainterPath clipPath;
clipPath.addRect( headerRect );
painter->setClipPath( clipPath, Qt::IntersectClip );
switch ( scale() )
{
case ScaleHour:
paintHourScaleHeader( painter, headerRect, exposedRect, offset, widget );
break;
case ScaleDay:
paintDayScaleHeader( painter, headerRect, exposedRect, offset, widget );
break;
case ScaleWeek:
paintWeekScaleHeader( painter, headerRect, exposedRect, offset, widget );
break;
case ScaleMonth:
paintMonthScaleHeader( painter, headerRect, exposedRect, offset, widget );
break;
case ScaleAuto:
{
DateTimeScaleFormatter *lower, *upper;
d->getAutomaticFormatters( &lower, &upper );
const qreal lowerHeight = d->tabHeight( lower->text( startDateTime() ) );
const qreal upperHeight = d->tabHeight( upper->text( startDateTime() ) );
const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1, headerRect.height()-upperHeaderRect.height()-1 );
paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, lower, widget );
paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, upper, widget );
break;
}
case ScaleUserDefined:
{
const qreal lowerHeight = d->tabHeight( d->lower->text( startDateTime() ) );
const qreal upperHeight = d->tabHeight( d->upper->text( startDateTime() ) );
const qreal upperRatio = upperHeight/( lowerHeight+upperHeight );
const QRectF upperHeaderRect( headerRect.x(), headerRect.top(), headerRect.width()-1, headerRect.height() * upperRatio );
const QRectF lowerHeaderRect( headerRect.x(), upperHeaderRect.bottom()+1, headerRect.width()-1, headerRect.height()-upperHeaderRect.height()-1 );
paintUserDefinedHeader( painter, lowerHeaderRect, exposedRect, offset, d->lower, widget );
paintUserDefinedHeader( painter, upperHeaderRect, exposedRect, offset, d->upper, widget );
}
break;
}
painter->restore();
}
void DateTimeGrid::paintUserDefinedHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, const DateTimeScaleFormatter* formatter,
QWidget* widget )
{
const QStyle* const style = widget ? widget->style() : QApplication::style();
QDateTime dt = formatter->currentRangeBegin( d->chartXtoDateTime( offset + exposedRect.left() ));
qreal x = d->dateTimeToChartX( dt );
while ( x < exposedRect.right() + offset ) {
const QDateTime next = formatter->nextRangeBegin( dt );
const qreal nextx = d->dateTimeToChartX( next );
QStyleOptionHeader opt;
if ( widget ) opt.init( widget );
opt.rect = QRectF( x - offset+1, headerRect.top(), qMax( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect();
opt.textAlignment = formatter->alignment();
opt.text = formatter->text( dt );
style->drawControl( QStyle::CE_Header, &opt, painter, widget );
dt = next;
x = nextx;
}
}
void DateTimeGrid::Private::paintHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget,
Private::HeaderType headerType,
DateTextFormatter *formatter )
{
QStyle* style = widget?widget->style():QApplication::style();
const qreal left = exposedRect.left() + offset;
const qreal right = exposedRect.right() + offset;
// Paint a section for each hour
QDateTime dt = chartXtoDateTime( left );
dt = adjustDateTimeForHeader( dt, headerType );
// Determine the time step per grid line
int offsetSeconds = 0;
int offsetDays = 0;
int offsetMonths = 0;
switch ( headerType ) {
case Private::HeaderHour:
offsetSeconds = 60*60;
break;
case Private::HeaderDay:
offsetDays = 1;
break;
case Private::HeaderWeek:
offsetDays = 7;
break;
case Private::HeaderMonth:
offsetMonths = 1;
break;
case Private::HeaderYear:
offsetMonths = 12;
break;
default:
// Other scales cannot be painted with this method!
assert( false );
break;
}
for ( qreal x = dateTimeToChartX( dt ); x < right;
dt = dt.addSecs( offsetSeconds ), dt = dt.addDays( offsetDays ), dt = dt.addMonths( offsetMonths ),
x = dateTimeToChartX( dt ) ) {
QStyleOptionHeader opt;
if ( widget ) opt.init( widget );
opt.rect = formatter->textRect( x, offset, dayWidth, headerRect, dt );
opt.text = formatter->format( dt );
opt.textAlignment = Qt::AlignCenter;
style->drawControl(QStyle::CE_Header, &opt, painter, widget);
}
}
/*! Paints the hour scale header.
* \sa paintHeader()
*/
void DateTimeGrid::paintHourScaleHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget )
{
class HourFormatter : public Private::DateTextFormatter {
public:
virtual ~HourFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return dt.time().toString( QString::fromLatin1( "hh" ) );
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
Q_UNUSED(dt);
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
QSizeF( dayWidth / 24.0, headerRect.height() / 2.0 ) ).toAlignedRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderHour, new HourFormatter ); // Custom parameters
class DayFormatter : public Private::DateTextFormatter {
public:
virtual ~DayFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return dt.date().toString();
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
Q_UNUSED(dt);
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderDay, new DayFormatter ); // Custom parameters
}
/*! Paints the day scale header.
* \sa paintHeader()
*/
void DateTimeGrid::paintDayScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget )
{
class DayFormatter : public Private::DateTextFormatter {
public:
virtual ~DayFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return dt.toString( QString::fromLatin1( "ddd" ) ).left( 1 );
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
Q_UNUSED(dt);
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset + 1.0, headerRect.height() / 2.0 ),
QSizeF( dayWidth, headerRect.height() / 2.0 ) ).toAlignedRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderDay, new DayFormatter ); // Custom parameters
class WeekFormatter : public Private::DateTextFormatter {
public:
virtual ~WeekFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return QString::number(dt.date().weekNumber()) + QLatin1String("/") + QString::number(dt.date().year());
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
Q_UNUSED(dt);
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderWeek, new WeekFormatter ); // Custom parameters
}
/*! Paints the week scale header.
* \sa paintHeader()
*/
void DateTimeGrid::paintWeekScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget )
{
class WeekFormatter : public Private::DateTextFormatter {
public:
virtual ~WeekFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return QString::number( dt.date().weekNumber() );
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
Q_UNUSED(dt);
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
QSizeF( dayWidth * 7, headerRect.height() / 2.0 ) ).toRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderWeek, new WeekFormatter ); // Custom parameters
class MonthFormatter : public Private::DateTextFormatter {
public:
virtual ~MonthFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return QLocale().monthName(dt.date().month(), QLocale::LongFormat) + QLatin1String("/") + QString::number(dt.date().year());
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderMonth, new MonthFormatter ); // Custom parameters
}
/*! Paints the week scale header.
* \sa paintHeader()
*/
void DateTimeGrid::paintMonthScaleHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget )
{
class MonthFormatter : public Private::DateTextFormatter {
public:
virtual ~MonthFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return QLocale().monthName(dt.date().month(), QLocale::ShortFormat) + QLatin1String("/") + QString::number(dt.date().year());
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, headerRect.height() / 2.0 ),
QSizeF( dayWidth * dt.date().daysInMonth(), headerRect.height() / 2.0 ) ).toRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderMonth, new MonthFormatter ); // Custom parameters
class YearFormatter : public Private::DateTextFormatter {
public:
virtual ~YearFormatter() {}
QString format( const QDateTime& dt ) Q_DECL_OVERRIDE {
return QString::number( dt.date().year() );
}
QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) Q_DECL_OVERRIDE {
return QRectF( QPointF( x, headerRect.top() ) + QPointF( -offset, 0.0 ),
QSizeF( dayWidth * dt.date().daysInYear(), headerRect.height() / 2.0 ) ).toRect();
}
};
d->paintHeader( painter, headerRect, exposedRect, offset, widget, // General parameters
Private::HeaderYear, new YearFormatter ); // Custom parameters
}
/*! Draw the background for a day.
*/
void DateTimeGrid::drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date)
{
+ Q_UNUSED(painter);
+ Q_UNUSED(rect);
Q_UNUSED(date);
- if (d->timelineOptions & Background) {
- d->drawTimeline(painter, rect);
- }
}
/*! Draw the foreground for a day.
*/
void DateTimeGrid::drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date)
{
+ Q_UNUSED(painter);
+ Q_UNUSED(rect);
Q_UNUSED(date);
- if (d->timelineOptions & Foreground) {
- d->drawTimeline(painter, rect);
- }
}
/** Return the rectangle that represents the date-range.
*/
QRectF DateTimeGrid::computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const
{
qreal topLeft = d->dateTimeToChartX(from);
qreal topRight = d->dateTimeToChartX(to);
return QRectF(topLeft, rect.top(), topRight - topLeft, rect.height());
}
/** Return a date-range represented by the rectangle.
*/
QPair DateTimeGrid::dateTimeRange(const QRectF& rect) const
{
QDateTime start;
QDateTime end;
start = d->chartXtoDateTime(rect.left());
end = d->chartXtoDateTime(rect.right());
return qMakePair(start, end);
}
void DateTimeGrid::drawBackground(QPainter* paint, const QRectF& rect)
{
int offset = (int)dayWidth();
assert( offset>0 );
// Figure out the date at the extreme left
QDate date = d->chartXtoDateTime(rect.left()).date();
// We need to paint from one end to the other
int startx = rect.left();
int endx = rect.right();
// Save the painter state
paint->save();
// Paint the first date column
while (1)
{
QDate nextDate = d->chartXtoDateTime(startx+1).date();
if (date != nextDate)
{
QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
dayRect = dayRect.adjusted(1, 0, 0, 0);
drawDayBackground(paint, dayRect, date);
break;
}
++startx;
}
// Paint the remaining dates
for (int i=startx; ichartXtoDateTime(i+1).date();
QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
dayRect = dayRect.adjusted(1, 0, 0, 0);
drawDayBackground(paint, dayRect, date);
}
// Restore the painter state
paint->restore();
}
void DateTimeGrid::drawForeground(QPainter* paint, const QRectF& rect)
{
int offset = (int)dayWidth();
// Figure out the date at the extreme left
QDate date = d->chartXtoDateTime(rect.left()).date();
// We need to paint from one end to the other
int startx = rect.left();
int endx = rect.right();
// Save the painter state
paint->save();
// Paint the first date column
while (1)
{
QDate nextDate = d->chartXtoDateTime(startx+1).date();
if (date != nextDate)
{
QRectF dayRect(startx-dayWidth(), rect.top(), dayWidth(), rect.height());
dayRect = dayRect.adjusted(1, 0, 0, 0);
drawDayForeground(paint, dayRect, date);
break;
}
++startx;
}
// Paint the remaining dates
for (int i=startx; ichartXtoDateTime(i+1).date();
QRectF dayRect(i, rect.top(), dayWidth(), rect.height());
dayRect = dayRect.adjusted(1, 0, 0, 0);
drawDayForeground(paint, dayRect, date);
}
// Restore the painter state
paint->restore();
}
-void DateTimeGrid::setTimelineTime(const QDateTime &dt)
-{
- d->timelineTime = dt;
- emit gridChanged();
-}
-
-QDateTime DateTimeGrid::timelineTime() const
-{
- return d->timelineTime;
-}
-
-void DateTimeGrid::setTimelinePen(const QPen &pen)
-{
- d->timelinePen = pen;
- emit gridChanged();
-}
-
-void DateTimeGrid::setTimelineOptions(DateTimeGrid::TimelineOptions mode)
-{
- d->timelineOptions = mode;
- emit gridChanged();
-}
-
-DateTimeGrid::TimelineOptions DateTimeGrid::timelineOptions() const
-{
- return d->timelineOptions;
-}
-
#undef d
#ifndef KDAB_NO_UNIT_TESTS
#include
#include "unittest/test.h"
static std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
{
#ifdef QT_NO_STL
os << dt.toString().toLatin1().constData();
#else
os << dt.toString().toStdString();
#endif
return os;
}
KDAB_SCOPED_UNITTEST_SIMPLE( KGantt, DateTimeGrid, "test" ) {
QStandardItemModel model( 3, 2 );
DateTimeGrid grid;
QDateTime dt = QDateTime::currentDateTime();
grid.setModel( &model );
QDateTime startdt = dt.addDays( -10 );
grid.setStartDateTime( startdt );
model.setData( model.index( 0, 0 ), dt, StartTimeRole );
model.setData( model.index( 0, 0 ), dt.addDays( 17 ), EndTimeRole );
model.setData( model.index( 2, 0 ), dt.addDays( 18 ), StartTimeRole );
model.setData( model.index( 2, 0 ), dt.addDays( 19 ), EndTimeRole );
Span s = grid.mapToChart( model.index( 0, 0 ) );
//qDebug() << "span="<0 );
assertTrue( s.length()>0 );
assertTrue( startdt == grid.mapToDateTime( grid.mapFromDateTime( startdt ) ) );
grid.mapFromChart( s, model.index( 1, 0 ) );
QDateTime s1 = model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime();
QDateTime e1 = model.data( model.index( 0, 0 ), EndTimeRole ).toDateTime();
QDateTime s2 = model.data( model.index( 1, 0 ), StartTimeRole ).toDateTime();
QDateTime e2 = model.data( model.index( 1, 0 ), EndTimeRole ).toDateTime();
assertTrue( s1.isValid() );
assertTrue( e1.isValid() );
assertTrue( s2.isValid() );
assertTrue( e2.isValid() );
assertEqual( s1, s2 );
assertEqual( e1, e2 );
assertTrue( grid.isSatisfiedConstraint( Constraint( model.index( 0, 0 ), model.index( 2, 0 ) ) ) );
assertFalse( grid.isSatisfiedConstraint( Constraint( model.index( 2, 0 ), model.index( 0, 0 ) ) ) );
s = grid.mapToChart( model.index( 0, 0 ) );
s.setEnd( s.end()+100000. );
bool rc = grid.mapFromChart( s, model.index( 0, 0 ) );
assertTrue( rc );
assertEqual( s1, model.data( model.index( 0, 0 ), StartTimeRole ).toDateTime() );
Span newspan = grid.mapToChart( model.index( 0, 0 ) );
assertEqual( newspan.start(), s.start() );
assertEqual( newspan.length(), s.length() );
{
QDateTime startDateTime = QDateTime::currentDateTime();
qreal dayWidth = 100;
QDate currentDate = QDate::currentDate();
QDateTime dt( QDate(currentDate.year(), 1, 1), QTime( 0, 0, 0, 0 ) );
assert( dt.isValid() );
qreal result = startDateTime.date().daysTo(dt.date())*24.*60.*60.;
result += startDateTime.time().msecsTo(dt.time())/1000.;
result *= dayWidth/( 24.*60.*60. );
int days = static_cast( result/dayWidth );
qreal secs = result*( 24.*60.*60. )/dayWidth;
QDateTime dt2 = startDateTime;
QDateTime result2 = dt2.addDays( days ).addSecs( static_cast(secs-(days*24.*60.*60.) ) ).addMSecs( qRound( ( secs-static_cast( secs ) )*1000. ) );
assertEqual( dt, result2 );
}
}
#endif /* KDAB_NO_UNIT_TESTS */
#include "moc_kganttdatetimegrid.cpp"
diff --git a/src/KGantt/kganttdatetimegrid.h b/src/KGantt/kganttdatetimegrid.h
index 89d1676..c28876c 100644
--- a/src/KGantt/kganttdatetimegrid.h
+++ b/src/KGantt/kganttdatetimegrid.h
@@ -1,238 +1,165 @@
/*
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef KGANTTDATETIMEGRID_H
#define KGANTTDATETIMEGRID_H
#include "kganttabstractgrid.h"
#include
#include
namespace KGantt {
class DateTimeScaleFormatter;
class KGANTT_EXPORT DateTimeGrid : public AbstractGrid
{
Q_OBJECT
KGANTT_DECLARE_PRIVATE_DERIVED( DateTimeGrid )
public:
enum Scale {
ScaleAuto,
ScaleHour,
ScaleDay,
ScaleWeek,
ScaleMonth,
ScaleUserDefined
};
DateTimeGrid();
virtual ~DateTimeGrid();
QDateTime startDateTime() const;
void setStartDateTime( const QDateTime& dt );
qreal dayWidth() const;
void setDayWidth( qreal );
qreal mapFromDateTime( const QDateTime& dt) const;
QDateTime mapToDateTime( qreal x ) const;
void setWeekStart( Qt::DayOfWeek );
Qt::DayOfWeek weekStart() const;
void setFreeDays( const QSet& fd );
QSet freeDays() const;
void setFreeDaysBrush(const QBrush brush);
QBrush freeDaysBrush() const;
void setScale( Scale s );
Scale scale() const;
void setUserDefinedLowerScale( DateTimeScaleFormatter* lower );
void setUserDefinedUpperScale( DateTimeScaleFormatter* upper );
DateTimeScaleFormatter* userDefinedLowerScale() const;
DateTimeScaleFormatter* userDefinedUpperScale() const;
bool rowSeparators() const;
void setRowSeparators( bool enable );
void setNoInformationBrush( const QBrush& brush );
QBrush noInformationBrush() const;
/*reimp*/ Span mapToChart( const QModelIndex& idx ) const Q_DECL_OVERRIDE;
/*reimp*/ bool mapFromChart( const Span& span, const QModelIndex& idx,
const QList& constraints=QList() ) const Q_DECL_OVERRIDE;
/*reimp*/ qreal mapToChart( const QVariant& value ) const Q_DECL_OVERRIDE;
/*reimp*/ QVariant mapFromChart( qreal x ) const Q_DECL_OVERRIDE;
/*reimp*/ void paintGrid( QPainter* painter,
const QRectF& sceneRect, const QRectF& exposedRect,
AbstractRowController* rowController = nullptr,
QWidget* widget = nullptr ) Q_DECL_OVERRIDE;
/*reimp*/ void paintHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget = nullptr ) Q_DECL_OVERRIDE;
- /// \enum TimelineOptions controls how the timeline is displayed
- enum TimelineOption {
- Foreground = 1, /// Display the timeline in the foreground.
- Background = 2, /// Display the timeline in the background.
- UseCustomPen = 4, /// Paint the timeline using the pen set with setTimelinePen().
- TimelineModeMax = 0xFFFF
- };
- Q_DECLARE_FLAGS(TimelineOptions, TimelineOption)
-
- /**
- * \brief Set the timeline options to \p options
- *
- * By default the timeline is not displayed.
- *
- * To display the timeline you have to set the options to either
- * Foreground or Background, e.g:
- * \code
- * grid->setTimelineOptions(KGantt::DateTimeGrid::Foreground);
- * \endcode
- *
- * \sa TimelineOptions
- * \sa DateTimeGrid::setTimelineTime
- * \sa DateTimeGrid::setTimelinePen
- */
- void setTimelineOptions(TimelineOptions options);
-
- /**
- * Return the current timeline options
- *
- * \sa DateTimeGrid::setTimelineMode()
- */
- TimelineOptions timelineOptions() const;
-
- /**
- * Returns the current timeline time
- *
- * \sa DateTimeGrid::setTimelineTime()
- */
- QDateTime timelineTime() const;
-
- /**
- * \brief Set a cutsom pen to use when drawing the timeline.
- *
- * The default pen is a solid line, cosmetic pen
- * with QApplication::palette().highlight() color.
- *
- * You must enable use by setting the flag UseCustomPen \see setTimelineOptions()
- */
- void setTimelinePen(const QPen &pen);
-
- public Q_SLOTS:
- /**
- * \brief Set the timeline time to \p dt.
- *
- * If \p dt is not valid the current datetime will be used
- *
- * If you want the timeline to be periodically updated with the current time,
- * you can do something like this in your program:
- * \code
- * QTimer *timelineTimer = new QTimer(this);
- * timelineTimer->setInterval(5000);
- * timelineTimer->start();
- * grid->setTimelineOptions(KGantt::DateTimeGrid::Foreground);
- * connect(timelineTimer, SIGNAL(timeout()), grid, SLOT(setTimelineTime()));
- * \endcode
- *
- * \sa DateTimeGrid::setTimelineOptions()
- * \sa DateTimeGrid::setTimelinePen()
- */
- void setTimelineTime(const QDateTime &dt = QDateTime());
-
protected:
virtual void paintHourScaleHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget = nullptr );
virtual void paintDayScaleHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget = nullptr );
virtual void paintWeekScaleHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget = nullptr );
virtual void paintMonthScaleHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget = nullptr );
virtual void paintUserDefinedHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, const DateTimeScaleFormatter* formatter,
QWidget* widget = nullptr );
virtual void drawDayBackground(QPainter* painter, const QRectF& rect, const QDate& date);
virtual void drawDayForeground(QPainter* painter, const QRectF& rect, const QDate& date);
QRectF computeRect(const QDateTime& from, const QDateTime& to, const QRectF& rect) const;
QPair dateTimeRange(const QRectF& rect) const;
/* reimp */ void drawBackground(QPainter* paint, const QRectF& rect) Q_DECL_OVERRIDE;
/* reimp */ void drawForeground(QPainter* paint, const QRectF& rect) Q_DECL_OVERRIDE;
};
class KGANTT_EXPORT DateTimeScaleFormatter
{
KGANTT_DECLARE_PRIVATE_BASE_POLYMORPHIC( DateTimeScaleFormatter )
public:
enum Range {
Second,
Minute,
Hour,
Day,
Week,
Month,
Year
};
DateTimeScaleFormatter( Range range, const QString& formatString,
Qt::Alignment alignment = Qt::AlignCenter );
DateTimeScaleFormatter( Range range, const QString& formatString,
const QString& templ, Qt::Alignment alignment = Qt::AlignCenter );
DateTimeScaleFormatter( const DateTimeScaleFormatter& other );
virtual ~DateTimeScaleFormatter();
DateTimeScaleFormatter& operator=( const DateTimeScaleFormatter& other );
QString format() const;
Range range() const;
Qt::Alignment alignment() const;
virtual QDateTime nextRangeBegin( const QDateTime& datetime ) const;
virtual QDateTime currentRangeBegin( const QDateTime& datetime ) const;
QString format( const QDateTime& datetime ) const;
virtual QString text( const QDateTime& datetime ) const;
};
}
#ifndef QT_NO_DEBUG_STREAM
QDebug KGANTT_EXPORT operator<<( QDebug dbg, KGantt::DateTimeScaleFormatter::Range );
#endif
-Q_DECLARE_OPERATORS_FOR_FLAGS(KGantt::DateTimeGrid::TimelineOptions)
-
#endif /* KGANTTDATETIMEGRID_H */
diff --git a/src/KGantt/kganttdatetimegrid_p.h b/src/KGantt/kganttdatetimegrid_p.h
index 8db031e..300f282 100644
--- a/src/KGantt/kganttdatetimegrid_p.h
+++ b/src/KGantt/kganttdatetimegrid_p.h
@@ -1,176 +1,166 @@
/*
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef KGANTTDATETIMEGRID_P_H
#define KGANTTDATETIMEGRID_P_H
#include "kganttdatetimegrid.h"
#include "kganttabstractgrid_p.h"
#include
#include
-#include
-#include
namespace KGantt {
class Q_DECL_HIDDEN DateTimeScaleFormatter::Private
{
public:
Private( DateTimeScaleFormatter::Range _range,
const QString& _format,
const QString& _templ,
Qt::Alignment _alignment )
: range( _range ),
format( _format ),
templ( _templ ),
alignment( _alignment )
{
}
const DateTimeScaleFormatter::Range range;
const QString format;
const QString templ;
const Qt::Alignment alignment;
};
class Q_DECL_HIDDEN DateTimeGrid::Private : public AbstractGrid::Private {
public:
Private()
: startDateTime( QDateTime::currentDateTime().addDays( -3 ) ),
dayWidth( 100. ),
scale( ScaleAuto ),
weekStart( Qt::Monday ),
freeDays( QSet() << Qt::Saturday << Qt::Sunday ),
rowSeparators( false ),
noInformationBrush( Qt::red, Qt::DiagCrossPattern ),
freeDaysBrush(QBrush()),
upper( new DateTimeScaleFormatter( DateTimeScaleFormatter::Week, QString::fromLatin1( "w" ) ) ),
lower( new DateTimeScaleFormatter( DateTimeScaleFormatter::Day, QString::fromLatin1( "ddd" ) ) ),
year_upper( DateTimeScaleFormatter::Year, QString::fromLatin1("yyyy" ) ),
year_lower( DateTimeScaleFormatter::Month, QString::fromLatin1("MMM" ) ),
month_upper( DateTimeScaleFormatter::Month, QString::fromLatin1("MMMM" ) ),
month_lower( DateTimeScaleFormatter::Week, QString::fromLatin1("w" ) ),
week_upper( DateTimeScaleFormatter::Week, QString::fromLatin1("w" ) ),
week_lower( DateTimeScaleFormatter::Day, QString::fromLatin1("ddd" ) ),
day_upper( DateTimeScaleFormatter::Day, QString::fromLatin1("dddd" ) ),
day_lower( DateTimeScaleFormatter::Hour, QString::fromLatin1("hh" ) ),
hour_upper( DateTimeScaleFormatter::Hour, QString::fromLatin1("hh" ) ),
hour_lower( DateTimeScaleFormatter::Minute, QString::fromLatin1("m" ) ),
minute_upper( DateTimeScaleFormatter::Minute, QString::fromLatin1("m" ) ),
- minute_lower( DateTimeScaleFormatter::Second, QString::fromLatin1("s" ) ),
- timelineOptions(nullptr)
+ minute_lower( DateTimeScaleFormatter::Second, QString::fromLatin1("s" ) )
{
}
~Private()
{
delete lower;
delete upper;
}
qreal dateTimeToChartX( const QDateTime& dt ) const;
QDateTime chartXtoDateTime( qreal x ) const;
int tabHeight( const QString& txt, QWidget* widget = nullptr ) const;
-
- void drawTimeline(QPainter* painter, const QRectF& rect);
-
void getAutomaticFormatters( DateTimeScaleFormatter** lower, DateTimeScaleFormatter** upper);
class DateTextFormatter {
public:
virtual ~DateTextFormatter() {}
virtual QString format( const QDateTime& dt ) = 0;
virtual QRect textRect( qreal x, qreal offset, qreal dayWidth, const QRectF& headerRect, const QDateTime& dt ) = 0;
};
/*!
* We need this because we have a header type for a year, but no such scale.
*/
enum HeaderType {
HeaderHour,
HeaderDay,
HeaderWeek,
HeaderMonth,
HeaderYear
};
HeaderType headerTypeForScale( DateTimeGrid::Scale scale );
void paintHeader( QPainter* painter,
const QRectF& headerRect, const QRectF& exposedRect,
qreal offset, QWidget* widget,
HeaderType headerType,
DateTextFormatter *formatter );
void paintVerticalLines( QPainter* painter,
const QRectF& sceneRect,
const QRectF& exposedRect,
QWidget* widget,
HeaderType headerType );
void paintVerticalUserDefinedLines( QPainter* painter,
const QRectF& sceneRect,
const QRectF& exposedRect,
const DateTimeScaleFormatter* formatter,
QWidget* widget );
Qt::PenStyle gridLinePenStyle( QDateTime dt, HeaderType headerType ) const;
QDateTime adjustDateTimeForHeader( QDateTime dt, HeaderType headerType ) const;
QDateTime startDateTime;
QDateTime endDateTime;
qreal dayWidth;
Scale scale;
Qt::DayOfWeek weekStart;
QSet freeDays;
bool rowSeparators;
QBrush noInformationBrush;
QBrush freeDaysBrush;
DateTimeScaleFormatter* upper;
DateTimeScaleFormatter* lower;
DateTimeScaleFormatter year_upper;
DateTimeScaleFormatter year_lower;
DateTimeScaleFormatter month_upper;
DateTimeScaleFormatter month_lower;
DateTimeScaleFormatter week_upper;
DateTimeScaleFormatter week_lower;
DateTimeScaleFormatter day_upper;
DateTimeScaleFormatter day_lower;
DateTimeScaleFormatter hour_upper;
DateTimeScaleFormatter hour_lower;
DateTimeScaleFormatter minute_upper;
DateTimeScaleFormatter minute_lower;
-
- QDateTime timelineTime;
- DateTimeGrid::TimelineOptions timelineOptions;
- QPen timelinePen;
};
inline DateTimeGrid::DateTimeGrid( DateTimeGrid::Private* d ) : AbstractGrid( d ) {}
inline DateTimeGrid::Private* DateTimeGrid::d_func() {
return static_cast( AbstractGrid::d_func() );
}
inline const DateTimeGrid::Private* DateTimeGrid::d_func() const {
return static_cast( AbstractGrid::d_func() );
}
}
#endif /* KGANTTDATETIMEGRID_P_H */