File indexing completed on 2024-05-26 04:24:16

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 
0011 #include "ui_mainwindow.h"
0012 #include "entrydelegate.h"
0013 #include "entrydialog.h"
0014 
0015 #include <KGanttConstraintModel>
0016 #include <KGanttDateTimeGrid>
0017 #include <KGanttGraphicsView>
0018 #include <KGanttLegend>
0019 #include <QAbstractItemView>
0020 #include <QDebug>
0021 #include <QHeaderView>
0022 #include <QStandardItemModel>
0023 #include <QStandardItem>
0024 #include <QTreeView>
0025 #include <QLabel>
0026 #include <QPointer>
0027 
0028 MainWindow::MainWindow( QWidget* parent, Qt::WindowFlags flags )
0029     : QMainWindow( parent, flags ),
0030       dayWidth( 70 ),
0031       ui( new Ui::MainWindow )
0032 {
0033     ui->setupUi( this );
0034 
0035     initModel();
0036     initActions();
0037     initItemDelegate();
0038     initGrid();
0039 
0040     QTreeView* leftView = qobject_cast<QTreeView*>( ui->ganttView->leftView() );
0041     Q_ASSERT( leftView );
0042     leftView->setColumnHidden( 1, true );
0043     leftView->setColumnHidden( 2, true );
0044     leftView->setColumnHidden( 3, true );
0045     leftView->setColumnHidden( 4, true );
0046     leftView->setColumnHidden( 5, true );
0047     leftView->header()->setStretchLastSection( true );
0048 
0049     connect( ui->ganttView->leftView(), SIGNAL(customContextMenuRequested(QPoint)),
0050              this, SLOT(showContextMenu(QPoint)) );
0051     connect( ui->ganttView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
0052              this, SLOT(enableActions(QItemSelection)) );
0053 
0054     connect( ui->ganttView->graphicsView(), SIGNAL(clicked(QModelIndex)),
0055              this, SLOT(slotClicked(QModelIndex)) );
0056     connect( ui->ganttView->graphicsView(), SIGNAL(qrealClicked(QModelIndex)),
0057              this, SLOT(slotDoubleClicked(QModelIndex)) );
0058 }
0059 
0060 void MainWindow::initModel()
0061 {
0062     model = new QStandardItemModel( 0, 6, this );
0063     model->setHeaderData( 0, Qt::Horizontal, tr( "Task" ) );
0064     ui->ganttView->setModel( model );
0065 
0066     KGantt::Legend* l = new KGantt::Legend;
0067     l->setWindowTitle( tr( "Legend" ) );
0068     l->show();
0069     l->setModel( model );
0070 
0071     constraintModel = new KGantt::ConstraintModel( this );
0072     ui->ganttView->setConstraintModel( constraintModel );
0073 }
0074 
0075 void MainWindow::initActions()
0076 {
0077     newEntryAction = new QAction( tr( "New entry" ), this );
0078     newEntryAction->setShortcut( QKeySequence::New );
0079     connect( newEntryAction, SIGNAL(triggered()), this, SLOT(addNewEntry()) );
0080 
0081     removeEntryAction = new QAction( tr( "Remove entry" ), this );
0082     removeEntryAction->setShortcut( QKeySequence::Delete );
0083     connect( removeEntryAction, SIGNAL(triggered()), this, SLOT(removeEntry()) );
0084 
0085     demoAction = new QAction( tr( "Demo entry" ), this );
0086     connect( demoAction, SIGNAL(triggered()), this, SLOT(addDemoEntry()) );
0087 
0088     printAction = new QAction( tr( "Print Preview..." ), this );
0089     connect( printAction, SIGNAL(triggered()), this, SLOT(printPreview()) );
0090 
0091     zoomInAction = new QAction( tr( "Zoom In" ), this );
0092     zoomInAction->setShortcut( QKeySequence::ZoomIn );
0093     connect( zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn()) );
0094 
0095     zoomOutAction = new QAction( tr( "Zoom Out" ), this );
0096     zoomOutAction->setShortcut( QKeySequence::ZoomOut );
0097     connect( zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut()) );
0098 
0099     ui->ganttView->leftView()->setContextMenuPolicy( Qt::CustomContextMenu );
0100     ui->ganttView->leftView()->addAction( newEntryAction );
0101     ui->ganttView->leftView()->addAction( removeEntryAction );
0102 
0103     QMenu* entryMenu = menuBar()->addMenu( tr( "Entry" ) );
0104     entryMenu->addAction( newEntryAction );
0105     entryMenu->addAction( removeEntryAction );
0106     entryMenu->addSeparator();
0107     entryMenu->addAction( demoAction );
0108     entryMenu->addSeparator();
0109     entryMenu->addAction( printAction );
0110 
0111     QMenu* zoomMenu = menuBar()->addMenu( tr( "Zoom" ) );
0112     zoomMenu->addAction( zoomInAction );
0113     zoomMenu->addAction( zoomOutAction );
0114 
0115     enableActions( QItemSelection() );
0116 }
0117 
0118 void MainWindow::initItemDelegate()
0119 {
0120     EntryDelegate* delegate = new EntryDelegate( constraintModel, this );
0121     ui->ganttView->leftView()->setItemDelegate( delegate );
0122 }
0123 
0124 void MainWindow::initGrid()
0125 {
0126     grid = new KGantt::DateTimeGrid();
0127     grid->setDayWidth( dayWidth );
0128     ui->ganttView->setGrid( grid );
0129 }
0130 
0131 void MainWindow::showContextMenu( const QPoint& pos )
0132 {
0133     if ( !ui->ganttView->leftView()->indexAt( pos ).isValid() )
0134         ui->ganttView->selectionModel()->clearSelection();
0135 
0136     QMenu menu( ui->ganttView->leftView() );
0137     menu.addAction( newEntryAction );
0138     menu.addAction( removeEntryAction );
0139     menu.exec( ui->ganttView->leftView()->viewport()->mapToGlobal( pos ) );
0140 }
0141 
0142 void MainWindow::enableActions(const QItemSelection & selected)
0143 {
0144     if ( selected.indexes().isEmpty() ) {
0145         newEntryAction->setEnabled( true );
0146         removeEntryAction->setEnabled( false );
0147         return;
0148     }
0149 
0150     QModelIndex selectedIndex = selected.indexes()[0];
0151 
0152     if ( model->data( model->index( selectedIndex.row(), 1 ) ) == KGantt::TypeEvent ||
0153         model->data( model->index( selectedIndex.row(), 1 ) ) == KGantt::TypeTask ) {
0154         newEntryAction->setEnabled( false );
0155         removeEntryAction->setEnabled( true );
0156         return;
0157     }
0158 
0159     newEntryAction->setEnabled( true );
0160     removeEntryAction->setEnabled( true );
0161 }
0162 
0163 void MainWindow::addNewEntry()
0164 {
0165     QPointer<EntryDialog> dialog = new EntryDialog( model );
0166     dialog->setWindowTitle( tr( "New Entry") );
0167     if ( dialog->exec() == QDialog::Rejected || !dialog ) {
0168         delete dialog;
0169         return;
0170     }
0171 
0172     QModelIndexList selectedIndexes = ui->ganttView->selectionModel()->selectedIndexes();
0173     const QModelIndex parent = selectedIndexes.value( 0 );
0174 
0175     if ( !model->insertRow( model->rowCount( parent ), parent ) )
0176         return;
0177 
0178     int row = model->rowCount( parent ) - 1;
0179     if (model->columnCount( parent ) < model->columnCount()) {
0180         model->insertColumns( model->columnCount( parent ), model->columnCount() - model->columnCount( parent ), parent );
0181     }
0182 
0183     model->setData( model->index( row, 0, parent ), dialog->name() );
0184     model->setData( model->index( row, 1, parent ), dialog->type() );
0185     if ( dialog->type() != KGantt::TypeSummary ) {
0186         model->setData( model->index( row, 2, parent ), dialog->startDate(), KGantt::StartTimeRole );
0187         model->setData( model->index( row, 3, parent ), dialog->endDate(), KGantt::EndTimeRole );
0188     }
0189     model->setData( model->index( row, 4, parent ), dialog->completion() );
0190     model->setData( model->index( row, 5, parent ), dialog->legend() );
0191 
0192     addConstraint( dialog->depends(), model->index( row, 0, parent ) );
0193     setReadOnly( model->index( row, 0, parent ), dialog->readOnly() );
0194 
0195     delete dialog;
0196 }
0197 
0198 void MainWindow::setReadOnly(const QModelIndex & index, bool readOnly)
0199 {
0200     int row = index.row();
0201     const QModelIndex parent = index.parent();
0202     QStandardItem* item;
0203 
0204     item = model->itemFromIndex( model->index( row, 0, parent ) );
0205     item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
0206 
0207     item = model->itemFromIndex( model->index( row, 1, parent ) );
0208     item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
0209 
0210     item = model->itemFromIndex( model->index( row, 2, parent ) );
0211     item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
0212 
0213     item = model->itemFromIndex( model->index( row, 3, parent ) );
0214     item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
0215 
0216     item = model->itemFromIndex( model->index( row, 4, parent ) );
0217     item->setFlags( readOnly ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable );
0218 }
0219 
0220 void MainWindow::addConstraint(const QModelIndex & index1, const QModelIndex & index2)
0221 {
0222     if ( !index1.isValid() || !index2.isValid() )
0223         return;
0224 
0225     KGantt::Constraint c( index1, index2 );
0226     ui->ganttView->constraintModel()->addConstraint( c );
0227 }
0228 
0229 void MainWindow::addConstraint( const QStandardItem* item1,  const QStandardItem* item2 )
0230 {
0231     addConstraint( model->indexFromItem( item1 ), model->indexFromItem( item2 ) );
0232 }
0233 
0234 void MainWindow::removeEntry()
0235 {
0236     QModelIndexList selectedIndexes = ui->ganttView->selectionModel()->selectedIndexes();
0237     QModelIndex index = selectedIndexes.value( 0 );
0238 
0239     if ( !index.isValid() )
0240         return;
0241 
0242     model->removeRow( index.row(), index.parent() );
0243 }
0244 
0245 class MyStandardItem : public QStandardItem {
0246 public:
0247     MyStandardItem( const QVariant& v ) : QStandardItem()
0248     {
0249         setData( v, Qt::DisplayRole );
0250     }
0251     MyStandardItem( const QString& v ) : QStandardItem()
0252     {
0253         setData( v, Qt::DisplayRole );
0254     }
0255     MyStandardItem( const QDateTime& dt, int role ) : QStandardItem()
0256     {
0257         setData( QVariant::fromValue( dt ), role );
0258     }
0259 };
0260 
0261 void MainWindow::addDemoEntry()
0262 {
0263     QStandardItem* softwareRelease = new MyStandardItem( tr("Software Release" ) );
0264     QStandardItem* codeFreeze = new MyStandardItem( tr( "Code Freeze" ) );
0265     codeFreeze->setData( KGantt::TextPositionRole, KGantt::StyleOptionGanttItem::Right );
0266     QStandardItem* packaging = new MyStandardItem( tr( "Packaging" ) );
0267     QStandardItem* upload = new MyStandardItem( tr( "Upload" ) );
0268     QStandardItem* testing = new MyStandardItem( tr( "Testing" ) );
0269     QStandardItem* updateDocumentation = new MyStandardItem( tr( "Update Documentation" ) );
0270 
0271     QDateTime now = QDateTime::currentDateTime();
0272 
0273     softwareRelease->appendRow( QList<QStandardItem*>()
0274                                 << codeFreeze << new MyStandardItem( KGantt::TypeEvent )
0275                                 << new MyStandardItem( now, KGantt::StartTimeRole ) );
0276     softwareRelease->appendRow( QList<QStandardItem*>()
0277                                 << packaging << new MyStandardItem( KGantt::TypeTask )
0278                                 << new MyStandardItem( now.addDays( 5 ), KGantt::StartTimeRole )
0279                                 << new MyStandardItem( now.addDays( 10 ), KGantt::EndTimeRole ) );
0280     softwareRelease->appendRow( QList<QStandardItem*>()
0281                                 << upload << new MyStandardItem( KGantt::TypeTask )
0282                                 << new MyStandardItem( now.addDays( 10 ).addSecs( 2*60*60 ), KGantt::StartTimeRole )
0283                                 << new MyStandardItem( now.addDays( 11 ), KGantt::EndTimeRole ) );
0284     softwareRelease->appendRow( QList<QStandardItem*>()
0285                                 << testing << new MyStandardItem( KGantt::TypeTask )
0286                                 << new MyStandardItem( now.addSecs( 3*60*60 ), KGantt::StartTimeRole )
0287                                 << new MyStandardItem( now.addDays( 5 ), KGantt::EndTimeRole ) );
0288     softwareRelease->appendRow( QList<QStandardItem*>()
0289                                 << updateDocumentation << new MyStandardItem( KGantt::TypeTask )
0290                                 << new MyStandardItem( now.addSecs( 3*60*60 ), KGantt::StartTimeRole )
0291                                 << new MyStandardItem( now.addDays( 3 ), KGantt::EndTimeRole ) );
0292 
0293     model->appendRow( QList<QStandardItem*>()
0294                       << softwareRelease << new MyStandardItem( KGantt::TypeSummary ) );
0295 
0296     addConstraint( codeFreeze, packaging );
0297     addConstraint( codeFreeze, testing );
0298     addConstraint( codeFreeze, updateDocumentation );
0299     addConstraint( packaging, upload );
0300     addConstraint( testing, packaging );
0301     addConstraint( updateDocumentation, packaging );
0302 }
0303 
0304 void MainWindow::zoomIn()
0305 {
0306     dayWidth += 10;
0307     if ( dayWidth > 400 )
0308         grid->setScale( KGantt::DateTimeGrid::ScaleHour );
0309 
0310     grid->setDayWidth( dayWidth );
0311 }
0312 
0313 void MainWindow::zoomOut()
0314 {
0315     dayWidth -= 10;
0316     if ( dayWidth < 10 )
0317         dayWidth = 10;
0318 
0319     if ( dayWidth <= 400 )
0320         grid->setScale( KGantt::DateTimeGrid::ScaleDay );
0321 
0322     grid->setDayWidth( dayWidth );
0323 }
0324 
0325 void MainWindow::printPreview()
0326 {
0327     QLabel* preview = new QLabel( this, Qt::Window );
0328     preview->setAttribute( Qt::WA_DeleteOnClose );
0329     preview->setScaledContents( true );
0330     preview->setWindowTitle( tr( "Print Preview" ) );
0331     QPixmap pix( 1000, 300 );
0332     pix.fill( Qt::white );
0333     {
0334         QPainter p( &pix );
0335         p.setRenderHints( QPainter::Antialiasing );
0336         ui->ganttView->print( &p, pix.rect() );
0337     }
0338     preview->setPixmap( pix );
0339     preview->show();
0340 }
0341 
0342 void MainWindow::slotClicked( const QModelIndex& index )
0343 {
0344     statusBar()->showMessage( tr( "(%1,%2,_,%4) clicked" )
0345                           .arg( index.row() )
0346                           .arg( index.column() )
0347                           .arg( ( quint64 )index.model() ) );
0348 }
0349 void MainWindow::slotDoubleClicked( const QModelIndex& index )
0350 {
0351     statusBar()->showMessage( tr( "(%1,%2,_,%4) qreal clicked" )
0352                           .arg( index.row() )
0353                           .arg( index.column() )
0354                           .arg( ( quint64 )index.model() ) );
0355 }