diff --git a/src/kptloadsharedprojectsdialog.cpp b/src/kptloadsharedprojectsdialog.cpp index fb033010..5fadd71d 100644 --- a/src/kptloadsharedprojectsdialog.cpp +++ b/src/kptloadsharedprojectsdialog.cpp @@ -1,92 +1,92 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kptloadsharedprojectsdialog.h" #include "kptproject.h" #include #include #include #include #include #include #include #include using namespace KPlato; LoadSharedProjectsDialog::LoadSharedProjectsDialog(Project &project, const QUrl &own, QWidget *parent) : KoDialog(parent) , m_view(new QTreeView(this)) { - setCaption( i18nc("@title", "Load Resource Assignments") ); + setCaption( xi18nc("@title:window", "Load Resource Assignments") ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); setMainWidget(m_view); QList skip; skip << own << project.sharedProjectsUrl(); QFileInfo fi(project.sharedProjectsUrl().path()); QDir dir = fi.dir(); QList paths; foreach(const QString &f, dir.entryList(QStringList()<<"*.plan")) { QString path = dir.canonicalPath(); if (path.isEmpty()) { continue; } path += '/' + f; QUrl url = QUrl::fromLocalFile(path); if (!skip.contains(url)) { paths << url; } } QStandardItemModel *m = new QStandardItemModel(m_view); for (int i = 0; i < paths.count(); ++i) { QStandardItem *item = new QStandardItem(); item->setData(paths.at(i).fileName(), Qt::DisplayRole); item->setData(paths.at(i), Qt::UserRole); item->setData(paths.at(i).toDisplayString(), Qt::ToolTipRole); item->setCheckable(true); item->setCheckState(Qt::Checked); m->appendRow(item); } m_view->setModel(m); m_view->setHeaderHidden(true); m_view->setRootIsDecorated(false); } QList LoadSharedProjectsDialog::urls() const { QList urls; QStandardItemModel *m = qobject_cast(m_view->model()); if (m) { for (int i = 0; i < m->rowCount(); ++i) { QStandardItem *item = m->item(i); if (item->checkState()) { urls << item->data(Qt::UserRole).toUrl(); } } } return urls; } diff --git a/src/kptviewlistdialog.cpp b/src/kptviewlistdialog.cpp index 2947270d..3f605253 100644 --- a/src/kptviewlistdialog.cpp +++ b/src/kptviewlistdialog.cpp @@ -1,677 +1,677 @@ /* This file is part of the KDE project Copyright (C) 2007 - 2010 Dag Andersen Copyright (C) 2012 Dag Andersen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "kptviewlistdialog.h" #include "kptviewlist.h" #include "kptview.h" #ifdef PLAN_USE_KREPORT #include "reports/reportview.h" #endif #include #include #include namespace KPlato { ViewListDialog::ViewListDialog( View *view, ViewListWidget &viewlist, QWidget *parent ) : KoDialog(parent) { - setCaption( i18nc( "@title:window", "Add View") ); + setCaption( xi18nc( "@title:window", "Add View") ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new AddViewPanel( view, viewlist, this ); setMainWidget( m_panel ); enableButtonOk(false); connect(this,&KoDialog::okClicked,this,&ViewListDialog::slotOk); connect( m_panel, &AddViewPanel::enableButtonOk, this, &KoDialog::enableButtonOk ); connect( m_panel, &AddViewPanel::viewCreated, this, &ViewListDialog::viewCreated ); connect(&viewlist, &ViewListWidget::viewListItemRemoved, this, &ViewListDialog::slotViewListItemRemoved); } void ViewListDialog::slotViewListItemRemoved( ViewListItem * ) { reject(); } void ViewListDialog::slotOk() { if ( m_panel->ok() ) { accept(); } } //------------------------ AddViewPanel::AddViewPanel( View *view, ViewListWidget &viewlist, QWidget *parent ) : QWidget( parent ), m_view( view ), m_viewlist( viewlist ), m_viewnameChanged( false ), m_viewtipChanged( false ) { widget.setupUi( this ); // NOTE: these lists must match switch in ok() FIXME: refactor m_viewtypes << "ResourceEditor" << "TaskEditor" << "CalendarEditor" << "AccountsEditor" << "DependencyEditor" << "PertEditor" << "ScheduleHandlerView" << "TaskStatusView" << "TaskView" << "TaskWorkPackageView" << "GanttView" << "MilestoneGanttView" << "ResourceAppointmentsView" << "ResourceAppointmentsGanttView" << "AccountsView" << "ProjectStatusView" << "PerformanceStatusView" << "ReportsGeneratorView"; #ifdef PLAN_USE_KREPORT m_viewtypes << "ReportView"; #endif QStringList lst; lst << i18n( "Resource Editor" ) << i18n( "Task Editor" ) << i18n( "Work & Vacation Editor" ) << i18n( "Accounts Editor" ) << i18n( "Dependency Editor (Graphic)" ) << i18n( "Dependency Editor (List)" ) << i18n( "Schedule Handler" ) << i18n( "Task Status" ) << i18n( "Task View" ) << i18n( "Work Package View" ) << i18n( "Gantt View" ) << i18n( "Milestone Gantt View" ) << i18n( "Resource Assignments" ) << i18n( "Resource Assignments (Gantt)" ) << i18n( "Cost Breakdown" ) << i18n( "Project Performance Chart" ) << i18n( "Tasks Performance Chart" ) << i18n("Reports generator"); #ifdef PLAN_USE_KREPORT lst << i18n( "Report" ); #endif widget.viewtype->addItems( lst ); foreach ( ViewListItem *item, m_viewlist.categories() ) { m_categories.insert( item->text( 0 ), item ); } widget.category->addItems( m_categories.keys() ); ViewListItem *curr = m_viewlist.currentCategory(); if ( curr ) { const QList &items = m_categories.values(); widget.category->setCurrentIndex(items.indexOf(curr)); } fillAfter( m_categories.value( widget.category->currentText() ) ); viewtypeChanged( widget.viewtype->currentIndex() ); connect( widget.viewname, &QLineEdit::textChanged, this, &AddViewPanel::changed ); connect( widget.tooltip, &QLineEdit::textChanged, this, &AddViewPanel::changed ); connect( widget.viewname, &QLineEdit::textChanged, this, &AddViewPanel::viewnameChanged ); connect( widget.tooltip, &QLineEdit::textChanged, this, &AddViewPanel::viewtipChanged ); connect( widget.insertAfter, SIGNAL(currentIndexChanged(int)), SLOT(changed()) ); connect( widget.viewtype, SIGNAL(currentIndexChanged(int)), SLOT(viewtypeChanged(int)) ); connect( widget.category, &QComboBox::editTextChanged, this, &AddViewPanel::categoryChanged ); QString categoryWhatsThis = xi18nc("@info:whatsthis", "The category of the view" "The view is placed under this category in the view selector." "You can edit the category name to create a new category."); widget.categoryLabel->setWhatsThis(categoryWhatsThis); widget.category->setWhatsThis(categoryWhatsThis); } void AddViewPanel::viewnameChanged( const QString &text ) { m_viewnameChanged = ! text.isEmpty(); } void AddViewPanel::viewtipChanged( const QString &text ) { m_viewtipChanged = ! text.isEmpty(); } void AddViewPanel::viewtypeChanged( int idx ) { ViewInfo vi = m_view->defaultViewInfo( m_viewtypes.value( idx ) ); if ( widget.viewname->text().isEmpty() ) { m_viewnameChanged = false; } if ( ! m_viewnameChanged ) { widget.viewname->setText( vi.name ); m_viewnameChanged = false; } if ( widget.tooltip->text().isEmpty() ) { m_viewtipChanged = false; } if ( ! m_viewtipChanged ) { QTextEdit e; e.setText(vi.tip); widget.tooltip->setText(e.toPlainText()); m_viewtipChanged = false; } } void AddViewPanel::categoryChanged() { debugPlan<currentText(); fillAfter( m_categories.value( widget.category->currentText() ) ); changed(); } void AddViewPanel::fillAfter( ViewListItem *cat ) { debugPlan<clear(); if ( cat ) { widget.insertAfter->addItem( i18n( "Top" ) ); // int idx = 0; for ( int i = 0; i < cat->childCount(); ++i ) { ViewListItem *itm = static_cast( cat->child( i ) ); widget.insertAfter->addItem( itm->text( 0 ), QVariant::fromValue( (void*)itm ) ); } if ( cat == m_viewlist.currentCategory() ) { ViewListItem *v = m_viewlist.currentItem(); if ( v && v->type() != ViewListItem::ItemType_Category ) { widget.insertAfter->setCurrentIndex( cat->indexOfChild( v ) + 1 ); } } } } bool AddViewPanel::ok() { QString n = widget.category->currentText(); ViewListItem *curr = m_categories.value( n ); QString c = curr == 0 ? n : curr->tag(); ViewListItem *cat = m_viewlist.addCategory( c, n ); if ( cat == 0 ) { return false; } ViewBase *v = 0; int index = widget.insertAfter->currentIndex(); int viewtype = widget.viewtype->currentIndex(); switch ( viewtype ) { case 0: { // Resource editor v = m_view->createResourceEditor( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 1: { // Task editor v = m_view->createTaskEditor( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 2: { // Work & Vacation Editor v = m_view->createCalendarEditor( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 3: { // Accounts Editor v = m_view->createAccountsEditor( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 4: { // Dependency Editor (Graphic) v = m_view->createDependencyEditor( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 5: { // Dependency Editor (List) v = m_view->createPertEditor( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 6: { // Schedules Handler v = m_view->createScheduleHandler( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 7: { // Task status v = m_view->createTaskStatusView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 8: { // Task status v = m_view->createTaskView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 9: { // Task work package v = m_view->createTaskWorkPackageView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 10: { // Gantt View v = m_view->createGanttView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 11: { // Milestone Gantt View v = m_view->createMilestoneGanttView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 12: { // Resource Assignments v = m_view->createResourceAppointmentsView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 13: { // Resource Assignments (Gantt) v = m_view->createResourceAppointmentsGanttView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 14: { // Cost Breakdown v = m_view->createAccountsView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 15: { // Project Performance Chart v = m_view->createProjectStatusView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 16: { // Task Performance Chart v = m_view->createPerformanceStatusView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } case 17: { // Reports generator v = m_view->createReportsGeneratorView(cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index); break; } #ifdef PLAN_USE_KREPORT case 18: { // Report view v = m_view->createReportView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); break; } #endif default: errorPlan<<"Unknown view type!"; break; } emit viewCreated( v ); return true; } void AddViewPanel::changed() { bool disable = widget.viewname->text().isEmpty() | widget.viewtype->currentText().isEmpty() | widget.category->currentText().isEmpty(); emit enableButtonOk( ! disable ); } //------------------------ ViewListEditViewDialog::ViewListEditViewDialog( ViewListWidget &viewlist, ViewListItem *item, QWidget *parent ) : KoDialog(parent) { - setCaption( i18nc( "@title:window", "Configure View" ) ); + setCaption( xi18nc( "@title:window", "Configure View" ) ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new EditViewPanel( viewlist, item, this ); setMainWidget( m_panel ); enableButtonOk(false); connect(this,&KoDialog::okClicked,this,&ViewListEditViewDialog::slotOk); connect( m_panel, &EditViewPanel::enableButtonOk, this, &KoDialog::enableButtonOk ); connect(&viewlist, &ViewListWidget::viewListItemRemoved, this, &ViewListEditViewDialog::slotViewListItemRemoved); } void ViewListEditViewDialog::slotViewListItemRemoved( ViewListItem * ) { reject(); } void ViewListEditViewDialog::slotOk() { if ( m_panel->ok() ) { accept(); } } EditViewPanel::EditViewPanel( ViewListWidget &viewlist, ViewListItem *item, QWidget *parent ) : QWidget( parent ), m_item( item ), m_viewlist( viewlist ) { widget.setupUi( this ); widget.viewname->setText( item->text( 0 ) ); QTextEdit e; e.setText(item->toolTip(0)); widget.tooltip->setText(e.toPlainText()); foreach ( ViewListItem *item, m_viewlist.categories() ) { m_categories.insert( item->text( 0 ), item ); } widget.category->addItems( m_categories.keys() ); ViewListItem *curr = m_viewlist.currentCategory(); if ( curr ) { const QList &items = m_categories.values(); widget.category->setCurrentIndex(items.indexOf(curr)); } categoryChanged(); connect( widget.viewname, &QLineEdit::textChanged, this, &EditViewPanel::changed ); connect( widget.tooltip, &QLineEdit::textChanged, this, &EditViewPanel::changed ); connect( widget.insertAfter, SIGNAL(currentIndexChanged(int)), SLOT(changed()) ); connect( widget.category, &QComboBox::editTextChanged, this, &EditViewPanel::categoryChanged ); QString categoryWhatsThis = xi18nc("@info:whatsthis", "The category of the view" "The view is placed under this category in the view selector." "Selecting a different category will move the view to the new category." "You can edit the category name to create a new category."); widget.categoryLabel->setWhatsThis(categoryWhatsThis); widget.category->setWhatsThis(categoryWhatsThis); } bool EditViewPanel::ok() { QString n = widget.category->currentText(); ViewListItem *curr = m_categories.value( n ); QString c = curr == 0 ? n : curr->tag(); ViewListItem *cat = m_viewlist.addCategory( c, n ); if ( cat == 0 ) { warnPlan<<"No category"; return false; } if ( widget.viewname->text() != m_item->text( 0 ) ) { m_item->setText( 0, widget.viewname->text() ); } if ( widget.tooltip->text() != m_item->toolTip( 0 ) ) { m_item->setToolTip( 0, widget.tooltip->text() ); } m_viewlist.removeViewListItem( m_item ); int index = qMin( widget.insertAfter->currentIndex(), cat->childCount() ); m_viewlist.addViewListItem( m_item, cat, index ); return true; } void EditViewPanel::changed() { bool disable = widget.viewname->text().isEmpty() | widget.category->currentText().isEmpty(); emit enableButtonOk( ! disable ); } void EditViewPanel::categoryChanged() { debugPlan<currentText(); fillAfter( m_categories.value( widget.category->currentText() ) ); changed(); } void EditViewPanel::fillAfter( ViewListItem *cat ) { debugPlan<clear(); if ( cat ) { widget.insertAfter->addItem( i18n( "Top" ) ); // int idx = 0; for ( int i = 0; i < cat->childCount(); ++i ) { ViewListItem *itm = static_cast( cat->child( i ) ); widget.insertAfter->addItem( itm->text( 0 ), QVariant::fromValue( (void*)itm ) ); } if ( cat == m_viewlist.currentCategory() ) { ViewListItem *v = m_viewlist.currentItem(); if ( v && v->type() != ViewListItem::ItemType_Category ) { widget.insertAfter->setCurrentIndex( cat->indexOfChild( v ) + 1 ); } } } } //------------------------ ViewListEditCategoryDialog::ViewListEditCategoryDialog( ViewListWidget &viewlist, ViewListItem *item, QWidget *parent ) : KoDialog(parent) { - setCaption( i18nc( "@title:window", "Configure Category" ) ); + setCaption( xi18nc( "@title:window", "Configure Category" ) ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new EditCategoryPanel( viewlist, item, this ); setMainWidget( m_panel ); enableButtonOk(false); connect(this,&KoDialog::okClicked,this,&ViewListEditCategoryDialog::slotOk); connect( m_panel, &EditCategoryPanel::enableButtonOk, this, &KoDialog::enableButtonOk ); connect(&viewlist, &ViewListWidget::viewListItemRemoved, this, &ViewListEditCategoryDialog::slotViewListItemRemoved); } void ViewListEditCategoryDialog::slotViewListItemRemoved( ViewListItem * ) { reject(); } void ViewListEditCategoryDialog::slotOk() { if ( m_panel->ok() ) { accept(); } } EditCategoryPanel::EditCategoryPanel( ViewListWidget &viewlist, ViewListItem *item, QWidget *parent ) : QWidget( parent ), m_item( item ), m_viewlist( viewlist ) { widget.setupUi( this ); widget.viewname->setText( item->text( 0 ) ); QTextEdit e; e.setText(item->toolTip(0)); widget.tooltip->setText(e.toPlainText()); fillAfter(); connect( widget.viewname, &QLineEdit::textChanged, this, &EditCategoryPanel::changed ); connect( widget.tooltip, &QLineEdit::textChanged, this, &EditCategoryPanel::changed ); connect( widget.insertAfter, SIGNAL(currentIndexChanged(int)), SLOT(changed()) ); } bool EditCategoryPanel::ok() { if ( widget.viewname->text() != m_item->text( 0 ) ) { m_item->setText( 0, widget.viewname->text() ); } if ( widget.tooltip->text() != m_item->toolTip( 0 ) ) { m_item->setToolTip( 0, widget.tooltip->text() ); } bool ex = m_item->isExpanded(); m_viewlist.removeViewListItem( m_item ); int index = widget.insertAfter->currentIndex(); m_viewlist.addViewListItem( m_item, 0, index ); m_item->setExpanded( ex ); return true; } void EditCategoryPanel::changed() { bool disable = widget.viewname->text().isEmpty(); emit enableButtonOk( ! disable ); } void EditCategoryPanel::fillAfter() { debugPlan; widget.insertAfter->clear(); widget.insertAfter->addItem( i18n( "Top" ) ); int idx = 0; QList lst = m_viewlist.categories(); for ( int i = 0; i < lst.count(); ++i ) { ViewListItem *itm = lst[ i ]; if ( m_item == itm ) { idx = i; } else { widget.insertAfter->addItem( itm->text( 0 ), QVariant::fromValue( (void*)itm ) ); } } widget.insertAfter->setCurrentIndex( idx ); } #ifdef PLAN_USE_KREPORT //------ Reports ViewListReportsDialog::ViewListReportsDialog( View *view, ViewListWidget &viewlist, const QDomDocument &doc, QWidget *parent ) : KoDialog(parent) { - setCaption( i18nc( "@title:window", "Add Report" ) ); + setCaption( xi18nc( "@title:window", "Add Report" ) ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new AddReportsViewPanel( view, viewlist, doc, this ); setMainWidget( m_panel ); enableButtonOk(true); connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); connect( m_panel, SIGNAL(enableButtonOk(bool)), SLOT(enableButtonOk(bool)) ); connect( m_panel, SIGNAL(viewCreated(KPlato::ViewBase*)), SIGNAL(viewCreated(KPlato::ViewBase*))); connect(&viewlist, SIGNAL(viewListItemRemoved(KPlato::ViewListItem*)), SLOT(slotViewListItemRemoved(KPlato::ViewListItem*))); } void ViewListReportsDialog::slotViewListItemRemoved( ViewListItem * ) { reject(); } void ViewListReportsDialog::slotOk() { if ( m_panel->ok() ) { accept(); } } //------------------------ AddReportsViewPanel::AddReportsViewPanel( View *view, ViewListWidget &viewlist, const QDomDocument &doc, QWidget *parent ) : QWidget( parent ), m_view( view ), m_viewlist( viewlist ), m_viewnameChanged( false ), m_viewtipChanged( false ), m_data(doc) { widget.setupUi( this ); // NOTE: these lists must match switch in ok() FIXME: refactor m_viewtypes << "ReportView"; QStringList lst; - lst << i18n( "Report" ); + lst << xi18n( "Report" ); widget.viewtype->addItems( lst ); foreach ( ViewListItem *item, m_viewlist.categories() ) { m_categories.insert( item->text( 0 ), item ); } widget.category->addItems( m_categories.keys() ); ViewListItem *curr = m_viewlist.currentCategory(); if ( curr ) { widget.category->setCurrentIndex( m_categories.values().indexOf( curr ) ); } fillAfter( m_categories.value( widget.category->currentText() ) ); viewtypeChanged( widget.viewtype->currentIndex() ); connect( widget.viewname, SIGNAL(textChanged(QString)), SLOT(changed()) ); connect( widget.tooltip, SIGNAL(textChanged(QString)), SLOT(changed()) ); connect( widget.viewname, SIGNAL(textChanged(QString)), SLOT(viewnameChanged(QString)) ); connect( widget.tooltip, SIGNAL(textChanged(QString)), SLOT(viewtipChanged(QString)) ); connect( widget.insertAfter, SIGNAL(currentIndexChanged(int)), SLOT(changed()) ); connect( widget.viewtype, SIGNAL(currentIndexChanged(int)), SLOT(viewtypeChanged(int)) ); connect( widget.category, SIGNAL(editTextChanged(QString)), SLOT(categoryChanged()) ); } void AddReportsViewPanel::viewnameChanged( const QString &text ) { m_viewnameChanged = ! text.isEmpty(); } void AddReportsViewPanel::viewtipChanged( const QString &text ) { m_viewtipChanged = ! text.isEmpty(); } void AddReportsViewPanel::viewtypeChanged( int idx ) { ViewInfo vi = m_view->defaultViewInfo( m_viewtypes.value( idx ) ); if ( widget.viewname->text().isEmpty() ) { m_viewnameChanged = false; } if ( ! m_viewnameChanged ) { widget.viewname->setText( vi.name ); m_viewnameChanged = false; } if ( widget.tooltip->text().isEmpty() ) { m_viewtipChanged = false; } if ( ! m_viewtipChanged ) { QTextEdit e; e.setText(vi.tip); widget.tooltip->setText(e.toPlainText()); m_viewtipChanged = false; } } void AddReportsViewPanel::categoryChanged() { debugPlan<currentText(); fillAfter( m_categories.value( widget.category->currentText() ) ); changed(); } void AddReportsViewPanel::fillAfter( ViewListItem *cat ) { debugPlan<clear(); if ( cat ) { widget.insertAfter->addItem( i18n( "Top" ) ); // int idx = 0; for ( int i = 0; i < cat->childCount(); ++i ) { ViewListItem *itm = static_cast( cat->child( i ) ); widget.insertAfter->addItem( itm->text( 0 ), QVariant::fromValue( (void*)itm ) ); } if ( cat == m_viewlist.currentCategory() ) { ViewListItem *v = m_viewlist.currentItem(); if ( v && v->type() != ViewListItem::ItemType_Category ) { widget.insertAfter->setCurrentIndex( cat->indexOfChild( v ) + 1 ); } } } } bool AddReportsViewPanel::ok() { QString n = widget.category->currentText(); ViewListItem *curr = m_categories.value( n ); QString c = curr == 0 ? n : curr->tag(); ViewListItem *cat = m_viewlist.addCategory( c, n ); if ( cat == 0 ) { return false; } ViewBase *v = 0; int index = widget.insertAfter->currentIndex(); int viewtype = widget.viewtype->currentIndex(); switch ( viewtype ) { case 0: { // Report view v = m_view->createReportView( cat, m_viewtypes.value( viewtype ), widget.viewname->text(), widget.tooltip->text(), index ); static_cast(v)->loadXML(m_data); break; } default: errorPlan<<"Unknown view type!"; break; } emit viewCreated( v ); return true; } void AddReportsViewPanel::changed() { bool disable = widget.viewname->text().isEmpty() | widget.viewtype->currentText().isEmpty() | widget.category->currentText().isEmpty(); emit enableButtonOk( ! disable ); } #endif } //KPlato namespace diff --git a/src/libs/models/kptschedulemodel.cpp b/src/libs/models/kptschedulemodel.cpp index 21311c3b..d69bd96f 100644 --- a/src/libs/models/kptschedulemodel.cpp +++ b/src/libs/models/kptschedulemodel.cpp @@ -1,1356 +1,1356 @@ /* This file is part of the KDE project Copyright (C) 2007, 2012 Dag Andersen danders@get2net> Copyright (C) 2016 Dag Andersen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "kptschedulemodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptschedule.h" #include "kptdatetime.h" #include "kptschedulerplugin.h" #include "kptdebug.h" #include #include #include #include #include namespace KPlato { //-------------------------------------- // internal, for displaying schedule name + state #define SpecialScheduleDisplayRole 99999999 ScheduleModel::ScheduleModel( QObject *parent ) : QObject( parent ) { } ScheduleModel::~ScheduleModel() { } const QMetaEnum ScheduleModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } int ScheduleModel::propertyCount() const { return columnMap().keyCount(); } //-------------------------------------- ScheduleItemModel::ScheduleItemModel( QObject *parent ) : ItemModelBase( parent ), m_manager( 0 ), m_flat( false ) { } ScheduleItemModel::~ScheduleItemModel() { } void ScheduleItemModel::slotScheduleManagerToBeInserted( const ScheduleManager *parent, int row ) { //debugPlan<(parent); beginInsertRows( index( parent ), row, row ); } void ScheduleItemModel::slotScheduleManagerInserted( const ScheduleManager *manager ) { //debugPlan<name(); if ( m_flat ) { int row = m_project->allScheduleManagers().indexOf( const_cast( manager ) ); Q_ASSERT( row >= 0 ); beginInsertRows( QModelIndex(), row, row ); m_managerlist.insert( row, const_cast( manager ) ); endInsertRows(); emit scheduleManagerAdded( const_cast( manager ) ); return; } Q_ASSERT( manager->parentManager() == m_manager ); endInsertRows(); m_manager = 0; emit scheduleManagerAdded( const_cast( manager ) ); } void ScheduleItemModel::slotScheduleManagerToBeRemoved( const ScheduleManager *manager ) { //debugPlan<name(); if ( m_flat ) { int row = m_managerlist.indexOf( const_cast( manager ) ); beginRemoveRows( QModelIndex(), row, row ); m_managerlist.removeAt( row ); return; } Q_ASSERT( m_manager == 0 ); m_manager = const_cast(manager); QModelIndex i = index( manager ); int row = i.row(); beginRemoveRows( parent( i ), row, row ); } void ScheduleItemModel::slotScheduleManagerRemoved( const ScheduleManager *manager ) { //debugPlan<name(); if ( m_flat ) { endRemoveRows(); return; } Q_ASSERT( manager == m_manager ); Q_UNUSED( manager ); endRemoveRows(); m_manager = 0; } void ScheduleItemModel::slotScheduleManagerToBeMoved( const ScheduleManager *manager ) { //debugPlan<name()<<"from"<<(manager->parentManager()?manager->parentManager()->name():"project"); slotScheduleManagerToBeRemoved( manager ); } void ScheduleItemModel::slotScheduleManagerMoved( const ScheduleManager *manager, int index ) { //debugPlan<name()<<"to"<parentManager()<parentManager(), index ); slotScheduleManagerInserted( manager ); } void ScheduleItemModel::slotScheduleToBeInserted( const ScheduleManager *, int /*row*/ ) { } void ScheduleItemModel::slotScheduleInserted( const MainSchedule * ) { } void ScheduleItemModel::slotScheduleToBeRemoved( const MainSchedule * ) { } void ScheduleItemModel::slotScheduleRemoved( const MainSchedule * ) { } void ScheduleItemModel::setProject( Project *project ) { beginResetModel(); if ( m_project ) { disconnect(m_project, &Project::aboutToBeDeleted, this, &ScheduleItemModel::projectDeleted); disconnect(m_project, &Project::scheduleManagerChanged, this, &ScheduleItemModel::slotManagerChanged); disconnect(m_project, &Project::scheduleManagerToBeAdded, this, &ScheduleItemModel::slotScheduleManagerToBeInserted); disconnect(m_project, &Project::scheduleManagerToBeRemoved, this, &ScheduleItemModel::slotScheduleManagerToBeRemoved); disconnect(m_project, &Project::scheduleManagerAdded, this, &ScheduleItemModel::slotScheduleManagerInserted); disconnect(m_project, &Project::scheduleManagerRemoved, this, &ScheduleItemModel::slotScheduleManagerRemoved); disconnect(m_project, &Project::scheduleManagerToBeMoved, this, &ScheduleItemModel::slotScheduleManagerToBeMoved); disconnect(m_project, &Project::scheduleManagerMoved, this, &ScheduleItemModel::slotScheduleManagerMoved); disconnect(m_project, &Project::scheduleChanged, this, &ScheduleItemModel::slotScheduleChanged); disconnect(m_project, &Project::scheduleToBeAdded, this, &ScheduleItemModel::slotScheduleToBeInserted); disconnect(m_project, &Project::scheduleToBeRemoved, this, &ScheduleItemModel::slotScheduleToBeRemoved); disconnect(m_project, &Project::scheduleAdded, this, &ScheduleItemModel::slotScheduleInserted); disconnect(m_project, &Project::scheduleRemoved, this, &ScheduleItemModel::slotScheduleRemoved); } m_project = project; if ( m_project ) { connect(m_project, &Project::aboutToBeDeleted, this, &ScheduleItemModel::projectDeleted); connect(m_project, &Project::scheduleManagerChanged, this, &ScheduleItemModel::slotManagerChanged); connect(m_project, &Project::scheduleManagerToBeAdded, this, &ScheduleItemModel::slotScheduleManagerToBeInserted); connect(m_project, &Project::scheduleManagerToBeRemoved, this, &ScheduleItemModel::slotScheduleManagerToBeRemoved); connect(m_project, &Project::scheduleManagerAdded, this, &ScheduleItemModel::slotScheduleManagerInserted); connect(m_project, &Project::scheduleManagerRemoved, this, &ScheduleItemModel::slotScheduleManagerRemoved); connect(m_project, &Project::scheduleManagerToBeMoved, this, &ScheduleItemModel::slotScheduleManagerToBeMoved); connect(m_project, &Project::scheduleManagerMoved, this, &ScheduleItemModel::slotScheduleManagerMoved); connect(m_project, &Project::scheduleChanged, this, &ScheduleItemModel::slotScheduleChanged); connect(m_project, &Project::scheduleToBeAdded, this, &ScheduleItemModel::slotScheduleToBeInserted); connect(m_project, &Project::scheduleToBeRemoved, this, &ScheduleItemModel::slotScheduleToBeRemoved); connect(m_project, &Project::scheduleAdded, this, &ScheduleItemModel::slotScheduleInserted); connect(m_project, &Project::scheduleRemoved, this, &ScheduleItemModel::slotScheduleRemoved); } setFlat( m_flat ); // update m_managerlist endResetModel(); } void ScheduleItemModel::slotManagerChanged( ScheduleManager *sch ) { if ( m_flat ) { int row = m_managerlist.indexOf( sch ); emit dataChanged( createIndex( row, 0, sch ), createIndex( row, columnCount() - 1, sch ) ); return; } int r = sch->parentManager() ? sch->parentManager()->indexOf( sch ) : m_project->indexOf( sch ); //debugPlan<schedulerPlugin(); if ( pl == 0 ) { return flags; } int capabilities = pl->capabilities(); flags &= ~Qt::ItemIsEditable; if ( sm && ! sm->isBaselined() ) { switch ( index.column() ) { case ScheduleModel::ScheduleName: if (!hasChildren(index) && !index.parent().isValid()) { flags |= Qt::ItemIsUserCheckable; } flags |= Qt::ItemIsEditable; break; case ScheduleModel::ScheduleState: break; case ScheduleModel::ScheduleMode: if (!sm->isBaselined() && !hasChildren(index) && !index.parent().isValid()) { flags |= Qt::ItemIsEditable; } break; case ScheduleModel::ScheduleOverbooking: if ( capabilities & SchedulerPlugin::AllowOverbooking && capabilities & SchedulerPlugin::AvoidOverbooking ) { flags |= Qt::ItemIsEditable; } break; case ScheduleModel::ScheduleDirection: if ( sm->parentManager() == 0 && capabilities & SchedulerPlugin::ScheduleForward && capabilities & SchedulerPlugin::ScheduleBackward) { flags |= Qt::ItemIsEditable; } break; case ScheduleModel::SchedulePlannedStart: break; case ScheduleModel::SchedulePlannedFinish: break; case ScheduleModel::ScheduleGranularity: if ( ! sm->supportedGranularities().isEmpty() ) { flags |= Qt::ItemIsEditable; } break; default: flags |= Qt::ItemIsEditable; break; } } return flags; } QModelIndex ScheduleItemModel::parent( const QModelIndex &inx ) const { if ( !inx.isValid() || m_project == 0 || m_flat ) { return QModelIndex(); } //debugPlan<parentManager() ); } QModelIndex ScheduleItemModel::index( int row, int column, const QModelIndex &parent ) const { //debugPlan<= columnCount() || row < 0 || row >= rowCount( parent ) ) { //debugPlan<children().value( row ) ); } return createIndex( row, column, m_project->scheduleManagers().value( row ) ); } QModelIndex ScheduleItemModel::index( const ScheduleManager *manager ) const { if ( m_project == 0 || manager == 0 ) { return QModelIndex(); } if ( m_flat ) { return createIndex( m_managerlist.indexOf( const_cast( manager ) ), 0, const_cast(manager) ); } if ( manager->parentManager() == 0 ) { return createIndex( m_project->indexOf( manager ), 0, const_cast(manager) ); } return createIndex( manager->parentManager()->indexOf( manager ), 0, const_cast(manager) ); } int ScheduleItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_model.propertyCount(); } int ScheduleItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 ) { return 0; } if ( m_flat ) { return m_managerlist.count(); } if ( !parent.isValid() ) { return m_project->numScheduleManagers(); } ScheduleManager *sm = manager( parent ); if ( sm ) { //debugPlan<name()<<","<children().count(); return sm->children().count(); } return 0; } QVariant ScheduleItemModel::name( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return sm->name(); case Qt::StatusTipRole: case Qt::ToolTipRole: case Qt::WhatsThisRole: break; case Qt::DecorationRole: if ( sm->isBaselined() ) { return koIcon("view-time-schedule-baselined"); } return QVariant(); default: break; } return QVariant(); } bool ScheduleItemModel::setName( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return false; } switch ( role ) { case Qt::EditRole: emit executeCommand( new ModifyScheduleManagerNameCmd( *sm, value.toString(), kundo2_i18n( "Modify schedule name" ) ) ); return true; default: break; } return false; } QVariant ScheduleItemModel::schedulingMode( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: return schedulingMode(index, Role::EnumList).toList().value(sm->schedulingMode()); case Qt::EditRole: return sm->schedulingMode(); case Qt::StatusTipRole: break; case Qt::ToolTipRole: if (sm->schedulingMode() == ScheduleManager::ManualMode) { - return i18nc("@info:tooltip", "The schedule is in Manual Mode, calculation must be initiated manually"); + return xi18nc("@info:tooltip", "The schedule is in Manual Mode, calculation must be initiated manually"); } - return i18nc("@info:tooltip", "The schedule is in Auto Mode, it will be calculated automatically"); + return xi18nc("@info:tooltip", "The schedule is in Auto Mode, it will be calculated automatically"); case Qt::WhatsThisRole: break; case Role::EnumList: return QStringList() << xi18nc( "@label:listbox", "Manual" ) << xi18nc( "@label:listbox", "Auto" ); case Role::EnumListValue: return sm->schedulingMode(); default: break; } return QVariant(); } bool ScheduleItemModel::setSchedulingMode( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return false; } switch ( role ) { case Qt::EditRole: emit executeCommand( new ModifyScheduleManagerSchedulingModeCmd( *sm, value.toInt(), kundo2_i18n( "Modify scheduling mode" ) ) ); return true; default: break; } return false; } QVariant ScheduleItemModel::state( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: { if ( sm->progress() > 0 ) { return sm->progress(); } QStringList l = sm->state(); if ( l.isEmpty() ) { return ""; } return l.first(); } case Qt::EditRole: { QStringList l = sm->state(); if ( l.isEmpty() ) { return ""; } return l.first(); } case Qt::ToolTipRole: return sm->state().join(", "); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Maximum: return sm->maxProgress(); case Role::Minimum: return 0; case SpecialScheduleDisplayRole: { QString st; if (!sm->isScheduled()) { st = sm->state().value(0); if (sm->progress() > 0) { st = QString("%1 %2%").arg(st).arg(sm->progress()); } } return st; } } return QVariant(); } bool ScheduleItemModel::setState( const QModelIndex &, const QVariant &, int role ) { switch ( role ) { case Qt::EditRole: return false; } return false; } QVariant ScheduleItemModel::allowOverbooking( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } SchedulerPlugin *pl = sm->schedulerPlugin(); if ( pl == 0 ) { return QVariant(); } int capabilities = pl->capabilities(); switch ( role ) { case Qt::EditRole: return sm->allowOverbooking(); case Qt::DisplayRole: if ( capabilities & SchedulerPlugin::AllowOverbooking && capabilities & SchedulerPlugin::AvoidOverbooking ) { return sm->allowOverbooking() ? i18n( "Allow" ) : i18n( "Avoid" ); } if ( capabilities & SchedulerPlugin::AllowOverbooking ) { return sm->allowOverbooking() ? i18n( "Allow" ) : i18n( "(Avoid)" ); } if ( capabilities & SchedulerPlugin::AvoidOverbooking ) { return sm->allowOverbooking() ? i18n( "(Allow)" ) : i18n( "Avoid" ); } break; case Qt::ToolTipRole: if ( capabilities & SchedulerPlugin::AllowOverbooking && capabilities & SchedulerPlugin::AvoidOverbooking ) { return sm->allowOverbooking() ? xi18nc( "@info:tooltip", "Allow overbooking resources" ) : xi18nc( "@info:tooltip", "Avoid overbooking resources" ); } if ( capabilities & SchedulerPlugin::AllowOverbooking ) { return sm->allowOverbooking() ? xi18nc( "@info:tooltip", "Allow overbooking of resources" ) : xi18nc( "@info:tooltip 1=scheduler name", "%1 always allows overbooking of resources", pl->name() ); } if ( capabilities & SchedulerPlugin::AvoidOverbooking ) { return sm->allowOverbooking() ? xi18nc( "@info:tooltip 1=scheduler name", "%1 always avoids overbooking of resources", pl->name() ) : xi18nc( "@info:tooltip", "Avoid overbooking resources" ); } break; case Role::EnumList: return QStringList() << xi18nc( "@label:listbox", "Avoid" ) << xi18nc( "@label:listbox", "Allow" ); case Role::EnumListValue: return sm->allowOverbooking() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ScheduleItemModel::setAllowOverbooking( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return false; } switch ( role ) { case Qt::EditRole: emit executeCommand( new ModifyScheduleManagerAllowOverbookingCmd( *sm, value.toBool(), kundo2_i18n( "Modify allow overbooking" ) ) ); return true; } return false; } QVariant ScheduleItemModel::usePert( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::EditRole: return sm->usePert(); case Qt::DisplayRole: return sm->usePert() ? i18n( "PERT" ) : i18n( "None" ); case Qt::ToolTipRole: return sm->usePert() ? xi18nc( "@info:tooltip", "Use PERT distribution to calculate expected estimate for the tasks" ) : xi18nc( "@info:tooltip", "Use the tasks expected estimate directly" ); case Role::EnumList: return QStringList() << xi18nc( "@label:listbox", "None" ) << xi18nc( "@label:listbox", "PERT" ); case Role::EnumListValue: return sm->usePert() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ScheduleItemModel::setUsePert( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return false; } switch ( role ) { case Qt::EditRole: emit executeCommand( new ModifyScheduleManagerDistributionCmd( *sm, value.toBool(), kundo2_i18n( "Modify scheduling distribution" ) ) ); slotManagerChanged( static_cast( sm ) ); return true; } return false; } QVariant ScheduleItemModel::projectStart( const QModelIndex &index, int role ) const { if ( m_project == 0 ) { return QVariant(); } ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( sm->isScheduled() ) { return QLocale().toString( sm->expected()->start(), QLocale::ShortFormat ); } break; case Qt::EditRole: if ( sm->isScheduled() ) { return sm->expected()->start(); } break; case Qt::ToolTipRole: if ( sm->isScheduled() ) { return xi18nc( "@info:tooltip", "Planned start: %1Target start: %2", QLocale().toString( sm->expected()->start(), QLocale::ShortFormat ), QLocale().toString( m_project->constraintStartTime(), QLocale::ShortFormat ) ); } else { return xi18nc( "@info:tooltip", "Target start: %1", QLocale().toString( m_project->constraintStartTime(), QLocale::ShortFormat ) ); } break; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ScheduleItemModel::projectEnd( const QModelIndex &index, int role ) const { if ( m_project == 0 ) { return QVariant(); } ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( sm->isScheduled() ) { return QLocale().toString( sm->expected()->end(), QLocale::ShortFormat ); } break; case Qt::EditRole: if ( sm->isScheduled() ) { return sm->expected()->end(); } break; case Qt::ToolTipRole: if ( sm->isScheduled() ) { return xi18nc( "@info:tooltip", "Planned finish: %1Target finish: %2", QLocale().toString( sm->expected()->end(), QLocale::ShortFormat ), QLocale().toString( m_project->constraintEndTime(), QLocale::ShortFormat ) ); } else { return xi18nc( "@info:tooltip", "Target finish: %1", QLocale().toString( m_project->constraintEndTime(), QLocale::ShortFormat ) ); } break; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ScheduleItemModel::schedulingDirection( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return QVariant(); } SchedulerPlugin *pl = sm->schedulerPlugin(); if ( pl == 0 ) { return QVariant(); } int capabilities = pl->capabilities(); switch ( role ) { case Qt::EditRole: return sm->schedulingDirection(); case Qt::DisplayRole: if ( capabilities & SchedulerPlugin::ScheduleForward && capabilities & SchedulerPlugin::ScheduleBackward ) { return sm->schedulingDirection() ? i18n( "Backwards" ) : i18n( "Forward" ); } if ( capabilities & SchedulerPlugin::ScheduleForward ) { return sm->schedulingDirection() ? i18n( "(Backwards)" ) : i18n( "Forward" ); } if ( capabilities & SchedulerPlugin::ScheduleBackward ) { return sm->schedulingDirection() ? i18n( "Backwards" ) : i18n( "(Forward)" ); } break; case Qt::ToolTipRole: if ( capabilities & SchedulerPlugin::ScheduleForward && capabilities & SchedulerPlugin::ScheduleBackward ) { return sm->schedulingDirection() ? xi18nc( "@info:tooltip", "Schedule project from target end time" ) : xi18nc( "@info:tooltip", "Schedule project from target start time" ); } if ( capabilities & SchedulerPlugin::ScheduleForward ) { return sm->schedulingDirection() ? xi18nc( "@info:tooltip 1=scheduler name", "%1 always schedules from target start time", pl->name() ) : xi18nc( "@info:tooltip", "Schedule project from target start time" ); } if ( capabilities & SchedulerPlugin::ScheduleBackward ) { return sm->schedulingDirection() ? xi18nc( "@info:tooltip", "Schedule project from target end time" ) : xi18nc( "@info:tooltip 1=scheduler name", "%1 always schedules from target end time", pl->name() ); } break; case Role::EnumList: return QStringList() << xi18nc( "@label:listbox", "Forward" ) << xi18nc( "@label:listbox", "Backwards" ); case Role::EnumListValue: return sm->schedulingDirection() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ScheduleItemModel::setSchedulingDirection( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager ( index ); if ( sm == 0 ) { return false; } switch ( role ) { case Qt::EditRole: emit executeCommand(new ModifyScheduleManagerSchedulingDirectionCmd( *sm, value.toBool(), kundo2_i18n( "Modify scheduling direction" ) ) ); slotManagerChanged( static_cast( sm ) ); return true; } return false; } QVariant ScheduleItemModel::scheduler( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager( index ); if ( sm == 0 ) { return QVariant(); } SchedulerPlugin *pl = sm->schedulerPlugin(); if ( pl ) { switch ( role ) { case Qt::EditRole: return sm->schedulerPluginId(); case Qt::DisplayRole: return pl ? pl->name() : i18n( "Unknown" ); case Qt::ToolTipRole: return pl ? pl->comment() : QString(); case Role::EnumList: return sm->schedulerPluginNames(); case Role::EnumListValue: return sm->schedulerPluginIndex(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: return QVariant(); case Qt::WhatsThisRole: { QString s = pl->description(); return s.isEmpty() ? QVariant() : QVariant( s ); } } } return QVariant(); } bool ScheduleItemModel::setScheduler( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager( index ); if ( sm != 0 ) { switch ( role ) { case Qt::EditRole: { emit executeCommand( new ModifyScheduleManagerSchedulerCmd( *sm, value.toInt(), kundo2_i18n( "Modify scheduler" ) ) ); return true; } } } return false; } QVariant ScheduleItemModel::isScheduled( const QModelIndex &index, int role ) const { ScheduleManager *sm = manager( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::EditRole: return sm->isScheduled(); case Qt::DisplayRole: return sm->isScheduled() ? i18n( "Scheduled" ) : i18n( "Not scheduled" ); case Qt::ToolTipRole: break; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ScheduleItemModel::granularity(const QModelIndex &index, int role) const { ScheduleManager *sm = manager( index ); if ( sm == 0 ) { return QVariant(); } switch ( role ) { case Qt::EditRole: case Role::EnumListValue: return qMin( sm->granularity(), sm->supportedGranularities().count() - 1 ); case Qt::DisplayRole: { QList lst = sm->supportedGranularities(); if ( lst.isEmpty() ) { return i18nc( "Scheduling granularity not supported", "None" ); } int idx = sm->granularity(); qulonglong g = idx < lst.count() ? lst[ idx ] : lst.last(); return KFormat().formatDuration( g ); } case Qt::ToolTipRole: { QList lst = sm->supportedGranularities(); if ( lst.isEmpty() ) { return xi18nc( "@info:tooltip", "Scheduling granularity not supported" ); } int idx = sm->granularity(); qulonglong g = idx < lst.count() ? lst[ idx ] : lst.last(); return xi18nc( "@info:tooltip", "Selected scheduling granularity: %1", KFormat().formatDuration( g ) ); } case Qt::TextAlignmentRole: return Qt::AlignRight; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::EnumList: { QStringList sl; KFormat format; foreach ( long unsigned int v, sm->supportedGranularities() ) { sl << format.formatDuration( v ); } return sl; } } return QVariant(); } bool ScheduleItemModel::setGranularity( const QModelIndex &index, const QVariant &value, int role ) { ScheduleManager *sm = manager( index ); if ( sm != 0 ) { switch ( role ) { case Qt::EditRole: { emit executeCommand( new ModifyScheduleManagerSchedulingGranularityCmd( *sm, value.toInt(), kundo2_i18n( "Modify scheduling granularity" ) ) ); return true; } } } return false; } QVariant ScheduleItemModel::data( const QModelIndex &index, int role ) const { //debugPlan<isScheduleManager( index.internalPointer() ) ) { o = static_cast( index.internalPointer() ); Q_ASSERT( o ); } return o; } void ScheduleItemModel::setFlat( bool flat ) { m_flat = flat; m_managerlist.clear(); if ( ! flat || m_project == 0 ) { return; } m_managerlist = m_project->allScheduleManagers(); } //-------------------------------------- ScheduleSortFilterModel::ScheduleSortFilterModel( QObject *parent ) : QSortFilterProxyModel( parent ) { } ScheduleSortFilterModel::~ScheduleSortFilterModel() { } ScheduleManager *ScheduleSortFilterModel::manager( const QModelIndex &index ) const { QModelIndex i = mapToSource( index ); const ScheduleItemModel *m = qobject_cast( i.model() ); return m == 0 ? 0 : m->manager( i ); } QVariant ScheduleSortFilterModel::data( const QModelIndex &index, int role ) const { QVariant v = QSortFilterProxyModel::data(index, role); if (role == Qt::DisplayRole && index.column() == ScheduleModel::ScheduleName) { QModelIndex state = index.sibling(index.row(), ScheduleModel::ScheduleState); if (state.data(Qt::EditRole).toString() != "Scheduled") { QString s = state.data(SpecialScheduleDisplayRole).toString(); return QString("%1 (%2)").arg(v.toString(), s); } } return v; } //-------------------------------------- ScheduleLogItemModel::ScheduleLogItemModel( QObject *parent ) : QStandardItemModel( parent ), m_project( 0 ), m_manager( 0 ), m_schedule( 0 ) { } ScheduleLogItemModel::~ScheduleLogItemModel() { } void ScheduleLogItemModel::slotScheduleManagerToBeRemoved( const ScheduleManager *manager ) { if ( m_manager == manager ) { setManager( 0 ); } } void ScheduleLogItemModel::slotScheduleManagerRemoved( const ScheduleManager *manager ) { debugPlan<name(); } void ScheduleLogItemModel::slotScheduleToBeInserted( const ScheduleManager *manager, int row ) { Q_UNUSED(manager); Q_UNUSED(row); if ( m_manager && m_manager->expected() /*== ??*/ ) { //TODO } } //FIXME remove const on MainSchedule void ScheduleLogItemModel::slotScheduleInserted( const MainSchedule *sch ) { debugPlan<manager() && sch == m_manager->expected() ) { m_schedule = const_cast( sch ); refresh(); } } void ScheduleLogItemModel::slotScheduleToBeRemoved( const MainSchedule *sch ) { debugPlan<"<"<expected(); refresh(); connect(m_manager, &ScheduleManager::logInserted, this, &ScheduleLogItemModel::slotLogInserted); } } } void ScheduleLogItemModel::slotLogInserted( MainSchedule *s, int firstrow, int lastrow ) { for ( int i = firstrow; i <= lastrow; ++i ) { addLogEntry( s->logs().value( i ), i + 1 ); } } //FIXME: This only add logs (insert is not used atm) void ScheduleLogItemModel::addLogEntry( const Schedule::Log &log, int /*row*/ ) { // debugPlan< lst; if ( log.resource ) { lst.append( new QStandardItem( log.resource->name() ) ); } else if ( log.node ) { lst.append( new QStandardItem( log.node->name() ) ); } else { lst.append( new QStandardItem( "" ) ); } lst.append( new QStandardItem( m_schedule->logPhase( log.phase ) ) ); QStandardItem *item = new QStandardItem( m_schedule->logSeverity( log.severity ) ); item->setData( log.severity, SeverityRole ); lst.append( item ); lst.append( new QStandardItem( log.message ) ); foreach ( QStandardItem *itm, lst ) { if ( log.resource ) { itm->setData( log.resource->id(), IdentityRole ); } else if ( log.node ) { itm->setData( log.node->id(), IdentityRole ); } switch ( log.severity ) { case Schedule::Log::Type_Debug: itm->setData( QColor(Qt::darkYellow), Qt::ForegroundRole ); break; case Schedule::Log::Type_Info: break; case Schedule::Log::Type_Warning: itm->setData( QColor(Qt::blue), Qt::ForegroundRole ); break; case Schedule::Log::Type_Error: itm->setData( QColor(Qt::red), Qt::ForegroundRole ); break; default: break; } } appendRow( lst ); // debugPlan<<"added:"<logs().count(); int i = 1; foreach ( const Schedule::Log &l, m_schedule->logs() ) { addLogEntry( l, i++ ); } } QString ScheduleLogItemModel::identity( const QModelIndex &idx ) const { QStandardItem *itm = itemFromIndex( idx ); return itm ? itm->data( IdentityRole ).toString() : QString(); } void ScheduleLogItemModel::slotManagerChanged( ScheduleManager *manager ) { debugPlan< * Copyright (C) 2011, 2012 Dag Andersen * Copyright (C) 2019 Dag Andersen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "kptaccountseditor.h" #include "kptcommand.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptaccount.h" #include "kptdatetime.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { AccountseditorConfigDialog::AccountseditorConfigDialog( ViewBase *view, AccountTreeView *treeview, QWidget *p, bool selectPrint) : KPageDialog(p), m_view( view ), m_treeview( treeview ) { setWindowTitle( i18n("Settings") ); QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_headerfooter = ViewBase::createHeaderFooterWidget( view ); m_headerfooter->setOptions( view->printingOptions() ); tab->addTab( m_headerfooter, m_headerfooter->windowTitle() ); KPageWidgetItem *page = addPage( tab, i18n( "Printing" ) ); page->setHeader( i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, &QDialog::accepted, this, &AccountseditorConfigDialog::slotOk); } void AccountseditorConfigDialog::slotOk() { debugPlan; m_view->setPageLayout( m_pagelayout->pageLayout() ); m_view->setPrintingOptions( m_headerfooter->options() ); } //-------------------- AccountTreeView::AccountTreeView( QWidget *parent ) : TreeViewBase( parent ) { setDragPixmap(koIcon("account").pixmap(32)); header()->setContextMenuPolicy( Qt::CustomContextMenu ); setModel( new AccountItemModel( this ) ); setSelectionModel( new QItemSelectionModel( model() ) ); setSelectionMode( QAbstractItemView::ExtendedSelection ); // setSelectionBehavior( QAbstractItemView::SelectRows ); connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) ); } void AccountTreeView::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlan<logicalIndexAt(pos)<<" at"<pos()), event->globalPos() ); } void AccountTreeView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel ) { debugPlan<selectedIndexes() ) { debugPlan<selectedIndexes() ); } void AccountTreeView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) { debugPlan; QTreeView::currentChanged( current, previous ); emit currentChanged( current ); // possible bug in qt: in QAbstractItemView::SingleSelection you can select multiple items/rows selectionModel()->select( current, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); } Account *AccountTreeView::currentAccount() const { return model()->account( currentIndex() ); } Account *AccountTreeView::selectedAccount() const { QModelIndexList lst = selectionModel()->selectedRows(); if ( lst.count() == 1 ) { return model()->account( lst.first() ); } return 0; } QList AccountTreeView::selectedAccounts() const { QList lst; foreach ( const QModelIndex &i, selectionModel()->selectedRows() ) { Account *a = model()->account( i ); if ( a ) { lst << a; } } return lst; } //----------------------------------- AccountsEditor::AccountsEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { if (doc && doc->isReadWrite()) { setXMLFile("AccountsEditorUi.rc"); } else { setXMLFile("AccountsEditorUi_readonly.rc"); } setupGui(); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new AccountTreeView( this ); connect(this, &ViewBase::expandAll, m_view, &TreeViewBase::slotExpand); connect(this, &ViewBase::collapseAll, m_view, &TreeViewBase::slotCollapse); l->addWidget( m_view ); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode(QAbstractItemView::DragOnly); m_view->setDropIndicatorShown( false ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( false ); m_view->setAcceptDropsOnView( false ); connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); connect( m_view, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); Help::add(this, xi18nc("@info:whatsthis", "Cost Breakdown Structure Editor" "" "The Cost Breakdown Structure (CBS) consists of accounts" " organized into a tree structure." " Accounts can be tied to tasks or resources." " Usually there will be two top accounts, one for aggregating costs from tasks" " and one for aggregating costs from resources." "" "This view supports printing using the context menu." "More..." "", Help::page("Manual/Cost_Breakdown_Structure_Editor"))); } void AccountsEditor::updateReadWrite( bool readwrite ) { m_view->setReadWrite( readwrite ); } void AccountsEditor::draw( Project &project ) { m_view->setProject( &project ); } void AccountsEditor::draw() { } void AccountsEditor::setGuiActive( bool activate ) { debugPlan<currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } slotSelectionChanged( m_view->selectionModel()->selectedRows() ); } } void AccountsEditor::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { debugPlan<setContextMenuIndex(index); slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); } void AccountsEditor::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlan; QList lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } Account *AccountsEditor::currentAccount() const { return m_view->currentAccount(); } void AccountsEditor::slotCurrentChanged( const QModelIndex &curr ) { debugPlan< lst = m_view->selectedAccounts(); bool one = lst.count() == 1; bool more = lst.count() > 1; actionAddAccount->setEnabled( on && !more ); actionAddSubAccount->setEnabled( on && one ); bool baselined = project() ? project()->isBaselined() : false; actionDeleteSelection->setEnabled( on && one && ! baselined ); } void AccountsEditor::setupGui() { - actionAddAccount = new QAction(koIcon("document-new"), i18n("Add Account"), this); + actionAddAccount = new QAction(koIcon("document-new"), xi18nc("@action:inmenu", "Add Account"), this); actionCollection()->addAction("add_account", actionAddAccount ); actionCollection()->setDefaultShortcut(actionAddAccount, Qt::CTRL + Qt::Key_I); connect( actionAddAccount, &QAction::triggered, this, &AccountsEditor::slotAddAccount ); - actionAddSubAccount = new QAction(koIcon("document-new"), i18n("Add Subaccount"), this); + actionAddSubAccount = new QAction(koIcon("document-new"), xi18nc("@action:inmenu", "Add Subaccount"), this); actionCollection()->addAction("add_subaccount", actionAddSubAccount ); actionCollection()->setDefaultShortcut(actionAddSubAccount, Qt::SHIFT + Qt::CTRL + Qt::Key_I); connect( actionAddSubAccount, &QAction::triggered, this, &AccountsEditor::slotAddSubAccount ); - actionDeleteSelection = new QAction(koIcon("edit-delete"), i18nc("@action", "Delete"), this); + actionDeleteSelection = new QAction(koIcon("edit-delete"), xi18nc("@action:inmenu", "Delete"), this); actionCollection()->addAction("delete_selection", actionDeleteSelection ); actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete); connect( actionDeleteSelection, &QAction::triggered, this, &AccountsEditor::slotDeleteSelection ); createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionPrint | ViewBase::OptionPrintPreview | ViewBase::OptionPrintPdf | ViewBase::OptionPrintConfig); } void AccountsEditor::slotOptions() { debugPlan; AccountseditorConfigDialog *dlg = new AccountseditorConfigDialog( this, m_view, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->open(); } void AccountsEditor::slotAddAccount() { debugPlan; int row = -1; Account *parent = m_view->selectedAccount(); // sibling if ( parent ) { row = parent->parent() ? parent->parent()->indexOf( parent ) : project()->accounts().indexOf( parent ); if ( row >= 0 ) { ++row; } parent = parent->parent(); } insertAccount( new Account(), parent, row ); } void AccountsEditor::slotAddSubAccount() { debugPlan; insertAccount( new Account(), m_view->selectedAccount(), -1 ); } void AccountsEditor::insertAccount( Account *account, Account *parent, int row ) { m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); QModelIndex i = m_view->model()->insertAccount( account, parent, row ); if ( i.isValid() ) { QModelIndex p = m_view->model()->parent( i ); if (parent) debugPlan<<" parent="<name()<<":"<setExpanded( p, true ); } m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); } } void AccountsEditor::slotDeleteSelection() { debugPlan; m_view->model()->removeAccounts( m_view->selectedAccounts() ); } void AccountsEditor::slotAccountsOk() { debugPlan<<"Account Editor : slotAccountsOk"; //QModelList //QModelIndex i = m_view->model()->insertGroup( g ); } KoPrintJob *AccountsEditor::createPrintJob() { return m_view->createPrintJob( this ); } bool AccountsEditor::loadContext(const KoXmlElement &context) { m_view->loadContext(model()->columnMap(), context); return true; } void AccountsEditor::saveContext(QDomElement &context) const { m_view->saveContext(model()->columnMap(), context); } void AccountsEditor::slotEditCopy() { m_view->editCopy(); } } // namespace KPlato diff --git a/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp b/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp index c6129b45..b9e99509 100644 --- a/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp +++ b/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp @@ -1,560 +1,560 @@ /* This file is part of the KDE project Copyright (C) 2017 Dag Andersen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "ReportsGeneratorView.h" #include "reportgenerator/ReportGenerator.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { #define FULLPATHROLE Qt::UserRole + 123 class TemplateFileDelegate : public QStyledItemDelegate { public: TemplateFileDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; QMap files; }; TemplateFileDelegate::TemplateFileDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *TemplateFileDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option) Q_UNUSED(index); return new QComboBox(parent); } void TemplateFileDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); debugPlan<setEditable(true); cb->addItems(files.keys()); QString file = index.data().toString(); cb->setCurrentText(file); } void TemplateFileDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); debugPlan<currentText(); debugPlan<<"template file:"<setData(index, nfile); if (files.contains(nfile)) { nfile = files[nfile].url(); } model->setData(index, nfile, FULLPATHROLE); model->setData(index, nfile, Qt::ToolTipRole); } } else debugPlan<<" No combo box editor!!"; } class FileItemDelegate : public QStyledItemDelegate { public: FileItemDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; QMap files; }; FileItemDelegate::FileItemDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *FileItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); KUrlRequester *u = new KUrlRequester(parent); u->setMode(KFile::File); return u; } void FileItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { KUrlRequester *u = qobject_cast(editor); QString file = index.data().toString(); if (!file.isEmpty()) { u->setUrl(QUrl(file)); } } void FileItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { KUrlRequester *u = qobject_cast(editor); if (u && index.isValid()) { model->setData(index, u->url().url()); } } class FileNameExtensionDelegate : public QStyledItemDelegate { public: FileNameExtensionDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void setEditorData(QWidget *editor, const QModelIndex &index) const override; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; }; FileNameExtensionDelegate::FileNameExtensionDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *FileNameExtensionDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); QComboBox *cb = new QComboBox(parent); for (int i = 0; i < ReportsGeneratorView::addOptions().count(); ++i) { cb->addItem(ReportsGeneratorView::addOptions().at(i), ReportsGeneratorView::addTags().value(i)); } return cb; } void FileNameExtensionDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); if (cb) { int idx = ReportsGeneratorView::addTags().indexOf(index.data(Qt::UserRole).toString()); cb->setCurrentIndex(idx < 0 ? 0 : idx); } } void FileNameExtensionDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *cb = qobject_cast(editor); if (cb && index.isValid()) { model->setData(index, cb->currentData(), Qt::UserRole); model->setData(index, cb->currentText()); } } QStringList ReportsGeneratorView::addOptions() { return QStringList() << i18n("Nothing") << i18n("Date") << i18n("Number"); } QStringList ReportsGeneratorView::addTags() { return QStringList() << "Nothing" << "Date" << "Number"; } ReportsGeneratorView::ReportsGeneratorView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { debugPlan<<"----------------- Create ReportsGeneratorView ----------------------"; if (doc && doc->isReadWrite()) { setXMLFile("ReportsGeneratorViewUi.rc"); } else { setXMLFile("ReportsGeneratorViewUi_readonly.rc"); } QVBoxLayout * l = new QVBoxLayout(this); l->setMargin(0); m_view = new QTreeView(this); QStandardItemModel *m = new QStandardItemModel(m_view); m->setHorizontalHeaderLabels(QStringList() << i18n("Name") << i18n("Report Template") << i18n("Report File") << i18n("Add")); m->setHeaderData(0, Qt::Horizontal, xi18nc("@info:tooltip", "Report name"), Qt::ToolTipRole); m->setHeaderData(1, Qt::Horizontal, xi18nc("@info:tooltip", "Report template file name"), Qt::ToolTipRole); m->setHeaderData(2, Qt::Horizontal, xi18nc("@info:tooltip", "Name of the generated report file"), Qt::ToolTipRole); m->setHeaderData(3, Qt::Horizontal, xi18nc("@info:tooltip", "Information added to filename"), Qt::ToolTipRole); m_view->setModel(m); m_view->setContextMenuPolicy(Qt::CustomContextMenu); m_view->setRootIsDecorated(false); m_view->setAlternatingRowColors(true); updateReadWrite(doc && doc->isReadWrite()); connect(m_view, &QWidget::customContextMenuRequested, this, &ReportsGeneratorView::slotContextMenuRequested); l->addWidget(m_view); TemplateFileDelegate *del = new TemplateFileDelegate(m_view); QString path = QStandardPaths::locate(QStandardPaths::AppDataLocation, "reports", QStandardPaths::LocateDirectory); debugPlan<<"standardpath:"<files.insert(url.fileName(), url); } } m_view->setItemDelegateForColumn(1, del); m_view->setItemDelegateForColumn(2, new FileItemDelegate(m_view)); m_view->setItemDelegateForColumn(3, new FileNameExtensionDelegate(m_view)); m_view->header()->setSectionResizeMode(3, QHeaderView::Fixed); m_view->header()->resizeSection(3, 12); connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ReportsGeneratorView::slotSelectionChanged); setupGui(); Help::add(this, xi18nc("@info:whatsthis", "Add and generate reports" "" "Enables you to add and generate reports based on Open Document (.odf) files." "" "You can create a report template using any Open Document text editor." "More..." "", Help::page("Manual/Reports_Generator_View"))); } void ReportsGeneratorView::updateReadWrite(bool rw) { QStandardItemModel *m = static_cast(m_view->model()); for (int r = 0; r < m->rowCount(); ++r) { for (int c = 0; c < m->columnCount(); ++c) { QStandardItem *item = m->itemFromIndex(m->index(r, c)); if (rw) { item->setFlags(item->flags() | Qt::ItemIsEditable); } else { item->setFlags(item->flags() & ~Qt::ItemIsEditable); } } } ViewBase::updateReadWrite(rw); } void ReportsGeneratorView::setGuiActive(bool activate) { debugPlan<selectionModel()->selectedRows(); } int ReportsGeneratorView::selectedRowCount() const { return selectedRows().count(); } void ReportsGeneratorView::slotContextMenuRequested(const QPoint& pos) { debugPlan; emit requestPopupMenu("reportsgeneratorview_popup", m_view->mapToGlobal(pos)); } void ReportsGeneratorView::slotEnableActions() { updateActionsEnabled(isReadWrite()); } void ReportsGeneratorView::updateActionsEnabled(bool on) { actionAddReport->setEnabled(on); actionRemoveReport->setEnabled(on && selectedRowCount() > 0); actionGenerateReport->setEnabled(on && selectedRowCount() > 0); } void ReportsGeneratorView::setupGui() { KActionCollection *coll = actionCollection(); actionAddReport = new QAction(koIcon("list-add"), i18n("Add Report"), this); coll->addAction("add_report", actionAddReport); coll->setDefaultShortcut(actionAddReport, Qt::CTRL + Qt::Key_I); connect(actionAddReport, &QAction::triggered, this, &ReportsGeneratorView::slotAddReport); addContextAction(actionAddReport); actionRemoveReport = new QAction(koIcon("list-remove"), i18n("Remove Report"), this); coll->addAction("remove_report", actionRemoveReport); coll->setDefaultShortcut(actionRemoveReport, Qt::CTRL + Qt::Key_D); connect(actionRemoveReport, &QAction::triggered, this, &ReportsGeneratorView::slotRemoveReport); addContextAction(actionRemoveReport); actionGenerateReport = new QAction(koIcon("document-export"), i18n("Generate Report"), this); coll->addAction("generate_report", actionGenerateReport); coll->setDefaultShortcut(actionGenerateReport, Qt::CTRL + Qt::Key_G); connect(actionGenerateReport, &QAction::triggered, this, &ReportsGeneratorView::slotGenerateReport); addContextAction(actionGenerateReport); // createOptionAction(); } void ReportsGeneratorView::slotOptions() { debugPlan; // SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog(this, m_view, this); // dlg->addPrintingOptions(); // connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); // dlg->show(); // dlg->raise(); // dlg->activateWindow(); } void ReportsGeneratorView::slotAddReport() { debugPlan; QAbstractItemModel *m = m_view->model(); int row = m->rowCount(); m->insertRow(row); QModelIndex idx = m->index(row, 0); m->setData(idx, i18n("New report")); QModelIndex add = m->index(row, 3); m->setData(add, ReportsGeneratorView::addOptions().at(0)); m->setData(add, ReportsGeneratorView::addTags().at(0), Qt::UserRole); m_view->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); m_view->edit(idx); emit optionsModified(); } void ReportsGeneratorView::slotRemoveReport() { debugPlan<model(); QModelIndexList lst = selectedRows(); if (lst.isEmpty()) { return; } // Assumption: model is flat // We must do this in descending row order QMap map; for (int i = 0; i < lst.count(); ++i) { map.insert(-lst.at(i).row(), lst.at(i)); // sort descending } for (const QModelIndex &idx : map) { Q_ASSERT(!idx.parent().isValid()); // must be flat m->removeRow(idx.row(), idx.parent()); } emit optionsModified(); } void ReportsGeneratorView::slotGenerateReport() { debugPlan; QAbstractItemModel *model = m_view->model(); foreach(const QModelIndex &idx, selectedRows()) { QString name = model->index(idx.row(), 0).data().toString(); QString tmp = model->index(idx.row(), 1).data(FULLPATHROLE).toString(); QString file = model->index(idx.row(), 2).data().toString(); if (tmp.isEmpty()) { QMessageBox::information(this, xi18nc("@title:window", "Generate Report"), i18n("Failed to generate %1." "\nTemplate file name is empty.", name)); continue; } if (file.isEmpty()) { debugPlan<<"No files for report:"<index(idx.row(), 3).data(Qt::UserRole).toString(); if (addition == "Date") { int dotpos = file.lastIndexOf('.'); QString date = QDate::currentDate().toString(); file = file.insert(dotpos, date.prepend('-')); } else if (addition == "Number") { int dotpos = file.lastIndexOf('.'); QString fn = file; for (int i = 1; QFile::exists(fn); ++i) { fn = file.insert(dotpos, QString::number(i).prepend('-')); } file = fn; } // warn if file exists if (QFile::exists(QUrl(file).path())) { if (QMessageBox::question(this, i18n("Report Generation"), i18n("File exists. Continue?")) == QMessageBox::No) { return; } } generateReport(tmp, file); } } bool ReportsGeneratorView::generateReport(const QString &templateFile, const QString &file) { ReportGenerator rg; rg.setReportType("odt"); // TODO: handle different report types rg.setTemplateFile(templateFile); rg.setReportFile(file); rg.setProject(project()); rg.setScheduleManager(scheduleManager()); if (!rg.open()) { debugPlan<<"Failed to open report generator"; QMessageBox::warning(this, i18n("Failed to open report generator"), rg.lastError()); return false; } if (!rg.createReport()) { QMessageBox::warning(this, i18n("Failed to create report"), rg.lastError()); return false; } - if (QMessageBox::question(this, i18nc("@title", "Report Generation"), i18nc("@info", "Report file generated:%1", file), QMessageBox::Open|QMessageBox::Close, QMessageBox::Close) == QMessageBox::Open) { + if (QMessageBox::question(this, xi18nc("@title:window", "Report Generation"), xi18nc("@info", "Report file generated:%1", file), QMessageBox::Open|QMessageBox::Close, QMessageBox::Close) == QMessageBox::Open) { return KRun::runUrl(QUrl(file), "application/vnd.oasis.opendocument.text", window(), (KRun::RunFlags)0); } return true; } bool ReportsGeneratorView::loadContext(const KoXmlElement &context) { debugPlan; m_view->header()->setStretchLastSection((bool)(context.attribute("stretch-last-column", "1").toInt())); KoXmlElement e = context.namedItem("sections").toElement(); if (!e.isNull()) { QHeaderView *h = m_view->header(); QString s("section-%1"); for (int i = 0; i < h->count(); ++i) { if (e.hasAttribute(s.arg(i))) { int index = e.attribute(s.arg(i), "-1").toInt(); if (index >= 0 && index < h->count()) { h->moveSection(h->visualIndex(index), i); } } } } KoXmlElement parent = context.namedItem("data").toElement(); if (!parent.isNull()) { debugPlan<<"Load data"; int row = 0; QAbstractItemModel *model = m_view->model(); forEachElement(e, parent) { if (e.tagName() != "row") { continue; } model->insertRow(row); QString name = e.attribute("name"); QString tmp = e.attribute("template"); QString file = e.attribute("file"); QString add = e.attribute("add"); QModelIndex idx = model->index(row, 0); model->setData(idx, name); idx = model->index(row, 1); model->setData(idx, tmp, FULLPATHROLE); model->setData(idx, tmp, Qt::ToolTipRole); model->setData(idx, QUrl(tmp).fileName()); idx = model->index(row, 2); model->setData(idx, file); idx = model->index(row, 3); model->setData(idx, add, Qt::UserRole); model->setData(idx, ReportsGeneratorView::addOptions().value(ReportsGeneratorView::addTags().indexOf(add))); ++row; } } ViewBase::loadContext(context); for (int c = 0; c < m_view->header()->count(); ++c) { m_view->resizeColumnToContents(c); } updateReadWrite(isReadWrite()); return true; } void ReportsGeneratorView::saveContext(QDomElement &context) const { debugPlan; context.setAttribute( "stretch-last-column", QString::number(m_view->header()->stretchLastSection()) ); QDomElement e = context.ownerDocument().createElement("sections"); context.appendChild(e); QHeaderView *h = m_view->header(); for (int i = 0; i < h->count(); ++i) { e.setAttribute(QString("section-%1").arg(i), h->logicalIndex(i)); } QDomElement data = context.ownerDocument().createElement("data"); context.appendChild(data); const QAbstractItemModel *model = m_view->model(); for (int row = 0; row < model->rowCount(); ++row) { e = data.ownerDocument().createElement("row"); data.appendChild(e); QModelIndex idx = model->index(row, 0); e.setAttribute("name", idx.data().toString()); idx = model->index(row, 1); e.setAttribute("template", idx.data(FULLPATHROLE).toString()); idx = model->index(row, 2); e.setAttribute("file", idx.data().toString()); idx = model->index(row, 3); e.setAttribute("add", idx.data(Qt::UserRole).toString()); } ViewBase::saveContext(context); } } // namespace KPlato diff --git a/src/plugins/schedulers/tj/PlanTJPlugin.cpp b/src/plugins/schedulers/tj/PlanTJPlugin.cpp index 611917c1..b518a279 100644 --- a/src/plugins/schedulers/tj/PlanTJPlugin.cpp +++ b/src/plugins/schedulers/tj/PlanTJPlugin.cpp @@ -1,168 +1,168 @@ /* This file is part of the KDE project * Copyright (C) 2009, 2011 Dag Andersen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "PlanTJPlugin.h" #include "kptschedulerplugin_macros.h" #include "PlanTJScheduler.h" #include "kptproject.h" #include "kptschedule.h" #include "kptdebug.h" #include #include #ifndef PLAN_NOPLUGIN PLAN_SCHEDULERPLUGIN_EXPORT(PlanTJPlugin, "plantjscheduler.json") #endif using namespace KPlato; PlanTJPlugin::PlanTJPlugin( QObject * parent, const QVariantList & ) : KPlato::SchedulerPlugin(parent) { m_granularities << (long unsigned int) 5 * 60 * 1000 << (long unsigned int) 15 * 60 * 1000 << (long unsigned int) 30 * 60 * 1000 << (long unsigned int) 60 * 60 * 1000; } PlanTJPlugin::~PlanTJPlugin() { } QString PlanTJPlugin::description() const { - return i18nc( "@info:whatsthis", "TaskJuggler Scheduler" + return xi18nc( "@info:whatsthis", "TaskJuggler Scheduler" "This is a slightly modified version of the scheduler used in TaskJuggler." " It has been enhanced to handle resource units." "Scheduling backwards is simulated by scheduling all tasks as late as possible." "Plan does not utilize all of its functionality." ); } int PlanTJPlugin::capabilities() const { return SchedulerPlugin::AvoidOverbooking | SchedulerPlugin::ScheduleForward | SchedulerPlugin::ScheduleBackward; } ulong PlanTJPlugin::currentGranularity() const { ulong v = m_granularities.value( m_granularity ); return qMax( v, (ulong)300000 ); // minimum 5 min } void PlanTJPlugin::calculate( KPlato::Project &project, KPlato::ScheduleManager *sm, bool nothread ) { foreach ( SchedulerThread *j, m_jobs ) { if ( j->manager() == sm ) { return; } } sm->setScheduling( true ); PlanTJScheduler *job = new PlanTJScheduler( &project, sm, currentGranularity() ); m_jobs << job; connect(job, &KPlato::SchedulerThread::jobFinished, this, &PlanTJPlugin::slotFinished); project.changed( sm ); connect(this, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*)), &project, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*))); connect(this, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*)), &project, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*))); connect(job, &KPlato::SchedulerThread::maxProgressChanged, sm, &KPlato::ScheduleManager::setMaxProgress); connect(job, &KPlato::SchedulerThread::progressChanged, sm, &KPlato::ScheduleManager::setProgress); if ( nothread ) { job->doRun(); } else { job->start(); } } void PlanTJPlugin::stopAllCalculations() { foreach ( SchedulerThread *s, m_jobs ) { stopCalculation( s ); } } void PlanTJPlugin::stopCalculation( SchedulerThread *sch ) { if ( sch ) { //FIXME: this should just call stopScheduling() and let the job finish "normally" disconnect( sch, &KPlato::SchedulerThread::jobFinished, this, &PlanTJPlugin::slotFinished ); sch->stopScheduling(); // wait max 20 seconds. sch->mainManager()->setCalculationResult( ScheduleManager::CalculationStopped ); if ( ! sch->wait( 20000 ) ) { sch->deleteLater(); m_jobs.removeAt( m_jobs.indexOf( sch ) ); } else { slotFinished( sch ); } } } void PlanTJPlugin::slotStarted( SchedulerThread *job ) { // debugPlan<<"PlanTJPlugin::slotStarted:"; emit sigCalculationStarted(job->mainProject(), job->mainManager()); } void PlanTJPlugin::slotFinished( SchedulerThread *j ) { PlanTJScheduler *job = static_cast( j ); Project *mp = job->mainProject(); ScheduleManager *sm = job->mainManager(); //debugPlan<<"PlanTJPlugin::slotFinished:"<isStopped(); if ( job->isStopped() ) { sm->setCalculationResult( ScheduleManager::CalculationCanceled ); } else { updateLog( job ); if ( job->result > 0 ) { sm->setCalculationResult( ScheduleManager::CalculationError ); } else { Project *tp = job->project(); ScheduleManager *tm = job->manager(); updateProject( tp, tm, mp, sm ); sm->setCalculationResult( ScheduleManager::CalculationDone ); } } sm->setScheduling( false ); m_jobs.removeAt( m_jobs.indexOf( job ) ); if ( m_jobs.isEmpty() ) { m_synctimer.stop(); } emit sigCalculationFinished( mp, sm ); disconnect(this, &PlanTJPlugin::sigCalculationStarted, mp, &KPlato::Project::sigCalculationStarted); disconnect(this, &PlanTJPlugin::sigCalculationFinished, mp, &KPlato::Project::sigCalculationFinished); job->deleteLater(); } #include "PlanTJPlugin.moc" diff --git a/src/workpackage/taskworkpackagemodel.cpp b/src/workpackage/taskworkpackagemodel.cpp index 81ad5dc6..839f1ce0 100644 --- a/src/workpackage/taskworkpackagemodel.cpp +++ b/src/workpackage/taskworkpackagemodel.cpp @@ -1,764 +1,764 @@ /* This file is part of the KDE project Copyright (C) 2009, 2011, 2012 Dag Andersen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // clazy:excludeall=qstring-arg #include "taskworkpackagemodel.h" #include "part.h" #include "workpackage.h" #include "kptglobal.h" #include "kptresource.h" #include "kptproject.h" #include "kpttask.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kpttaskcompletedelegate.h" #include #include #include #include #include #include #include #include "debugarea.h" using namespace KPlato; namespace KPlatoWork { TaskWorkPackageModel::TaskWorkPackageModel( Part *part, QObject *parent ) : ItemModelBase( parent ), m_part( part ) { m_packages = m_part->workPackages().values(); connect( part, &Part::workPackageAdded, this, &TaskWorkPackageModel::addWorkPackage ); connect( part, &Part::workPackageRemoved, this, &TaskWorkPackageModel::removeWorkPackage ); } Qt::ItemFlags TaskWorkPackageModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = QAbstractItemModel::flags( index ); flags &= ~( Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled ); Node *n = nodeForIndex( index ); if ( n == 0 ) { return flags; } if ( n->type() != Node::Type_Task && n->type() != Node::Type_Milestone ) { return flags; } Task *t = static_cast( n ); if ( ! t->completion().isStarted() ) { switch ( index.column() ) { case NodeActualStart: flags |= Qt::ItemIsEditable; break; case NodeCompleted: flags |= Qt::ItemIsEditable; break; default: break; } } else if ( ! t->completion().isFinished() ) { // task is running switch ( index.column() ) { case NodeActualFinish: case NodeCompleted: case NodeRemainingEffort: case NodeActualEffort: flags |= Qt::ItemIsEditable; break; default: break; } } return flags; } void TaskWorkPackageModel::slotNodeToBeInserted( Node *parent, int row ) { //debugPlanWork<name()<<"; "<parentNode()->name()<<"-->"<name(); endInsertRows(); } void TaskWorkPackageModel::slotNodeToBeRemoved( Node *node ) { //debugPlanWork<name(); int row = indexForNode( node ).row(); beginRemoveRows( indexForNode( node->parentNode() ), row, row ); } void TaskWorkPackageModel::slotNodeRemoved( Node */*node*/ ) { //debugPlanWork<name(); endRemoveRows(); } void TaskWorkPackageModel::slotNodeChanged( Node *node ) { if ( node == 0 || node->type() == Node::Type_Project ) { return; } int row = indexForNode( node ).row(); debugPlanWork<name()<parentNode() ), createIndex( row, columnCount()-1, node->parentNode() ) ); } void TaskWorkPackageModel::slotDocumentAdded( Node *node, Document */*doc*/, int row ) { QModelIndex parent = indexForNode( node ); if ( parent.isValid() ) { beginInsertRows( parent, row, row ); endInsertRows(); } } void TaskWorkPackageModel::slotDocumentRemoved( Node *node, Document */*doc*/, int row ) { QModelIndex parent = indexForNode( node ); if ( parent.isValid() ) { beginRemoveRows( parent, row, row ); endRemoveRows(); } } void TaskWorkPackageModel::slotDocumentChanged( Node *node, Document */*doc*/, int row ) { QModelIndex parent = indexForNode( node ); if ( parent.isValid() ) { emit dataChanged( index( row, 0, parent ), index( row, columnCount( parent ), parent ) ); } } void TaskWorkPackageModel::addWorkPackage( WorkPackage *package, int /*row*/ ) { int row = m_packages.count(); beginInsertRows( QModelIndex(), row, row ); m_packages.append(package); Project *project = package->project(); endInsertRows(); if ( project ) { connect( project, &KPlato::Project::nodeChanged, this, &TaskWorkPackageModel::slotNodeChanged ); connect( project, &KPlato::Project::nodeToBeAdded, this, &TaskWorkPackageModel::slotNodeToBeInserted ); connect( project, &KPlato::Project::nodeToBeRemoved, this, &TaskWorkPackageModel::slotNodeToBeRemoved ); connect( project, &KPlato::Project::nodeAdded, this, &TaskWorkPackageModel::slotNodeInserted ); connect( project, &KPlato::Project::nodeRemoved, this, &TaskWorkPackageModel::slotNodeRemoved ); connect(project, &KPlato::Project::documentAdded, this, &TaskWorkPackageModel::slotDocumentAdded); connect(project, &KPlato::Project::documentRemoved, this, &TaskWorkPackageModel::slotDocumentRemoved); connect(project, &KPlato::Project::documentChanged, this, &TaskWorkPackageModel::slotDocumentChanged); } } void TaskWorkPackageModel::removeWorkPackage( WorkPackage *package, int /*row*/ ) { int row = m_packages.indexOf(package); beginRemoveRows( QModelIndex(), row, row ); m_packages.removeAt(row); Project *project = package->project(); debugPlanWork<project(); if ( project ) { disconnect( project, &KPlato::Project::nodeChanged, this, &TaskWorkPackageModel::slotNodeChanged ); disconnect( project, &KPlato::Project::nodeToBeAdded, this, &TaskWorkPackageModel::slotNodeToBeInserted ); disconnect( project, &KPlato::Project::nodeToBeRemoved, this, &TaskWorkPackageModel::slotNodeToBeRemoved ); disconnect( project, &KPlato::Project::nodeAdded, this, &TaskWorkPackageModel::slotNodeInserted ); disconnect( project, &KPlato::Project::nodeRemoved, this, &TaskWorkPackageModel::slotNodeRemoved ); disconnect(project, &KPlato::Project::documentAdded, this, &TaskWorkPackageModel::slotDocumentAdded); disconnect(project, &KPlato::Project::documentRemoved, this, &TaskWorkPackageModel::slotDocumentRemoved); disconnect(project, &KPlato::Project::documentChanged, this, &TaskWorkPackageModel::slotDocumentChanged); } endRemoveRows(); } QVariant TaskWorkPackageModel::name( const Resource *r, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return r->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant TaskWorkPackageModel::email( const Resource *r, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return r->email(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant TaskWorkPackageModel::projectName( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: { const Node *proj = node->projectNode(); return proj == 0 ? QVariant() : proj->name(); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant TaskWorkPackageModel::projectManager( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: { const Node *proj = node->projectNode(); return proj == 0 ? QVariant() : proj->leader(); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } int TaskWorkPackageModel::rowCount( const QModelIndex &parent ) const { if ( ! parent.isValid() ) { //debugPlanWork<workPackageCount(); return m_packages.count(); // == no of nodes (1 node pr wp) } Node *n = nodeForIndex( parent ); if ( n ) { //debugPlanWork<documents().count(); return n->documents().count(); } //debugPlanWork<description(), nullptr); QString description = w.toPlainText(); if (description.length() > 200) { description = description.left(200) + " ..."; description.replace('\n', "
"); } else { description = n->description(); } w.setHtml(i18n("

%1: %2

%3

", wp->wbsCode(), n->name(), description)); return w.toHtml(); } if (role == Qt::DecorationRole && index.column() == NodeName) { WorkPackage *wp = workPackage(index.row()); if (wp->task()->completion().isFinished()) { return koIcon("checkmark"); } } return nodeData( n, index.column(), role ); } Document *doc = documentForIndex( index ); if ( doc ) { return documentData( doc, index.column(), role ); } return QVariant(); } QVariant TaskWorkPackageModel::actualStart( Node *n, int role ) const { QVariant v = m_nodemodel.startedTime( n, role ); if ( role == Qt::EditRole && ! v.toDateTime().isValid() ) { v = QDateTime::currentDateTime(); } return v; } QVariant TaskWorkPackageModel::actualFinish( Node *n, int role ) const { QVariant v = m_nodemodel.finishedTime( n, role ); if ( role == Qt::EditRole && ! v.toDateTime().isValid() ) { v = QDateTime::currentDateTime(); } return v; } QVariant TaskWorkPackageModel::plannedEffort( Node *n, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { Duration v = n->plannedEffort( CURRENTSCHEDULE, ECCT_EffortWork ); return v.format(); } default: break; } return QVariant(); } QVariant TaskWorkPackageModel::status( Node *n, int role ) const { return m_nodemodel.status( n, role ); } QVariant TaskWorkPackageModel::nodeData( Node *n, int column, int role ) const { if ( role >= Qt::UserRole ) { // debugPlanWork<name()<type() ) { case Node::Type_Task: return KGantt::TypeTask; default: break; } break; case KGantt::StartTimeRole: debugPlanWork<name()<<"start:"<startTime(); return m_nodemodel.data( n, NodeModel::NodeStartTime, Qt::EditRole ); case KGantt::EndTimeRole: debugPlanWork<name()<<"end:"<endTime(); return m_nodemodel.data( n, NodeModel::NodeEndTime, Qt::EditRole ); default: break; } } switch ( column ) { case NodeName: return m_nodemodel.data( n, NodeModel::NodeName, role ); case NodeType: return m_nodemodel.data( n, NodeModel::NodeType, role ); case NodeResponsible: return m_nodemodel.data( n, NodeModel::NodeResponsible, role ); case NodeDescription: return m_nodemodel.data( n, NodeModel::NodeDescription, role ); // After scheduling case NodeStartTime: return m_nodemodel.data( n, NodeModel::NodeStartTime, role ); case NodeEndTime: return m_nodemodel.data( n, NodeModel::NodeEndTime, role ); case NodeAssignments: return m_nodemodel.data( n, NodeModel::NodeAssignments, role ); // Completion case NodeCompleted: return m_nodemodel.data( n, NodeModel::NodeCompleted, role ); case NodeActualEffort: return m_nodemodel.data( n, NodeModel::NodeActualEffort, role ); case NodeRemainingEffort: return m_nodemodel.data( n, NodeModel::NodeRemainingEffort, role ); case NodePlannedEffort: return plannedEffort( n, role ); case NodeActualStart: return actualStart( n, role ); case NodeStarted: return m_nodemodel.data( n, NodeModel::NodeStarted, role ); case NodeActualFinish: return actualFinish( n, role ); case NodeFinished: return m_nodemodel.data( n, NodeModel::NodeFinished, role ); case NodeStatus: return status( n, role ); case NodeStatusNote: return m_nodemodel.data( n, NodeModel::NodeStatusNote, role ); case ProjectName: return projectName( n, role ); case ProjectManager: return projectManager( n, role ); default: //debugPlanWork<<"Invalid column number: "<url().fileName()<name(); case NodeType: return doc->typeToString( doc->type(), true ); case NodeStatusNote: return doc->status(); default: return ""; } } else if ( role == Qt::ToolTipRole ) { switch ( column ) { case NodeName: { QString s = xi18nc("@info:tooltip", "Type: %1Url: %2", doc->typeToString(doc->type(), true), doc->url().toDisplayString()); return s; } default: break; } } return QVariant(); } bool TaskWorkPackageModel::setCompletion( Node *node, const QVariant &value, int role ) { if ( role != Qt::EditRole ) { return false; } if ( node->type() == Node::Type_Task ) { Completion &c = static_cast( node )->completion(); QDate date = qMax( c.entryDate(), QDate::currentDate() ); QDateTime dt( date, QTime::currentTime() ); // xgettext: no-c-format MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify completion" ) ); if ( ! c.isStarted() ) { m->addCommand( new ModifyCompletionStartedCmd( c, true ) ); m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) ); } m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, value.toInt() ) ); if ( value.toInt() == 100 ) { m->addCommand( new ModifyCompletionFinishedCmd( c, true ) ); m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) ); } bool newentry = c.entryDate() < date; emit executeCommand( m ); // also adds a new entry if necessary if ( newentry ) { // new entry so calculate used/remaining based on completion Duration planned = static_cast( node )->plannedEffort( m_nodemodel.id() ); Duration actual = ( planned * value.toInt() ) / 100; debugPlanWork<execute(); m->addCommand( cmd ); cmd = new ModifyCompletionRemainingEffortCmd( c, date, planned - actual ); cmd->execute(); m->addCommand( cmd ); } else if ( c.isFinished() && c.remainingEffort() != 0 ) { ModifyCompletionRemainingEffortCmd *cmd = new ModifyCompletionRemainingEffortCmd( c, date, Duration::zeroDuration ); cmd->execute(); m->addCommand( cmd ); } return true; } if ( node->type() == Node::Type_Milestone ) { Completion &c = static_cast( node )->completion(); if ( value.toInt() > 0 ) { QDateTime dt = QDateTime::currentDateTime(); QDate date = dt.date(); MacroCommand *m = new MacroCommand( kundo2_i18n( "Set finished" ) ); m->addCommand( new ModifyCompletionStartedCmd( c, true ) ); m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionFinishedCmd( c, true ) ); m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, 100 ) ); emit executeCommand( m ); // also adds a new entry if necessary return true; } return false; } return false; } bool TaskWorkPackageModel::setRemainingEffort( Node *node, const QVariant &value, int role ) { if ( role == Qt::EditRole && node->type() == Node::Type_Task ) { Task *t = static_cast( node ); double d( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration dur( d, unit ); emit executeCommand( new ModifyCompletionRemainingEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify remaining effort" ) ) ); return true; } return false; } bool TaskWorkPackageModel::setActualEffort( Node *node, const QVariant &value, int role ) { if ( role == Qt::EditRole && node->type() == Node::Type_Task ) { Task *t = static_cast( node ); double d( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration dur( d, unit ); emit executeCommand( new ModifyCompletionActualEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify actual effort" ) ) ); return true; } return false; } bool TaskWorkPackageModel::setStartedTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Task *t = qobject_cast( node ); if ( t == 0 ) { return false; } MacroCommand *m = new MacroCommand( kundo2_noi18n(headerData( NodeModel::NodeActualStart, Qt::Horizontal, Qt::DisplayRole ).toString()) ); //FIXME: proper description when string freeze is lifted if ( ! t->completion().isStarted() ) { m->addCommand( new ModifyCompletionStartedCmd( t->completion(), true ) ); } m->addCommand( new ModifyCompletionStartTimeCmd( t->completion(), value.toDateTime() ) ); if ( t->type() == Node::Type_Milestone ) { m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) ); m->addCommand( new ModifyCompletionFinishTimeCmd( t->completion(), value.toDateTime() ) ); if ( t->completion().percentFinished() < 100 ) { Completion::Entry *e = new Completion::Entry( 100, Duration::zeroDuration, Duration::zeroDuration ); m->addCommand( new AddCompletionEntryCmd( t->completion(), value.toDate(), e ) ); } } emit executeCommand( m ); return true; } } return false; } bool TaskWorkPackageModel::setFinishedTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Task *t = qobject_cast( node ); if ( t == 0 ) { return false; } MacroCommand *m = new MacroCommand( kundo2_noi18n(headerData( NodeModel::NodeActualFinish, Qt::Horizontal, Qt::DisplayRole ).toString()) ); //FIXME: proper description when string freeze is lifted if ( ! t->completion().isFinished() ) { m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) ); if ( t->completion().percentFinished() < 100 ) { QDate lastdate = t->completion().entryDate(); if ( ! lastdate.isValid() || lastdate < value.toDate() ) { Completion::Entry *e = new Completion::Entry( 100, Duration::zeroDuration, Duration::zeroDuration ); m->addCommand( new AddCompletionEntryCmd( t->completion(), value.toDate(), e ) ); } else { Completion::Entry *e = new Completion::Entry( *( t->completion().entry( lastdate ) ) ); e->percentFinished = 100; m->addCommand( new ModifyCompletionEntryCmd( t->completion(), lastdate, e ) ); } } } m->addCommand( new ModifyCompletionFinishTimeCmd( t->completion(), value.toDateTime() ) ); if ( t->type() == Node::Type_Milestone ) { m->addCommand( new ModifyCompletionStartedCmd( t->completion(), true ) ); m->addCommand( new ModifyCompletionStartTimeCmd( t->completion(), value.toDateTime() ) ); } emit executeCommand( m ); return true; } } return false; } bool TaskWorkPackageModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } switch ( index.column() ) { case NodeCompleted: return setCompletion( nodeForIndex( index ), value, role ); case NodeRemainingEffort: return setRemainingEffort( nodeForIndex( index ), value, role ); case NodeActualEffort: return setActualEffort( nodeForIndex( index ), value, role ); case NodeActualStart: return setStartedTime( nodeForIndex( index ), value, role ); case NodeActualFinish: return setFinishedTime( nodeForIndex( index ), value, role ); default: break; } return false; } QVariant TaskWorkPackageModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Vertical ) { return section; } if ( role == Qt::DisplayRole ) { switch ( section ) { - case NodeName: return i18n( "Name" ); - case NodeType: return i18n( "Type" ); - case NodeResponsible: return i18n( "Responsible" ); - case NodeDescription: return i18n( "Description" ); + case NodeName: return xi18nc( "@title:column", "Name" ); + case NodeType: return xi18nc( "@title:column", "Type" ); + case NodeResponsible: return xi18nc( "@title:column", "Responsible" ); + case NodeDescription: return xi18nc( "@title:column", "Description" ); // After scheduling - case NodeStartTime: return i18n( "Planned Start" ); - case NodeEndTime: return i18n( "Planned Finish" ); - case NodeAssignments: return i18n( "Resource Assignments" ); + case NodeStartTime: return xi18nc( "@title:column", "Planned Start" ); + case NodeEndTime: return xi18nc( "@title:column", "Planned Finish" ); + case NodeAssignments: return xi18nc( "@title:column", "Resource Assignments" ); // Completion - case NodeCompleted: return i18n( "Completion" ); - case NodeActualEffort: return i18n( "Actual Effort" ); - case NodeRemainingEffort: return i18n( "Remaining Effort" ); - case NodePlannedEffort: return i18n( "Planned Effort" ); - case NodeActualStart: return i18n( "Actual Start" ); - case NodeStarted: return i18n( "Started" ); - case NodeActualFinish: return i18n( "Actual Finish" ); - case NodeFinished: return i18n( "Finished" ); - case NodeStatus: return i18nc( "@title:column", "Status" ); - case NodeStatusNote: return i18n( "Note" ); - - case ProjectName: return i18n( "Project Name" ); - case ProjectManager: return i18n( "Project Manager" ); + case NodeCompleted: return xi18nc( "@title:column", "Completion" ); + case NodeActualEffort: return xi18nc( "@title:column", "Actual Effort" ); + case NodeRemainingEffort: return xi18nc( "@title:column", "Remaining Effort" ); + case NodePlannedEffort: return xi18nc( "@title:column", "Planned Effort" ); + case NodeActualStart: return xi18nc( "@title:column", "Actual Start" ); + case NodeStarted: return xi18nc( "@title:column", "Started" ); + case NodeActualFinish: return xi18nc( "@title:column", "Actual Finish" ); + case NodeFinished: return xi18nc( "@title:column", "Finished" ); + case NodeStatus: return xi18nc( "@title:column", "Status" ); + case NodeStatusNote: return xi18nc( "@title:column", "Note" ); + + case ProjectName: return xi18nc( "@title:column", "Project Name" ); + case ProjectManager: return xi18nc( "@title:column", "Project Manager" ); default: //debugPlanWork<<"Invalid column number: "<node()->name(); return wp->node(); } return 0; } Document *TaskWorkPackageModel::documentForIndex( const QModelIndex &index ) const { if ( index.isValid() ) { Node *parent = ptrToNode( index ); if ( parent && index.row() < parent->documents().count() ) { //debugPlanWork<name(); return parent->documents().value( index.row() ); } } return 0; } QModelIndex TaskWorkPackageModel::indexForNode( Node *node ) const { WorkPackage *p = m_part->workPackage( node ); if ( p == 0 ) { return QModelIndex(); } return createIndex( m_packages.indexOf( p ), 0, p ); } WorkPackage *TaskWorkPackageModel::workPackage( int index ) const { return m_packages.value(index); } QAbstractItemDelegate *TaskWorkPackageModel::createDelegate( int column, QWidget *parent ) const { switch ( column ) { case NodeCompleted: return new TaskCompleteDelegate( parent ); case NodeRemainingEffort: return new DurationSpinBoxDelegate( parent ); case NodeActualEffort: return new DurationSpinBoxDelegate( parent ); case NodeActualStart: return new DateTimeCalendarDelegate( parent ); case NodeActualFinish: return new DateTimeCalendarDelegate( parent ); default: break; } return 0; } QModelIndex mapToModel(const TaskWorkPackageModel *m, const QModelIndex &indx) { if (indx.model() == m) { return indx; } QModelIndex idx = indx; const QAbstractProxyModel *proxy = qobject_cast(idx.model()); while (proxy) { idx = proxy->mapToSource(idx); proxy = qobject_cast(idx.model()); } return idx; } WorkPackage *TaskWorkPackageModel::ptrToWorkPackage( const QModelIndex &indx ) const { QModelIndex idx = mapToModel(this, indx); Q_ASSERT(idx.model() == this); return qobject_cast( static_cast( idx.internalPointer() ) ); } Node *TaskWorkPackageModel::ptrToNode( const QModelIndex &indx ) const { QModelIndex idx = mapToModel(this, indx); Q_ASSERT(idx.model() == this); return qobject_cast( static_cast( idx.internalPointer() ) ); } bool TaskWorkPackageModel::isNode( const QModelIndex &indx ) const { QModelIndex idx = mapToModel(this, indx); Q_ASSERT(idx.model() == this); // a node index: ptr is WorkPackage* return qobject_cast( static_cast( idx.internalPointer() ) ) != 0; } bool TaskWorkPackageModel::isDocument( const QModelIndex &indx ) const { QModelIndex idx = mapToModel(this, indx); Q_ASSERT(idx.model() == this); // a document index: ptr is Node* return qobject_cast( static_cast( idx.internalPointer() ) ) != 0; } } //namespace KPlato