File indexing completed on 2024-05-12 16:39:27

0001 /* This file is part of the KDE project
0002   Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
0003   Copyright (C) 2002 - 2009, 2011, 2012 Dag Andersen <danders@get2net.dk>
0004   Copyright (C) 2019 Dag Andersen <danders@get2net.dk>
0005   
0006   This library is free software; you can redistribute it and/or
0007   modify it under the terms of the GNU Library General Public
0008   License as published by the Free Software Foundation; either
0009   version 2 of the License, or (at your option) any later version.
0010 
0011   This library is distributed in the hope that it will be useful,
0012   but WITHOUT ANY WARRANTY; without even the implied warranty of
0013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014   Library General Public License for more details.
0015 
0016   You should have received a copy of the GNU Library General Public License
0017   along with this library; see the file COPYING.LIB.  If not, write to
0018   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019 * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 // clazy:excludeall=qstring-arg
0023 #include "view.h"
0024 #include "mainwindow.h"
0025 #include "taskworkpackageview.h"
0026 #include "workpackage.h"
0027 #include "taskcompletiondialog.h"
0028 #include "calligraplanworksettings.h"
0029 #include "kpttaskeditor.h"
0030 #include "kpttaskdescriptiondialog.h"
0031 #include "kptcommonstrings.h"
0032 
0033 #include "KoDocumentInfo.h"
0034 #include <KoMainWindow.h>
0035 
0036 #include <QApplication>
0037 #include <QLabel>
0038 #include <QString>
0039 #include <QSize>
0040 #include <QTabWidget>
0041 #include <QVBoxLayout>
0042 #include <QPrinter>
0043 #include <QPrintDialog>
0044 #include <QDomDocument>
0045 #include <QPointer>
0046 #include <QMenu>
0047 #include <QAction>
0048 
0049 #include <KLocalizedString>
0050 #include <ktoolbar.h>
0051 
0052 #include <kxmlguifactory.h>
0053 #include <ktoolinvocation.h>
0054 #include <kactioncollection.h>
0055 #include <QTemporaryFile>
0056 
0057 #include <kmessagebox.h>
0058 
0059 #include <KoIcon.h>
0060 
0061 #include "part.h"
0062 #include "factory.h"
0063 
0064 #include "kptviewbase.h"
0065 #include "kptdocumentseditor.h"
0066 
0067 #include "kptnode.h"
0068 #include "kptproject.h"
0069 #include "kpttask.h"
0070 #include "kptcommand.h"
0071 #include "kptdocuments.h"
0072 #include "kpttaskprogressdialog.h"
0073 #include "kptcalendar.h"
0074 
0075 #include <assert.h>
0076 
0077 #include "debugarea.h"
0078 
0079 namespace KPlatoWork
0080 {
0081 
0082 View::View(Part *part,  QWidget *parent, KActionCollection *collection)
0083     : QStackedWidget(parent),
0084     m_part(part),
0085     m_scheduleActionGroup(new QActionGroup(this)),
0086     m_manager(0)
0087 {
0088     m_readWrite = part->isReadWrite();
0089     debugPlanWork<<m_readWrite;
0090 
0091     // Add sub views
0092     createViews();
0093 
0094     // The menu items
0095     // ------ Edit
0096     actionRemoveSelectedPackages  = new QAction(koIcon("edit-delete"), i18n("Remove Packages"), this);
0097     collection->addAction("package_remove_selected", actionRemoveSelectedPackages);
0098     connect(actionRemoveSelectedPackages, &QAction::triggered, this, &View::slotRemoveSelectedPackages);
0099 
0100     actionRemoveCurrentPackage  = new QAction(koIcon("edit-delete"), i18n("Remove Package"), this);
0101     collection->addAction("package_remove_current", actionRemoveCurrentPackage);
0102     connect(actionRemoveCurrentPackage, &QAction::triggered, this, &View::slotRemoveCurrentPackage);
0103 
0104     actionViewList  = new QAction(koIcon("view-list-tree"), i18n("List"), this);
0105     actionViewList->setToolTip(i18nc("@info:tooltip", "Select task list"));
0106     collection->addAction("view_list", actionViewList);
0107     connect(actionViewList, &QAction::triggered, this, &View::slotViewList);
0108 
0109     actionViewGantt  = new QAction(koIcon("view-time-schedule"), i18n("Gantt"), this);
0110     actionViewGantt->setToolTip(i18nc("@info:tooltip", "Select timeline"));
0111     collection->addAction("view_gantt", actionViewGantt);
0112     connect(actionViewGantt, &QAction::triggered, this, &View::slotViewGantt);
0113 
0114 //     actionTaskProgress  = new QAction(koIcon("document-edit"), i18n("Progress..."), this);
0115 //     collection->addAction("task_progress", actionTaskProgress);
0116 //     connect(actionTaskProgress, SIGNAL(triggered(bool)), SLOT(slotTaskProgress()));
0117 
0118     //------ Settings
0119     actionConfigure  = new QAction(koIcon("configure"), i18n("Configure PlanWork..."), this);
0120     collection->addAction("configure", actionConfigure);
0121     connect(actionConfigure, &QAction::triggered, this, &View::slotConfigure);
0122 
0123     //------ Popups
0124     actionEditDocument  = new QAction(koIcon("document-edit"), i18n("Edit..."), this);
0125     collection->addAction("edit_document", actionEditDocument);
0126     connect(actionEditDocument, SIGNAL(triggered(bool)), SLOT(slotEditDocument()));
0127 
0128     actionViewDocument  = new QAction(koIcon("document-preview"), i18nc("@verb", "View..."), this);
0129     collection->addAction("view_document", actionViewDocument);
0130     connect(actionViewDocument, &QAction::triggered, this, &View::slotViewDocument);
0131 
0132     // FIXME remove UndoText::removeDocument() when string freeze is lifted
0133     actionRemoveDocument = new QAction(koIcon("list-remove"), UndoText::removeDocument().toString(), this);
0134     collection->addAction("remove_document", actionRemoveDocument);
0135     connect(actionRemoveDocument, &QAction::triggered, this, &View::slotRemoveDocument);
0136 
0137     actionSendPackage  = new QAction(koIcon("mail-send"), i18n("Send Package..."), this);
0138     collection->addAction("edit_sendpackage", actionSendPackage);
0139     connect(actionSendPackage, &QAction::triggered, this, &View::slotSendPackage);
0140 
0141     actionTaskCompletion  = new QAction(koIcon("document-edit"), i18n("Edit Progress..."), this);
0142     collection->addAction("task_progress", actionTaskCompletion);
0143     connect(actionTaskCompletion, &QAction::triggered, this, &View::slotTaskCompletion);
0144 
0145     actionViewDescription  = new QAction(/*koIcon("document_view"),*/ i18n("View Description..."), this);
0146     collection->addAction("task_description", actionViewDescription);
0147     connect(actionViewDescription, &QAction::triggered, this, &View::slotTaskDescription);
0148 
0149 
0150     updateReadWrite(m_readWrite);
0151     //debugPlanWork<<" end";
0152 
0153     loadContext();
0154     slotCurrentChanged(currentIndex());
0155     connect(this, &QStackedWidget::currentChanged, this, &View::slotCurrentChanged);
0156 
0157     slotSelectionChanged();
0158 }
0159 
0160 View::~View()
0161 {
0162     saveContext();
0163 }
0164 
0165 void View::slotCurrentChanged(int index)
0166 {
0167     actionViewList->setEnabled(index != 0);
0168     actionViewGantt->setEnabled(index != 1);
0169     saveContext();
0170 }
0171 
0172 void View::slotViewList()
0173 {
0174     debugPlanWork;
0175     setCurrentIndex(0);
0176 }
0177 
0178 void View::slotViewGantt()
0179 {
0180     debugPlanWork;
0181     setCurrentIndex(1);
0182 }
0183 
0184 void View::createViews()
0185 {
0186     QWidget *v = createTaskWorkPackageView();
0187     addWidget(v);
0188     v = createGanttView();
0189     addWidget(v);
0190 }
0191 
0192 TaskWorkPackageView *View::createTaskWorkPackageView()
0193 {
0194     TaskWorkPackageView *v = new TaskWorkPackageView(part(), this);
0195 
0196     connect(v, &AbstractView::requestPopupMenu, this, &View::slotPopupMenu);
0197 
0198     connect(v, &AbstractView::selectionChanged, this, &View::slotSelectionChanged);
0199     v->updateReadWrite(m_readWrite);
0200     v->loadContext();
0201     return v;
0202 }
0203 
0204 TaskWPGanttView *View::createGanttView()
0205 {
0206     TaskWPGanttView *v = new TaskWPGanttView(part(), this);
0207 
0208     connect(v, &AbstractView::requestPopupMenu, this, &View::slotPopupMenu);
0209 
0210     connect(v, &AbstractView::selectionChanged, this, &View::slotSelectionChanged);
0211     v->updateReadWrite(m_readWrite);
0212     v->loadContext();
0213     return v;
0214 }
0215 
0216 void View::setupPrinter(QPrinter &/*printer*/, QPrintDialog &/*printDialog */)
0217 {
0218     //debugPlanWork;
0219 }
0220 
0221 void View::print(QPrinter &/*printer*/, QPrintDialog &/*printDialog*/)
0222 {
0223 }
0224 
0225 void View::slotSelectionChanged()
0226 {
0227     bool enable = ! currentView()->selectedNodes().isEmpty();
0228     actionRemoveSelectedPackages->setEnabled(enable);
0229     actionRemoveCurrentPackage->setEnabled(enable);
0230 }
0231 
0232 void View::slotEditCut()
0233 {
0234     //debugPlanWork;
0235 }
0236 
0237 void View::slotEditCopy()
0238 {
0239     //debugPlanWork;
0240 }
0241 
0242 void View::slotEditPaste()
0243 {
0244     //debugPlanWork;
0245 }
0246 
0247 void View::slotProgressChanged(int)
0248 {
0249 }
0250 
0251 void View::slotConfigure()
0252 {
0253 }
0254 
0255 ScheduleManager *View::currentScheduleManager() const
0256 {
0257     WorkPackage *wp = m_part->findWorkPackage(currentNode());
0258     return wp ? wp->project()->scheduleManagers().value(0) : nullptr;
0259 }
0260 
0261 void View::updateReadWrite(bool readwrite)
0262 {
0263     debugPlanWork<<m_readWrite<<"->"<<readwrite;
0264     m_readWrite = readwrite;
0265 
0266 //    actionTaskProgress->setEnabled(readwrite);
0267 
0268     emit sigUpdateReadWrite(readwrite);
0269 }
0270 
0271 Part *View::part() const
0272 {
0273     return m_part;
0274 }
0275 
0276 void View::slotPopupMenu(const QString& name, const QPoint & pos)
0277 {
0278     debugPlanWork<<name;
0279     Q_ASSERT(m_part->factory());
0280     if (m_part->factory() == 0) {
0281         return;
0282     }
0283     QMenu *menu = ((QMenu*) m_part->factory() ->container(name, m_part));
0284     if (menu == 0) {
0285         return;
0286     }
0287     QList<QAction*> lst;
0288     AbstractView *v = currentView();
0289     if (v) {
0290         lst = v->contextActionList();
0291         debugPlanWork<<lst;
0292         if (! lst.isEmpty()) {
0293             menu->addSeparator();
0294             foreach (QAction *a, lst) {
0295                 menu->addAction(a);
0296             }
0297         }
0298     }
0299     menu->exec(pos);
0300     foreach (QAction *a, lst) {
0301         menu->removeAction(a);
0302     }
0303 }
0304 
0305 bool View::loadContext()
0306 {
0307     debugPlanWork;
0308     setCurrentIndex(PlanWorkSettings::self()->currentView());
0309     return true;
0310 }
0311 
0312 void View::saveContext() const
0313 {
0314     debugPlanWork;
0315     PlanWorkSettings::self()->setCurrentView(currentIndex());
0316     PlanWorkSettings::self()->save();
0317 }
0318 
0319 void View::slotEditDocument()
0320 {
0321     slotEditDocument(currentDocument());
0322 }
0323 
0324 void View::slotEditDocument(Document *doc)
0325 {
0326     debugPlanWork<<doc;
0327     if (doc == 0) {
0328         debugPlanWork<<"No document";
0329         return;
0330     }
0331     if (doc->type() != Document::Type_Product) {
0332         KMessageBox::error(0, i18n("This file is not editable"));
0333         return;
0334     }
0335     part()->editWorkpackageDocument(doc);
0336 }
0337 
0338 void View::slotViewDocument()
0339 {
0340     emit viewDocument(currentDocument());
0341 }
0342 
0343 void View::slotRemoveDocument()
0344 {
0345     part()->removeDocument(currentDocument());
0346 }
0347 
0348 void View::slotSendPackage()
0349 {
0350     Node *node = currentNode();
0351     if (node == 0) {
0352         KMessageBox::error(0, i18n("No work package is selected"));
0353         return;
0354     }
0355     debugPlanWork<<node->name();
0356     WorkPackage *wp = part()->findWorkPackage(node);
0357     if (wp == 0) {
0358         KMessageBox::error(0, i18n("Cannot find work package"));
0359         return;
0360     }
0361 /*    if (wp->isModified()) {
0362         int r = KMessageBox::questionYesNoCancel(0, i18n("This work package has been modified.\nDo you want to save it before sending?"), node->name());
0363         switch (r) {
0364             case KMessageBox::Cancel: return;
0365             case KMessageBox::Yes: wp->saveToProjects(part()); break;
0366             default: break;
0367         }
0368     }*/
0369 
0370     bool wasmodified = wp->isModified();
0371     if (wp->sendUrl().isValid()) {
0372         QTemporaryFile temp(wp->sendUrl().toLocalFile() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String(".planwork"));
0373         temp.setAutoRemove(false);
0374         if (! temp.open()) {
0375             KMessageBox::error(0, i18n("Could not open file. Sending is aborted."));
0376             return;
0377         }
0378         wp->saveNativeFormat(part(), temp.fileName());
0379     } else {
0380         QTemporaryFile temp(QDir::tempPath() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String(".planwork"));
0381         temp.setAutoRemove(false);
0382         if (! temp.open()) {
0383             KMessageBox::error(0, i18n("Could not open temporary file. Sending is aborted."));
0384             return;
0385         }
0386         wp->saveNativeFormat(part(), temp.fileName());
0387 
0388         QStringList attachURLs;
0389         attachURLs << temp.fileName();
0390 
0391         QString to = node->projectNode()->leader();
0392         QString cc;
0393         QString bcc;
0394         QString subject = i18n("Work Package: %1", node->name());
0395         QString body = node->projectNode()->name();
0396         QString messageFile;
0397 
0398         KToolInvocation::invokeMailer(to, cc, bcc, subject, body, messageFile, attachURLs);
0399     }
0400     wp->setModified(wasmodified);
0401 }
0402 
0403 void View::slotTaskDescription()
0404 {
0405     Task *node = qobject_cast<Task*>(currentNode());
0406     if (node == 0) {
0407         return;
0408     }
0409     QPointer<TaskDescriptionDialog> dlg = new TaskDescriptionDialog(*node, this, true);
0410     dlg->exec();
0411     delete dlg;
0412 }
0413 
0414 AbstractView *View::currentView() const
0415 {
0416     return qobject_cast<AbstractView*>(currentWidget());
0417 }
0418 
0419 Node *View::currentNode() const
0420 {
0421     AbstractView *v = currentView();
0422     return v ? v->currentNode() : 0;
0423 }
0424 
0425 Document *View::currentDocument() const
0426 {
0427     AbstractView *v = currentView();
0428     return v ? v->currentDocument() : 0;
0429 }
0430 
0431 void View::slotTaskProgress()
0432 {
0433     debugPlanWork;
0434     Task *n = qobject_cast<Task*>(currentNode());
0435     if (n == 0) {
0436         return;
0437     }
0438     StandardWorktime *w = qobject_cast<Project*>(n->projectNode())->standardWorktime();
0439     QPointer<TaskProgressDialog> dlg = new TaskProgressDialog(*n, currentScheduleManager(), w, this);
0440     if (dlg->exec() == QDialog::Accepted && dlg) {
0441         KUndo2Command *cmd = dlg->buildCommand();
0442         if (cmd) {
0443             cmd->redo(); //FIXME m_part->addCommand(cmd);
0444         }
0445     }
0446 }
0447 
0448 void View::slotTaskCompletion()
0449 {
0450     debugPlanWork;
0451     WorkPackage *wp = m_part->findWorkPackage(currentNode());
0452     if (wp == 0) {
0453         return;
0454     }
0455     QPointer<TaskCompletionDialog> dlg = new TaskCompletionDialog(*wp, currentScheduleManager(), this);
0456     if (dlg->exec() == QDialog::Accepted && dlg) {
0457         KUndo2Command *cmd = dlg->buildCommand();
0458         if (cmd) {
0459             m_part->addCommand(cmd);
0460         }
0461     }
0462     delete dlg;
0463 }
0464 
0465 void View::slotRemoveSelectedPackages()
0466 {
0467     debugPlanWork;
0468     QList<Node*> lst = currentView()->selectedNodes();
0469     if (lst.isEmpty()) {
0470         return;
0471     }
0472     m_part->removeWorkPackages(lst);
0473 }
0474 
0475 void View::slotRemoveCurrentPackage()
0476 {
0477     debugPlanWork;
0478     Node *n = currentNode();
0479     if (n == 0) {
0480         return;
0481     }
0482     m_part->removeWorkPackage(n);
0483 }
0484 
0485 
0486 }  //KPlatoWork namespace