File indexing completed on 2024-11-24 03:57:49
0001 /** 0002 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KGantt library. 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "mainwindow.h" 0010 #include "../common/projectmodel.h" 0011 0012 #include <QAction> 0013 #include <QApplication> 0014 #include <QComboBox> 0015 #include <QMenuBar> 0016 #include <QMenu> 0017 #include <QModelIndex> 0018 #include <QItemSelectionModel> 0019 #include <QTreeView> 0020 #include <QDebug> 0021 #include <QBrush> 0022 #include <QPainter> 0023 #include <QPrinter> 0024 #include <QPrintDialog> 0025 #include <QFileDialog> 0026 #include <QLabel> 0027 #include <QGridLayout> 0028 #include <QVBoxLayout> 0029 #include <QHBoxLayout> 0030 #include <QFileInfo> 0031 #include <QLineEdit> 0032 #include <QCheckBox> 0033 #include <QPushButton> 0034 #include <QDialogButtonBox> 0035 0036 #include <KGanttGlobal> 0037 #include <KGanttView> 0038 #include <KGanttItemDelegate> 0039 #include <KGanttDateTimeGrid> 0040 #include <KGanttStyleOptionGanttItem> 0041 #include <KGanttConstraintModel> 0042 #include <KGanttGraphicsView> 0043 #include <KGanttDateTimeTimeLine> 0044 0045 class ItemTypeComboBox : public QComboBox { 0046 Q_OBJECT 0047 Q_PROPERTY( KGantt::ItemType itemType READ itemType WRITE setItemType ) 0048 public: 0049 explicit ItemTypeComboBox( QWidget* parent = nullptr ); 0050 0051 KGantt::ItemType itemType() const; 0052 public Q_SLOTS: 0053 void setItemType( KGantt::ItemType typ ); 0054 }; 0055 0056 ItemTypeComboBox::ItemTypeComboBox( QWidget* parent ) 0057 : QComboBox( parent ) 0058 { 0059 addItem( tr( "Task" ), QVariant( KGantt::TypeTask ) ); 0060 addItem( tr( "Event" ), QVariant( KGantt::TypeEvent ) ); 0061 addItem( tr( "Summary" ), QVariant( KGantt::TypeSummary ) ); 0062 } 0063 0064 KGantt::ItemType ItemTypeComboBox::itemType() const 0065 { 0066 return static_cast<KGantt::ItemType>( itemData( currentIndex() ).toInt() ); 0067 } 0068 0069 void ItemTypeComboBox::setItemType( KGantt::ItemType typ ) 0070 { 0071 setCurrentIndex( typ-1 ); 0072 } 0073 0074 class MyItemDelegate : public KGantt::ItemDelegate { 0075 public: 0076 explicit MyItemDelegate( QObject* parent = nullptr ); 0077 0078 /*reimp*/ QWidget* createEditor( QWidget* parent, 0079 const QStyleOptionViewItem& option, 0080 const QModelIndex& idx ) const override; 0081 /*reimp*/ void setEditorData( QWidget* editor, const QModelIndex& index ) const override; 0082 /*reimp*/ void setModelData( QWidget* editor, QAbstractItemModel* model, 0083 const QModelIndex & index ) const override; 0084 protected: 0085 /*reimp*/void drawDisplay( QPainter* painter, const QStyleOptionViewItem & option, 0086 const QRect& rect, const QString& text ) const override; 0087 }; 0088 0089 MyItemDelegate::MyItemDelegate( QObject* parent ) 0090 : KGantt::ItemDelegate( parent ) 0091 { 0092 } 0093 0094 QWidget* MyItemDelegate::createEditor( QWidget* parent, 0095 const QStyleOptionViewItem& option, 0096 const QModelIndex& idx ) const 0097 { 0098 qDebug() << "MyItemDelegate::createEditor("<<parent<<idx<<")"; 0099 if ( idx.isValid() && idx.column() == 1 ) 0100 return new ItemTypeComboBox(parent); 0101 return ItemDelegate::createEditor( parent, option, idx ); 0102 } 0103 0104 void MyItemDelegate::setEditorData ( QWidget* editor, const QModelIndex& index ) const 0105 { 0106 ItemTypeComboBox* c; 0107 if ( (c = qobject_cast<ItemTypeComboBox*>(editor)) && index.isValid() ) { 0108 c->setItemType(static_cast<KGantt::ItemType>(index.data(Qt::EditRole).toInt())); 0109 } else { 0110 ItemDelegate::setEditorData(editor,index); 0111 } 0112 } 0113 0114 void MyItemDelegate::setModelData ( QWidget* editor, QAbstractItemModel* model, 0115 const QModelIndex & index ) const 0116 { 0117 ItemTypeComboBox* c; 0118 if ( (c = qobject_cast<ItemTypeComboBox*>(editor)) && index.isValid() ) { 0119 model->setData(index,c->itemType()); 0120 } else { 0121 ItemDelegate::setModelData(editor,model,index); 0122 } 0123 } 0124 0125 void MyItemDelegate::drawDisplay( QPainter* painter, const QStyleOptionViewItem& option, 0126 const QRect& rect, const QString& text ) const 0127 { 0128 //qDebug() << "MyItemDelegate::drawDisplay(" <<painter<<rect<<text<<")"; 0129 KGantt::ItemType typ = static_cast<KGantt::ItemType>(text.toInt()); 0130 QString str; 0131 switch (typ) { 0132 case KGantt::TypeTask: str = tr("Task"); break; 0133 case KGantt::TypeEvent: str = tr("Event"); break; 0134 case KGantt::TypeSummary: str = tr("Summary"); break; 0135 default: str = tr("None"); break; 0136 } 0137 ItemDelegate::drawDisplay(painter,option,rect,str); 0138 } 0139 0140 /////////////////////////////////////////////////////////////////////////////// 0141 // Provide custom background and foreground 0142 /////////////////////////////////////////////////////////////////////////////// 0143 0144 class DateTimeGrid : public KGantt::DateTimeGrid 0145 { 0146 public: 0147 DateTimeGrid(QObject* parent = nullptr) { 0148 setParent(parent); 0149 setFreeDays( QSet<Qt::DayOfWeek>() ); 0150 setFreeDaysBrush( QBrush( Qt::NoBrush ) ); 0151 } 0152 ~DateTimeGrid() override { } 0153 0154 //virtual void paintUserDefinedHeader(QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect, qreal offset, const KGantt::DateTimeScaleFormatter* formatter, QWidget* widget = 0); 0155 void drawBackground(QPainter* painter, const QRectF& rect) override; 0156 void drawForeground(QPainter* painter, const QRectF& rect) override; 0157 }; 0158 0159 void DateTimeGrid::drawBackground(QPainter* painter, const QRectF& rect) 0160 { 0161 QLinearGradient grad; 0162 grad.setCoordinateMode( QGradient::ObjectBoundingMode ); 0163 grad.setStart( 0.5, 0.5 ); 0164 grad.setFinalStop( 0.5, 0.0 ); 0165 grad.setSpread( QGradient::ReflectSpread ); 0166 // grad.setCenter( 0.5, 0.5 ); 0167 // grad.setFocalPoint( 0.5, 0.5 ); 0168 // grad.setRadius( 0.5 ); 0169 QColor currentColor = Qt::blue; 0170 for ( qreal i = 0; i <= 1.0; i += 0.1 ) 0171 { 0172 currentColor = currentColor.lighter( 100 + 20 * i ); 0173 grad.setColorAt( i, currentColor ); 0174 } 0175 QBrush brush( grad); 0176 //brush.setColor(Qt::lightGray); 0177 0178 QRectF r = computeRect(QDateTime::currentDateTime(), 0179 QDateTime::currentDateTime().addDays(2), 0180 rect); 0181 painter->fillRect(r, brush); 0182 KGantt::DateTimeGrid::drawBackground(painter, rect); 0183 } 0184 0185 void DateTimeGrid::drawForeground(QPainter* painter, const QRectF& rect) 0186 { 0187 painter->save(); 0188 0189 QRectF r = computeRect(QDateTime::currentDateTime(), 0190 QDateTime::currentDateTime().addDays(2), 0191 rect); 0192 0193 static QString text("Holiday"); 0194 QFont font = painter->font(); 0195 font.setPixelSize(r.width()/5); 0196 0197 QFontMetrics fm(font); 0198 int width = fm.boundingRect(text).width(); 0199 int height = fm.boundingRect(text).height(); 0200 0201 painter->translate(r.center()); 0202 painter->translate(-width/2, height/2); 0203 painter->setFont(font); 0204 painter->drawText(0, 0, text); 0205 0206 painter->restore(); 0207 KGantt::DateTimeGrid::drawForeground(painter, rect); 0208 } 0209 /* 0210 void DateTimeGrid::paintUserDefinedHeader( QPainter* painter, const QRectF& headerRect, const QRectF& exposedRect, qreal offset, const KGantt::DateTimeScaleFormatter* formatter, QWidget* widget) 0211 { 0212 const QStyle* const style = widget ? widget->style() : QApplication::style(); 0213 0214 QDateTime dt = formatter->currentRangeBegin( mapToDateTime( offset + exposedRect.left() ) ).toUTC(); 0215 qreal x = mapFromDateTime( dt ); 0216 0217 while ( x < exposedRect.right() + offset ) { 0218 const QDateTime next = formatter->nextRangeBegin( dt ); 0219 const qreal nextx = mapFromDateTime( next ); 0220 0221 QStyleOptionHeader opt; 0222 if ( widget ) opt.init( widget ); 0223 opt.rect = QRectF( x - offset+1, headerRect.top(), qMax( 1., nextx-x-1 ), headerRect.height() ).toAlignedRect(); 0224 //opt.state = QStyle::State_Raised | QStyle::State_Enabled; 0225 opt.textAlignment = formatter->alignment(); 0226 opt.text = formatter->text( dt ); 0227 0228 // use white text on black background 0229 opt.palette.setColor(QPalette::Window, QColor("black")); 0230 opt.palette.setColor(QPalette::ButtonText, QColor("white")); 0231 0232 style->drawControl( QStyle::CE_Header, &opt, painter, widget ); 0233 0234 dt = next; 0235 x = nextx; 0236 } 0237 } 0238 */ 0239 MainWindow::MainWindow( QWidget* parent ) 0240 : QMainWindow( parent ), 0241 m_model( new ProjectModel( this ) ), 0242 m_view( new KGantt::View ) 0243 { 0244 m_view->setModel( m_model ); 0245 m_view->setSelectionModel( new QItemSelectionModel(m_model)); 0246 0247 // slotToolsNewItem(); 0248 m_view->leftView()->setItemDelegateForColumn( 1, new MyItemDelegate( this ) ); 0249 m_view->leftView()->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); 0250 m_view->graphicsView()->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); 0251 0252 DateTimeGrid *grid = new DateTimeGrid(this); 0253 grid->timeLine()->setPen(QPen(Qt::red)); 0254 grid->timeLine()->setOptions(KGantt::DateTimeTimeLine::UseCustomPen); 0255 grid->timeLine()->setInterval(5000); 0256 m_view->setGrid(grid); 0257 0258 //QItemEditorCreatorBase *creator = new QItemEditorCreator<ItemTypeComboBox>("itemType"); 0259 //QItemEditorFactory* factory = new QItemEditorFactory; 0260 //factory->registerEditor( QVariant( KGantt::TypeTask ).type(), creator ); 0261 //m_view->itemDelegate()->setItemEditorFactory( factory ); 0262 0263 setCentralWidget( m_view ); 0264 0265 QMenuBar* mb = menuBar(); 0266 0267 QMenu* fileMenu = new QMenu( tr( "&File" ) ); 0268 0269 #ifndef QT_NO_PRINTER 0270 fileMenu->addAction( tr( "&Save as PDF..." ), this, SLOT(slotFileSavePdf()) ); 0271 fileMenu->addAction( tr( "&Print..." ), this, SLOT(slotFilePrint()) ); 0272 #endif 0273 0274 fileMenu->addSeparator(); 0275 fileMenu->addAction( tr( "&Quit" ), this, SLOT(slotFileQuit()) ); 0276 0277 mb->addMenu( fileMenu ); 0278 0279 QMenu* toolsMenu = new QMenu( tr( "&Tools" ) ); 0280 0281 toolsMenu->addAction( tr( "&New Item" ), this, SLOT(slotToolsNewItem()) ); 0282 toolsMenu->addAction( tr( "&Add Item" ), this, SLOT(slotToolsAppendItem()) ); 0283 toolsMenu->addAction( tr( "&Remove Item" ), this, SLOT(slotToolsRemoveItem()) ); 0284 toolsMenu->addSeparator(); 0285 QMenu *alignMenu = toolsMenu->addMenu( tr( "Ali&gn" ) ); 0286 alignMenu->addAction( tr( "&Left" ), this, SLOT(slotAlignLeft()) ); 0287 alignMenu->addAction( tr( "&Center" ), this, SLOT(slotAlignCenter()) ); 0288 alignMenu->addAction( tr( "&Right" ), this, SLOT(slotAlignRight()) ); 0289 alignMenu->addAction( tr( "&Hidden" ), this, SLOT(slotAlignHidden()) ); 0290 toolsMenu->addSeparator(); 0291 toolsMenu->addAction( tr( "&Collapse All" ), this, SLOT(slotCollapseAll()) ); 0292 toolsMenu->addAction( tr( "&Expand All" ), this, SLOT(slotExpandAll()) ); 0293 0294 mb->addMenu( toolsMenu ); 0295 0296 /* 0297 slotToolsNewItem(); 0298 slotToolsNewItem(); 0299 slotToolsNewItem(); 0300 for (int i = 0; i < 3; ++i) { 0301 m_model->setData(m_model->index(i,2,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(i)), KGantt::StartTimeRole); 0302 m_model->setData(m_model->index(i,3,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(i+1)), KGantt::EndTimeRole); 0303 } 0304 m_view->setConstraintModel(new KGantt::ConstraintModel(m_view)); 0305 m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(0,0,QModelIndex()),m_model->index(1,0,QModelIndex()))); 0306 m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(1,0,QModelIndex()),m_model->index(2,0,QModelIndex()))); 0307 */ 0308 } 0309 0310 SavePdfDialog::SavePdfDialog(QWidget *parent) 0311 : QDialog(parent) 0312 { 0313 setModal(true); 0314 setWindowTitle(tr("Save as PDF")); 0315 QVBoxLayout *l = new QVBoxLayout(this); 0316 setLayout(l); 0317 0318 QHBoxLayout *fileLayout = new QHBoxLayout(this); 0319 l->addLayout(fileLayout); 0320 QLabel *fileLabel = new QLabel(tr("File:"), this); 0321 fileLayout->addWidget(fileLabel); 0322 m_fileEdit = new QLineEdit(this); 0323 fileLabel->setBuddy(m_fileEdit); 0324 m_fileEdit->setText(QFileInfo(QDir::homePath(), "gantt.pdf").absoluteFilePath()); 0325 fileLayout->addWidget(m_fileEdit); 0326 QPushButton *m_fileButton = new QPushButton("...", this); 0327 connect(m_fileButton, SIGNAL(clicked()), this, SLOT(fileButtonClicked())); 0328 fileLayout->addWidget(m_fileButton); 0329 0330 m_rowLabels = new QCheckBox(tr("Row Header"), this); 0331 m_rowLabels->setChecked(true); 0332 l->addWidget(m_rowLabels); 0333 0334 m_columnLabels = new QCheckBox(tr("Column Header"), this); 0335 m_columnLabels->setChecked(true); 0336 l->addWidget(m_columnLabels); 0337 0338 QDialogButtonBox *btnBox = new QDialogButtonBox(this); 0339 btnBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); 0340 connect(btnBox, SIGNAL(accepted()), this, SLOT(accept())); 0341 connect(btnBox, SIGNAL(rejected()), this, SLOT(reject())); 0342 l->addWidget(btnBox); 0343 0344 resize(QSize(400, 100).expandedTo(minimumSizeHint())); 0345 } 0346 0347 void SavePdfDialog::fileButtonClicked() 0348 { 0349 const QString file = QFileDialog::getSaveFileName(this, tr("Choose PDF File..."), QString(), tr("PDF files (*.pdf)")); 0350 if (!file.isEmpty()) 0351 m_fileEdit->setText(file); 0352 } 0353 0354 void MainWindow::slotFileSavePdf() 0355 { 0356 #ifndef QT_NO_PRINTER 0357 SavePdfDialog dialog(this); 0358 if (dialog.exec() != QDialog::Accepted) 0359 return; 0360 0361 const QString file = dialog.m_fileEdit->text(); 0362 if (file.isEmpty()) 0363 return; 0364 0365 const bool drawRowLabels = dialog.m_rowLabels->isChecked(); 0366 const bool drawColumnLabels = dialog.m_columnLabels->isChecked(); 0367 0368 QPrinter printer(QPrinter::HighResolution); 0369 printer.setPageOrientation(QPageLayout::Landscape); 0370 printer.setColorMode(QPrinter::Color); 0371 printer.setPageMargins(QMarginsF(0.2, 0.2, 0.2, 0.2), QPageLayout::Point); 0372 printer.setOutputFormat(QPrinter::PdfFormat); 0373 printer.setOutputFileName(file); 0374 m_view->print(&printer, drawRowLabels, drawColumnLabels); 0375 #endif 0376 } 0377 0378 void MainWindow::slotFilePrint() 0379 { 0380 #ifndef QT_NO_PRINTER 0381 QPrinter printer(QPrinter::HighResolution); 0382 printer.setPageOrientation(QPageLayout::Landscape); 0383 printer.setColorMode(QPrinter::Color); 0384 QPrintDialog dialog(&printer, this); 0385 if (dialog.exec() != QDialog::Accepted) 0386 return; 0387 m_view->print(&printer); 0388 #endif 0389 } 0390 0391 void MainWindow::slotFileQuit() 0392 { 0393 // TODO 0394 QApplication::instance()->quit(); 0395 } 0396 0397 void MainWindow::slotToolsNewItem() 0398 { 0399 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0400 if ( idx.isValid() ) { 0401 qDebug() << "MainWindow::slotToolsNewItem" << idx; 0402 m_model->insertRows( 0, 1, m_model->index( idx.row(),0,idx.parent() ) ); 0403 } else { 0404 m_model->insertRows( 0, 1, m_view->rootIndex() ); 0405 } 0406 } 0407 0408 void MainWindow::slotToolsAppendItem() 0409 { 0410 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0411 if ( idx.isValid() ) { 0412 qDebug() << "MainWindow::slotToolsAppendItem" << idx; 0413 m_model->insertRows( m_model->rowCount( idx ), 1, m_model->index( idx.row(),0,idx.parent() ) ); 0414 } else { 0415 m_model->insertRows( m_model->rowCount( m_view->rootIndex() ), 1, m_view->rootIndex() ); 0416 } 0417 } 0418 0419 void MainWindow::slotToolsRemoveItem() 0420 { 0421 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0422 if ( idx.isValid() ) { 0423 qDebug() << "MainWindow::slotToolsRemoveItem" << idx; 0424 m_model->removeRows( idx.row(), 1, idx.parent() ); 0425 } 0426 } 0427 0428 void MainWindow::slotCollapseAll() 0429 { 0430 // don't use the treeview's collapseAll/expandAll methods but use the one provided by the 0431 // view cause that one will take care to update everyt6hing as needed. 0432 //QTreeView* view = qobject_cast<QTreeView*>( m_view->leftView() ); 0433 //view->collapseAll(); 0434 0435 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0436 if ( idx.isValid() ) 0437 m_view->collapseAll(); 0438 } 0439 0440 void MainWindow::slotExpandAll() 0441 { 0442 // don't use the treeview's collapseAll/expandAll methods but use the one provided by the 0443 // view cause that one will take care to update everyt6hing as needed. 0444 //QTreeView* view = qobject_cast<QTreeView*>( m_view->leftView() ); 0445 //view->expandAll(); 0446 0447 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0448 if ( idx.isValid() ) 0449 m_view->expandAll(); 0450 } 0451 0452 void MainWindow::slotAlignLeft() 0453 { 0454 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0455 if ( idx.isValid() ) { 0456 m_model->setData( idx, KGantt::StyleOptionGanttItem::Left, KGantt::TextPositionRole ); 0457 } 0458 } 0459 0460 void MainWindow::slotAlignCenter() 0461 { 0462 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0463 if ( idx.isValid() ) { 0464 m_model->setData( idx, KGantt::StyleOptionGanttItem::Center, KGantt::TextPositionRole ); 0465 } 0466 } 0467 0468 void MainWindow::slotAlignRight() 0469 { 0470 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0471 if ( idx.isValid() ) { 0472 m_model->setData( idx, KGantt::StyleOptionGanttItem::Right, KGantt::TextPositionRole ); 0473 } 0474 } 0475 0476 void MainWindow::slotAlignHidden() 0477 { 0478 QModelIndex idx = m_view->selectionModel()->currentIndex(); 0479 if ( idx.isValid() ) { 0480 m_model->setData( idx, KGantt::StyleOptionGanttItem::Hidden, KGantt::TextPositionRole ); 0481 } 0482 } 0483 0484 #include "mainwindow.moc"