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 }