1 /**
2 * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KGantt library.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "mainwindow.h"
21 #include "../common/projectmodel.h"
22
23 #include <QAction>
24 #include <QApplication>
25 #include <QComboBox>
26 #include <QMenuBar>
27 #include <QMenu>
28 #include <QModelIndex>
29 #include <QItemSelectionModel>
30 #include <QTreeView>
31 #include <QDebug>
32 #include <QBrush>
33 #include <QPainter>
34 #include <QPrinter>
35 #include <QPrintDialog>
36 #include <QPrintPreviewDialog>
37 #include <QFileDialog>
38 #include <QLabel>
39 #include <QGridLayout>
40 #include <QVBoxLayout>
41 #include <QHBoxLayout>
42 #include <QFileInfo>
43 #include <QLineEdit>
44 #include <QCheckBox>
45 #include <QPushButton>
46 #include <QDialogButtonBox>
47
48 #include <KGanttGlobal>
49 #include <KGanttView>
50 #include <KGanttItemDelegate>
51 #include <KGanttDateTimeGrid>
52 #include <KGanttStyleOptionGanttItem>
53 #include <KGanttConstraintModel>
54 #include <KGanttGraphicsView>
55 #include <KGanttDateTimeTimeLine>
56
57 // Define a printer friendly palette
58 #define VeryLightGray "#f8f8f8"
59 #define LightLightGray "#f0f0f0"
60 #define DarkDarkGray "#b3b3b3"
61 #define VeryDarkGray "#838383"
62 class PrintPalette {
63 public:
PrintPalette()64 PrintPalette() {
65 orig = QApplication::palette();
66 QPalette palette = orig;
67 // define a palette that works when printing on white paper
68 palette.setColor(QPalette::Window, Qt::white);
69 palette.setColor(QPalette::WindowText, Qt::black);
70 palette.setColor(QPalette::Base, Qt::white);
71 palette.setColor(QPalette::AlternateBase, VeryLightGray);
72 palette.setColor(QPalette::ToolTipBase, Qt::white);
73 palette.setColor(QPalette::ToolTipText, Qt::black);
74 palette.setColor(QPalette::Text, Qt::black);
75 palette.setColor(QPalette::Button, Qt::lightGray);
76 palette.setColor(QPalette::ButtonText, Qt::black);
77 palette.setColor(QPalette::BrightText, Qt::white);
78 palette.setColor(QPalette::Link, Qt::blue);
79 palette.setColor(QPalette::Highlight, Qt::blue);
80 palette.setColor(QPalette::HighlightedText, Qt::white);
81 palette.setColor(QPalette::Light, QColor(VeryLightGray));
82 palette.setColor(QPalette::Midlight, QColor(LightLightGray));
83 palette.setColor(QPalette::Dark, QColor(DarkDarkGray));
84 palette.setColor(QPalette::Mid, QColor(VeryDarkGray));
85 palette.setColor(QPalette::Shadow, Qt::black);
86 QApplication::setPalette(palette);
87 }
~PrintPalette()88 ~PrintPalette() {
89 QApplication::setPalette(orig);
90 }
91 QPalette orig;
92 };
93
94
95 class ItemTypeComboBox : public QComboBox {
96 Q_OBJECT
97 Q_PROPERTY( KGantt::ItemType itemType READ itemType WRITE setItemType )
98 public:
99 explicit ItemTypeComboBox( QWidget* parent = nullptr );
100
101 KGantt::ItemType itemType() const;
102 public Q_SLOTS:
103 void setItemType( KGantt::ItemType typ );
104 };
105
ItemTypeComboBox(QWidget * parent)106 ItemTypeComboBox::ItemTypeComboBox( QWidget* parent )
107 : QComboBox( parent )
108 {
109 addItem( tr( "Task" ), QVariant( KGantt::TypeTask ) );
110 addItem( tr( "Event" ), QVariant( KGantt::TypeEvent ) );
111 addItem( tr( "Summary" ), QVariant( KGantt::TypeSummary ) );
112 }
113
itemType() const114 KGantt::ItemType ItemTypeComboBox::itemType() const
115 {
116 return static_cast<KGantt::ItemType>( itemData( currentIndex() ).toInt() );
117 }
118
setItemType(KGantt::ItemType typ)119 void ItemTypeComboBox::setItemType( KGantt::ItemType typ )
120 {
121 setCurrentIndex( typ-1 );
122 }
123
124 class MyItemDelegate : public KGantt::ItemDelegate {
125 public:
126 explicit MyItemDelegate( QObject* parent = nullptr );
127
128 /*reimp*/ QWidget* createEditor( QWidget* parent,
129 const QStyleOptionViewItem& option,
130 const QModelIndex& idx ) const override;
131 /*reimp*/ void setEditorData( QWidget* editor, const QModelIndex& index ) const override;
132 /*reimp*/ void setModelData( QWidget* editor, QAbstractItemModel* model,
133 const QModelIndex & index ) const override;
134 };
135
MyItemDelegate(QObject * parent)136 MyItemDelegate::MyItemDelegate( QObject* parent )
137 : KGantt::ItemDelegate( parent )
138 {
139 }
140
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex & idx) const141 QWidget* MyItemDelegate::createEditor( QWidget* parent,
142 const QStyleOptionViewItem& option,
143 const QModelIndex& idx ) const
144 {
145 qDebug() << "MyItemDelegate::createEditor("<<parent<<idx<<")";
146 if ( idx.isValid() && idx.column() == 1 )
147 return new ItemTypeComboBox(parent);
148 return ItemDelegate::createEditor( parent, option, idx );
149 }
150
setEditorData(QWidget * editor,const QModelIndex & index) const151 void MyItemDelegate::setEditorData ( QWidget* editor, const QModelIndex& index ) const
152 {
153 ItemTypeComboBox* c;
154 if ( (c = qobject_cast<ItemTypeComboBox*>(editor)) && index.isValid() ) {
155 c->setItemType(static_cast<KGantt::ItemType>(index.data(Qt::EditRole).toInt()));
156 } else {
157 ItemDelegate::setEditorData(editor,index);
158 }
159 }
160
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const161 void MyItemDelegate::setModelData ( QWidget* editor, QAbstractItemModel* model,
162 const QModelIndex & index ) const
163 {
164 ItemTypeComboBox* c;
165 if ( (c = qobject_cast<ItemTypeComboBox*>(editor)) && index.isValid() ) {
166 model->setData(index,c->itemType());
167 } else {
168 ItemDelegate::setModelData(editor,model,index);
169 }
170 }
171
MainWindow(QWidget * parent)172 MainWindow::MainWindow( QWidget* parent )
173 : QMainWindow( parent ),
174 m_model( new ProjectModel( this ) ),
175 m_view( new KGantt::View )
176 {
177 m_view->setModel( m_model );
178
179 m_view->leftView()->setItemDelegateForColumn( 1, new MyItemDelegate( this ) );
180
181 KGantt::DateTimeGrid *grid = new KGantt::DateTimeGrid();
182 grid->timeLine()->setPen(QPen(Qt::red));
183 grid->timeLine()->setOptions(KGantt::DateTimeTimeLine::UseCustomPen);
184 grid->timeLine()->setInterval(5000);
185 grid->setRowSeparators(true);
186 m_view->setGrid(grid);
187
188
189 setCentralWidget( m_view );
190
191 QMenuBar* mb = menuBar();
192
193 QMenu* fileMenu = new QMenu( tr( "&File" ) );
194
195 #ifndef QT_NO_PRINTER
196 fileMenu->addAction( tr( "&Save as PDF..." ), this, SLOT(slotFileSavePdf()) );
197 fileMenu->addAction( tr( "&Print Preview..." ), this, SLOT(slotFilePrintPreview()) );
198 fileMenu->addAction( tr( "&Print..." ), this, SLOT(slotFilePrint()) );
199 #endif
200
201 fileMenu->addSeparator();
202 fileMenu->addAction( tr( "&Quit" ), this, SLOT(slotFileQuit()) );
203
204 mb->addMenu( fileMenu );
205
206 QMenu* toolsMenu = new QMenu( tr( "&Tools" ) );
207
208 toolsMenu->addAction( tr( "&New Item" ), this, SLOT(slotToolsNewItem()) );
209 toolsMenu->addAction( tr( "&Add Item" ), this, SLOT(slotToolsAppendItem()) );
210 toolsMenu->addSeparator();
211 QMenu *alignMenu = toolsMenu->addMenu( tr( "Ali&gn" ) );
212 alignMenu->addAction( tr( "&Left" ), this, SLOT(slotAlignLeft()) );
213 alignMenu->addAction( tr( "&Center" ), this, SLOT(slotAlignCenter()) );
214 alignMenu->addAction( tr( "&Right" ), this, SLOT(slotAlignRight()) );
215 alignMenu->addAction( tr( "&Hidden" ), this, SLOT(slotAlignHidden()) );
216 toolsMenu->addSeparator();
217 toolsMenu->addAction( tr( "&Collapse All" ), this, SLOT(slotCollapseAll()) );
218 toolsMenu->addAction( tr( "&Expand All" ), this, SLOT(slotExpandAll()) );
219
220 mb->addMenu( toolsMenu );
221
222 // define some items with different properties
223 slotToolsAppendItem();
224 slotToolsAppendItem();
225 slotToolsAppendItem();
226 for (int i = 0; i < 3; ++i) {
227 m_model->setData(m_model->index(i,2,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(i)), KGantt::StartTimeRole);
228 m_model->setData(m_model->index(i,3,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(i+1)), KGantt::EndTimeRole);
229 }
230 slotToolsAppendItem();
231 m_model->setData(m_model->index(3,2,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime()), KGantt::StartTimeRole);
232 m_model->setData(m_model->index(3,3,QModelIndex()), QVariant::fromValue(QDateTime::currentDateTime().addDays(1)), KGantt::EndTimeRole);
233 m_model->setData(m_model->index(3,4,QModelIndex()), QVariant::fromValue(50), KGantt::TaskCompletionRole);
234
235 m_view->setConstraintModel(new KGantt::ConstraintModel(m_view));
236 m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(0,0,QModelIndex()),m_model->index(1,0,QModelIndex())));
237 m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(1,0,QModelIndex()),m_model->index(2,0,QModelIndex())));
238 // invalid contraint
239 m_view->constraintModel()->addConstraint(KGantt::Constraint(m_model->index(2,0,QModelIndex()),m_model->index(3,0,QModelIndex())));
240
241 // no info
242 slotToolsAppendItem();
243 m_model->setData(m_model->index(4,2,QModelIndex()), QVariant::fromValue(QDateTime()), KGantt::StartTimeRole);
244 m_model->setData(m_model->index(4,3,QModelIndex()), QVariant::fromValue(QDateTime()), KGantt::EndTimeRole);
245 }
246
SavePdfDialog(QWidget * parent)247 SavePdfDialog::SavePdfDialog(QWidget *parent)
248 : QDialog(parent)
249 {
250 setModal(true);
251 setWindowTitle(tr("Save as PDF"));
252 QVBoxLayout *l = new QVBoxLayout(this);
253 setLayout(l);
254
255 QHBoxLayout *fileLayout = new QHBoxLayout(this);
256 l->addLayout(fileLayout);
257 QLabel *fileLabel = new QLabel(tr("File:"), this);
258 fileLayout->addWidget(fileLabel);
259 m_fileEdit = new QLineEdit(this);
260 fileLabel->setBuddy(m_fileEdit);
261 m_fileEdit->setText(QFileInfo(QDir::homePath(), "gantt.pdf").absoluteFilePath());
262 fileLayout->addWidget(m_fileEdit);
263 QPushButton *m_fileButton = new QPushButton("...", this);
264 connect(m_fileButton, SIGNAL(clicked()), this, SLOT(fileButtonClicked()));
265 fileLayout->addWidget(m_fileButton);
266
267 m_rowLabels = new QCheckBox(tr("Row Header"), this);
268 m_rowLabels->setChecked(true);
269 l->addWidget(m_rowLabels);
270
271 m_columnLabels = new QCheckBox(tr("Column Header"), this);
272 m_columnLabels->setChecked(true);
273 l->addWidget(m_columnLabels);
274
275 QDialogButtonBox *btnBox = new QDialogButtonBox(this);
276 btnBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
277 connect(btnBox, SIGNAL(accepted()), this, SLOT(accept()));
278 connect(btnBox, SIGNAL(rejected()), this, SLOT(reject()));
279 l->addWidget(btnBox);
280
281 resize(QSize(400, 100).expandedTo(minimumSizeHint()));
282 }
283
fileButtonClicked()284 void SavePdfDialog::fileButtonClicked()
285 {
286 const QString file = QFileDialog::getSaveFileName(this, tr("Choose PDF File..."), QString(), tr("PDF files (*.pdf)"));
287 if (!file.isEmpty())
288 m_fileEdit->setText(file);
289 }
290
slotFileSavePdf()291 void MainWindow::slotFileSavePdf()
292 {
293 #ifndef QT_NO_PRINTER
294 SavePdfDialog dialog(this);
295 if (dialog.exec() != QDialog::Accepted)
296 return;
297
298 const QString file = dialog.m_fileEdit->text();
299 if (file.isEmpty())
300 return;
301
302 const bool drawRowLabels = dialog.m_rowLabels->isChecked();
303 const bool drawColumnLabels = dialog.m_columnLabels->isChecked();
304
305 QPrinter printer(QPrinter::HighResolution);
306 printer.setOrientation(QPrinter::Landscape);
307 printer.setColorMode(QPrinter::Color);
308 printer.setPageMargins(0.2, 0.2, 0.2, 0.2, QPrinter::Point);
309 printer.setOutputFormat(QPrinter::PdfFormat);
310 printer.setOutputFileName(file);
311 PrintPalette p;
312 m_view->print(&printer, drawRowLabels, drawColumnLabels);
313 #endif
314 }
315
slotFilePrint()316 void MainWindow::slotFilePrint()
317 {
318 #ifndef QT_NO_PRINTER
319 QPrinter printer(QPrinter::HighResolution);
320 printer.setOrientation(QPrinter::Landscape);
321 printer.setColorMode(QPrinter::Color);
322 QPrintDialog dialog(&printer, this);
323 if (dialog.exec() != QDialog::Accepted) {
324 return;
325 }
326 PrintPalette p;
327 m_view->print(&printer);
328 #endif
329 }
330
slotFilePrintPreview()331 void MainWindow::slotFilePrintPreview()
332 {
333 QPrinter printer(QPrinter::HighResolution);
334 printer.setOrientation(QPrinter::Landscape);
335 printer.setColorMode(QPrinter::Color);
336 QPrintPreviewDialog preview(&printer);
337 connect(&preview, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPrintPreviewPaintRequest(QPrinter*)));
338 preview.exec();
339 }
340
slotPrintPreviewPaintRequest(QPrinter * printer)341 void MainWindow::slotPrintPreviewPaintRequest(QPrinter *printer)
342 {
343 PrintPalette p;
344 m_view->print(printer);
345 }
346
slotFileQuit()347 void MainWindow::slotFileQuit()
348 {
349 // TODO
350 QApplication::instance()->quit();
351 }
352
slotToolsNewItem()353 void MainWindow::slotToolsNewItem()
354 {
355 QModelIndex idx = m_view->selectionModel()->currentIndex();
356 if ( idx.isValid() ) {
357 qDebug() << "MainWindow::slotToolsNewItem" << idx;
358 m_model->insertRows( 0, 1, m_model->index( idx.row(),0,idx.parent() ) );
359 } else {
360 m_model->insertRows( 0, 1, m_view->rootIndex() );
361 }
362 }
363
slotToolsAppendItem()364 void MainWindow::slotToolsAppendItem()
365 {
366 QModelIndex idx = m_view->selectionModel()->currentIndex();
367 if ( idx.isValid() ) {
368 qDebug() << "MainWindow::slotToolsAppendItem" << idx;
369 m_model->insertRows( m_model->rowCount( idx ), 1, m_model->index( idx.row(),0,idx.parent() ) );
370 } else {
371 m_model->insertRows( m_model->rowCount( m_view->rootIndex() ), 1, m_view->rootIndex() );
372 }
373 }
374
slotCollapseAll()375 void MainWindow::slotCollapseAll()
376 {
377 // don't use the treeview's collapseAll/expandAll methods but use the one provided by the
378 // view cause that one will take care to update everyt6hing as needed.
379 //QTreeView* view = qobject_cast<QTreeView*>( m_view->leftView() );
380 //view->collapseAll();
381
382 QModelIndex idx = m_view->selectionModel()->currentIndex();
383 if ( idx.isValid() )
384 m_view->collapseAll();
385 }
386
slotExpandAll()387 void MainWindow::slotExpandAll()
388 {
389 // don't use the treeview's collapseAll/expandAll methods but use the one provided by the
390 // view cause that one will take care to update everyt6hing as needed.
391 //QTreeView* view = qobject_cast<QTreeView*>( m_view->leftView() );
392 //view->expandAll();
393
394 QModelIndex idx = m_view->selectionModel()->currentIndex();
395 if ( idx.isValid() )
396 m_view->expandAll();
397 }
398
slotAlignLeft()399 void MainWindow::slotAlignLeft()
400 {
401 QModelIndex idx = m_view->selectionModel()->currentIndex();
402 if ( idx.isValid() ) {
403 m_model->setData( idx, KGantt::StyleOptionGanttItem::Left, KGantt::TextPositionRole );
404 }
405 }
406
slotAlignCenter()407 void MainWindow::slotAlignCenter()
408 {
409 QModelIndex idx = m_view->selectionModel()->currentIndex();
410 if ( idx.isValid() ) {
411 m_model->setData( idx, KGantt::StyleOptionGanttItem::Center, KGantt::TextPositionRole );
412 }
413 }
414
slotAlignRight()415 void MainWindow::slotAlignRight()
416 {
417 QModelIndex idx = m_view->selectionModel()->currentIndex();
418 if ( idx.isValid() ) {
419 m_model->setData( idx, KGantt::StyleOptionGanttItem::Right, KGantt::TextPositionRole );
420 }
421 }
422
slotAlignHidden()423 void MainWindow::slotAlignHidden()
424 {
425 QModelIndex idx = m_view->selectionModel()->currentIndex();
426 if ( idx.isValid() ) {
427 m_model->setData( idx, KGantt::StyleOptionGanttItem::Hidden, KGantt::TextPositionRole );
428 }
429 }
430
431 #include "mainwindow.moc"
432