1 /* This file is part of the KDE project
2 * Copyright (C) 2019 Dag Andersen <danders@get2net.dk>
3 * Copyright (C) 2006-2011, 2012 Dag Andersen <danders@get2net.dk>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 // clazy:excludeall=qstring-arg
22 #include "kptscheduleeditor.h"
23
24 #include "kptcommand.h"
25 #include "kptcalendar.h"
26 #include "kptduration.h"
27 #include "kptnode.h"
28 #include "kptproject.h"
29 #include "kpttask.h"
30 #include "kptschedule.h"
31 #include "kptdatetime.h"
32 #include "kptpertresult.h"
33 #include "kptitemviewsettup.h"
34 #include "kptrecalculatedialog.h"
35 #include "Help.h"
36 #include "kptdebug.h"
37
38 #include <KoDocument.h>
39 #include <KoIcon.h>
40
41 #include <QList>
42 #include <QVBoxLayout>
43 #include <QHeaderView>
44 #include <QApplication>
45 #include <QClipboard>
46 #include <QContextMenuEvent>
47 #include <QAction>
48 #include <QMenu>
49
50 #include <KLocalizedString>
51 #include <kactioncollection.h>
52
53 #include <ktoggleaction.h>
54
55
56 namespace KPlato
57 {
58
ScheduleTreeView(QWidget * parent)59 ScheduleTreeView::ScheduleTreeView(QWidget *parent)
60 : TreeViewBase(parent)
61 {
62 header()->setStretchLastSection (false);
63
64 ScheduleItemModel *m = new ScheduleItemModel(this);
65 setModel(m);
66 //setSelectionBehavior(QAbstractItemView::SelectItems);
67 setSelectionMode(QAbstractItemView::SingleSelection);
68 setSelectionBehavior(QAbstractItemView::SelectRows);
69 setTreePosition(-1); // always visual index 0
70
71 createItemDelegates(m);
72 }
73
selectionChanged(const QItemSelection & sel,const QItemSelection & desel)74 void ScheduleTreeView::selectionChanged(const QItemSelection &sel, const QItemSelection &desel)
75 {
76 //debugPlan<<sel.indexes().count();
77 foreach(const QModelIndex &i, selectionModel()->selectedIndexes()) {
78 Q_UNUSED(i);
79 //debugPlan<<i.row()<<","<<i.column();
80 }
81 QTreeView::selectionChanged(sel, desel);
82 emit selectionChanged(selectionModel()->selectedIndexes());
83 }
84
currentChanged(const QModelIndex & current,const QModelIndex & previous)85 void ScheduleTreeView::currentChanged(const QModelIndex & current, const QModelIndex & previous)
86 {
87 //debugPlan<<current.row()<<","<<current.column();
88 QTreeView::currentChanged(current, previous);
89 emit currentChanged(current);
90 // possible bug in qt: in QAbstractItemView::SingleSelection you can select multiple items/rows
91 selectionModel()->select(current, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
92 }
93
manager(const QModelIndex & idx) const94 ScheduleManager *ScheduleTreeView::manager(const QModelIndex &idx) const
95 {
96 return model()->manager(idx);
97 }
98
currentManager() const99 ScheduleManager *ScheduleTreeView::currentManager() const
100 {
101 return model()->manager(currentIndex());
102 }
103
selectedRows() const104 QModelIndexList ScheduleTreeView::selectedRows() const
105 {
106 QModelIndexList lst = selectionModel()->selectedRows();
107 debugPlan<<lst;
108 return lst;
109 }
110
selectedManager() const111 ScheduleManager *ScheduleTreeView::selectedManager() const
112 {
113 ScheduleManager *sm = 0;
114 QModelIndexList lst = selectedRows();
115 if (lst.count() == 1) {
116 sm = model()->manager(lst.first());
117 }
118 return sm;
119 }
120
121 //-----------------------------------
ScheduleEditor(KoPart * part,KoDocument * doc,QWidget * parent)122 ScheduleEditor::ScheduleEditor(KoPart *part, KoDocument *doc, QWidget *parent)
123 : ViewBase(part, doc, parent)
124 {
125 if (doc && doc->isReadWrite()) {
126 setXMLFile("ScheduleEditorUi.rc");
127 } else {
128 setXMLFile("ScheduleEditorUi_readonly.rc");
129 }
130
131 setupGui();
132 slotEnableActions();
133
134 QVBoxLayout * l = new QVBoxLayout(this);
135 l->setMargin(0);
136 m_schedulingRange = new SchedulingRange(doc, this);
137 l->addWidget(m_schedulingRange);
138 m_view = new ScheduleTreeView(this);
139 connect(this, &ViewBase::expandAll, m_view, &TreeViewBase::slotExpand);
140 connect(this, &ViewBase::collapseAll, m_view, &TreeViewBase::slotCollapse);
141
142 l->addWidget(m_view);
143 m_view->setEditTriggers(m_view->editTriggers() | QAbstractItemView::EditKeyPressed);
144
145 QList<int> show;
146 show << ScheduleModel::ScheduleName
147 << ScheduleModel::ScheduleState
148 << ScheduleModel::ScheduleDirection
149 << ScheduleModel::ScheduleOverbooking
150 << ScheduleModel::ScheduleDistribution
151 << ScheduleModel::SchedulePlannedStart
152 << ScheduleModel::SchedulePlannedFinish
153 << ScheduleModel::ScheduleScheduler
154 << ScheduleModel::ScheduleGranularity
155 << ScheduleModel::ScheduleMode
156 ;
157
158 QList<int> lst;
159 for (int c = 0; c < model()->columnCount(); ++c) {
160 if (! show.contains(c)) {
161 lst << c;
162 }
163 }
164 m_view->setColumnsHidden(lst);
165 m_view->setDefaultColumns(show);
166
167
168 connect(model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand);
169
170 connect(m_view, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)));
171
172 connect(m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)));
173
174 connect(model(), &QAbstractItemModel::dataChanged, this, &ScheduleEditor::updateActionsEnabled);
175
176 connect(m_view, &TreeViewBase::contextMenuRequested, this, &ScheduleEditor::slotContextMenuRequested);
177
178 connect(m_view, &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested);
179
180 Help::add(this,
181 xi18nc("@info:whatsthis",
182 "<title>Schedule Editor</title>"
183 "<para>"
184 "The Schedule Editor is used to create, edit, calculate and delete schedules."
185 "</para><para>"
186 "If <emphasis>Mode</emphasis> is set to <emphasis>Auto</emphasis>, the schedule is calculated automatically."
187 " <note>Only one schedule can be in <emphasis>Auto Mode</emphasis> simultaneously"
188 " and it must be a top level schedule without sub-schedules.</note>"
189 "</para><para>"
190 "A schedule can have sub-schedules. A sub-schedule can use the projects progress data"
191 " in order to reschedule only tasks that are not yet finished."
192 " Rescheduling will then use e.g. actual start and remaining effort for the tasks."
193 "<nl/><link url='%1'>More...</link>"
194 "</para>", Help::page("Schedules_Editor")));
195 }
196
draw(Project & project)197 void ScheduleEditor::draw(Project &project)
198 {
199 m_view->setProject(&project);
200 m_schedulingRange->setProject(&project);
201 }
202
draw()203 void ScheduleEditor::draw()
204 {
205 }
206
setGuiActive(bool activate)207 void ScheduleEditor::setGuiActive(bool activate)
208 {
209 //debugPlan<<activate;
210 ViewBase::setGuiActive(activate);
211 if (activate && !m_view->currentIndex().isValid()) {
212 m_view->selectionModel()->setCurrentIndex(m_view->model()->index(0, 0), QItemSelectionModel::NoUpdate);
213 }
214 }
215
slotContextMenuRequested(const QModelIndex & index,const QPoint & pos)216 void ScheduleEditor::slotContextMenuRequested(const QModelIndex &index, const QPoint& pos)
217 {
218 debugPlan<<index.row()<<","<<index.column()<<":"<<pos;
219 QString name;
220 m_view->setContextMenuIndex(index);
221 if (name.isEmpty()) {
222 slotHeaderContextMenuRequested(pos);
223 m_view->setContextMenuIndex(QModelIndex());
224 return;
225 }
226 debugPlan<<name;
227 emit requestPopupMenu(name, pos);
228 m_view->setContextMenuIndex(QModelIndex());
229 }
230
slotCurrentChanged(const QModelIndex &)231 void ScheduleEditor::slotCurrentChanged(const QModelIndex &)
232 {
233 //debugPlan<<curr.row()<<","<<curr.column();
234 }
235
slotSelectionChanged(const QModelIndexList &)236 void ScheduleEditor::slotSelectionChanged(const QModelIndexList &/*list*/)
237 {
238 //debugPlan<<list.count();
239 // Note: Don't use list as it includes all columns in a row
240 QModelIndexList lst = m_view->selectedRows(); // gets column 0 in each row (should be 1 or 0 rows)
241 if (lst.count() == 1) {
242 ScheduleManager *sm = m_view->model()->manager(lst.first());
243 emit scheduleSelectionChanged(sm);
244 } else {
245 emit scheduleSelectionChanged(0);
246 }
247 slotEnableActions();
248
249 }
250
updateActionsEnabled(const QModelIndex & index)251 void ScheduleEditor::updateActionsEnabled(const QModelIndex &index)
252 {
253 debugPlan<<index;
254 slotEnableActions();
255 }
256
slotEnableActions()257 void ScheduleEditor::slotEnableActions()
258 {
259 if (! isReadWrite()) {
260 actionAddSchedule->setEnabled(false);
261 actionAddSubSchedule->setEnabled(false);
262 actionDeleteSelection->setEnabled(false);
263 actionCalculateSchedule->setEnabled(false);
264 actionBaselineSchedule->setEnabled(false);
265 actionMoveLeft->setEnabled(false);
266 return;
267 }
268 QModelIndexList lst = m_view->selectedRows();
269 if (lst.isEmpty()) {
270 actionAddSchedule->setEnabled(true);
271 actionAddSubSchedule->setEnabled(false);
272 actionDeleteSelection->setEnabled(false);
273 actionCalculateSchedule->setEnabled(false);
274 actionBaselineSchedule->setEnabled(false);
275 actionMoveLeft->setEnabled(false);
276 return;
277 }
278 if (lst.count() > 1) {
279 actionAddSchedule->setEnabled(false);
280 actionAddSubSchedule->setEnabled(false);
281 actionDeleteSelection->setEnabled(false);
282 actionCalculateSchedule->setEnabled(false);
283 actionBaselineSchedule->setEnabled(false);
284 actionMoveLeft->setEnabled(false);
285 return;
286 }
287 // one and only one manager selected
288 ScheduleManager *sm = m_view->manager(lst.first());
289 Q_ASSERT(sm);
290 actionAddSchedule->setEnabled(true);
291 actionAddSubSchedule->setEnabled(sm->isScheduled());
292 actionDeleteSelection->setEnabled(! (sm->isBaselined() || sm->isChildBaselined()));
293 actionCalculateSchedule->setEnabled(! sm->scheduling() && sm->childCount() == 0 && ! (sm->isBaselined() || sm->isChildBaselined()));
294
295 const char *const actionBaselineScheduleIconName =
296 sm->isBaselined() ? koIconNameCStr("view-time-schedule-baselined-remove") : koIconNameCStr("view-time-schedule-baselined-add");
297 actionBaselineSchedule->setIcon(QIcon::fromTheme(QLatin1String(actionBaselineScheduleIconName)));
298
299 // enable if scheduled and no one else is baselined
300 bool en = sm->isScheduled() && (sm->isBaselined() || ! m_view->project()->isBaselined());
301 actionBaselineSchedule->setEnabled(en);
302
303 actionMoveLeft->setEnabled(sm->parentManager());
304 }
305
setupGui()306 void ScheduleEditor::setupGui()
307 {
308 actionAddSchedule = new QAction(koIcon("view-time-schedule-insert"), i18n("Add Schedule"), this);
309 actionCollection()->setDefaultShortcut(actionAddSchedule, Qt::CTRL + Qt::Key_I);
310 actionCollection()->addAction("add_schedule", actionAddSchedule);
311 connect(actionAddSchedule, &QAction::triggered, this, &ScheduleEditor::slotAddSchedule);
312
313 actionAddSubSchedule = new QAction(koIcon("view-time-schedule-child-insert"), i18n("Add Sub-schedule"), this);
314 actionCollection()->setDefaultShortcut(actionAddSubSchedule, Qt::CTRL + Qt::SHIFT + Qt::Key_I);
315 actionCollection()->addAction("add_subschedule", actionAddSubSchedule);
316 connect(actionAddSubSchedule, &QAction::triggered, this, &ScheduleEditor::slotAddSubSchedule);
317
318 actionDeleteSelection = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this);
319 actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete);
320 actionCollection()->addAction("delete_selection", actionDeleteSelection);
321 connect(actionDeleteSelection, &QAction::triggered, this, &ScheduleEditor::slotDeleteSelection);
322
323 actionCalculateSchedule = new QAction(koIcon("view-time-schedule-calculus"), i18n("Calculate"), this);
324 // actionCollection()->setDefaultShortcut(actionCalculateSchedule, Qt::CTRL + Qt::Key_C);
325 actionCollection()->addAction("calculate_schedule", actionCalculateSchedule);
326 connect(actionCalculateSchedule, &QAction::triggered, this, &ScheduleEditor::slotCalculateSchedule);
327
328 actionBaselineSchedule = new QAction(koIcon("view-time-schedule-baselined-add"), i18n("Baseline"), this);
329 // actionCollection()->setDefaultShortcut(actionBaselineSchedule, Qt::CTRL + Qt::Key_B);
330 actionCollection()->addAction("schedule_baseline", actionBaselineSchedule);
331 connect(actionBaselineSchedule, &QAction::triggered, this, &ScheduleEditor::slotBaselineSchedule);
332
333 actionMoveLeft = new QAction(koIcon("go-first"), xi18nc("@action", "Detach"), this);
334 actionCollection()->addAction("schedule_move_left", actionMoveLeft);
335 connect(actionMoveLeft, &QAction::triggered, this, &ScheduleEditor::slotMoveLeft);
336
337 // Add the context menu actions for the view options
338 createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig);
339 }
340
updateReadWrite(bool readwrite)341 void ScheduleEditor::updateReadWrite(bool readwrite)
342 {
343 debugPlan<<readwrite;
344 ViewBase::updateReadWrite(readwrite);
345 m_view->setReadWrite(readwrite);
346 m_schedulingRange->setReadWrite(readwrite);
347 slotEnableActions();
348 }
349
slotOptions()350 void ScheduleEditor::slotOptions()
351 {
352 debugPlan;
353 ItemViewSettupDialog *dlg = new ItemViewSettupDialog(this, m_view, true, this);
354 connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int)));
355 dlg->open();
356 }
357
slotCalculateSchedule()358 void ScheduleEditor::slotCalculateSchedule()
359 {
360 //debugPlan;
361 ScheduleManager *sm = m_view->selectedManager();
362 if (sm == 0) {
363 return;
364 }
365 if (sm->parentManager() || (sm->isScheduled() && project()->isStarted())) {
366 RecalculateDialog dlg;
367 if (dlg.exec() == QDialog::Rejected) {
368 return;
369 }
370 sm->setRecalculate(true);
371 sm->setRecalculateFrom(DateTime(dlg.dateTime()));
372 }
373 emit calculateSchedule(m_view->project(), sm);
374 }
375
slotAddSchedule()376 void ScheduleEditor::slotAddSchedule()
377 {
378 //debugPlan;
379 int idx = -1;
380 ScheduleManager *sm = m_view->selectedManager();
381 if (sm) {
382 idx = sm->parentManager() ? sm->parentManager()->indexOf(sm) : m_view->project()->indexOf(sm);
383 if (idx >= 0) {
384 ++idx;
385 }
386 }
387 if (sm && sm->parentManager()) {
388 sm = sm->parentManager();
389 ScheduleManager *m = m_view->project()->createScheduleManager(sm->name() + QString(".%1").arg(sm->children().count() + 1));
390 part()->addCommand(new AddScheduleManagerCmd(sm, m, idx, kundo2_i18n("Create sub-schedule")));
391 QModelIndex idx = model()->index(m);
392 if (idx.isValid()) {
393 m_view->setFocus();
394 m_view->scrollTo(idx);
395 m_view->selectionModel()->select(idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
396 m_view->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::NoUpdate);
397 }
398 } else {
399 Project *p = m_view->project();
400 ScheduleManager *m = p->createScheduleManager();
401 AddScheduleManagerCmd *cmd = new AddScheduleManagerCmd(*p, m, idx, kundo2_i18n("Add schedule %1", m->name()));
402 part() ->addCommand(cmd);
403 QModelIndex idx = model()->index(m);
404 if (idx.isValid()) {
405 m_view->setFocus();
406 m_view->scrollTo(idx);
407 m_view->selectionModel()->select(idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
408 m_view->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::NoUpdate);
409 }
410 }
411 }
412
slotAddSubSchedule()413 void ScheduleEditor::slotAddSubSchedule()
414 {
415 //debugPlan;
416 ScheduleManager *sm = m_view->selectedManager();
417 if (sm) {
418 int row = sm->parentManager() ? sm->parentManager()->indexOf(sm) : m_view->project()->indexOf(sm);
419 if (row >= 0) {
420 ++row;
421 }
422 ScheduleManager *m = m_view->project()->createScheduleManager(sm->name() + QString(".%1").arg(sm->children().count() + 1));
423 part()->addCommand(new AddScheduleManagerCmd(sm, m, row, kundo2_i18n("Create sub-schedule")));
424 m_view->expand(model()->index(sm));
425 QModelIndex idx = model()->index(m);
426 if (idx.isValid()) {
427 m_view->selectionModel()->select(idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
428 m_view->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::NoUpdate);
429 }
430 } else {
431 slotAddSchedule();
432 }
433 }
434
slotBaselineSchedule()435 void ScheduleEditor::slotBaselineSchedule()
436 {
437 //debugPlan;
438 ScheduleManager *sm = m_view->selectedManager();
439 if (sm) {
440 emit baselineSchedule(m_view->project(), sm);
441 }
442 }
443
slotDeleteSelection()444 void ScheduleEditor::slotDeleteSelection()
445 {
446 //debugPlan;
447 ScheduleManager *sm = m_view->selectedManager();
448 if (sm) {
449 emit deleteScheduleManager(m_view->project(), sm);
450 }
451 }
452
slotMoveLeft()453 void ScheduleEditor::slotMoveLeft()
454 {
455 ScheduleManager *sm = m_view->selectedManager();
456 if (sm) {
457 int index = -1;
458 for (ScheduleManager *m = sm; m != 0; m = m->parentManager()) {
459 if (m->parentManager() == 0) {
460 index = m->project().indexOf(m) + 1;
461 }
462 }
463 debugPlan<<sm->name()<<index;
464 emit moveScheduleManager(sm, 0, index);
465 }
466 }
467
loadContext(const KoXmlElement & context)468 bool ScheduleEditor::loadContext(const KoXmlElement &context)
469 {
470 debugPlan;
471 return m_view->loadContext(model()->columnMap(), context);
472 }
473
saveContext(QDomElement & context) const474 void ScheduleEditor::saveContext(QDomElement &context) const
475 {
476 m_view->saveContext(model()->columnMap(), context);
477 }
478
createPrintJob()479 KoPrintJob *ScheduleEditor::createPrintJob()
480 {
481 return m_view->createPrintJob(this);
482 }
483
484 //-----------------------------------------
ScheduleLogTreeView(QWidget * parent)485 ScheduleLogTreeView::ScheduleLogTreeView(QWidget *parent)
486 : QTreeView(parent)
487 {
488 header()->setStretchLastSection (true);
489 header()->setContextMenuPolicy(Qt::CustomContextMenu);
490
491 m_model = new QSortFilterProxyModel(this);
492 m_model->setFilterRole(Qt::UserRole+1);
493 m_model->setFilterKeyColumn (2); // severity
494 m_model->setFilterWildcard("[^0]"); // Filter out Debug
495
496 m_model->setSourceModel(new ScheduleLogItemModel(this));
497 setModel(m_model);
498
499 setRootIsDecorated(false);
500 setSelectionMode(QAbstractItemView::ExtendedSelection);
501 setSelectionBehavior(QAbstractItemView::SelectRows);
502 setAlternatingRowColors(true);
503
504 connect(header(), &QWidget::customContextMenuRequested, this, &ScheduleLogTreeView::headerContextMenuRequested);
505
506 actionShowDebug = new KToggleAction(xi18nc("@action", "Show Debug Information"), this);
507 connect(actionShowDebug, &QAction::toggled, this, &ScheduleLogTreeView::slotShowDebug);
508 }
509
setFilterWildcard(const QString & filter)510 void ScheduleLogTreeView::setFilterWildcard(const QString &filter)
511 {
512 m_model->setFilterWildcard(filter);
513 }
514
filterRegExp() const515 QRegExp ScheduleLogTreeView::filterRegExp() const
516 {
517 return m_model->filterRegExp();
518 }
519
slotShowDebug(bool on)520 void ScheduleLogTreeView::slotShowDebug(bool on)
521 {
522 on ? setFilterWildcard(QString()) : setFilterWildcard("[^0]");
523 }
524
contextMenuEvent(QContextMenuEvent * e)525 void ScheduleLogTreeView::contextMenuEvent (QContextMenuEvent *e)
526 {
527 debugPlan<<indexAt(e->pos())<<" at"<<e->pos();
528 emit contextMenuRequested(indexAt(e->pos()), e->globalPos());
529 }
530
headerContextMenuRequested(const QPoint & pos)531 void ScheduleLogTreeView::headerContextMenuRequested(const QPoint &pos)
532 {
533 //debugPlan<<header()->logicalIndexAt(pos)<<" at"<<pos;
534 QMenu *m = new QMenu(this);
535 m->addAction(actionShowDebug);
536 m->exec(mapToGlobal(pos));
537 delete m;
538 }
539
selectionChanged(const QItemSelection & sel,const QItemSelection & desel)540 void ScheduleLogTreeView::selectionChanged(const QItemSelection &sel, const QItemSelection &desel)
541 {
542 //debugPlan<<sel.indexes().count();
543 foreach(const QModelIndex &i, selectionModel()->selectedIndexes()) {
544 Q_UNUSED(i);
545 //debugPlan<<i.row()<<","<<i.column();
546 }
547 QTreeView::selectionChanged(sel, desel);
548 emit selectionChanged(selectionModel()->selectedIndexes());
549 }
550
currentChanged(const QModelIndex & current,const QModelIndex & previous)551 void ScheduleLogTreeView::currentChanged(const QModelIndex & current, const QModelIndex & previous)
552 {
553 //debugPlan<<current.row()<<","<<current.column();
554 QTreeView::currentChanged(current, previous);
555 emit currentChanged(current);
556 // selectionModel()->select(current, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
557 }
558
slotEditCopy()559 void ScheduleLogTreeView::slotEditCopy()
560 {
561 QStringList lst;
562 // int row = 0;
563 QString s;
564 QHeaderView *h = header();
565 foreach(const QModelIndex &i, selectionModel()->selectedRows()) {
566 QString s;
567 for (int section = 0; section < h->count(); ++section) {
568 QModelIndex idx = model()->index(i.row(), h->logicalIndex(section));
569 if (! idx.isValid() || isColumnHidden(idx.column())) {
570 continue;
571 }
572 if (! s.isEmpty()) {
573 s += ' ';
574 }
575 s = QString("%1%2").arg(s).arg(idx.data().toString(), -10);
576 }
577 if (! s.isEmpty()) {
578 lst << s;
579 }
580 }
581 if (! lst.isEmpty()) {
582 QApplication::clipboard()->setText(lst.join("\n"));
583 }
584 }
585
586 //-----------------------------------
ScheduleLogView(KoPart * part,KoDocument * doc,QWidget * parent)587 ScheduleLogView::ScheduleLogView(KoPart *part, KoDocument *doc, QWidget *parent)
588 : ViewBase(part, doc, parent)
589 {
590 setupGui();
591 slotEnableActions(0);
592
593 QVBoxLayout * l = new QVBoxLayout(this);
594 m_view = new ScheduleLogTreeView(this);
595 l->addWidget(m_view);
596 // m_view->setEditTriggers(m_view->editTriggers() | QAbstractItemView::EditKeyPressed);
597
598
599 connect(m_view, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)));
600
601 connect(m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)));
602
603 connect(baseModel(), &QAbstractItemModel::dataChanged, this, &ScheduleLogView::updateActionsEnabled);
604
605 connect(m_view, &ScheduleLogTreeView::contextMenuRequested, this, &ScheduleLogView::slotContextMenuRequested);
606
607 }
608
setProject(Project * project)609 void ScheduleLogView::setProject(Project *project)
610 {
611 m_view->setProject(project);
612 }
613
draw(Project & project)614 void ScheduleLogView::draw(Project &project)
615 {
616 setProject(&project);
617 }
618
setGuiActive(bool activate)619 void ScheduleLogView::setGuiActive(bool activate)
620 {
621 //debugPlan<<activate;
622 ViewBase::setGuiActive(activate);
623 /* if (activate && !m_view->currentIndex().isValid()) {
624 m_view->selectionModel()->setCurrentIndex(m_view->model()->index(0, 0), QItemSelectionModel::NoUpdate);
625 }*/
626 }
627
slotEdit()628 void ScheduleLogView::slotEdit()
629 {
630 QString id = sender()->property("p_identity").toString();
631 if (id.isEmpty()) {
632 emit editNode(project());
633 return;
634 }
635 Node *n = project()->findNode(id);
636 if (n) {
637 emit editNode(n);
638 return;
639 }
640 Resource *r = project()->findResource(id);
641 if (r) {
642 emit editResource(r);
643 return;
644 }
645 warnPlan<<"No object";
646 }
647
slotContextMenuRequested(const QModelIndex & index,const QPoint & pos)648 void ScheduleLogView::slotContextMenuRequested(const QModelIndex &index, const QPoint& pos)
649 {
650 if (! isReadWrite() || ! index.isValid()) {
651 return;
652 }
653 QMenu *m = new QMenu(this);
654 QString id = index.data(ScheduleLogItemModel::IdentityRole).toString();
655 if (id.isEmpty()) {
656 return;
657 }
658 QAction *a = new QAction(koIcon("document-edit"), i18n("Edit..."), m);
659 a->setProperty("p_identity", id);
660 m->addAction(a);
661 connect(a, &QAction::triggered, this, &ScheduleLogView::slotEdit);
662 m->addSeparator();
663 m->exec(pos);
664 delete m;
665 }
666
slotScheduleSelectionChanged(ScheduleManager * sm)667 void ScheduleLogView::slotScheduleSelectionChanged(ScheduleManager *sm)
668 {
669 baseModel()->setManager(sm);
670 }
671
slotCurrentChanged(const QModelIndex &)672 void ScheduleLogView::slotCurrentChanged(const QModelIndex &)
673 {
674 //debugPlan<<curr.row()<<","<<curr.column();
675 }
676
slotSelectionChanged(const QModelIndexList & list)677 void ScheduleLogView::slotSelectionChanged(const QModelIndexList &list)
678 {
679 debugPlan<<list.count();
680 }
681
updateActionsEnabled(const QModelIndex & index)682 void ScheduleLogView::updateActionsEnabled(const QModelIndex &index)
683 {
684 debugPlan<<index;
685 }
686
slotEnableActions(const ScheduleManager *)687 void ScheduleLogView::slotEnableActions(const ScheduleManager *)
688 {
689 }
690
setupGui()691 void ScheduleLogView::setupGui()
692 {
693 // Add the context menu actions for the view options
694 createOptionActions(0);
695 }
696
updateReadWrite(bool readwrite)697 void ScheduleLogView::updateReadWrite(bool readwrite)
698 {
699 debugPlan<<readwrite;
700 ViewBase::updateReadWrite(readwrite);
701 // m_view->setReadWrite(readwrite);
702 //slotEnableActions(m_view->currentManager());
703 }
704
slotOptions()705 void ScheduleLogView::slotOptions()
706 {
707 debugPlan;
708 }
709
slotEditCopy()710 void ScheduleLogView::slotEditCopy()
711 {
712 m_view->slotEditCopy();
713 }
714
loadContext(const KoXmlElement &)715 bool ScheduleLogView::loadContext(const KoXmlElement &/*context */)
716 {
717 debugPlan;
718 return true;//m_view->loadContext(model()->columnMap(), context);
719 }
720
saveContext(QDomElement &) const721 void ScheduleLogView::saveContext(QDomElement &/*context */) const
722 {
723 //m_view->saveContext(model()->columnMap(), context);
724 }
725
726
727 //---------------------------
728
ScheduleHandlerView(KoPart * part,KoDocument * doc,QWidget * parent)729 ScheduleHandlerView::ScheduleHandlerView(KoPart *part, KoDocument *doc, QWidget *parent)
730 : SplitterView(part, doc, parent)
731 {
732 debugPlan<<"---------------- Create ScheduleHandlerView ------------------";
733 m_scheduleEditor = new ScheduleEditor(part, doc, this);
734 m_scheduleEditor->setObjectName("ScheduleEditor");
735 addView(m_scheduleEditor);
736 insertChildClient(m_scheduleEditor);
737
738 QTabWidget *tab = addTabWidget();
739
740 PertResult *p = new PertResult(part, doc, tab);
741 p->setObjectName("PertResult");
742 addView(p, tab, i18n("Result"));
743 connect(m_scheduleEditor, &ScheduleEditor::scheduleSelectionChanged, p, &PertResult::slotScheduleSelectionChanged);
744
745 PertCpmView *c = new PertCpmView(part, doc, tab);
746 c->setObjectName("PertCpmView");
747 addView(c, tab, i18n("Critical Path"));
748 connect(m_scheduleEditor, &ScheduleEditor::scheduleSelectionChanged, c, &PertCpmView::slotScheduleSelectionChanged);
749
750 ScheduleLogView *v = new ScheduleLogView(part, doc, tab);
751 v->setObjectName("ScheduleLogView");
752 addView(v, tab, i18n("Scheduling Log"));
753 connect(m_scheduleEditor, SIGNAL(scheduleSelectionChanged(KPlato::ScheduleManager*)), v, SLOT(slotScheduleSelectionChanged(KPlato::ScheduleManager*)));
754 connect(v, &ScheduleLogView::editNode, this, &ScheduleHandlerView::editNode);
755 connect(v, &ScheduleLogView::editResource, this, &ScheduleHandlerView::editResource);
756 }
757
currentTabChanged(int)758 void ScheduleHandlerView::currentTabChanged(int)
759 {
760 }
761
hitView(const QPoint &)762 ViewBase *ScheduleHandlerView::hitView(const QPoint &/*glpos */)
763 {
764 //debugPlan<<this<<glpos<<"->"<<mapFromGlobal(glpos)<<"in"<<frameGeometry();
765 return this;
766 }
767
768
setGuiActive(bool active)769 void ScheduleHandlerView::setGuiActive(bool active) // virtual slot
770 {
771 foreach (ViewBase *v, findChildren<ViewBase*>()) {
772 v->setGuiActive(active);
773 }
774 m_activeview = active ? this : 0;
775 emit guiActivated(this, active);
776 }
777
slotGuiActivated(ViewBase *,bool)778 void ScheduleHandlerView::slotGuiActivated(ViewBase *, bool)
779 {
780 }
781
SchedulingRange(KoDocument * doc,QWidget * parent)782 SchedulingRange::SchedulingRange(KoDocument *doc, QWidget *parent)
783 : QWidget(parent)
784 , m_doc(doc)
785 , m_project(0)
786 {
787 setupUi(this);
788
789 connect(targetStartTime, &QAbstractSpinBox::editingFinished, this, &SchedulingRange::slotStartChanged);
790 connect(targetEndTime, &QAbstractSpinBox::editingFinished, this, &SchedulingRange::slotEndChanged);
791 }
792
setReadWrite(bool rw)793 void SchedulingRange::setReadWrite(bool rw)
794 {
795 targetStartTime->setEnabled(rw);
796 targetEndTime->setEnabled(rw);
797 }
798
setProject(Project * project)799 void SchedulingRange::setProject(Project *project)
800 {
801 if (m_project) {
802 disconnect(m_project, &Project::nodeChanged, this, &SchedulingRange::slotProjectChanged);
803 }
804 m_project = project;
805 if (m_project) {
806 connect(m_project, &Project::nodeChanged, this, &SchedulingRange::slotProjectChanged);
807 slotProjectChanged(m_project);
808 }
809 }
810
slotProjectChanged(Node * node)811 void SchedulingRange::slotProjectChanged(Node *node)
812 {
813 if (node != m_project) {
814 return;
815 }
816 if (targetStartTime->dateTime() != m_project->constraintStartTime()) {
817 targetStartTime->setDateTime(m_project->constraintStartTime());
818 }
819 if (targetEndTime->dateTime() != m_project->constraintEndTime()) {
820 targetEndTime->setDateTime(m_project->constraintEndTime());
821 }
822 }
823
slotStartChanged()824 void SchedulingRange::slotStartChanged()
825 {
826 if (!m_project || !m_doc) {
827 return;
828 }
829 if (targetStartTime->dateTime() == m_project->constraintStartTime()) {
830 return;
831 }
832 ProjectModifyStartTimeCmd *cmd = new ProjectModifyStartTimeCmd(*m_project, targetStartTime->dateTime(), kundo2_i18n("Modify project target start time"));
833 m_doc->addCommand(cmd);
834 }
835
slotEndChanged()836 void SchedulingRange::slotEndChanged()
837 {
838 if (!m_project || !m_doc) {
839 return;
840 }
841 if (targetEndTime->dateTime() == m_project->constraintEndTime()) {
842 return;
843 }
844 ProjectModifyEndTimeCmd *cmd = new ProjectModifyEndTimeCmd(*m_project, targetEndTime->dateTime(), kundo2_i18n("Modify project target end time"));
845 m_doc->addCommand(cmd);
846 }
847
848 } // namespace KPlato
849