15 #include "kdganttgraphicsview_p.h"
17 #include <QAbstractProxyModel>
18 #include <QActionGroup>
20 #include <QPaintEvent>
23 #include <QResizeEvent>
29 #include "../evaldialog/evaldialog.h"
45 HeaderWidget::~HeaderWidget()
49 void HeaderWidget::scrollTo(
int v)
57 void HeaderWidget::paintEvent(QPaintEvent *ev)
60 view()->grid()->paintHeader(&p, rect(), ev->rect(), m_offset,
this);
63 bool HeaderWidget::event(QEvent *event)
65 if (event->type() == QEvent::ToolTip) {
66 auto *
const grid = qobject_cast<DateTimeGrid *>(view()->grid());
68 auto *e =
static_cast<QHelpEvent *
>(event);
69 QDateTime dt = grid->mapFromChart(view()->mapToScene(e->x(), 0).x()).toDateTime();
70 setToolTip(dt.toString());
73 return QWidget::event(event);
76 void HeaderWidget::contextMenuEvent(QContextMenuEvent *event)
80 auto *
const grid = qobject_cast<DateTimeGrid *>(view()->grid());
81 QAction *actionScaleAuto =
nullptr;
82 QAction *actionScaleMonth =
nullptr;
83 QAction *actionScaleWeek =
nullptr;
84 QAction *actionScaleDay =
nullptr;
85 QAction *actionScaleHour =
nullptr;
86 QAction *actionZoomIn =
nullptr;
87 QAction *actionZoomOut =
nullptr;
88 if (grid !=
nullptr) {
89 auto *menuScale =
new QMenu(tr(
"Scale"), &contextMenu);
90 auto *scaleGroup =
new QActionGroup(&contextMenu);
91 scaleGroup->setExclusive(
true);
93 actionScaleAuto =
new QAction(tr(
"Auto"), menuScale);
94 actionScaleAuto->setCheckable(
true);
95 actionScaleAuto->setChecked(grid->scale() == DateTimeGrid::ScaleAuto);
96 actionScaleMonth =
new QAction(tr(
"Month"), menuScale);
97 actionScaleMonth->setCheckable(
true);
98 actionScaleMonth->setChecked(grid->scale() == DateTimeGrid::ScaleMonth);
99 actionScaleWeek =
new QAction(tr(
"Week"), menuScale);
100 actionScaleWeek->setCheckable(
true);
101 actionScaleWeek->setChecked(grid->scale() == DateTimeGrid::ScaleWeek);
102 actionScaleDay =
new QAction(tr(
"Day"), menuScale);
103 actionScaleDay->setCheckable(
true);
104 actionScaleDay->setChecked(grid->scale() == DateTimeGrid::ScaleDay);
105 actionScaleHour =
new QAction(tr(
"Hour"), menuScale);
106 actionScaleHour->setCheckable(
true);
107 actionScaleHour->setChecked(grid->scale() == DateTimeGrid::ScaleHour);
109 scaleGroup->addAction(actionScaleAuto);
110 menuScale->addAction(actionScaleAuto);
112 scaleGroup->addAction(actionScaleMonth);
113 menuScale->addAction(actionScaleMonth);
115 scaleGroup->addAction(actionScaleWeek);
116 menuScale->addAction(actionScaleWeek);
118 scaleGroup->addAction(actionScaleDay);
119 menuScale->addAction(actionScaleDay);
121 scaleGroup->addAction(actionScaleHour);
122 menuScale->addAction(actionScaleHour);
124 contextMenu.addMenu(menuScale);
126 contextMenu.addSeparator();
128 actionZoomIn =
new QAction(tr(
"Zoom In"), &contextMenu);
129 contextMenu.addAction(actionZoomIn);
130 actionZoomOut =
new QAction(tr(
"Zoom Out"), &contextMenu);
131 contextMenu.addAction(actionZoomOut);
134 if (contextMenu.isEmpty()) {
139 const QAction *
const action = contextMenu.exec(event->globalPos());
140 if (action ==
nullptr) {
141 }
else if (action == actionScaleAuto) {
142 assert(grid !=
nullptr);
143 grid->setScale(DateTimeGrid::ScaleAuto);
144 }
else if (action == actionScaleMonth) {
145 assert(grid !=
nullptr);
146 grid->setScale(DateTimeGrid::ScaleMonth);
147 }
else if (action == actionScaleWeek) {
148 assert(grid !=
nullptr);
149 grid->setScale(DateTimeGrid::ScaleWeek);
150 }
else if (action == actionScaleDay) {
151 assert(grid !=
nullptr);
152 grid->setScale(DateTimeGrid::ScaleDay);
153 }
else if (action == actionScaleHour) {
154 assert(grid !=
nullptr);
155 grid->setScale(DateTimeGrid::ScaleHour);
156 }
else if (action == actionZoomIn) {
157 assert(grid !=
nullptr);
158 grid->setDayWidth(qMax(0.1, grid->dayWidth() + grid->dayWidth() * 0.2));
159 }
else if (action == actionZoomOut) {
160 assert(grid !=
nullptr);
161 grid->setDayWidth(qMax(0.1, grid->dayWidth() - grid->dayWidth() * 0.2));
169 , rowcontroller(nullptr)
174 void GraphicsView::Private::updateHeaderGeometry()
176 q->setViewportMargins(0, rowcontroller->headerHeight(), 0, 0);
177 headerwidget.setGeometry(q->viewport()->x(),
178 q->viewport()->y() - rowcontroller->headerHeight(),
179 q->viewport()->width(),
180 rowcontroller->headerHeight());
183 void GraphicsView::Private::slotGridChanged()
185 updateHeaderGeometry();
186 headerwidget.update();
187 q->updateSceneRect();
191 void GraphicsView::Private::slotHorizontalScrollValueChanged(
int val)
193 const QRectF viewRect = q->transform().mapRect(q->sceneRect());
194 headerwidget.scrollTo(val - q->horizontalScrollBar()->minimum() +
static_cast<int>(viewRect.left()));
197 void GraphicsView::Private::slotColumnsInserted(
const QModelIndex &parent,
int start,
int end)
201 QModelIndex idx = scene.model()->index(0, 0, scene.summaryHandlingModel()->mapToSource(parent));
203 scene.updateRow(scene.summaryHandlingModel()->mapFromSource(idx));
204 }
while ((idx = rowcontroller->indexBelow(idx)) != QModelIndex() && rowcontroller->isRowVisible(idx));
206 q->updateSceneRect();
209 void GraphicsView::Private::slotColumnsRemoved(
const QModelIndex &parent,
int start,
int end)
218 void GraphicsView::Private::slotDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
221 const QModelIndex parent = topLeft.parent();
222 for (
int row = topLeft.row(); row <= bottomRight.row(); ++row) {
223 scene.updateRow(scene.summaryHandlingModel()->index(row, 0, parent));
227 void GraphicsView::Private::slotLayoutChanged()
233 void GraphicsView::Private::slotModelReset()
239 void GraphicsView::Private::slotRowsInserted(
const QModelIndex &parent,
int start,
int end)
247 void GraphicsView::Private::slotRowsAboutToBeRemoved(
const QModelIndex &parent,
int start,
int end)
250 for (
int row = start; row <= end; ++row) {
251 for (
int col = 0; col < scene.summaryHandlingModel()->columnCount(parent); ++col) {
253 scene.removeItem(scene.summaryHandlingModel()->index(row, col, parent));
258 void GraphicsView::Private::slotRowsRemoved(
const QModelIndex &parent,
int start,
int end)
269 void GraphicsView::Private::slotItemClicked(
const QModelIndex &idx)
271 QModelIndex sidx = idx;
272 Q_EMIT q->clicked(sidx);
273 if (q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick,
nullptr, q))
274 Q_EMIT q->activated(sidx);
277 void GraphicsView::Private::slotItemDoubleClicked(
const QModelIndex &idx)
279 QModelIndex sidx = idx;
280 Q_EMIT q->qrealClicked(sidx);
281 if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick,
nullptr, q))
282 Q_EMIT q->activated(sidx);
285 void GraphicsView::Private::slotHeaderContextMenuRequested(
const QPoint &pt)
287 Q_EMIT q->headerContextMenuRequested(headerwidget.mapToGlobal(pt));
311 GraphicsView::GraphicsView(QWidget *parent)
312 : QGraphicsView(parent)
313 , _d(new Private(this))
315 #if defined KDAB_EVAL
316 EvalDialog::checkEvalLicense(
"KD Gantt");
318 connect(horizontalScrollBar(), &QScrollBar::valueChanged,
319 this, [
this](
int value) {
320 _d->slotHorizontalScrollValueChanged(value);
324 _d->slotGridChanged();
331 this, [
this](
const QModelIndex &index) {
332 _d->slotItemClicked(index);
335 this, [
this](
const QModelIndex &index) {
336 _d->slotItemDoubleClicked(index);
338 connect(&_d->scene, &GraphicsScene::sceneRectChanged,
340 connect(&_d->headerwidget, &HeaderWidget::customContextMenuRequested,
341 this, [
this](
const QPoint &point) {
342 _d->slotHeaderContextMenuRequested(point);
344 setScene(&_d->scene);
351 setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
379 if (
d->scene.model()) {
380 disconnect(
d->scene.model());
392 return d->scene.model();
397 disconnect(
d->scene.summaryHandlingModel());
398 d->scene.setSummaryHandlingModel(proxyModel);
403 connect(proxyModel, &QAbstractProxyModel::columnsInserted,
404 this, [
this](
const QModelIndex &parent,
int first,
int last) {
405 d->slotColumnsInserted(parent, first, last);
407 connect(proxyModel, &QAbstractProxyModel::columnsRemoved,
408 this, [
this](
const QModelIndex &parent,
int first,
int last) {
409 d->slotColumnsRemoved(parent, first, last);
411 connect(proxyModel, &QAbstractProxyModel::dataChanged,
412 this, [
this](
const QModelIndex &topLeft,
const QModelIndex &bottomRight) {
413 d->slotDataChanged(topLeft, bottomRight);
415 connect(proxyModel, &QAbstractProxyModel::layoutChanged,
417 d->slotLayoutChanged();
419 connect(proxyModel, &QAbstractProxyModel::modelReset,
423 connect(proxyModel, &QAbstractProxyModel::rowsInserted,
424 this, [
this](
const QModelIndex &parent,
int first,
int last) {
425 d->slotRowsInserted(parent, first, last);
427 connect(proxyModel, &QAbstractProxyModel::rowsAboutToBeRemoved,
428 this, [
this](
const QModelIndex &parent,
int first,
int last) {
429 d->slotRowsAboutToBeRemoved(parent, first, last);
431 connect(proxyModel, &QAbstractProxyModel::rowsRemoved,
432 this, [
this](
const QModelIndex &parent,
int first,
int last) {
433 d->slotRowsRemoved(parent, first, last);
444 d->scene.setConstraintModel(cmodel);
451 return d->scene.constraintModel();
458 return d->scene.summaryHandlingModel();
466 d->scene.setRootIndex(idx);
473 return d->scene.rootIndex();
481 d->scene.setSelectionModel(
model);
488 return d->scene.selectionModel();
496 d->scene.setItemDelegate(delegate);
503 return d->scene.itemDelegate();
513 d->rowcontroller = rowcontroller;
514 d->scene.setRowController(rowcontroller);
523 return d->rowcontroller;
533 d->scene.setGrid(
grid);
534 d->slotGridChanged();
541 return d->scene.grid();
549 d->scene.setReadOnly(ro);
556 return d->scene.isReadOnly();
570 d->headerwidget.setContextMenuPolicy(p);
577 return d->headerwidget.contextMenuPolicy();
589 const QModelIndex &to,
590 Qt::KeyboardModifiers modifiers)
605 d->updateHeaderGeometry();
606 QRectF r = scene()->itemsBoundingRect();
608 r.setLeft(qMin<qreal>(0.0, r.left()));
611 QSizeF size = viewport()->size();
613 if (size.width() > r.width()) {
614 r.setWidth(size.width() - 2);
616 if (size.height() > r.height()) {
617 r.setHeight(size.height() - 2);
620 if (r.height() < totalh) {
624 scene()->setSceneRect(r);
626 QGraphicsView::resizeEvent(ev);
637 QGraphicsItem *item = itemAt(pos);
638 if (
auto *gitem = qgraphicsitem_cast<GraphicsItem *>(item)) {
639 return d->scene.summaryHandlingModel()->mapToSource(gitem->index());
641 return QModelIndex();
648 d->scene.clearItems();
654 d->scene.updateRow(
d->scene.summaryHandlingModel()->mapFromSource(idx));
665 qreal range = horizontalScrollBar()->maximum() - horizontalScrollBar()->minimum();
666 const qreal hscroll = horizontalScrollBar()->value() / (range > 0 ? range : 1);
667 QRectF r =
d->scene.itemsBoundingRect();
670 r.setLeft(qMin<qreal>(0.0, r.left()));
671 r.setSize(r.size().expandedTo(viewport()->size()));
673 if (r.height() < totalh)
675 d->scene.setSceneRect(r);
678 range = horizontalScrollBar()->maximum() - horizontalScrollBar()->minimum();
680 horizontalScrollBar()->setValue(qRound(hscroll * range));
686 d->scene.invalidate(QRectF(), QGraphicsScene::BackgroundLayer);
707 scene()->invalidate(QRectF(), QGraphicsScene::BackgroundLayer);
713 return d->scene.createItem(type);
719 d->scene.deleteSubtree(
d->scene.summaryHandlingModel()->mapFromSource(idx));
732 d->scene.print(printer, drawRowLabels, drawColumnLabels);
747 void GraphicsView::print(QPrinter *printer, qreal start, qreal end,
bool drawRowLabels,
bool drawColumnLabels)
749 d->scene.print(printer, start, end, drawRowLabels, drawColumnLabels);
758 void GraphicsView::print(QPainter *painter,
const QRectF &targetRect,
bool drawRowLabels,
bool drawColumnLabels)
760 d->scene.print(painter, targetRect, drawRowLabels, drawColumnLabels);
774 const QRectF &targetRect,
bool drawRowLabels,
bool drawColumnLabels)
776 d->scene.print(painter, start, end, targetRect, drawRowLabels, drawColumnLabels);
779 #include "moc_kdganttgraphicsview.cpp"
Abstract baseclass for grids.
Abstract baseclass for row controllers.
virtual int totalHeight() const =0
The ConstraintModel keeps track of the interdependencies between gantt items in a View.
virtual void addConstraint(const Constraint &c)
Adds the constraint c to this ConstraintModel If the Constraint c is already in this ConstraintModel,...
bool hasConstraint(const Constraint &c) const
Returns true if a Constraint with start s and end e exists, otherwise false.
virtual bool removeConstraint(const Constraint &c)
Removes the Constraint c from this ConstraintModel.
A class used to represent a dependency.
void entered(const QModelIndex &index)
void clicked(const QModelIndex &index)
void qrealClicked(const QModelIndex &index)
void pressed(const QModelIndex &index)
The GraphicsView class provides a model/view implementation of a gantt chart.
void setItemDelegate(ItemDelegate *delegate)
Sets the KDGantt::ItemDelegate used for rendering items on this view.
void setModel(QAbstractItemModel *)
Sets the model to be displayed in this view to model.
QAbstractItemModel * model() const
void entered(const QModelIndex &index)
void pressed(const QModelIndex &index)
void setRootIndex(const QModelIndex &)
Sets the root index of the model displayed by this view.
void setRowController(AbstractRowController *)
Sets the AbstractRowController used by this view.
~GraphicsView() override
Destroys this view.
void print(QPrinter *printer, bool drawRowLabels=true, bool drawColumnLabels=true)
Print the Gantt chart using printer.
void setSelectionModel(QItemSelectionModel *)
Sets the QItemSelectionModel used by this view to manage selections.
void setGrid(AbstractGrid *)
Sets the AbstractGrid for this view.
void resizeEvent(QResizeEvent *) override
void setHeaderContextMenuPolicy(Qt::ContextMenuPolicy)
Sets the context menu policy for the header.
QModelIndex rootIndex() const
ConstraintModel * constraintModel() const
void setConstraintModel(ConstraintModel *)
Sets the constraintmodel displayed by this view.
virtual void addConstraint(const QModelIndex &from, const QModelIndex &to, Qt::KeyboardModifiers modifiers)
Adds a constraint from from to to.
QItemSelectionModel * selectionModel() const
AbstractGrid * grid() const
AbstractRowController * rowController() const
void setSummaryHandlingModel(QAbstractProxyModel *model)
Qt::ContextMenuPolicy headerContextMenuPolicy() const
void setReadOnly(bool)
Sets the view to read-only mode if to is true.
void updateRow(const QModelIndex &)
ItemDelegate * itemDelegate() const
QModelIndex indexAt(const QPoint &pos) const
QAbstractProxyModel * summaryHandlingModel() const
void deleteSubtree(const QModelIndex &)
Class used to render gantt items in a KDGantt::GraphicsView.
ItemType
The values of this enum are used to represent the different types of gantt items that KDGantt underst...