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 <QPrintPreviewDialog>
0026 #include <QFileDialog>
0027 #include <QLabel>
0028 #include <QGridLayout>
0029 #include <QVBoxLayout>
0030 #include <QHBoxLayout>
0031 #include <QFileInfo>
0032 #include <QLineEdit>
0033 #include <QCheckBox>
0034 #include <QPushButton>
0035 #include <QDialogButtonBox>
0036 
0037 #include <KGanttGlobal>
0038 #include <KGanttView>
0039 #include <KGanttItemDelegate>
0040 #include <KGanttDateTimeGrid>
0041 #include <KGanttStyleOptionGanttItem>
0042 #include <KGanttConstraintModel>
0043 #include <KGanttGraphicsView>
0044 #include <KGanttDateTimeTimeLine>
0045 
0046 // Define a printer friendly palette
0047 #define VeryLightGray   "#f8f8f8"
0048 #define LightLightGray  "#f0f0f0"
0049 #define DarkDarkGray    "#b3b3b3"
0050 #define VeryDarkGray    "#838383"
0051 class PrintPalette {
0052 public:
0053     PrintPalette() {
0054         orig = QApplication::palette();
0055         QPalette palette = orig;
0056         // define a palette that works when printing on white paper
0057         palette.setColor(QPalette::Window, Qt::white);
0058         palette.setColor(QPalette::WindowText, Qt::black);
0059         palette.setColor(QPalette::Base, Qt::white);
0060         palette.setColor(QPalette::AlternateBase, VeryLightGray);
0061         palette.setColor(QPalette::ToolTipBase, Qt::white);
0062         palette.setColor(QPalette::ToolTipText, Qt::black);
0063         palette.setColor(QPalette::Text, Qt::black);
0064         palette.setColor(QPalette::Button, Qt::lightGray);
0065         palette.setColor(QPalette::ButtonText, Qt::black);
0066         palette.setColor(QPalette::BrightText, Qt::white);
0067         palette.setColor(QPalette::Link, Qt::blue);
0068         palette.setColor(QPalette::Highlight, Qt::blue);
0069         palette.setColor(QPalette::HighlightedText, Qt::white);
0070         palette.setColor(QPalette::Light, QColor(VeryLightGray));
0071         palette.setColor(QPalette::Midlight, QColor(LightLightGray));
0072         palette.setColor(QPalette::Dark, QColor(DarkDarkGray));
0073         palette.setColor(QPalette::Mid, QColor(VeryDarkGray));
0074         palette.setColor(QPalette::Shadow, Qt::black);
0075         QApplication::setPalette(palette);
0076     }
0077     ~PrintPalette() {
0078         QApplication::setPalette(orig);
0079     }
0080     QPalette orig;
0081 };
0082 
0083 
0084 class ItemTypeComboBox : public QComboBox {
0085     Q_OBJECT
0086     Q_PROPERTY( KGantt::ItemType itemType READ itemType WRITE setItemType )
0087 public:
0088     explicit ItemTypeComboBox( QWidget* parent = nullptr );
0089 
0090     KGantt::ItemType itemType() const;
0091 public Q_SLOTS:
0092     void setItemType( KGantt::ItemType typ );
0093 };
0094 
0095 ItemTypeComboBox::ItemTypeComboBox( QWidget* parent )
0096     : QComboBox( parent )
0097 {
0098     addItem( tr( "Task" ), QVariant( KGantt::TypeTask ) );
0099     addItem( tr( "Event" ), QVariant( KGantt::TypeEvent ) );
0100     addItem( tr( "Summary" ), QVariant( KGantt::TypeSummary ) );
0101 }
0102 
0103 KGantt::ItemType ItemTypeComboBox::itemType() const
0104 {
0105     return static_cast<KGantt::ItemType>( itemData( currentIndex() ).toInt() );
0106 }
0107 
0108 void ItemTypeComboBox::setItemType( KGantt::ItemType typ )
0109 {
0110     setCurrentIndex( typ-1 );
0111 }
0112 
0113 class MyItemDelegate : public KGantt::ItemDelegate {
0114 public:
0115     explicit MyItemDelegate( QObject* parent = nullptr );
0116 
0117     /*reimp*/ QWidget* createEditor( QWidget* parent,
0118                                      const QStyleOptionViewItem& option,
0119                                      const QModelIndex& idx ) const override;
0120     /*reimp*/ void setEditorData( QWidget* editor, const QModelIndex& index ) const override;
0121     /*reimp*/ void setModelData( QWidget* editor, QAbstractItemModel* model,
0122                                   const QModelIndex & index ) const override;
0123 };
0124 
0125 MyItemDelegate::MyItemDelegate( QObject* parent )
0126     : KGantt::ItemDelegate( parent )
0127 {
0128 }
0129 
0130 QWidget* MyItemDelegate::createEditor( QWidget* parent,
0131                                        const QStyleOptionViewItem& option,
0132                                        const QModelIndex& idx ) const
0133 {
0134     qDebug() << "MyItemDelegate::createEditor("<<parent<<idx<<")";
0135     if ( idx.isValid() && idx.column() == 1 )
0136       return new ItemTypeComboBox(parent);
0137     return ItemDelegate::createEditor( parent, option, idx );
0138 }
0139 
0140 void MyItemDelegate::setEditorData ( QWidget* editor, const QModelIndex& index ) const
0141 {
0142   ItemTypeComboBox* c;
0143   if ( (c = qobject_cast<ItemTypeComboBox*>(editor)) && index.isValid() ) {
0144       c->setItemType(static_cast<KGantt::ItemType>(index.data(Qt::EditRole).toInt()));
0145   } else {
0146       ItemDelegate::setEditorData(editor,index);
0147   }
0148 }
0149 
0150 void MyItemDelegate::setModelData ( QWidget* editor, QAbstractItemModel* model,
0151                                   const QModelIndex & index ) const
0152 {
0153   ItemTypeComboBox* c;
0154   if ( (c = qobject_cast<ItemTypeComboBox*>(editor)) && index.isValid() ) {
0155       model->setData(index,c->itemType());
0156   } else {
0157       ItemDelegate::setModelData(editor,model,index);
0158   }
0159 }
0160 
0161 MainWindow::MainWindow( QWidget* parent )
0162     : QMainWindow( parent ),
0163       m_model( new ProjectModel( this ) ),
0164       m_view( new KGantt::View )
0165 {
0166     m_view->setModel( m_model );
0167 
0168     m_view->leftView()->setItemDelegateForColumn( 1, new MyItemDelegate( this ) );
0169 
0170     KGantt::DateTimeGrid *grid = new KGantt::DateTimeGrid();
0171     grid->timeLine()->setPen(QPen(Qt::red));
0172     grid->timeLine()->setOptions(KGantt::DateTimeTimeLine::UseCustomPen);
0173     grid->timeLine()->setInterval(5000);
0174     grid->setRowSeparators(true);
0175     m_view->setGrid(grid);
0176 
0177 
0178     setCentralWidget( m_view );
0179 
0180     QMenuBar* mb = menuBar();
0181 
0182     QMenu* fileMenu = new QMenu( tr( "&File" ) );
0183 
0184 #ifndef QT_NO_PRINTER
0185     fileMenu->addAction( tr( "&Save as PDF..." ), this, SLOT(slotFileSavePdf()) );
0186     fileMenu->addAction( tr( "&Print Preview..." ), this, SLOT(slotFilePrintPreview()) );
0187     fileMenu->addAction( tr( "&Print..." ), this, SLOT(slotFilePrint()) );
0188 #endif
0189 
0190     fileMenu->addSeparator();
0191     fileMenu->addAction( tr( "&Quit" ), this, SLOT(slotFileQuit()) );
0192 
0193     mb->addMenu( fileMenu );
0194 
0195     QMenu* toolsMenu = new QMenu( tr( "&Tools" ) );
0196 
0197     toolsMenu->addAction( tr( "&New Item" ), this, SLOT(slotToolsNewItem()) );
0198     toolsMenu->addAction( tr( "&Add Item" ), this, SLOT(slotToolsAppendItem()) );
0199     toolsMenu->addSeparator();
0200     QMenu *alignMenu = toolsMenu->addMenu( tr( "Ali&gn" ) );
0201     alignMenu->addAction( tr( "&Left" ), this, SLOT(slotAlignLeft()) );
0202     alignMenu->addAction( tr( "&Center" ), this, SLOT(slotAlignCenter()) );
0203     alignMenu->addAction( tr( "&Right" ), this, SLOT(slotAlignRight()) );
0204     alignMenu->addAction( tr( "&Hidden" ), this, SLOT(slotAlignHidden()) );
0205     toolsMenu->addSeparator();
0206     toolsMenu->addAction( tr( "&Collapse All" ), this, SLOT(slotCollapseAll()) );
0207     toolsMenu->addAction( tr( "&Expand All" ), this, SLOT(slotExpandAll()) );
0208 
0209     mb->addMenu( toolsMenu );
0210 
0211     // define some items with different properties
0212     slotToolsAppendItem();
0213     slotToolsAppendItem();
0214     slotToolsAppendItem();
0215     for (int i = 0; i < 3; ++i) {
0216         m_model->setData(m_model->index(i,2,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(i)), KGantt::StartTimeRole);
0217         m_model->setData(m_model->index(i,3,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(i+1)), KGantt::EndTimeRole);
0218     }
0219     slotToolsAppendItem();
0220     m_model->setData(m_model->index(3,2,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime()), KGantt::StartTimeRole);
0221     m_model->setData(m_model->index(3,3,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(1)), KGantt::EndTimeRole);
0222     m_model->setData(m_model->index(3,4,QModelIndex()), QVariant::fromValue(50), KGantt::TaskCompletionRole);
0223 
0224     m_view->setConstraintModel(new KGantt::ConstraintModel(m_view));
0225     m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(0,0,QModelIndex()),m_model->index(1,0,QModelIndex())));
0226     m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(1,0,QModelIndex()),m_model->index(2,0,QModelIndex())));
0227     // invalid constraint
0228     m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(2,0,QModelIndex()),m_model->index(3,0,QModelIndex())));
0229 
0230     // no info
0231     slotToolsAppendItem();
0232     m_model->setData(m_model->index(4,2,QModelIndex()), QVariant::fromValue(QDateTime()), KGantt::StartTimeRole);
0233     m_model->setData(m_model->index(4,3,QModelIndex()), QVariant::fromValue(QDateTime()), KGantt::EndTimeRole);
0234 }
0235 
0236 SavePdfDialog::SavePdfDialog(QWidget *parent)
0237     : QDialog(parent)
0238 {
0239     setModal(true);
0240     setWindowTitle(tr("Save as PDF"));
0241     QVBoxLayout *l = new QVBoxLayout(this);
0242     setLayout(l);
0243 
0244     QHBoxLayout *fileLayout = new QHBoxLayout(this);
0245     l->addLayout(fileLayout);
0246     QLabel *fileLabel = new QLabel(tr("File:"), this);
0247     fileLayout->addWidget(fileLabel);
0248     m_fileEdit = new QLineEdit(this);
0249     fileLabel->setBuddy(m_fileEdit);
0250     m_fileEdit->setText(QFileInfo(QDir::homePath(), "gantt.pdf").absoluteFilePath());
0251     fileLayout->addWidget(m_fileEdit);
0252     QPushButton *m_fileButton = new QPushButton("...", this);
0253     connect(m_fileButton, SIGNAL(clicked()), this, SLOT(fileButtonClicked()));
0254     fileLayout->addWidget(m_fileButton);
0255 
0256     m_rowLabels = new QCheckBox(tr("Row Header"), this);
0257     m_rowLabels->setChecked(true);
0258     l->addWidget(m_rowLabels);
0259 
0260     m_columnLabels = new QCheckBox(tr("Column Header"), this);
0261     m_columnLabels->setChecked(true);
0262     l->addWidget(m_columnLabels);
0263 
0264     QDialogButtonBox *btnBox = new QDialogButtonBox(this);
0265     btnBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
0266     connect(btnBox, SIGNAL(accepted()), this, SLOT(accept()));
0267     connect(btnBox, SIGNAL(rejected()), this, SLOT(reject()));
0268     l->addWidget(btnBox);
0269 
0270     resize(QSize(400, 100).expandedTo(minimumSizeHint()));
0271 }
0272 
0273 void SavePdfDialog::fileButtonClicked()
0274 {
0275     const QString file = QFileDialog::getSaveFileName(this, tr("Choose PDF File..."), QString(), tr("PDF files (*.pdf)"));
0276     if (!file.isEmpty())
0277         m_fileEdit->setText(file);
0278 }
0279 
0280 void MainWindow::slotFileSavePdf()
0281 {
0282 #ifndef QT_NO_PRINTER
0283     SavePdfDialog dialog(this);
0284     if (dialog.exec() != QDialog::Accepted)
0285         return;
0286 
0287     const QString file = dialog.m_fileEdit->text();
0288     if (file.isEmpty())
0289         return;
0290 
0291     const bool drawRowLabels = dialog.m_rowLabels->isChecked();
0292     const bool drawColumnLabels = dialog.m_columnLabels->isChecked();
0293 
0294     QPrinter printer(QPrinter::HighResolution);
0295     printer.setPageOrientation(QPageLayout::Landscape);
0296     printer.setColorMode(QPrinter::Color);
0297     printer.setPageMargins(QMarginsF(0.2, 0.2, 0.2, 0.2), QPageLayout::Point);
0298     printer.setOutputFormat(QPrinter::PdfFormat);
0299     printer.setOutputFileName(file);
0300     PrintPalette p;
0301     m_view->print(&printer, drawRowLabels, drawColumnLabels);
0302 #endif
0303 }
0304 
0305 void MainWindow::slotFilePrint()
0306 {
0307 #ifndef QT_NO_PRINTER
0308     QPrinter printer(QPrinter::HighResolution);
0309     printer.setPageOrientation(QPageLayout::Landscape);
0310     printer.setColorMode(QPrinter::Color);
0311     QPrintDialog dialog(&printer, this);
0312     if (dialog.exec() != QDialog::Accepted) {
0313         return;
0314     }
0315     PrintPalette p;
0316     m_view->print(&printer);
0317 #endif
0318 }
0319 
0320 void MainWindow::slotFilePrintPreview()
0321 {
0322     QPrinter printer(QPrinter::HighResolution);
0323     printer.setPageOrientation(QPageLayout::Landscape);
0324     printer.setColorMode(QPrinter::Color);
0325     QPrintPreviewDialog preview(&printer);
0326     connect(&preview, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPrintPreviewPaintRequest(QPrinter*)));
0327     preview.exec();
0328 }
0329 
0330 void MainWindow::slotPrintPreviewPaintRequest(QPrinter *printer)
0331 {
0332     PrintPalette p;
0333     m_view->print(printer);
0334 }
0335 
0336 void MainWindow::slotFileQuit()
0337 {
0338     // TODO
0339     QApplication::instance()->quit();
0340 }
0341 
0342 void MainWindow::slotToolsNewItem()
0343 {
0344     QModelIndex idx = m_view->selectionModel()->currentIndex();
0345     if ( idx.isValid() ) {
0346         qDebug() << "MainWindow::slotToolsNewItem" << idx;
0347         m_model->insertRows( 0, 1, m_model->index( idx.row(),0,idx.parent() ) );
0348     } else {
0349         m_model->insertRows( 0, 1, m_view->rootIndex() );
0350     }
0351 }
0352 
0353 void MainWindow::slotToolsAppendItem()
0354 {
0355     QModelIndex idx = m_view->selectionModel()->currentIndex();
0356     if ( idx.isValid() ) {
0357         qDebug() << "MainWindow::slotToolsAppendItem" << idx;
0358         m_model->insertRows( m_model->rowCount( idx ), 1, m_model->index( idx.row(),0,idx.parent() ) );
0359     } else {
0360         m_model->insertRows( m_model->rowCount( m_view->rootIndex() ), 1, m_view->rootIndex() );
0361     }
0362 }
0363 
0364 void MainWindow::slotCollapseAll()
0365 {
0366     // don't use the treeview's collapseAll/expandAll methods but use the one provided by the
0367     // view cause that one will take care to update everyt6hing as needed.
0368     //QTreeView* view = qobject_cast<QTreeView*>( m_view->leftView() );
0369     //view->collapseAll();
0370 
0371     QModelIndex idx = m_view->selectionModel()->currentIndex();
0372     if ( idx.isValid() )
0373         m_view->collapseAll();
0374 }
0375 
0376 void MainWindow::slotExpandAll()
0377 {
0378     // don't use the treeview's collapseAll/expandAll methods but use the one provided by the
0379     // view cause that one will take care to update everyt6hing as needed.
0380     //QTreeView* view = qobject_cast<QTreeView*>( m_view->leftView() );
0381     //view->expandAll();
0382 
0383     QModelIndex idx = m_view->selectionModel()->currentIndex();
0384     if ( idx.isValid() )
0385         m_view->expandAll();
0386 }
0387 
0388 void MainWindow::slotAlignLeft()
0389 {
0390     QModelIndex idx = m_view->selectionModel()->currentIndex();
0391     if ( idx.isValid() ) {
0392         m_model->setData( idx, KGantt::StyleOptionGanttItem::Left, KGantt::TextPositionRole );
0393     }
0394 }
0395 
0396 void MainWindow::slotAlignCenter()
0397 {
0398     QModelIndex idx = m_view->selectionModel()->currentIndex();
0399     if ( idx.isValid() ) {
0400         m_model->setData( idx, KGantt::StyleOptionGanttItem::Center, KGantt::TextPositionRole );
0401     }
0402 }
0403 
0404 void MainWindow::slotAlignRight()
0405 {
0406     QModelIndex idx = m_view->selectionModel()->currentIndex();
0407     if ( idx.isValid() ) {
0408         m_model->setData( idx, KGantt::StyleOptionGanttItem::Right, KGantt::TextPositionRole );
0409     }
0410 }
0411 
0412 void MainWindow::slotAlignHidden()
0413 {
0414     QModelIndex idx = m_view->selectionModel()->currentIndex();
0415     if ( idx.isValid() ) {
0416         m_model->setData( idx, KGantt::StyleOptionGanttItem::Hidden, KGantt::TextPositionRole );
0417     }
0418 }
0419 
0420 #include "mainwindow.moc"