diff --git a/src/ConfigProjectPanel.cpp b/src/ConfigProjectPanel.cpp index 33e02ac2..d631962e 100644 --- a/src/ConfigProjectPanel.cpp +++ b/src/ConfigProjectPanel.cpp @@ -1,111 +1,111 @@ /* 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. */ #include "ConfigProjectPanel.h" #include "calligraplansettings.h" #include #include namespace KPlato { ConfigProjectPanel::ConfigProjectPanel( QWidget *parent ) : ConfigProjectPanelImpl( parent ) { } //----------------------------- ConfigProjectPanelImpl::ConfigProjectPanelImpl(QWidget *p ) : QWidget(p) { setupUi(this); initDescription(); - connect(resourceFileBrowseBtn, SIGNAL(clicked()), this, SLOT(resourceFileBrowseBtnClicked())); - connect(projectsPlaceBrowseBtn, SIGNAL(clicked()), this, SLOT(projectsPlaceBrowseBtnClicked())); + connect(resourceFileBrowseBtn, &QAbstractButton::clicked, this, &ConfigProjectPanelImpl::resourceFileBrowseBtnClicked); + connect(projectsPlaceBrowseBtn, &QAbstractButton::clicked, this, &ConfigProjectPanelImpl::projectsPlaceBrowseBtnClicked); } void ConfigProjectPanelImpl::resourceFileBrowseBtnClicked() { QFileDialog dialog(this, tr("Shared resources file")); dialog.setFileMode(QFileDialog::AnyFile); dialog.setNameFilters(QStringList()<setText(dialog.selectedFiles().value(0)); } } void ConfigProjectPanelImpl::projectsPlaceBrowseBtnClicked() { QFileDialog dialog(this, tr("Shared projects place")); dialog.setFileMode(QFileDialog::Directory); if (dialog.exec()) { kcfg_SharedProjectsPlace->setText(dialog.directory().absolutePath()); } } void ConfigProjectPanelImpl::initDescription() { toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly ); KActionCollection *collection = new KActionCollection( this ); //krazy:exclude=tipsandthis kcfg_ProjectDescription->setRichTextSupport( KRichTextWidget::SupportBold | KRichTextWidget::SupportItalic | KRichTextWidget::SupportUnderline | KRichTextWidget::SupportStrikeOut | KRichTextWidget::SupportChangeListStyle | KRichTextWidget::SupportAlignment | KRichTextWidget::SupportFormatPainting ); collection->addActions(kcfg_ProjectDescription->createActions()); toolbar->addAction( collection->action( "format_text_bold" ) ); toolbar->addAction( collection->action( "format_text_italic" ) ); toolbar->addAction( collection->action( "format_text_underline" ) ); toolbar->addAction( collection->action( "format_text_strikeout" ) ); toolbar->addSeparator(); toolbar->addAction( collection->action( "format_list_style" ) ); toolbar->addSeparator(); toolbar->addAction( collection->action( "format_align_left" ) ); toolbar->addAction( collection->action( "format_align_center" ) ); toolbar->addAction( collection->action( "format_align_right" ) ); toolbar->addAction( collection->action( "format_align_justify" ) ); toolbar->addSeparator(); // toolbar->addAction( collection->action( "format_painter" ) ); kcfg_ProjectDescription->append( "" ); kcfg_ProjectDescription->setReadOnly( false ); kcfg_ProjectDescription->setOverwriteMode( false ); kcfg_ProjectDescription->setLineWrapMode( KTextEdit::WidgetWidth ); kcfg_ProjectDescription->setTabChangesFocus( true ); } } //KPlato namespace diff --git a/src/ConfigWorkVacationPanel.cpp b/src/ConfigWorkVacationPanel.cpp index d6ff096d..7a16c2ff 100644 --- a/src/ConfigWorkVacationPanel.cpp +++ b/src/ConfigWorkVacationPanel.cpp @@ -1,91 +1,91 @@ /* 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. */ #include "ConfigWorkVacationPanel.h" #include "calligraplansettings.h" #include #ifdef HAVE_KHOLIDAYS #include #endif #include namespace KPlato { ConfigWorkVacationPanel::ConfigWorkVacationPanel( QWidget *parent ) : ConfigWorkVacationPanelImpl( parent ) { } //----------------------------- ConfigWorkVacationPanelImpl::ConfigWorkVacationPanelImpl(QWidget *p ) : QWidget(p) { setupUi(this); kcfg_Region->hide(); #ifdef HAVE_KHOLIDAYS int idx = 0; const QString regionCode = kcfg_Region->text(); region->addItem(i18n("Default"), "Default"); foreach(const QString &s, KHolidays::HolidayRegion::regionCodes()) { region->addItem(KHolidays::HolidayRegion::name(s), s); int row = region->count() - 1; region->setItemData(row, KHolidays::HolidayRegion::description(s), Qt::ToolTipRole); if (s == regionCode) { idx = row; } } connect(region, SIGNAL(currentIndexChanged(int)), this, SLOT(slotRegionChanged(int))); - connect(kcfg_Region, SIGNAL(textChanged(QString)), this, SLOT(slotRegionCodeChanged(QString))); + connect(kcfg_Region, &QLineEdit::textChanged, this, &ConfigWorkVacationPanelImpl::slotRegionCodeChanged); region->setCurrentIndex(idx); #else holidaysWidget->hide(); #endif } #ifdef HAVE_KHOLIDAYS void ConfigWorkVacationPanelImpl::slotRegionChanged(int idx) { QString r = region->itemData(idx).toString(); if (r != kcfg_Region->text()) { kcfg_Region->setText(r); } } void ConfigWorkVacationPanelImpl::slotRegionCodeChanged(const QString &code) { QString r = region->itemData(region->currentIndex()).toString(); if (r != code) { for (int idx = 0; idx < region->count(); ++idx) { if (region->itemData(idx).toString() == code) { region->setCurrentIndex(idx); break; } } } } #endif } //KPlato namespace diff --git a/src/kptbuiltinschedulerplugin.cpp b/src/kptbuiltinschedulerplugin.cpp index 32db9e39..a0f669a2 100644 --- a/src/kptbuiltinschedulerplugin.cpp +++ b/src/kptbuiltinschedulerplugin.cpp @@ -1,177 +1,177 @@ /* This file is part of the KDE project Copyright (C) 2009 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 "kptbuiltinschedulerplugin.h" #include "kptproject.h" #include "kptschedule.h" #include "kptxmlloaderobject.h" #include namespace KPlato { BuiltinSchedulerPlugin::BuiltinSchedulerPlugin(QObject *parent) : SchedulerPlugin(parent) { setName( i18nc( "Network = task dependency network", "Network Scheduler" ) ); setComment( xi18nc( "@info:tooltip", "Built-in network (PERT) based scheduler" ) ); } BuiltinSchedulerPlugin::~BuiltinSchedulerPlugin() { } QString BuiltinSchedulerPlugin::description() const { return xi18nc( "@info:whatsthis", "Network (PERT) Scheduler" "The network scheduler generally schedules tasks according to their dependencies." " When a task is scheduled it is scheduled in full, booking the allocated resources if available." " If overbooking is not allowed, subsequent tasks that requests the same resource" " will be scheduled later in time." "Tasks with time constraints will be scheduled first to minimize the problem" " with resource conflicts" "This scheduler does not handle resource conflicts well." "You can try a different scheduler if available." " You may also change resource allocations or add dummy dependencies to avoid the conflicts." ); } void BuiltinSchedulerPlugin::calculate( Project &project, ScheduleManager *sm, bool nothread ) { KPlatoScheduler *job = new KPlatoScheduler( &project, sm ); m_jobs << job; - connect(job, SIGNAL(jobStarted(KPlato::SchedulerThread*)), SLOT(slotStarted(KPlato::SchedulerThread*))); - connect(job, SIGNAL(jobFinished(KPlato::SchedulerThread*)), SLOT(slotFinished(KPlato::SchedulerThread*))); + connect(job, &SchedulerThread::jobStarted, this, &BuiltinSchedulerPlugin::slotStarted); + connect(job, &SchedulerThread::jobFinished, this, &BuiltinSchedulerPlugin::slotFinished); // 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*))); sm->setScheduling( true ); if ( nothread ) { - connect(job, SIGNAL(maxProgressChanged(int)), sm, SLOT(setMaxProgress(int))); - connect(job, SIGNAL(progressChanged(int)), sm, SLOT(setProgress(int))); + connect(job, &SchedulerThread::maxProgressChanged, sm, &ScheduleManager::setMaxProgress); + connect(job, &SchedulerThread::progressChanged, sm, &ScheduleManager::setProgress); job->doRun(); } else { job->start(); } m_synctimer.start(); } void BuiltinSchedulerPlugin::slotStarted( SchedulerThread *job ) { qDebug()<<"BuiltinSchedulerPlugin::slotStarted:"<mainProject()<mainManager(); emit sigCalculationStarted( job->mainProject(), job->mainManager() ); } void BuiltinSchedulerPlugin::slotFinished( SchedulerThread *job ) { ScheduleManager *sm = job->mainManager(); Project *mp = job->mainProject(); qDebug()<<"BuiltinSchedulerPlugin::slotFinished:"<isStopped(); if ( job->isStopped() ) { sm->setCalculationResult( ScheduleManager::CalculationCanceled ); } else { updateLog( job ); Project *tp = static_cast( job )->project(); ScheduleManager *tm = static_cast( 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, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*)), mp, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*))); - disconnect(this, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*)), mp, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*))); + disconnect(this, &BuiltinSchedulerPlugin::sigCalculationStarted, mp, &Project::sigCalculationStarted); + disconnect(this, &BuiltinSchedulerPlugin::sigCalculationFinished, mp, &Project::sigCalculationFinished); job->deleteLater(); qDebug()<<"BuiltinSchedulerPlugin::slotFinished: <<<"; } //-------------------- KPlatoScheduler::KPlatoScheduler( Project *project, ScheduleManager *sm, QObject *parent ) : SchedulerThread( project, sm, parent) { qDebug()<<"KPlatoScheduler::KPlatoScheduler:"<name()<stopcalculation = true; } } void KPlatoScheduler::run() { if ( m_haltScheduling ) { deleteLater(); return; } if ( m_stopScheduling ) { return; } { // mutex --> m_projectMutex.lock(); m_managerMutex.lock(); m_project = new Project(); loadProject( m_project, m_pdoc ); m_project->setName( "Schedule: " + m_project->name() ); //Debug m_manager = m_project->scheduleManager( m_mainmanagerId ); Q_ASSERT( m_manager ); Q_ASSERT( m_manager->expected() ); Q_ASSERT( m_manager != m_mainmanager ); Q_ASSERT( m_manager->scheduleId() == m_mainmanager->scheduleId() ); Q_ASSERT( m_manager->expected() != m_mainmanager->expected() ); m_manager->setName( "Schedule: " + m_manager->name() ); //Debug m_managerMutex.unlock(); m_projectMutex.unlock(); } // <--- mutex connect(m_project, SIGNAL(maxProgress(int)), this, SLOT(setMaxProgress(int))); connect(m_project, SIGNAL(sigProgress(int)), this, SLOT(setProgress(int))); bool x = connect(m_manager, SIGNAL(sigLogAdded(KPlato::Schedule::Log)), this, SLOT(slotAddLog(KPlato::Schedule::Log))); Q_ASSERT( x ); Q_UNUSED( x ); m_project->calculate( *m_manager ); if ( m_haltScheduling ) { deleteLater(); } } } //namespace KPlato diff --git a/src/kptinsertfiledlg.cpp b/src/kptinsertfiledlg.cpp index 4919de29..c86fc252 100644 --- a/src/kptinsertfiledlg.cpp +++ b/src/kptinsertfiledlg.cpp @@ -1,129 +1,129 @@ /* This file is part of the KDE project Copyright (C) 20079 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 "kptinsertfiledlg.h" #include "kptnode.h" #include "kptproject.h" #include #include namespace KPlato { InsertFileDialog::InsertFileDialog( Project &project, Node *currentNode, QWidget *parent ) : KoDialog(parent) { setCaption( i18n("Insert File") ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); m_panel = new InsertFilePanel( project, currentNode, this ); setMainWidget( m_panel ); enableButtonOk(false); - connect( m_panel, SIGNAL(enableButtonOk(bool)), SLOT(enableButtonOk(bool)) ); + connect( m_panel, &InsertFilePanel::enableButtonOk, this, &KoDialog::enableButtonOk ); } QUrl InsertFileDialog::url() const { return m_panel->url(); } Node *InsertFileDialog::parentNode() const { return m_panel->parentNode(); } Node *InsertFileDialog::afterNode() const { return m_panel->afterNode(); } //------------------------ InsertFilePanel::InsertFilePanel( Project &project, Node *currentNode, QWidget *parent ) : QWidget( parent ), m_project( project ), m_node( currentNode ) { ui.setupUi( this ); if ( currentNode == 0 || currentNode->type() == Node::Type_Project ) { ui.ui_isAfter->setEnabled( false ); ui.ui_isParent->setEnabled( false ); ui.ui_useProject->setChecked( true ); ui.ui_name->setText( project.name() ); } else { ui.ui_isAfter->setChecked( true ); ui.ui_name->setText( currentNode->name() ); } - connect( ui.ui_url, SIGNAL(textChanged(QString)), SLOT(changed(QString)) ); + connect( ui.ui_url, &KUrlRequester::textChanged, this, &InsertFilePanel::changed ); - connect( ui.ui_url, SIGNAL(openFileDialog(KUrlRequester*)), SLOT(slotOpenFileDialog(KUrlRequester*)) ); + connect( ui.ui_url, &KUrlRequester::openFileDialog, this, &InsertFilePanel::slotOpenFileDialog ); } void InsertFilePanel::slotOpenFileDialog( KUrlRequester * ) { ui.ui_url->setFilter( "*.plan" ); } void InsertFilePanel::changed( const QString &text ) { KIO::StatJob* statJob = KIO::stat( QUrl::fromUserInput(text) ); statJob->setSide( KIO::StatJob::SourceSide ); const bool isUrlReadable = statJob->exec(); emit enableButtonOk( isUrlReadable ); } QUrl InsertFilePanel::url() const { return ui.ui_url->url(); } Node *InsertFilePanel::parentNode() const { if ( ui.ui_useProject->isChecked() ) { return &(m_project); } if ( ui.ui_isParent->isChecked() ) { return m_node; } if ( ui.ui_isAfter->isChecked() ) { return m_node->parentNode(); } return &(m_project); } Node *InsertFilePanel::afterNode() const { if ( ui.ui_isAfter->isChecked() ) { return m_node; } return 0; } } //KPlato namespace diff --git a/src/kptmaindocument.cpp b/src/kptmaindocument.cpp index 78c4edbe..f3a15728 100644 --- a/src/kptmaindocument.cpp +++ b/src/kptmaindocument.cpp @@ -1,1582 +1,1582 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 Torben Weis Copyright (C) 2004, 2010, 2012 Dag Andersen Copyright (C) 2006 Raphael Langerhorst Copyright (C) 2007 Thorsten Zachmann 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 "kptmaindocument.h" #include "kptpart.h" #include "kptview.h" #include "kptfactory.h" #include "kptproject.h" #include "kptlocale.h" #include "kptresource.h" #include "kptcontext.h" #include "kptschedulerpluginloader.h" #include "kptschedulerplugin.h" #include "kptbuiltinschedulerplugin.h" #include "kptcommand.h" #include "calligraplansettings.h" #include "kpttask.h" #include "KPlatoXmlLoader.h" #include "kptpackage.h" #include "kptworkpackagemergedialog.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KHOLIDAYS #include #endif namespace KPlato { MainDocument::MainDocument(KoPart *part) : KoDocument(part), m_project( 0 ), m_context( 0 ), m_xmlLoader(), m_loadingTemplate( false ), m_loadingSharedResourcesTemplate( false ), m_viewlistModified( false ), m_checkingForWorkPackages( false ), m_loadingSharedProject(false), m_skipSharedProjects(false), m_isTaskModule(false) { Q_ASSERT(part); setAlwaysAllowSaving(true); m_config.setReadWrite( true ); loadSchedulerPlugins(); setProject( new Project( m_config ) ); // after config & plugins are loaded m_project->setId( m_project->uniqueNodeId() ); m_project->registerNodeId( m_project ); // register myself connect(this, &MainDocument::insertSharedProject, this, &MainDocument::slotInsertSharedProject); - QTimer::singleShot ( 5000, this, SLOT(autoCheckForWorkPackages()) ); + QTimer::singleShot ( 5000, this, &MainDocument::autoCheckForWorkPackages ); } MainDocument::~MainDocument() { qDeleteAll( m_schedulerPlugins ); if ( m_project ) { m_project->deref(); // deletes if last user } qDeleteAll( m_mergedPackages ); delete m_context; } void MainDocument::setReadWrite( bool rw ) { m_config.setReadWrite( rw ); KoDocument::setReadWrite( rw ); } void MainDocument::loadSchedulerPlugins() { // Add built-in scheduler addSchedulerPlugin( "Built-in", new BuiltinSchedulerPlugin( this ) ); // Add all real scheduler plugins SchedulerPluginLoader *loader = new SchedulerPluginLoader(this); - connect(loader, SIGNAL(pluginLoaded(QString,KPlato::SchedulerPlugin*)), this, SLOT(addSchedulerPlugin(QString,KPlato::SchedulerPlugin*))); + connect(loader, &SchedulerPluginLoader::pluginLoaded, this, &MainDocument::addSchedulerPlugin); loader->loadAllPlugins(); } void MainDocument::addSchedulerPlugin( const QString &key, SchedulerPlugin *plugin) { debugPlan<setConfig( m_config ); } void MainDocument::setProject( Project *project ) { if ( m_project ) { - disconnect( m_project, SIGNAL(projectChanged()), this, SIGNAL(changed()) ); + disconnect( m_project, &Project::projectChanged, this, &MainDocument::changed ); delete m_project; } m_project = project; if ( m_project ) { - connect( m_project, SIGNAL(projectChanged()), this, SIGNAL(changed()) ); + connect( m_project, &Project::projectChanged, this, &MainDocument::changed ); // m_project->setConfig( config() ); m_project->setSchedulerPlugins( m_schedulerPlugins ); } m_aboutPage.setProject( project ); emit changed(); } bool MainDocument::loadOdf( KoOdfReadStore &odfStore ) { warnPlan<< "OpenDocument not supported, let's try native xml format"; return loadXML( odfStore.contentDoc(), 0 ); // We have only one format, so try to load that! } bool MainDocument::loadXML( const KoXmlDocument &document, KoStore* ) { QPointer updater; if (progressUpdater()) { updater = progressUpdater()->startSubtask(1, "Plan::Part::loadXML"); updater->setProgress(0); m_xmlLoader.setUpdater( updater ); } QString value; KoXmlElement plan = document.documentElement(); // Check if this is the right app value = plan.attribute( "mime", QString() ); if ( value.isEmpty() ) { errorPlan << "No mime type specified!"; setErrorMessage( i18n( "Invalid document. No mimetype specified." ) ); return false; } if ( value == "application/x-vnd.kde.kplato" ) { if (updater) { updater->setProgress(5); } m_xmlLoader.setMimetype( value ); QString message; Project *newProject = new Project(m_config, false); KPlatoXmlLoader loader( m_xmlLoader, newProject ); bool ok = loader.load( plan ); if ( ok ) { setProject( newProject ); setModified( false ); debugPlan<schedules(); // Cleanup after possible bug: // There should *not* be any deleted schedules (or with parent == 0) foreach ( Node *n, newProject->nodeDict()) { foreach ( Schedule *s, n->schedules()) { if ( s->isDeleted() ) { // true also if parent == 0 errorPlan<name()<takeSchedule( s ); delete s; } } } } else { setErrorMessage( loader.errorMessage() ); delete newProject; } if (updater) { updater->setProgress(100); // the rest is only processing, not loading } emit changed(); return ok; } if ( value != "application/x-vnd.kde.plan" ) { errorPlan << "Unknown mime type " << value; setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-vnd.kde.plan, got %1", value ) ); return false; } QString syntaxVersion = plan.attribute( "version", PLAN_FILE_SYNTAX_VERSION ); m_xmlLoader.setVersion( syntaxVersion ); if ( syntaxVersion > PLAN_FILE_SYNTAX_VERSION ) { KMessageBox::ButtonCode ret = KMessageBox::warningContinueCancel( 0, i18n( "This document was created with a newer version of Plan (syntax version: %1)\n" "Opening it in this version of Plan will lose some information.", syntaxVersion ), i18n( "File-Format Mismatch" ), KGuiItem( i18n( "Continue" ) ) ); if ( ret == KMessageBox::Cancel ) { setErrorMessage( "USER_CANCELED" ); return false; } } if (updater) updater->setProgress(5); /* #ifdef KOXML_USE_QDOM int numNodes = plan.childNodes().count(); #else int numNodes = plan.childNodesCount(); #endif */ #if 0 This test does not work any longer. KoXml adds a couple of elements not present in the file!! if ( numNodes > 2 ) { //TODO: Make a proper bitching about this debugPlan <<"*** Error ***"; debugPlan <<" Children count should be maximum 2, but is" << numNodes; return false; } #endif m_xmlLoader.startLoad(); KoXmlNode n = plan.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "project" ) { Project *newProject = new Project(m_config, false); m_xmlLoader.setProject( newProject ); if ( newProject->load( e, m_xmlLoader ) ) { if ( newProject->id().isEmpty() ) { newProject->setId( newProject->uniqueNodeId() ); newProject->registerNodeId( newProject ); } // The load went fine. Throw out the old project setProject( newProject ); // Cleanup after possible bug: // There should *not* be any deleted schedules (or with parent == 0) foreach ( Node *n, newProject->nodeDict()) { foreach ( Schedule *s, n->schedules()) { if ( s->isDeleted() ) { // true also if parent == 0 errorPlan<name()<takeSchedule( s ); delete s; } } } } else { delete newProject; m_xmlLoader.addMsg( XMLLoaderObject::Errors, "Loading of project failed" ); //TODO add some ui here } } } m_xmlLoader.stopLoad(); if (updater) updater->setProgress(100); // the rest is only processing, not loading setModified( false ); emit changed(); return true; } QDomDocument MainDocument::saveXML() { debugPlan; QDomDocument document( "plan" ); document.appendChild( document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); QDomElement doc = document.createElement( "plan" ); doc.setAttribute( "editor", "Plan" ); doc.setAttribute( "mime", "application/x-vnd.kde.plan" ); doc.setAttribute( "version", PLAN_FILE_SYNTAX_VERSION ); document.appendChild( doc ); // Save the project m_project->save( doc ); return document; } QDomDocument MainDocument::saveWorkPackageXML( const Node *node, long id, Resource *resource ) { debugPlan; QDomDocument document( "plan" ); document.appendChild( document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); QDomElement doc = document.createElement( "planwork" ); doc.setAttribute( "editor", "Plan" ); doc.setAttribute( "mime", "application/x-vnd.kde.plan.work" ); doc.setAttribute( "version", PLANWORK_FILE_SYNTAX_VERSION ); doc.setAttribute( "plan-version", PLAN_FILE_SYNTAX_VERSION ); document.appendChild( doc ); // Work package info QDomElement wp = document.createElement( "workpackage" ); if ( resource ) { wp.setAttribute( "owner", resource->name() ); wp.setAttribute( "owner-id", resource->id() ); } wp.setAttribute( "time-tag", QDateTime::currentDateTime().toString( Qt::ISODate ) ); doc.appendChild( wp ); // Save the project m_project->saveWorkPackageXML( doc, node, id ); return document; } bool MainDocument::saveWorkPackageToStream( QIODevice *dev, const Node *node, long id, Resource *resource ) { QDomDocument doc = saveWorkPackageXML( node, id, resource ); // Save to buffer QByteArray s = doc.toByteArray(); // utf8 already dev->open( QIODevice::WriteOnly ); int nwritten = dev->write( s.data(), s.size() ); if ( nwritten != (int)s.size() ) { warnPlan<<"wrote:"<m_specialOutputFlag == SaveEncrypted ) { backend = KoStore::Encrypted; debugPlan <<"Saving using encrypted backend."; }*/ #endif QByteArray mimeType = "application/x-vnd.kde.plan.work"; debugPlan <<"MimeType=" << mimeType; KoStore *store = KoStore::createStore( file, KoStore::Write, mimeType, backend ); /* if ( d->m_specialOutputFlag == SaveEncrypted && !d->m_password.isNull( ) ) { store->setPassword( d->m_password ); }*/ if ( store->bad() ) { setErrorMessage( i18n( "Could not create the workpackage file for saving: %1", file ) ); // more details needed? delete store; return false; } // Tell KoStore not to touch the file names if ( ! store->open( "root" ) ) { setErrorMessage( i18n( "Not able to write '%1'. Partition full?", QString( "maindoc.xml") ) ); delete store; return false; } KoStoreDevice dev( store ); if ( !saveWorkPackageToStream( &dev, node, id, resource ) || !store->close() ) { debugPlan <<"saveToStream failed"; delete store; return false; } node->documents().saveToStore( store ); debugPlan <<"Saving done of url:" << file; if ( !store->finalize() ) { delete store; return false; } // Success delete store; return true; } bool MainDocument::saveWorkPackageUrl( const QUrl &_url, const Node *node, long id, Resource *resource ) { //debugPlan<<_url; QApplication::setOverrideCursor( Qt::WaitCursor ); emit statusBarMessage( i18n("Saving...") ); bool ret = false; ret = saveWorkPackageFormat( _url.path(), node, id, resource ); // kzip don't handle file:// QApplication::restoreOverrideCursor(); emit clearStatusBarMessage(); return ret; } bool MainDocument::loadWorkPackage( Project &project, const QUrl &url ) { debugPlan<bad() ) { // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file ); debugPlan<<"bad store"<open( "root" ) ) { // "old" file format (maindoc.xml) // i18n( "File does not have a maindoc.xml: %1", file ); debugPlan<<"No root"<device(), &errorMsg, &errorLine, &errorColumn ); if ( ! ok ) { errorPlan << "Parsing error in " << url.url() << "! Aborting!" << endl << " In line: " << errorLine << ", column: " << errorColumn << endl << " Error message: " << errorMsg; //d->lastErrorMessage = i18n( "Parsing error in %1 at line %2, column %3\nError message: %4",filename ,errorLine, errorColumn , QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0, QCoreApplication::UnicodeUTF8)); } else { package = loadWorkPackageXML( project, store->device(), doc, url ); if ( package ) { package->url = url; m_workpackages.insert( package->timeTag, package ); } else { ok = false; } } store->close(); //### if ( ok && package && package->settings.documents ) { ok = extractFiles( store, package ); } delete store; if ( ! ok ) { // QApplication::restoreOverrideCursor(); return false; } return true; } Package *MainDocument::loadWorkPackageXML( Project &project, QIODevice *, const KoXmlDocument &document, const QUrl &/*url*/ ) { QString value; bool ok = true; Project *proj = 0; Package *package = 0; KoXmlElement plan = document.documentElement(); // Check if this is the right app value = plan.attribute( "mime", QString() ); if ( value.isEmpty() ) { debugPlan << "No mime type specified!"; setErrorMessage( i18n( "Invalid document. No mimetype specified." ) ); return 0; } else if ( value == "application/x-vnd.kde.kplato.work" ) { m_xmlLoader.setMimetype( value ); m_xmlLoader.setWorkVersion( plan.attribute( "version", "0.0.0" ) ); proj = new Project(); KPlatoXmlLoader loader( m_xmlLoader, proj ); ok = loader.loadWorkpackage( plan ); if ( ! ok ) { setErrorMessage( loader.errorMessage() ); delete proj; return 0; } package = loader.package(); package->timeTag = QDateTime::fromString( loader.timeTag(), Qt::ISODate ); } else if ( value != "application/x-vnd.kde.plan.work" ) { debugPlan << "Unknown mime type " << value; setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-vnd.kde.plan.work, got %1", value ) ); return 0; } else { QString syntaxVersion = plan.attribute( "version", "0.0.0" ); m_xmlLoader.setWorkVersion( syntaxVersion ); if ( syntaxVersion > PLANWORK_FILE_SYNTAX_VERSION ) { KMessageBox::ButtonCode ret = KMessageBox::warningContinueCancel( 0, i18n( "This document was created with a newer version of PlanWork (syntax version: %1)\n" "Opening it in this version of PlanWork will lose some information.", syntaxVersion ), i18n( "File-Format Mismatch" ), KGuiItem( i18n( "Continue" ) ) ); if ( ret == KMessageBox::Cancel ) { setErrorMessage( "USER_CANCELED" ); return 0; } } m_xmlLoader.setVersion( plan.attribute( "plan-version", PLAN_FILE_SYNTAX_VERSION ) ); m_xmlLoader.startLoad(); proj = new Project(); package = new Package(); package->project = proj; KoXmlNode n = plan.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "project" ) { m_xmlLoader.setProject( proj ); ok = proj->load( e, m_xmlLoader ); if ( ! ok ) { m_xmlLoader.addMsg( XMLLoaderObject::Errors, "Loading of work package failed" ); //TODO add some ui here } } else if ( e.tagName() == "workpackage" ) { package->timeTag = QDateTime::fromString( e.attribute( "time-tag" ), Qt::ISODate ); package->ownerId = e.attribute( "owner-id" ); package->ownerName = e.attribute( "owner" ); debugPlan<<"workpackage:"<timeTag<ownerId<ownerName; KoXmlElement elem; forEachElement( elem, e ) { if ( elem.tagName() != "settings" ) { continue; } package->settings.usedEffort = (bool)elem.attribute( "used-effort" ).toInt(); package->settings.progress = (bool)elem.attribute( "progress" ).toInt(); package->settings.documents = (bool)elem.attribute( "documents" ).toInt(); } } } if ( proj->numChildren() > 0 ) { package->task = static_cast( proj->childNode( 0 ) ); package->toTask = qobject_cast( m_project->findNode( package->task->id() ) ); WorkPackage &wp = package->task->workPackage(); if ( wp.ownerId().isEmpty() ) { wp.setOwnerId( package->ownerId ); wp.setOwnerName( package->ownerName ); } debugPlan<<"Task set:"<task->name(); } m_xmlLoader.stopLoad(); } if ( ok && proj->id() == project.id() && proj->childNode( 0 ) ) { ok = project.nodeDict().contains( proj->childNode( 0 )->id() ); if ( ok && m_mergedPackages.contains( package->timeTag ) ) { ok = false; // already merged } if ( ok && package->timeTag.isValid() && ! m_mergedPackages.contains( package->timeTag ) ) { m_mergedPackages[ package->timeTag ] = proj; // register this for next time } if ( ok && ! package->timeTag.isValid() ) { warnPlan<<"Work package is not time tagged:"<childNode( 0 )->name()<url; ok = false; } } if ( ! ok ) { delete proj; delete package; return 0; } Q_ASSERT( package ); return package; } bool MainDocument::extractFiles( KoStore *store, Package *package ) { if ( package->task == 0 ) { errorPlan<<"No task!"; return false; } foreach ( Document *doc, package->task->documents().documents() ) { if ( ! doc->isValid() || doc->type() != Document::Type_Product || doc->sendAs() != Document::SendAs_Copy ) { continue; } if ( ! extractFile( store, package, doc ) ) { return false; } } return true; } bool MainDocument::extractFile( KoStore *store, Package *package, const Document *doc ) { QTemporaryFile tmpfile; if ( ! tmpfile.open() ) { errorPlan<<"Failed to open temporary file"; return false; } if ( ! store->extractFile( doc->url().fileName(), tmpfile.fileName() ) ) { errorPlan<<"Failed to extract file:"<url().fileName()<<"to:"<documents.insert( tmpfile.fileName(), doc->url() ); tmpfile.setAutoRemove( false ); debugPlan<<"extracted:"<url().fileName()<<"->"<numChildren() == 0 ) { return; } m_checkingForWorkPackages = true; if ( ! keep ) { qDeleteAll( m_mergedPackages ); m_mergedPackages.clear(); } QDir dir( m_config.retrieveUrl().path(), "*.planwork" ); m_infoList = dir.entryInfoList( QDir::Files | QDir::Readable, QDir::Time ); checkForWorkPackage(); return; } void MainDocument::checkForWorkPackage() { if ( ! m_infoList.isEmpty() ) { loadWorkPackage( *m_project, QUrl::fromLocalFile( m_infoList.takeLast().absoluteFilePath() ) ); if ( ! m_infoList.isEmpty() ) { - QTimer::singleShot ( 0, this, SLOT(checkForWorkPackage()) ); + QTimer::singleShot ( 0, this, &MainDocument::checkForWorkPackage ); return; } // all files read // remove other projects QMutableMapIterator it( m_workpackages ); while ( it.hasNext() ) { it.next(); Package *package = it.value(); if ( package->project->id() != m_project->id() ) { delete package->project; delete package; it.remove(); } } // Merge our workpackages if ( ! m_workpackages.isEmpty() ) { WorkPackageMergeDialog *dlg = new WorkPackageMergeDialog( i18n( "New work packages detected. Merge data with existing tasks?" ), m_workpackages ); connect(dlg, SIGNAL(finished(int)), SLOT(workPackageMergeDialogFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } } } void MainDocument::workPackageMergeDialogFinished( int result ) { WorkPackageMergeDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == KoDialog::Yes ) { // merge the oldest first foreach( int i, dlg->checkedList() ) { const QList &packages = m_workpackages.values(); mergeWorkPackage(packages.at(i)); } // 'Yes' was hit so terminate all packages foreach(const Package *p, m_workpackages) { terminateWorkPackage( p ); } } qDeleteAll( m_workpackages ); m_workpackages.clear(); m_checkingForWorkPackages = false; dlg->deleteLater(); } void MainDocument::mergeWorkPackages() { foreach (const Package *package, m_workpackages) { mergeWorkPackage( package ); } } void MainDocument::terminateWorkPackage( const Package *package ) { QFile file( package->url.path() ); if ( ! file.exists() ) { return; } if ( KPlatoSettings::deleteFile() || KPlatoSettings::saveUrl().isEmpty() ) { file.remove(); } else if ( KPlatoSettings::saveFile() && ! KPlatoSettings::saveUrl().isEmpty() ) { QDir dir( KPlatoSettings::saveUrl().path() ); if ( ! dir.exists() ) { if ( ! dir.mkpath( dir.path() ) ) { //TODO message debugPlan<<"Could not create directory:"<project); if ( proj.id() == m_project->id() && proj.childNode( 0 ) ) { const Task *from = package->task; Task *to = package->toTask; if ( to && from ) { mergeWorkPackage( to, from, package ); } } } void MainDocument::mergeWorkPackage( Task *to, const Task *from, const Package *package ) { Resource *resource = m_project->findResource( package->ownerId ); if ( resource == 0 ) { KMessageBox::error( 0, i18n( "The package owner '%1' is not a resource in this project. You must handle this manually.", package->ownerName ) ); return; } MacroCommand *cmd = new MacroCommand( kundo2_noi18n("Merge workpackage") ); Completion &org = to->completion(); const Completion &curr = from->completion(); if ( package->settings.progress ) { if ( org.isStarted() != curr.isStarted() ) { cmd->addCommand( new ModifyCompletionStartedCmd(org, curr.isStarted() ) ); } if ( org.isFinished() != curr.isFinished() ) { cmd->addCommand( new ModifyCompletionFinishedCmd( org, curr.isFinished() ) ); } if ( org.startTime() != curr.startTime() ) { cmd->addCommand( new ModifyCompletionStartTimeCmd( org, curr.startTime() ) ); } if ( org.finishTime() != curr.finishTime() ) { cmd->addCommand( new ModifyCompletionFinishTimeCmd( org, curr.finishTime() ) ); } // TODO: review how/if to merge data from different resources // remove entries const QList &dates = org.entries().keys(); for (const QDate &d : dates) { if ( ! curr.entries().contains( d ) ) { debugPlan<<"remove entry "<addCommand( new RemoveCompletionEntryCmd( org, d ) ); } } // add new entries / modify existing const QList &cdates = curr.entries().keys(); for (const QDate &d : cdates) { if ( org.entries().contains( d ) && curr.entry( d ) == org.entry( d ) ) { continue; } Completion::Entry *e = new Completion::Entry( *( curr.entry( d ) ) ); cmd->addCommand( new ModifyCompletionEntryCmd( org, d, e ) ); } } if ( package->settings.usedEffort ) { Completion::UsedEffort *ue = new Completion::UsedEffort(); Completion::Entry prev; Completion::EntryList::ConstIterator entriesIt = curr.entries().constBegin(); const Completion::EntryList::ConstIterator entriesEnd = curr.entries().constEnd(); for (; entriesIt != entriesEnd; ++entriesIt) { const QDate &d = entriesIt.key(); const Completion::Entry &e = *entriesIt.value(); // set used effort from date entry and remove used effort from date entry Completion::UsedEffort::ActualEffort effort( e.totalPerformed - prev.totalPerformed ); ue->setEffort( d, effort ); prev = e; } cmd->addCommand( new AddCompletionUsedEffortCmd( org, resource, ue ) ); } bool docsaved = false; if ( package->settings.documents ) { //TODO: handle remote files QMap::const_iterator it = package->documents.constBegin(); QMap::const_iterator end = package->documents.constEnd(); for ( ; it != end; ++it ) { const QUrl src = QUrl::fromLocalFile(it.key()); KIO::CopyJob *job = KIO::move( src, it.value(), KIO::Overwrite ); if ( job->exec() ) { docsaved = true; //TODO: async debugPlan<<"Moved file:"<isEmpty() ) { KMessageBox::information( 0, i18n( "Nothing to save from this package" ) ); } // add a copy to our tasks list of transmitted packages WorkPackage *wp = new WorkPackage( from->workPackage() ); wp->setParentTask( to ); if ( ! wp->transmitionTime().isValid() ) { wp->setTransmitionTime( package->timeTag ); } wp->setTransmitionStatus( WorkPackage::TS_Receive ); cmd->addCommand( new WorkPackageAddCmd( m_project, to, wp ) ); addCommand( cmd ); } void MainDocument::paintContent( QPainter &, const QRect &) { // Don't embed this app!!! } void MainDocument::slotViewDestroyed() { } void MainDocument::setLoadingTemplate(bool loading) { m_loadingTemplate = loading; } void MainDocument::setLoadingSharedResourcesTemplate(bool loading) { m_loadingSharedResourcesTemplate = loading; } bool MainDocument::completeLoading( KoStore *store ) { // If we get here the new project is loaded and set if (m_loadingSharedProject) { // this file is loaded by another project // to read resource appointments, // so we must not load any extra stuff return true; } if ( m_loadingTemplate ) { //debugPlan<<"Loading template, generate unique ids"; m_project->generateUniqueIds(); m_project->setConstraintStartTime( QDateTime(QDate::currentDate(), QTime(0, 0, 0), Qt::LocalTime) ); m_project->setConstraintEndTime( m_project->constraintStartTime().addYears( 2 ) ); m_project->locale()->setCurrencyLocale(QLocale::AnyLanguage, QLocale::AnyCountry); m_project->locale()->setCurrencySymbol(QString()); } else if ( isImporting() ) { // NOTE: I don't think this is a good idea. // Let the filter generate ids for non-plan files. // If the user wants to create a new project from an old one, // he should use Tools -> Insert Project File //m_project->generateUniqueNodeIds(); } if (m_loadingSharedResourcesTemplate && m_project->calendarCount() > 0) { Calendar *c = m_project->calendarAt(0); c->setTimeZone(QTimeZone::systemTimeZone()); } if (m_project->useSharedResources() && !m_project->sharedResourcesFile().isEmpty() && !m_skipSharedProjects) { QUrl url = QUrl::fromLocalFile(m_project->sharedResourcesFile()); if (url.isValid()) { insertResourcesFile(url, m_project->loadProjectsAtStartup() ? m_project->sharedProjectsUrl() : QUrl()); } } if ( store == 0 ) { // can happen if loading a template debugPlan<<"No store"; return true; // continue anyway } delete m_context; m_context = new Context(); KoXmlDocument doc; if ( loadAndParse( store, "context.xml", doc ) ) { store->close(); m_context->load( doc ); } else warnPlan<<"No context"; return true; } // TODO: // Due to splitting of KoDocument into a document and a part, // we simulate the old behaviour by registering all views in the document. // Find a better solution! void MainDocument::registerView( View* view ) { if ( view && ! m_views.contains( view ) ) { m_views << QPointer( view ); } } bool MainDocument::completeSaving( KoStore *store ) { foreach ( View *view, m_views ) { if ( view ) { if ( store->open( "context.xml" ) ) { if ( m_context == 0 ) m_context = new Context(); QDomDocument doc = m_context->save( view ); KoStoreDevice dev( store ); QByteArray s = doc.toByteArray(); // this is already Utf8! (void)dev.write( s.data(), s.size() ); (void)store->close(); m_viewlistModified = false; emit viewlistModified( false ); } break; } } return true; } bool MainDocument::loadAndParse(KoStore *store, const QString &filename, KoXmlDocument &doc) { //debugPlan << "oldLoadAndParse: Trying to open " << filename; if (!store->open(filename)) { warnPlan << "Entry " << filename << " not found!"; // d->lastErrorMessage = i18n( "Could not find %1",filename ); return false; } // Error variables for QDomDocument::setContent QString errorMsg; int errorLine, errorColumn; bool ok = doc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn ); if ( !ok ) { errorPlan << "Parsing error in " << filename << "! Aborting!" << endl << " In line: " << errorLine << ", column: " << errorColumn << endl << " Error message: " << errorMsg; /* d->lastErrorMessage = i18n( "Parsing error in %1 at line %2, column %3\nError message: %4" ,filename ,errorLine, errorColumn , QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0, QCoreApplication::UnicodeUTF8));*/ store->close(); return false; } debugPlan << "File " << filename << " loaded and parsed"; return true; } void MainDocument::insertFile( const QUrl &url, Node *parent, Node *after ) { Part *part = new Part( this ); MainDocument *doc = new MainDocument( part ); part->setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable doc->m_insertFileInfo.url = url; doc->m_insertFileInfo.parent = parent; doc->m_insertFileInfo.after = after; - connect(doc, SIGNAL(completed()), SLOT(insertFileCompleted())); - connect(doc, SIGNAL(canceled(QString)), SLOT(insertFileCancelled(QString))); + connect(doc, &KoDocument::completed, this, &MainDocument::insertFileCompleted); + connect(doc, &KoDocument::canceled, this, &MainDocument::insertFileCancelled); doc->openUrl( url ); } void MainDocument::insertFileCompleted() { debugPlan<( sender() ); if ( doc ) { Project &p = doc->getProject(); insertProject( p, doc->m_insertFileInfo.parent, doc->m_insertFileInfo.after ); doc->documentPart()->deleteLater(); // also deletes document } else { KMessageBox::error( 0, i18n("Internal error, failed to insert file.") ); } } void MainDocument::insertResourcesFile(const QUrl &url, const QUrl &projects) { insertSharedProjects(projects); // prepare for insertion after shared resources m_sharedProjectsFiles.removeAll(url); // resource file is not a project Part *part = new Part( this ); MainDocument *doc = new MainDocument( part ); doc->m_skipSharedProjects = true; // should not have shared projects, but... part->setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable doc->setCheckAutoSaveFile(false); - connect(doc, SIGNAL(completed()), SLOT(insertResourcesFileCompleted())); - connect(doc, SIGNAL(canceled(QString)), SLOT(insertFileCancelled(QString))); + connect(doc, &KoDocument::completed, this, &MainDocument::insertResourcesFileCompleted); + connect(doc, &KoDocument::canceled, this, &MainDocument::insertFileCancelled); doc->openUrl( url ); } void MainDocument::insertResourcesFileCompleted() { debugPlanShared<( sender() ); if (doc) { Project &p = doc->getProject(); mergeResources(p); m_project->setSharedResourcesLoaded(true); doc->documentPart()->deleteLater(); // also deletes document slotInsertSharedProject(); // insert shared bookings } else { KMessageBox::error( 0, i18n("Internal error, failed to insert file.") ); } } void MainDocument::insertFileCancelled( const QString &error ) { debugPlan<( sender() ); if ( doc ) { doc->documentPart()->deleteLater(); // also deletes document } } void MainDocument::clearResourceAssignments() { foreach (Resource *r, m_project->resourceList()) { r->clearExternalAppointments(); } } void MainDocument::loadResourceAssignments(QUrl url) { insertSharedProjects(url); slotInsertSharedProject(); } void MainDocument::insertSharedProjects(const QUrl &url) { m_sharedProjectsFiles.clear(); QFileInfo fi(url.path()); if (!fi.exists()) { return; } if (fi.isFile()) { m_sharedProjectsFiles = QList() << url; debugPlan<<"Get all projects in file:"<m_skipSharedProjects = true; // never load recursively part->setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable doc->setCheckAutoSaveFile(false); doc->m_loadingSharedProject = true; - connect(doc, SIGNAL(completed()), SLOT(insertSharedProjectCompleted())); - connect(doc, SIGNAL(canceled(QString)), SLOT(insertSharedProjectCancelled(QString))); + connect(doc, &KoDocument::completed, this, &MainDocument::insertSharedProjectCompleted); + connect(doc, &KoDocument::canceled, this, &MainDocument::insertSharedProjectCancelled); doc->openUrl(m_sharedProjectsFiles.takeFirst()); } void MainDocument::insertSharedProjectCompleted() { debugPlanShared<( sender() ); if (doc) { Project &p = doc->getProject(); debugPlanShared<id()<<"Loaded project:"<id() && p.isScheduled(ANYSCHEDULED)) { // FIXME: improve! // find a suitable schedule ScheduleManager *sm = 0; foreach(ScheduleManager *m, p.allScheduleManagers()) { if (m->isBaselined()) { sm = m; break; } if (m->isScheduled()) { sm = m; // take the last one, more likely to be subschedule } } if (sm) { foreach(Resource *r, p.resourceList()) { Resource *res = m_project->resource(r->id()); if (res && res->isShared()) { Appointment *app = new Appointment(); app->setAuxcilliaryInfo(p.name()); foreach(const Appointment *a, r->appointments(sm->scheduleId())) { *app += *a; } if (app->isEmpty()) { delete app; } else { res->addExternalAppointment(p.id(), app); debugPlanShared<name()<<"added:"<auxcilliaryInfo()<documentPart()->deleteLater(); // also deletes document emit insertSharedProject(); // do next file } else { KMessageBox::error( 0, i18n("Internal error, failed to insert file.") ); } } void MainDocument::insertSharedProjectCancelled( const QString &error ) { debugPlanShared<( sender() ); if ( doc ) { doc->documentPart()->deleteLater(); // also deletes document } } bool MainDocument::insertProject( Project &project, Node *parent, Node *after ) { debugPlan<<&project; // make sure node ids in new project is unique also in old project QList existingIds = m_project->nodeDict().keys(); foreach ( Node *n, project.allNodes() ) { QString oldid = n->id(); n->setId( project.uniqueNodeId( existingIds ) ); project.removeId( oldid ); // remove old id project.registerNodeId( n ); // register new id } MacroCommand *m = new InsertProjectCmd( project, parent==0?m_project:parent, after, kundo2_i18n( "Insert project" ) ); if ( m->isEmpty() ) { delete m; } else { addCommand( m ); } return true; } // check if calendar 'c' has children that will not be removed (normally 'Local' calendars) bool canRemoveCalendar(const Calendar *c, const QList &lst) { for (Calendar *cc : c->calendars()) { if (!lst.contains(cc)) { return false; } if (!canRemoveCalendar(cc, lst)) { return false; } } return true; } // sort parent calendars before children QList sortedRemoveCalendars(Project &shared, const QList &lst) { QList result; for (Calendar *c : lst) { if (c->isShared() && !shared.calendar(c->id())) { result << c; } result += sortedRemoveCalendars(shared, c->calendars()); } return result; } bool MainDocument::mergeResources(Project &project) { debugPlanShared<<&project; // Just in case, remove stuff not related to resources foreach(Node *n, project.childNodeIterator()) { debugPlanShared<<"Project not empty, delete node:"<name(); NodeDeleteCmd cmd(n); cmd.execute(); } foreach(ScheduleManager *m, project.scheduleManagers()) { debugPlanShared<<"Project not empty, delete schedule:"<name(); DeleteScheduleManagerCmd cmd(project, m); cmd.execute(); } foreach(Account *a, project.accounts().accountList()) { debugPlanShared<<"Project not empty, delete account:"<name(); RemoveAccountCmd cmd(project, a); cmd.execute(); } // Mark all resources / groups as shared foreach(ResourceGroup *g, project.resourceGroups()) { g->setShared(true); } foreach(Resource *r, project.resourceList()) { r->setShared(true); } // Mark all calendars shared foreach(Calendar *c, project.allCalendars()) { c->setShared(true); } // check if any shared stuff has been removed QList removedGroups; QList removedResources; QList removedCalendars; QStringList removed; foreach(ResourceGroup *g, m_project->resourceGroups()) { if (g->isShared() && !project.findResourceGroup(g->id())) { removedGroups << g; removed << i18n("Group: %1", g->name()); } } foreach(Resource *r, m_project->resourceList()) { if (r->isShared() && !project.findResource(r->id())) { removedResources << r; removed << i18n("Resource: %1", r->name()); } } removedCalendars = sortedRemoveCalendars(project, m_project->calendars()); for (Calendar *c : qAsConst(removedCalendars)) { removed << i18n("Calendar: %1", c->name()); } if (!removed.isEmpty()) { KMessageBox::ButtonCode result = KMessageBox::warningYesNoCancelList( 0, i18n("Shared resources has been removed from the shared resources file." "\nSelect how they shall be treated in this project."), removed, xi18nc("@title:window", "Shared resources"), KStandardGuiItem::remove(), KGuiItem(i18n("Convert")), KGuiItem(i18n("Keep")) ); switch (result) { case KMessageBox::Yes: // Remove for (Resource *r : qAsConst(removedResources)) { RemoveResourceCmd cmd(r->parentGroup(), r); cmd.redo(); } for (ResourceGroup *g : qAsConst(removedGroups)) { if (g->resources().isEmpty()) { RemoveResourceGroupCmd cmd(m_project, g); cmd.redo(); } else { // we may have put local resource(s) in this group // so we need to keep it g->setShared(false); m_project->removeResourceGroupId(g->id()); g->setId(m_project->uniqueResourceGroupId()); m_project->insertResourceGroupId(g->id(), g); } } for (Calendar *c : qAsConst(removedCalendars)) { CalendarRemoveCmd cmd(m_project, c); cmd.redo(); } break; case KMessageBox::No: // Convert for (Resource *r : qAsConst(removedResources)) { r->setShared(false); m_project->removeResourceId(r->id()); r->setId(m_project->uniqueResourceId()); m_project->insertResourceId(r->id(), r); } for (ResourceGroup *g : qAsConst(removedGroups)) { g->setShared(false); m_project->removeResourceGroupId(g->id()); g->setId(m_project->uniqueResourceGroupId()); m_project->insertResourceGroupId(g->id(), g); } for (Calendar *c : qAsConst(removedCalendars)) { c->setShared(false); m_project->removeCalendarId(c->id()); c->setId(m_project->uniqueCalendarId()); m_project->insertCalendarId(c->id(), c); } break; case KMessageBox::Cancel: // Keep break; default: break; } } // update values of already existing objects QStringList l1; foreach(ResourceGroup *g, project.resourceGroups()) { l1 << g->id(); } QStringList l2; foreach(ResourceGroup *g, m_project->resourceGroups()) { l2 << g->id(); } debugPlanShared< removegroups; foreach(ResourceGroup *g, project.resourceGroups()) { ResourceGroup *group = m_project->findResourceGroup(g->id()); if (group) { if (!group->isShared()) { // User has probably created shared resources from this project, // so the resources exists but are local ones. // Convert to shared and do not load the group from shared. removegroups << g; group->setShared(true); debugPlanShared<<"Set group to shared:"<id(); } group->setName(g->name()); group->setType(g->type()); debugPlanShared<<"Updated group:"<id(); } } QList removeresources; foreach(Resource *r, project.resourceList()) { Resource *resource = m_project->findResource(r->id()); if (resource) { if (!resource->isShared()) { // User has probably created shared resources from this project, // so the resources exists but are local ones. // Convert to shared and do not load the resource from shared. removeresources << r; resource->setShared(true); debugPlanShared<<"Set resource to shared:"<id(); } resource->setName(r->name()); resource->setInitials(r->initials()); resource->setEmail(r->email()); resource->setType(r->type()); resource->setAutoAllocate(r->autoAllocate()); resource->setAvailableFrom(r->availableFrom()); resource->setAvailableUntil(r->availableUntil()); resource->setUnits(r->units()); resource->setNormalRate(r->normalRate()); resource->setOvertimeRate(r->overtimeRate()); QString id = r->calendar(true) ? r->calendar(true)->id() : QString(); resource->setCalendar(m_project->findCalendar(id)); id = r->account() ? r->account()->name() : QString(); resource->setAccount(m_project->accounts().findAccount(id)); resource->setRequiredIds(r->requiredIds()); resource->setTeamMemberIds(r->teamMemberIds()); debugPlanShared<<"Updated resource:"<id(); } } QList removecalendars; foreach(Calendar *c, project.allCalendars()) { Calendar *calendar = m_project->findCalendar(c->id()); if (calendar) { if (!calendar->isShared()) { // User has probably created shared resources from this project, // so the calendar exists but are local ones. // Convert to shared and do not load the resource from shared. removecalendars << c; calendar->setShared(true); debugPlanShared<<"Set calendar to shared:"<id(); } *calendar = *c; debugPlanShared<<"Updated calendar:"<id(); } } debugPlanShared<<"Remove:"<childCount() == 0) { removecalendars.removeAt(i); debugPlanShared<<"Delete calendar:"<id(); CalendarRemoveCmd cmd(&project, c); cmd.execute(); } } } for (Resource *r : qAsConst(removeresources)) { debugPlanShared<<"Delete resource:"<id(); RemoveResourceCmd cmd(r->parentGroup(), r); cmd.execute(); } for (ResourceGroup *g : qAsConst(removegroups)) { debugPlanShared<<"Delete group:"<id(); RemoveResourceGroupCmd cmd(&project, g); cmd.execute(); } // insert new objects Q_ASSERT(project.childNodeIterator().isEmpty()); InsertProjectCmd cmd(project, m_project, 0); cmd.execute(); return true; } void MainDocument::insertViewListItem( View */*view*/, const ViewListItem *item, const ViewListItem *parent, int index ) { // FIXME callers should take care that they now get a signal even if originating from themselves emit viewListItemAdded(item, parent, index); setModified( true ); m_viewlistModified = true; } void MainDocument::removeViewListItem( View */*view*/, const ViewListItem *item ) { // FIXME callers should take care that they now get a signal even if originating from themselves emit viewListItemRemoved(item); setModified( true ); m_viewlistModified = true; } void MainDocument::setModified( bool mod ) { debugPlan<name().isEmpty()) { setUrl(QUrl(m_project->name() + ".plan")); } Calendar *week = 0; if (KPlatoSettings::generateWeek()) { bool always = KPlatoSettings::generateWeekChoice() == KPlatoSettings::EnumGenerateWeekChoice::Always; bool ifnone = KPlatoSettings::generateWeekChoice() == KPlatoSettings::EnumGenerateWeekChoice::NoneExists; if (always || (ifnone && m_project->calendarCount() == 0)) { // create a calendar week = new Calendar(i18nc("Base calendar name", "Base")); m_project->addCalendar(week); CalendarDay vd(CalendarDay::NonWorking); for (int i = Qt::Monday; i <= Qt::Sunday; ++i) { if (m_config.isWorkingday(i)) { CalendarDay wd(CalendarDay::Working); TimeInterval ti(m_config.dayStartTime(i), m_config.dayLength(i)); wd.addInterval(ti); week->setWeekday(i, wd); } else { week->setWeekday(i, vd); } } } } #ifdef HAVE_KHOLIDAYS if (KPlatoSettings::generateHolidays()) { bool inweek = week != 0 && KPlatoSettings::generateHolidaysChoice() == KPlatoSettings::EnumGenerateHolidaysChoice::InWeekCalendar; bool subcalendar = week != 0 && KPlatoSettings::generateHolidaysChoice() == KPlatoSettings::EnumGenerateHolidaysChoice::AsSubCalendar; bool separate = week == 0 || KPlatoSettings::generateHolidaysChoice() == KPlatoSettings::EnumGenerateHolidaysChoice::AsSeparateCalendar; Calendar *c = 0; if (inweek) { c = week; qDebug()<addCalendar(c, week); qDebug()<addCalendar(c); qDebug()<setHolidayRegion(KPlatoSettings::region()); } #endif } // creates a "new" project from current project (new ids etc) void MainDocument::createNewProject() { setEmpty(); clearUndoHistory(); setModified( false ); resetURL(); KoDocumentInfo *info = documentInfo(); info->resetMetaData(); info->setProperty( "title", "" ); setTitleModified(); m_project->generateUniqueNodeIds(); Duration dur = m_project->constraintEndTime() - m_project->constraintStartTime(); m_project->setConstraintStartTime( QDateTime(QDate::currentDate(), QTime(0, 0, 0), Qt::LocalTime) ); m_project->setConstraintEndTime( m_project->constraintStartTime() + dur ); while ( m_project->numScheduleManagers() > 0 ) { foreach ( ScheduleManager *sm, m_project->allScheduleManagers() ) { if ( sm->childCount() > 0 ) { continue; } if ( sm->expected() ) { sm->expected()->setDeleted( true ); sm->setExpected( 0 ); } m_project->takeScheduleManager( sm ); delete sm; } } foreach ( Schedule *s, m_project->schedules() ) { m_project->takeSchedule( s ); delete s; } foreach ( Node *n, m_project->allNodes() ) { foreach ( Schedule *s, n->schedules() ) { n->takeSchedule( s ); delete s; } } foreach ( Resource *r, m_project->resourceList() ) { foreach ( Schedule *s, r->schedules() ) { r->takeSchedule( s ); delete s; } } } void MainDocument::setIsTaskModule(bool value) { m_isTaskModule = value; } bool MainDocument::isTaskModule() const { return m_isTaskModule; } } //KPlato namespace diff --git a/src/kptpart.cpp b/src/kptpart.cpp index 4d25f3d7..7331b03f 100644 --- a/src/kptpart.cpp +++ b/src/kptpart.cpp @@ -1,213 +1,213 @@ /* This file is part of the KDE project Copyright (C) 2012 C. Boemann 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 "kptpart.h" #include "kptview.h" #include "kptmaindocument.h" #include "kptfactory.h" #include "welcome/WelcomeView.h" #include "kpthtmlview.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include Part::Part(QObject *parent) : KoPart(Factory::global(), parent) , startUpWidget(0) { setTemplatesResourcePath(QLatin1String("calligraplan/templates/")); KDesktopFile df(componentData().aboutData().desktopFileName() + ".desktop"); new Help(df.readDocPath()); } Part::~Part() { } void Part::setDocument(KPlato::MainDocument *document) { KoPart::setDocument(document); m_document = document; } KoView *Part::createViewInstance(KoDocument *document, QWidget *parent) { // synchronize view selector View *view = dynamic_cast(views().value(0)); /*FIXME if (view && m_context) { QDomDocument doc = m_context->save(view); m_context->setContent(doc.toString()); }*/ view = new View(this, qobject_cast(document), parent); // connect(view, SIGNAL(destroyed()), this, SLOT(slotViewDestroyed())); // connect(document, SIGNAL(viewListItemAdded(const ViewListItem*,const ViewListItem*,int)), view, SLOT(addViewListItem(const ViewListItem*,const ViewListItem*,int))); // connect(document, SIGNAL(viewListItemRemoved(const ViewListItem*)), view, SLOT(removeViewListItem(const ViewListItem*))); return view; } KoMainWindow *Part::createMainWindow() { KoMainWindow *w = new KoMainWindow(PLAN_MIME_TYPE, componentData()); QAction *handbookAction = w->action("help_contents"); if (handbookAction) { // we do not want to use khelpcenter as we do not install docs disconnect(handbookAction, 0, 0, 0); connect(handbookAction, &QAction::triggered, this, &Part::slotHelpContents); } return w; } void Part::slotHelpContents() { QDesktopServices::openUrl(QUrl(Help::page("Manual"))); } void Part::showStartUpWidget(KoMainWindow *parent) { m_toolbarVisible = parent->factory()->container("mainToolBar", parent)->isVisible(); if (m_toolbarVisible) { parent->factory()->container("mainToolBar", parent)->hide(); } if (startUpWidget) { startUpWidget->show(); } else { createStarUpWidget(parent); parent->setCentralWidget(startUpWidget); } parent->setPartToOpen(this); } void Part::openTemplate(const QUrl &url) { debugPlan<<"Open shared resources template:"<setLoadingTemplate(true); m_document->setLoadingSharedResourcesTemplate(url.fileName() == "SharedResources.plant"); KoPart::openTemplate(url); m_document->setLoadingTemplate(false); } void Part::openTaskModule(const QUrl &url) { Part *part = new Part(0); MainDocument *doc = new MainDocument(part); part->setDocument(doc); doc->setIsTaskModule(true); mainWindows().first()->openDocument(part, url); } void Part::createStarUpWidget(KoMainWindow *parent) { startUpWidget = new QStackedWidget(parent); startUpWidget->addWidget(createWelcomeView(parent)); startUpWidget->addWidget(createIntroductionView()); } void Part::finish() { mainWindows().first()->setRootDocument(document(), this); if (m_toolbarVisible) { KoPart::mainWindows().first()->factory()->container("mainToolBar", mainWindows().first())->show(); } } QWidget *Part::createWelcomeView(KoMainWindow *mw) { MainDocument *doc = static_cast(document()); WelcomeView *v = new WelcomeView(this, doc, startUpWidget); v->setProject(&(doc->getProject())); KSharedConfigPtr configPtr = Factory::global().config(); KRecentFilesAction recent("x", 0); recent.loadEntries(configPtr->group("RecentFiles")); v->setRecentFiles(recent.items()); - connect(v, SIGNAL(loadSharedResources(QUrl,QUrl)), doc, SLOT(insertResourcesFile(QUrl,QUrl))); - connect(v, SIGNAL(recentProject(QUrl)), mw, SLOT(slotFileOpenRecent(QUrl))); - connect(v, SIGNAL(showIntroduction()), this, SLOT(slotShowIntroduction())); - connect(v, SIGNAL(projectCreated()), doc, SLOT(slotProjectCreated())); - connect(v, SIGNAL(finished()), this, SLOT(finish())); + connect(v, &WelcomeView::loadSharedResources, doc, &MainDocument::insertResourcesFile); + connect(v, &WelcomeView::recentProject, mw, &KoMainWindow::slotFileOpenRecent); + connect(v, &WelcomeView::showIntroduction, this, &Part::slotShowIntroduction); + connect(v, &WelcomeView::projectCreated, doc, &MainDocument::slotProjectCreated); + connect(v, &WelcomeView::finished, this, &Part::finish); connect(v, SIGNAL(openTemplate(QUrl)), this, SLOT(openTemplate(QUrl))); return v; } void Part::slotShowIntroduction() { startUpWidget->setCurrentIndex(1); slotOpenUrlRequest(static_cast(startUpWidget->currentWidget()), QUrl("about:plan/main")); } void Part::slotOpenUrlRequest( HtmlView *v, const QUrl &url ) { debugPlan<setCurrentIndex(0); return; } if ( url.url().startsWith( QLatin1String( "about:plan" ) ) ) { MainDocument *doc = static_cast(document()); doc->aboutPage().generatePage( v->htmlPart(), url ); return; } } if ( url.scheme() == QLatin1String("help") ) { KHelpClient::invokeHelp( "", url.fileName() ); return; } // try to open the url debugPlan<htmlPart().setJScriptEnabled(false); v->htmlPart().setJavaEnabled(false); v->htmlPart().setMetaRefreshEnabled(false); v->htmlPart().setPluginsEnabled(false); slotOpenUrlRequest( v, QUrl( "about:plan/main" ) ); - connect( v, SIGNAL(openUrlRequest(HtmlView*,QUrl)), SLOT(slotOpenUrlRequest(HtmlView*,QUrl)) ); + connect( v, &HtmlView::openUrlRequest, this, &Part::slotOpenUrlRequest ); return v; } diff --git a/src/kptschedulesdocker.cpp b/src/kptschedulesdocker.cpp index f20cc852..fb43e9dc 100644 --- a/src/kptschedulesdocker.cpp +++ b/src/kptschedulesdocker.cpp @@ -1,111 +1,111 @@ /* This file is part of the KDE project * Copyright (C) 2009, 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. */ #include "kptschedulesdocker.h" #include "kptschedule.h" #include #include #include #include #include #include namespace KPlato { SchedulesDocker::SchedulesDocker() { setWindowTitle(i18n("Schedule Selector")); m_view = new QTreeView( this ); m_sfModel.setSourceModel( &m_model ); m_view->setModel( &m_sfModel ); m_sfModel.setFilterKeyColumn ( ScheduleModel::ScheduleScheduled ); m_sfModel.setFilterRole( Qt::EditRole ); m_sfModel.setFilterFixedString( "true" ); m_sfModel.setDynamicSortFilter ( true ); for( int c = 1; c < m_model.columnCount(); ++c ) { m_view->setColumnHidden( c, true ); } m_view->setHeaderHidden( true ); m_view->setSelectionMode( QAbstractItemView::SingleSelection ); m_view->setSelectionBehavior( QAbstractItemView::SelectRows ); setWidget(m_view); - connect( m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged()) ); + connect( m_view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SchedulesDocker::slotSelectionChanged ); } SchedulesDocker::~SchedulesDocker() { } void SchedulesDocker::slotSelectionChanged() { emit selectionChanged( selectedSchedule() ); } void SchedulesDocker::setProject( Project *project ) { debugPlan<selectionModel()->selectedRows(); Q_ASSERT( lst.count() <= 1 ); ScheduleManager *sm = 0; if ( ! lst.isEmpty() ) { sm = m_model.manager( m_sfModel.mapToSource( lst.first() ) ); } return sm; } void SchedulesDocker::setSelectedSchedule( ScheduleManager *sm ) { qDebug()<<"setSelectedSchedule:"<selectionModel()->select( idx, QItemSelectionModel::ClearAndSelect ); qDebug()<<"setSelectedSchedule:"< 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 "kpttaskdefaultpanel.h" #include "kptduration.h" #include "kptmycombobox_p.h" #include "calligraplansettings.h" #ifdef PLAN_KDEPIMLIBS_FOUND #include #include #include #endif #include #include #include namespace KPlato { TaskDefaultPanel::TaskDefaultPanel( QWidget *parent ) : ConfigTaskPanelImpl( parent ) { } //----------------------------- ConfigTaskPanelImpl::ConfigTaskPanelImpl(QWidget *p ) : QWidget(p) { setupUi(this); kcfg_ExpectedEstimate->setMinimumUnit( (Duration::Unit)KPlatoSettings::self()->minimumDurationUnit() ); kcfg_ExpectedEstimate->setMaximumUnit( (Duration::Unit)KPlatoSettings::self()->maximumDurationUnit() ); #ifndef PLAN_KDEPIMLIBS_FOUND chooseLeader->hide(); #endif // FIXME // [Bug 311940] New: Plan crashes when typing a text in the filter textbox before the textbook is fully loaded when selecting a contact from the adressbook chooseLeader->hide(); initDescription(); - connect(chooseLeader, SIGNAL(clicked()), SLOT(changeLeader())); + connect(chooseLeader, &QAbstractButton::clicked, this, &ConfigTaskPanelImpl::changeLeader); - connect( kcfg_ConstraintStartTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(startDateTimeChanged(QDateTime)) ); + connect( kcfg_ConstraintStartTime, &QDateTimeEdit::dateTimeChanged, this, &ConfigTaskPanelImpl::startDateTimeChanged ); - connect( kcfg_ConstraintEndTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(endDateTimeChanged(QDateTime)) ); + connect( kcfg_ConstraintEndTime, &QDateTimeEdit::dateTimeChanged, this, &ConfigTaskPanelImpl::endDateTimeChanged ); // Hack to have an interface to kcfg wo adding a custom class for this kcfg_Unit->addItems( Duration::unitList( true ) ); - connect( kcfg_ExpectedEstimate, SIGNAL(unitChanged(int)), SLOT(unitChanged(int)) ); + connect( kcfg_ExpectedEstimate, &DurationSpinBox::unitChanged, this, &ConfigTaskPanelImpl::unitChanged ); kcfg_Unit->hide(); connect( kcfg_Unit, SIGNAL(currentIndexChanged(int)), SLOT(currentUnitChanged(int)) ); } void ConfigTaskPanelImpl::initDescription() { toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly ); KActionCollection *collection = new KActionCollection( this ); //krazy:exclude=tipsandthis kcfg_Description->setRichTextSupport( KRichTextWidget::SupportBold | KRichTextWidget::SupportItalic | KRichTextWidget::SupportUnderline | KRichTextWidget::SupportStrikeOut | KRichTextWidget::SupportChangeListStyle | KRichTextWidget::SupportAlignment | KRichTextWidget::SupportFormatPainting ); collection->addActions(kcfg_Description->createActions()); toolbar->addAction( collection->action( "format_text_bold" ) ); toolbar->addAction( collection->action( "format_text_italic" ) ); toolbar->addAction( collection->action( "format_text_underline" ) ); toolbar->addAction( collection->action( "format_text_strikeout" ) ); toolbar->addSeparator(); toolbar->addAction( collection->action( "format_list_style" ) ); toolbar->addSeparator(); toolbar->addAction( collection->action( "format_align_left" ) ); toolbar->addAction( collection->action( "format_align_center" ) ); toolbar->addAction( collection->action( "format_align_right" ) ); toolbar->addAction( collection->action( "format_align_justify" ) ); toolbar->addSeparator(); // toolbar->addAction( collection->action( "format_painter" ) ); // kcfg_Description->append( "" ); kcfg_Description->setReadOnly( false ); kcfg_Description->setOverwriteMode( false ); kcfg_Description->setLineWrapMode( KTextEdit::WidgetWidth ); kcfg_Description->setTabChangesFocus( true ); } void ConfigTaskPanelImpl::changeLeader() { #ifdef PLAN_KDEPIMLIBS_FOUND QPointer dlg = new Akonadi::EmailAddressSelectionDialog( this ); if ( dlg->exec() && dlg ) { QStringList names; const Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); foreach ( const Akonadi::EmailAddressSelection &selection, selections ) { QString s = selection.name(); if ( ! selection.email().isEmpty() ) { if ( ! selection.name().isEmpty() ) { s += " <"; } s += selection.email(); if ( ! selection.name().isEmpty() ) { s += '>'; } if ( ! s.isEmpty() ) { names << s; } } } if ( ! names.isEmpty() ) { kcfg_Leader->setText( names.join( ", " ) ); } } #endif } void ConfigTaskPanelImpl::startDateTimeChanged( const QDateTime &dt ) { if ( dt > kcfg_ConstraintEndTime->dateTime() ) { kcfg_ConstraintEndTime->setDateTime( dt ); } } void ConfigTaskPanelImpl::endDateTimeChanged( const QDateTime &dt ) { if ( kcfg_ConstraintStartTime->dateTime() > dt ) { kcfg_ConstraintStartTime->setDateTime( dt ); } } void ConfigTaskPanelImpl::unitChanged( int unit ) { if ( kcfg_Unit->currentIndex() != unit ) { kcfg_Unit->setCurrentIndex( unit ); // kcfg uses the activated() signal to track changes kcfg_Unit->emitActivated( unit ); } } void ConfigTaskPanelImpl::currentUnitChanged( int unit ) { // to get values set at startup if ( unit != kcfg_ExpectedEstimate->unit() ) { kcfg_ExpectedEstimate->setUnit( (Duration::Unit)unit ); } } } //KPlato namespace diff --git a/src/kptview.cpp b/src/kptview.cpp index 7dcf87c2..5b543dae 100644 --- a/src/kptview.cpp +++ b/src/kptview.cpp @@ -1,3258 +1,3258 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 Torben Weis Copyright (C) 2002 - 2011 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. */ #include "kptview.h" #include #include #include "KoDocumentInfo.h" #include "KoMainWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kptlocale.h" #include "kptviewbase.h" #include "kptaccountsview.h" #include "kptaccountseditor.h" #include "kptcalendareditor.h" #include "kptfactory.h" #include "kptmilestoneprogressdialog.h" #include "kpttaskdescriptiondialog.h" #include "kptnode.h" #include "kptmaindocument.h" #include "kptproject.h" #include "kptmainprojectdialog.h" #include "kpttask.h" #include "kptsummarytaskdialog.h" #include "kpttaskdialog.h" #include "kpttaskprogressdialog.h" #include "kptganttview.h" #include "kpttaskeditor.h" #include "kptdependencyeditor.h" #include "kptperteditor.h" #include "kptdatetime.h" #include "kptcommand.h" #include "kptrelation.h" #include "kptrelationdialog.h" #include "kptresourceappointmentsview.h" #include "kptresourceeditor.h" #include "kptscheduleeditor.h" #include "kptresourcedialog.h" #include "kptresource.h" #include "kptstandardworktimedialog.h" #include "kptwbsdefinitiondialog.h" #include "kptresourceassignmentview.h" #include "kpttaskstatusview.h" #include "kptsplitterview.h" #include "kptpertresult.h" #include "ConfigProjectPanel.h" #include "ConfigWorkVacationPanel.h" #include "kpttaskdefaultpanel.h" #include "kptworkpackageconfigpanel.h" #include "kptcolorsconfigpanel.h" #include "kptinsertfiledlg.h" #include "kpthtmlview.h" #include "about/aboutpage.h" #include "kptlocaleconfigmoneydialog.h" #include "kptflatproxymodel.h" #include "kpttaskstatusmodel.h" #include "reportsgenerator/ReportsGeneratorView.h" #ifdef PLAN_USE_KREPORT #include "reports/reportview.h" #include "reports/reportdata.h" #endif #include "kptviewlistdialog.h" #include "kptviewlistdocker.h" #include "kptviewlist.h" #include "kptschedulesdocker.h" #include "kptpart.h" #include "kptdebug.h" #include "calligraplansettings.h" #include "kptprintingcontrolprivate.h" // #include "KPtViewAdaptor.h" #include namespace KPlato { //------------------------------- ConfigDialog::ConfigDialog(QWidget *parent, const QString& name, KConfigSkeleton *config ) : KConfigDialog( parent, name, config ), m_config( config ) { KConfigDialogManager::changedMap()->insert("KRichTextWidget", SIGNAL(textChanged()) ); } bool ConfigDialog::hasChanged() { QRegExp kcfg( "kcfg_*" ); foreach ( KRichTextWidget *w, findChildren( kcfg ) ) { KConfigSkeletonItem *item = m_config->findItem( w->objectName().mid(5) ); if ( ! item->isEqual( w->toHtml() ) ) { return true; } } return false; } void ConfigDialog::updateSettings() { bool changed = false; QRegExp kcfg( "kcfg_*" ); foreach ( KRichTextWidget *w, findChildren( kcfg ) ) { KConfigSkeletonItem *item = m_config->findItem( w->objectName().mid(5) ); if ( ! item ) { warnPlan << "The setting '" << w->objectName().mid(5) << "' has disappeared!"; continue; } if ( ! item->isEqual( QVariant( w->toHtml() ) ) ) { item->setProperty( QVariant( w->toHtml() ) ); changed = true; } } if ( changed ) { m_config->save(); } } void ConfigDialog::updateWidgets() { QRegExp kcfg( "kcfg_*" ); foreach ( KRichTextWidget *w, findChildren( kcfg ) ) { KConfigSkeletonItem *item = m_config->findItem( w->objectName().mid(5) ); if ( ! item ) { warnPlan << "The setting '" << w->objectName().mid(5) << "' has disappeared!"; continue; } if ( ! item->isEqual( QVariant( w->toHtml() ) ) ) { w->setHtml( item->property().toString() ); } } } void ConfigDialog::updateWidgetsDefault() { bool usedefault = m_config->useDefaults( true ); updateWidgets(); m_config->useDefaults( usedefault ); } bool ConfigDialog::isDefault() { bool bUseDefaults = m_config->useDefaults(true); bool result = !hasChanged(); m_config->useDefaults(bUseDefaults); return result; } //------------------------------------ View::View(KoPart *part, MainDocument *doc, QWidget *parent) : KoView(part, doc, parent), m_currentEstimateType( Estimate::Use_Expected ), m_scheduleActionGroup( new QActionGroup( this ) ), m_readWrite( false ), m_defaultView(1), m_partpart (part) { //debugPlan; doc->registerView( this ); setComponentName(Factory::global().componentName(), Factory::global().componentDisplayName()); if ( !doc->isReadWrite() ) setXMLFile( "calligraplan_readonly.rc" ); else setXMLFile( "calligraplan.rc" ); // new ViewAdaptor( this ); m_sp = new QSplitter( this ); QVBoxLayout *layout = new QVBoxLayout( this ); layout->setMargin(0); layout->addWidget( m_sp ); ViewListDocker *docker = 0; if ( mainWindow() == 0 ) { // Don't use docker if embedded m_viewlist = new ViewListWidget(doc, m_sp); m_viewlist->setProject( &( getProject() ) ); - connect( m_viewlist, SIGNAL(selectionChanged(KPlato::ScheduleManager*)), SLOT(slotSelectionChanged(KPlato::ScheduleManager*))); - connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), m_viewlist, SLOT(setSelectedSchedule(KPlato::ScheduleManager*))); - connect( m_viewlist, SIGNAL(updateViewInfo(KPlato::ViewListItem*)), SLOT(slotUpdateViewInfo(KPlato::ViewListItem*))); + connect( m_viewlist, &ViewListWidget::selectionChanged, this, &View::slotSelectionChanged); + connect( this, &View::currentScheduleManagerChanged, m_viewlist, &ViewListWidget::setSelectedSchedule); + connect( m_viewlist, &ViewListWidget::updateViewInfo, this, &View::slotUpdateViewInfo); } else { ViewListDockerFactory vl(this); docker = static_cast(mainWindow()->createDockWidget(&vl)); if (docker->view() != this) { docker->setView(this); } m_viewlist = docker->viewList(); #if 0 //SchedulesDocker SchedulesDockerFactory sdf; SchedulesDocker *sd = dynamic_cast( createDockWidget( &sdf ) ); Q_ASSERT( sd ); sd->setProject( &getProject() ); connect(sd, SIGNAL(selectionChanged(KPlato::ScheduleManager*)), SLOT(slotSelectionChanged(KPlato::ScheduleManager*))); connect(this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), sd, SLOT(setSelectedSchedule(KPlato::ScheduleManager*))); #endif } m_tab = new QStackedWidget( m_sp ); //////////////////////////////////////////////////////////////////////////////////////////////////// // Add sub views createIntroductionView(); // The menu items // ------ File /* actionCreateTemplate = new QAction( i18n( "&Create Template From Document..." ), this ); actionCollection()->addAction("file_createtemplate", actionCreateTemplate ); connect( actionCreateTemplate, SIGNAL(triggered(bool)), SLOT(slotCreateTemplate()) ); */ actionCreateNewProject = new QAction( i18n( "&Create New Project..." ), this ); actionCollection()->addAction("file_createnewproject", actionCreateNewProject ); - connect( actionCreateNewProject, SIGNAL(triggered(bool)), SLOT(slotCreateNewProject()) ); + connect( actionCreateNewProject, &QAction::triggered, this, &View::slotCreateNewProject ); // ------ Edit actionCut = actionCollection()->addAction(KStandardAction::Cut, "edit_cut", this, SLOT(slotEditCut())); actionCopy = actionCollection()->addAction(KStandardAction::Copy, "edit_copy", this, SLOT(slotEditCopy())); actionPaste = actionCollection()->addAction(KStandardAction::Paste, "edit_paste", this, SLOT(slotEditPaste())); // ------ View actionCollection()->addAction( KStandardAction::Redisplay, "view_refresh" , this, SLOT(slotRefreshView()) ); actionViewSelector = new KToggleAction(i18n("Show Selector"), this); actionCollection()->addAction("view_show_selector", actionViewSelector ); - connect( actionViewSelector, SIGNAL(triggered(bool)), SLOT(slotViewSelector(bool)) ); + connect( actionViewSelector, &QAction::triggered, this, &View::slotViewSelector ); // ------ Insert // ------ Project actionEditMainProject = new QAction(koIcon("view-time-schedule-edit"), i18n("Edit Main Project..."), this); actionCollection()->addAction("project_edit", actionEditMainProject ); - connect( actionEditMainProject, SIGNAL(triggered(bool)), SLOT(slotProjectEdit()) ); + connect( actionEditMainProject, &QAction::triggered, this, &View::slotProjectEdit ); actionEditStandardWorktime = new QAction(koIcon("configure"), i18n("Define Estimate Conversions..."), this); actionCollection()->addAction("project_worktime", actionEditStandardWorktime ); - connect( actionEditStandardWorktime, SIGNAL(triggered(bool)), SLOT(slotProjectWorktime()) ); + connect( actionEditStandardWorktime, &QAction::triggered, this, &View::slotProjectWorktime ); // ------ Tools actionDefineWBS = new QAction(koIcon("configure"), i18n("Define WBS Pattern..."), this); actionCollection()->addAction("tools_define_wbs", actionDefineWBS ); - connect( actionDefineWBS, SIGNAL(triggered(bool)), SLOT(slotDefineWBS()) ); + connect( actionDefineWBS, &QAction::triggered, this, &View::slotDefineWBS ); actionInsertFile = new QAction(koIcon("document-import"), i18n("Insert Project File..."), this); actionCollection()->addAction("insert_file", actionInsertFile ); - connect( actionInsertFile, SIGNAL(triggered(bool)), SLOT(slotInsertFile()) ); + connect( actionInsertFile, &QAction::triggered, this, &View::slotInsertFile ); // ------ Settings actionConfigure = new QAction(koIcon("configure"), i18n("Configure Plan..."), this); actionCollection()->addAction("configure", actionConfigure ); - connect( actionConfigure, SIGNAL(triggered(bool)), SLOT(slotConfigure()) ); + connect( actionConfigure, &QAction::triggered, this, &View::slotConfigure ); actionCurrencyConfig = new QAction(koIcon("configure"), i18n("Define Currency..."), this); actionCollection()->addAction( "config_currency", actionCurrencyConfig ); - connect( actionCurrencyConfig, SIGNAL(triggered(bool)), SLOT(slotCurrencyConfig()) ); + connect( actionCurrencyConfig, &QAction::triggered, this, &View::slotCurrencyConfig ); #ifdef PLAN_USE_KREPORT actionOpenReportFile = new QAction(koIcon("document-open"), i18n("Open Report Definition File..."), this); actionCollection()->addAction( "reportdesigner_open_file", actionOpenReportFile ); connect( actionOpenReportFile, SIGNAL(triggered(bool)), SLOT(slotOpenReportFile()) ); #endif // ------ Help actionIntroduction = new QAction(koIcon("dialog-information"), i18n("Introduction to Plan"), this); actionCollection()->addAction("plan_introduction", actionIntroduction ); - connect( actionIntroduction, SIGNAL(triggered(bool)), SLOT(slotIntroduction()) ); + connect( actionIntroduction, &QAction::triggered, this, &View::slotIntroduction ); // ------ Popup actionOpenNode = new QAction(koIcon("document-edit"), i18n("Edit..."), this); actionCollection()->addAction("node_properties", actionOpenNode ); connect( actionOpenNode, SIGNAL(triggered(bool)), SLOT(slotOpenNode()) ); actionTaskProgress = new QAction(koIcon("document-edit"), i18n("Progress..."), this); actionCollection()->addAction("task_progress", actionTaskProgress ); - connect( actionTaskProgress, SIGNAL(triggered(bool)), SLOT(slotTaskProgress()) ); + connect( actionTaskProgress, &QAction::triggered, this, &View::slotTaskProgress ); actionDeleteTask = new QAction(koIcon("edit-delete"), i18n("Delete Task"), this); actionCollection()->addAction("delete_task", actionDeleteTask ); connect( actionDeleteTask, SIGNAL(triggered(bool)), SLOT(slotDeleteTask()) ); actionTaskDescription = new QAction(koIcon("document-edit"), i18n("Description..."), this); actionCollection()->addAction("task_description", actionTaskDescription ); - connect( actionTaskDescription, SIGNAL(triggered(bool)), SLOT(slotTaskDescription()) ); + connect( actionTaskDescription, &QAction::triggered, this, &View::slotTaskDescription ); actionIndentTask = new QAction(koIcon("format-indent-more"), i18n("Indent Task"), this); actionCollection()->addAction("indent_task", actionIndentTask ); - connect( actionIndentTask, SIGNAL(triggered(bool)), SLOT(slotIndentTask()) ); + connect( actionIndentTask, &QAction::triggered, this, &View::slotIndentTask ); actionUnindentTask= new QAction(koIcon("format-indent-less"), i18n("Unindent Task"), this); actionCollection()->addAction("unindent_task", actionUnindentTask ); - connect( actionUnindentTask, SIGNAL(triggered(bool)), SLOT(slotUnindentTask()) ); + connect( actionUnindentTask, &QAction::triggered, this, &View::slotUnindentTask ); actionMoveTaskUp = new QAction(koIcon("arrow-up"), i18n("Move Task Up"), this); actionCollection()->addAction("move_task_up", actionMoveTaskUp ); - connect( actionMoveTaskUp, SIGNAL(triggered(bool)), SLOT(slotMoveTaskUp()) ); + connect( actionMoveTaskUp, &QAction::triggered, this, &View::slotMoveTaskUp ); actionMoveTaskDown = new QAction(koIcon("arrow-down"), i18n("Move Task Down"), this); actionCollection()->addAction("move_task_down", actionMoveTaskDown ); - connect( actionMoveTaskDown, SIGNAL(triggered(bool)), SLOT(slotMoveTaskDown()) ); + connect( actionMoveTaskDown, &QAction::triggered, this, &View::slotMoveTaskDown ); actionEditResource = new QAction(koIcon("document-edit"), i18n("Edit Resource..."), this); actionCollection()->addAction("edit_resource", actionEditResource ); connect( actionEditResource, SIGNAL(triggered(bool)), SLOT(slotEditResource()) ); actionEditRelation = new QAction(koIcon("document-edit"), i18n("Edit Dependency..."), this); actionCollection()->addAction("edit_dependency", actionEditRelation ); connect( actionEditRelation, SIGNAL(triggered(bool)), SLOT(slotModifyRelation()) ); actionDeleteRelation = new QAction(koIcon("edit-delete"), i18n("Delete Dependency"), this); actionCollection()->addAction("delete_dependency", actionDeleteRelation ); - connect( actionDeleteRelation, SIGNAL(triggered(bool)), SLOT(slotDeleteRelation()) ); + connect( actionDeleteRelation, &QAction::triggered, this, &View::slotDeleteRelation ); // Viewlist popup - connect( m_viewlist, SIGNAL(createView()), SLOT(slotCreateView()) ); + connect( m_viewlist, &ViewListWidget::createView, this, &View::slotCreateView ); m_estlabel = new QLabel( "", 0 ); if ( statusBar() ) { addStatusBarItem( m_estlabel, 0, true ); } - connect( &getProject(), SIGNAL(scheduleChanged(KPlato::MainSchedule*)), SLOT(slotScheduleChanged(KPlato::MainSchedule*)) ); + connect( &getProject(), &Project::scheduleChanged, this, &View::slotScheduleChanged ); - connect( &getProject(), SIGNAL(scheduleAdded(const KPlato::MainSchedule*)), SLOT(slotScheduleAdded(const KPlato::MainSchedule*)) ); - connect( &getProject(), SIGNAL(scheduleRemoved(const KPlato::MainSchedule*)), SLOT(slotScheduleRemoved(const KPlato::MainSchedule*)) ); + connect( &getProject(), &Project::scheduleAdded, this, &View::slotScheduleAdded ); + connect( &getProject(), &Project::scheduleRemoved, this, &View::slotScheduleRemoved ); slotPlugScheduleActions(); - connect( doc, SIGNAL(changed()), SLOT(slotUpdate()) ); + connect( doc, &MainDocument::changed, this, &View::slotUpdate ); - connect( m_scheduleActionGroup, SIGNAL(triggered(QAction*)), SLOT(slotViewSchedule(QAction*)) ); + connect( m_scheduleActionGroup, &QActionGroup::triggered, this, &View::slotViewSchedule ); - connect( getPart(), SIGNAL(workPackageLoaded()), SLOT(slotWorkPackageLoaded()) ); + connect( getPart(), &MainDocument::workPackageLoaded, this, &View::slotWorkPackageLoaded ); // hide unused dockers - QTimer::singleShot( 0, this, SLOT(hideToolDocker()) ); + QTimer::singleShot( 0, this, &View::hideToolDocker ); // create views after dockers hidden, views take time for large projects - QTimer::singleShot( 100, this, SLOT(initiateViews()) ); + QTimer::singleShot( 100, this, &View::initiateViews ); const QList pluginFactories = KoPluginLoader::instantiatePluginFactories(QStringLiteral("calligraplan/extensions")); foreach (KPluginFactory* factory, pluginFactories) { QObject *object = factory->create(this, QVariantList()); KXMLGUIClient *clientPlugin = dynamic_cast(object); if (clientPlugin) { insertChildClient(clientPlugin); } else { // not our/valid plugin, so delete the created object object->deleteLater(); } } // do not watch task module changes if we are editing one if (!doc->isTaskModule()) { QString dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); if (!dir.isEmpty()) { dir += "/taskmodules"; m_dirwatch.addDir(dir, KDirWatch::WatchFiles); QStringList modules = KoResourcePaths::findAllResources( "calligraplan_taskmodules", "*.plan", KoResourcePaths::NoDuplicates|KoResourcePaths::Recursive ); for (const QString &f : modules) { m_dirwatch.addFile(f); } - connect(&m_dirwatch, SIGNAL(created(QString)), this, SLOT(taskModuleFileChanged(QString))); - connect(&m_dirwatch, SIGNAL(deleted(QString)), this, SLOT(taskModuleFileChanged(QString))); + connect(&m_dirwatch, &KDirWatch::created, this, &View::taskModuleFileChanged); + connect(&m_dirwatch, &KDirWatch::deleted, this, &View::taskModuleFileChanged); } } //debugPlan<<" end"; } View::~View() { ViewBase *view = currentView(); if (view) { // deactivate view to remove dockers etc slotGuiActivated(view, false); } /* removeStatusBarItem( m_estlabel ); delete m_estlabel;*/ } // hackish way to get rid of unused dockers, but as long as no official way exists... void View::hideToolDocker() { if ( mainWindow() ) { QStringList lst; lst << "KPlatoViewList" << "Scripting"; QStringList names; foreach ( QDockWidget *w, mainWindow()->dockWidgets() ) { if ( ! lst.contains( w->objectName() ) ) { names << w->windowTitle(); w->setFeatures( QDockWidget::DockWidgetClosable ); w->hide(); } } foreach(const KActionCollection *c, KActionCollection::allCollections()) { KActionMenu *a = qobject_cast(c->action("settings_dockers_menu")); if ( a ) { QList actions = a->menu()->actions(); foreach ( QAction *act, actions ) { if ( names.contains( act->text() ) ) { a->removeAction( act ); } } a->addSeparator(); break; } } } } void View::initiateViews() { QApplication::setOverrideCursor( Qt::WaitCursor ); createViews(); - connect( m_viewlist, SIGNAL(activated(ViewListItem*,ViewListItem*)), SLOT(slotViewActivated(ViewListItem*,ViewListItem*)) ); + connect( m_viewlist, &ViewListWidget::activated, this, &View::slotViewActivated ); // after createViews() !! - connect( m_viewlist, SIGNAL(viewListItemRemoved(ViewListItem*)), SLOT(slotViewListItemRemoved(ViewListItem*)) ); + connect( m_viewlist, &ViewListWidget::viewListItemRemoved, this, &View::slotViewListItemRemoved ); // after createViews() !! - connect( m_viewlist, SIGNAL(viewListItemInserted(ViewListItem*,ViewListItem*,int)), SLOT(slotViewListItemInserted(ViewListItem*,ViewListItem*,int)) ); + connect( m_viewlist, &ViewListWidget::viewListItemInserted, this, &View::slotViewListItemInserted ); QDockWidget *docker = qobject_cast( m_viewlist->parent() ); if ( docker ) { // after createViews() !! connect( m_viewlist, SIGNAL(modified()), docker, SLOT(slotModified())); connect( m_viewlist, SIGNAL(modified()), getPart(), SLOT(viewlistModified())); connect(getPart(), SIGNAL(viewlistModified(bool)), docker, SLOT(updateWindowTitle(bool))); } - connect( m_tab, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)) ); + connect( m_tab, &QStackedWidget::currentChanged, this, &View::slotCurrentChanged ); slotSelectDefaultView(); loadContext(); QApplication::restoreOverrideCursor(); } void View::slotCreateNewProject() { debugPlan; if ( KMessageBox::Continue == KMessageBox::warningContinueCancel( this, xi18nc( "@info", "This action cannot be undone." "Create a new Project from the current project " "with new project- and task identities." "Resource- and calendar identities are not changed." "All scheduling information is removed." "Do you want to continue?" ) ) ) { emit currentScheduleManagerChanged(0); getPart()->createNewProject(); slotOpenNode( &getProject() ); } } void View::createViews() { Context *ctx = getPart()->context(); if ( ctx && ctx->isLoaded() ) { debugPlan<<"isLoaded"; KoXmlNode n = ctx->context().namedItem( "categories" ); if ( n.isNull() ) { warnPlan<<"No categories"; } else { n = n.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if (e.tagName() != "category") { continue; } debugPlan<<"category: "<addCategory( ct, cn ); KoXmlNode n1 = e.firstChild(); for ( ; ! n1.isNull(); n1 = n1.nextSibling() ) { if ( ! n1.isElement() ) { continue; } KoXmlElement e1 = n1.toElement(); if (e1.tagName() != "view") { continue; } ViewBase *v = 0; QString type = e1.attribute( "viewtype" ); QString tag = e1.attribute( "tag" ); QString name = e1.attribute( "name" ); QString tip = e1.attribute( "tooltip" ); v = createView( cat, type, tag, name, tip ); //KoXmlNode settings = e1.namedItem( "settings " ); ???? KoXmlNode settings = e1.firstChild(); for ( ; ! settings.isNull(); settings = settings.nextSibling() ) { if ( settings.nodeName() == "settings" ) { break; } } if ( v && settings.isElement() ) { debugPlan<<" settings"; v->loadContext( settings.toElement() ); } } } } } else { debugPlan<<"Default"; ViewListItem *cat; QString ct = "Editors"; cat = m_viewlist->addCategory( ct, defaultCategoryInfo( ct ).name ); createCalendarEditor( cat, "CalendarEditor", QString(), TIP_USE_DEFAULT_TEXT ); createAccountsEditor( cat, "AccountsEditor", QString(), TIP_USE_DEFAULT_TEXT ); createResourceEditor( cat, "ResourceEditor", QString(), TIP_USE_DEFAULT_TEXT ); createTaskEditor( cat, "TaskEditor", QString(), TIP_USE_DEFAULT_TEXT ); createDependencyEditor( cat, "DependencyEditor", QString(), TIP_USE_DEFAULT_TEXT ); // Do not show by default // createPertEditor( cat, "PertEditor", QString(), TIP_USE_DEFAULT_TEXT ); createScheduleHandler( cat, "ScheduleHandlerView", QString(), TIP_USE_DEFAULT_TEXT ); ct = "Views"; cat = m_viewlist->addCategory( ct, defaultCategoryInfo( ct ).name ); createGanttView( cat, "GanttView", QString(), TIP_USE_DEFAULT_TEXT ); createMilestoneGanttView( cat, "MilestoneGanttView", QString(), TIP_USE_DEFAULT_TEXT ); createResourceAppointmentsView( cat, "ResourceAppointmentsView", QString(), TIP_USE_DEFAULT_TEXT ); createResourceAppointmentsGanttView( cat, "ResourceAppointmentsGanttView", QString(), TIP_USE_DEFAULT_TEXT ); createAccountsView( cat, "AccountsView", QString(), TIP_USE_DEFAULT_TEXT ); ct = "Execution"; cat = m_viewlist->addCategory( ct, defaultCategoryInfo( ct ).name ); createProjectStatusView( cat, "ProjectStatusView", QString(), TIP_USE_DEFAULT_TEXT ); createPerformanceStatusView( cat, "PerformanceStatusView", QString(), TIP_USE_DEFAULT_TEXT ); createTaskStatusView( cat, "TaskStatusView", QString(), TIP_USE_DEFAULT_TEXT ); createTaskView( cat, "TaskView", QString(), TIP_USE_DEFAULT_TEXT ); createTaskWorkPackageView( cat, "TaskWorkPackageView", QString(), TIP_USE_DEFAULT_TEXT ); ct = "Reports"; cat = m_viewlist->addCategory(ct, defaultCategoryInfo(ct).name); createReportsGeneratorView(cat, "ReportsGeneratorView", i18n("Generate reports"), TIP_USE_DEFAULT_TEXT); #ifdef PLAN_USE_KREPORT // Let user add reports explicitly, we prefer reportsgenerator now // A little hack to get the user started... #if 0 ReportView *rv = qobject_cast( createReportView( cat, "ReportView", i18n( "Task Status Report" ), TIP_USE_DEFAULT_TEXT ) ); if ( rv ) { QDomDocument doc; doc.setContent( standardTaskStatusReport() ); rv->loadXML( doc ); } #endif #endif } } ViewBase *View::createView( ViewListItem *cat, const QString &type, const QString &tag, const QString &name, const QString &tip, int index ) { ViewBase *v = 0; //NOTE: type is the same as classname (so if it is changed...) if ( type == "CalendarEditor" ) { v = createCalendarEditor( cat, tag, name, tip, index ); } else if ( type == "AccountsEditor" ) { v = createAccountsEditor( cat, tag, name, tip, index ); } else if ( type == "ResourceEditor" ) { v = createResourceEditor( cat, tag, name, tip, index ); } else if ( type == "TaskEditor" ) { v = createTaskEditor( cat, tag, name, tip, index ); } else if ( type == "DependencyEditor" ) { v = createDependencyEditor( cat, tag, name, tip, index ); } else if ( type == "PertEditor" ) { v = createPertEditor( cat, tag, name, tip, index ); } else if ( type == "ScheduleEditor" ) { v = createScheduleEditor( cat, tag, name, tip, index ); } else if ( type == "ScheduleHandlerView" ) { v = createScheduleHandler( cat, tag, name, tip, index ); } else if ( type == "ProjectStatusView" ) { v = createProjectStatusView( cat, tag, name, tip, index ); } else if ( type == "TaskStatusView" ) { v = createTaskStatusView( cat, tag, name, tip, index ); } else if ( type == "TaskView" ) { v = createTaskView( cat, tag, name, tip, index ); } else if ( type == "TaskWorkPackageView" ) { v = createTaskWorkPackageView( cat, tag, name, tip, index ); } else if ( type == "GanttView" ) { v = createGanttView( cat, tag, name, tip, index ); } else if ( type == "MilestoneGanttView" ) { v = createMilestoneGanttView( cat, tag, name, tip, index ); } else if ( type == "ResourceAppointmentsView" ) { v = createResourceAppointmentsView( cat, tag, name, tip, index ); } else if ( type == "ResourceAppointmentsGanttView" ) { v = createResourceAppointmentsGanttView( cat, tag, name, tip, index ); } else if ( type == "AccountsView" ) { v = createAccountsView( cat, tag, name, tip, index ); } else if ( type == "PerformanceStatusView" ) { v = createPerformanceStatusView( cat, tag, name, tip, index ); } else if ( type == "ReportsGeneratorView" ) { v = createReportsGeneratorView(cat, tag, name, tip, index); } else if ( type == "ReportView" ) { #ifdef PLAN_USE_KREPORT v = createReportView( cat, tag, name, tip, index ); #endif } else { warnPlan<<"Unknown viewtype: "<type() == ViewListItem::ItemType_SubView ) { itm->setViewInfo( defaultViewInfo( itm->viewType() ) ); } else if ( itm->type() == ViewListItem::ItemType_Category ) { ViewInfo vi = defaultCategoryInfo( itm->tag() ); itm->setViewInfo( vi ); } } ViewInfo View::defaultViewInfo( const QString &type ) const { ViewInfo vi; if ( type == "CalendarEditor" ) { vi.name = i18n( "Work & Vacation" ); vi.tip = xi18nc( "@info:tooltip", "Edit working- and vacation days for resources" ); } else if ( type == "AccountsEditor" ) { vi.name = i18n( "Cost Breakdown Structure" ); vi.tip = xi18nc( "@info:tooltip", "Edit cost breakdown structure." ); } else if ( type == "ResourceEditor" ) { vi.name = i18n( "Resources" ); vi.tip = xi18nc( "@info:tooltip", "Edit resource breakdown structure" ); } else if ( type == "TaskEditor" ) { vi.name = i18n( "Tasks" ); vi.tip = xi18nc( "@info:tooltip", "Edit work breakdown structure" ); } else if ( type == "DependencyEditor" ) { vi.name = i18n( "Dependencies (Graphic)" ); vi.tip = xi18nc( "@info:tooltip", "Edit task dependencies" ); } else if ( type == "PertEditor" ) { vi.name = i18n( "Dependencies (List)" ); vi.tip = xi18nc( "@info:tooltip", "Edit task dependencies" ); } else if ( type == "ScheduleEditor" ) { // This view is not used stand-alone atm vi.name = i18n( "Schedules" ); } else if ( type == "ScheduleHandlerView" ) { vi.name = i18n( "Schedules" ); vi.tip = xi18nc( "@info:tooltip", "Calculate and analyze project schedules" ); } else if ( type == "ProjectStatusView" ) { vi.name = i18n( "Project Performance Chart" ); vi.tip = xi18nc( "@info:tooltip", "View project status information" ); } else if ( type == "TaskStatusView" ) { vi.name = i18n( "Task Status" ); vi.tip = xi18nc( "@info:tooltip", "View task progress information" ); } else if ( type == "TaskView" ) { vi.name = i18n( "Task Execution" ); vi.tip = xi18nc( "@info:tooltip", "View task execution information" ); } else if ( type == "TaskWorkPackageView" ) { vi.name = i18n( "Work Package View" ); vi.tip = xi18nc( "@info:tooltip", "View task work package information" ); } else if ( type == "GanttView" ) { vi.name = i18n( "Gantt" ); vi.tip = xi18nc( "@info:tooltip", "View Gantt chart" ); } else if ( type == "MilestoneGanttView" ) { vi.name = i18n( "Milestone Gantt" ); vi.tip = xi18nc( "@info:tooltip", "View milestone Gantt chart" ); } else if ( type == "ResourceAppointmentsView" ) { vi.name = i18n( "Resource Assignments" ); vi.tip = xi18nc( "@info:tooltip", "View resource assignments in a table" ); } else if ( type == "ResourceAppointmentsGanttView" ) { vi.name = i18n( "Resource Assignments (Gantt)" ); vi.tip = xi18nc( "@info:tooltip", "View resource assignments in Gantt chart" ); } else if ( type == "AccountsView" ) { vi.name = i18n( "Cost Breakdown" ); vi.tip = xi18nc( "@info:tooltip", "View planned and actual cost" ); } else if ( type == "PerformanceStatusView" ) { vi.name = i18n( "Tasks Performance Chart" ); vi.tip = xi18nc( "@info:tooltip", "View tasks performance status information" ); } else if ( type == "ReportsGeneratorView" ) { vi.name = i18n( "Reports Generator" ); vi.tip = xi18nc( "@info:tooltip", "Generate reports" ); } else if ( type == "ReportView" ) { vi.name = i18n( "Report" ); vi.tip = xi18nc( "@info:tooltip", "View report" ); } else { warnPlan<<"Unknown viewtype: "<count()-1) : m_visitedViews.at(m_visitedViews.count() - 2); debugPlan<<"Prev:"<setCurrentIndex(view); return; } if ( url.url().startsWith( QLatin1String( "about:plan" ) ) ) { getPart()->aboutPage().generatePage( v->htmlPart(), url ); return; } } if ( url.scheme() == QLatin1String("help") ) { KHelpClient::invokeHelp( "", url.fileName() ); return; } // try to open the url debugPlan<htmlPart().setJScriptEnabled(false); v->htmlPart().setJavaEnabled(false); v->htmlPart().setMetaRefreshEnabled(false); v->htmlPart().setPluginsEnabled(false); slotOpenUrlRequest( v, QUrl( "about:plan/main" ) ); - connect( v, SIGNAL(openUrlRequest(HtmlView*,QUrl)), SLOT(slotOpenUrlRequest(HtmlView*,QUrl)) ); + connect( v, &HtmlView::openUrlRequest, this, &View::slotOpenUrlRequest ); m_tab->addWidget( v ); return v; } ViewBase *View::createResourceAppointmentsGanttView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ResourceAppointmentsGanttView *v = new ResourceAppointmentsGanttView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ResourceAppointmentsGanttView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); v->setProject( &( getProject() ) ); v->setScheduleManager( currentScheduleManager() ); v->updateReadWrite( m_readWrite ); return v; } ViewBase *View::createResourceAppointmentsView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ResourceAppointmentsView *v = new ResourceAppointmentsView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ResourceAppointmentsView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); v->setProject( &( getProject() ) ); v->setScheduleManager( currentScheduleManager() ); v->updateReadWrite( m_readWrite ); return v; } ViewBase *View::createResourceEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ResourceEditor *resourceeditor = new ResourceEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( resourceeditor ); resourceeditor->setProject( &(getProject()) ); ViewListItem *i = m_viewlist->addView( cat, tag, name, resourceeditor, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ResourceEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( resourceeditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( resourceeditor, &ViewBase::guiActivated, this, &View::slotGuiActivated ); - connect( resourceeditor, SIGNAL(deleteObjectList(QObjectList)), SLOT(slotDeleteResourceObjects(QObjectList)) ); + connect( resourceeditor, &ResourceEditor::deleteObjectList, this, &View::slotDeleteResourceObjects ); connect( resourceeditor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); resourceeditor->updateReadWrite( m_readWrite ); return resourceeditor; } ViewBase *View::createTaskEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { TaskEditor *taskeditor = new TaskEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( taskeditor ); m_defaultView = m_tab->count() - 1; ViewListItem *i = m_viewlist->addView( cat, tag, name, taskeditor, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "TaskEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } taskeditor->setProject( &(getProject()) ); taskeditor->setScheduleManager( currentScheduleManager() ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), taskeditor, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); - connect( taskeditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( taskeditor, &ViewBase::guiActivated, this, &View::slotGuiActivated ); - connect( taskeditor, SIGNAL(addTask()), SLOT(slotAddTask()) ); - connect( taskeditor, SIGNAL(addMilestone()), SLOT(slotAddMilestone()) ); - connect( taskeditor, SIGNAL(addSubtask()), SLOT(slotAddSubTask()) ); - connect( taskeditor, SIGNAL(addSubMilestone()), SLOT(slotAddSubMilestone()) ); + connect( taskeditor, &TaskEditor::addTask, this, &View::slotAddTask ); + connect( taskeditor, &TaskEditor::addMilestone, this, &View::slotAddMilestone ); + connect( taskeditor, &TaskEditor::addSubtask, this, &View::slotAddSubTask ); + connect( taskeditor, &TaskEditor::addSubMilestone, this, &View::slotAddSubMilestone ); connect( taskeditor, SIGNAL(deleteTaskList(QList)), SLOT(slotDeleteTask(QList)) ); - connect( taskeditor, SIGNAL(moveTaskUp()), SLOT(slotMoveTaskUp()) ); - connect( taskeditor, SIGNAL(moveTaskDown()), SLOT(slotMoveTaskDown()) ); - connect( taskeditor, SIGNAL(indentTask()), SLOT(slotIndentTask()) ); - connect( taskeditor, SIGNAL(unindentTask()), SLOT(slotUnindentTask()) ); + connect( taskeditor, &TaskEditor::moveTaskUp, this, &View::slotMoveTaskUp ); + connect( taskeditor, &TaskEditor::moveTaskDown, this, &View::slotMoveTaskDown ); + connect( taskeditor, &TaskEditor::indentTask, this, &View::slotIndentTask ); + connect( taskeditor, &TaskEditor::unindentTask, this, &View::slotUnindentTask ); - connect(taskeditor, SIGNAL(saveTaskModule(QUrl,KPlato::Project*)), SLOT(saveTaskModule(QUrl,KPlato::Project*))); - connect(taskeditor, SIGNAL(removeTaskModule(QUrl)), SLOT(removeTaskModule(QUrl))); + connect(taskeditor, &TaskEditor::saveTaskModule, this, &View::saveTaskModule); + connect(taskeditor, &TaskEditor::removeTaskModule, this, &View::removeTaskModule); connect(taskeditor, SIGNAL(openDocument(QUrl)), static_cast(m_partpart), SLOT(openTaskModule(QUrl))); - connect(this, SIGNAL(taskModulesChanged(QStringList)), taskeditor, SLOT(setTaskModules(QStringList))); + connect(this, &View::taskModulesChanged, taskeditor, &TaskEditor::setTaskModules); connect( taskeditor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); taskeditor->updateReadWrite( m_readWrite ); // last: QStringList modules = KoResourcePaths::findAllResources( "calligraplan_taskmodules", "*.plan", KoResourcePaths::NoDuplicates|KoResourcePaths::Recursive ); debugPlan<setTaskModules( modules ); return taskeditor; } ViewBase *View::createAccountsEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { AccountsEditor *ae = new AccountsEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( ae ); ViewListItem *i = m_viewlist->addView( cat, tag, name, ae, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "AccountsEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } ae->draw( getProject() ); - connect( ae, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( ae, &ViewBase::guiActivated, this, &View::slotGuiActivated ); ae->updateReadWrite( m_readWrite ); return ae; } ViewBase *View::createCalendarEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { CalendarEditor *calendareditor = new CalendarEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( calendareditor ); ViewListItem *i = m_viewlist->addView( cat, tag, name, calendareditor, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "CalendarEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } calendareditor->draw( getProject() ); - connect( calendareditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( calendareditor, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( calendareditor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); calendareditor->updateReadWrite( m_readWrite ); return calendareditor; } ViewBase *View::createScheduleHandler( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ScheduleHandlerView *handler = new ScheduleHandlerView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( handler ); ViewListItem *i = m_viewlist->addView( cat, tag, name, handler, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ScheduleHandlerView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( handler->scheduleEditor(), SIGNAL(addScheduleManager(KPlato::Project*)), SLOT(slotAddScheduleManager(KPlato::Project*)) ); - connect( handler->scheduleEditor(), SIGNAL(deleteScheduleManager(KPlato::Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(KPlato::Project*,ScheduleManager*)) ); - connect( handler->scheduleEditor(), SIGNAL(moveScheduleManager(KPlato::ScheduleManager*,KPlato::ScheduleManager*,int)), SLOT(slotMoveScheduleManager(KPlato::ScheduleManager*,KPlato::ScheduleManager*,int))); + connect( handler->scheduleEditor(), &ScheduleEditor::addScheduleManager, this, &View::slotAddScheduleManager ); + connect( handler->scheduleEditor(), &ScheduleEditor::deleteScheduleManager, this, &View::slotDeleteScheduleManager ); + connect( handler->scheduleEditor(), &ScheduleEditor::moveScheduleManager, this, &View::slotMoveScheduleManager); - connect( handler->scheduleEditor(), SIGNAL(calculateSchedule(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotCalculateSchedule(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( handler->scheduleEditor(), &ScheduleEditor::calculateSchedule, this, &View::slotCalculateSchedule ); - connect( handler->scheduleEditor(), SIGNAL(baselineSchedule(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotBaselineSchedule(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( handler->scheduleEditor(), &ScheduleEditor::baselineSchedule, this, &View::slotBaselineSchedule ); - connect( handler, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( handler, &ViewBase::guiActivated, this, &View::slotGuiActivated ); - connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), handler, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)) ); + connect( this, &View::currentScheduleManagerChanged, handler, &ScheduleHandlerView::currentScheduleManagerChanged ); connect( handler, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); connect(handler, SIGNAL(editNode(KPlato::Node*)), this, SLOT(slotOpenNode(KPlato::Node*))); connect(handler, SIGNAL(editResource(KPlato::Resource*)), this, SLOT(slotEditResource(KPlato::Resource*))); handler->draw( getProject() ); handler->updateReadWrite( m_readWrite ); return handler; } ScheduleEditor *View::createScheduleEditor( QWidget *parent ) { ScheduleEditor *scheduleeditor = new ScheduleEditor(getKoPart(), getPart(), parent ); - connect( scheduleeditor, SIGNAL(addScheduleManager(KPlato::Project*)), SLOT(slotAddScheduleManager(KPlato::Project*)) ); - connect( scheduleeditor, SIGNAL(deleteScheduleManager(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotDeleteScheduleManager(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( scheduleeditor, &ScheduleEditor::addScheduleManager, this, &View::slotAddScheduleManager ); + connect( scheduleeditor, &ScheduleEditor::deleteScheduleManager, this, &View::slotDeleteScheduleManager ); - connect( scheduleeditor, SIGNAL(calculateSchedule(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotCalculateSchedule(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( scheduleeditor, &ScheduleEditor::calculateSchedule, this, &View::slotCalculateSchedule ); - connect( scheduleeditor, SIGNAL(baselineSchedule(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotBaselineSchedule(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( scheduleeditor, &ScheduleEditor::baselineSchedule, this, &View::slotBaselineSchedule ); scheduleeditor->updateReadWrite( m_readWrite ); return scheduleeditor; } ViewBase *View::createScheduleEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ScheduleEditor *scheduleeditor = new ScheduleEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( scheduleeditor ); ViewListItem *i = m_viewlist->addView( cat, tag, name, scheduleeditor, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ScheduleEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } scheduleeditor->setProject( &( getProject() ) ); - connect( scheduleeditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( scheduleeditor, &ViewBase::guiActivated, this, &View::slotGuiActivated ); - connect( scheduleeditor, SIGNAL(addScheduleManager(KPlato::Project*)), SLOT(slotAddScheduleManager(KPlato::Project*)) ); + connect( scheduleeditor, &ScheduleEditor::addScheduleManager, this, &View::slotAddScheduleManager ); - connect( scheduleeditor, SIGNAL(deleteScheduleManager(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotDeleteScheduleManager(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( scheduleeditor, &ScheduleEditor::deleteScheduleManager, this, &View::slotDeleteScheduleManager ); - connect( scheduleeditor, SIGNAL(calculateSchedule(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotCalculateSchedule(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( scheduleeditor, &ScheduleEditor::calculateSchedule, this, &View::slotCalculateSchedule ); - connect( scheduleeditor, SIGNAL(baselineSchedule(KPlato::Project*,KPlato::ScheduleManager*)), SLOT(slotBaselineSchedule(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( scheduleeditor, &ScheduleEditor::baselineSchedule, this, &View::slotBaselineSchedule ); scheduleeditor->updateReadWrite( m_readWrite ); return scheduleeditor; } ViewBase *View::createDependencyEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { DependencyEditor *editor = new DependencyEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( editor ); ViewListItem *i = m_viewlist->addView( cat, tag, name, editor, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "DependencyEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } editor->draw( getProject() ); - connect( editor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( editor, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( editor, SIGNAL(addRelation(KPlato::Node*,KPlato::Node*,int)), SLOT(slotAddRelation(KPlato::Node*,KPlato::Node*,int)) ); connect( editor, SIGNAL(modifyRelation(KPlato::Relation*,int)), SLOT(slotModifyRelation(KPlato::Relation*,int)) ); connect( editor, SIGNAL(modifyRelation(KPlato::Relation*)), SLOT(slotModifyRelation(KPlato::Relation*)) ); connect( editor, SIGNAL(editNode(KPlato::Node*)), SLOT(slotOpenNode(KPlato::Node*)) ); - connect( editor, SIGNAL(addTask()), SLOT(slotAddTask()) ); - connect( editor, SIGNAL(addMilestone()), SLOT(slotAddMilestone()) ); - connect( editor, SIGNAL(addSubMilestone()), SLOT(slotAddSubMilestone()) ); - connect( editor, SIGNAL(addSubtask()), SLOT(slotAddSubTask()) ); + connect( editor, &DependencyEditor::addTask, this, &View::slotAddTask ); + connect( editor, &DependencyEditor::addMilestone, this, &View::slotAddMilestone ); + connect( editor, &DependencyEditor::addSubMilestone, this, &View::slotAddSubMilestone ); + connect( editor, &DependencyEditor::addSubtask, this, &View::slotAddSubTask ); connect( editor, SIGNAL(deleteTaskList(QList)), SLOT(slotDeleteTask(QList)) ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), editor, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( editor, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); editor->updateReadWrite( m_readWrite ); editor->setScheduleManager( currentScheduleManager() ); return editor; } ViewBase *View::createPertEditor( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { PertEditor *perteditor = new PertEditor(getKoPart(), getPart(), m_tab ); m_tab->addWidget( perteditor ); ViewListItem *i = m_viewlist->addView( cat, tag, name, perteditor, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "PertEditor" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } perteditor->draw( getProject() ); - connect( perteditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( perteditor, &ViewBase::guiActivated, this, &View::slotGuiActivated ); m_updatePertEditor = true; perteditor->updateReadWrite( m_readWrite ); return perteditor; } ViewBase *View::createProjectStatusView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ProjectStatusView *v = new ProjectStatusView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ProjectStatusView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); v->updateReadWrite( m_readWrite ); v->setProject( &getProject() ); v->setScheduleManager( currentScheduleManager() ); return v; } ViewBase *View::createPerformanceStatusView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { PerformanceStatusView *v = new PerformanceStatusView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "PerformanceStatusView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); v->updateReadWrite( m_readWrite ); v->setProject( &getProject() ); v->setScheduleManager( currentScheduleManager() ); return v; } ViewBase *View::createTaskStatusView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { TaskStatusView *taskstatusview = new TaskStatusView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( taskstatusview ); ViewListItem *i = m_viewlist->addView( cat, tag, name, taskstatusview, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "TaskStatusView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } - connect( taskstatusview, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( taskstatusview, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), taskstatusview, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( taskstatusview, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); taskstatusview->updateReadWrite( m_readWrite ); taskstatusview->draw( getProject() ); taskstatusview->setScheduleManager( currentScheduleManager() ); return taskstatusview; } ViewBase *View::createTaskView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { TaskView *v = new TaskView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "TaskView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } v->draw( getProject() ); v->setScheduleManager( currentScheduleManager() ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); v->updateReadWrite( m_readWrite ); return v; } ViewBase *View::createTaskWorkPackageView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { TaskWorkPackageView *v = new TaskWorkPackageView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "TaskWorkPackageView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } v->setProject( &getProject() ); v->setScheduleManager( currentScheduleManager() ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); - connect( v, SIGNAL(mailWorkpackage(KPlato::Node*,KPlato::Resource*)), SLOT(slotMailWorkpackage(KPlato::Node*,KPlato::Resource*)) ); - connect( v, SIGNAL(mailWorkpackages(QList,KPlato::Resource*)), SLOT(slotMailWorkpackages(QList,KPlato::Resource*)) ); + connect( v, &TaskWorkPackageView::mailWorkpackage, this, &View::slotMailWorkpackage ); + connect( v, &TaskWorkPackageView::mailWorkpackages, this, &View::slotMailWorkpackages ); connect(v, SIGNAL(checkForWorkPackages()), getPart(), SLOT(checkForWorkPackages())); v->updateReadWrite( m_readWrite ); return v; } ViewBase *View::createGanttView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { GanttView *ganttview = new GanttView(getKoPart(), getPart(), m_tab, koDocument()->isReadWrite() ); m_tab->addWidget( ganttview ); ViewListItem *i = m_viewlist->addView( cat, tag, name, ganttview, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "GanttView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } ganttview->setProject( &( getProject() ) ); ganttview->setScheduleManager( currentScheduleManager() ); - connect( ganttview, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( ganttview, &ViewBase::guiActivated, this, &View::slotGuiActivated ); /* TODO: Review these connect( ganttview, SIGNAL(addRelation(KPlato::Node*,KPlato::Node*,int)), SLOT(slotAddRelation(KPlato::Node*,KPlato::Node*,int)) ); connect( ganttview, SIGNAL(modifyRelation(KPlato::Relation*,int)), SLOT(slotModifyRelation(KPlato::Relation*,int)) ); connect( ganttview, SIGNAL(modifyRelation(KPlato::Relation*)), SLOT(slotModifyRelation(KPlato::Relation*)) ); connect( ganttview, SIGNAL(itemDoubleClicked()), SLOT(slotOpenNode()) ); connect( ganttview, SIGNAL(itemRenamed(KPlato::Node*,QString)), this, SLOT(slotRenameNode(KPlato::Node*,QString)) );*/ connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), ganttview, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( ganttview, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); ganttview->updateReadWrite( m_readWrite ); return ganttview; } ViewBase *View::createMilestoneGanttView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { MilestoneGanttView *ganttview = new MilestoneGanttView(getKoPart(), getPart(), m_tab, koDocument()->isReadWrite() ); m_tab->addWidget( ganttview ); ViewListItem *i = m_viewlist->addView( cat, tag, name, ganttview, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "MilestoneGanttView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } ganttview->setProject( &( getProject() ) ); ganttview->setScheduleManager( currentScheduleManager() ); - connect( ganttview, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( ganttview, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), ganttview, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( ganttview, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); ganttview->updateReadWrite( m_readWrite ); return ganttview; } ViewBase *View::createAccountsView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { AccountsView *accountsview = new AccountsView(getKoPart(), &getProject(), getPart(), m_tab ); m_tab->addWidget( accountsview ); ViewListItem *i = m_viewlist->addView( cat, tag, name, accountsview, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "AccountsView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } accountsview->setScheduleManager( currentScheduleManager() ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), accountsview, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); - connect( accountsview, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( accountsview, &ViewBase::guiActivated, this, &View::slotGuiActivated ); accountsview->updateReadWrite( m_readWrite ); return accountsview; } ViewBase *View::createResourceAssignmentView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { ResourceAssignmentView *resourceAssignmentView = new ResourceAssignmentView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( resourceAssignmentView ); m_updateResourceAssignmentView = true; ViewListItem *i = m_viewlist->addView( cat, tag, name, resourceAssignmentView, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ResourceAssignmentView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } resourceAssignmentView->draw( getProject() ); - connect( resourceAssignmentView, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( resourceAssignmentView, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( resourceAssignmentView, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); resourceAssignmentView->updateReadWrite( m_readWrite ); return resourceAssignmentView; } ViewBase *View::createReportsGeneratorView(ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index) { ReportsGeneratorView *v = new ReportsGeneratorView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView(cat, tag, name, v, getPart(), "", index); ViewInfo vi = defaultViewInfo( "ReportsGeneratorView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } v->setProject( &getProject() ); - connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); - connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(slotRefreshView())); + connect( this, &View::currentScheduleManagerChanged, v, &ViewBase::setScheduleManager ); + connect( this, &View::currentScheduleManagerChanged, v, &ViewBase::slotRefreshView); v->setScheduleManager( currentScheduleManager() ); - connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); + connect( v, &ViewBase::guiActivated, this, &View::slotGuiActivated ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); v->updateReadWrite( m_readWrite ); return v; } ViewBase *View::createReportView( ViewListItem *cat, const QString &tag, const QString &name, const QString &tip, int index ) { #ifdef PLAN_USE_KREPORT ReportView *v = new ReportView(getKoPart(), getPart(), m_tab ); m_tab->addWidget( v ); ViewListItem *i = m_viewlist->addView( cat, tag, name, v, getPart(), "", index ); ViewInfo vi = defaultViewInfo( "ReportView" ); if ( name.isEmpty() ) { i->setText( 0, vi.name ); } if ( tip == TIP_USE_DEFAULT_TEXT ) { i->setToolTip( 0, vi.tip ); } else { i->setToolTip( 0, tip ); } v->setProject( &getProject() ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(setScheduleManager(KPlato::ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(KPlato::ScheduleManager*)), v, SLOT(slotRefreshView())); v->setScheduleManager( currentScheduleManager() ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); v->updateReadWrite( m_readWrite ); return v; #else Q_UNUSED(cat) Q_UNUSED(tag) Q_UNUSED(name) Q_UNUSED(tip) Q_UNUSED(index) return 0; #endif } Project& View::getProject() const { return getPart() ->getProject(); } KoPrintJob * View::createPrintJob() { KoView *v = qobject_cast( canvas() ); if ( v == 0 ) { return 0; } return v->createPrintJob(); } ViewBase *View::currentView() const { return qobject_cast( m_tab->currentWidget() ); } void View::slotEditCut() { ViewBase *v = currentView(); if ( v ) { v->slotEditCut(); } } void View::slotEditCopy() { ViewBase *v = currentView(); if ( v ) { v->slotEditCopy(); } } void View::slotEditPaste() { ViewBase *v = currentView(); if ( v ) { v->slotEditPaste(); } } void View::slotRefreshView() { ViewBase *v = currentView(); if ( v ) { debugPlan<slotRefreshView(); } } void View::slotViewSelector( bool show ) { //debugPlan; m_viewlist->setVisible( show ); } void View::slotInsertResourcesFile(const QString &file, const QUrl &projects) { getPart()->insertResourcesFile(QUrl(file), projects); } void View::slotInsertFile() { InsertFileDialog *dlg = new InsertFileDialog( getProject(), currentTask(), this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotInsertFileFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void View::slotInsertFileFinished( int result ) { InsertFileDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == QDialog::Accepted ) { getPart()->insertFile( dlg->url(), dlg->parentNode(), dlg->afterNode() ); } dlg->deleteLater(); } void View::slotProjectEdit() { slotOpenNode( &getProject() ); } void View::slotProjectWorktime() { StandardWorktimeDialog *dia = new StandardWorktimeDialog( getProject(), this ); connect(dia, SIGNAL(finished(int)), this, SLOT(slotProjectWorktimeFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotProjectWorktimeFinished( int result ) { StandardWorktimeDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * cmd = dia->buildCommand(); if ( cmd ) { //debugPlan<<"Modifying calendar(s)"; getPart() ->addCommand( cmd ); //also executes } } dia->deleteLater(); } void View::slotSelectionChanged( ScheduleManager *sm ) { debugPlan<expected()); if (!a) { debugPlan<expected(); return; } a->setChecked( true ); // this doesn't trigger QActionGroup slotViewSchedule( a ); } QList View::sortedActionList() { QMap lst; const QMap map = m_scheduleActions; QMap::const_iterator it; for (it = map.constBegin(); it != map.constEnd(); ++it) { lst.insert(it.key()->objectName(), it.key()); } return lst.values(); } void View::slotScheduleRemoved( const MainSchedule *sch ) { debugPlan<name(); QAction *a = 0; QAction *checked = m_scheduleActionGroup->checkedAction(); QMapIterator i( m_scheduleActions ); while (i.hasNext()) { i.next(); if ( i.value() == sch ) { a = i.key(); break; } } if ( a ) { unplugActionList( "view_schedule_list" ); delete a; plugActionList( "view_schedule_list", sortedActionList() ); if ( checked && checked != a ) { checked->setChecked( true ); } else if ( ! m_scheduleActions.isEmpty() ) { m_scheduleActions.firstKey()->setChecked( true ); } } slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotScheduleAdded( const MainSchedule *sch ) { if ( sch->type() != Schedule::Expected ) { return; // Only view expected } MainSchedule *s = const_cast( sch ); // debugPlan<name()<<" deleted="<isDeleted()<<"scheduled="<isScheduled(); QAction *checked = m_scheduleActionGroup->checkedAction(); if ( ! sch->isDeleted() && sch->isScheduled() ) { unplugActionList( "view_schedule_list" ); QAction *act = addScheduleAction( s ); plugActionList( "view_schedule_list", sortedActionList() ); if ( checked ) { checked->setChecked( true ); } else if ( act ) { act->setChecked( true ); } else if ( ! m_scheduleActions.isEmpty() ) { m_scheduleActions.firstKey()->setChecked( true ); } } slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotScheduleChanged( MainSchedule *sch ) { // debugPlan<name()<<" deleted="<isDeleted()<<"scheduled="<isScheduled(); if ( sch->isDeleted() || ! sch->isScheduled() ) { slotScheduleRemoved( sch ); return; } if (QAction *a = m_scheduleActions.key(sch)) { slotScheduleRemoved( sch ); // hmmm, how to avoid this? } slotScheduleAdded( sch ); } QAction *View::addScheduleAction( Schedule *sch ) { QAction *act = 0; if ( ! sch->isDeleted() && sch->isScheduled() ) { QString n = sch->name(); act = new KToggleAction( n, this); actionCollection()->addAction(n, act ); m_scheduleActions.insert( act, sch ); m_scheduleActionGroup->addAction( act ); //debugPlan<<"Add:"<manager(); } setLabel( 0 ); slotViewScheduleManager(sm); } void View::slotActionDestroyed( QObject *o ) { //debugPlan<name(); m_scheduleActions.remove( static_cast( o ) ); // slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotPlugScheduleActions() { //debugPlan< map = m_scheduleActions; QMap::const_iterator it; for (it = map.constBegin(); it != map.constEnd(); ++it) { m_scheduleActionGroup->removeAction(it.key()); delete it.key(); } m_scheduleActions.clear(); QAction *ca = 0; foreach( ScheduleManager *sm, getProject().allScheduleManagers() ) { Schedule *sch = sm->expected(); if ( sch == 0 ) { continue; } QAction *act = addScheduleAction( sch ); if ( act && id == sch->id() ) { ca = act; } } plugActionList( "view_schedule_list", sortedActionList() ); if ( ca == 0 && m_scheduleActionGroup->actions().count() > 0 ) { ca = m_scheduleActionGroup->actions().constFirst(); } if ( ca ) { ca->setChecked( true ); } slotViewSchedule( ca ); } void View::slotProjectCalculated( ScheduleManager *sm ) { // we only get here if current schedule was calculated if ( sm->isScheduled() ) { slotSelectionChanged( sm ); } } void View::slotCalculateSchedule( Project *project, ScheduleManager *sm ) { if ( project == 0 || sm == 0 ) { return; } if ( sm->parentManager() && ! sm->parentManager()->isScheduled() ) { // the parent must be scheduled return; } if ( sm == currentScheduleManager() ) { - connect( project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); + connect( project, &Project::projectCalculated, this, &View::slotProjectCalculated ); } CalculateScheduleCmd *cmd = new CalculateScheduleCmd( *project, sm, kundo2_i18nc("@info:status 1=schedule name", "Calculate %1", sm->name() ) ); getPart() ->addCommand( cmd ); slotUpdate(); } void View::slotRemoveCommands() { while ( ! m_undocommands.isEmpty() ) { m_undocommands.last()->undo(); delete m_undocommands.takeLast(); } } void View::slotBaselineSchedule( Project *project, ScheduleManager *sm ) { if ( project == 0 || sm == 0 ) { return; } if ( ! sm->isBaselined() && project->isBaselined() ) { KMessageBox::sorry( this, i18n( "Cannot baseline. The project is already baselined." ) ); return; } KUndo2Command *cmd; if ( sm->isBaselined() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "This schedule is baselined. Do you want to remove the baseline?" ) ); if ( res == KMessageBox::Cancel ) { return; } cmd = new ResetBaselineScheduleCmd( *sm, kundo2_i18n( "Reset baseline %1", sm->name() ) ); } else { cmd = new BaselineScheduleCmd( *sm, kundo2_i18n( "Baseline %1", sm->name() ) ); } getPart() ->addCommand( cmd ); } void View::slotAddScheduleManager( Project *project ) { if ( project == 0 ) { return; } ScheduleManager *sm = project->createScheduleManager(); AddScheduleManagerCmd *cmd = new AddScheduleManagerCmd( *project, sm, -1, kundo2_i18n( "Add schedule %1", sm->name() ) ); getPart() ->addCommand( cmd ); } void View::slotDeleteScheduleManager( Project *project, ScheduleManager *sm ) { if ( project == 0 || sm == 0) { return; } DeleteScheduleManagerCmd *cmd = new DeleteScheduleManagerCmd( *project, sm, kundo2_i18n( "Delete schedule %1", sm->name() ) ); getPart() ->addCommand( cmd ); } void View::slotMoveScheduleManager( ScheduleManager *sm, ScheduleManager *parent, int index ) { if ( sm == 0 ) { return; } MoveScheduleManagerCmd *cmd = new MoveScheduleManagerCmd( sm, parent, index, kundo2_i18n( "Move schedule %1", sm->name() ) ); getPart() ->addCommand( cmd ); } void View::slotAddSubTask() { Task * node = getProject().createTask( getPart() ->config().taskDefaults() ); SubTaskAddDialog *dia = new SubTaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this ); - connect(dia, SIGNAL(finished(int)), SLOT(slotAddSubTaskFinished(int))); + connect(dia, &QDialog::finished, this, &View::slotAddSubTaskFinished); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotAddSubTaskFinished( int result ) { SubTaskAddDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command *m = dia->buildCommand(); getPart() ->addCommand( m ); // add task to project } dia->deleteLater(); } void View::slotAddTask() { Task * node = getProject().createTask( getPart() ->config().taskDefaults() ); TaskAddDialog *dia = new TaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this ); - connect(dia, SIGNAL(finished(int)), SLOT(slotAddTaskFinished(int))); + connect(dia, &QDialog::finished, this, &View::slotAddTaskFinished); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotAddTaskFinished( int result ) { TaskAddDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command *m = dia->buildCommand(); getPart() ->addCommand( m ); // add task to project } dia->deleteLater(); } void View::slotAddMilestone() { Task * node = getProject().createTask(); node->estimate() ->clear(); TaskAddDialog *dia = new TaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this ); - connect(dia, SIGNAL(finished(int)), SLOT(slotAddMilestoneFinished(int))); + connect(dia, &QDialog::finished, this, &View::slotAddMilestoneFinished); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotAddMilestoneFinished( int result ) { TaskAddDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { MacroCommand *c = new MacroCommand( kundo2_i18n( "Add milestone" ) ); c->addCommand( dia->buildCommand() ); getPart() ->addCommand( c ); // add task to project } dia->deleteLater(); } void View::slotAddSubMilestone() { Task * node = getProject().createTask(); node->estimate() ->clear(); SubTaskAddDialog *dia = new SubTaskAddDialog( getProject(), *node, currentNode(), getProject().accounts(), this ); - connect(dia, SIGNAL(finished(int)), SLOT(slotAddSubMilestoneFinished(int))); + connect(dia, &QDialog::finished, this, &View::slotAddSubMilestoneFinished); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotAddSubMilestoneFinished( int result ) { SubTaskAddDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { MacroCommand *c = new MacroCommand( kundo2_i18n( "Add sub-milestone" ) ); c->addCommand( dia->buildCommand() ); getPart() ->addCommand( c ); // add task to project } dia->deleteLater(); } void View::slotDefineWBS() { //debugPlan; Project &p = getProject(); WBSDefinitionDialog *dia = new WBSDefinitionDialog( p, p.wbsDefinition(), this ); connect(dia, SIGNAL(finished(int)), SLOT(slotDefineWBSFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotDefineWBSFinished( int result ) { //debugPlan; WBSDefinitionDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted ) { KUndo2Command *cmd = dia->buildCommand(); if ( cmd ) { getPart()->addCommand( cmd ); } } dia->deleteLater(); } void View::slotConfigure() { //debugPlan; if( KConfigDialog::showDialog("Plan Settings") ) { return; } ConfigDialog *dialog = new ConfigDialog( this, "Plan Settings", KPlatoSettings::self() ); dialog->addPage(new ConfigProjectPanel(), i18n("Project Defaults"), koIconName("calligraplan") ); dialog->addPage(new ConfigWorkVacationPanel(), i18n("Work & Vacation"), koIconName("view-calendar") ); dialog->addPage(new TaskDefaultPanel(), i18n("Task Defaults"), koIconName("view-task") ); dialog->addPage(new ColorsConfigPanel(), i18n("Task Colors"), koIconName("fill-color") ); dialog->addPage(new WorkPackageConfigPanel(), i18n("Work Package"), koIconName("calligraplanwork") ); dialog->show(); } void View::slotIntroduction() { m_tab->setCurrentIndex(0); } Calendar *View::currentCalendar() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return 0; } return v->currentCalendar(); } Node *View::currentNode() const { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return 0; } Node * task = v->currentNode(); if ( 0 != task ) { return task; } return &( getProject() ); } Task *View::currentTask() const { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return 0; } Node * task = v->currentNode(); if ( task ) { return dynamic_cast( task ); } return 0; } Resource *View::currentResource() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return 0; } return v->currentResource(); } ResourceGroup *View::currentResourceGroup() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return 0; } return v->currentResourceGroup(); } void View::slotOpenNode() { //debugPlan; Node * node = currentNode(); slotOpenNode( node ); } void View::slotOpenNode( Node *node ) { //debugPlan; if ( !node ) return ; switch ( node->type() ) { case Node::Type_Project: { Project * project = static_cast( node ); MainProjectDialog *dia = new MainProjectDialog( *project, this ); - connect(dia, SIGNAL(dialogFinished(int)), SLOT(slotProjectEditFinished(int))); - connect(dia, SIGNAL(sigLoadSharedResources(QString,QUrl,bool)), this, SLOT(slotInsertResourcesFile(QString,QUrl))); + connect(dia, &MainProjectDialog::dialogFinished, this, &View::slotProjectEditFinished); + connect(dia, &MainProjectDialog::sigLoadSharedResources, this, &View::slotInsertResourcesFile); connect(dia, &MainProjectDialog::loadResourceAssignments, getPart(), &MainDocument::loadResourceAssignments); connect(dia, &MainProjectDialog::clearResourceAssignments, getPart(), &MainDocument::clearResourceAssignments); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Subproject: //TODO break; case Node::Type_Task: { Task *task = static_cast( node ); TaskDialog *dia = new TaskDialog( getProject(), *task, getProject().accounts(), this ); - connect(dia, SIGNAL(finished(int)), SLOT(slotTaskEditFinished(int))); + connect(dia, &QDialog::finished, this, &View::slotTaskEditFinished); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Milestone: { // Use the normal task dialog for now. // Maybe milestone should have it's own dialog, but we need to be able to // enter a duration in case we accidentally set a tasks duration to zero // and hence, create a milestone Task *task = static_cast( node ); TaskDialog *dia = new TaskDialog( getProject(), *task, getProject().accounts(), this ); - connect(dia, SIGNAL(finished(int)), SLOT(slotTaskEditFinished(int))); + connect(dia, &QDialog::finished, this, &View::slotTaskEditFinished); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Summarytask: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); SummaryTaskDialog *dia = new SummaryTaskDialog( *task, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotSummaryTaskEditFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } default: break; // avoid warnings } } void View::slotProjectEditFinished( int result ) { MainProjectDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * cmd = dia->buildCommand(); if ( cmd ) { getPart() ->addCommand( cmd ); } } dia->deleteLater(); } void View::slotTaskEditFinished( int result ) { TaskDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * cmd = dia->buildCommand(); if ( cmd ) { getPart() ->addCommand( cmd ); } } dia->deleteLater(); } void View::slotSummaryTaskEditFinished( int result ) { SummaryTaskDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * cmd = dia->buildCommand(); if ( cmd ) { getPart() ->addCommand( cmd ); } } dia->deleteLater(); } ScheduleManager *View::currentScheduleManager() const { Schedule *s = m_scheduleActions.value( m_scheduleActionGroup->checkedAction() ); return s == 0 ? 0 : s->manager(); } long View::activeScheduleId() const { Schedule *s = m_scheduleActions.value( m_scheduleActionGroup->checkedAction() ); return s == 0 ? -1 : s->id(); } void View::setActiveSchedule( long id ) { if ( id != -1 ) { QMap::const_iterator it = m_scheduleActions.constBegin(); for (; it != m_scheduleActions.constEnd(); ++it ) { if ( it.value()->id() == id ) { it.key()->setChecked( true ); slotViewSchedule( it.key() ); // signal not emitted from group, so trigger it here break; } } } } void View::slotTaskProgress() { //debugPlan; Node * node = currentNode(); if ( !node ) return ; switch ( node->type() ) { case Node::Type_Project: { break; } case Node::Type_Subproject: //TODO break; case Node::Type_Task: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); TaskProgressDialog *dia = new TaskProgressDialog( *task, currentScheduleManager(), getProject().standardWorktime(), this ); connect(dia, SIGNAL(finished(int)), SLOT(slotTaskProgressFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Milestone: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); MilestoneProgressDialog *dia = new MilestoneProgressDialog( *task, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotMilestoneProgressFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } case Node::Type_Summarytask: { // TODO break; } default: break; // avoid warnings } } void View::slotTaskProgressFinished( int result ) { TaskProgressDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotMilestoneProgressFinished( int result ) { MilestoneProgressDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotTaskDescription() { //debugPlan; Node * node = currentNode(); if ( !node ) return ; switch ( node->type() ) { case Node::Type_Project: { break; } case Node::Type_Subproject: //TODO break; case Node::Type_Task: case Node::Type_Milestone: case Node::Type_Summarytask: { Task *task = dynamic_cast( node ); Q_ASSERT( task ); TaskDescriptionDialog *dia = new TaskDescriptionDialog( *task, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotTaskDescriptionFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); break; } default: break; // avoid warnings } } void View::slotTaskDescriptionFinished( int result ) { TaskDescriptionDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotDeleteTask( QList lst ) { //debugPlan; foreach ( Node *n, lst ) { if ( n->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "A task that has been scheduled will be deleted. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } break; } } if ( lst.count() == 1 ) { getPart()->addCommand( new NodeDeleteCmd( lst.takeFirst(), kundo2_i18n( "Delete task" ) ) ); return; } int num = 0; MacroCommand *cmd = new MacroCommand( kundo2_i18np( "Delete task", "Delete tasks", lst.count() ) ); while ( !lst.isEmpty() ) { Node *node = lst.takeFirst(); if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); continue; } bool del = true; foreach ( Node *n, lst ) { if ( node->isChildOf( n ) ) { del = false; // node is going to be deleted when we delete n break; } } if ( del ) { //debugPlan<name(); cmd->addCommand( new NodeDeleteCmd( node, kundo2_i18n( "Delete task" ) ) ); num++; } } if ( num > 0 ) { getPart()->addCommand( cmd ); } else { delete cmd; } } void View::slotDeleteTask( Node *node ) { //debugPlan; if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); return ; } if ( node->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "This task has been scheduled. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } } NodeDeleteCmd *cmd = new NodeDeleteCmd( node, kundo2_i18n( "Delete task" ) ); getPart() ->addCommand( cmd ); } void View::slotDeleteTask() { //debugPlan; return slotDeleteTask( currentNode() ); } void View::slotIndentTask() { //debugPlan; Node * node = currentNode(); if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); return ; } if ( getProject().canIndentTask( node ) ) { NodeIndentCmd * cmd = new NodeIndentCmd( *node, kundo2_i18n( "Indent task" ) ); getPart() ->addCommand( cmd ); } } void View::slotUnindentTask() { //debugPlan; Node * node = currentNode(); if ( node == 0 || node->parentNode() == 0 ) { debugPlan << ( node ?"Task is main project" :"No current task" ); return ; } if ( getProject().canUnindentTask( node ) ) { NodeUnindentCmd * cmd = new NodeUnindentCmd( *node, kundo2_i18n( "Unindent task" ) ); getPart() ->addCommand( cmd ); } } void View::slotMoveTaskUp() { //debugPlan; Node * task = currentNode(); if ( 0 == task ) { // is always != 0. At least we would get the Project, but you never know who might change that // so better be careful errorPlan << "No current task" << endl; return ; } if ( Node::Type_Project == task->type() ) { debugPlan <<"The root node cannot be moved up"; return ; } if ( getProject().canMoveTaskUp( task ) ) { NodeMoveUpCmd * cmd = new NodeMoveUpCmd( *task, kundo2_i18n( "Move task up" ) ); getPart() ->addCommand( cmd ); } } void View::slotMoveTaskDown() { //debugPlan; Node * task = currentNode(); if ( 0 == task ) { // is always != 0. At least we would get the Project, but you never know who might change that // so better be careful return ; } if ( Node::Type_Project == task->type() ) { debugPlan <<"The root node cannot be moved down"; return ; } if ( getProject().canMoveTaskDown( task ) ) { NodeMoveDownCmd * cmd = new NodeMoveDownCmd( *task, kundo2_i18n( "Move task down" ) ); getPart() ->addCommand( cmd ); } } void View::slotAddRelation( Node *par, Node *child ) { //debugPlan; Relation * rel = new Relation( par, child ); AddRelationDialog *dia = new AddRelationDialog( getProject(), rel, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotAddRelationFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotAddRelationFinished( int result ) { AddRelationDialog *dia = qobject_cast(sender() ); if ( dia == 0 ) { return; } if ( result == QDialog::Accepted) { KUndo2Command * m = dia->buildCommand(); if ( m ) { getPart() ->addCommand( m ); } } dia->deleteLater(); } void View::slotAddRelation( Node *par, Node *child, int linkType ) { //debugPlan; if ( linkType == Relation::FinishStart || linkType == Relation::StartStart || linkType == Relation::FinishFinish ) { Relation * rel = new Relation( par, child, static_cast( linkType ) ); getPart() ->addCommand( new AddRelationCmd( getProject(), rel, kundo2_i18n( "Add task dependency" ) ) ); } else { slotAddRelation( par, child ); } } void View::slotModifyRelation( Relation *rel ) { //debugPlan; ModifyRelationDialog *dia = new ModifyRelationDialog( getProject(), rel, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotModifyRelationFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotModifyRelationFinished( int result ) { ModifyRelationDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return ; } if ( result == QDialog::Accepted) { KUndo2Command *cmd = dia->buildCommand(); if ( cmd ) { getPart() ->addCommand( cmd ); } } dia->deleteLater(); } void View::slotModifyRelation( Relation *rel, int linkType ) { //debugPlan; if ( linkType == Relation::FinishStart || linkType == Relation::StartStart || linkType == Relation::FinishFinish ) { getPart() ->addCommand( new ModifyRelationTypeCmd( rel, static_cast( linkType ) ) ); } else { slotModifyRelation( rel ); } } void View::slotModifyRelation() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return; } Relation *rel = v->currentRelation(); if ( rel ) { slotModifyRelation( rel ); } } void View::slotDeleteRelation() { ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v == 0 ) { return; } Relation *rel = v->currentRelation(); if ( rel ) { getPart()->addCommand( new DeleteRelationCmd( getProject(), rel, kundo2_i18n( "Delete task dependency" ) ) ); } } void View::slotEditResource() { //debugPlan; slotEditResource( currentResource() ); } void View::slotEditResource( Resource *resource ) { if ( resource == 0 ) { return ; } ResourceDialog *dia = new ResourceDialog( getProject(), resource, this ); connect(dia, SIGNAL(finished(int)), SLOT(slotEditResourceFinished(int))); dia->show(); dia->raise(); dia->activateWindow(); } void View::slotEditResourceFinished( int result ) { //debugPlan; ResourceDialog *dia = qobject_cast( sender() ); if ( dia == 0 ) { return ; } if ( result == QDialog::Accepted) { KUndo2Command * cmd = dia->buildCommand(); if ( cmd ) getPart() ->addCommand( cmd ); } dia->deleteLater(); } void View::slotDeleteResource( Resource *resource ) { getPart()->addCommand( new RemoveResourceCmd( resource->parentGroup(), resource, kundo2_i18n( "Delete resource" ) ) ); } void View::slotDeleteResourceGroup( ResourceGroup *group ) { getPart()->addCommand( new RemoveResourceGroupCmd( group->project(), group, kundo2_i18n( "Delete resourcegroup" ) ) ); } void View::slotDeleteResourceObjects( QObjectList lst ) { //debugPlan; foreach ( QObject *o, lst ) { Resource *r = qobject_cast( o ); if ( r && r->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "A resource that has been scheduled will be deleted. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } break; } ResourceGroup *g = qobject_cast( o ); if ( g && g->isScheduled() ) { KMessageBox::ButtonCode res = KMessageBox::warningContinueCancel( this, i18n( "A resource that has been scheduled will be deleted. This will invalidate the schedule." ) ); if ( res == KMessageBox::Cancel ) { return; } break; } } if ( lst.count() == 1 ) { Resource *r = qobject_cast( lst.first() ); if ( r ) { slotDeleteResource( r ); } else { ResourceGroup *g = qobject_cast( lst.first() ); if ( g ) { slotDeleteResourceGroup( g ); } } return; } // int num = 0; MacroCommand *cmd = 0, *rc = 0, *gc = 0; foreach ( QObject *o, lst ) { Resource *r = qobject_cast( o ); if ( r ) { if ( rc == 0 ) rc = new MacroCommand( KUndo2MagicString() ); rc->addCommand( new RemoveResourceCmd( r->parentGroup(), r ) ); continue; } ResourceGroup *g = qobject_cast( o ); if ( g ) { if ( gc == 0 ) gc = new MacroCommand( KUndo2MagicString() ); gc->addCommand( new RemoveResourceGroupCmd( g->project(), g ) ); } } if ( rc || gc ) { KUndo2MagicString s; if ( rc && gc ) { s = kundo2_i18n( "Delete resourcegroups and resources" ); } else if ( rc ) { s = kundo2_i18np( "Delete resource", "Delete resources", lst.count() ); } else { s = kundo2_i18np( "Delete resourcegroup", "Delete resourcegroups", lst.count() ); } cmd = new MacroCommand( s ); } if ( rc ) cmd->addCommand( rc ); if ( gc ) cmd->addCommand( gc ); if ( cmd ) getPart()->addCommand( cmd ); } void View::updateReadWrite( bool readwrite ) { m_readWrite = readwrite; m_viewlist->setReadWrite( readwrite ); } MainDocument *View::getPart() const { return ( MainDocument * ) koDocument(); } KoPart *View::getKoPart() const { return m_partpart; } void View::slotConnectNode() { //debugPlan; /* NodeItem *curr = ganttview->currentItem(); if (curr) { debugPlan<<"node="<getNode().name(); }*/ } QMenu * View::popupMenu( const QString& name ) { //debugPlan; if ( factory() ) { return ( ( QMenu* ) factory() ->container( name, this ) ); } debugPlan<<"No factory"; return 0L; } void View::slotUpdate() { //debugPlan<<"calculate="<currentWidget() ); } void View::slotGuiActivated( ViewBase *view, bool activate ) { //FIXME: Avoid unplug if possible, it flashes the gui // always unplug, in case they already are plugged foreach( const QString &name, view->actionListNames() ) { unplugActionList( name ); } if ( activate ) { foreach( const QString &name, view->actionListNames() ) { plugActionList( name, view->actionList( name ) ); } foreach ( DockWidget *ds, view->dockers() ) { m_dockers.append( ds ); ds->activate( mainWindow() ); } if (!m_dockers.isEmpty()) {debugPlan<<"Added dockers:"<deactivate( mainWindow() ); } } } void View::guiActivateEvent( bool activated ) { if ( activated ) { // plug my own actionlists, they may be gone slotPlugScheduleActions(); } // propagate to sub-view ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v ) { v->setGuiActive( activated ); } } void View::slotViewListItemRemoved( ViewListItem *item ) { getPart()->removeViewListItem( this, item ); } void View::removeViewListItem( const ViewListItem *item ) { if ( item == 0 ) { return; } ViewListItem *itm = m_viewlist->findItem( item->tag() ); if ( itm == 0 ) { return; } m_viewlist->removeViewListItem( itm ); return; } void View::slotViewListItemInserted( ViewListItem *item, ViewListItem *parent, int index ) { getPart()->insertViewListItem( this, item, parent, index ); } void View::addViewListItem( const ViewListItem *item, const ViewListItem *parent, int index ) { if ( item == 0 ) { return; } if ( parent == 0 ) { if ( item->type() != ViewListItem::ItemType_Category ) { return; } m_viewlist->blockSignals( true ); ViewListItem *cat = m_viewlist->addCategory( item->tag(), item->text( 0 ) ); cat->setToolTip( 0, item->toolTip( 0 ) ); m_viewlist->blockSignals( false ); return; } ViewListItem *cat = m_viewlist->findCategory( parent->tag() ); if ( cat == 0 ) { return; } m_viewlist->blockSignals( true ); createView( cat, item->viewType(), item->tag(), item->text( 0 ), item->toolTip( 0 ), index ); m_viewlist->blockSignals( false ); } void View::createReportView(const QDomDocument &doc) { #ifdef PLAN_USE_KREPORT QPointer vd = new ViewListReportsDialog( this, *m_viewlist, doc, this ); vd->exec(); // FIXME make non-crash delete vd; #else Q_UNUSED(doc) #endif } void View::slotOpenReportFile() { #ifdef PLAN_USE_KREPORT QFileDialog *dlg = new QFileDialog(this); connect(dlg, SIGNAL(finished(int)), SLOT(slotOpenReportFileFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); #endif } void View::slotOpenReportFileFinished( int result ) { #ifdef PLAN_USE_KREPORT QFileDialog *fdlg = qobject_cast( sender() ); if ( fdlg == 0 || result != QDialog::Accepted ) { return; } QString fn = fdlg->selectedFiles().value(0); if ( fn.isEmpty() ) { return; } QFile file( fn ); if ( ! file.open( QIODevice::ReadOnly | QIODevice::Text ) ) { KMessageBox::sorry( this, xi18nc( "@info", "Cannot open file:
%1", fn ) ); return; } QDomDocument doc; doc.setContent( &file ); createReportView(doc); #else Q_UNUSED(result) #endif } void View::slotReportDesignFinished( int /*result */) { #ifdef PLAN_USE_KREPORT if ( sender() ) { sender()->deleteLater(); } #endif } void View::slotCreateView() { ViewListDialog *dlg = new ViewListDialog( this, *m_viewlist, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotCreateViewFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void View::slotCreateViewFinished( int ) { if ( sender() ) { sender()->deleteLater(); } } void View::slotViewActivated( ViewListItem *item, ViewListItem *prev ) { QApplication::setOverrideCursor( Qt::WaitCursor ); if ( prev && prev->type() == ViewListItem::ItemType_Category && m_viewlist->previousViewItem() ) { // A view is shown anyway... ViewBase *v = qobject_cast( m_viewlist->previousViewItem()->view() ); if ( v ) { v->setGuiActive( false ); } } else if ( prev && prev->type() == ViewListItem::ItemType_SubView ) { ViewBase *v = qobject_cast( prev->view() ); if ( v ) { v->setGuiActive( false ); } } if ( item && item->type() == ViewListItem::ItemType_SubView ) { //debugPlan<<"Activate:"<setCurrentWidget( item->view() ); // Add sub-view specific gui ViewBase *v = dynamic_cast( m_tab->currentWidget() ); if ( v ) { v->setGuiActive( true ); } } QApplication::restoreOverrideCursor(); } QWidget *View::canvas() const { return m_tab->currentWidget();//KoView::canvas(); } KoPageLayout View::pageLayout() const { return currentView()->pageLayout(); } void View::setPageLayout(const KoPageLayout &pageLayout) { currentView()->setPageLayout(pageLayout); } QPrintDialog *View::createPrintDialog( KoPrintJob *printJob, QWidget *parent ) { debugPlan<( printJob ); if ( ! job ) { return 0; } QPrintDialog *dia = KoView::createPrintDialog( job, parent ); PrintingDialog *j = dynamic_cast( job ); if ( j ) { new PrintingControlPrivate( j, dia ); } return dia; } void View::slotCurrentChanged( int view ) { m_visitedViews << view; ViewListItem *item = m_viewlist->findItem( qobject_cast( m_tab->currentWidget() ) ); m_viewlist->setCurrentItem( item ); } void View::slotSelectDefaultView() { m_tab->setCurrentIndex(qMin(m_defaultView, m_tab->count()-1)); } void View::updateView( QWidget * ) { QApplication::setOverrideCursor( Qt::WaitCursor ); //setScheduleActionsEnabled(); QWidget *widget2; widget2 = m_viewlist->findView( "ResourceAssignmentView" ); if ( widget2 && m_updateResourceAssignmentView ) static_cast( widget2 ) ->draw( getProject() ); m_updateResourceAssignmentView = false; QApplication::restoreOverrideCursor(); } void View::slotRenameNode( Node *node, const QString& name ) { //debugPlan<type() ) { case Node::Type_Task: s = kundo2_i18n( "Modify task name" ); break; case Node::Type_Milestone: s = kundo2_i18n( "Modify milestone name" ); break; case Node::Type_Summarytask: s = kundo2_i18n( "Modify summarytask name" ); break; case Node::Type_Project: s = kundo2_i18n( "Modify project name" ); break; } NodeModifyNameCmd * cmd = new NodeModifyNameCmd( *node, name, s ); getPart() ->addCommand( cmd ); } } void View::slotPopupMenu( const QString& menuname, const QPoint & pos ) { QMenu * menu = this->popupMenu( menuname ); if ( menu ) { //debugPlan<actions().count(); ViewBase *v = qobject_cast( m_tab->currentWidget() ); //debugPlan< lst; if ( v ) { lst = v->contextActionList(); debugPlan<addSeparator(); foreach ( QAction *a, lst ) { menu->addAction( a ); } } } menu->exec( pos ); foreach ( QAction *a, lst ) { menu->removeAction( a ); } } } void View::slotPopupMenu( const QString& menuname, const QPoint &pos, ViewListItem *item ) { //debugPlan<context(); if ( ctx == 0 || ! ctx->isLoaded() ) { return false; } KoXmlElement n = ctx->context(); QString cv = n.attribute( "current-view" ); if ( ! cv.isEmpty() ) { m_viewlist->setSelected( m_viewlist->findItem( cv ) ); } else debugPlan<<"No current view"; long id = n.attribute( "current-schedule", "-1" ).toLong(); if ( id != -1 ) { setActiveSchedule( id ); } else debugPlan<<"No current schedule"; return true; } void View::saveContext( QDomElement &me ) const { //debugPlan; long id = activeScheduleId(); if ( id != -1 ) { me.setAttribute( "current-schedule", QString::number((qlonglong)id) ); } ViewListItem *item = m_viewlist->findItem( qobject_cast( m_tab->currentWidget() ) ); if ( item ) { me.setAttribute("current-view", item->tag() ); } m_viewlist->save( me ); } bool View::loadWorkPackage( Project &project, const QUrl &url ) { return getPart()->loadWorkPackage( project, url ); } void View::setLabel( ScheduleManager *sm ) { //debugPlan; Schedule *s = sm == 0 ? 0 : sm->expected(); if ( s && !s->isDeleted() && s->isScheduled() ) { m_estlabel->setText( sm->name() ); return; } m_estlabel->setText( xi18nc( "@info:status", "Not scheduled" ) ); } void View::slotWorkPackageLoaded() { debugPlan<workPackages(); } void View::slotMailWorkpackage( Node *node, Resource *resource ) { debugPlan; QTemporaryFile tmpfile(QDir::tempPath() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String( ".planwork" )); tmpfile.setAutoRemove( false ); if ( ! tmpfile.open() ) { debugPlan<<"Failed to open file"; KMessageBox::error(0, i18n("Failed to open temporary file" ) ); return; } QUrl url = QUrl::fromLocalFile( tmpfile.fileName() ); if ( ! getPart()->saveWorkPackageUrl( url, node, activeScheduleId(), resource ) ) { debugPlan<<"Failed to save to file"; KMessageBox::error(0, xi18nc( "@info", "Failed to save to temporary file:
%1", url.url() ) ); return; } QStringList attachURLs; attachURLs << url.url(); QString to = resource == 0 ? node->leader() : ( resource->name() + " <" + resource->email() + '>' ); QString cc; QString bcc; QString subject = i18n( "Work Package: %1", node->name() ); QString body = i18nc( "1=project name, 2=task name", "%1\n%2", getProject().name(), node->name() ); QString messageFile; KToolInvocation::invokeMailer( to, cc, bcc, subject, body, messageFile, attachURLs ); } void View::slotMailWorkpackages( const QList &nodes, Resource *resource ) { debugPlan; if ( resource == 0 ) { warnPlan<<"No resource, we don't handle node->leader() yet"; return; } QString to = resource->name() + " <" + resource->email() + '>'; QString subject = i18n( "Work Package for project: %1", getProject().name() ); QString body; QStringList attachURLs; foreach ( Node *n, nodes ) { QTemporaryFile tmpfile(QDir::tempPath() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String( ".planwork" )); tmpfile.setAutoRemove( false ); if ( ! tmpfile.open() ) { debugPlan<<"Failed to open file"; KMessageBox::error(0, i18n("Failed to open temporary file" ) ); return; } QUrl url = QUrl::fromLocalFile( tmpfile.fileName() ); if ( ! getPart()->saveWorkPackageUrl( url, n, activeScheduleId(), resource ) ) { debugPlan<<"Failed to save to file"; KMessageBox::error(0, xi18nc( "@info", "Failed to save to temporary file:
%1", url.url() ) ); return; } attachURLs << url.url(); body += n->name() + '\n'; } QString cc; QString bcc; QString messageFile; KToolInvocation::invokeMailer( to, cc, bcc, subject, body, messageFile, attachURLs ); } void View::slotCurrencyConfig() { LocaleConfigMoneyDialog *dlg = new LocaleConfigMoneyDialog( getProject().locale(), this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotCurrencyConfigFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void View::slotCurrencyConfigFinished( int result ) { LocaleConfigMoneyDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == QDialog::Accepted ) { KUndo2Command *c = dlg->buildCommand( getProject() ); if ( c ) { getPart()->addCommand( c ); } } dlg->deleteLater(); } void View::saveTaskModule( const QUrl &url, Project *project ) { // NOTE: workaround: KoResourcePaths::saveLocation( "calligraplan_taskmodules" ); does not work const QString dir = KoResourcePaths::saveLocation( "appdata", "taskmodules/" ); debugPlan<<"dir="<setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable doc->insertProject( *project, 0, 0 ); // FIXME: destroys project, find better way doc->getProject().setName( project->name() ); doc->getProject().setLeader( project->leader() ); doc->getProject().setDescription( project->description() ); doc->saveNativeFormat( dir + url.fileName() ); part->deleteLater(); // also deletes document debugPlan<" "" "" "%1" "" "" "predefined" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "") .arg( i18n( "Report" ), i18nc( "Project manager", "Manager:" ), i18n( "Project:" ), i18n( "Task Status Report" ), i18nc( "As in: Page 1 of 2", "of" ), i18n( "Page" ), i18nc( "Task name", "Name" ), i18nc( "Task completion", "Completion (%)" ) ); #endif return s; } } //KPlato namespace diff --git a/src/kptviewlist.cpp b/src/kptviewlist.cpp index 0e6db7b2..2220b931 100644 --- a/src/kptviewlist.cpp +++ b/src/kptviewlist.cpp @@ -1,870 +1,870 @@ /* This file is part of the KDE project Copyright (C) 2007 -2010 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 "kptviewlist.h" #include #include #include #include #include #include #include #include #include #include #include #include "KoDocument.h" #include "kptviewbase.h" #include "kptmaindocument.h" #include "kptviewlistdialog.h" #include "kptviewlistdocker.h" #include "kptschedulemodel.h" #include "Help.h" #include #include namespace KPlato { // class ViewCategoryDelegate : public QItemDelegate { public: ViewCategoryDelegate( QObject *parent, QTreeView *view ) : QItemDelegate( parent ), m_view( view ) {} QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; private: QTreeView *m_view; }; QSize ViewCategoryDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const { const QAbstractItemModel * model = index.model(); Q_ASSERT( model ); if ( model->parent( index ).isValid() ) { return QItemDelegate::sizeHint( option, index ); } return QItemDelegate::sizeHint( option, index ).expandedTo( QSize( 0, 16 ) ); } void ViewCategoryDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { const QAbstractItemModel * model = index.model(); Q_ASSERT( model ); if ( !model->parent( index ).isValid() ) { // this is a top-level item. QStyleOptionButton buttonOption; buttonOption.state = option.state; buttonOption.rect = option.rect; buttonOption.palette = option.palette; buttonOption.features = QStyleOptionButton::None; m_view->style() ->drawControl( QStyle::CE_PushButton, &buttonOption, painter, m_view ); QStyleOption branchOption; static const int i = 9; // ### hardcoded in qcommonstyle.cpp QRect r = option.rect; branchOption.rect = QRect( r.left() + i / 2, r.top() + ( r.height() - i ) / 2, i, i ); branchOption.palette = option.palette; branchOption.state = QStyle::State_Children; if ( m_view->isExpanded( index ) ) branchOption.state |= QStyle::State_Open; m_view->style() ->drawPrimitive( QStyle::PE_IndicatorBranch, &branchOption, painter, m_view ); // draw text QRect textrect = QRect( r.left() + i * 2, r.top(), r.width() - ( ( 5 * i ) / 2 ), r.height() ); QString text = elidedText( option.fontMetrics, textrect.width(), Qt::ElideMiddle, model->data( index, Qt::DisplayRole ).toString() ); m_view->style() ->drawItemText( painter, textrect, Qt::AlignLeft|Qt::AlignVCenter, option.palette, m_view->isEnabled(), text ); } else { QItemDelegate::paint( painter, option, index ); } } ViewListItem::ViewListItem( const QString &tag, const QStringList &strings, int type ) : QTreeWidgetItem( strings, type ), m_tag( tag ) { } ViewListItem::ViewListItem( QTreeWidget *parent, const QString &tag, const QStringList &strings, int type ) : QTreeWidgetItem( parent, strings, type ), m_tag( tag ) { } ViewListItem::ViewListItem( QTreeWidgetItem *parent, const QString &tag, const QStringList &strings, int type ) : QTreeWidgetItem( parent, strings, type ), m_tag( tag ) { } void ViewListItem::setReadWrite( bool rw ) { if ( type() == ItemType_SubView ) { static_cast( view() )->updateReadWrite( rw ); } } void ViewListItem::setView( ViewBase *view ) { setData( 0, ViewListItem::DataRole_View, qVariantFromValue(static_cast( view ) ) ); } ViewBase *ViewListItem::view() const { if ( data(0, ViewListItem::DataRole_View ).isValid() ) { return static_cast( data(0, ViewListItem::DataRole_View ).value() ); } return 0; } void ViewListItem::setDocument( KoDocument *doc ) { setData( 0, ViewListItem::DataRole_Document, qVariantFromValue(static_cast( doc ) ) ); } KoDocument *ViewListItem::document() const { if ( data(0, ViewListItem::DataRole_Document ).isValid() ) { return static_cast( data(0, ViewListItem::DataRole_Document ).value() ); } return 0; } QString ViewListItem::viewType() const { if ( type() != ItemType_SubView ) { return QString(); } QString name = view()->metaObject()->className(); if ( name.contains( ':' ) ) { name = name.remove( 0, name.lastIndexOf( ':' ) + 1 ); } return name; } void ViewListItem::save( QDomElement &element ) const { element.setAttribute( "itemtype", QString::number(type()) ); element.setAttribute( "tag", tag() ); if ( type() == ItemType_SubView ) { element.setAttribute( "viewtype", viewType() ); element.setAttribute( "name", m_viewinfo.name == text( 0 ) ? "" : text( 0 ) ); element.setAttribute( "tooltip", m_viewinfo.tip == toolTip( 0 ) ? TIP_USE_DEFAULT_TEXT : toolTip( 0 ) ); } else if ( type() == ItemType_Category ) { debugPlan<hide(); setRootIsDecorated( false ); setItemDelegate( new ViewCategoryDelegate( this, this ) ); setItemsExpandable( true ); setSelectionMode( QAbstractItemView::SingleSelection ); setDragDropMode( QAbstractItemView::InternalMove ); //setContextMenuPolicy( Qt::ActionsContextMenu ); - connect( this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), SLOT(handleMousePress(QTreeWidgetItem*)) ); + connect( this, &QTreeWidget::itemPressed, this, &ViewListTreeWidget::handleMousePress ); } void ViewListTreeWidget::drawRow( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { QTreeWidget::drawRow( painter, option, index ); } void ViewListTreeWidget::handleMousePress( QTreeWidgetItem *item ) { //debugPlan; if ( item == 0 ) return ; if ( item->parent() == 0 ) { setItemExpanded( item, !isItemExpanded( item ) ); return ; } } void ViewListTreeWidget::mousePressEvent ( QMouseEvent *event ) { if ( event->button() == Qt::RightButton ) { QTreeWidgetItem *item = itemAt( event->pos() ); if ( item && item->type() == ViewListItem::ItemType_Category ) { setCurrentItem( item ); emit customContextMenuRequested( event->pos() ); event->accept(); return; } } QTreeWidget::mousePressEvent( event ); } void ViewListTreeWidget::save( QDomElement &element ) const { int cnt = topLevelItemCount(); if ( cnt == 0 ) { return; } QDomElement cs = element.ownerDocument().createElement( "categories" ); element.appendChild( cs ); for ( int i = 0; i < cnt; ++i ) { ViewListItem *itm = static_cast( topLevelItem( i ) ); if ( itm->type() != ViewListItem::ItemType_Category ) { continue; } QDomElement c = cs.ownerDocument().createElement( "category" ); cs.appendChild( c ); emit const_cast( this )->updateViewInfo( itm ); itm->save( c ); for ( int j = 0; j < itm->childCount(); ++j ) { ViewListItem *vi = static_cast( itm->child( j ) ); if ( vi->type() != ViewListItem::ItemType_SubView ) { continue; } QDomElement el = c.ownerDocument().createElement( "view" ); c.appendChild( el ); emit const_cast( this )->updateViewInfo( vi ); vi->save( el ); QDomElement elm = el.ownerDocument().createElement( "settings" ); el.appendChild( elm ); static_cast( vi->view() )->saveContext( elm ); } } } // void ViewListTreeWidget::startDrag( Qt::DropActions supportedActions ) { QModelIndexList indexes = selectedIndexes(); if ( indexes.count() == 1 ) { ViewListItem *item = static_cast( itemFromIndex( indexes.at( 0 ) ) ); Q_ASSERT( item ); QTreeWidgetItem *root = invisibleRootItem(); int count = root->childCount(); if ( item && item->type() == ViewListItem::ItemType_Category ) { root->setFlags( root->flags() | Qt::ItemIsDropEnabled ); for ( int i = 0; i < count; ++i ) { QTreeWidgetItem * ch = root->child( i ); ch->setFlags( ch->flags() & ~Qt::ItemIsDropEnabled ); } } else if ( item ) { root->setFlags( root->flags() & ~Qt::ItemIsDropEnabled ); for ( int i = 0; i < count; ++i ) { QTreeWidgetItem * ch = root->child( i ); ch->setFlags( ch->flags() | Qt::ItemIsDropEnabled ); } } } QTreeWidget::startDrag( supportedActions ); } void ViewListTreeWidget::dropEvent( QDropEvent *event ) { QTreeWidget::dropEvent( event ); if ( event->isAccepted() ) { emit modified(); } } ViewListItem *ViewListTreeWidget::findCategory( const QString &cat ) { QTreeWidgetItem * item; int cnt = topLevelItemCount(); for ( int i = 0; i < cnt; ++i ) { item = topLevelItem( i ); if ( static_cast(item)->tag() == cat ) return static_cast(item); } return 0; } ViewListItem *ViewListTreeWidget::category( const KoView *view ) const { QTreeWidgetItem * item; int cnt = topLevelItemCount(); for ( int i = 0; i < cnt; ++i ) { item = topLevelItem( i ); for ( int c = 0; c < item->childCount(); ++c ) { if ( view == static_cast( item->child( c ) )->view() ) { return static_cast( item ); } } } return 0; } //----------------------- ViewListWidget::ViewListWidget( MainDocument *part, QWidget *parent )//QString name, KXmlGuiWindow *parent ) : QWidget( parent ), m_part( part ), m_prev( 0 ), m_temp( 0 ) { setObjectName("ViewListWidget"); Help::add(this, xi18nc("@info:whatsthis", "View Selector" "This is the list of views and editors." "You can configure the list by using the context menu:" "" "Rename categories or views" "Configure. Move, remove, rename or edit tool tip for categories or views" "Insert categories and views" "" "More..." "", Help::page("Manual/View_Selector"))); m_viewlist = new ViewListTreeWidget( this ); m_viewlist->setEditTriggers( QAbstractItemView::NoEditTriggers ); - connect(m_viewlist, SIGNAL(modified()), this, SIGNAL(modified())); + connect(m_viewlist, &ViewListTreeWidget::modified, this, &ViewListWidget::modified); m_currentSchedule = new KComboBox( this ); m_model.setFlat( true ); m_sfModel.setFilterKeyColumn ( ScheduleModel::ScheduleScheduled ); m_sfModel.setFilterRole( Qt::EditRole ); m_sfModel.setFilterFixedString( "true" ); m_sfModel.setDynamicSortFilter ( true ); m_sfModel.setSourceModel( &m_model ); m_currentSchedule->setModel( &m_sfModel ); Help::add(m_currentSchedule, xi18nc("@info:whatsthis", "Schedule selector" "" "Selects the schedule to be used when displaying schedule dependent data." "Unscheduled tasks are only shown in editors." "More..." "", Help::page("Manual/Main_Work_Space#Schedule_Selector"))); QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); l->addWidget( m_viewlist ); l->addWidget( m_currentSchedule ); - connect( m_viewlist, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotActivated(QTreeWidgetItem*,QTreeWidgetItem*)) ); + connect( m_viewlist, &QTreeWidget::currentItemChanged, this, &ViewListWidget::slotActivated ); - connect( m_viewlist, SIGNAL(itemChanged(QTreeWidgetItem*,int)), SLOT(slotItemChanged(QTreeWidgetItem*,int)) ); + connect( m_viewlist, &QTreeWidget::itemChanged, this, &ViewListWidget::slotItemChanged ); setupContextMenus(); connect( m_currentSchedule, SIGNAL(activated(int)), SLOT(slotCurrentScheduleChanged(int)) ); - connect( &m_model, SIGNAL(scheduleManagerAdded(ScheduleManager*)), SLOT(slotScheduleManagerAdded(ScheduleManager*)) ); + connect( &m_model, &ScheduleItemModel::scheduleManagerAdded, this, &ViewListWidget::slotScheduleManagerAdded ); - connect( m_viewlist, SIGNAL(updateViewInfo(ViewListItem*)), SIGNAL(updateViewInfo(ViewListItem*)) ); + connect( m_viewlist, &ViewListTreeWidget::updateViewInfo, this, &ViewListWidget::updateViewInfo ); } ViewListWidget::~ViewListWidget() { } void ViewListWidget::setReadWrite( bool rw ) { foreach ( ViewListItem *c, categories() ) { for ( int i = 0; i < c->childCount(); ++i ) { static_cast( c->child( i ) )->setReadWrite( rw ); } } } void ViewListWidget::slotItemChanged( QTreeWidgetItem */*item*/, int /*col */) { //debugPlan; } void ViewListWidget::slotActivated( QTreeWidgetItem *item, QTreeWidgetItem *prev ) { if ( m_prev ) { m_prev->setData( 0, Qt::BackgroundRole, QVariant() ); } if ( item && item->type() == ViewListItem::ItemType_Category ) { return ; } emit activated( static_cast( item ), static_cast( prev ) ); if ( item ) { QVariant v = QBrush( QColor( Qt::yellow ) ); item->setData( 0, Qt::BackgroundRole, v ); m_prev = static_cast( item ); } } ViewListItem *ViewListWidget::addCategory( const QString &tag, const QString& name ) { //debugPlan ; ViewListItem *item = m_viewlist->findCategory( tag ); if ( item == 0 ) { item = new ViewListItem( m_viewlist, tag, QStringList( name ), ViewListItem::ItemType_Category ); item->setExpanded( true ); item->setFlags( item->flags() | Qt::ItemIsEditable ); } return item; } QList ViewListWidget::categories() const { QList lst; QTreeWidgetItem *item; int cnt = m_viewlist->topLevelItemCount(); for ( int i = 0; i < cnt; ++i ) { item = m_viewlist->topLevelItem( i ); if ( item->type() == ViewListItem::ItemType_Category ) lst << static_cast( item ); } return lst; } ViewListItem *ViewListWidget::findCategory( const QString &tag ) const { return m_viewlist->findCategory( tag ); } ViewListItem *ViewListWidget::category( const KoView *view ) const { return m_viewlist->category( view ); } QString ViewListWidget::uniqueTag( const QString &seed ) const { QString tag = seed; for ( int i = 1; findItem( tag ); ++i ) { tag = QString("%1-%2").arg( seed ).arg( i ); } return tag; } ViewListItem *ViewListWidget::addView(QTreeWidgetItem *category, const QString &tag, const QString &name, ViewBase *view, KoDocument *doc, const QString &iconName, int index) { ViewListItem * item = new ViewListItem( uniqueTag( tag ), QStringList( name ), ViewListItem::ItemType_SubView ); item->setView( view ); item->setDocument( doc ); if (! iconName.isEmpty()) { item->setData(0, Qt::DecorationRole, QIcon::fromTheme(iconName)); } item->setFlags( ( item->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled ); insertViewListItem( item, category, index ); - connect(view, SIGNAL(optionsModified()), SLOT(setModified())); + connect(view, &ViewBase::optionsModified, this, &ViewListWidget::setModified); return item; } void ViewListWidget::setSelected( QTreeWidgetItem *item ) { //debugPlan<currentItem(); if ( item == 0 && m_viewlist->currentItem() ) { m_viewlist->currentItem()->setSelected( false ); if ( m_prev ) { m_prev->setData( 0, Qt::BackgroundRole, QVariant() ); } } m_viewlist->setCurrentItem( item ); //debugPlan<currentItem(); } void ViewListWidget::setCurrentItem( QTreeWidgetItem *item ) { m_viewlist->setCurrentItem( item ); //debugPlan<currentItem(); } ViewListItem *ViewListWidget::currentItem() const { return static_cast( m_viewlist->currentItem() ); } ViewListItem *ViewListWidget::currentCategory() const { ViewListItem *item = static_cast( m_viewlist->currentItem() ); if ( item == 0 ) { return 0; } if ( item->type() == ViewListItem::ItemType_Category ) { return item; } return static_cast( item->parent() ); } KoView *ViewListWidget::findView( const QString &tag ) const { ViewListItem *i = findItem( tag ); if ( i == 0 ) { return 0; } return i->view(); } ViewListItem *ViewListWidget::findItem( const QString &tag ) const { ViewListItem *item = findItem( tag, m_viewlist->invisibleRootItem() ); if ( item == 0 ) { QTreeWidgetItem *parent = m_viewlist->invisibleRootItem(); for (int i = 0; i < parent->childCount(); ++i ) { item = findItem( tag, parent->child( i ) ); if ( item != 0 ) { break; } } } return item; } ViewListItem *ViewListWidget::findItem( const QString &tag, QTreeWidgetItem *parent ) const { if ( parent == 0 ) { return findItem( tag, m_viewlist->invisibleRootItem() ); } for (int i = 0; i < parent->childCount(); ++i ) { ViewListItem * ch = static_cast( parent->child( i ) ); if ( ch->tag() == tag ) { //debugPlan<invisibleRootItem() ); } for (int i = 0; i < parent->childCount(); ++i ) { ViewListItem * ch = static_cast( parent->child( i ) ); if ( ch->view() == view ) { //debugPlan<type() != ViewListItem::ItemType_Category ) { return; } debugPlan<type(); if ( m_contextitem->childCount() > 0 ) { if ( KMessageBox::warningContinueCancel( this, i18n( "Removing this category will also remove all its views." ) ) == KMessageBox::Cancel ) { return; } } // first remove all views in this category while ( m_contextitem->childCount() > 0 ) { ViewListItem *itm = static_cast( m_contextitem->child( 0 ) ); takeViewListItem( itm ); delete itm->view(); delete itm; } takeViewListItem( m_contextitem ); delete m_contextitem; m_contextitem = 0; emit modified(); } void ViewListWidget::slotRemoveView() { if ( m_contextitem ) { takeViewListItem( m_contextitem ); delete m_contextitem->view(); delete m_contextitem; emit modified(); } } void ViewListWidget::slotEditViewTitle() { //QTreeWidgetItem *item = m_viewlist->currentItem(); if ( m_contextitem ) { debugPlan<type(); QString title = m_contextitem->text( 0 ); m_viewlist->editItem( m_contextitem ); if ( title != m_contextitem->text( 0 ) ) { emit modified(); } } } void ViewListWidget::slotConfigureItem() { if ( m_contextitem == 0 ) { return; } KoDialog *dlg = 0; if ( m_contextitem->type() == ViewListItem::ItemType_Category ) { debugPlan<type(); dlg = new ViewListEditCategoryDialog( *this, m_contextitem, this ); } else if ( m_contextitem->type() == ViewListItem::ItemType_SubView ) { dlg = new ViewListEditViewDialog( *this, m_contextitem, this ); } if ( dlg ) { connect(dlg, SIGNAL(finished(int)), SLOT(slotDialogFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } } void ViewListWidget::slotDialogFinished( int result ) { if ( result == QDialog::Accepted ) { emit modified(); } if ( sender() ) { sender()->deleteLater(); } } void ViewListWidget::slotEditDocumentTitle() { //QTreeWidgetItem *item = m_viewlist->currentItem(); if ( m_contextitem ) { debugPlan<type(); QString title = m_contextitem->text( 0 ); m_viewlist->editItem( m_contextitem ); } } int ViewListWidget::removeViewListItem( ViewListItem *item ) { QTreeWidgetItem *p = item->parent(); if ( p == 0 ) { p = m_viewlist->invisibleRootItem(); } int i = p->indexOfChild( item ); if ( i != -1 ) { p->takeChild( i ); emit modified(); } return i; } void ViewListWidget::addViewListItem( ViewListItem *item, QTreeWidgetItem *parent, int index ) { QTreeWidgetItem *p = parent; if ( p == 0 ) { p = m_viewlist->invisibleRootItem(); } if ( index == -1 ) { index = p->childCount(); } p->insertChild( index, item ); emit modified(); } int ViewListWidget::takeViewListItem( ViewListItem *item ) { while ( item->childCount() > 0 ) { takeViewListItem( static_cast( item->child( 0 ) ) ); } int pos = removeViewListItem( item ); if ( pos != -1 ) { emit viewListItemRemoved( item ); if ( item == m_prev ) { m_prev = 0; } if ( m_prev ) { setCurrentItem( m_prev ); } } return pos; } void ViewListWidget::insertViewListItem( ViewListItem *item, QTreeWidgetItem *parent, int index ) { addViewListItem( item, parent, index ); emit viewListItemInserted( item, static_cast( parent ), index ); } void ViewListWidget::setupContextMenus() { // NOTE: can't use xml file as there may not be a factory() QAction *action; // view actions action = new QAction(koIcon("edit-rename"), xi18nc("@action:inmenu rename view", "Rename"), this); - connect( action, SIGNAL(triggered(bool)), this, SLOT(slotEditViewTitle()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::slotEditViewTitle ); m_viewactions.append( action ); action = new QAction(koIcon("configure"), xi18nc("@action:inmenu configure view", "Configure..."), this ); - connect( action, SIGNAL(triggered(bool)), this, SLOT(slotConfigureItem()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::slotConfigureItem ); m_viewactions.append( action ); action = new QAction(koIcon("list-remove"), xi18nc("@action:inmenu remove view", "Remove"), this); - connect( action, SIGNAL(triggered(bool)), this, SLOT(slotRemoveView()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::slotRemoveView ); m_viewactions.append( action ); action = new QAction( this ); action->setSeparator( true ); m_viewactions.append( action ); // Category actions action = new QAction(koIcon("edit-rename"), xi18nc("@action:inmenu rename view category", "Rename"), this); - connect( action, SIGNAL(triggered(bool)), SLOT(renameCategory()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::renameCategory ); m_categoryactions.append( action ); action = new QAction(koIcon("configure"), xi18nc("@action:inmenu configure view category", "Configure..."), this); - connect( action, SIGNAL(triggered(bool)), this, SLOT(slotConfigureItem()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::slotConfigureItem ); m_categoryactions.append( action ); action = new QAction(koIcon("list-remove"), xi18nc("@action:inmenu Remove view category", "Remove"),this); - connect( action, SIGNAL(triggered(bool)), this, SLOT(slotRemoveCategory()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::slotRemoveCategory ); m_categoryactions.append( action ); action = new QAction( this ); action->setSeparator( true ); m_categoryactions.append( action ); // list actions action = new QAction(koIcon("list-add"), xi18nc("@action:inmenu Insert View", "Insert..."), this); - connect( action, SIGNAL(triggered(bool)), this, SLOT(slotAddView()) ); + connect( action, &QAction::triggered, this, &ViewListWidget::slotAddView ); m_listactions.append( action ); } void ViewListWidget::renameCategory() { if ( m_contextitem ) { QString title = m_contextitem->text( 0 ); m_viewlist->editItem( m_contextitem, 0 ); } } void ViewListWidget::contextMenuEvent ( QContextMenuEvent *event ) { QMenu menu; QList lst; m_contextitem = static_cast(m_viewlist->itemAt( event->pos() ) ); if ( m_contextitem == 0 ) { lst += m_listactions; } else { if ( m_contextitem->type() == ViewListItem::ItemType_Category ) { lst += m_categoryactions; } else if ( m_contextitem->type() == ViewListItem::ItemType_SubView ) { lst += m_viewactions; ViewBase *v = dynamic_cast( m_contextitem->view() ); if ( v ) { lst += v->viewlistActionList(); } } lst += m_listactions; } if ( ! lst.isEmpty() ) { //menu.addTitle( i18n( "Edit" ) ); foreach ( QAction *a, lst ) { menu.addAction( a ); } } if ( ! menu.actions().isEmpty() ) { menu.exec( event->globalPos() ); } } void ViewListWidget::save( QDomElement &element ) const { m_viewlist->save( element ); } void ViewListWidget::setProject( Project *project ) { debugPlan<currentIndex(), m_currentSchedule->modelColumn() ); debugPlan<setCurrentIndex( idx.row() ); debugPlan< 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. */ #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") ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new AddViewPanel( view, viewlist, this ); setMainWidget( m_panel ); enableButtonOk(false); - 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(this,&KoDialog::okClicked,this,&ViewListDialog::slotOk); + connect( m_panel, &AddViewPanel::enableButtonOk, this, &KoDialog::enableButtonOk ); + connect( m_panel, &AddViewPanel::viewCreated, this, &ViewListDialog::viewCreated ); - connect(&viewlist, SIGNAL(viewListItemRemoved(KPlato::ViewListItem*)), SLOT(slotViewListItemRemoved(KPlato::ViewListItem*))); + 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, 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.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, SIGNAL(editTextChanged(QString)), SLOT(categoryChanged()) ); + 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" ) ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new EditViewPanel( viewlist, item, this ); setMainWidget( m_panel ); enableButtonOk(false); - connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); - connect( m_panel, SIGNAL(enableButtonOk(bool)), SLOT(enableButtonOk(bool)) ); + connect(this,&KoDialog::okClicked,this,&ViewListEditViewDialog::slotOk); + connect( m_panel, &EditViewPanel::enableButtonOk, this, &KoDialog::enableButtonOk ); - connect(&viewlist, SIGNAL(viewListItemRemoved(ViewListItem*)), SLOT(slotViewListItemRemoved(ViewListItem*))); + 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, SIGNAL(textChanged(QString)), SLOT(changed()) ); - connect( widget.tooltip, SIGNAL(textChanged(QString)), SLOT(changed()) ); + 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, SIGNAL(editTextChanged(QString)), SLOT(categoryChanged()) ); + 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" ) ); setButtons( KoDialog::Ok | KoDialog::Cancel ); setDefaultButton( Ok ); m_panel = new EditCategoryPanel( viewlist, item, this ); setMainWidget( m_panel ); enableButtonOk(false); - connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); - connect( m_panel, SIGNAL(enableButtonOk(bool)), SLOT(enableButtonOk(bool)) ); + connect(this,&KoDialog::okClicked,this,&ViewListEditCategoryDialog::slotOk); + connect( m_panel, &EditCategoryPanel::enableButtonOk, this, &KoDialog::enableButtonOk ); - connect(&viewlist, SIGNAL(viewListItemRemoved(KPlato::ViewListItem*)), SLOT(slotViewListItemRemoved(KPlato::ViewListItem*))); + 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, SIGNAL(textChanged(QString)), SLOT(changed()) ); - connect( widget.tooltip, SIGNAL(textChanged(QString)), SLOT(changed()) ); + 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" ) ); 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" ); 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/kptviewlistdocker.cpp b/src/kptviewlistdocker.cpp index db3426bb..4c9c3987 100644 --- a/src/kptviewlistdocker.cpp +++ b/src/kptviewlistdocker.cpp @@ -1,98 +1,98 @@ /* This file is part of the KDE project * Copyright (C) 2007 Fredy Yanardi * * 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 "kptviewlistdocker.h" #include "kptviewlist.h" #include "kptview.h" #include "Help.h" #include "kptdebug.h" #include namespace KPlato { ViewListDocker::ViewListDocker(View *view) { updateWindowTitle( false ); setView(view); } ViewListDocker::~ViewListDocker() { } View *ViewListDocker::view() { return m_view; } void ViewListDocker::setView(View *view) { m_view = view; QWidget *wdg = widget(); if (wdg) delete wdg; m_viewlist = new ViewListWidget(view->getPart(), this); setWhatsThis(m_viewlist->whatsThis()); setWidget(m_viewlist); m_viewlist->setProject( &( view->getProject() ) ); connect( m_viewlist, SIGNAL(selectionChanged(ScheduleManager*)), view, SLOT(slotSelectionChanged(ScheduleManager*)) ); - connect( view, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), m_viewlist, SLOT(setSelectedSchedule(ScheduleManager*)) ); + connect( view, &View::currentScheduleManagerChanged, m_viewlist, &ViewListWidget::setSelectedSchedule ); connect( m_viewlist, SIGNAL(updateViewInfo(ViewListItem*)), view, SLOT(slotUpdateViewInfo(ViewListItem*)) ); } void ViewListDocker::slotModified() { setWindowTitle( xi18nc( "@title:window", "View Selector [modified]" ) ); } void ViewListDocker::updateWindowTitle( bool modified ) { if ( modified ) { setWindowTitle( xi18nc( "@title:window", "View Selector [modified]" ) ); } else { setWindowTitle(xi18nc( "@title:window", "View Selector")); } } //---------- ViewListDockerFactory::ViewListDockerFactory(View *view) { m_view = view; } QString ViewListDockerFactory::id() const { return QString("KPlatoViewList"); } QDockWidget* ViewListDockerFactory::createDockWidget() { ViewListDocker *widget = new ViewListDocker(m_view); widget->setObjectName(id()); return widget; } } //namespace KPlato diff --git a/src/libs/kernel/kptproject.cpp b/src/libs/kernel/kptproject.cpp index 045dc60a..88f97541 100644 --- a/src/libs/kernel/kptproject.cpp +++ b/src/libs/kernel/kptproject.cpp @@ -1,2940 +1,2940 @@ /* This file is part of the KDE project Copyright (C) 2001 Thomas zander Copyright (C) 2004 - 2010, 2012 Dag Andersen Copyright (C) 2007 Florian Piquemal Copyright (C) 2007 Alexis Ménard 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 "kptproject.h" #include "kptlocale.h" #include "kptappointment.h" #include "kpttask.h" #include "kptdatetime.h" #include "kpteffortcostmap.h" #include "kptschedule.h" #include "kptwbsdefinition.h" #include "kptxmlloaderobject.h" #include "kptschedulerplugin.h" #include "kptdebug.h" #include #include #include #include #include #include namespace KPlato { Project::Project( Node *parent ) : Node( parent ), m_accounts( *this ), m_defaultCalendar( 0 ), m_config( &emptyConfig ), m_schedulerPlugins(), m_useSharedResources(false), m_sharedResourcesLoaded(false), m_loadProjectsAtStartup(false) { //debugPlan<<"("<setDefaultValues(*this); } Project::Project( ConfigBase &config, bool useDefaultValues, Node *parent ) : Node( parent ), m_accounts( *this ), m_defaultCalendar( 0 ), m_config( &config ), m_schedulerPlugins(), m_useSharedResources(false), m_sharedResourcesLoaded(false), m_loadProjectsAtStartup(false) { debugPlan<<"("<setDefaultValues(*this); } } void Project::init() { m_refCount = 1; // always used by creator m_constraint = Node::MustStartOn; m_standardWorktime = new StandardWorktime(); m_timeZone = QTimeZone::systemTimeZone(); // local timezone as default //debugPlan<= 0 ); if ( m_refCount <= 0 ) { emit aboutToBeDeleted(); deleteLater(); } } Project::~Project() { debugPlan<<"("<blockChanged(); } for (Resource *r : qAsConst(resourceIdDict)) { r->blockChanged(); } for (ResourceGroup *g : qAsConst(resourceGroupIdDict)) { g->blockChanged(); } delete m_standardWorktime; while ( !m_resourceGroups.isEmpty() ) delete m_resourceGroups.takeFirst(); while ( !m_calendars.isEmpty() ) delete m_calendars.takeFirst(); while ( !m_managers.isEmpty() ) delete m_managers.takeFirst(); m_config = 0; //not mine, don't delete } int Project::type() const { return Node::Type_Project; } void Project::generateUniqueNodeIds() { foreach ( Node *n, nodeIdDict ) { debugPlan<name()<<"old"<id(); QString uid = uniqueNodeId(); nodeIdDict.remove( n->id() ); n->setId( uid ); nodeIdDict[ uid ] = n; debugPlan<name()<<"new"<id(); } } void Project::generateUniqueIds() { generateUniqueNodeIds(); foreach ( ResourceGroup *g, resourceGroupIdDict ) { if (g->isShared()) { continue; } resourceGroupIdDict.remove( g->id() ); g->setId( uniqueResourceGroupId() ); resourceGroupIdDict[ g->id() ] = g; } foreach ( Resource *r, resourceIdDict ) { if (r->isShared()) { continue; } resourceIdDict.remove( r->id() ); r->setId( uniqueResourceId() ); resourceIdDict[ r->id() ] = r; } foreach ( Calendar *c, calendarIdDict ) { if (c->isShared()) { continue; } calendarIdDict.remove( c->id() ); c->setId( uniqueCalendarId() ); calendarIdDict[ c->id() ] = c; } } void Project::calculate( Schedule *schedule, const DateTime &dt ) { if ( schedule == 0 ) { errorPlan << "Schedule == 0, cannot calculate"; return ; } m_currentSchedule = schedule; calculate( dt ); } void Project::calculate( const DateTime &dt ) { if ( m_currentSchedule == 0 ) { errorPlan << "No current schedule to calculate"; return ; } stopcalculation = false; QLocale locale; DateTime time = dt.isValid() ? dt : DateTime( QDateTime::currentDateTime() ); MainSchedule *cs = static_cast( m_currentSchedule ); Estimate::Use estType = ( Estimate::Use ) cs->type(); if ( type() == Type_Project ) { cs->setPhaseName( 0, i18n( "Init" ) ); cs->logInfo( i18n( "Schedule project from: %1", locale.toString(dt, QLocale::ShortFormat) ), 0 ); initiateCalculation( *cs ); initiateCalculationLists( *cs ); // must be after initiateCalculation() !! propagateEarliestStart( time ); // Calculate lateFinish from time. If a task has started, remainingEffort is used. cs->setPhaseName( 1, i18nc( "Schedule project forward", "Forward" ) ); cs->logInfo( i18n( "Calculate finish" ), 1 ); cs->lateFinish = calculateForward( estType ); cs->lateFinish = checkEndConstraints( cs->lateFinish ); propagateLatestFinish( cs->lateFinish ); // Calculate earlyFinish. If a task has started, remainingEffort is used. cs->setPhaseName( 2, i18nc( "Schedule project backward","Backward" ) ); cs->logInfo( i18n( "Calculate start" ), 2 ); calculateBackward( estType ); // Schedule. If a task has started, remainingEffort is used and appointments are copied from parent cs->setPhaseName( 3, i18n( "Schedule" ) ); cs->logInfo( i18n( "Schedule tasks forward" ), 3 ); cs->endTime = scheduleForward( cs->startTime, estType ); cs->logInfo( i18n( "Scheduled finish: %1", locale.toString(cs->endTime, QLocale::ShortFormat) ), 3 ); if ( cs->endTime > m_constraintEndTime ) { cs->logError( i18n( "Could not finish project in time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else if ( cs->endTime == m_constraintEndTime ) { cs->logWarning( i18n( "Finished project exactly on time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else { cs->logInfo( i18n( "Finished project before time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } calcCriticalPath( false ); calcResourceOverbooked(); cs->notScheduled = false; calcFreeFloat(); emit scheduleChanged( cs ); emit projectChanged(); } else if ( type() == Type_Subproject ) { warnPlan << "Subprojects not implemented"; } else { errorPlan << "Illegal project type: " << type(); } } void Project::calculate( ScheduleManager &sm ) { emit sigCalculationStarted( this, &sm ); sm.setScheduling( true ); m_progress = 0; int nodes = 0; foreach ( Node *n, nodeIdDict ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { nodes++; } } int maxprogress = nodes * 3; if ( sm.recalculate() ) { emit maxProgress( maxprogress ); sm.setMaxProgress( maxprogress ); incProgress(); if ( sm.parentManager() ) { sm.expected()->startTime = sm.parentManager()->expected()->startTime; sm.expected()->earlyStart = sm.parentManager()->expected()->earlyStart; } incProgress(); calculate( sm.expected(), sm.recalculateFrom() ); } else { emit maxProgress( maxprogress ); sm.setMaxProgress( maxprogress ); calculate( sm.expected() ); emit scheduleChanged( sm.expected() ); setCurrentSchedule( sm.expected()->id() ); } emit sigProgress( maxprogress ); emit sigCalculationFinished( this, &sm ); emit scheduleManagerChanged( &sm ); emit projectCalculated( &sm ); emit projectChanged(); sm.setScheduling( false ); } void Project::calculate( Schedule *schedule ) { if ( schedule == 0 ) { errorPlan << "Schedule == 0, cannot calculate"; return ; } m_currentSchedule = schedule; calculate(); } void Project::calculate() { if ( m_currentSchedule == 0 ) { errorPlan << "No current schedule to calculate"; return ; } stopcalculation = false; MainSchedule *cs = static_cast( m_currentSchedule ); bool backwards = false; if ( cs->manager() ) { backwards = cs->manager()->schedulingDirection(); } QLocale locale; Estimate::Use estType = ( Estimate::Use ) cs->type(); if ( type() == Type_Project ) { QTime timer; timer.start(); initiateCalculation( *cs ); initiateCalculationLists( *cs ); // must be after initiateCalculation() !! if ( ! backwards ) { cs->setPhaseName( 0, i18n( "Init" ) ); cs->logInfo( i18n( "Schedule project forward from: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 0 ); cs->startTime = m_constraintStartTime; cs->earlyStart = m_constraintStartTime; // Calculate from start time propagateEarliestStart( cs->earlyStart ); cs->setPhaseName( 1, i18nc( "Schedule project forward", "Forward" ) ); cs->logInfo( i18n( "Calculate late finish" ), 1 ); cs->lateFinish = calculateForward( estType ); // cs->lateFinish = checkEndConstraints( cs->lateFinish ); cs->logInfo( i18n( "Late finish calculated: %1", locale.toString(cs->lateFinish, QLocale::ShortFormat) ), 1 ); propagateLatestFinish( cs->lateFinish ); cs->setPhaseName( 2, i18nc( "Schedule project backward", "Backward" ) ); cs->logInfo( i18n( "Calculate early start" ), 2 ); calculateBackward( estType ); cs->setPhaseName( 3, i18n( "Schedule" ) ); cs->logInfo( i18n( "Schedule tasks forward" ), 3 ); cs->endTime = scheduleForward( cs->startTime, estType ); cs->duration = cs->endTime - cs->startTime; cs->logInfo( i18n( "Scheduled finish: %1", locale.toString(cs->endTime, QLocale::ShortFormat) ), 3 ); if ( cs->endTime > m_constraintEndTime ) { cs->constraintError = true; cs->logError( i18n( "Could not finish project in time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else if ( cs->endTime == m_constraintEndTime ) { cs->logWarning( i18n( "Finished project exactly on time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } else { cs->logInfo( i18n( "Finished project before time: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 3 ); } calcCriticalPath( false ); } else { cs->setPhaseName( 0, i18n( "Init" ) ); cs->logInfo( i18n( "Schedule project backward from: %1", locale.toString(m_constraintEndTime, QLocale::ShortFormat) ), 0 ); // Calculate from end time propagateLatestFinish( m_constraintEndTime ); cs->setPhaseName( 1, i18nc( "Schedule project backward", "Backward" ) ); cs->logInfo( i18n( "Calculate early start" ), 1 ); cs->earlyStart = calculateBackward( estType ); // cs->earlyStart = checkStartConstraints( cs->earlyStart ); cs->logInfo( i18n( "Early start calculated: %1", locale.toString(cs->earlyStart, QLocale::ShortFormat) ), 1 ); propagateEarliestStart( cs->earlyStart ); cs->setPhaseName( 2, i18nc( "Schedule project forward", "Forward" ) ); cs->logInfo( i18n( "Calculate late finish" ), 2 ); cs->lateFinish = qMax( m_constraintEndTime, calculateForward( estType ) ); cs->logInfo( i18n( "Late finish calculated: %1", locale.toString(cs->lateFinish, QLocale::ShortFormat) ), 2 ); cs->setPhaseName( 3, i18n( "Schedule" ) ); cs->logInfo( i18n( "Schedule tasks backward" ), 3 ); cs->startTime = scheduleBackward( cs->lateFinish, estType ); cs->endTime = cs->startTime; foreach ( Node *n, allNodes() ) { if ( n->type() == Type_Task || n->type() == Type_Milestone ) { DateTime e = n->endTime( cs->id() ); if ( cs->endTime < e ) { cs->endTime = e; } } } if ( cs->endTime > m_constraintEndTime ) { cs->constraintError = true; cs->logError( i18n( "Failed to finish project within target time" ), 3 ); } cs->duration = cs->endTime - cs->startTime; cs->logInfo( i18n( "Scheduled start: %1, target time: %2", locale.toString(cs->startTime, QLocale::ShortFormat), locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); if ( cs->startTime < m_constraintStartTime ) { cs->constraintError = true; cs->logError( i18n( "Must start project early in order to finish in time: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); } else if ( cs->startTime == m_constraintStartTime ) { cs->logWarning( i18n( "Start project exactly on time: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); } else { cs->logInfo( i18n( "Can start project later than time: %1", locale.toString(m_constraintStartTime, QLocale::ShortFormat) ), 3 ); } calcCriticalPath( true ); } cs->logInfo( i18n( "Calculation took: %1", KFormat().formatDuration( timer.elapsed() ) ) ); // TODO: fix this uncertainty, manager should *always* be available if (cs->manager()) { finishCalculation(*(cs->manager())); } } else if ( type() == Type_Subproject ) { warnPlan << "Subprojects not implemented"; } else { errorPlan << "Illegal project type: " << type(); } } void Project::finishCalculation( ScheduleManager &sm ) { MainSchedule *cs = sm.expected(); if (nodeIdDict.count() > 1) { // calculate project duration cs->startTime = m_constraintEndTime; cs->endTime = m_constraintStartTime; for (const Node *n : qAsConst(nodeIdDict)) { cs->startTime = qMin(cs->startTime, n->startTime(cs->id())); cs->endTime = qMax(cs->endTime, n->endTime(cs->id())); } cs->duration = cs->endTime - cs->startTime; } calcCriticalPath( false ); calcResourceOverbooked(); cs->notScheduled = false; calcFreeFloat(); emit scheduleChanged( cs ); emit projectChanged(); debugPlan<startTime<endTime<<"-------------------------"; } void Project::setProgress( int progress, ScheduleManager *sm ) { m_progress = progress; if ( sm ) { sm->setProgress( progress ); } emit sigProgress( progress ); } void Project::setMaxProgress( int max, ScheduleManager *sm ) { if ( sm ) { sm->setMaxProgress( max ); } emitMaxProgress( max ); } void Project::incProgress() { m_progress += 1; emit sigProgress( m_progress ); } void Project::emitMaxProgress( int value ) { emit maxProgress( value ); } bool Project::calcCriticalPath( bool fromEnd ) { //debugPlan; MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 ) { return false; } if ( fromEnd ) { QListIterator startnodes = cs->startNodes(); while ( startnodes.hasNext() ) { startnodes.next() ->calcCriticalPath( fromEnd ); } } else { QListIterator endnodes = cs->endNodes(); while ( endnodes.hasNext() ) { endnodes.next() ->calcCriticalPath( fromEnd ); } } calcCriticalPathList( cs ); return false; } void Project::calcCriticalPathList( MainSchedule *cs ) { //debugPlan<name(); cs->clearCriticalPathList(); foreach ( Node *n, allNodes() ) { if ( n->numDependParentNodes() == 0 && n->inCriticalPath( cs->id() ) ) { cs->addCriticalPath(); cs->addCriticalPathNode( n ); calcCriticalPathList( cs, n ); } } cs->criticalPathListCached = true; //debugPlan<<*(criticalPathList( cs->id() )); } void Project::calcCriticalPathList( MainSchedule *cs, Node *node ) { //debugPlan<name()<<", "<id(); bool newPath = false; QList lst = *( cs->currentCriticalPath() ); foreach ( Relation *r, node->dependChildNodes() ) { if ( r->child()->inCriticalPath( cs->id() ) ) { if ( newPath ) { cs->addCriticalPath( &lst ); //debugPlan<name()<<" new path"; } cs->addCriticalPathNode( r->child() ); calcCriticalPathList( cs, r->child() ); newPath = true; } } } const QList< QList > *Project::criticalPathList( long id ) { Schedule *s = schedule( id ); if ( s == 0 ) { //debugPlan<<"No schedule with id="<( s ); if ( ! ms->criticalPathListCached ) { initiateCalculationLists( *ms ); calcCriticalPathList( ms ); } return ms->criticalPathList(); } QList Project::criticalPath( long id, int index ) { Schedule *s = schedule( id ); if ( s == 0 ) { //debugPlan<<"No schedule with id="<(); } MainSchedule *ms = static_cast( s ); if ( ! ms->criticalPathListCached ) { initiateCalculationLists( *ms ); calcCriticalPathList( ms ); } return ms->criticalPath( index ); } DateTime Project::startTime( long id ) const { Schedule *s = schedule( id ); return s ? s->startTime : m_constraintStartTime; } DateTime Project::endTime( long id ) const { Schedule *s = schedule( id ); return s ? s->endTime : m_constraintEndTime; } Duration Project::duration( long id ) const { Schedule *s = schedule( id ); return s ? s->duration : Duration::zeroDuration; } Duration *Project::getRandomDuration() { return 0L; } DateTime Project::checkStartConstraints( const DateTime &dt ) const { DateTime t = dt; foreach ( Node *n, nodeIdDict ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { switch ( n->constraint() ) { case Node::FixedInterval: case Node::StartNotEarlier: case Node::MustStartOn: t = qMin( t, qMax( n->constraintStartTime(), m_constraintStartTime ) ); break; default: break; } } } return t; } DateTime Project::checkEndConstraints( const DateTime &dt ) const { DateTime t = dt; foreach ( Node *n, nodeIdDict ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { switch ( n->constraint() ) { case Node::FixedInterval: case Node::FinishNotLater: case Node::MustFinishOn: t = qMax( t, qMin( n->constraintEndTime(), m_constraintEndTime ) ); break; default: break; } } } return t; } #ifndef PLAN_NLOGDEBUG bool Project::checkParent( Node *n, const QList &list, QList &checked ) { if ( n->isStartNode() ) { debugPlan< lst = list; lst << n; foreach ( Relation *r, n->dependParentNodes() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } checked << r; if ( ! checkParent( r->parent(), lst, checked ) ) { return false; } } Task *t = static_cast( n ); foreach ( Relation *r, t->parentProxyRelations() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } checked << r; debugPlan<<"Proxy:"<parent()<<":"<parent(), lst, checked ) ) { return false; } } return true; } bool Project::checkChildren( Node *n, const QList &list, QList &checked ) { if ( n->isEndNode() ) { debugPlan< lst = list; lst << n; foreach ( Relation *r, n->dependChildNodes() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } checked << r; if ( ! checkChildren( r->child(), lst, checked ) ) { return false; } } Task *t = static_cast( n ); foreach ( Relation *r, t->childProxyRelations() ) { if ( checked.contains( r ) ) { debugPlan<<"Depend:"<parent()<<": checked"; continue; } debugPlan<<"Proxy:"<parent()<<":"<child(), lst, checked ) ) { return false; } } return true; } #endif void Project::tasksForward() { m_hardConstraints.clear(); m_softConstraints.clear(); m_terminalNodes.clear(); foreach ( Task *t, allTasks() ) { switch ( t->constraint() ) { case Node::MustStartOn: case Node::MustFinishOn: case Node::FixedInterval: m_hardConstraints.append( t ); break; case Node::StartNotEarlier: case Node::FinishNotLater: m_softConstraints.append( t ); break; default: if ( t->isEndNode() ) { m_terminalNodes.append( t ); } break; } } #ifndef PLAN_NLOGDEBUG debugPlan<<"End nodes:"< lst; QList rel; Q_ASSERT( checkParent( n, lst, rel ) ); Q_UNUSED( n ); } #endif } void Project::tasksBackward() { m_hardConstraints.clear(); m_softConstraints.clear(); m_terminalNodes.clear(); foreach ( Task *t, allTasks() ) { switch ( t->constraint() ) { case Node::MustStartOn: case Node::MustFinishOn: case Node::FixedInterval: m_hardConstraints.append( t ); break; case Node::StartNotEarlier: case Node::FinishNotLater: m_softConstraints.append( t ); break; default: if ( t->isStartNode() ) { m_terminalNodes.append( t ); } break; } } #ifndef PLAN_NLOGDEBUG debugPlan<<"Start nodes:"< lst; QList rel; Q_ASSERT( checkChildren( n, lst, rel ) ); Q_UNUSED( n ); } #endif } DateTime Project::calculateForward( int use ) { //debugPlan<( m_currentSchedule ); if ( cs == 0 ) { return finish; } if ( type() == Node::Type_Project ) { QTime timer; timer.start(); cs->logInfo( i18n( "Start calculating forward" ) ); m_visitedForward = true; if ( ! m_visitedBackward ) { // setup tasks tasksForward(); // Do all hard constrained first foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Calculate task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateEarlyFinish( use ); // do not do predeccessors if ( time > finish ) { finish = time; } } // do the predeccessors foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Calculate predeccessors to hard constrained task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } // now try to schedule soft constrained *with* predeccessors foreach ( Node *n, m_softConstraints ) { cs->logDebug( "Calculate task with soft constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } // and then the rest using the end nodes to calculate everything (remaining) foreach ( Task *n, m_terminalNodes ) { cs->logDebug( "Calculate using end task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } } else { // tasks have been calculated backwards in this order foreach ( Node *n, cs->backwardNodes() ) { DateTime time = n->calculateForward( use ); if ( time > finish ) { finish = time; } } } cs->logInfo( i18n( "Finished calculating forward: %1 ms", timer.elapsed() ) ); } else { //TODO: subproject } return finish; } DateTime Project::calculateBackward( int use ) { //debugPlan<( m_currentSchedule ); if ( cs == 0 ) { return start; } if ( type() == Node::Type_Project ) { QTime timer; timer.start(); cs->logInfo( i18n( "Start calculating backward" ) ); m_visitedBackward = true; if ( ! m_visitedForward ) { // setup tasks tasksBackward(); // Do all hard constrained first foreach ( Task *n, m_hardConstraints ) { cs->logDebug( "Calculate task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateLateStart( use ); // do not do predeccessors if ( ! start.isValid() || time < start ) { start = time; } } // then do the predeccessors foreach ( Task *n, m_hardConstraints ) { cs->logDebug( "Calculate predeccessors to hard constrained task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } // now try to schedule soft constrained *with* predeccessors foreach ( Task *n, m_softConstraints ) { cs->logDebug( "Calculate task with soft constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } // and then the rest using the start nodes to calculate everything (remaining) foreach ( Task *n, m_terminalNodes ) { cs->logDebug( "Calculate using start task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } } else { // tasks have been calculated forwards in this order foreach ( Node *n, cs->forwardNodes() ) { DateTime time = n->calculateBackward( use ); if ( ! start.isValid() || time < start ) { start = time; } } } cs->logInfo( i18n( "Finished calculating backward: %1 ms", timer.elapsed() ) ); } else { //TODO: subproject } return start; } DateTime Project::scheduleForward( const DateTime &earliest, int use ) { DateTime end; MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 || stopcalculation ) { return DateTime(); } QTime timer; timer.start(); cs->logInfo( i18n( "Start scheduling forward" ) ); resetVisited(); // Schedule in the same order as calculated forward // Do all hard constrained first foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Schedule task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleFromStartTime( use ); // do not do predeccessors if ( time > end ) { end = time; } } foreach ( Node *n, cs->forwardNodes() ) { cs->logDebug( "Schedule task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleForward( earliest, use ); if ( time > end ) { end = time; } } // Fix summarytasks adjustSummarytask(); cs->logInfo( i18n( "Finished scheduling forward: %1 ms", timer.elapsed() ) ); foreach ( Node *n, allNodes() ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { Q_ASSERT( n->isScheduled() ); } } return end; } DateTime Project::scheduleBackward( const DateTime &latest, int use ) { DateTime start; MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 || stopcalculation ) { return start; } QTime timer; timer.start(); cs->logInfo( i18n( "Start scheduling backward" ) ); resetVisited(); // Schedule in the same order as calculated backward // Do all hard constrained first foreach ( Node *n, m_hardConstraints ) { cs->logDebug( "Schedule task with hard constraint:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleFromEndTime( use ); // do not do predeccessors if ( ! start.isValid() || time < start ) { start = time; } } foreach ( Node *n, cs->backwardNodes() ) { cs->logDebug( "Schedule task:" + n->name() + " : " + n->constraintToString() ); DateTime time = n->scheduleBackward( latest, use ); if ( ! start.isValid() || time < start ) { start = time; } } // Fix summarytasks adjustSummarytask(); cs->logInfo( i18n( "Finished scheduling backward: %1 ms", timer.elapsed() ) ); foreach ( Node *n, allNodes() ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { Q_ASSERT( n->isScheduled() ); } } return start; } void Project::adjustSummarytask() { MainSchedule *cs = static_cast( m_currentSchedule ); if ( cs == 0 || stopcalculation ) { return; } QListIterator it( cs->summaryTasks() ); while ( it.hasNext() ) { it.next() ->adjustSummarytask(); } } void Project::initiateCalculation( MainSchedule &sch ) { //debugPlan< git( m_resourceGroups ); while ( git.hasNext() ) { git.next() ->initiateCalculation( sch ); } Node::initiateCalculation( sch ); } void Project::initiateCalculationLists( MainSchedule &sch ) { //debugPlan< it = childNodeIterator(); while ( it.hasNext() ) { it.next() ->initiateCalculationLists( sch ); } } else { //TODO: subproject } } bool Project::load( KoXmlElement &element, XMLLoaderObject &status ) { //debugPlan<<"--->"; m_useSharedResources = false; // default should off in case old project // load locale first KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "locale" ) { Locale *l = locale(); l->setCurrencySymbol(e.attribute( "currency-symbol", "")); if ( e.hasAttribute( "currency-digits" ) ) { l->setMonetaryDecimalPlaces(e.attribute("currency-digits").toInt()); } QLocale::Language language = QLocale::AnyLanguage; QLocale::Country country = QLocale::AnyCountry; if (e.hasAttribute("language")) { language = static_cast(e.attribute("language").toInt()); } if (e.hasAttribute("country")) { country = static_cast(e.attribute("country").toInt()); } l->setCurrencyLocale(language, country); } else if (e.tagName() == "shared-resources") { m_useSharedResources = e.attribute("use", "0").toInt(); m_sharedResourcesFile = e.attribute("file"); m_sharedProjectsUrl = QUrl(e.attribute("projects-url")); m_loadProjectsAtStartup = (bool)e.attribute("projects-loadatstartup", "0").toInt(); } } QList cals; QString s; bool ok = false; setName( element.attribute( "name" ) ); removeId( m_id ); m_id = element.attribute( "id" ); registerNodeId( this ); m_leader = element.attribute( "leader" ); m_description = element.attribute( "description" ); QTimeZone tz( element.attribute( "timezone" ).toLatin1() ); if ( tz.isValid() ) { m_timeZone = tz; } else warnPlan<<"No timezone specified, using default (local)"; status.setProjectTimeZone( m_timeZone ); // Allow for both numeric and text s = element.attribute( "scheduling", "0" ); m_constraint = ( Node::ConstraintType ) s.toInt( &ok ); if ( !ok ) setConstraint( s ); if ( m_constraint != Node::MustStartOn && m_constraint != Node::MustFinishOn ) { errorPlan << "Illegal constraint: " << constraintToString(); setConstraint( Node::MustStartOn ); } s = element.attribute( "start-time" ); if ( !s.isEmpty() ) m_constraintStartTime = DateTime::fromString( s, m_timeZone ); s = element.attribute( "end-time" ); if ( !s.isEmpty() ) m_constraintEndTime = DateTime::fromString( s, m_timeZone ); status.setProgress( 10 ); // Load the project children // Do calendars first, they only reference other calendars //debugPlan<<"Calendars--->"; n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "calendar" ) { // Load the calendar. // Referenced by resources Calendar * child = new Calendar(); child->setProject( this ); if ( child->load( e, status ) ) { cals.append( child ); // temporary, reorder later } else { // TODO: Complain about this errorPlan << "Failed to load calendar"; delete child; } } else if ( e.tagName() == "standard-worktime" ) { // Load standard worktime StandardWorktime * child = new StandardWorktime(); if ( child->load( e, status ) ) { setStandardWorktime( child ); } else { errorPlan << "Failed to load standard worktime"; delete child; } } } // calendars references calendars in arbritary saved order bool added = false; do { added = false; QList lst; while ( !cals.isEmpty() ) { Calendar *c = cals.takeFirst(); c->m_blockversion = true; if ( c->parentId().isEmpty() ) { addCalendar( c, status.baseCalendar() ); // handle pre 0.6 version added = true; //debugPlan<<"added to project:"<name(); } else { Calendar *par = calendar( c->parentId() ); if ( par ) { par->m_blockversion = true; addCalendar( c, par ); added = true; //debugPlan<<"added:"<name()<<" to parent:"<name(); par->m_blockversion = false; } else { lst.append( c ); // treat later //debugPlan<<"treat later:"<name(); } } c->m_blockversion = false; } cals = lst; } while ( added ); if ( ! cals.isEmpty() ) { errorPlan<<"All calendars not saved!"; } //debugPlan<<"Calendars<---"; status.setProgress( 15 ); // Resource groups and resources, can reference calendars n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "resource-group" ) { // Load the resources // References calendars ResourceGroup * child = new ResourceGroup(); if ( child->load( e, status ) ) { addResourceGroup( child ); } else { // TODO: Complain about this delete child; } } } status.setProgress( 20 ); // The main stuff n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if ( e.tagName() == "project" ) { //debugPlan<<"Sub project--->"; /* // Load the subproject Project * child = new Project( this ); if ( child->load( e ) ) { if ( !addTask( child, this ) ) { delete child; // TODO: Complain about this } } else { // TODO: Complain about this delete child; }*/ } else if ( e.tagName() == "task" ) { //debugPlan<<"Task--->"; // Load the task (and resourcerequests). // Depends on resources already loaded Task * child = new Task( this ); if ( child->load( e, status ) ) { if ( !addTask( child, this ) ) { delete child; // TODO: Complain about this } } else { // TODO: Complain about this delete child; } } } status.setProgress( 70 ); // These go last n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { debugPlan<"; // Load accounts // References tasks if ( !m_accounts.load( e, *this ) ) { errorPlan << "Failed to load accounts"; } } else if ( e.tagName() == "relation" ) { //debugPlan<<"Relation--->"; // Load the relation // References tasks Relation * child = new Relation(); if ( !child->load( e, *this ) ) { // TODO: Complain about this errorPlan << "Failed to load relation"; delete child; } //debugPlan<<"Relation<---"; } else if ( e.tagName() == "schedules" ) { //debugPlan<<"Project schedules & task appointments--->"; // References tasks and resources KoXmlNode sn = e.firstChild(); for ( ; ! sn.isNull(); sn = sn.nextSibling() ) { if ( ! sn.isElement() ) { continue; } KoXmlElement el = sn.toElement(); //debugPlan<loadXML( el, status ) ) { if ( add ) addScheduleManager( sm ); } else { errorPlan << "Failed to load schedule manager"; delete sm; } } else { debugPlan<<"No schedule manager ?!"; } } //debugPlan<<"Node schedules<---"; } else if ( e.tagName() == "resource-teams" ) { //debugPlan<<"Resource teams--->"; // References other resources KoXmlNode tn = e.firstChild(); for ( ; ! tn.isNull(); tn = tn.nextSibling() ) { if ( ! tn.isElement() ) { continue; } KoXmlElement el = tn.toElement(); if ( el.tagName() == "team" ) { Resource *r = findResource( el.attribute( "team-id" ) ); Resource *tm = findResource( el.attribute( "member-id" ) ); if ( r == 0 || tm == 0 ) { errorPlan<<"resource-teams: cannot find resources"; continue; } if ( r == tm ) { errorPlan<<"resource-teams: a team cannot be a member of itself"; continue; } r->addTeamMemberId( tm->id() ); } else { errorPlan<<"resource-teams: unhandled tag"<currencySymbolExplicit().isEmpty()) { loc.setAttribute("currency-symbol", l->currencySymbolExplicit()); } loc.setAttribute("currency-digits", l->monetaryDecimalPlaces()); loc.setAttribute("language", l->currencyLanguage()); loc.setAttribute("country", l->currencyCountry()); QDomElement share = me.ownerDocument().createElement( "shared-resources" ); me.appendChild(share); share.setAttribute("use", m_useSharedResources); share.setAttribute("file", m_sharedResourcesFile); share.setAttribute("projects-url", QString(m_sharedProjectsUrl.toEncoded())); share.setAttribute("projects-loadatstartup", m_loadProjectsAtStartup); m_accounts.save( me ); // save calendars foreach ( Calendar *c, calendarIdDict ) { c->save( me ); } // save standard worktime if ( m_standardWorktime ) m_standardWorktime->save( me ); // save project resources, must be after calendars QListIterator git( m_resourceGroups ); while ( git.hasNext() ) { git.next() ->save( me ); } // Only save parent relations QListIterator it( m_dependParentNodes ); while ( it.hasNext() ) { it.next() ->save( me ); } for ( int i = 0; i < numChildren(); i++ ) // Save all children childNode( i ) ->save( me ); // Now we can save relations assuming no tasks have relations outside the project QListIterator nodes( m_nodes ); while ( nodes.hasNext() ) { nodes.next() ->saveRelations( me ); } if ( !m_managers.isEmpty() ) { QDomElement el = me.ownerDocument().createElement( "schedules" ); me.appendChild( el ); foreach ( ScheduleManager *sm, m_managers ) { sm->saveXML( el ); } } // save resource teams QDomElement el = me.ownerDocument().createElement( "resource-teams" ); me.appendChild( el ); foreach ( Resource *r, resourceIdDict ) { if ( r->type() != Resource::Type_Team ) { continue; } foreach ( const QString &id, r->teamMemberIds() ) { QDomElement e = el.ownerDocument().createElement( "team" ); el.appendChild( e ); e.setAttribute( "team-id", r->id() ); e.setAttribute( "member-id", id ); } } } void Project::saveWorkPackageXML( QDomElement &element, const Node *node, long id ) const { QDomElement me = element.ownerDocument().createElement( "project" ); element.appendChild( me ); me.setAttribute( "name", m_name ); me.setAttribute( "leader", m_leader ); me.setAttribute( "id", m_id ); me.setAttribute( "description", m_description ); me.setAttribute( "timezone", m_timeZone.isValid() ? QString::fromLatin1(m_timeZone.id()) : QString() ); me.setAttribute( "scheduling", constraintToString() ); me.setAttribute( "start-time", m_constraintStartTime.toString( Qt::ISODate ) ); me.setAttribute( "end-time", m_constraintEndTime.toString( Qt::ISODate ) ); QListIterator git( m_resourceGroups ); while ( git.hasNext() ) { git.next() ->saveWorkPackageXML( me, node->assignedResources( id ) ); } if ( node == 0 ) { return; } node->saveWorkPackageXML( me, id ); foreach ( ScheduleManager *sm, m_managerIdMap ) { if ( sm->scheduleId() == id ) { QDomElement el = me.ownerDocument().createElement( "schedules" ); me.appendChild( el ); sm->saveWorkPackageXML( el, *node ); break; } } } void Project::setParentSchedule( Schedule *sch ) { QListIterator it = m_nodes; while ( it.hasNext() ) { it.next() ->setParentSchedule( sch ); } } void Project::addResourceGroup( ResourceGroup *group, int index ) { int i = index == -1 ? m_resourceGroups.count() : index; emit resourceGroupToBeAdded( group, i ); m_resourceGroups.insert( i, group ); setResourceGroupId( group ); group->setProject( this ); foreach ( Resource *r, group->resources() ) { setResourceId( r ); r->setProject( this ); } emit resourceGroupAdded( group ); emit projectChanged(); } ResourceGroup *Project::takeResourceGroup( ResourceGroup *group ) { int i = m_resourceGroups.indexOf( group ); Q_ASSERT( i != -1 ); if ( i == -1 ) { return 0; } emit resourceGroupToBeRemoved( group ); ResourceGroup *g = m_resourceGroups.takeAt( i ); Q_ASSERT( group == g ); g->setProject( 0 ); removeResourceGroupId( g->id() ); foreach ( Resource *r, g->resources() ) { r->setProject( 0 ); removeResourceId( r->id() ); } emit resourceGroupRemoved( g ); emit projectChanged(); return g; } QList &Project::resourceGroups() { return m_resourceGroups; } void Project::addResource( ResourceGroup *group, Resource *resource, int index ) { int i = index == -1 ? group->numResources() : index; emit resourceToBeAdded( group, i ); group->addResource( i, resource, 0 ); setResourceId( resource ); emit resourceAdded( resource ); emit projectChanged(); } Resource *Project::takeResource( ResourceGroup *group, Resource *resource ) { emit resourceToBeRemoved( resource ); bool result = removeResourceId( resource->id() ); Q_ASSERT( result == true ); if (!result) { warnPlan << "Could not remove resource with id" << resource->id(); } resource->removeRequests(); // not valid anymore Resource *r = group->takeResource( resource ); Q_ASSERT( resource == r ); if (resource != r) { warnPlan << "Could not take resource from group"; } emit resourceRemoved( resource ); emit projectChanged(); return r; } void Project::moveResource( ResourceGroup *group, Resource *resource ) { if ( group == resource->parentGroup() ) { return; } takeResource( resource->parentGroup(), resource ); addResource( group, resource ); return; } QMap< QString, QString > Project::externalProjects() const { QMap< QString, QString > map; foreach ( Resource *r, resourceList() ) { for( QMapIterator it( r->externalProjects() ); it.hasNext(); ) { it.next(); if ( ! map.contains( it.key() ) ) { map[ it.key() ] = it.value(); } } } return map; } bool Project::addTask( Node* task, Node* position ) { // we want to add a task at the given position. => the new node will // become next sibling right after position. if ( 0 == position ) { return addSubTask( task, this ); } //debugPlan<<"Add"<name()<<" after"<name(); // in case we want to add to the main project, we make it child element // of the root element. if ( Node::Type_Project == position->type() ) { return addSubTask( task, position ); } // find the position // we have to tell the parent that we want to delete one of its children Node* parentNode = position->parentNode(); if ( !parentNode ) { debugPlan <<"parent node not found???"; return false; } int index = parentNode->findChildNode( position ); if ( -1 == index ) { // ok, it does not exist debugPlan <<"Task not found???"; return false; } return addSubTask( task, index + 1, parentNode ); } bool Project::addSubTask( Node* task, Node* parent ) { // append task to parent return addSubTask( task, -1, parent ); } bool Project::addSubTask( Node* task, int index, Node* parent, bool emitSignal ) { // we want to add a subtask to the node "parent" at the given index. // If parent is 0, add to this Node *p = parent; if ( 0 == p ) { p = this; } if ( !registerNodeId( task ) ) { errorPlan << "Failed to register node id, can not add subtask: " << task->name(); return false; } int i = index == -1 ? p->numChildren() : index; if ( emitSignal ) emit nodeToBeAdded( p, i ); p->insertChildNode( i, task ); - connect( this, SIGNAL(standardWorktimeChanged(KPlato::StandardWorktime*)), task, SLOT(slotStandardWorktimeChanged(KPlato::StandardWorktime*)) ); + connect( this, &Project::standardWorktimeChanged, task, &Node::slotStandardWorktimeChanged ); if ( emitSignal ) { emit nodeAdded( task ); emit projectChanged(); if ( p != this && p->numChildren() == 1 ) { emit nodeChanged( p ); } } return true; } void Project::takeTask( Node *node, bool emitSignal ) { //debugPlan<name(); Node * parent = node->parentNode(); if ( parent == 0 ) { debugPlan <<"Node must have a parent!"; return; } removeId( node->id() ); if ( emitSignal ) emit nodeToBeRemoved( node ); - disconnect( this, SIGNAL(standardWorktimeChanged(KPlato::StandardWorktime*)), node, SLOT(slotStandardWorktimeChanged(KPlato::StandardWorktime*)) ); + disconnect( this, &Project::standardWorktimeChanged, node, &Node::slotStandardWorktimeChanged ); parent->takeChildNode( node ); if ( emitSignal ) { emit nodeRemoved( node ); emit projectChanged(); if ( parent != this && parent->type() != Node::Type_Summarytask ) { emit nodeChanged( parent ); } } } bool Project::canMoveTask( Node* node, Node *newParent ) { //debugPlan<name()<<" to"<name(); if ( node == this ) { return false; } Node *p = newParent; while ( p && p != this ) { if ( ! node->canMoveTo( p ) ) { return false; } p = p->parentNode(); } return true; } bool Project::moveTask( Node* node, Node *newParent, int newPos ) { //debugPlan<name()<<" to"<name()<<","<parentNode(); int oldPos = oldParent->indexOf( node ); int i = newPos < 0 ? newParent->numChildren() : newPos; if ( oldParent == newParent && i == oldPos ) { // no need to move to where it already is return false; } int newRow = i; if ( oldParent == newParent && newPos > oldPos ) { ++newRow; // itemmodels wants new row *before* node is removed from old position } debugPlan<name()<<"at"<indexOf( node )<<"to"<name()<numChildren() == 0 ) { emit nodeChanged( oldParent ); } if ( newParent != this && newParent->numChildren() == 1 ) { emit nodeChanged( newParent ); } return true; } bool Project::canIndentTask( Node* node ) { if ( 0 == node ) { // should always be != 0. At least we would get the Project, // but you never know who might change that, so better be careful return false; } if ( node->type() == Node::Type_Project ) { //debugPlan<<"The root node cannot be indented"; return false; } // we have to find the parent of task to manipulate its list of children Node* parentNode = node->parentNode(); if ( !parentNode ) { return false; } if ( parentNode->findChildNode( node ) == -1 ) { errorPlan << "Tasknot found???"; return false; } Node *sib = node->siblingBefore(); if ( !sib ) { //debugPlan<<"new parent node not found"; return false; } if ( node->findParentRelation( sib ) || node->findChildRelation( sib ) ) { //debugPlan<<"Cannot have relations to parent"; return false; } return true; } bool Project::indentTask( Node* node, int index ) { if ( canIndentTask( node ) ) { Node * newParent = node->siblingBefore(); int i = index == -1 ? newParent->numChildren() : index; moveTask( node, newParent, i ); //debugPlan; return true; } return false; } bool Project::canUnindentTask( Node* node ) { if ( 0 == node ) { // is always != 0. At least we would get the Project, but you // never know who might change that, so better be careful return false; } if ( Node::Type_Project == node->type() ) { //debugPlan<<"The root node cannot be unindented"; return false; } // we have to find the parent of task to manipulate its list of children // and we need the parent's parent too Node* parentNode = node->parentNode(); if ( !parentNode ) { return false; } Node* grandParentNode = parentNode->parentNode(); if ( !grandParentNode ) { //debugPlan<<"This node already is at the top level"; return false; } int index = parentNode->findChildNode( node ); if ( -1 == index ) { errorPlan << "Tasknot found???"; return false; } return true; } bool Project::unindentTask( Node* node ) { if ( canUnindentTask( node ) ) { Node * parentNode = node->parentNode(); Node *grandParentNode = parentNode->parentNode(); int i = grandParentNode->indexOf( parentNode ) + 1; if ( i == 0 ) { i = grandParentNode->numChildren(); } moveTask( node, grandParentNode, i ); //debugPlan; return true; } return false; } bool Project::canMoveTaskUp( Node* node ) { if ( node == 0 ) return false; // safety // we have to find the parent of task to manipulate its list of children Node* parentNode = node->parentNode(); if ( !parentNode ) { //debugPlan<<"No parent found"; return false; } if ( parentNode->findChildNode( node ) == -1 ) { errorPlan << "Tasknot found???"; return false; } if ( node->siblingBefore() ) { return true; } return false; } bool Project::moveTaskUp( Node* node ) { if ( canMoveTaskUp( node ) ) { moveTask( node, node->parentNode(), node->parentNode()->indexOf( node ) - 1 ); return true; } return false; } bool Project::canMoveTaskDown( Node* node ) { if ( node == 0 ) return false; // safety // we have to find the parent of task to manipulate its list of children Node* parentNode = node->parentNode(); if ( !parentNode ) { return false; } if ( parentNode->findChildNode( node ) == -1 ) { errorPlan << "Tasknot found???"; return false; } if ( node->siblingAfter() ) { return true; } return false; } bool Project::moveTaskDown( Node* node ) { if ( canMoveTaskDown( node ) ) { moveTask( node, node->parentNode(), node->parentNode()->indexOf( node ) + 1 ); return true; } return false; } Task *Project::createTask() { Task * node = new Task(); node->setId( uniqueNodeId() ); reserveId( node->id(), node ); return node; } Task *Project::createTask( const Task &def ) { Task * node = new Task( def ); node->setId( uniqueNodeId() ); reserveId( node->id(), node ); return node; } Node *Project::findNode( const QString &id ) const { if ( m_parent == 0 ) { if ( nodeIdDict.contains( id ) ) { return nodeIdDict[ id ]; } return 0; } return m_parent->findNode( id ); } bool Project::nodeIdentExists( const QString &id ) const { return nodeIdDict.contains( id ) || nodeIdReserved.contains( id ); } QString Project::uniqueNodeId( int seed ) const { Q_UNUSED(seed); QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString ident = s + KRandom::randomString( 10 ); // int i = seed; while ( nodeIdentExists( ident ) ) { ident = s + KRandom::randomString( 10 ); } return ident; } QString Project::uniqueNodeId( const QList &existingIds, int seed ) { QString id = uniqueNodeId( seed ); while ( existingIds.contains( id ) ) { id = uniqueNodeId( seed ); } return id; } bool Project::removeId( const QString &id ) { //debugPlan <<"id=" << id; if ( m_parent ) { return m_parent->removeId( id ); } //debugPlan << "id=" << id<< nodeIdDict.contains(id); return nodeIdDict.remove( id ); } void Project::reserveId( const QString &id, Node *node ) { //debugPlan <<"id=" << id << node->name(); nodeIdReserved.insert( id, node ); } bool Project::registerNodeId( Node *node ) { nodeIdReserved.remove( node->id() ); if ( node->id().isEmpty() ) { warnPlan << "Node id is empty, cannot register it"; return false; } Node *rn = findNode( node->id() ); if ( rn == 0 ) { //debugPlan <<"id=" << node->id() << node->name(); nodeIdDict.insert( node->id(), node ); return true; } if ( rn != node ) { errorPlan << "Id already exists for different task: " << node->id(); return false; } //debugPlan<<"Already exists" <<"id=" << node->id() << node->name(); return true; } QList Project::allNodes() const { QList lst = nodeIdDict.values(); int me = lst.indexOf( const_cast( this ) ); if ( me != -1 ) { lst.removeAt( me ); } return lst; } QList Project::allTasks( const Node *parent ) const { QList lst; const Node *p = parent ? parent : this; foreach ( Node *n, p->childNodeIterator() ) { if ( n->type() == Node::Type_Task || n->type() == Type_Milestone ) { lst << static_cast( n ); } lst += allTasks( n ); } return lst; } bool Project::setResourceGroupId( ResourceGroup *group ) { if ( group == 0 ) { return false; } if ( ! group->id().isEmpty() ) { ResourceGroup *g = findResourceGroup( group->id() ); if ( group == g ) { return true; } else if ( g == 0 ) { insertResourceGroupId( group->id(), group ); return true; } } QString id = uniqueResourceGroupId(); group->setId( id ); if ( id.isEmpty() ) { return false; } insertResourceGroupId( id, group ); return true; } QString Project::uniqueResourceGroupId() const { QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString id = s + KRandom::randomString( 10 ); while ( resourceGroupIdDict.contains( id ) ) { id = s + KRandom::randomString( 10 ); } return id; } ResourceGroup *Project::group( const QString& id ) { return findResourceGroup( id ); } ResourceGroup *Project::groupByName( const QString& name ) const { foreach ( ResourceGroup *g, resourceGroupIdDict ) { if ( g->name() == name ) { return g; } } return 0; } QList Project::autoAllocateResources() const { QList lst; foreach ( Resource *r, resourceIdDict ) { if ( r->autoAllocate() ) { lst << r; } } return lst; } void Project::insertResourceId( const QString &id, Resource *resource ) { resourceIdDict.insert( id, resource ); } bool Project::removeResourceId( const QString &id ) { return resourceIdDict.remove( id ); } bool Project::setResourceId( Resource *resource ) { if ( resource == 0 ) { return false; } if ( ! resource->id().isEmpty() ) { Resource *r = findResource( resource->id() ); if ( resource == r ) { return true; } else if ( r == 0 ) { insertResourceId( resource->id(), resource ); return true; } } QString id = uniqueResourceId(); resource->setId( id ); if ( id.isEmpty() ) { return false; } insertResourceId( id, resource ); return true; } QString Project::uniqueResourceId() const { QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString id = s + KRandom::randomString( 10 ); while ( resourceIdDict.contains( id ) ) { id = s + KRandom::randomString( 10 ); } return id; } Resource *Project::resource( const QString& id ) { return findResource( id ); } Resource *Project::resourceByName( const QString& name ) const { QHash::const_iterator it; for (it = resourceIdDict.constBegin(); it != resourceIdDict.constEnd(); ++it) { Resource *r = it.value(); if ( r->name() == name ) { Q_ASSERT( it.key() == r->id() ); return r; } } return 0; } QStringList Project::resourceNameList() const { QStringList lst; foreach ( Resource *r, resourceIdDict ) { lst << r->name(); } return lst; } EffortCostMap Project::plannedEffortCostPrDay( QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->plannedEffortCostPrDay( start, end, id, typ ); } return ec; } EffortCostMap Project::plannedEffortCostPrDay( const Resource *resource, QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->plannedEffortCostPrDay( resource, start, end, id, typ ); } return ec; } EffortCostMap Project::actualEffortCostPrDay( QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->actualEffortCostPrDay( start, end, id, typ ); } return ec; } EffortCostMap Project::actualEffortCostPrDay( const Resource *resource, QDate start, QDate end, long id, EffortCostCalculationType typ ) const { //debugPlan< it( childNodeIterator() ); while ( it.hasNext() ) { ec += it.next() ->actualEffortCostPrDay( resource, start, end, id, typ ); } return ec; } // Returns the total planned effort for this project (or subproject) Duration Project::plannedEffort( long id, EffortCostCalculationType typ ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->plannedEffort( id, typ ); } return eff; } // Returns the total planned effort for this project (or subproject) on date Duration Project::plannedEffort( QDate date, long id, EffortCostCalculationType typ ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->plannedEffort( date, id, typ ); } return eff; } // Returns the total planned effort for this project (or subproject) upto and including date Duration Project::plannedEffortTo( QDate date, long id, EffortCostCalculationType typ ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->plannedEffortTo( date, id, typ ); } return eff; } // Returns the total actual effort for this project (or subproject) upto and including date Duration Project::actualEffortTo( QDate date ) const { //debugPlan; Duration eff; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { eff += it.next() ->actualEffortTo( date ); } return eff; } // Returns the total planned effort for this project (or subproject) upto and including date double Project::plannedCostTo( QDate date, long id, EffortCostCalculationType typ ) const { //debugPlan; double c = 0; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { c += it.next() ->plannedCostTo( date, id, typ ); } return c; } // Returns the total actual cost for this project (or subproject) upto and including date EffortCost Project::actualCostTo( long int id, QDate date ) const { //debugPlan; EffortCost c; QListIterator it( childNodeIterator() ); while ( it.hasNext() ) { c += it.next() ->actualCostTo( id, date ); } return c; } Duration Project::budgetedWorkPerformed( QDate date, long id ) const { //debugPlan; Duration e; foreach (Node *n, childNodeIterator()) { e += n->budgetedWorkPerformed( date, id ); } return e; } double Project::budgetedCostPerformed( QDate date, long id ) const { //debugPlan; double c = 0.0; foreach (Node *n, childNodeIterator()) { c += n->budgetedCostPerformed( date, id ); } return c; } double Project::effortPerformanceIndex( QDate date, long id ) const { //debugPlan; debugPlan< 0.0 ) { r = p / s; } debugPlan< date ? end : date), id ); double budgetAtCompletion; double plannedCompleted; double budgetedCompleted; bool useEffort = false; //FIXME if ( useEffort ) { budgetAtCompletion = plan.totalEffort().toDouble( Duration::Unit_h ); plannedCompleted = plan.effortTo( date ).toDouble( Duration::Unit_h ); //actualCompleted = actual.effortTo( date ).toDouble( Duration::Unit_h ); budgetedCompleted = budgetedWorkPerformed( date, id ).toDouble( Duration::Unit_h ); } else { budgetAtCompletion = plan.totalCost(); plannedCompleted = plan.costTo( date ); budgetedCompleted = budgetedCostPerformed( date, id ); } double c = 0.0; if ( budgetAtCompletion > 0.0 ) { double percentageCompletion = budgetedCompleted / budgetAtCompletion; c = budgetAtCompletion * percentageCompletion; //?? debugPlan<name()<<","<<(parent?parent->name():"No parent"); int row = parent == 0 ? m_calendars.count() : parent->calendars().count(); if ( index >= 0 && index < row ) { row = index; } emit calendarToBeAdded( parent, row ); calendar->setProject( this ); if ( parent == 0 ) { calendar->setParentCal( 0 ); // in case m_calendars.insert( row, calendar ); } else { calendar->setParentCal( parent, row ); } if ( calendar->isDefault() ) { setDefaultCalendar( calendar ); } setCalendarId( calendar ); emit calendarAdded( calendar ); emit projectChanged(); } void Project::takeCalendar( Calendar *calendar ) { emit calendarToBeRemoved( calendar ); removeCalendarId( calendar->id() ); if ( calendar == m_defaultCalendar ) { m_defaultCalendar = 0; } if ( calendar->parentCal() == 0 ) { int i = indexOf( calendar ); if ( i != -1 ) { m_calendars.removeAt( i ); } } else { calendar->setParentCal( 0 ); } emit calendarRemoved( calendar ); calendar->setProject( 0 ); emit projectChanged(); } int Project::indexOf( const Calendar *calendar ) const { return m_calendars.indexOf( const_cast(calendar) ); } Calendar *Project::calendar( const QString& id ) const { return findCalendar( id ); } Calendar *Project::calendarByName( const QString& name ) const { foreach( Calendar *c, calendarIdDict ) { if ( c->name() == name ) { return c; } } return 0; } const QList &Project::calendars() const { return m_calendars; } QList Project::allCalendars() const { return calendarIdDict.values(); } QStringList Project::calendarNames() const { QStringList lst; foreach( Calendar *c, calendarIdDict ) { lst << c->name(); } return lst; } bool Project::setCalendarId( Calendar *calendar ) { if ( calendar == 0 ) { return false; } if ( ! calendar->id().isEmpty() ) { Calendar *c = findCalendar( calendar->id() ); if ( calendar == c ) { return true; } else if ( c == 0 ) { insertCalendarId( calendar->id(), calendar ); return true; } } QString id = uniqueCalendarId(); calendar->setId( id ); if ( id.isEmpty() ) { return false; } insertCalendarId( id, calendar ); return true; } QString Project::uniqueCalendarId() const { QString s = QDateTime::currentDateTime().toString( Qt::ISODate ) + ' '; QString id = s + KRandom::randomString( 10 ); while ( calendarIdDict.contains( id ) ) { id = s + KRandom::randomString( 10 ); } return id; } void Project::setDefaultCalendar( Calendar *cal ) { if ( m_defaultCalendar ) { m_defaultCalendar->setDefault( false ); } m_defaultCalendar = cal; if ( cal ) { cal->setDefault( true ); } emit defaultCalendarChanged( cal ); emit projectChanged(); } void Project::setStandardWorktime( StandardWorktime * worktime ) { if ( m_standardWorktime != worktime ) { delete m_standardWorktime; m_standardWorktime = worktime; m_standardWorktime->setProject( this ); emit standardWorktimeChanged( worktime ); } } void Project::emitDocumentAdded( Node *node , Document *doc , int index ) { emit documentAdded( node, doc, index ); } void Project::emitDocumentRemoved( Node *node , Document *doc , int index ) { emit documentRemoved( node, doc, index ); } void Project::emitDocumentChanged( Node *node , Document *doc , int index ) { emit documentChanged( node, doc, index ); } bool Project::linkExists( const Node *par, const Node *child ) const { if ( par == 0 || child == 0 || par == child || par->isDependChildOf( child ) ) { return false; } foreach ( Relation *r, par->dependChildNodes() ) { if ( r->child() == child ) { return true; } } return false; } bool Project::legalToLink( const Node *par, const Node *child ) const { //debugPlan<isDependChildOf( child ) ) { return false; } if ( linkExists( par, child ) ) { return false; } bool legal = true; // see if par/child is related if ( legal && ( par->isParentOf( child ) || child->isParentOf( par ) ) ) { legal = false; } if ( legal ) legal = legalChildren( par, child ); if ( legal ) legal = legalParents( par, child ); if ( legal ) { foreach ( Node *p, par->childNodeIterator() ) { if ( ! legalToLink( p, child ) ) { return false; } } } return legal; } bool Project::legalParents( const Node *par, const Node *child ) const { bool legal = true; //debugPlan<name()<<" ("<numDependParentNodes()<<" parents)"<name()<<" ("<numDependChildNodes()<<" children)"; for ( int i = 0; i < par->numDependParentNodes() && legal; ++i ) { Node *pNode = par->getDependParentNode( i ) ->parent(); if ( child->isParentOf( pNode ) || pNode->isParentOf( child ) ) { //debugPlan<<"Found:"<name()<<" is related to"<name(); legal = false; } else { legal = legalChildren( pNode, child ); } if ( legal ) legal = legalParents( pNode, child ); } return legal; } bool Project::legalChildren( const Node *par, const Node *child ) const { bool legal = true; //debugPlan<name()<<" ("<numDependParentNodes()<<" parents)"<name()<<" ("<numDependChildNodes()<<" children)"; for ( int j = 0; j < child->numDependChildNodes() && legal; ++j ) { Node *cNode = child->getDependChildNode( j ) ->child(); if ( par->isParentOf( cNode ) || cNode->isParentOf( par ) ) { //debugPlan<<"Found:"<name()<<" is related to"<name(); legal = false; } else { legal = legalChildren( par, cNode ); } } return legal; } WBSDefinition &Project::wbsDefinition() { return m_wbsDefinition; } void Project::setWbsDefinition( const WBSDefinition &def ) { //debugPlan; m_wbsDefinition = def; emit wbsDefinitionChanged(); emit projectChanged(); } QString Project::generateWBSCode( QList &indexes, bool sortable ) const { QString code = m_wbsDefinition.projectCode(); if (sortable) { int fw = (nodeIdDict.count() / 10) + 1; QLatin1Char fc('0'); foreach ( int index, indexes ) { code += ".%1"; code = code.arg(QString::number(index), fw, fc); } debugPlan< hash = resourceIdDict; foreach ( Resource * r, hash ) { r->setCurrentSchedule( id ); } emit currentScheduleChanged(); emit projectChanged(); } ScheduleManager *Project::scheduleManager( long id ) const { foreach ( ScheduleManager *sm, m_managers ) { if ( sm->scheduleId() == id ) { return sm; } } return 0; } ScheduleManager *Project::scheduleManager( const QString &id ) const { return m_managerIdMap.value( id ); } ScheduleManager *Project::findScheduleManagerByName( const QString &name ) const { //debugPlan; ScheduleManager *m = 0; foreach( ScheduleManager *sm, m_managers ) { m = sm->findManager( name ); if ( m ) { break; } } return m; } QList Project::allScheduleManagers() const { QList lst; foreach ( ScheduleManager *sm, m_managers ) { lst << sm; lst << sm->allChildren(); } return lst; } QString Project::uniqueScheduleName() const { //debugPlan; QString n = i18n( "Plan" ); bool unique = findScheduleManagerByName( n ) == 0; if ( unique ) { return n; } n += " %1"; int i = 1; for ( ; true; ++i ) { unique = findScheduleManagerByName( n.arg( i ) ) == 0; if ( unique ) { break; } } return n.arg( i ); } void Project::addScheduleManager( ScheduleManager *sm, ScheduleManager *parent, int index ) { int row = parent == 0 ? m_managers.count() : parent->childCount(); if ( index >= 0 && index < row ) { row = index; } if ( parent == 0 ) { emit scheduleManagerToBeAdded( parent, row ); m_managers.insert( row, sm ); } else { emit scheduleManagerToBeAdded( parent, row ); sm->setParentManager( parent, row ); } if ( sm->managerId().isEmpty() ) { sm->setManagerId( uniqueScheduleManagerId() ); } Q_ASSERT( ! m_managerIdMap.contains( sm->managerId() ) ); m_managerIdMap.insert( sm->managerId(), sm ); emit scheduleManagerAdded( sm ); emit projectChanged(); //debugPlan<<"Added:"<name()<<", now"<children() ) { takeScheduleManager( s ); } if ( sm->scheduling() ) { sm->stopCalculation(); } int index = -1; if ( sm->parentManager() ) { int index = sm->parentManager()->indexOf( sm ); if ( index >= 0 ) { emit scheduleManagerToBeRemoved( sm ); sm->setParentManager( 0 ); m_managerIdMap.remove( sm->managerId() ); emit scheduleManagerRemoved( sm ); emit projectChanged(); } } else { index = indexOf( sm ); if ( index >= 0 ) { emit scheduleManagerToBeRemoved( sm ); m_managers.removeAt( indexOf( sm ) ); m_managerIdMap.remove( sm->managerId() ); emit scheduleManagerRemoved( sm ); emit projectChanged(); } } return index; } void Project::moveScheduleManager( ScheduleManager *sm, ScheduleManager *newparent, int newindex ) { //debugPlan<name()<parentManager() ) { m_managers.removeAt( indexOf( sm ) ); } sm->setParentManager( newparent, newindex ); if ( ! newparent ) { m_managers.insert( newindex, sm ); } emit scheduleManagerMoved( sm, newindex ); } bool Project::isScheduleManager( void *ptr ) const { const ScheduleManager *sm = static_cast( ptr ); if ( indexOf( sm ) >= 0 ) { return true; } foreach ( ScheduleManager *p, m_managers ) { if ( p->isParentOf( sm ) ) { return true; } } return false; } ScheduleManager *Project::createScheduleManager( const QString &name ) { //debugPlan<isBaselined() ) { return true; } } return false; } Schedule *s = schedule( id ); return s == 0 ? false : s->isBaselined(); } MainSchedule *Project::createSchedule( const QString& name, Schedule::Type type ) { //debugPlan<<"No of schedules:"<setName( name ); sch->setType( type ); addMainSchedule( sch ); return sch; } void Project::addMainSchedule( MainSchedule *sch ) { if ( sch == 0 ) { return; } //debugPlan<<"No of schedules:"<setId( i ); sch->setNode( this ); addSchedule( sch ); } bool Project::removeCalendarId( const QString &id ) { //debugPlan <<"id=" << id; return calendarIdDict.remove( id ); } void Project::insertCalendarId( const QString &id, Calendar *calendar ) { //debugPlan <<"id=" << id <<":" << calendar->name(); calendarIdDict.insert( id, calendar ); } void Project::changed( Node *node, int property ) { if ( m_parent == 0 ) { Node::changed( node, property ); // reset cache if ( property != Node::Type ) { // add/remove node is handled elsewhere emit nodeChanged( node ); emit projectChanged(); } return; } Node::changed( node, property ); } void Project::changed( ResourceGroup *group ) { //debugPlan; emit resourceGroupChanged( group ); emit projectChanged(); } void Project::changed( ScheduleManager *sm ) { emit scheduleManagerChanged( sm ); emit projectChanged(); } void Project::changed( MainSchedule *sch ) { //debugPlan<id(); emit scheduleChanged( sch ); emit projectChanged(); } void Project::sendScheduleToBeAdded( const ScheduleManager *sm, int row ) { emit scheduleToBeAdded( sm, row ); } void Project::sendScheduleAdded( const MainSchedule *sch ) { //debugPlan<id(); emit scheduleAdded( sch ); emit projectChanged(); } void Project::sendScheduleToBeRemoved( const MainSchedule *sch ) { //debugPlan<id(); emit scheduleToBeRemoved( sch ); } void Project::sendScheduleRemoved( const MainSchedule *sch ) { //debugPlan<id(); emit scheduleRemoved( sch ); emit projectChanged(); } void Project::changed( Resource *resource ) { emit resourceChanged( resource ); emit projectChanged(); } void Project::changed( Calendar *cal ) { emit calendarChanged( cal ); emit projectChanged(); } void Project::changed( StandardWorktime *w ) { emit standardWorktimeChanged( w ); emit projectChanged(); } bool Project::addRelation( Relation *rel, bool check ) { if ( rel->parent() == 0 || rel->child() == 0 ) { return false; } if ( check && !legalToLink( rel->parent(), rel->child() ) ) { return false; } emit relationToBeAdded( rel, rel->parent()->numDependChildNodes(), rel->child()->numDependParentNodes() ); rel->parent()->addDependChildNode( rel ); rel->child()->addDependParentNode( rel ); emit relationAdded( rel ); emit projectChanged(); return true; } void Project::takeRelation( Relation *rel ) { emit relationToBeRemoved( rel ); rel->parent() ->takeDependChildNode( rel ); rel->child() ->takeDependParentNode( rel ); emit relationRemoved( rel ); emit projectChanged(); } void Project::setRelationType( Relation *rel, Relation::Type type ) { emit relationToBeModified( rel ); rel->setType( type ); emit relationModified( rel ); emit projectChanged(); } void Project::setRelationLag( Relation *rel, const Duration &lag ) { emit relationToBeModified( rel ); rel->setLag( lag ); emit relationModified( rel ); emit projectChanged(); } QList Project::flatNodeList( Node *parent ) { QList lst; Node *p = parent == 0 ? this : parent; //debugPlan<name()<childNodeIterator() ) { lst.append( n ); if ( n->numChildren() > 0 ) { lst += flatNodeList( n ); } } return lst; } void Project::setSchedulerPlugins( const QMap &plugins ) { m_schedulerPlugins = plugins; debugPlan< 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 "kptschedulerplugin.h" #include "kptproject.h" #include "kptschedule.h" #include "kptxmlloaderobject.h" #include "kptdebug.h" #include "KoXmlReader.h" namespace KPlato { class Q_DECL_HIDDEN SchedulerPlugin::Private { public: Private() {} QString name; QString comment; }; SchedulerPlugin::SchedulerPlugin(QObject *parent) : QObject(parent), d( new SchedulerPlugin::Private() ), m_granularity( 0 ) { // register Schedule::Log so it can be used in queued connections qRegisterMetaType("Schedule::Log"); m_synctimer.setInterval( 500 ); - connect(&m_synctimer, SIGNAL(timeout()), SLOT(slotSyncData())); + connect(&m_synctimer, &QTimer::timeout, this, &SchedulerPlugin::slotSyncData); } SchedulerPlugin::~SchedulerPlugin() { foreach ( SchedulerThread *s, m_jobs ) { s->haltScheduling(); } delete d; } void SchedulerPlugin::setName( const QString &name ) { d->name = name; } QString SchedulerPlugin::name() const { return d->name; } void SchedulerPlugin::setComment( const QString &comment ) { d->comment = comment; } QString SchedulerPlugin::comment() const { return d->comment; } int SchedulerPlugin::capabilities() const { return AvoidOverbooking | AllowOverbooking | ScheduleForward | ScheduleBackward; } void SchedulerPlugin::stopCalculation( ScheduleManager *sm ) { foreach ( SchedulerThread *j, m_jobs ) { if ( sm == j->mainManager() ) { j->stopScheduling(); } } } void SchedulerPlugin::haltCalculation( ScheduleManager *sm ) { debugPlan<<"SchedulerPlugin::haltCalculation:"<mainManager() ) { haltCalculation( j ); break; } } sm->setCalculationResult( ScheduleManager::CalculationCanceled ); sm->setScheduling( false ); } void SchedulerPlugin::stopCalculation( SchedulerThread *job ) { job->stopScheduling(); } void SchedulerPlugin::haltCalculation( SchedulerThread *job ) { debugPlan<<"SchedulerPlugin::haltCalculation:"<haltScheduling(); if ( m_jobs.contains( job ) ) { debugPlan<<"SchedulerPlugin::haltCalculation: remove"< SchedulerPlugin::granularities() const { return m_granularities; } int SchedulerPlugin::granularity() const { return m_granularity; } void SchedulerPlugin::setGranularity( int index ) { m_granularity = qMin( index, m_granularities.count() - 1 ); } void SchedulerPlugin::slotSyncData() { updateProgress(); updateLog(); } void SchedulerPlugin::updateProgress() { foreach ( SchedulerThread *j, m_jobs ) { ScheduleManager *sm = j->mainManager(); if ( sm->maxProgress() != j->maxProgress() ) { sm->setMaxProgress( j->maxProgress() ); } sm->setProgress( j->progress() ); } } void SchedulerPlugin::updateLog() { foreach ( SchedulerThread *j, m_jobs ) { updateLog( j ); } } void SchedulerPlugin::updateLog( SchedulerThread *j ) { ScheduleManager *sm = j->mainManager(); Project *p = j->mainProject(); Q_ASSERT( p == &(sm->project()) ); #ifdef NDEBUG Q_UNUSED(p) #endif if ( j->manager() ) { sm->setPhaseNames( j->phaseNames() ); } QVector logs = j->takeLog(); QMutableVectorIterator i(logs); while (i.hasNext()) { Schedule::Log &l = i.next(); // map log from temporary project to real project if ( l.resource ) { const Resource *r = l.resource; l.resource = sm->project().findResource( l.resource->id() ); Q_ASSERT( r != l.resource ); #ifdef NDEBUG Q_UNUSED(r) #endif Q_ASSERT( l.resource->project() == p ); } if ( l.node ) { const Node *n = l.node; if ( l.node->type() == Node::Type_Project ) { l.node = &( sm->project() ); } else { l.node = sm->project().findNode( l.node->id() ); } Q_ASSERT( n != l.node ); #ifdef NDEBUG Q_UNUSED(n) #endif Q_ASSERT( l.node->projectNode() == p ); } } if ( ! logs.isEmpty() ) { sm->slotAddLog( logs ); } } void SchedulerPlugin::updateProject( const Project *tp, const ScheduleManager *tm, Project *mp, ScheduleManager *sm ) const { Q_CHECK_PTR( tp ); Q_CHECK_PTR( tm ); Q_CHECK_PTR( mp ); Q_CHECK_PTR( sm ); //debugPlan<<"SchedulerPlugin::updateProject:"<name()<<"->"<name()<scheduleId(); Q_ASSERT( sid == sm->scheduleId() ); XMLLoaderObject status; status.setVersion( PLAN_FILE_SYNTAX_VERSION ); status.setProject( mp ); status.setProjectTimeZone( mp->timeZone() ); foreach ( const Node *tn, tp->allNodes() ) { Node *mn = mp->findNode( tn->id() ); Q_ASSERT( mn ); if ( mn ) { updateNode( tn, mn, sid, status ); } } foreach ( const Resource *tr, tp->resourceList() ) { Resource *r = mp->findResource( tr->id() ); Q_ASSERT( r ); if ( r ) { updateResource( tr, r, status ); } } // update main schedule and appointments updateAppointments( tp, tm, mp, sm, status ); sm->scheduleChanged( sm->expected() ); } void SchedulerPlugin::updateNode( const Node *tn, Node *mn, long sid, XMLLoaderObject &status ) const { //debugPlan<<"SchedulerPlugin::updateNode:"<name()<<"->"<name(); NodeSchedule *s = static_cast( tn->schedule( sid ) ); if ( s == 0 ) { warnPlan<<"SchedulerPlugin::updateNode:"<<"Task:"<name()<<"could not find schedule with id:"<saveXML( e ); Q_ASSERT( ! mn->findSchedule( sid ) ); s = static_cast( mn->schedule( sid ) ); Q_ASSERT( s == 0 ); s = new NodeSchedule(); KoXmlDocument xd; xd.setContent( doc.toString() ); KoXmlElement se = xd.documentElement().namedItem( "schedule" ).toElement(); Q_ASSERT( ! se.isNull() ); s->loadXML( se, status ); s->setDeleted( false ); s->setNode( mn ); mn->addSchedule( s ); } void SchedulerPlugin::updateResource( const Resource *tr, Resource *r, XMLLoaderObject &status ) const { QDomDocument doc( "tmp" ); QDomElement e = doc.createElement( "cache" ); doc.appendChild( e ); tr->saveCalendarIntervalsCache( e ); KoXmlDocument xd; QString err; xd.setContent( doc.toString(), &err ); KoXmlElement se = xd.documentElement(); Q_ASSERT( ! se.isNull() ); r->loadCalendarIntervalsCache( se, status ); Calendar *cr = tr->calendar(); Calendar *c = r->calendar(); if ( cr == 0 || c == 0 ) { return; } debugPlan<<"cr:"<cacheVersion()<<"c"<cacheVersion(); c->setCacheVersion( cr->cacheVersion() ); } void SchedulerPlugin::updateAppointments( const Project *tp, const ScheduleManager *tm, Project *mp, ScheduleManager *sm, XMLLoaderObject &status ) const { MainSchedule *sch = tm->expected(); Q_ASSERT( sch ); Q_ASSERT( sch != sm->expected() ); Q_ASSERT( sch->id() == sm->expected()->id() ); QDomDocument doc( "tmp" ); QDomElement e = doc.createElement( "schedule" ); doc.appendChild( e ); sch->saveXML( e ); tp->saveAppointments( e, sch->id() ); KoXmlDocument xd; xd.setContent( doc.toString() ); KoXmlElement se = xd.namedItem( "schedule" ).toElement(); Q_ASSERT( ! se.isNull() ); bool ret = sm->loadMainSchedule( sm->expected(), se, status ); // also loads appointments Q_ASSERT( ret ); #ifdef NDEBUG Q_UNUSED(ret) #endif mp->setCurrentSchedule( sch->id() ); sm->expected()->setPhaseNames( sch->phaseNames() ); mp->changed( sm ); } //---------------------- SchedulerThread::SchedulerThread( Project *project, ScheduleManager *manager, QObject *parent ) : QThread( parent ), m_mainproject( project ), m_mainmanager( manager ), m_mainmanagerId( manager->managerId() ), m_project( 0 ), m_manager( 0 ), m_stopScheduling(false ), m_haltScheduling( false ), m_progress( 0 ) { manager->createSchedules(); // creates expected() to get log messages during calculation QDomDocument document( "kplato" ); saveProject( project, document ); m_pdoc.setContent( document.toString() ); - connect( this, SIGNAL(started()), this, SLOT(slotStarted())); - connect( this, SIGNAL(finished()), this, SLOT(slotFinished())); + connect( this, &QThread::started, this, &SchedulerThread::slotStarted); + connect( this, &QThread::finished, this, &SchedulerThread::slotFinished); } SchedulerThread::~SchedulerThread() { debugPlan<<"SchedulerThread::~SchedulerThread:"< SchedulerThread::takeLog() { QMutexLocker m( &m_logMutex ); const QVector l = m_logs; m_logs.clear(); return l; } QMap SchedulerThread::phaseNames() const { QMutexLocker m( &m_managerMutex ); return m_manager->phaseNames(); } void SchedulerThread::slotStarted() { emit jobStarted( this ); } void SchedulerThread::slotFinished() { if ( m_haltScheduling ) { deleteLater(); } else { emit jobFinished( this ); } } void SchedulerThread::doRun() { slotStarted(); run(); slotFinished(); } ScheduleManager *SchedulerThread::manager() const { QMutexLocker m( &m_managerMutex ); return m_manager; } Project *SchedulerThread::project() const { QMutexLocker m( &m_projectMutex ); return m_project; } void SchedulerThread::stopScheduling() { debugPlan<<"SchedulerThread::stopScheduling:"; m_stopScheduling = true; } void SchedulerThread::haltScheduling() { debugPlan<<"SchedulerThread::haltScheduling:"; m_haltScheduling = true; } void SchedulerThread::logError( Node *n, Resource *r, const QString &msg, int phase ) { Schedule::Log log; if ( r == 0 ) { log = Schedule::Log( n, Schedule::Log::Type_Error, msg, phase ); } else { log = Schedule::Log( n, r, Schedule::Log::Type_Error, msg, phase ); } slotAddLog( log ); } void SchedulerThread::logWarning( Node *n, Resource *r, const QString &msg, int phase ) { Schedule::Log log; if ( r == 0 ) { log = Schedule::Log( n, Schedule::Log::Type_Warning, msg, phase ); } else { log = Schedule::Log( n, r, Schedule::Log::Type_Warning, msg, phase ); } slotAddLog( log ); } void SchedulerThread::logInfo( Node *n, Resource *r, const QString &msg, int phase ) { Schedule::Log log; if ( r == 0 ) { log = Schedule::Log( n, Schedule::Log::Type_Info, msg, phase ); } else { log = Schedule::Log( n, r, Schedule::Log::Type_Info, msg, phase ); } slotAddLog( log ); } void SchedulerThread::logDebug( Node *n, Resource *r, const QString &msg, int phase ) { Schedule::Log log; if ( r == 0 ) { log = Schedule::Log( n, Schedule::Log::Type_Debug, msg, phase ); } else { log = Schedule::Log( n, r, Schedule::Log::Type_Debug, msg, phase ); } slotAddLog( log ); } //static void SchedulerThread::saveProject( Project *project, QDomDocument &document ) { document.appendChild( document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) ); QDomElement doc = document.createElement( "kplato" ); doc.setAttribute( "editor", "Plan" ); doc.setAttribute( "mime", "application/x-vnd.kde.plan" ); doc.setAttribute( "version", PLAN_FILE_SYNTAX_VERSION ); document.appendChild( doc ); project->save( doc ); } //static bool SchedulerThread::loadProject( Project *project, const KoXmlDocument &doc ) { KoXmlElement pel = doc.documentElement().namedItem( "project" ).toElement(); if ( pel.isNull() ) { return false; } XMLLoaderObject status; status.setVersion( PLAN_FILE_SYNTAX_VERSION ); status.setProject( project ); return project->load( pel, status ); } } //namespace KPlato diff --git a/src/libs/kundo2/kundo2group.cpp b/src/libs/kundo2/kundo2group.cpp index 648a4d3a..0d9fbdbd 100644 --- a/src/libs/kundo2/kundo2group.cpp +++ b/src/libs/kundo2/kundo2group.cpp @@ -1,469 +1,469 @@ /**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "kundo2group.h" #include "kundo2stack.h" #include "kundo2stack_p.h" #include #ifndef QT_NO_UNDOGROUP /*! \class KUndo2Group \brief The KUndo2Group class is a group of KUndo2QStack objects. \since 4.2 For an overview of the Qt's undo framework, see the \link qundo.html overview\endlink. An application often has multiple undo stacks, one for each opened document. At the same time, an application usually has one undo action and one redo action, which triggers undo or redo in the active document. KUndo2Group is a group of KUndo2QStack objects, one of which may be active. It has an undo() and redo() slot, which calls KUndo2QStack::undo() and KUndo2QStack::redo() for the active stack. It also has the functions createUndoAction() and createRedoAction(). The actions returned by these functions behave in the same way as those returned by KUndo2QStack::createUndoAction() and KUndo2QStack::createRedoAction() of the active stack. Stacks are added to a group with addStack() and removed with removeStack(). A stack is implicitly added to a group when it is created with the group as its parent QObject. It is the programmer's responsibility to specify which stack is active by calling KUndo2QStack::setActive(), usually when the associated document window receives focus. The active stack may also be set with setActiveStack(), and is returned by activeStack(). When a stack is added to a group using addStack(), the group does not take ownership of the stack. This means the stack has to be deleted separately from the group. When a stack is deleted, it is automatically removed from a group. A stack may belong to only one group. Adding it to another group will cause it to be removed from the previous group. A KUndo2Group is also useful in conjunction with KUndo2View. If a KUndo2View is set to watch a group using KUndo2View::setGroup(), it will update itself to display the active stack. */ /*! Creates an empty KUndo2Group object with parent \a parent. \sa addStack() */ KUndo2Group::KUndo2Group(QObject *parent) : QObject(parent), m_active(0) { } /*! Destroys the KUndo2Group. */ KUndo2Group::~KUndo2Group() { // Ensure all KUndo2Stacks no longer refer to this group. QList::iterator it = m_stack_list.begin(); QList::iterator end = m_stack_list.end(); while (it != end) { (*it)->m_group = 0; ++it; } } /*! Adds \a stack to this group. The group does not take ownership of the stack. Another way of adding a stack to a group is by specifying the group as the stack's parent QObject in KUndo2QStack::KUndo2QStack(). In this case, the stack is deleted when the group is deleted, in the usual manner of QObjects. \sa removeStack() stacks() KUndo2QStack::KUndo2QStack() */ void KUndo2Group::addStack(KUndo2QStack *stack) { if (m_stack_list.contains(stack)) return; m_stack_list.append(stack); if (KUndo2Group *other = stack->m_group) other->removeStack(stack); stack->m_group = this; } /*! Removes \a stack from this group. If the stack was the active stack in the group, the active stack becomes 0. \sa addStack() stacks() KUndo2QStack::~KUndo2QStack() */ void KUndo2Group::removeStack(KUndo2QStack *stack) { if (m_stack_list.removeAll(stack) == 0) return; if (stack == m_active) setActiveStack(0); stack->m_group = 0; } /*! Returns a list of stacks in this group. \sa addStack() removeStack() */ QList KUndo2Group::stacks() const { return m_stack_list; } /*! Sets the active stack of this group to \a stack. If the stack is not a member of this group, this function does nothing. Synonymous with calling KUndo2QStack::setActive() on \a stack. The actions returned by createUndoAction() and createRedoAction() will now behave in the same way as those returned by \a stack's KUndo2QStack::createUndoAction() and KUndo2QStack::createRedoAction(). \sa KUndo2QStack::setActive() activeStack() */ void KUndo2Group::setActiveStack(KUndo2QStack *stack) { if (m_active == stack) return; if (m_active != 0) { - disconnect(m_active, SIGNAL(canUndoChanged(bool)), - this, SIGNAL(canUndoChanged(bool))); - disconnect(m_active, SIGNAL(undoTextChanged(QString)), - this, SIGNAL(undoTextChanged(QString))); - disconnect(m_active, SIGNAL(canRedoChanged(bool)), - this, SIGNAL(canRedoChanged(bool))); - disconnect(m_active, SIGNAL(redoTextChanged(QString)), - this, SIGNAL(redoTextChanged(QString))); - disconnect(m_active, SIGNAL(indexChanged(int)), - this, SIGNAL(indexChanged(int))); - disconnect(m_active, SIGNAL(cleanChanged(bool)), - this, SIGNAL(cleanChanged(bool))); + disconnect(m_active, &KUndo2QStack::canUndoChanged, + this, &KUndo2Group::canUndoChanged); + disconnect(m_active, &KUndo2QStack::undoTextChanged, + this, &KUndo2Group::undoTextChanged); + disconnect(m_active, &KUndo2QStack::canRedoChanged, + this, &KUndo2Group::canRedoChanged); + disconnect(m_active, &KUndo2QStack::redoTextChanged, + this, &KUndo2Group::redoTextChanged); + disconnect(m_active, &KUndo2QStack::indexChanged, + this, &KUndo2Group::indexChanged); + disconnect(m_active, &KUndo2QStack::cleanChanged, + this, &KUndo2Group::cleanChanged); } m_active = stack; if (m_active == 0) { emit canUndoChanged(false); emit undoTextChanged(QString()); emit canRedoChanged(false); emit redoTextChanged(QString()); emit cleanChanged(true); emit indexChanged(0); } else { - connect(m_active, SIGNAL(canUndoChanged(bool)), - this, SIGNAL(canUndoChanged(bool))); - connect(m_active, SIGNAL(undoTextChanged(QString)), - this, SIGNAL(undoTextChanged(QString))); - connect(m_active, SIGNAL(canRedoChanged(bool)), - this, SIGNAL(canRedoChanged(bool))); - connect(m_active, SIGNAL(redoTextChanged(QString)), - this, SIGNAL(redoTextChanged(QString))); - connect(m_active, SIGNAL(indexChanged(int)), - this, SIGNAL(indexChanged(int))); - connect(m_active, SIGNAL(cleanChanged(bool)), - this, SIGNAL(cleanChanged(bool))); + connect(m_active, &KUndo2QStack::canUndoChanged, + this, &KUndo2Group::canUndoChanged); + connect(m_active, &KUndo2QStack::undoTextChanged, + this, &KUndo2Group::undoTextChanged); + connect(m_active, &KUndo2QStack::canRedoChanged, + this, &KUndo2Group::canRedoChanged); + connect(m_active, &KUndo2QStack::redoTextChanged, + this, &KUndo2Group::redoTextChanged); + connect(m_active, &KUndo2QStack::indexChanged, + this, &KUndo2Group::indexChanged); + connect(m_active, &KUndo2QStack::cleanChanged, + this, &KUndo2Group::cleanChanged); emit canUndoChanged(m_active->canUndo()); emit undoTextChanged(m_active->undoText()); emit canRedoChanged(m_active->canRedo()); emit redoTextChanged(m_active->redoText()); emit cleanChanged(m_active->isClean()); emit indexChanged(m_active->index()); } emit activeStackChanged(m_active); } /*! Returns the active stack of this group. If none of the stacks are active, or if the group is empty, this function returns 0. \sa setActiveStack() KUndo2QStack::setActive() */ KUndo2QStack *KUndo2Group::activeStack() const { return m_active; } /*! Calls KUndo2QStack::undo() on the active stack. If none of the stacks are active, or if the group is empty, this function does nothing. \sa redo() canUndo() setActiveStack() */ void KUndo2Group::undo() { if (m_active != 0) m_active->undo(); } /*! Calls KUndo2QStack::redo() on the active stack. If none of the stacks are active, or if the group is empty, this function does nothing. \sa undo() canRedo() setActiveStack() */ void KUndo2Group::redo() { if (m_active != 0) m_active->redo(); } /*! Returns the value of the active stack's KUndo2QStack::canUndo(). If none of the stacks are active, or if the group is empty, this function returns false. \sa canRedo() setActiveStack() */ bool KUndo2Group::canUndo() const { return m_active != 0 && m_active->canUndo(); } /*! Returns the value of the active stack's KUndo2QStack::canRedo(). If none of the stacks are active, or if the group is empty, this function returns false. \sa canUndo() setActiveStack() */ bool KUndo2Group::canRedo() const { return m_active != 0 && m_active->canRedo(); } /*! Returns the value of the active stack's KUndo2QStack::undoActionText(). If none of the stacks are active, or if the group is empty, this function returns an empty string. \sa undoItemText() redoActionText() setActiveStack() */ QString KUndo2Group::undoText() const { return m_active == 0 ? QString() : m_active->undoText(); } /*! Returns the value of the active stack's KUndo2QStack::redoActionText(). If none of the stacks are active, or if the group is empty, this function returns an empty string. \sa redoItemText() undoActionText() setActiveStack() */ QString KUndo2Group::redoText() const { return m_active == 0 ? QString() : m_active->redoText(); } /*! Returns the value of the active stack's KUndo2QStack::isClean(). If none of the stacks are active, or if the group is empty, this function returns true. \sa setActiveStack() */ bool KUndo2Group::isClean() const { return m_active == 0 || m_active->isClean(); } #ifndef QT_NO_ACTION /*! Creates an undo QAction object with parent \a parent. Triggering this action will cause a call to KUndo2QStack::undo() on the active stack. The text of this action will always be the text of the command which will be undone in the next call to undo(), prefixed by \a prefix. If there is no command available for undo, if the group is empty or if none of the stacks are active, this action will be disabled. If \a prefix is empty, the default prefix "Undo" is used. \sa createRedoAction() canUndo() KUndo2Command::text() */ QAction *KUndo2Group::createUndoAction(QObject *parent) const { KUndo2Action *result = new KUndo2Action(i18n("Undo %1"), i18nc("Default text for undo action", "Undo"), parent); result->setEnabled(canUndo()); result->setPrefixedText(undoText()); - connect(this, SIGNAL(canUndoChanged(bool)), - result, SLOT(setEnabled(bool))); - connect(this, SIGNAL(undoTextChanged(QString)), - result, SLOT(setPrefixedText(QString))); - connect(result, SIGNAL(triggered()), this, SLOT(undo())); + connect(this, &KUndo2Group::canUndoChanged, + result, &QAction::setEnabled); + connect(this, &KUndo2Group::undoTextChanged, + result, &KUndo2Action::setPrefixedText); + connect(result, &QAction::triggered, this, &KUndo2Group::undo); return result; } /*! Creates an redo QAction object with parent \a parent. Triggering this action will cause a call to KUndo2QStack::redo() on the active stack. The text of this action will always be the text of the command which will be redone in the next call to redo(), prefixed by \a prefix. If there is no command available for redo, if the group is empty or if none of the stacks are active, this action will be disabled. If \a prefix is empty, the default prefix "Undo" is used. \sa createUndoAction() canRedo() KUndo2Command::text() */ QAction *KUndo2Group::createRedoAction(QObject *parent) const { KUndo2Action *result = new KUndo2Action(i18n("Redo %1"), i18nc("Default text for redo action", "Redo"), parent); result->setEnabled(canRedo()); result->setPrefixedText(redoText()); - connect(this, SIGNAL(canRedoChanged(bool)), - result, SLOT(setEnabled(bool))); - connect(this, SIGNAL(redoTextChanged(QString)), - result, SLOT(setPrefixedText(QString))); - connect(result, SIGNAL(triggered()), this, SLOT(redo())); + connect(this, &KUndo2Group::canRedoChanged, + result, &QAction::setEnabled); + connect(this, &KUndo2Group::redoTextChanged, + result, &KUndo2Action::setPrefixedText); + connect(result, &QAction::triggered, this, &KUndo2Group::redo); return result; } #endif // QT_NO_ACTION /*! \fn void KUndo2Group::activeStackChanged(KUndo2QStack *stack) This signal is emitted whenever the active stack of the group changes. This can happen when setActiveStack() or KUndo2QStack::setActive() is called, or when the active stack is removed form the group. \a stack is the new active stack. If no stack is active, \a stack is 0. \sa setActiveStack() KUndo2QStack::setActive() */ /*! \fn void KUndo2Group::indexChanged(int idx) This signal is emitted whenever the active stack emits KUndo2QStack::indexChanged() or the active stack changes. \a idx is the new current index, or 0 if the active stack is 0. \sa KUndo2QStack::indexChanged() setActiveStack() */ /*! \fn void KUndo2Group::cleanChanged(bool clean) This signal is emitted whenever the active stack emits KUndo2QStack::cleanChanged() or the active stack changes. \a clean is the new state, or true if the active stack is 0. \sa KUndo2QStack::cleanChanged() setActiveStack() */ /*! \fn void KUndo2Group::canUndoChanged(bool canUndo) This signal is emitted whenever the active stack emits KUndo2QStack::canUndoChanged() or the active stack changes. \a canUndo is the new state, or false if the active stack is 0. \sa KUndo2QStack::canUndoChanged() setActiveStack() */ /*! \fn void KUndo2Group::canRedoChanged(bool canRedo) This signal is emitted whenever the active stack emits KUndo2QStack::canRedoChanged() or the active stack changes. \a canRedo is the new state, or false if the active stack is 0. \sa KUndo2QStack::canRedoChanged() setActiveStack() */ /*! \fn void KUndo2Group::undoTextChanged(const QString &undoText) This signal is emitted whenever the active stack emits KUndo2QStack::undoTextChanged() or the active stack changes. \a undoText is the new state, or an empty string if the active stack is 0. \sa KUndo2QStack::undoTextChanged() setActiveStack() */ /*! \fn void KUndo2Group::redoTextChanged(const QString &redoText) This signal is emitted whenever the active stack emits KUndo2QStack::redoTextChanged() or the active stack changes. \a redoText is the new state, or an empty string if the active stack is 0. \sa KUndo2QStack::redoTextChanged() setActiveStack() */ #endif // QT_NO_UNDOGROUP diff --git a/src/libs/kundo2/kundo2model.cpp b/src/libs/kundo2/kundo2model.cpp index 58006e4b..2c304e4f 100644 --- a/src/libs/kundo2/kundo2model.cpp +++ b/src/libs/kundo2/kundo2model.cpp @@ -1,219 +1,217 @@ /* This file is part of the KDE project * Copyright (C) 2010 Matus Talcik * * 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. */ /**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "kundo2model.h" #include KUndo2Model::KUndo2Model(QObject *parent) : QAbstractItemModel(parent) { m_stack = 0; m_sel_model = new QItemSelectionModel(this, this); - connect(m_sel_model, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(setStackCurrentIndex(QModelIndex))); + connect(m_sel_model, &QItemSelectionModel::currentChanged, this, &KUndo2Model::setStackCurrentIndex); m_emty_label = i18n(""); } QItemSelectionModel *KUndo2Model::selectionModel() const { return m_sel_model; } KUndo2QStack *KUndo2Model::stack() const { return m_stack; } void KUndo2Model::setStack(KUndo2QStack *stack) { if (m_stack == stack) return; if (m_stack != 0) { - disconnect(m_stack, SIGNAL(cleanChanged(bool)), this, SLOT(stackChanged())); - disconnect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(stackChanged())); - disconnect(m_stack, SIGNAL(destroyed(QObject*)), this, SLOT(stackDestroyed(QObject*))); - disconnect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(addImage(int))); + disconnect(m_stack, &KUndo2QStack::cleanChanged, this, &KUndo2Model::stackChanged); + disconnect(m_stack, &KUndo2QStack::indexChanged, this, &KUndo2Model::stackChanged); + disconnect(m_stack, &QObject::destroyed, this, &KUndo2Model::stackDestroyed); } m_stack = stack; if (m_stack != 0) { - connect(m_stack, SIGNAL(cleanChanged(bool)), this, SLOT(stackChanged())); - connect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(stackChanged())); - connect(m_stack, SIGNAL(destroyed(QObject*)), this, SLOT(stackDestroyed(QObject*))); - connect(m_stack, SIGNAL(indexChanged(int)), this, SLOT(addImage(int))); + connect(m_stack, &KUndo2QStack::cleanChanged, this, &KUndo2Model::stackChanged); + connect(m_stack, &KUndo2QStack::indexChanged, this, &KUndo2Model::stackChanged); + connect(m_stack, &QObject::destroyed, this, &KUndo2Model::stackDestroyed); } stackChanged(); } void KUndo2Model::stackDestroyed(QObject *obj) { if (obj != m_stack) return; m_stack = 0; stackChanged(); } void KUndo2Model::stackChanged() { beginResetModel(); endResetModel(); m_sel_model->setCurrentIndex(selectedIndex(), QItemSelectionModel::ClearAndSelect); } void KUndo2Model::setStackCurrentIndex(const QModelIndex &index) { if (m_stack == 0) return; if (index == selectedIndex()) return; if (index.column() != 0) return; m_stack->setIndex(index.row()); } QModelIndex KUndo2Model::selectedIndex() const { return m_stack == 0 ? QModelIndex() : createIndex(m_stack->index(), 0); } QModelIndex KUndo2Model::index(int row, int column, const QModelIndex &parent) const { if (m_stack == 0) return QModelIndex(); if (parent.isValid()) return QModelIndex(); if (column != 0) return QModelIndex(); if (row < 0 || row > m_stack->count()) return QModelIndex(); return createIndex(row, column); } QModelIndex KUndo2Model::parent(const QModelIndex&) const { return QModelIndex(); } int KUndo2Model::rowCount(const QModelIndex &parent) const { if (m_stack == 0) return 0; if (parent.isValid()) return 0; return m_stack->count() + 1; } int KUndo2Model::columnCount(const QModelIndex&) const { return 1; } QVariant KUndo2Model::data(const QModelIndex &index, int role) const { if (m_stack == 0) return QVariant(); if (index.column() != 0) return QVariant(); if (index.row() < 0 || index.row() > m_stack->count()) return QVariant(); if (role == Qt::DisplayRole) { if (index.row() == 0) return m_emty_label; return m_stack->text(index.row() - 1); } else if (role == Qt::DecorationRole) { if (index.row() == m_stack->cleanIndex() && !m_clean_icon.isNull()) return m_clean_icon; } return QVariant(); } QString KUndo2Model::emptyLabel() const { return m_emty_label; } void KUndo2Model::setEmptyLabel(const QString &label) { m_emty_label = label; stackChanged(); } void KUndo2Model::setCleanIcon(const QIcon &icon) { m_clean_icon = icon; stackChanged(); } QIcon KUndo2Model::cleanIcon() const { return m_clean_icon; } diff --git a/src/libs/kundo2/kundo2stack.cpp b/src/libs/kundo2/kundo2stack.cpp index 79af9b23..4c322800 100644 --- a/src/libs/kundo2/kundo2stack.cpp +++ b/src/libs/kundo2/kundo2stack.cpp @@ -1,1446 +1,1446 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /**************************************************************************** ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include "kundo2stack.h" #include "kundo2stack_p.h" #include "kundo2group.h" #include #include #ifndef QT_NO_UNDOCOMMAND /*! \class KUndo2Command \brief The KUndo2Command class is the base class of all commands stored on a KUndo2QStack. \since 4.2 For an overview of Qt's Undo Framework, see the \l{Overview of Qt's Undo Framework}{overview document}. A KUndo2Command represents a single editing action on a document; for example, inserting or deleting a block of text in a text editor. KUndo2Command can apply a change to the document with redo() and undo the change with undo(). The implementations for these functions must be provided in a derived class. \snippet doc/src/snippets/code/src_gui_util_qundostack.cpp 0 A KUndo2Command has an associated text(). This is a short string describing what the command does. It is used to update the text properties of the stack's undo and redo actions; see KUndo2QStack::createUndoAction() and KUndo2QStack::createRedoAction(). KUndo2Command objects are owned by the stack they were pushed on. KUndo2QStack deletes a command if it has been undone and a new command is pushed. For example: \snippet doc/src/snippets/code/src_gui_util_qundostack.cpp 1 In effect, when a command is pushed, it becomes the top-most command on the stack. To support command compression, KUndo2Command has an id() and the virtual function mergeWith(). These functions are used by KUndo2QStack::push(). To support command macros, a KUndo2Command object can have any number of child commands. Undoing or redoing the parent command will cause the child commands to be undone or redone. A command can be assigned to a parent explicitly in the constructor. In this case, the command will be owned by the parent. The parent in this case is usually an empty command, in that it doesn't provide its own implementation of undo() and redo(). Instead, it uses the base implementations of these functions, which simply call undo() or redo() on all its children. The parent should, however, have a meaningful text(). \snippet doc/src/snippets/code/src_gui_util_qundostack.cpp 2 Another way to create macros is to use the convenience functions KUndo2QStack::beginMacro() and KUndo2QStack::endMacro(). \sa KUndo2QStack */ /*! Constructs a KUndo2Command object with the given \a parent and \a text. If \a parent is not 0, this command is appended to parent's child list. The parent command then owns this command and will delete it in its destructor. \sa ~KUndo2Command() */ KUndo2Command::KUndo2Command(const KUndo2MagicString &text, KUndo2Command *parent): m_hasParent(parent != 0), m_timedID(0), m_endOfCommand(QTime::currentTime()) { d = new KUndo2CommandPrivate; if (parent != 0) { parent->d->child_list.append(this); } setText(text); setTime(); } /*! Constructs a KUndo2Command object with parent \a parent. If \a parent is not 0, this command is appended to parent's child list. The parent command then owns this command and will delete it in its destructor. \sa ~KUndo2Command() */ KUndo2Command::KUndo2Command(KUndo2Command *parent): m_hasParent(parent != 0),m_timedID(0) { d = new KUndo2CommandPrivate; if (parent != 0) parent->d->child_list.append(this); setTime(); } /*! Destroys the KUndo2Command object and all child commands. \sa KUndo2Command() */ KUndo2Command::~KUndo2Command() { qDeleteAll(d->child_list); delete d; } /*! Returns the ID of this command. A command ID is used in command compression. It must be an integer unique to this command's class, or -1 if the command doesn't support compression. If the command supports compression this function must be overridden in the derived class to return the correct ID. The base implementation returns -1. KUndo2QStack::push() will only try to merge two commands if they have the same ID, and the ID is not -1. \sa mergeWith(), KUndo2QStack::push() */ int KUndo2Command::id() const { return -1; } /*! Attempts to merge this command with \a command. Returns true on success; otherwise returns false. If this function returns true, calling this command's redo() must have the same effect as redoing both this command and \a command. Similarly, calling this command's undo() must have the same effect as undoing \a command and this command. KUndo2QStack will only try to merge two commands if they have the same id, and the id is not -1. The default implementation returns false. \snippet doc/src/snippets/code/src_gui_util_qundostack.cpp 3 \sa id() KUndo2QStack::push() */ bool KUndo2Command::mergeWith(const KUndo2Command *command) { Q_UNUSED(command); return false; } /*! Applies a change to the document. This function must be implemented in the derived class. Calling KUndo2QStack::push(), KUndo2QStack::undo() or KUndo2QStack::redo() from this function leads to undefined behavior. The default implementation calls redo() on all child commands. \sa undo() */ void KUndo2Command::redo() { for (int i = 0; i < d->child_list.size(); ++i) d->child_list.at(i)->redo(); } /*! Reverts a change to the document. After undo() is called, the state of the document should be the same as before redo() was called. This function must be implemented in the derived class. Calling KUndo2QStack::push(), KUndo2QStack::undo() or KUndo2QStack::redo() from this function leads to undefined behavior. The default implementation calls undo() on all child commands in reverse order. \sa redo() */ void KUndo2Command::undo() { for (int i = d->child_list.size() - 1; i >= 0; --i) d->child_list.at(i)->undo(); } /*! Returns a short text string describing what this command does; for example, "insert text". The text is used when the text properties of the stack's undo and redo actions are updated. \sa setText(), KUndo2QStack::createUndoAction(), KUndo2QStack::createRedoAction() */ QString KUndo2Command::actionText() const { if(d->actionText!=0) return d->actionText; else return QString(); } /*! Returns a short text string describing what this command does; for example, "insert text". The text is used when the text properties of the stack's undo and redo actions are updated. \sa setText(), KUndo2QStack::createUndoAction(), KUndo2QStack::createRedoAction() */ KUndo2MagicString KUndo2Command::text() const { return d->text; } /*! Sets the command's text to be the \a text specified. The specified text should be a short user-readable string describing what this command does. \sa text() KUndo2QStack::createUndoAction() KUndo2QStack::createRedoAction() */ void KUndo2Command::setText(const KUndo2MagicString &undoText) { d->text = undoText; d->actionText = undoText.toSecondaryString(); } /*! \since 4.4 Returns the number of child commands in this command. \sa child() */ int KUndo2Command::childCount() const { return d->child_list.count(); } /*! \since 4.4 Returns the child command at \a index. \sa childCount(), KUndo2QStack::command() */ const KUndo2Command *KUndo2Command::child(int index) const { if (index < 0 || index >= d->child_list.count()) return 0; return d->child_list.at(index); } bool KUndo2Command::hasParent() { return m_hasParent; } int KUndo2Command::timedId() { return m_timedID; } void KUndo2Command::setTimedID(int value) { m_timedID = value; } bool KUndo2Command::timedMergeWith(KUndo2Command *other) { if(other->timedId() == this->timedId() && other->timedId()!=-1 ) m_mergeCommandsVector.append(other); else return false; return true; } void KUndo2Command::setTime() { m_timeOfCreation = QTime::currentTime(); } QTime KUndo2Command::time() { return m_timeOfCreation; } void KUndo2Command::setEndTime() { m_endOfCommand = QTime::currentTime(); } QTime KUndo2Command::endTime() { return m_endOfCommand; } void KUndo2Command::undoMergedCommands() { undo(); if (!mergeCommandsVector().isEmpty()) { QVectorIterator it(mergeCommandsVector()); it.toFront(); while (it.hasNext()) { KUndo2Command* cmd = it.next(); cmd->undoMergedCommands(); } } } void KUndo2Command::redoMergedCommands() { if (!mergeCommandsVector().isEmpty()) { QVectorIterator it(mergeCommandsVector()); it.toBack(); while (it.hasPrevious()) { KUndo2Command* cmd = it.previous(); cmd->redoMergedCommands(); } } redo(); } QVector KUndo2Command::mergeCommandsVector() { return m_mergeCommandsVector; } bool KUndo2Command::isMerged() { return !m_mergeCommandsVector.isEmpty(); } KUndo2CommandExtraData* KUndo2Command::extraData() const { return d->extraData.data(); } void KUndo2Command::setExtraData(KUndo2CommandExtraData *data) { d->extraData.reset(data); } #endif // QT_NO_UNDOCOMMAND #ifndef QT_NO_UNDOSTACK /*! \class KUndo2QStack \brief The KUndo2QStack class is a stack of KUndo2Command objects. \since 4.2 For an overview of Qt's Undo Framework, see the \l{Overview of Qt's Undo Framework}{overview document}. An undo stack maintains a stack of commands that have been applied to a document. New commands are pushed on the stack using push(). Commands can be undone and redone using undo() and redo(), or by triggering the actions returned by createUndoAction() and createRedoAction(). KUndo2QStack keeps track of the \a current command. This is the command which will be executed by the next call to redo(). The index of this command is returned by index(). The state of the edited object can be rolled forward or back using setIndex(). If the top-most command on the stack has already been redone, index() is equal to count(). KUndo2QStack provides support for undo and redo actions, command compression, command macros, and supports the concept of a \e{clean state}. \section1 Undo and Redo Actions KUndo2QStack provides convenient undo and redo QAction objects, which can be inserted into a menu or a toolbar. When commands are undone or redone, KUndo2QStack updates the text properties of these actions to reflect what change they will trigger. The actions are also disabled when no command is available for undo or redo. These actions are returned by KUndo2QStack::createUndoAction() and KUndo2QStack::createRedoAction(). \section1 Command Compression and Macros Command compression is useful when several commands can be compressed into a single command that can be undone and redone in a single operation. For example, when a user types a character in a text editor, a new command is created. This command inserts the character into the document at the cursor position. However, it is more convenient for the user to be able to undo or redo typing of whole words, sentences, or paragraphs. Command compression allows these single-character commands to be merged into a single command which inserts or deletes sections of text. For more information, see KUndo2Command::mergeWith() and push(). A command macro is a sequence of commands, all of which are undone and redone in one go. Command macros are created by giving a command a list of child commands. Undoing or redoing the parent command will cause the child commands to be undone or redone. Command macros may be created explicitly by specifying a parent in the KUndo2Command constructor, or by using the convenience functions beginMacro() and endMacro(). Although command compression and macros appear to have the same effect to the user, they often have different uses in an application. Commands that perform small changes to a document may be usefully compressed if there is no need to individually record them, and if only larger changes are relevant to the user. However, for commands that need to be recorded individually, or those that cannot be compressed, it is useful to use macros to provide a more convenient user experience while maintaining a record of each command. \section1 Clean State KUndo2QStack supports the concept of a clean state. When the document is saved to disk, the stack can be marked as clean using setClean(). Whenever the stack returns to this state through undoing and redoing commands, it emits the signal cleanChanged(). This signal is also emitted when the stack leaves the clean state. This signal is usually used to enable and disable the save actions in the application, and to update the document's title to reflect that it contains unsaved changes. \sa KUndo2Command, KUndo2View */ #ifndef QT_NO_ACTION KUndo2Action::KUndo2Action(const QString &textTemplate, const QString &defaultText, QObject *parent) : QAction(parent) { m_textTemplate = textTemplate; m_defaultText = defaultText; } void KUndo2Action::setPrefixedText(const QString &text) { if (text.isEmpty()) setText(m_defaultText); else setText(m_textTemplate.arg(text)); } #endif // QT_NO_ACTION /*! \internal Sets the current index to \a idx, emitting appropriate signals. If \a clean is true, makes \a idx the clean index as well. */ void KUndo2QStack::setIndex(int idx, bool clean) { bool was_clean = m_index == m_clean_index; if (m_lastMergedIndex <= idx) { m_lastMergedSetCount = idx - m_lastMergedIndex; } else { m_lastMergedSetCount = 1; m_lastMergedIndex = idx-1; } if(idx == 0){ m_lastMergedSetCount = 0; m_lastMergedIndex = 0; } if (idx != m_index) { m_index = idx; emit indexChanged(m_index); emit canUndoChanged(canUndo()); emit undoTextChanged(undoText()); emit canRedoChanged(canRedo()); emit redoTextChanged(redoText()); } if (clean) m_clean_index = m_index; bool is_clean = m_index == m_clean_index; if (is_clean != was_clean) emit cleanChanged(is_clean); } void KUndo2QStack::purgeRedoState() { bool macro = !m_macro_stack.isEmpty(); if (macro) return; bool redoStateChanged = false; bool cleanStateChanged = false; while (m_index < m_command_list.size()) { delete m_command_list.takeLast(); redoStateChanged = true; } if (m_clean_index > m_index) { m_clean_index = -1; // we've deleted the clean state cleanStateChanged = true; } if (redoStateChanged) { emit canRedoChanged(canRedo()); emit redoTextChanged(redoText()); } if (cleanStateChanged) { emit cleanChanged(isClean()); } } /*! \internal If the number of commands on the stack exceedes the undo limit, deletes commands from the bottom of the stack. Returns true if commands were deleted. */ bool KUndo2QStack::checkUndoLimit() { if (m_undo_limit <= 0 || !m_macro_stack.isEmpty() || m_undo_limit >= m_command_list.count()) return false; int del_count = m_command_list.count() - m_undo_limit; for (int i = 0; i < del_count; ++i) delete m_command_list.takeFirst(); m_index -= del_count; if (m_clean_index != -1) { if (m_clean_index < del_count) m_clean_index = -1; // we've deleted the clean command else m_clean_index -= del_count; } return true; } /*! Constructs an empty undo stack with the parent \a parent. The stack will initially be in the clean state. If \a parent is a KUndo2Group object, the stack is automatically added to the group. \sa push() */ KUndo2QStack::KUndo2QStack(QObject *parent) : QObject(parent), m_index(0), m_clean_index(0), m_group(0), m_undo_limit(0), m_useCumulativeUndoRedo(false), m_lastMergedSetCount(0), m_lastMergedIndex(0) { setTimeT1(5); setTimeT2(1); setStrokesN(2); #ifndef QT_NO_UNDOGROUP if (KUndo2Group *group = qobject_cast(parent)) group->addStack(this); #endif } /*! Destroys the undo stack, deleting any commands that are on it. If the stack is in a KUndo2Group, the stack is automatically removed from the group. \sa KUndo2QStack() */ KUndo2QStack::~KUndo2QStack() { #ifndef QT_NO_UNDOGROUP if (m_group != 0) m_group->removeStack(this); #endif clear(); } /*! Clears the command stack by deleting all commands on it, and returns the stack to the clean state.{ } Commands are not undone or redone; the state of the edited object remains unchanged. This function is usually used when the contents of the document are abandoned. \sa KUndo2QStack() */ void KUndo2QStack::clear() { if (m_command_list.isEmpty()) return; bool was_clean = isClean(); m_macro_stack.clear(); qDeleteAll(m_command_list); m_command_list.clear(); m_index = 0; m_clean_index = 0; emit indexChanged(0); emit canUndoChanged(false); emit undoTextChanged(QString()); emit canRedoChanged(false); emit redoTextChanged(QString()); if (!was_clean) emit cleanChanged(true); } /*! Pushes \a cmd on the stack or merges it with the most recently executed command. In either case, executes \a cmd by calling its redo() function. If \a cmd's id is not -1, and if the id is the same as that of the most recently executed command, KUndo2QStack will attempt to merge the two commands by calling KUndo2Command::mergeWith() on the most recently executed command. If KUndo2Command::mergeWith() returns true, \a cmd is deleted and false is returned. In all other cases \a cmd is simply pushed on the stack and true is returned. If commands were undone before \a cmd was pushed, the current command and all commands above it are deleted. Hence \a cmd always ends up being the top-most on the stack. Once a command is pushed, the stack takes ownership of it. There are no getters to return the command, since modifying it after it has been executed will almost always lead to corruption of the document's state. \sa KUndo2Command::id() KUndo2Command::mergeWith() */ bool KUndo2QStack::push(KUndo2Command *cmd) { cmd->redoMergedCommands(); cmd->setEndTime(); bool macro = !m_macro_stack.isEmpty(); KUndo2Command *cur = 0; if (macro) { KUndo2Command *macro_cmd = m_macro_stack.last(); if (!macro_cmd->d->child_list.isEmpty()) cur = macro_cmd->d->child_list.last(); } else { if (m_index > 0) cur = m_command_list.at(m_index - 1); while (m_index < m_command_list.size()) delete m_command_list.takeLast(); if (m_clean_index > m_index) m_clean_index = -1; // we've deleted the clean state } bool try_merge = cur != 0 && cur->id() != -1 && cur->id() == cmd->id() && (macro || m_index != m_clean_index); /*! *Here we are going to try to merge several commands together using the QVector field in the commands using *3 parameters. N : Number of commands that should remain individual at the top of the stack. T1 : Time lapsed between current command and previously merged command -- signal to *merge throughout the stack. T2 : Time lapsed between two commands signalling both commands belong to the same set *Whenever a KUndo2Command is initialized -- it consists of a start-time and when it is pushed --an end time. *Every time a command is pushed -- it checks whether the command pushed was pushed after T1 seconds of the last merged command *Then the merging begins with each group depending on the time in between each command (T2). * *@TODO : Currently it is not able to merge two merged commands together. */ if (!macro && m_command_list.size() > 1 && cmd->timedId() != -1 && m_useCumulativeUndoRedo) { KUndo2Command* lastcmd = m_command_list.last(); if (qAbs(cmd->time().msecsTo(lastcmd->endTime())) < m_timeT2 * 1000) { m_lastMergedSetCount++; } else { m_lastMergedSetCount = 0; m_lastMergedIndex = m_index-1; } if (lastcmd->timedId() == -1){ m_lastMergedSetCount = 0; m_lastMergedIndex = m_index; } if (m_lastMergedSetCount > m_strokesN) { KUndo2Command* toMerge = m_command_list.at(m_lastMergedIndex); if (toMerge && m_command_list.size() >= m_lastMergedIndex + 1 && m_command_list.at(m_lastMergedIndex + 1)) { if(toMerge->timedMergeWith(m_command_list.at(m_lastMergedIndex + 1))){ m_command_list.removeAt(m_lastMergedIndex + 1); } m_lastMergedSetCount--; m_lastMergedIndex = m_command_list.indexOf(toMerge); } } m_index = m_command_list.size(); if(m_lastMergedIndextime().msecsTo(m_command_list.at(m_lastMergedIndex)->endTime()) < -m_timeT1 * 1000) { //T1 time elapsed QListIterator it(m_command_list); it.toBack(); m_lastMergedSetCount = 1; while (it.hasPrevious()) { KUndo2Command* curr = it.previous(); KUndo2Command* lastCmdInCurrent = curr; if (!lastcmd->mergeCommandsVector().isEmpty()) { if (qAbs(lastcmd->mergeCommandsVector().constLast()->time().msecsTo(lastCmdInCurrent->endTime())) < int(m_timeT2 * 1000) && lastcmd != lastCmdInCurrent && lastcmd != curr) { if(lastcmd->timedMergeWith(curr)){ if (m_command_list.contains(curr)) { m_command_list.removeOne(curr); } } } else { lastcmd = curr; //end of a merge set } } else { if (qAbs(lastcmd->time().msecsTo(lastCmdInCurrent->endTime())) < int(m_timeT2 * 1000) && lastcmd != lastCmdInCurrent &&lastcmd!=curr) { if(lastcmd->timedMergeWith(curr)){ if (m_command_list.contains(curr)){ m_command_list.removeOne(curr); } } } else { lastcmd = curr; //end of a merge set } } } m_lastMergedIndex = m_command_list.size()-1; } } m_index = m_command_list.size(); } if (try_merge && cur->mergeWith(cmd)) { delete cmd; cmd = 0; if (!macro) { emit indexChanged(m_index); emit canUndoChanged(canUndo()); emit undoTextChanged(undoText()); emit canRedoChanged(canRedo()); emit redoTextChanged(redoText()); } } else { if (macro) { m_macro_stack.last()->d->child_list.append(cmd); } else { m_command_list.append(cmd); if(checkUndoLimit()) { m_lastMergedIndex = m_index - m_strokesN; } setIndex(m_index + 1, false); } } return cmd; } /*! Marks the stack as clean and emits cleanChanged() if the stack was not already clean. Whenever the stack returns to this state through the use of undo/redo commands, it emits the signal cleanChanged(). This signal is also emitted when the stack leaves the clean state. \sa isClean(), cleanIndex() */ void KUndo2QStack::setClean() { if (!m_macro_stack.isEmpty()) { qWarning("KUndo2QStack::setClean(): cannot set clean in the middle of a macro"); return; } setIndex(m_index, true); } /*! If the stack is in the clean state, returns true; otherwise returns false. \sa setClean() cleanIndex() */ bool KUndo2QStack::isClean() const { if (!m_macro_stack.isEmpty()) return false; return m_clean_index == m_index; } /*! Returns the clean index. This is the index at which setClean() was called. A stack may not have a clean index. This happens if a document is saved, some commands are undone, then a new command is pushed. Since push() deletes all the undone commands before pushing the new command, the stack can't return to the clean state again. In this case, this function returns -1. \sa isClean() setClean() */ int KUndo2QStack::cleanIndex() const { return m_clean_index; } /*! Undoes the command below the current command by calling KUndo2Command::undo(). Decrements the current command index. If the stack is empty, or if the bottom command on the stack has already been undone, this function does nothing. \sa redo() index() */ void KUndo2QStack::undo() { if (m_index == 0) return; if (!m_macro_stack.isEmpty()) { qWarning("KUndo2QStack::undo(): cannot undo in the middle of a macro"); return; } int idx = m_index - 1; m_command_list.at(idx)->undoMergedCommands(); setIndex(idx, false); } /*! Redoes the current command by calling KUndo2Command::redo(). Increments the current command index. If the stack is empty, or if the top command on the stack has already been redone, this function does nothing. \sa undo() index() */ void KUndo2QStack::redo() { if (m_index == m_command_list.size()) return; if (!m_macro_stack.isEmpty()) { qWarning("KUndo2QStack::redo(): cannot redo in the middle of a macro"); return; } m_command_list.at(m_index)->redoMergedCommands(); setIndex(m_index + 1, false); } /*! Returns the number of commands on the stack. Macro commands are counted as one command. \sa index() setIndex() command() */ int KUndo2QStack::count() const { return m_command_list.size(); } /*! Returns the index of the current command. This is the command that will be executed on the next call to redo(). It is not always the top-most command on the stack, since a number of commands may have been undone. \sa undo() redo() count() */ int KUndo2QStack::index() const { return m_index; } /*! Repeatedly calls undo() or redo() until the current command index reaches \a idx. This function can be used to roll the state of the document forwards of backwards. indexChanged() is emitted only once. \sa index() count() undo() redo() */ void KUndo2QStack::setIndex(int idx) { if (!m_macro_stack.isEmpty()) { qWarning("KUndo2QStack::setIndex(): cannot set index in the middle of a macro"); return; } if (idx < 0) idx = 0; else if (idx > m_command_list.size()) idx = m_command_list.size(); int i = m_index; while (i < idx) { m_command_list.at(i++)->redoMergedCommands(); notifySetIndexChangedOneCommand(); } while (i > idx) { m_command_list.at(--i)->undoMergedCommands(); notifySetIndexChangedOneCommand(); } setIndex(idx, false); } /** * Called by setIndex after every command execution. It is needed by * Krita to insert barriers between different kind of commands */ void KUndo2QStack::notifySetIndexChangedOneCommand() { } /*! Returns true if there is a command available for undo; otherwise returns false. This function returns false if the stack is empty, or if the bottom command on the stack has already been undone. Synonymous with index() == 0. \sa index() canRedo() */ bool KUndo2QStack::canUndo() const { if (!m_macro_stack.isEmpty()) return false; return m_index > 0; } /*! Returns true if there is a command available for redo; otherwise returns false. This function returns false if the stack is empty or if the top command on the stack has already been redone. Synonymous with index() == count(). \sa index() canUndo() */ bool KUndo2QStack::canRedo() const { if (!m_macro_stack.isEmpty()) return false; return m_index < m_command_list.size(); } /*! Returns the text of the command which will be undone in the next call to undo(). \sa KUndo2Command::text() redoActionText() undoItemText() */ QString KUndo2QStack::undoText() const { if (!m_macro_stack.isEmpty()) return QString(); if (m_index > 0 && m_command_list.at(m_index-1)!=0) return m_command_list.at(m_index - 1)->actionText(); return QString(); } /*! Returns the text of the command which will be redone in the next call to redo(). \sa KUndo2Command::text() undoActionText() redoItemText() */ QString KUndo2QStack::redoText() const { if (!m_macro_stack.isEmpty()) return QString(); if (m_index < m_command_list.size()) return m_command_list.at(m_index)->actionText(); return QString(); } #ifndef QT_NO_ACTION /*! Creates an undo QAction object with the given \a parent. Triggering this action will cause a call to undo(). The text of this action is the text of the command which will be undone in the next call to undo(), prefixed by the specified \a prefix. If there is no command available for undo, this action will be disabled. If \a prefix is empty, the default prefix "Undo" is used. \sa createRedoAction(), canUndo(), KUndo2Command::text() */ QAction *KUndo2QStack::createUndoAction(QObject *parent) const { KUndo2Action *result = new KUndo2Action(i18n("Undo %1"), i18nc("Default text for undo action", "Undo"), parent); result->setEnabled(canUndo()); result->setPrefixedText(undoText()); - connect(this, SIGNAL(canUndoChanged(bool)), - result, SLOT(setEnabled(bool))); - connect(this, SIGNAL(undoTextChanged(QString)), - result, SLOT(setPrefixedText(QString))); - connect(result, SIGNAL(triggered()), this, SLOT(undo())); + connect(this, &KUndo2QStack::canUndoChanged, + result, &QAction::setEnabled); + connect(this, &KUndo2QStack::undoTextChanged, + result, &KUndo2Action::setPrefixedText); + connect(result, &QAction::triggered, this, &KUndo2QStack::undo); return result; } /*! Creates an redo QAction object with the given \a parent. Triggering this action will cause a call to redo(). The text of this action is the text of the command which will be redone in the next call to redo(), prefixed by the specified \a prefix. If there is no command available for redo, this action will be disabled. If \a prefix is empty, the default prefix "Redo" is used. \sa createUndoAction(), canRedo(), KUndo2Command::text() */ QAction *KUndo2QStack::createRedoAction(QObject *parent) const { KUndo2Action *result = new KUndo2Action(i18n("Redo %1"), i18nc("Default text for redo action", "Redo"), parent); result->setEnabled(canRedo()); result->setPrefixedText(redoText()); - connect(this, SIGNAL(canRedoChanged(bool)), - result, SLOT(setEnabled(bool))); - connect(this, SIGNAL(redoTextChanged(QString)), - result, SLOT(setPrefixedText(QString))); - connect(result, SIGNAL(triggered()), this, SLOT(redo())); + connect(this, &KUndo2QStack::canRedoChanged, + result, &QAction::setEnabled); + connect(this, &KUndo2QStack::redoTextChanged, + result, &KUndo2Action::setPrefixedText); + connect(result, &QAction::triggered, this, &KUndo2QStack::redo); return result; } #endif // QT_NO_ACTION /*! Begins composition of a macro command with the given \a text description. An empty command described by the specified \a text is pushed on the stack. Any subsequent commands pushed on the stack will be appended to the empty command's children until endMacro() is called. Calls to beginMacro() and endMacro() may be nested, but every call to beginMacro() must have a matching call to endMacro(). While a macro is composed, the stack is disabled. This means that: \list \i indexChanged() and cleanChanged() are not emitted, \i canUndo() and canRedo() return false, \i calling undo() or redo() has no effect, \i the undo/redo actions are disabled. \endlist The stack becomes enabled and appropriate signals are emitted when endMacro() is called for the outermost macro. \snippet doc/src/snippets/code/src_gui_util_qundostack.cpp 4 This code is equivalent to: \snippet doc/src/snippets/code/src_gui_util_qundostack.cpp 5 \sa endMacro() */ void KUndo2QStack::beginMacro(const KUndo2MagicString &text) { KUndo2Command *cmd = new KUndo2Command(); cmd->setText(text); if (m_macro_stack.isEmpty()) { while (m_index < m_command_list.size()) delete m_command_list.takeLast(); if (m_clean_index > m_index) m_clean_index = -1; // we've deleted the clean state m_command_list.append(cmd); } else { m_macro_stack.last()->d->child_list.append(cmd); } m_macro_stack.append(cmd); if (m_macro_stack.count() == 1) { emit canUndoChanged(false); emit undoTextChanged(QString()); emit canRedoChanged(false); emit redoTextChanged(QString()); } } /*! Ends composition of a macro command. If this is the outermost macro in a set nested macros, this function emits indexChanged() once for the entire macro command. \sa beginMacro() */ void KUndo2QStack::endMacro() { if (m_macro_stack.isEmpty()) { qWarning("KUndo2QStack::endMacro(): no matching beginMacro()"); return; } m_macro_stack.removeLast(); if (m_macro_stack.isEmpty()) { checkUndoLimit(); setIndex(m_index + 1, false); } } /*! \since 4.4 Returns a const pointer to the command at \a index. This function returns a const pointer, because modifying a command, once it has been pushed onto the stack and executed, almost always causes corruption of the state of the document, if the command is later undone or redone. \sa KUndo2Command::child() */ const KUndo2Command *KUndo2QStack::command(int index) const { if (index < 0 || index >= m_command_list.count()) return 0; return m_command_list.at(index); } /*! Returns the text of the command at index \a idx. \sa beginMacro() */ QString KUndo2QStack::text(int idx) const { if (idx < 0 || idx >= m_command_list.size()) return QString(); return m_command_list.at(idx)->text().toString(); } /*! \property KUndo2QStack::undoLimit \brief the maximum number of commands on this stack. \since 4.3 When the number of commands on a stack exceedes the stack's undoLimit, commands are deleted from the bottom of the stack. Macro commands (commands with child commands) are treated as one command. The default value is 0, which means that there is no limit. This property may only be set when the undo stack is empty, since setting it on a non-empty stack might delete the command at the current index. Calling setUndoLimit() on a non-empty stack prints a warning and does nothing. */ void KUndo2QStack::setUndoLimit(int limit) { if (!m_command_list.isEmpty()) { qWarning("KUndo2QStack::setUndoLimit(): an undo limit can only be set when the stack is empty"); return; } if (limit == m_undo_limit) return; m_undo_limit = limit; checkUndoLimit(); emit undoLimitChanged(m_undo_limit); } int KUndo2QStack::undoLimit() const { return m_undo_limit; } /*! \property KUndo2QStack::active \brief the active status of this stack. An application often has multiple undo stacks, one for each opened document. The active stack is the one associated with the currently active document. If the stack belongs to a KUndo2Group, calls to KUndo2Group::undo() or KUndo2Group::redo() will be forwarded to this stack when it is active. If the KUndo2Group is watched by a KUndo2View, the view will display the contents of this stack when it is active. If the stack does not belong to a KUndo2Group, making it active has no effect. It is the programmer's responsibility to specify which stack is active by calling setActive(), usually when the associated document window receives focus. \sa KUndo2Group */ void KUndo2QStack::setActive(bool active) { #ifdef QT_NO_UNDOGROUP Q_UNUSED(active); #else bool prev = isActive(); if (m_group != 0) { if (active) m_group->setActiveStack(this); else if (m_group->activeStack() == this) m_group->setActiveStack(0); } if (isActive() != prev) { emit activeChanged(!prev); } #endif } bool KUndo2QStack::isActive() const { #ifdef QT_NO_UNDOGROUP return true; #else return m_group == 0 || m_group->activeStack() == this; #endif } void KUndo2QStack::setUseCumulativeUndoRedo(bool value) { m_useCumulativeUndoRedo = value; } bool KUndo2QStack::useCumulativeUndoRedo() { return m_useCumulativeUndoRedo; } void KUndo2QStack::setTimeT1(double value) { m_timeT1 = value; } double KUndo2QStack::timeT1() { return m_timeT1; } void KUndo2QStack::setTimeT2(double value) { m_timeT2 = value; } double KUndo2QStack::timeT2() { return m_timeT2; } int KUndo2QStack::strokesN() { return m_strokesN; } void KUndo2QStack::setStrokesN(int value) { m_strokesN = value; } QAction* KUndo2Stack::createRedoAction(KActionCollection* actionCollection, const QString& actionName) { QAction* action = KUndo2QStack::createRedoAction(actionCollection); if (actionName.isEmpty()) { action->setObjectName(KStandardAction::name(KStandardAction::Redo)); } else { action->setObjectName(actionName); } action->setIcon(koIcon("edit-redo")); action->setIconText(i18n("Redo")); action->setShortcuts(KStandardShortcut::redo()); actionCollection->addAction(action->objectName(), action); return action; } QAction* KUndo2Stack::createUndoAction(KActionCollection* actionCollection, const QString& actionName) { QAction* action = KUndo2QStack::createUndoAction(actionCollection); if (actionName.isEmpty()) { action->setObjectName(KStandardAction::name(KStandardAction::Undo)); } else { action->setObjectName(actionName); } action->setIcon(koIcon("edit-undo")); action->setIconText(i18n("Undo")); action->setShortcuts(KStandardShortcut::undo()); actionCollection->addAction(action->objectName(), action); return action; } /*! \fn void KUndo2QStack::indexChanged(int idx) This signal is emitted whenever a command modifies the state of the document. This happens when a command is undone or redone. When a macro command is undone or redone, or setIndex() is called, this signal is emitted only once. \a idx specifies the index of the current command, ie. the command which will be executed on the next call to redo(). \sa index() setIndex() */ /*! \fn void KUndo2QStack::cleanChanged(bool clean) This signal is emitted whenever the stack enters or leaves the clean state. If \a clean is true, the stack is in a clean state; otherwise this signal indicates that it has left the clean state. \sa isClean() setClean() */ /*! \fn void KUndo2QStack::undoTextChanged(const QString &undoText) This signal is emitted whenever the value of undoText() changes. It is used to update the text property of the undo action returned by createUndoAction(). \a undoText specifies the new text. */ /*! \fn void KUndo2QStack::canUndoChanged(bool canUndo) This signal is emitted whenever the value of canUndo() changes. It is used to enable or disable the undo action returned by createUndoAction(). \a canUndo specifies the new value. */ /*! \fn void KUndo2QStack::redoTextChanged(const QString &redoText) This signal is emitted whenever the value of redoText() changes. It is used to update the text property of the redo action returned by createRedoAction(). \a redoText specifies the new text. */ /*! \fn void KUndo2QStack::canRedoChanged(bool canRedo) This signal is emitted whenever the value of canRedo() changes. It is used to enable or disable the redo action returned by createRedoAction(). \a canRedo specifies the new value. */ KUndo2Stack::KUndo2Stack(QObject *parent): KUndo2QStack(parent) { } #endif // QT_NO_UNDOSTACK diff --git a/src/libs/kundo2/kundo2view.cpp b/src/libs/kundo2/kundo2view.cpp index 791f0f64..cf49cdda 100644 --- a/src/libs/kundo2/kundo2view.cpp +++ b/src/libs/kundo2/kundo2view.cpp @@ -1,285 +1,285 @@ /* This file is part of the KDE project * Copyright (C) 2010 Matus Talcik * * 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. */ /**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "kundo2stack.h" #include "kundo2view.h" #include "kundo2model.h" #include "kundo2group.h" #ifndef QT_NO_UNDOVIEW #include #include #include /*! \class KUndo2View \brief The KUndo2View class displays the contents of a KUndo2QStack. \since 4.2 \ingroup advanced KUndo2View is a QListView which displays the list of commands pushed on an undo stack. The most recently executed command is always selected. Selecting a different command results in a call to KUndo2QStack::setIndex(), rolling the state of the document backwards or forward to the new command. The stack can be set explicitly with setStack(). Alternatively, a QUndoGroup object can be set with setGroup(). The view will then update itself automatically whenever the active stack of the group changes. */ class KUndo2ViewPrivate { public: KUndo2ViewPrivate() : #ifndef QT_NO_UNDOGROUP group(0), #endif model(0) {} #ifndef QT_NO_UNDOGROUP QPointer group; #endif KUndo2Model *model; KUndo2View* q; void init(KUndo2View* view); }; void KUndo2ViewPrivate::init(KUndo2View* view) { q = view; model = new KUndo2Model(q); q->setModel(model); q->setSelectionModel(model->selectionModel()); } /*! Constructs a new view with parent \a parent. */ KUndo2View::KUndo2View(QWidget *parent) : QListView(parent), d(new KUndo2ViewPrivate) { d->init(this); } /*! Constructs a new view with parent \a parent and sets the observed stack to \a stack. */ KUndo2View::KUndo2View(KUndo2QStack *stack, QWidget *parent) : QListView(parent), d(new KUndo2ViewPrivate) { d->init(this); setStack(stack); } #ifndef QT_NO_UNDOGROUP /*! Constructs a new view with parent \a parent and sets the observed group to \a group. The view will update itself autmiatically whenever the active stack of the group changes. */ KUndo2View::KUndo2View(KUndo2Group *group, QWidget *parent) : QListView(parent), d(new KUndo2ViewPrivate) { d->init(this); setGroup(group); } #endif // QT_NO_UNDOGROUP /*! Destroys this view. */ KUndo2View::~KUndo2View() { delete d; } /*! Returns the stack currently displayed by this view. If the view is looking at a QUndoGroup, this the group's active stack. \sa setStack() setGroup() */ KUndo2QStack *KUndo2View::stack() const { return d->model->stack(); } /*! Sets the stack displayed by this view to \a stack. If \a stack is 0, the view will be empty. If the view was previously looking at a QUndoGroup, the group is set to 0. \sa stack() setGroup() */ void KUndo2View::setStack(KUndo2QStack *stack) { #ifndef QT_NO_UNDOGROUP setGroup(0); #endif d->model->setStack(stack); } #ifndef QT_NO_UNDOGROUP /*! Sets the group displayed by this view to \a group. If \a group is 0, the view will be empty. The view will update itself autmiatically whenever the active stack of the group changes. \sa group() setStack() */ void KUndo2View::setGroup(KUndo2Group *group) { if (d->group == group) return; if (d->group != 0) { - disconnect(d->group, SIGNAL(activeStackChanged(KUndo2QStack*)), - d->model, SLOT(setStack(KUndo2QStack*))); + disconnect(d->group.data(), &KUndo2Group::activeStackChanged, + d->model, &KUndo2Model::setStack); } d->group = group; if (d->group != 0) { - connect(d->group, SIGNAL(activeStackChanged(KUndo2QStack*)), - d->model, SLOT(setStack(KUndo2QStack*))); + connect(d->group.data(), &KUndo2Group::activeStackChanged, + d->model, &KUndo2Model::setStack); d->model->setStack((KUndo2QStack *)d->group->activeStack()); } else { d->model->setStack(0); } } /*! Returns the group displayed by this view. If the view is not looking at group, this function returns 0. \sa setGroup() setStack() */ KUndo2Group *KUndo2View::group() const { return d->group; } #endif // QT_NO_UNDOGROUP /*! \property KUndo2View::emptyLabel \brief the label used for the empty state. The empty label is the topmost element in the list of commands, which represents the state of the document before any commands were pushed on the stack. The default is the string "". */ void KUndo2View::setEmptyLabel(const QString &label) { bool changed = d->model->emptyLabel() != label; d->model->setEmptyLabel(label); if (changed) { emit emptyLabelChanged(); } } QString KUndo2View::emptyLabel() const { return d->model->emptyLabel(); } /*! \property KUndo2View::cleanIcon \brief the icon used to represent the clean state. A stack may have a clean state set with KUndo2QStack::setClean(). This is usually the state of the document at the point it was saved. KUndo2View can display an icon in the list of commands to show the clean state. If this property is a null icon, no icon is shown. The default value is the null icon. */ void KUndo2View::setCleanIcon(const QIcon &icon) { d->model->setCleanIcon(icon); emit cleanIconChanged(); } QIcon KUndo2View::cleanIcon() const { return d->model->cleanIcon(); } #endif // QT_NO_UNDOVIEW diff --git a/src/libs/main/KoApplication.cpp b/src/libs/main/KoApplication.cpp index 27a707d2..c642fad9 100644 --- a/src/libs/main/KoApplication.cpp +++ b/src/libs/main/KoApplication.cpp @@ -1,633 +1,633 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2009 Thomas Zander Copyright (C) 2012 Boudewijn Rempt 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 "KoApplication.h" #include "KoGlobal.h" #ifndef QT_NO_DBUS #include "KoApplicationAdaptor.h" #include #include #include #endif #include "KoPrintJob.h" #include "KoDocumentEntry.h" #include "KoDocument.h" #include "KoMainWindow.h" #include "KoAutoSaveRecoveryDialog.h" #include #include "KoPart.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #endif #include KoApplication* KoApplication::KoApp = 0; namespace { const QTime appStartTime(QTime::currentTime()); } class KoApplicationPrivate { public: KoApplicationPrivate() : splashScreen(0) {} QByteArray nativeMimeType; QWidget *splashScreen; QList partList; }; class KoApplication::ResetStarting { public: ResetStarting(QWidget *splash = 0) : m_splash(splash) { } ~ResetStarting() { if (m_splash) { KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false); if (hideSplash) { m_splash->hide(); } else { m_splash->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); QRect r(QPoint(), m_splash->size()); m_splash->move(QApplication::desktop()->screenGeometry().center() - r.center()); m_splash->setWindowTitle(qAppName()); foreach(QObject *o, m_splash->children()) { QWidget *w = qobject_cast(o); if (w && w->isHidden()) { w->setVisible(true); } } m_splash->show(); } } } QWidget *m_splash; }; KoApplication::KoApplication(const QByteArray &nativeMimeType, const QString &windowIconName, AboutDataGenerator aboutDataGenerator, int &argc, char **argv) : QApplication(argc, argv) , d(new KoApplicationPrivate()) { QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); QScopedPointer aboutData(aboutDataGenerator()); KAboutData::setApplicationData(*aboutData); setWindowIcon(QIcon::fromTheme(windowIconName, windowIcon())); KoApplication::KoApp = this; d->nativeMimeType = nativeMimeType; // Initialize all Calligra directories etc. KoGlobal::initialize(); #ifndef QT_NO_DBUS KDBusService service(KDBusService::Multiple); new KoApplicationAdaptor(this); QDBusConnection::sessionBus().registerObject("/application", this); #endif #ifdef Q_OS_MACX if ( QSysInfo::MacintoshVersion > QSysInfo::MV_10_8 ) { // fix Mac OS X 10.9 (mavericks) font issue // https://bugreports.qt-project.org/browse/QTBUG-32789 QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande"); } setAttribute(Qt::AA_DontShowIconsInMenus, true); #endif } #if defined(Q_OS_WIN) && defined(ENV32BIT) typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process; BOOL isWow64() { BOOL bIsWow64 = FALSE; //IsWow64Process is not available on all supported versions of Windows. //Use GetModuleHandle to get a handle to the DLL that contains the function //and GetProcAddress to get a pointer to the function if available. fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); if(0 != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { //handle error } } return bIsWow64; } #endif bool KoApplication::start() { KAboutData aboutData = KAboutData::applicationData(); // process commandline parameters QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addHelpOption(); parser.addVersionOption(); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("benchmark-loading"), i18n("just load the file and then exit"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("benchmark-loading-show-window"), i18n("load the file, show the window and progressbar and then exit"))); parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("profile-filename"), i18n("Filename to write profiling information into."), QStringLiteral("filename"))); parser.addPositionalArgument(QStringLiteral("[file(s)]"), i18n("File(s) or URL(s) to open")); parser.process(*this); aboutData.processCommandLine(&parser); #if defined(Q_OS_WIN) || defined (Q_OS_MACX) #ifdef ENV32BIT if (isWow64()) { KMessageBox::information(0, i18n("You are running a 32 bits build on a 64 bits Windows.\n" "This is not recommended.\n" "Please download and install the x64 build instead."), qApp->applicationName(), "calligra_32_on_64_warning"); } #endif QDir appdir(applicationDirPath()); appdir.cdUp(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (!env.contains("XDG_DATA_DIRS")) { qputenv("XDG_DATA_DIRS", QFile::encodeName(appdir.absolutePath() + "/share")); } qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";" + appdir.absolutePath() + "/lib" + ";" + appdir.absolutePath() + "/lib/kde4" + ";" + appdir.absolutePath() + "/Frameworks" + ";" + appdir.absolutePath())); #endif if (d->splashScreen) { d->splashScreen->show(); d->splashScreen->repaint(); processEvents(); } ResetStarting resetStarting(d->splashScreen); // remove the splash when done Q_UNUSED(resetStarting); // Find the part component file corresponding to the application instance name KoDocumentEntry entry; QList pluginLoaders = KoPluginLoader::pluginLoaders("calligraplan/parts", d->nativeMimeType); Q_FOREACH (QPluginLoader *loader, pluginLoaders) { if (loader->fileName().contains(applicationName()+QString("part"))) { entry = KoDocumentEntry(loader); pluginLoaders.removeOne(loader); break; } } qDeleteAll(pluginLoaders); if (entry.isEmpty()) { QMessageBox::critical(0, i18n("%1: Critical Error", applicationName()), i18n("Essential application components could not be found.\n" "This might be an installation issue.\n" "Try restarting or reinstalling.")); return false; } // No argument -> create an empty document const QStringList fileUrls = parser.positionalArguments(); if (fileUrls.isEmpty()) { // if there's no document, add the current working directory // to the recent dirs so the open dialog and open pane show // the directory from where the app was started, instead of // the last directory from where we opened a file KRecentDirs::add(":OpenDialog", QDir::currentPath()); QString errorMsg; KoPart *part = entry.createKoPart(&errorMsg); d->partList << part; if (!part) { if (!errorMsg.isEmpty()) KMessageBox::error(0, errorMsg); return false; } // XXX: the document should be separate plugin KoDocument *doc = part->document(); KoMainWindow *mainWindow = part->createMainWindow(); mainWindow->show(); - QObject::connect(doc, SIGNAL(sigProgress(int)), mainWindow, SLOT(slotProgress(int))); + QObject::connect(doc, &KoDocument::sigProgress, mainWindow, &KoMainWindow::slotProgress); // for initDoc to fill in the recent docs list // and for KoDocument::slotStarted part->addMainWindow(mainWindow); // Check for autosave files from a previous run. There can be several, and // we want to offer a restore for every one. Including a nice thumbnail! QStringList autoSaveFiles; // get all possible autosave files in the home dir, this is for unsaved document autosave files // Using the extension allows to avoid relying on the mime magic when opening QMimeType mimeType = QMimeDatabase().mimeTypeForName(doc->nativeFormatMimeType()); if (!mimeType.isValid()) { qFatal("It seems your installation is broken/incomplete because we failed to load the native mimetype \"%s\".", doc->nativeFormatMimeType().constData()); } const QString extension = mimeType.preferredSuffix(); QStringList filters; filters << QString(".%1-%2-%3-autosave%4").arg(part->componentData().componentName()).arg("*").arg("*").arg(extension); #ifdef Q_OS_WIN QDir autosaveDir = QDir::tempPath(); #else QDir autosaveDir = QDir::home(); #endif // all autosave files for our application autoSaveFiles = autosaveDir.entryList(filters, QDir::Files | QDir::Hidden); QStringList pids; QString ourPid; ourPid.setNum(applicationPid()); #ifndef QT_NO_DBUS // all running instances of our application -- bit hackish, but we cannot get at the dbus name here, for some reason QDBusReply reply = QDBusConnection::sessionBus().interface()->registeredServiceNames(); foreach (const QString &name, reply.value()) { if (name.contains(part->componentData().componentName())) { // we got another instance of ourselves running, let's get the pid QString pid = name.split('-').last(); if (pid != ourPid) { pids << pid; } } } #endif // remove the autosave files that are saved for other, open instances of ourselves foreach(const QString &autoSaveFileName, autoSaveFiles) { if (!QFile::exists(autosaveDir.absolutePath() + QDir::separator() + autoSaveFileName)) { autoSaveFiles.removeAll(autoSaveFileName); continue; } QStringList split = autoSaveFileName.split('-'); if (split.size() == 4) { if (pids.contains(split[1])) { // We've got an active, owned autosave file. Remove. autoSaveFiles.removeAll(autoSaveFileName); } } } // Allow the user to make their selection if (autoSaveFiles.size() > 0) { KoAutoSaveRecoveryDialog dlg(autoSaveFiles); if (dlg.exec() == QDialog::Accepted) { QStringList filesToRecover = dlg.recoverableFiles(); foreach (const QString &autoSaveFileName, autoSaveFiles) { if (!filesToRecover.contains(autoSaveFileName)) { // remove the files the user didn't want to recover QFile::remove(autosaveDir.absolutePath() + QDir::separator() + autoSaveFileName); } } autoSaveFiles = filesToRecover; } else { // don't recover any of the files, but don't delete them either autoSaveFiles.clear(); } } if (autoSaveFiles.size() > 0) { short int numberOfOpenDocuments = 0; // number of documents open // bah, we need to re-use the document that was already created QUrl url = QUrl::fromLocalFile(autosaveDir.absolutePath() + QDir::separator() + autoSaveFiles.takeFirst()); if (mainWindow->openDocument(part, url)) { doc->resetURL(); doc->setModified(true); // TODO: what if the app crashes immediately, before another autosave was made? better keep & rename QFile::remove(url.toLocalFile()); numberOfOpenDocuments++; } // And then for the other autosave files, we copy & paste the code // and loop through them. foreach(const QString &autoSaveFile, autoSaveFiles) { // For now create an empty document QString errorMsg; KoPart *part = entry.createKoPart(&errorMsg); d->partList << part; if (part) { url = QUrl::fromLocalFile(autosaveDir.absolutePath() + QDir::separator() + autoSaveFile); KoMainWindow *mainWindow = part->createMainWindow(); mainWindow->show(); if (mainWindow->openDocument(part, url)) { doc->resetURL(); doc->setModified(true); // TODO: what if the app crashes immediately, before another autosave was made? better keep & rename QFile::remove(url.toLocalFile()); numberOfOpenDocuments++; } } } return (numberOfOpenDocuments > 0); } else { part->showStartUpWidget(mainWindow); } } else { const bool benchmarkLoading = parser.isSet("benchmark-loading") || parser.isSet("benchmark-loading-show-window"); // only show the mainWindow when no command-line mode option is passed const bool showmainWindow = parser.isSet("benchmark-loading-show-window") || !parser.isSet("benchmark-loading"); const QString profileFileName = parser.value("profile-filename"); QTextStream profileoutput; QFile profileFile(profileFileName); if (!profileFileName.isEmpty() && profileFile.open(QFile::WriteOnly | QFile::Truncate)) { profileoutput.setDevice(&profileFile); } // Loop through arguments short int numberOfOpenDocuments = 0; // number of documents open // TODO: remove once Qt has proper handling itself const QRegExp withProtocolChecker( QStringLiteral("^[a-zA-Z]+:") ); for (int argNumber = 0; argNumber < fileUrls.size(); ++argNumber) { const QString fileUrl = fileUrls.at(argNumber); // convert to an url const bool startsWithProtocol = (withProtocolChecker.indexIn(fileUrl) == 0); const QUrl url = startsWithProtocol ? QUrl::fromUserInput(fileUrl) : QUrl::fromLocalFile(QDir::current().absoluteFilePath(fileUrl)); // For now create an empty document QString errorMsg; KoPart *part = entry.createKoPart(&errorMsg); d->partList << part; if (part) { KoDocument *doc = part->document(); // show a mainWindow asap KoMainWindow *mainWindow = part->createMainWindow(); if (showmainWindow) { mainWindow->show(); } if (benchmarkLoading) { doc->setReadWrite(false); connect(mainWindow, &KoMainWindow::loadCompleted, this, &KoApplication::benchmarkLoadingFinished); connect(mainWindow, &KoMainWindow::loadCompleted, this, &KoApplication::benchmarkLoadingFinished); } if (profileoutput.device()) { doc->setProfileStream(&profileoutput); profileoutput << "KoApplication::start\t" << appStartTime.msecsTo(QTime::currentTime()) <<"\t0" << endl; doc->setAutoErrorHandlingEnabled(false); } doc->setProfileReferenceTime(appStartTime); #if 0 // are we just trying to open a Calligra-style template? if (doTemplate) { QString templatePath; if (url.isLocalFile() && QFile::exists(url.toLocalFile())) { templatePath = url.toLocalFile(); debugMain << "using full path..."; } else { QString desktopName(fileUrls.at(argNumber)); const QString templatesResourcePath = part->templatesResourcePath(); QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName); if (paths.isEmpty()) { paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName); } if (paths.isEmpty()) { KMessageBox::error(0, i18n("No template found for: %1", desktopName)); delete mainWindow; } else if (paths.count() > 1) { KMessageBox::error(0, i18n("Too many templates found for: %1", desktopName)); delete mainWindow; } else { templatePath = paths.at(0); } } if (!templatePath.isEmpty()) { QUrl templateBase; templateBase.setPath(templatePath); KDesktopFile templateInfo(templatePath); QString templateName = templateInfo.readUrl(); QUrl templateURL; templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName); if (mainWindow->openDocument(part, templateURL)) { doc->resetURL(); doc->setEmpty(); doc->setTitleModified(); debugMain << "Template loaded..."; numberOfOpenDocuments++; } else { KMessageBox::error(0, i18n("Template %1 failed to load.", templateURL.toDisplayString())); delete mainWindow; } } // now try to load } else if (doNew) { if (url.isLocalFile() && !QFile::exists(url.toLocalFile())) { KMessageBox::error(0, i18n("No template found at: %1", url.toDisplayString())); delete mainWindow; } else { if (mainWindow->openDocument(part, url)) { doc->resetURL(); doc->setEmpty(); doc->setTitleModified(); debugMain << "Template loaded..."; numberOfOpenDocuments++; } else { KMessageBox::error(0, i18n("Template %1 failed to load.", url.toDisplayString())); delete mainWindow; } } } else #endif if (mainWindow->openDocument(part, url)) { if (benchmarkLoading) { if (profileoutput.device()) { profileoutput << "KoApplication::start\t" << appStartTime.msecsTo(QTime::currentTime()) <<"\t100" << endl; } return true; // only load one document! } else { // Normal case, success numberOfOpenDocuments++; } } else { // .... if failed // delete doc; done by openDocument // delete mainWindow; done by ~KoDocument } if (profileoutput.device()) { profileoutput << "KoApplication::start\t" << appStartTime.msecsTo(QTime::currentTime()) <<"\t100" << endl; } } } if (benchmarkLoading) { return false; // no valid urls found. } if (numberOfOpenDocuments == 0) { // no doc, e.g. all URLs were malformed return false; } } // not calling this before since the program will quit there. return true; } KoApplication::~KoApplication() { delete d; } void KoApplication::benchmarkLoadingFinished() { KoPart *part = d->partList.value(0); if (!part) { return; } KoMainWindow *mainWindow = part->mainWindows().value(0); if (!mainWindow) { return; } // close the document mainWindow->slotFileQuit(); } void KoApplication::setSplashScreen(QWidget *splashScreen) { d->splashScreen = splashScreen; } QList KoApplication::partList() const { return d->partList; } QStringList KoApplication::mimeFilter(KoFilterManager::Direction direction) const { KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(d->nativeMimeType); QJsonObject json = entry.metaData(); #ifdef CALLIGRA_OLD_PLUGIN_METADATA QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toString().split(','); #else QStringList mimeTypes = json.value("X-KDE-ExtraNativeMimeTypes").toVariant().toStringList(); #endif return KoFilterManager::mimeFilter(d->nativeMimeType, direction, mimeTypes); } bool KoApplication::notify(QObject *receiver, QEvent *event) { try { return QApplication::notify(receiver, event); } catch (std::exception &e) { qWarning("Error %s sending event %i to object %s", e.what(), event->type(), qPrintable(receiver->objectName())); } catch (...) { qWarning("Error sending event %i to object %s", event->type(), qPrintable(receiver->objectName())); } return false; } KoApplication *KoApplication::koApplication() { return KoApp; } diff --git a/src/libs/main/KoAutoSaveRecoveryDialog.cpp b/src/libs/main/KoAutoSaveRecoveryDialog.cpp index 74db54e7..eb049cf4 100644 --- a/src/libs/main/KoAutoSaveRecoveryDialog.cpp +++ b/src/libs/main/KoAutoSaveRecoveryDialog.cpp @@ -1,249 +1,249 @@ /* This file is part of the KDE project Copyright (C) 2012 Boudewijn Rempt 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 "KoAutoSaveRecoveryDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct FileItem { FileItem() : checked(true) {} QImage thumbnail; QString name; QString date; bool checked; }; class FileItemDelegate : public KWidgetItemDelegate { public: FileItemDelegate(QAbstractItemView *itemView, KoAutoSaveRecoveryDialog *dlg) : KWidgetItemDelegate(itemView, dlg) , m_parent(dlg) { } QList createItemWidgets(const QModelIndex &index) const { QWidget *page = new QWidget; QHBoxLayout *layout = new QHBoxLayout(page); QCheckBox *checkBox = new QCheckBox; checkBox->setProperty("fileitem", index.data()); - connect(checkBox, SIGNAL(toggled(bool)), m_parent, SLOT(toggleFileItem(bool))); + connect(checkBox, &QAbstractButton::toggled, m_parent, &KoAutoSaveRecoveryDialog::toggleFileItem); QLabel *thumbnail = new QLabel; QLabel *filename = new QLabel; QLabel *dateModified = new QLabel; layout->addWidget(checkBox); layout->addWidget(thumbnail); layout->addWidget(filename); layout->addWidget(dateModified); page->setFixedSize(600, 200); return QList() << page; } void updateItemWidgets(const QList widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const { FileItem *fileItem = (FileItem*)index.data().value(); QWidget* page= widgets[0]; QHBoxLayout* layout = qobject_cast(page->layout()); QCheckBox *checkBox = qobject_cast(layout->itemAt(0)->widget()); QLabel *thumbnail = qobject_cast(layout->itemAt(1)->widget()); QLabel *filename = qobject_cast(layout->itemAt(2)->widget()); QLabel *modified = qobject_cast(layout->itemAt(3)->widget()); checkBox->setChecked(fileItem->checked); thumbnail->setPixmap(QPixmap::fromImage(fileItem->thumbnail)); filename->setText(fileItem->name); modified->setText(fileItem->date); // move the page _up_ otherwise it will draw relative to the actual position page->setGeometry(option.rect.translated(0, -option.rect.y())); } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const { //paint background for selected or hovered item QStyleOptionViewItem opt = option; itemView()->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, 0); } QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const { return QSize(600, 200); } KoAutoSaveRecoveryDialog *m_parent; }; class KoAutoSaveRecoveryDialog::FileItemModel : public QAbstractListModel { public: FileItemModel(QList fileItems, QObject *parent) : QAbstractListModel(parent) , m_fileItems(fileItems){} virtual ~FileItemModel() { qDeleteAll(m_fileItems); m_fileItems.clear(); } int rowCount(const QModelIndex &/*parent*/) const { return m_fileItems.size(); } Qt::ItemFlags flags(const QModelIndex& /*index*/) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; return flags; } QVariant data(const QModelIndex& index, int role) const { if (index.isValid() && index.row() < m_fileItems.size()) { FileItem *item = m_fileItems.at(index.row()); switch (role) { case Qt::DisplayRole: { return QVariant::fromValue((void*)item); } case Qt::SizeHintRole: return QSize(600, 200); } } return QVariant(); } bool setData(const QModelIndex& index, const QVariant& /*value*/, int role) { if (index.isValid() && index.row() < m_fileItems.size()) { if (role == Qt::CheckStateRole) { m_fileItems.at(index.row())->checked = !m_fileItems.at(index.row())->checked; return true; } } return false; } QList m_fileItems; }; KoAutoSaveRecoveryDialog::KoAutoSaveRecoveryDialog(const QStringList &filenames, QWidget *parent) : KoDialog(parent) { setCaption(i18nc("@title:window", "Recover Files")); setMinimumSize(650, 500); QWidget *page = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(page); if (filenames.size() == 1) { layout->addWidget(new QLabel(i18n("The following autosave file can be recovered:"))); } else { layout->addWidget(new QLabel(i18n("The following autosave files can be recovered:"))); } m_listView = new QListView(); m_listView->setAcceptDrops(false); KWidgetItemDelegate *delegate = new FileItemDelegate(m_listView, this); m_listView->setItemDelegate(delegate); QList fileItems; foreach(const QString &filename, filenames) { FileItem *file = new FileItem(); file->name = filename; QString path = QDir::homePath() + "/" + filename; // get thumbnail -- all calligra apps save a thumbnail KoStore* store = KoStore::createStore(path, KoStore::Read); if (store && ( store->open(QString("Thumbnails/thumbnail.png")) || store->open(QString("preview.png")))) { // Hooray! No long delay for the user... QByteArray bytes = store->read(store->size()); store->close(); delete store; QImage img; img.loadFromData(bytes); file->thumbnail = img.scaled(QSize(200,200), Qt::KeepAspectRatio, Qt::SmoothTransformation); } // get the date QDateTime date = QFileInfo(path).lastModified(); file->date = "(" + date.toString(Qt::LocalDate) + ")"; fileItems.append(file); } m_model = new FileItemModel(fileItems, m_listView); m_listView->setModel(m_model); layout->addWidget(m_listView); setMainWidget(page); } QStringList KoAutoSaveRecoveryDialog::recoverableFiles() { QStringList files; foreach(FileItem* fileItem, m_model->m_fileItems) { if (fileItem->checked) { files << fileItem->name; } } return files; } void KoAutoSaveRecoveryDialog::toggleFileItem(bool toggle) { // I've made better man from a piece of putty and matchstick! QVariant v = sender()->property("fileitem") ; if (v.isValid()) { FileItem *fileItem = (FileItem*)v.value(); fileItem->checked = toggle; } } diff --git a/src/libs/main/KoDocument.cpp b/src/libs/main/KoDocument.cpp index a81d75df..04ef9782 100644 --- a/src/libs/main/KoDocument.cpp +++ b/src/libs/main/KoDocument.cpp @@ -1,2689 +1,2689 @@ /* This file is part of the KDE project * Copyright (C) 1998, 1999 Torben Weis * Copyright (C) 2000-2005 David Faure * Copyright (C) 2007-2008 Thorsten Zachmann * Copyright (C) 2010-2012 Boudewijn Rempt * Copyright (C) 2011 Inge Wallin * * 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 "KoDocument.h" #include "KoMainWindow.h" // XXX: remove #include // XXX: remove #include // XXX: remove #include "KoComponentData.h" #include "KoPart.h" #include "KoEmbeddedDocumentSaver.h" #include "KoFilterManager.h" #include "KoFileDialog.h" #include "KoDocumentInfo.h" #include "KoView.h" #include "KoOdfReadStore.h" #include "KoOdfWriteStore.h" #include "KoXmlNS.h" #include #include #include //#include #include #include #include #include #include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef QT_NO_DBUS #include #include #endif // Define the protocol used here for embedded documents' URL // This used to "store" but QUrl didn't like it, // so let's simply make it "tar" ! #define STORE_PROTOCOL "tar" // The internal path is a hack to make QUrl happy and for document children #define INTERNAL_PROTOCOL "intern" #define INTERNAL_PREFIX "intern:/" // Warning, keep it sync in koStore.cc #include #include "KoUndoStackAction.h" #include using namespace std; /********************************************************** * * KoDocument * **********************************************************/ namespace { class DocumentProgressProxy : public KoProgressProxy { public: KoMainWindow *m_mainWindow; DocumentProgressProxy(KoMainWindow *mainWindow) : m_mainWindow(mainWindow) { } ~DocumentProgressProxy() { // signal that the job is done setValue(-1); } int maximum() const { return 100; } void setValue(int value) { if (m_mainWindow) { m_mainWindow->slotProgress(value); } } void setRange(int /*minimum*/, int /*maximum*/) { } void setFormat(const QString &/*format*/) { } }; } //static QString KoDocument::newObjectName() { static int s_docIFNumber = 0; QString name; name.setNum(s_docIFNumber++); name.prepend("document_"); return name; } class Q_DECL_HIDDEN KoDocument::Private { public: Private(KoDocument *document, KoPart *part) : document(document), parentPart(part), docInfo(0), // docRdf(0), progressUpdater(0), progressProxy(0), profileStream(0), filterManager(0), specialOutputFlag(0), // default is native format isImporting(false), isExporting(false), password(QString()), modifiedAfterAutosave(false), autosaving(false), shouldCheckAutoSaveFile(true), autoErrorHandlingEnabled(true), backupFile(true), backupPath(QString()), doNotSaveExtDoc(false), storeInternal(false), isLoading(false), undoStack(0), modified(false), readwrite(true), alwaysAllowSaving(false), disregardAutosaveFailure(false) { m_job = 0; m_statJob = 0; m_uploadJob = 0; m_saveOk = false; m_waitForSave = false; m_duringSaveAs = false; m_bTemp = false; m_bAutoDetectedMime = false; confirmNonNativeSave[0] = true; confirmNonNativeSave[1] = true; if (QLocale().measurementSystem() == QLocale::ImperialSystem) { unit = KoUnit::Inch; } else { unit = KoUnit::Centimeter; } } KoDocument *document; KoPart *const parentPart; KoDocumentInfo *docInfo; // KoDocumentRdfBase *docRdf; KoProgressUpdater *progressUpdater; KoProgressProxy *progressProxy; QTextStream *profileStream; QTime profileReferenceTime; KoUnit unit; KoFilterManager *filterManager; // The filter-manager to use when loading/saving [for the options] QByteArray mimeType; // The actual mimetype of the document QByteArray outputMimeType; // The mimetype to use when saving bool confirmNonNativeSave [2]; // used to pop up a dialog when saving for the // first time if the file is in a foreign format // (Save/Save As, Export) int specialOutputFlag; // See KoFileDialog in koMainWindow.cc bool isImporting; bool isExporting; // File --> Import/Export vs File --> Open/Save QString password; // The password used to encrypt an encrypted document QTimer autoSaveTimer; QString lastErrorMessage; // see openFile() int autoSaveDelay; // in seconds, 0 to disable. bool modifiedAfterAutosave; bool autosaving; bool shouldCheckAutoSaveFile; // usually true bool autoErrorHandlingEnabled; // usually true bool backupFile; QString backupPath; bool doNotSaveExtDoc; // makes it possible to save only internally stored child documents bool storeInternal; // Store this doc internally even if url is external bool isLoading; // True while loading (openUrl is async) QList versionInfo; KUndo2Stack *undoStack; // KoGridData gridData; // KoGuidesData guidesData; bool isEmpty; KoPageLayout pageLayout; KIO::FileCopyJob * m_job; KIO::StatJob * m_statJob; KIO::FileCopyJob * m_uploadJob; QUrl m_originalURL; // for saveAs QString m_originalFilePath; // for saveAs bool m_saveOk : 1; bool m_waitForSave : 1; bool m_duringSaveAs : 1; bool m_bTemp: 1; // If @p true, @p m_file is a temporary file that needs to be deleted later. bool m_bAutoDetectedMime : 1; // whether the mimetype in the arguments was detected by the part itself QUrl m_url; // Remote (or local) url - the one displayed to the user. QString m_file; // Local file - the only one the part implementation should deal with. QEventLoop m_eventLoop; bool modified; bool readwrite; bool alwaysAllowSaving; bool disregardAutosaveFailure; bool openFile() { DocumentProgressProxy *progressProxy = 0; if (!document->progressProxy()) { KoMainWindow *mainWindow = 0; if (parentPart->mainWindows().count() > 0) { mainWindow = parentPart->mainWindows()[0]; } progressProxy = new DocumentProgressProxy(mainWindow); document->setProgressProxy(progressProxy); } document->setUrl(m_url); bool ok = document->openFile(); if (progressProxy) { document->setProgressProxy(0); delete progressProxy; } return ok; } bool openLocalFile() { m_bTemp = false; // set the mimetype only if it was not already set (for example, by the host application) if (mimeType.isEmpty()) { // get the mimetype of the file // using findByUrl() to avoid another string -> url conversion QMimeType mime = QMimeDatabase().mimeTypeForUrl(m_url); if (mime.isValid()) { mimeType = mime.name().toLatin1(); m_bAutoDetectedMime = true; } } const bool ret = openFile(); if (ret) { emit document->completed(); } else { emit document->canceled(QString()); } return ret; } void openRemoteFile() { m_bTemp = true; // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice) QString fileName = m_url.fileName(); QFileInfo fileInfo(fileName); QString ext = fileInfo.completeSuffix(); QString extension; if (!ext.isEmpty() && m_url.query().isNull()) // not if the URL has a query, e.g. cgi.pl?something extension = '.'+ext; // keep the '.' QTemporaryFile tempFile(QDir::tempPath() + "/" + qAppName() + QLatin1String("_XXXXXX") + extension); tempFile.setAutoRemove(false); tempFile.open(); m_file = tempFile.fileName(); const QUrl destURL = QUrl::fromLocalFile( m_file ); KIO::JobFlags flags = KIO::DefaultFlags; flags |= KIO::Overwrite; m_job = KIO::file_copy(m_url, destURL, 0600, flags); #ifndef QT_NO_DBUS KJobWidgets::setWindow(m_job, 0); if (m_job->uiDelegate()) { KJobWidgets::setWindow(m_job, parentPart->currentMainwindow()); } #endif - QObject::connect(m_job, SIGNAL(result(KJob*)), document, SLOT(_k_slotJobFinished(KJob*))); - QObject::connect(m_job, SIGNAL(mimetype(KIO::Job*,QString)), document, SLOT(_k_slotGotMimeType(KIO::Job*,QString))); + QObject::connect(m_job, SIGNAL(result(KJob*)), document, SLOT(_k_slotJobFinished(KJob*))); // clazy:exclude=old-style-connect + QObject::connect(m_job, SIGNAL(mimetype(KIO::Job*,QString)), document, SLOT(_k_slotGotMimeType(KIO::Job*,QString))); // clazy:exclude=old-style-connect } // Set m_file correctly for m_url void prepareSaving() { // Local file if ( m_url.isLocalFile() ) { if ( m_bTemp ) // get rid of a possible temp file first { // (happens if previous url was remote) QFile::remove( m_file ); m_bTemp = false; } m_file = m_url.toLocalFile(); } else { // Remote file // We haven't saved yet, or we did but locally - provide a temp file if ( m_file.isEmpty() || !m_bTemp ) { QTemporaryFile tempFile; tempFile.setAutoRemove(false); tempFile.open(); m_file = tempFile.fileName(); m_bTemp = true; } // otherwise, we already had a temp file } } void _k_slotJobFinished( KJob * job ) { Q_ASSERT( job == m_job ); m_job = 0; if (job->error()) emit document->canceled( job->errorString() ); else { if ( openFile() ) { emit document->completed(); } else { emit document->canceled(QString()); } } } void _k_slotStatJobFinished(KJob * job) { Q_ASSERT(job == m_statJob); m_statJob = 0; // this could maybe confuse some apps? So for now we'll just fallback to KIO::get // and error again. Well, maybe this even helps with wrong stat results. if (!job->error()) { const QUrl localUrl = static_cast(job)->mostLocalUrl(); if (localUrl.isLocalFile()) { m_file = localUrl.toLocalFile(); openLocalFile(); return; } } openRemoteFile(); } void _k_slotGotMimeType(KIO::Job *job, const QString &mime) { // kDebug(1000) << mime; Q_ASSERT(job == m_job); Q_UNUSED(job); // set the mimetype only if it was not already set (for example, by the host application) if (mimeType.isEmpty()) { mimeType = mime.toLatin1(); m_bAutoDetectedMime = true; } } void _k_slotUploadFinished( KJob * ) { if (m_uploadJob->error()) { QFile::remove(m_uploadJob->srcUrl().toLocalFile()); m_uploadJob = 0; if (m_duringSaveAs) { document->setUrl(m_originalURL); m_file = m_originalFilePath; } } else { ::org::kde::KDirNotify::emitFilesAdded(QUrl::fromLocalFile(m_url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path())); m_uploadJob = 0; document->setModified( false ); emit document->completed(); m_saveOk = true; } m_duringSaveAs = false; m_originalURL = QUrl(); m_originalFilePath.clear(); if (m_waitForSave) { m_eventLoop.quit(); } } }; KoDocument::KoDocument(KoPart *parent, KUndo2Stack *undoStack) : d(new Private(this, parent)) { Q_ASSERT(parent); d->isEmpty = true; d->filterManager = new KoFilterManager(this, d->progressUpdater); - connect(&d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); + connect(&d->autoSaveTimer, &QTimer::timeout, this, &KoDocument::slotAutoSave); setAutoSave(defaultAutoSave()); setObjectName(newObjectName()); d->docInfo = new KoDocumentInfo(this); d->pageLayout.width = 0; d->pageLayout.height = 0; d->pageLayout.topMargin = 0; d->pageLayout.bottomMargin = 0; d->pageLayout.leftMargin = 0; d->pageLayout.rightMargin = 0; d->undoStack = undoStack; d->undoStack->setParent(this); KConfigGroup cfgGrp(d->parentPart->componentData().config(), "Undo"); d->undoStack->setUndoLimit(cfgGrp.readEntry("UndoLimit", 1000)); - connect(d->undoStack, SIGNAL(indexChanged(int)), this, SLOT(slotUndoStackIndexChanged(int))); + connect(d->undoStack, &KUndo2QStack::indexChanged, this, &KoDocument::slotUndoStackIndexChanged); } KoDocument::~KoDocument() { d->autoSaveTimer.disconnect(this); d->autoSaveTimer.stop(); d->parentPart->deleteLater(); delete d->filterManager; delete d; } KoPart *KoDocument::documentPart() const { return d->parentPart; } bool KoDocument::exportDocument(const QUrl &_url) { bool ret; d->isExporting = true; // // Preserve a lot of state here because we need to restore it in order to // be able to fake a File --> Export. Can't do this in saveFile() because, // for a start, KParts has already set url and m_file and because we need // to restore the modified flag etc. and don't want to put a load on anyone // reimplementing saveFile() (Note: importDocument() and exportDocument() // will remain non-virtual). // QUrl oldURL = url(); QString oldFile = localFilePath(); bool wasModified = isModified(); QByteArray oldMimeType = mimeType(); // save... ret = saveAs(_url); // // This is sooooo hacky :( // Hopefully we will restore enough state. // debugMain << "Restoring KoDocument state to before export"; // always restore url & m_file because KParts has changed them // (regardless of failure or success) setUrl(oldURL); setLocalFilePath(oldFile); // on successful export we need to restore modified etc. too // on failed export, mimetype/modified hasn't changed anyway if (ret) { setModified(wasModified); d->mimeType = oldMimeType; } d->isExporting = false; return ret; } bool KoDocument::saveFile() { debugMain << "doc=" << url().url(); // Save it to be able to restore it after a failed save const bool wasModified = isModified(); // The output format is set by koMainWindow, and by openFile QByteArray outputMimeType = d->outputMimeType; if (outputMimeType.isEmpty()) { outputMimeType = d->outputMimeType = nativeFormatMimeType(); debugMain << "Empty output mime type, saving to" << outputMimeType; } QApplication::setOverrideCursor(Qt::WaitCursor); if (backupFile()) { if (url().isLocalFile()) KBackup::backupFile(url().toLocalFile(), d->backupPath); else { KIO::UDSEntry entry; if (KIO::NetAccess::stat(url(), entry, d->parentPart->currentMainwindow())) { // this file exists => backup emit statusBarMessage(i18n("Making backup...")); QUrl backup; if (d->backupPath.isEmpty()) backup = url(); else backup = QUrl::fromLocalFile(d->backupPath + '/' + url().fileName()); backup.setPath(backup.path() + QString::fromLatin1("~")); KFileItem item(entry, url()); Q_ASSERT(item.name() == url().fileName()); KIO::FileCopyJob *job = KIO::file_copy(url(), backup, item.permissions(), KIO::Overwrite | KIO::HideProgressInfo); job->exec(); } } } emit statusBarMessage(i18n("Saving...")); qApp->processEvents(); bool ret = false; bool suppressErrorDialog = false; if (!isNativeFormat(outputMimeType)) { debugMain << "Saving to format" << outputMimeType << "in" << localFilePath(); // Not native format : save using export filter KoFilter::ConversionStatus status = d->filterManager->exportDocument(localFilePath(), outputMimeType); ret = status == KoFilter::OK; suppressErrorDialog = (status == KoFilter::UserCancelled || status == KoFilter::BadConversionGraph); } else { // Native format => normal save Q_ASSERT(!localFilePath().isEmpty()); ret = saveNativeFormat(localFilePath()); } if (ret) { d->undoStack->setClean(); removeAutoSaveFiles(); // Restart the autosave timer // (we don't want to autosave again 2 seconds after a real save) setAutoSave(d->autoSaveDelay); } QApplication::restoreOverrideCursor(); if (!ret) { if (!suppressErrorDialog) { if (errorMessage().isEmpty()) { KMessageBox::error(0, i18n("Could not save\n%1", localFilePath())); } else if (errorMessage() != "USER_CANCELED") { KMessageBox::error(0, i18n("Could not save %1\nReason: %2", localFilePath(), errorMessage())); } } // couldn't save file so this new URL is invalid // FIXME: we should restore the current document's true URL instead of // setting it to nothing otherwise anything that depends on the URL // being correct will not work (i.e. the document will be called // "Untitled" which may not be true) // // Update: now the URL is restored in KoMainWindow but really, this // should still be fixed in KoDocument/KParts (ditto for file). // We still resetURL() here since we may or may not have been called // by KoMainWindow - Clarence resetURL(); // As we did not save, restore the "was modified" status setModified(wasModified); } if (ret) { d->mimeType = outputMimeType; setConfirmNonNativeSave(isExporting(), false); } emit clearStatusBarMessage(); if (ret) { KNotification *notify = new KNotification("DocumentSaved"); notify->setText(i18n("Document %1 saved", url().url())); notify->addContext("url", url().url()); - QTimer::singleShot(0, notify, SLOT(sendEvent())); + QTimer::singleShot(0, notify, &KNotification::sendEvent); } return ret; } QByteArray KoDocument::mimeType() const { return d->mimeType; } void KoDocument::setMimeType(const QByteArray & mimeType) { d->mimeType = mimeType; } void KoDocument::setOutputMimeType(const QByteArray & mimeType, int specialOutputFlag) { d->outputMimeType = mimeType; d->specialOutputFlag = specialOutputFlag; } QByteArray KoDocument::outputMimeType() const { return d->outputMimeType; } int KoDocument::specialOutputFlag() const { return d->specialOutputFlag; } bool KoDocument::confirmNonNativeSave(const bool exporting) const { // "exporting ? 1 : 0" is different from "exporting" because a bool is // usually implemented like an "int", not "unsigned : 1" return d->confirmNonNativeSave [ exporting ? 1 : 0 ]; } void KoDocument::setConfirmNonNativeSave(const bool exporting, const bool on) { d->confirmNonNativeSave [ exporting ? 1 : 0] = on; } bool KoDocument::saveInBatchMode() const { return d->filterManager->getBatchMode(); } void KoDocument::setSaveInBatchMode(const bool batchMode) { d->filterManager->setBatchMode(batchMode); } bool KoDocument::isImporting() const { return d->isImporting; } bool KoDocument::isExporting() const { return d->isExporting; } void KoDocument::setCheckAutoSaveFile(bool b) { d->shouldCheckAutoSaveFile = b; } void KoDocument::setAutoErrorHandlingEnabled(bool b) { d->autoErrorHandlingEnabled = b; } bool KoDocument::isAutoErrorHandlingEnabled() const { return d->autoErrorHandlingEnabled; } void KoDocument::slotAutoSave() { if (d->modified && d->modifiedAfterAutosave && !d->isLoading) { // Give a warning when trying to autosave an encrypted file when no password is known (should not happen) if (d->specialOutputFlag == SaveEncrypted && d->password.isNull()) { // That advice should also fix this error from occurring again emit statusBarMessage(i18n("The password of this encrypted document is not known. Autosave aborted! Please save your work manually.")); } else { - connect(this, SIGNAL(sigProgress(int)), d->parentPart->currentMainwindow(), SLOT(slotProgress(int))); + connect(this, &KoDocument::sigProgress, d->parentPart->currentMainwindow(), &KoMainWindow::slotProgress); emit statusBarMessage(i18n("Autosaving...")); d->autosaving = true; bool ret = saveNativeFormat(autoSaveFile(localFilePath())); setModified(true); if (ret) { d->modifiedAfterAutosave = false; d->autoSaveTimer.stop(); // until the next change } d->autosaving = false; emit clearStatusBarMessage(); - disconnect(this, SIGNAL(sigProgress(int)), d->parentPart->currentMainwindow(), SLOT(slotProgress(int))); + disconnect(this, &KoDocument::sigProgress, d->parentPart->currentMainwindow(), &KoMainWindow::slotProgress); if (!ret && !d->disregardAutosaveFailure) { emit statusBarMessage(i18n("Error during autosave! Partition full?")); } } } } void KoDocument::setReadWrite(bool readwrite) { d->readwrite = readwrite; setAutoSave(d->autoSaveDelay); // XXX: this doesn't belong in KoDocument foreach(KoView *view, d->parentPart->views()) { view->updateReadWrite(readwrite); } foreach(KoMainWindow *mainWindow, d->parentPart->mainWindows()) { mainWindow->setReadWrite(readwrite); } } void KoDocument::setAutoSave(int delay) { d->autoSaveDelay = delay; if (isReadWrite() && d->autoSaveDelay > 0) d->autoSaveTimer.start(d->autoSaveDelay * 1000); else d->autoSaveTimer.stop(); } KoDocumentInfo *KoDocument::documentInfo() const { return d->docInfo; } /* KoDocumentRdfBase *KoDocument::documentRdf() const { return d->docRdf; } void KoDocument::setDocumentRdf(KoDocumentRdfBase *rdfDocument) { delete d->docRdf; d->docRdf = rdfDocument; } */ bool KoDocument::isModified() const { return d->modified; } bool KoDocument::saveNativeFormat(const QString & file) { d->lastErrorMessage.clear(); KoStore::Backend backend = KoStore::Auto; if (d->specialOutputFlag == SaveAsDirectoryStore) { backend = KoStore::Directory; debugMain << "Saving as uncompressed XML, using directory store."; } #ifdef QCA2 else if (d->specialOutputFlag == SaveEncrypted) { backend = KoStore::Encrypted; debugMain << "Saving using encrypted backend."; } #endif else if (d->specialOutputFlag == SaveAsFlatXML) { debugMain << "Saving as a flat XML file."; QFile f(file); if (f.open(QIODevice::WriteOnly | QIODevice::Text)) { bool success = saveToStream(&f); f.close(); return success; } else return false; } debugMain << "KoDocument::saveNativeFormat nativeFormatMimeType=" << nativeFormatMimeType(); // OLD: bool oasis = d->specialOutputFlag == SaveAsOASIS; // OLD: QCString mimeType = oasis ? nativeOasisMimeType() : nativeFormatMimeType(); QByteArray mimeType = d->outputMimeType; debugMain << "KoDocument::savingTo mimeType=" << mimeType; QByteArray nativeOasisMime = nativeOasisMimeType(); bool oasis = !mimeType.isEmpty() && (mimeType == nativeOasisMime || mimeType == nativeOasisMime + "-template" || mimeType.startsWith("application/vnd.oasis.opendocument")); // TODO: use std::auto_ptr or create store on stack [needs API fixing], // to remove all the 'delete store' in all the branches KoStore *store = KoStore::createStore(file, KoStore::Write, mimeType, backend); if (d->specialOutputFlag == SaveEncrypted && !d->password.isNull()) store->setPassword(d->password); if (store->bad()) { d->lastErrorMessage = i18n("Could not create the file for saving"); // more details needed? delete store; return false; } if (oasis) { return saveNativeFormatODF(store, mimeType); } else { return saveNativeFormatCalligra(store); } } bool KoDocument::saveNativeFormatODF(KoStore *store, const QByteArray &mimeType) { debugMain << "Saving to OASIS format"; // Tell KoStore not to touch the file names KoOdfWriteStore odfStore(store); KoXmlWriter *manifestWriter = odfStore.manifestWriter(mimeType); KoEmbeddedDocumentSaver embeddedSaver; SavingContext documentContext(odfStore, embeddedSaver); if (!saveOdf(documentContext)) { debugMain << "saveOdf failed"; odfStore.closeManifestWriter(false); delete store; return false; } // Save embedded objects if (!embeddedSaver.saveEmbeddedDocuments(documentContext)) { debugMain << "save embedded documents failed"; odfStore.closeManifestWriter(false); delete store; return false; } if (store->open("meta.xml")) { if (!d->docInfo->saveOasis(store) || !store->close()) { odfStore.closeManifestWriter(false); delete store; return false; } manifestWriter->addManifestEntry("meta.xml", "text/xml"); } else { d->lastErrorMessage = i18n("Not able to write '%1'. Partition full?", QString("meta.xml")); odfStore.closeManifestWriter(false); delete store; return false; } /* if (d->docRdf && !d->docRdf->saveOasis(store, manifestWriter)) { d->lastErrorMessage = i18n("Not able to write RDF metadata. Partition full?"); odfStore.closeManifestWriter(false); delete store; return false; } */ if (store->open("Thumbnails/thumbnail.png")) { if (!saveOasisPreview(store, manifestWriter) || !store->close()) { d->lastErrorMessage = i18n("Error while trying to write '%1'. Partition full?", QString("Thumbnails/thumbnail.png")); odfStore.closeManifestWriter(false); delete store; return false; } // No manifest entry! } else { d->lastErrorMessage = i18n("Not able to write '%1'. Partition full?", QString("Thumbnails/thumbnail.png")); odfStore.closeManifestWriter(false); delete store; return false; } if (!d->versionInfo.isEmpty()) { if (store->open("VersionList.xml")) { KoStoreDevice dev(store); KoXmlWriter *xmlWriter = KoOdfWriteStore::createOasisXmlWriter(&dev, "VL:version-list"); for (int i = 0; i < d->versionInfo.size(); ++i) { KoVersionInfo *version = &d->versionInfo[i]; xmlWriter->startElement("VL:version-entry"); xmlWriter->addAttribute("VL:title", version->title); xmlWriter->addAttribute("VL:comment", version->comment); xmlWriter->addAttribute("VL:creator", version->saved_by); xmlWriter->addAttribute("dc:date-time", version->date.toString(Qt::ISODate)); xmlWriter->endElement(); } xmlWriter->endElement(); // root element xmlWriter->endDocument(); delete xmlWriter; store->close(); manifestWriter->addManifestEntry("VersionList.xml", "text/xml"); for (int i = 0; i < d->versionInfo.size(); ++i) { KoVersionInfo *version = &d->versionInfo[i]; store->addDataToFile(version->data, "Versions/" + version->title); } } else { d->lastErrorMessage = i18n("Not able to write '%1'. Partition full?", QString("VersionList.xml")); odfStore.closeManifestWriter(false); delete store; return false; } } // Write out manifest file if (!odfStore.closeManifestWriter()) { d->lastErrorMessage = i18n("Error while trying to write '%1'. Partition full?", QString("META-INF/manifest.xml")); delete store; return false; } // Remember the given password, if necessary if (store->isEncrypted() && !d->isExporting) d->password = store->password(); delete store; return true; } bool KoDocument::saveNativeFormatCalligra(KoStore *store) { debugMain << "Saving root"; if (store->open("root")) { KoStoreDevice dev(store); if (!saveToStream(&dev) || !store->close()) { debugMain << "saveToStream failed"; delete store; return false; } } else { d->lastErrorMessage = i18n("Not able to write '%1'. Partition full?", QString("maindoc.xml")); delete store; return false; } if (store->open("documentinfo.xml")) { QDomDocument doc = KoDocument::createDomDocument("document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1"); doc = d->docInfo->save(doc); KoStoreDevice dev(store); QByteArray s = doc.toByteArray(); // this is already Utf8! (void)dev.write(s.data(), s.size()); (void)store->close(); } if (store->open("preview.png")) { // ### TODO: missing error checking (The partition could be full!) savePreview(store); (void)store->close(); } if (!completeSaving(store)) { delete store; return false; } debugMain << "Saving done of url:" << url().url(); if (!store->finalize()) { delete store; return false; } // Success delete store; return true; } bool KoDocument::saveToStream(QIODevice *dev) { QDomDocument doc = saveXML(); // Save to buffer QByteArray s = doc.toByteArray(); // utf8 already dev->open(QIODevice::WriteOnly); int nwritten = dev->write(s.data(), s.size()); if (nwritten != (int)s.size()) warnMain << "wrote " << nwritten << "- expected" << s.size(); return nwritten == (int)s.size(); } QString KoDocument::checkImageMimeTypes(const QString &mimeType, const QUrl &url) const { if (!url.isLocalFile()) return mimeType; if (url.toLocalFile().endsWith(".kpp")) return "image/png"; QStringList imageMimeTypes; imageMimeTypes << "image/jpeg" << "image/x-psd" << "image/photoshop" << "image/x-photoshop" << "image/x-vnd.adobe.photoshop" << "image/vnd.adobe.photoshop" << "image/x-portable-pixmap" << "image/x-portable-graymap" << "image/x-portable-bitmap" << "application/pdf" << "image/x-exr" << "image/x-xcf" << "image/x-eps" << "image/png" << "image/bmp" << "image/x-xpixmap" << "image/gif" << "image/x-xbitmap" << "image/tiff" << "image/jp2"; if (!imageMimeTypes.contains(mimeType)) return mimeType; QFile f(url.toLocalFile()); f.open(QIODevice::ReadOnly); QByteArray ba = f.read(qMin(f.size(), (qint64)512)); // should be enough for images QMimeType mime = QMimeDatabase().mimeTypeForData(ba); f.close(); return mime.name(); } // Called for embedded documents bool KoDocument::saveToStore(KoStore *_store, const QString & _path) { debugMain << "Saving document to store" << _path; _store->pushDirectory(); // Use the path as the internal url if (_path.startsWith(STORE_PROTOCOL)) setUrl(QUrl(_path)); else // ugly hack to pass a relative URI setUrl(QUrl(INTERNAL_PREFIX + _path)); // In the current directory we're the king :-) if (_store->open("root")) { KoStoreDevice dev(_store); if (!saveToStream(&dev)) { _store->close(); return false; } if (!_store->close()) return false; } if (!completeSaving(_store)) return false; // Now that we're done leave the directory again _store->popDirectory(); debugMain << "Saved document to store"; return true; } bool KoDocument::saveOasisPreview(KoStore *store, KoXmlWriter *manifestWriter) { const QPixmap pix = generatePreview(QSize(128, 128)); if (pix.isNull()) return true; //no thumbnail to save, but the process succeeded QImage preview(pix.toImage().convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly)); if (preview.isNull()) return false; //thumbnail to save, but the process failed // ### TODO: freedesktop.org Thumbnail specification (date...) KoStoreDevice io(store); if (!io.open(QIODevice::WriteOnly)) return false; if (! preview.save(&io, "PNG", 0)) return false; io.close(); manifestWriter->addManifestEntry("Thumbnails/thumbnail.png", "image/png"); return true; } bool KoDocument::savePreview(KoStore *store) { QPixmap pix = generatePreview(QSize(256, 256)); const QImage preview(pix.toImage().convertToFormat(QImage::Format_ARGB32, Qt::ColorOnly)); KoStoreDevice io(store); if (!io.open(QIODevice::WriteOnly)) return false; if (! preview.save(&io, "PNG")) // ### TODO What is -9 in quality terms? return false; io.close(); return true; } QPixmap KoDocument::generatePreview(const QSize& size) { qreal docWidth, docHeight; int pixmapSize = qMax(size.width(), size.height()); if (d->pageLayout.width > 1.0) { docWidth = d->pageLayout.width / 72 * KoDpi::dpiX(); docHeight = d->pageLayout.height / 72 * KoDpi::dpiY(); } else { // If we don't have a page layout, just draw the top left hand corner docWidth = 500.0; docHeight = 500.0; } qreal ratio = docWidth / docHeight; int previewWidth, previewHeight; if (ratio > 1.0) { previewWidth = (int) pixmapSize; previewHeight = (int)(pixmapSize / ratio); } else { previewWidth = (int)(pixmapSize * ratio); previewHeight = (int) pixmapSize; } QPixmap pix((int)docWidth, (int)docHeight); pix.fill(QColor(245, 245, 245)); QRect rc(0, 0, pix.width(), pix.height()); QPainter p; p.begin(&pix); paintContent(p, rc); p.end(); return pix.scaled(QSize(previewWidth, previewHeight), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } QString KoDocument::autoSaveFile(const QString & path) const { QString retval; // Using the extension allows to avoid relying on the mime magic when opening QMimeType mime = QMimeDatabase().mimeTypeForName(nativeFormatMimeType()); if (! mime.isValid()) { qFatal("It seems your installation is broken/incomplete because we failed to load the native mimetype \"%s\".", nativeFormatMimeType().constData()); } const QString extension = mime.preferredSuffix(); if (path.isEmpty()) { // Never saved? #ifdef Q_OS_WIN // On Windows, use the temp location (https://bugs.kde.org/show_bug.cgi?id=314921) retval = QString("%1/.%2-%3-%4-autosave%5").arg(QDir::tempPath()).arg(d->parentPart->componentData().componentName()).arg(QApplication::applicationPid()).arg(objectName()).arg(extension); #else // On Linux, use a temp file in $HOME then. Mark it with the pid so two instances don't overwrite each other's autosave file retval = QString("%1/.%2-%3-%4-autosave%5").arg(QDir::homePath()).arg(d->parentPart->componentData().componentName()).arg(QApplication::applicationPid()).arg(objectName()).arg(extension); #endif } else { QUrl url = QUrl::fromLocalFile(path); Q_ASSERT(url.isLocalFile()); QString dir = QFileInfo(url.toLocalFile()).absolutePath(); QString filename = url.fileName(); retval = QString("%1.%2-autosave%3").arg(dir).arg(filename).arg(extension); } return retval; } void KoDocument::setDisregardAutosaveFailure(bool disregardFailure) { d->disregardAutosaveFailure = disregardFailure; } bool KoDocument::importDocument(const QUrl &_url) { bool ret; debugMain << "url=" << _url.url(); d->isImporting = true; // open... ret = openUrl(_url); // reset url & m_file (kindly? set by KoParts::openUrl()) to simulate a // File --> Import if (ret) { debugMain << "success, resetting url"; resetURL(); setTitleModified(); } d->isImporting = false; return ret; } bool KoDocument::openUrl(const QUrl &_url) { debugMain << "url=" << _url.url(); d->lastErrorMessage.clear(); // Reimplemented, to add a check for autosave files and to improve error reporting if (!_url.isValid()) { d->lastErrorMessage = i18n("Malformed URL\n%1", _url.url()); // ## used anywhere ? return false; } abortLoad(); QUrl url(_url); bool autosaveOpened = false; d->isLoading = true; if (url.isLocalFile() && d->shouldCheckAutoSaveFile) { QString file = url.toLocalFile(); QString asf = autoSaveFile(file); if (QFile::exists(asf)) { //debugMain <<"asf=" << asf; // ## TODO compare timestamps ? int res = KMessageBox::warningYesNoCancel(0, i18n("An autosaved file exists for this document.\nDo you want to open it instead?")); switch (res) { case KMessageBox::Yes : url.setPath(asf); autosaveOpened = true; break; case KMessageBox::No : QFile::remove(asf); break; default: // Cancel d->isLoading = false; return false; } } } bool ret = openUrlInternal(url); if (autosaveOpened) { resetURL(); // Force save to act like 'Save As' setReadWrite(true); // enable save button setModified(true); } else { d->parentPart->addRecentURLToAllMainWindows(_url); if (ret) { // Detect readonly local-files; remote files are assumed to be writable, unless we add a KIO::stat here (async). KFileItem file(url, mimeType(), KFileItem::Unknown); setReadWrite(file.isWritable()); } } return ret; } // It seems that people have started to save .docx files as .doc and // similar for xls and ppt. So let's make a small replacement table // here and see if we can open the files anyway. static const struct MimetypeReplacement { const char *typeFromName; // If the mime type from the name is this... const char *typeFromContents; // ...and findByFileContents() reports this type... const char *useThisType; // ...then use this type for real. } replacementMimetypes[] = { // doc / docx { "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, { "application/msword", "application/zip", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, { "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/msword", "application/msword" }, { "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/x-ole-storage", "application/msword" }, // xls / xlsx { "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, { "application/vnd.ms-excel", "application/zip", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-excel", "application/vnd.ms-excel" }, { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/x-ole-storage", "application/vnd.ms-excel" }, // ppt / pptx { "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, { "application/vnd.ms-powerpoint", "application/zip", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, { "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.ms-powerpoint", "application/vnd.ms-powerpoint" }, { "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/x-ole-storage", "application/vnd.ms-powerpoint" } }; bool KoDocument::openFile() { //debugMain <<"for" << localFilePath(); if (!QFile::exists(localFilePath())) { QApplication::restoreOverrideCursor(); if (d->autoErrorHandlingEnabled) // Maybe offer to create a new document with that name ? KMessageBox::error(0, i18n("The file %1 does not exist.", localFilePath())); d->isLoading = false; return false; } QApplication::setOverrideCursor(Qt::WaitCursor); d->specialOutputFlag = 0; QByteArray _native_format = nativeFormatMimeType(); QUrl u = QUrl::fromLocalFile(localFilePath()); QString typeName = mimeType(); if (typeName.isEmpty()) { typeName = QMimeDatabase().mimeTypeForUrl(u).name(); } // for images, always check content. typeName = checkImageMimeTypes(typeName, u); // Sometimes it seems that arguments().mimeType() contains a much // too generic mime type. In that case, let's try some educated // guesses based on what we know about file extension. // // FIXME: Should we just ignore this and always call // KMimeType::findByUrl()? David Faure says that it's // impossible for findByUrl() to fail to initiate the // mimetype for "*.doc" to application/msword. This hints // that we should do that. But why does it happen like // this at all? if (typeName == "application/zip") { QString filename = u.fileName(); // None of doc, xls or ppt are really zip files. But docx, // xlsx and pptx are. This miscategorization seems to only // crop up when there is a, say, docx file saved as doc. The // conversion to the docx mimetype will happen below. if (filename.endsWith(".doc")) typeName = "application/msword"; else if (filename.endsWith(".xls")) typeName = "application/vnd.ms-excel"; else if (filename.endsWith(".ppt")) typeName = "application/vnd.ms-powerpoint"; // Potentially more guesses here... } else if (typeName == "application/x-ole-storage") { QString filename = u.fileName(); // None of docx, xlsx or pptx are really OLE files. But doc, // xls and ppt are. This miscategorization seems to only crop // up when there is a, say, doc file saved as docx. The // conversion to the doc mimetype will happen below. if (filename.endsWith(".docx")) typeName = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; else if (filename.endsWith(".xlsx")) typeName = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; else if (filename.endsWith(".pptx")) typeName = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; // Potentially more guesses here... } //debugMain << "mimetypes 3:" << typeName; // In some cases docx files are saved as doc and similar. We have // a small hardcoded table for those cases. Check if this is // applicable here. for (uint i = 0; i < sizeof(replacementMimetypes) / sizeof(struct MimetypeReplacement); ++i) { const MimetypeReplacement *replacement = &replacementMimetypes[i]; if (typeName == replacement->typeFromName) { //debugMain << "found potential replacement target:" << typeName; // QT5TODO: this needs a new look with the different behaviour of QMimeDatabase QString typeFromContents = QMimeDatabase().mimeTypeForUrl(u).name(); //debugMain << "found potential replacement:" << typeFromContents; if (typeFromContents == replacement->typeFromContents) { typeName = replacement->useThisType; //debugMain << "So really use this:" << typeName; break; } } } //debugMain << "mimetypes 4:" << typeName; // Allow to open backup files, don't keep the mimetype application/x-trash. if (typeName == "application/x-trash") { QString path = u.path(); QMimeDatabase db; QMimeType mime = db.mimeTypeForName(typeName); const QStringList patterns = mime.isValid() ? mime.globPatterns() : QStringList(); // Find the extension that makes it a backup file, and remove it for (QStringList::ConstIterator it = patterns.begin(); it != patterns.end(); ++it) { QString ext = *it; if (!ext.isEmpty() && ext[0] == '*') { ext.remove(0, 1); if (path.endsWith(ext)) { path.chop(ext.length()); break; } } } typeName = db.mimeTypeForFile(path, QMimeDatabase::MatchExtension).name(); } // Special case for flat XML files (e.g. using directory store) if (u.fileName() == "maindoc.xml" || u.fileName() == "content.xml" || typeName == "inode/directory") { typeName = _native_format; // Hmm, what if it's from another app? ### Check mimetype d->specialOutputFlag = SaveAsDirectoryStore; debugMain << "loading" << u.fileName() << ", using directory store for" << localFilePath() << "; typeName=" << typeName; } debugMain << localFilePath() << "type:" << typeName; QString importedFile = localFilePath(); // create the main progress monitoring object for loading, this can // contain subtasks for filtering and loading KoProgressProxy *progressProxy = 0; if (d->progressProxy) { progressProxy = d->progressProxy; } d->progressUpdater = new KoProgressUpdater(progressProxy, KoProgressUpdater::Unthreaded, d->profileStream); d->progressUpdater->setReferenceTime(d->profileReferenceTime); d->progressUpdater->start(100, i18n("Opening Document")); setupOpenFileSubProgress(); if (!isNativeFormat(typeName.toLatin1())) { KoFilter::ConversionStatus status; importedFile = d->filterManager->importDocument(localFilePath(), typeName, status); if (status != KoFilter::OK) { QApplication::restoreOverrideCursor(); QString msg; switch (status) { case KoFilter::OK: break; case KoFilter::FilterCreationError: msg = i18n("Could not create the filter plugin"); break; case KoFilter::CreationError: msg = i18n("Could not create the output document"); break; case KoFilter::FileNotFound: msg = i18n("File not found"); break; case KoFilter::StorageCreationError: msg = i18n("Cannot create storage"); break; case KoFilter::BadMimeType: msg = i18n("Bad MIME type"); break; case KoFilter::EmbeddedDocError: msg = i18n("Error in embedded document"); break; case KoFilter::WrongFormat: msg = i18n("Format not recognized"); break; case KoFilter::NotImplemented: msg = i18n("Not implemented"); break; case KoFilter::ParsingError: msg = i18n("Parsing error"); break; case KoFilter::PasswordProtected: msg = i18n("Document is password protected"); break; case KoFilter::InvalidFormat: msg = i18n("Invalid file format"); break; case KoFilter::InternalError: case KoFilter::UnexpectedEOF: case KoFilter::UnexpectedOpcode: case KoFilter::StupidError: // ?? what is this ?? case KoFilter::UsageError: msg = i18n("Internal error"); break; case KoFilter::OutOfMemory: msg = i18n("Out of memory"); break; case KoFilter::FilterEntryNull: msg = i18n("Empty Filter Plugin"); break; case KoFilter::NoDocumentCreated: msg = i18n("Trying to load into the wrong kind of document"); break; case KoFilter::DownloadFailed: msg = i18n("Failed to download remote file"); break; case KoFilter::UserCancelled: case KoFilter::BadConversionGraph: // intentionally we do not prompt the error message here break; default: msg = i18n("Unknown error"); break; } if (d->autoErrorHandlingEnabled && !msg.isEmpty()) { QString errorMsg(i18n("Could not open %2.\nReason: %1.\n%3", msg, prettyPathOrUrl(), errorMessage())); KMessageBox::error(0, errorMsg); } d->isLoading = false; delete d->progressUpdater; d->progressUpdater = 0; return false; } d->isEmpty = false; debugMain << "importedFile" << importedFile << "status:" << static_cast(status); } QApplication::restoreOverrideCursor(); bool ok = true; if (!importedFile.isEmpty()) { // Something to load (tmp or native file) ? // The filter, if any, has been applied. It's all native format now. if (!loadNativeFormat(importedFile)) { ok = false; if (d->autoErrorHandlingEnabled) { showLoadingErrorDialog(); } } } if (importedFile != localFilePath()) { // We opened a temporary file (result of an import filter) // Set document URL to empty - we don't want to save in /tmp ! // But only if in readwrite mode (no saving problem otherwise) // -- // But this isn't true at all. If this is the result of an // import, then importedFile=temporary_file.kwd and // file/m_url=foreignformat.ext so m_url is correct! // So don't resetURL() or else the caption won't be set when // foreign files are opened (an annoying bug). // - Clarence // #if 0 if (isReadWrite()) resetURL(); #endif // remove temp file - uncomment this to debug import filters if (!importedFile.isEmpty()) { #ifndef NDEBUG if (!getenv("CALLIGRA_DEBUG_FILTERS")) #endif QFile::remove(importedFile); } } if (ok) { setMimeTypeAfterLoading(typeName); KNotification *notify = new KNotification("DocumentLoaded"); notify->setText(i18n("Document %1 loaded", url().url())); notify->addContext("url", url().url()); - QTimer::singleShot(0, notify, SLOT(sendEvent())); + QTimer::singleShot(0, notify, &KNotification::sendEvent); } if (progressUpdater()) { QPointer updater = progressUpdater()->startSubtask(1, "clear undo stack"); updater->setProgress(0); undoStack()->clear(); updater->setProgress(100); } delete d->progressUpdater; d->progressUpdater = 0; d->isLoading = false; return ok; } KoProgressUpdater *KoDocument::progressUpdater() const { return d->progressUpdater; } void KoDocument::setProgressProxy(KoProgressProxy *progressProxy) { d->progressProxy = progressProxy; } KoProgressProxy* KoDocument::progressProxy() const { if (!d->progressProxy) { KoMainWindow *mainWindow = 0; if (d->parentPart->mainwindowCount() > 0) { mainWindow = d->parentPart->mainWindows()[0]; } d->progressProxy = new DocumentProgressProxy(mainWindow); } return d->progressProxy; } // shared between openFile and koMainWindow's "create new empty document" code void KoDocument::setMimeTypeAfterLoading(const QString& mimeType) { d->mimeType = mimeType.toLatin1(); d->outputMimeType = d->mimeType; const bool needConfirm = !isNativeFormat(d->mimeType); setConfirmNonNativeSave(false, needConfirm); setConfirmNonNativeSave(true, needConfirm); } // The caller must call store->close() if loadAndParse returns true. bool KoDocument::oldLoadAndParse(KoStore *store, const QString& filename, KoXmlDocument& doc) { //debugMain <<"Trying to open" << filename; if (!store->open(filename)) { warnMain << "Entry " << filename << " not found!"; d->lastErrorMessage = i18n("Could not find %1", filename); return false; } // Error variables for QDomDocument::setContent QString errorMsg; int errorLine, errorColumn; bool ok = doc.setContent(store->device(), &errorMsg, &errorLine, &errorColumn); store->close(); if (!ok) { errorMain << "Parsing error in " << filename << "! Aborting!" << endl << " In line: " << errorLine << ", column: " << errorColumn << endl << " Error message: " << errorMsg << endl; d->lastErrorMessage = i18n("Parsing error in %1 at line %2, column %3\nError message: %4" , filename , errorLine, errorColumn , QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0)); return false; } debugMain << "File" << filename << " loaded and parsed"; return true; } bool KoDocument::loadNativeFormat(const QString & file_) { QString file = file_; QFileInfo fileInfo(file); if (!fileInfo.exists()) { // check duplicated from openUrl, but this is useful for templates d->lastErrorMessage = i18n("The file %1 does not exist.", file); return false; } if (!fileInfo.isFile()) { file += "/content.xml"; QFileInfo fileInfo2(file); if (!fileInfo2.exists() || !fileInfo2.isFile()) { d->lastErrorMessage = i18n("%1 is not a file." , file_); return false; } } QApplication::setOverrideCursor(Qt::WaitCursor); debugMain << file; QFile in; bool isRawXML = false; if (d->specialOutputFlag != SaveAsDirectoryStore) { // Don't try to open a directory ;) in.setFileName(file); if (!in.open(QIODevice::ReadOnly)) { QApplication::restoreOverrideCursor(); d->lastErrorMessage = i18n("Could not open the file for reading (check read permissions)."); return false; } char buf[6]; buf[5] = 0; int pos = 0; do { if (in.read(buf + pos , 1) < 1) { QApplication::restoreOverrideCursor(); in.close(); d->lastErrorMessage = i18n("Could not read the beginning of the file."); return false; } if (QChar(buf[pos]).isSpace()) continue; pos++; } while (pos < 5); isRawXML = (qstrnicmp(buf, "lastErrorMessage = i18n("parsing error in the main document at line %1, column %2\nError message: %3", errorLine, errorColumn, i18n(errorMsg.toUtf8())); res = false; } QApplication::restoreOverrideCursor(); in.close(); d->isEmpty = false; return res; } else { // It's a calligra store (tar.gz, zip, directory, etc.) in.close(); return loadNativeFormatFromStore(file); } } bool KoDocument::loadNativeFormatFromStore(const QString& file) { KoStore::Backend backend = (d->specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto; KoStore *store = KoStore::createStore(file, KoStore::Read, "", backend); if (store->bad()) { d->lastErrorMessage = i18n("Not a valid Calligra file: %1", file); delete store; QApplication::restoreOverrideCursor(); return false; } // Remember that the file was encrypted if (d->specialOutputFlag == 0 && store->isEncrypted() && !d->isImporting) d->specialOutputFlag = SaveEncrypted; const bool success = loadNativeFormatFromStoreInternal(store); // Retrieve the password after loading the file, only then is it guaranteed to exist if (success && store->isEncrypted() && !d->isImporting) d->password = store->password(); delete store; return success; } bool KoDocument::loadNativeFormatFromStore(QByteArray &data) { bool succes; KoStore::Backend backend = (d->specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto; QBuffer buffer(&data); KoStore *store = KoStore::createStore(&buffer, KoStore::Read, "", backend); if (store->bad()) { delete store; return false; } // Remember that the file was encrypted if (d->specialOutputFlag == 0 && store->isEncrypted() && !d->isImporting) d->specialOutputFlag = SaveEncrypted; succes = loadNativeFormatFromStoreInternal(store); // Retrieve the password after loading the file, only then is it guaranteed to exist if (succes && store->isEncrypted() && !d->isImporting) d->password = store->password(); delete store; return succes; } bool KoDocument::loadNativeFormatFromStoreInternal(KoStore *store) { bool oasis = true; /* if (oasis && store->hasFile("manifest.rdf") && d->docRdf) { d->docRdf->loadOasis(store); } */ // OASIS/OOo file format? if (store->hasFile("content.xml")) { // We could check the 'mimetype' file, but let's skip that and be tolerant. if (!loadOasisFromStore(store)) { QApplication::restoreOverrideCursor(); return false; } } else if (store->hasFile("root") || store->hasFile("maindoc.xml")) { // Fallback to "old" file format (maindoc.xml) oasis = false; KoXmlDocument doc = KoXmlDocument(true); bool ok = oldLoadAndParse(store, "root", doc); if (ok) ok = loadXML(doc, store); if (!ok) { QApplication::restoreOverrideCursor(); return false; } } else { errorMain << "ERROR: No maindoc.xml" << endl; d->lastErrorMessage = i18n("Invalid document: no file 'maindoc.xml'."); QApplication::restoreOverrideCursor(); return false; } if (oasis && store->hasFile("meta.xml")) { KoXmlDocument metaDoc; KoOdfReadStore oasisStore(store); if (oasisStore.loadAndParse("meta.xml", metaDoc, d->lastErrorMessage)) { d->docInfo->loadOasis(metaDoc); } } else if (!oasis && store->hasFile("documentinfo.xml")) { KoXmlDocument doc = KoXmlDocument(true); if (oldLoadAndParse(store, "documentinfo.xml", doc)) { d->docInfo->load(doc); } } else { //kDebug( 30003 ) <<"cannot open document info"; delete d->docInfo; d->docInfo = new KoDocumentInfo(this); } if (oasis && store->hasFile("VersionList.xml")) { KNotification *notify = new KNotification("DocumentHasVersions"); notify->setText(i18n("Document %1 contains several versions. Go to File->Versions to open an old version.", store->urlOfStore().url())); notify->addContext("url", store->urlOfStore().url()); - QTimer::singleShot(0, notify, SLOT(sendEvent())); + QTimer::singleShot(0, notify, &KNotification::sendEvent); KoXmlDocument versionInfo; KoOdfReadStore oasisStore(store); if (oasisStore.loadAndParse("VersionList.xml", versionInfo, d->lastErrorMessage)) { KoXmlNode list = KoXml::namedItemNS(versionInfo, KoXmlNS::VL, "version-list"); KoXmlElement e; forEachElement(e, list) { if (e.localName() == "version-entry" && e.namespaceURI() == KoXmlNS::VL) { KoVersionInfo version; version.comment = e.attribute("comment"); version.title = e.attribute("title"); version.saved_by = e.attribute("creator"); version.date = QDateTime::fromString(e.attribute("date-time"), Qt::ISODate); store->extractFile("Versions/" + version.title, version.data); d->versionInfo.append(version); } } } } bool res = completeLoading(store); QApplication::restoreOverrideCursor(); d->isEmpty = false; return res; } // For embedded documents bool KoDocument::loadFromStore(KoStore *_store, const QString& url) { if (_store->open(url)) { KoXmlDocument doc = KoXmlDocument(true); doc.setContent(_store->device()); if (!loadXML(doc, _store)) { _store->close(); return false; } _store->close(); } else { qWarning() << "couldn't open " << url; } _store->pushDirectory(); // Store as document URL if (url.startsWith(STORE_PROTOCOL)) { setUrl(QUrl::fromUserInput(url)); } else { setUrl(QUrl(INTERNAL_PREFIX + url)); _store->enterDirectory(url); } bool result = completeLoading(_store); // Restore the "old" path _store->popDirectory(); return result; } bool KoDocument::loadOasisFromStore(KoStore *store) { KoOdfReadStore odfStore(store); if (! odfStore.loadAndParse(d->lastErrorMessage)) { return false; } return loadOdf(odfStore); } bool KoDocument::addVersion(const QString& comment) { debugMain << "Saving the new version...."; KoStore::Backend backend = KoStore::Auto; if (d->specialOutputFlag != 0) return false; QByteArray mimeType = d->outputMimeType; QByteArray nativeOasisMime = nativeOasisMimeType(); bool oasis = !mimeType.isEmpty() && (mimeType == nativeOasisMime || mimeType == nativeOasisMime + "-template"); if (!oasis) return false; // TODO: use std::auto_ptr or create store on stack [needs API fixing], // to remove all the 'delete store' in all the branches QByteArray data; QBuffer buffer(&data); KoStore *store = KoStore::createStore(&buffer/*file*/, KoStore::Write, mimeType, backend); if (store->bad()) { delete store; return false; } debugMain << "Saving to OASIS format"; KoOdfWriteStore odfStore(store); KoXmlWriter *manifestWriter = odfStore.manifestWriter(mimeType); Q_UNUSED(manifestWriter); // XXX why? KoEmbeddedDocumentSaver embeddedSaver; SavingContext documentContext(odfStore, embeddedSaver); if (!saveOdf(documentContext)) { debugMain << "saveOdf failed"; delete store; return false; } // Save embedded objects if (!embeddedSaver.saveEmbeddedDocuments(documentContext)) { debugMain << "save embedded documents failed"; delete store; return false; } // Write out manifest file if (!odfStore.closeManifestWriter()) { d->lastErrorMessage = i18n("Error while trying to write '%1'. Partition full?", QString("META-INF/manifest.xml")); delete store; return false; } if (!store->finalize()) { delete store; return false; } delete store; KoVersionInfo version; version.comment = comment; version.title = "Version" + QString::number(d->versionInfo.count() + 1); version.saved_by = documentInfo()->authorInfo("creator"); version.date = QDateTime::currentDateTime(); version.data = data; d->versionInfo.append(version); save(); //finally save the document + the new version return true; } bool KoDocument::isStoredExtern() const { return !storeInternal() && hasExternURL(); } void KoDocument::setModified() { d->modified = true; } void KoDocument::setModified(bool mod) { if (isAutosaving()) // ignore setModified calls due to autosaving return; if ( !d->readwrite && d->modified ) { qCritical(/*1000*/) << "Can't set a read-only document to 'modified' !" << endl; return; } //debugMain<<" url:" << url.path(); //debugMain<<" mod="<The document '%1' has been modified.

Do you want to save it?

", name)); switch (res) { case KMessageBox::Yes : save(); // NOTE: External files always in native format. ###TODO: Handle non-native format setModified(false); // Now when queryClose() is called by closeEvent it won't do anything. break; case KMessageBox::No : removeAutoSaveFiles(); setModified(false); // Now when queryClose() is called by closeEvent it won't do anything. break; default : // case KMessageBox::Cancel : return res; // cancels the rest of the files } return res; } QString KoDocument::prettyPathOrUrl() const { QString _url(url().toDisplayString()); #ifdef Q_WS_WIN if (url().isLocalFile()) { _url = QDir::convertSeparators(_url); } #endif return _url; } // Note: We do not: Get caption from document info (title(), in about page) QString KoDocument::caption() const { QString c = url().fileName(); if (!c.isEmpty() && c.endsWith(".plan")) { c.remove(c.lastIndexOf(".plan"), 5); } return c; } void KoDocument::setTitleModified() { emit titleModified(caption(), isModified()); } bool KoDocument::completeLoading(KoStore*) { return true; } bool KoDocument::completeSaving(KoStore*) { return true; } QDomDocument KoDocument::createDomDocument(const QString& tagName, const QString& version) const { return createDomDocument(d->parentPart->componentData().componentName(), tagName, version); } //static QDomDocument KoDocument::createDomDocument(const QString& appName, const QString& tagName, const QString& version) { QDomImplementation impl; QString url = QString("http://www.calligra.org/DTD/%1-%2.dtd").arg(appName).arg(version); QDomDocumentType dtype = impl.createDocumentType(tagName, QString("-//KDE//DTD %1 %2//EN").arg(appName).arg(version), url); // The namespace URN doesn't need to include the version number. QString namespaceURN = QString("http://www.calligra.org/DTD/%1").arg(appName); QDomDocument doc = impl.createDocument(namespaceURN, tagName, dtype); doc.insertBefore(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), doc.documentElement()); return doc; } QDomDocument KoDocument::saveXML() { errorMain << "not implemented" << endl; d->lastErrorMessage = i18n("Internal error: saveXML not implemented"); return QDomDocument(); } bool KoDocument::isNativeFormat(const QByteArray& mimetype) const { if (mimetype == nativeFormatMimeType()) return true; return extraNativeMimeTypes().contains(mimetype); } int KoDocument::supportedSpecialFormats() const { // Apps which support special output flags can add reimplement and add to this. // E.g. this is how did "saving in the 1.1 format". // SaveAsDirectoryStore is a given since it's implemented by KoDocument itself. // SaveEncrypted is implemented in KoDocument as well, if QCA2 was found. #ifdef QCA2 return SaveAsDirectoryStore | SaveEncrypted; #else return SaveAsDirectoryStore; #endif } void KoDocument::setErrorMessage(const QString& errMsg) { d->lastErrorMessage = errMsg; } QString KoDocument::errorMessage() const { return d->lastErrorMessage; } void KoDocument::showLoadingErrorDialog() { if (errorMessage().isEmpty()) { KMessageBox::error(0, i18n("Could not open\n%1", localFilePath())); } else if (errorMessage() != "USER_CANCELED") { KMessageBox::error(0, i18n("Could not open %1\nReason: %2", localFilePath(), errorMessage())); } } bool KoDocument::isAutosaving() const { return d->autosaving; } bool KoDocument::isLoading() const { return d->isLoading; } void KoDocument::removeAutoSaveFiles() { // Eliminate any auto-save file QString asf = autoSaveFile(localFilePath()); // the one in the current dir if (QFile::exists(asf)) QFile::remove(asf); asf = autoSaveFile(QString()); // and the one in $HOME if (QFile::exists(asf)) QFile::remove(asf); } void KoDocument::setBackupFile(bool _b) { if (d->backupFile != _b) { d->backupFile = _b; emit backupFileChanged(_b); } } bool KoDocument::backupFile()const { return d->backupFile; } void KoDocument::setBackupPath(const QString & _path) { d->backupPath = _path; } QString KoDocument::backupPath()const { return d->backupPath; } bool KoDocument::storeInternal() const { return d->storeInternal; } void KoDocument::setStoreInternal(bool i) { d->storeInternal = i; //debugMain<<"="<storeInternal<<" doc:"<pageLayout; } void KoDocument::setPageLayout(const KoPageLayout &pageLayout) { d->pageLayout = pageLayout; } KoUnit KoDocument::unit() const { return d->unit; } void KoDocument::setUnit(const KoUnit &unit) { if (d->unit != unit) { d->unit = unit; emit unitChanged(unit); } } void KoDocument::saveUnitOdf(KoXmlWriter *settingsWriter) const { settingsWriter->addConfigItem("unit", unit().symbol()); } void KoDocument::initEmpty() { setEmpty(); setModified(false); } QList & KoDocument::versionList() { return d->versionInfo; } KUndo2Stack *KoDocument::undoStack() { return d->undoStack; } void KoDocument::addCommand(KUndo2Command *command) { if (command) d->undoStack->push(command); } void KoDocument::beginMacro(const KUndo2MagicString & text) { d->undoStack->beginMacro(text); } void KoDocument::endMacro() { d->undoStack->endMacro(); } void KoDocument::slotUndoStackIndexChanged(int idx) { // even if the document was already modified, call setModified to re-start autosave timer setModified(idx != d->undoStack->cleanIndex()); } void KoDocument::setProfileStream(QTextStream *profilestream) { d->profileStream = profilestream; } void KoDocument::setProfileReferenceTime(const QTime& referenceTime) { d->profileReferenceTime = referenceTime; } void KoDocument::clearUndoHistory() { d->undoStack->clear(); } /* KoGridData &KoDocument::gridData() { return d->gridData; } KoGuidesData &KoDocument::guidesData() { return d->guidesData; } */ bool KoDocument::isEmpty() const { return d->isEmpty; } void KoDocument::setEmpty() { d->isEmpty = true; } // static int KoDocument::defaultAutoSave() { return 300; } void KoDocument::resetURL() { setUrl(QUrl()); setLocalFilePath(QString()); } int KoDocument::pageCount() const { return 1; } void KoDocument::setupOpenFileSubProgress() {} KoDocumentInfoDlg *KoDocument::createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const { KoDocumentInfoDlg *dlg = new KoDocumentInfoDlg(parent, docInfo); KoMainWindow *mainwin = dynamic_cast(parent); if (mainwin) { - connect(dlg, SIGNAL(saveRequested()), mainwin, SLOT(slotFileSave())); + connect(dlg, &KoDocumentInfoDlg::saveRequested, mainwin, &KoMainWindow::slotFileSave); } return dlg; } bool KoDocument::isReadWrite() const { return d->readwrite; } QUrl KoDocument::url() const { return d->m_url; } bool KoDocument::closeUrl(bool promptToSave) { abortLoad(); //just in case if (promptToSave) { if ( d->document->isReadWrite() && d->document->isModified()) { if (!queryClose()) return false; } } // Not modified => ok and delete temp file. d->mimeType = QByteArray(); if ( d->m_bTemp ) { QFile::remove( d->m_file ); d->m_bTemp = false; } // It always succeeds for a read-only part, // but the return value exists for reimplementations // (e.g. pressing cancel for a modified read-write part) return true; } bool KoDocument::saveAs( const QUrl &kurl ) { if (!kurl.isValid()) { qCritical(/*1000*/) << "saveAs: Malformed URL " << kurl.url() << endl; return false; } d->m_duringSaveAs = true; d->m_originalURL = d->m_url; d->m_originalFilePath = d->m_file; d->m_url = kurl; // Store where to upload in saveToURL d->prepareSaving(); bool result = save(); // Save local file and upload local file if (!result) { d->m_url = d->m_originalURL; d->m_file = d->m_originalFilePath; d->m_duringSaveAs = false; d->m_originalURL = QUrl(); d->m_originalFilePath.clear(); } return result; } bool KoDocument::save() { d->m_saveOk = false; if ( d->m_file.isEmpty() ) // document was created empty d->prepareSaving(); DocumentProgressProxy *progressProxy = 0; if (!d->document->progressProxy()) { KoMainWindow *mainWindow = 0; if (d->parentPart->mainwindowCount() > 0) { mainWindow = d->parentPart->mainWindows()[0]; } progressProxy = new DocumentProgressProxy(mainWindow); d->document->setProgressProxy(progressProxy); } d->document->setUrl(url()); // THIS IS WRONG! KoDocument::saveFile should move here, and whoever subclassed KoDocument to // reimplement saveFile should now subclass KoPart. bool ok = d->document->saveFile(); if (progressProxy) { d->document->setProgressProxy(0); delete progressProxy; } if (ok) { return saveToUrl(); } else { emit canceled(QString()); } return false; } bool KoDocument::waitSaveComplete() { if (!d->m_uploadJob) return d->m_saveOk; d->m_waitForSave = true; d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); d->m_waitForSave = false; return d->m_saveOk; } void KoDocument::abortLoad() { if ( d->m_statJob ) { //kDebug(1000) << "Aborting job" << d->m_statJob; d->m_statJob->kill(); d->m_statJob = 0; } if ( d->m_job ) { //kDebug(1000) << "Aborting job" << d->m_job; d->m_job->kill(); d->m_job = 0; } } void KoDocument::setUrl(const QUrl &url) { d->m_url = url; } QString KoDocument::localFilePath() const { return d->m_file; } void KoDocument::setLocalFilePath( const QString &localFilePath ) { d->m_file = localFilePath; } bool KoDocument::queryClose() { if ( !d->document->isReadWrite() || !d->document->isModified() ) return true; QString docName = url().fileName(); if (docName.isEmpty()) docName = i18n( "Untitled" ); int res = KMessageBox::warningYesNoCancel( 0, i18n( "The document \"%1\" has been modified.\n" "Do you want to save your changes or discard them?" , docName ), i18n( "Close Document" ), KStandardGuiItem::save(), KStandardGuiItem::discard() ); bool abortClose=false; bool handled=false; switch(res) { case KMessageBox::Yes : if (!handled) { if (d->m_url.isEmpty()) { KoMainWindow *mainWindow = 0; if (d->parentPart->mainWindows().count() > 0) { mainWindow = d->parentPart->mainWindows()[0]; } KoFileDialog dialog(mainWindow, KoFileDialog::SaveFile, "SaveDocument"); QUrl url = QUrl::fromLocalFile(dialog.filename()); if (url.isEmpty()) return false; saveAs( url ); } else { save(); } } else if (abortClose) return false; return waitSaveComplete(); case KMessageBox::No : return true; default : // case KMessageBox::Cancel : return false; } } bool KoDocument::saveToUrl() { if ( d->m_url.isLocalFile() ) { d->document->setModified( false ); emit completed(); // if m_url is a local file there won't be a temp file -> nothing to remove Q_ASSERT( !d->m_bTemp ); d->m_saveOk = true; d->m_duringSaveAs = false; d->m_originalURL = QUrl(); d->m_originalFilePath.clear(); return true; // Nothing to do } #ifndef Q_OS_WIN else { if (d->m_uploadJob) { QFile::remove(d->m_uploadJob->srcUrl().toLocalFile()); d->m_uploadJob->kill(); d->m_uploadJob = 0; } QTemporaryFile *tempFile = new QTemporaryFile(); tempFile->open(); QString uploadFile = tempFile->fileName(); delete tempFile; QUrl uploadUrl; uploadUrl.setPath( uploadFile ); // Create hardlink if (::link(QFile::encodeName(d->m_file), QFile::encodeName(uploadFile)) != 0) { // Uh oh, some error happened. return false; } d->m_uploadJob = KIO::file_move( uploadUrl, d->m_url, -1, KIO::Overwrite ); #ifndef QT_NO_DBUS KJobWidgets::setWindow(d->m_uploadJob, 0); #endif - connect( d->m_uploadJob, SIGNAL(result(KJob*)), this, SLOT(_k_slotUploadFinished(KJob*)) ); + connect( d->m_uploadJob, SIGNAL(result(KJob*)), this, SLOT(_k_slotUploadFinished(KJob*)) ); // clazy:exclude=old-style-connect return true; } #else return false; #endif } bool KoDocument::openUrlInternal(const QUrl &url) { if ( !url.isValid() ) return false; if (d->m_bAutoDetectedMime) { d->mimeType = QByteArray(); d->m_bAutoDetectedMime = false; } QByteArray mimetype = d->mimeType; if ( !closeUrl() ) return false; d->mimeType = mimetype; setUrl(url); d->m_file.clear(); if (d->m_url.isLocalFile()) { d->m_file = d->m_url.toLocalFile(); return d->openLocalFile(); } else { d->openRemoteFile(); return true; } } // have to include this because of Q_PRIVATE_SLOT #include diff --git a/src/libs/main/KoFilter.cpp b/src/libs/main/KoFilter.cpp index 58b8f1c2..2048356d 100644 --- a/src/libs/main/KoFilter.cpp +++ b/src/libs/main/KoFilter.cpp @@ -1,64 +1,64 @@ /* This file is part of the KDE libraries Copyright (C) 2001 Werner Trobin 2002 Werner Trobin 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 "KoFilter.h" #include #include #include #include #include "KoFilterManager.h" #include "KoUpdater.h" class Q_DECL_HIDDEN KoFilter::Private { public: QPointer updater; Private() :updater(0) {} }; KoFilter::KoFilter(QObject *parent) : QObject(parent), m_chain(0), d(new Private) { } KoFilter::~KoFilter() { if (d->updater) d->updater->setProgress(100); delete d; } void KoFilter::setUpdater(const QPointer& updater) { if (d->updater && !updater) { - disconnect(this, SLOT(slotProgress(int))); + connect(this, &KoFilter::sigProgress, this, &KoFilter::slotProgress); } else if (!d->updater && updater) { - connect(this, SIGNAL(sigProgress(int)), SLOT(slotProgress(int))); + connect(this, &KoFilter::sigProgress, this, &KoFilter::slotProgress); } d->updater = updater; } void KoFilter::slotProgress(int value) { if (d->updater) { d->updater->setValue(value); } } diff --git a/src/libs/main/KoFilterManager_p.cpp b/src/libs/main/KoFilterManager_p.cpp index f31cb775..4e326727 100644 --- a/src/libs/main/KoFilterManager_p.cpp +++ b/src/libs/main/KoFilterManager_p.cpp @@ -1,91 +1,91 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis 2000, 2001 Werner Trobin Copyright (C) 2004 Nicolas Goutte Copyright (C) 2009 Thomas Zander 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 "KoFilterManager_p.h" #include #include #include #include #include #include #include KoFilterChooser::KoFilterChooser(QWidget *parent, const QStringList &mimeTypes, const QString &/*nativeFormat*/, const QUrl &url) : KoDialog(parent), m_mimeTypes(mimeTypes) { setObjectName("kofilterchooser"); setInitialSize(QSize(300, 350)); setButtons(KoDialog::Ok|KoDialog::Cancel); setDefaultButton(KoDialog::Ok); setCaption(i18n("Choose Filter")); setModal(true); QWidget *page = new QWidget(this); setMainWidget(page); QVBoxLayout *layout = new QVBoxLayout(page); if (url.isValid()) { KSqueezedTextLabel *l = new KSqueezedTextLabel(url.path(), page); layout->addWidget(l); } m_filterList = new QListWidget(page); layout->addWidget(m_filterList); page->setLayout(layout); Q_ASSERT(!m_mimeTypes.isEmpty()); QMimeDatabase db; for (QStringList::ConstIterator it = m_mimeTypes.constBegin(); it != m_mimeTypes.constEnd(); ++it) { QMimeType mime = db.mimeTypeForName(*it); const QString name = mime.isValid() ? mime.comment() : *it; if (! name.isEmpty()) { QListWidgetItem *item = new QListWidgetItem(name, m_filterList); item->setData(32, *it); } } m_filterList->sortItems(); if (m_filterList->currentRow() == -1) m_filterList->setCurrentRow(0); m_filterList->setFocus(); - connect(m_filterList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(accept())); + connect(m_filterList, &QListWidget::itemDoubleClicked, this, &QDialog::accept); resize(QSize(520, 400));//.expandedTo(minimumSizeHint())); } KoFilterChooser::~KoFilterChooser() { } QString KoFilterChooser::filterSelected() { QListWidgetItem *item = m_filterList->currentItem(); return item->data(32).toString(); } diff --git a/src/libs/main/KoMainWindow.cpp b/src/libs/main/KoMainWindow.cpp index 25604345..b8d5946a 100644 --- a/src/libs/main/KoMainWindow.cpp +++ b/src/libs/main/KoMainWindow.cpp @@ -1,2145 +1,2150 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2006 David Faure Copyright (C) 2007, 2009 Thomas zander Copyright (C) 2010 Benjamin Port 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 "KoMainWindow.h" #include "KoView.h" #include "KoDocument.h" #include "KoFilterManager.h" #include "KoDocumentInfo.h" #include "KoDocumentInfoDlg.h" #include "KoFileDialog.h" #include "KoDockFactoryBase.h" #include "KoDockWidgetTitleBar.h" #include "KoPrintJob.h" #include "KoDocumentEntry.h" #include "KoPart.h" #include #include #include "KoApplication.h" #include #include "KoResourcePaths.h" #include "KoComponentData.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_KACTIVITIES #include #endif // // qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MainDebug.h" class KoMainWindowPrivate { public: KoMainWindowPrivate(const QByteArray &_nativeMimeType, const KoComponentData &componentData_, KoMainWindow *w) : componentData(componentData_) { nativeMimeType = _nativeMimeType; parent = w; rootDocument = 0; rootPart = 0; partToOpen = 0; mainWindowGuiIsBuilt = false; forQuit = false; activePart = 0; activeView = 0; firstTime = true; progress = 0; showDocumentInfo = 0; saveAction = 0; saveActionAs = 0; printAction = 0; printActionPreview = 0; sendFileAction = 0; exportPdf = 0; closeFile = 0; reloadFile = 0; importFile = 0; exportFile = 0; #if 0 encryptDocument = 0; #ifndef NDEBUG uncompressToDir = 0; #endif #endif isImporting = false; isExporting = false; windowSizeDirty = false; lastExportSpecialOutputFlag = 0; readOnly = false; dockWidgetMenu = 0; deferredClosingEvent = 0; #ifdef HAVE_KACTIVITIES activityResource = 0; #endif m_helpMenu = 0; // PartManger m_activeWidget = 0; m_activePart = 0; noCleanup = false; openingDocument = false; } ~KoMainWindowPrivate() { qDeleteAll(toolbarList); } void applyDefaultSettings(QPrinter &printer) { QString title = rootDocument->documentInfo()->aboutInfo("title"); if (title.isEmpty()) { title = rootDocument->url().fileName(); // strip off the native extension (I don't want foobar.kwd.ps when printing into a file) QMimeType mime = QMimeDatabase().mimeTypeForName(rootDocument->outputMimeType()); if (mime.isValid()) { const QString extension = mime.preferredSuffix(); if (title.endsWith(extension)) title.chop(extension.length()); } } if (title.isEmpty()) { // #139905 title = i18n("%1 unsaved document (%2)", parent->componentData().componentDisplayName(), QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); } printer.setDocName(title); } QByteArray nativeMimeType; KoMainWindow *parent; KoDocument *rootDocument; QList rootViews; // PartManager QPointer rootPart; QPointer partToOpen; QPointer activePart; QPointer m_activePart; QPointer m_registeredPart; KoView *activeView; QWidget *m_activeWidget; QPointer progress; QMutex progressMutex; QList toolbarList; bool mainWindowGuiIsBuilt; bool forQuit; bool firstTime; bool windowSizeDirty; bool readOnly; QAction *showDocumentInfo; QAction *saveAction; QAction *saveActionAs; QAction *printAction; QAction *printActionPreview; QAction *sendFileAction; QAction *exportPdf; QAction *closeFile; QAction *reloadFile; QAction *importFile; QAction *exportFile; #if 0 QAction *encryptDocument; #ifndef NDEBUG QAction *uncompressToDir; #endif #endif KToggleAction *toggleDockers; KToggleAction *toggleDockerTitleBars; KRecentFilesAction *recent; bool isImporting; bool isExporting; QUrl lastExportUrl; QByteArray lastExportedFormat; int lastExportSpecialOutputFlag; QMap dockWidgetsMap; KActionMenu *dockWidgetMenu; QMap dockWidgetVisibilityMap; QList dockWidgets; QByteArray m_dockerStateBeforeHiding; QCloseEvent *deferredClosingEvent; #ifdef HAVE_KACTIVITIES KActivities::ResourceInstance *activityResource; #endif KoComponentData componentData; KHelpMenu *m_helpMenu; bool noCleanup; bool openingDocument; }; KoMainWindow::KoMainWindow(const QByteArray &nativeMimeType, const KoComponentData &componentData) : KXmlGuiWindow() , d(new KoMainWindowPrivate(nativeMimeType, componentData, this)) { #ifdef Q_OS_MAC setUnifiedTitleAndToolBarOnMac(true); #endif setStandardToolBarMenuEnabled(true); setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); - connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); + connect(this, &KoMainWindow::restoringDone, this, &KoMainWindow::forceDockTabFonts); // PartManager // End QString doc; const QStringList allFiles = KoResourcePaths::findAllResources("data", "calligraplan/calligraplan_shell.rc"); setXMLFile(findMostRecentXMLFile(allFiles, doc)); setLocalXMLFile(KoResourcePaths::locateLocal("data", "calligraplan/calligraplan_shell.rc")); actionCollection()->addAction(KStandardAction::New, "file_new", this, SLOT(slotFileNew())); actionCollection()->addAction(KStandardAction::Open, "file_open", this, SLOT(slotFileOpen())); d->recent = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); - connect(d->recent, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); + connect(d->recent, &KRecentFilesAction::recentListCleared, this, &KoMainWindow::saveRecentFiles); d->saveAction = actionCollection()->addAction(KStandardAction::Save, "file_save", this, SLOT(slotFileSave())); d->saveActionAs = actionCollection()->addAction(KStandardAction::SaveAs, "file_save_as", this, SLOT(slotFileSaveAs())); d->printAction = actionCollection()->addAction(KStandardAction::Print, "file_print", this, SLOT(slotFilePrint())); d->printActionPreview = actionCollection()->addAction(KStandardAction::PrintPreview, "file_print_preview", this, SLOT(slotFilePrintPreview())); d->exportPdf = new QAction(i18n("Print to PDF..."), this); d->exportPdf->setIcon(koIcon("application-pdf")); actionCollection()->addAction("file_export_pdf", d->exportPdf); - connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf())); + connect(d->exportPdf, &QAction::triggered, this, static_cast(&KoMainWindow::exportToPdf)); d->sendFileAction = actionCollection()->addAction(KStandardAction::Mail, "file_send_file", this, SLOT(slotEmailFile())); d->closeFile = actionCollection()->addAction(KStandardAction::Close, "file_close", this, SLOT(slotFileClose())); actionCollection()->addAction(KStandardAction::Quit, "file_quit", this, SLOT(slotFileQuit())); d->reloadFile = new QAction(i18n("Reload"), this); actionCollection()->addAction("file_reload_file", d->reloadFile); - connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile())); + connect(d->reloadFile, &QAction::triggered, this, &KoMainWindow::slotReloadFile); d->importFile = new QAction(koIcon("document-import"), i18n("Import..."), this); actionCollection()->addAction("file_import_file", d->importFile); - connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); + connect(d->importFile, &QAction::triggered, this, &KoMainWindow::slotImportFile); d->exportFile = new QAction(koIcon("document-export"), i18n("E&xport..."), this); actionCollection()->addAction("file_export_file", d->exportFile); - connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); + connect(d->exportFile, &QAction::triggered, this, &KoMainWindow::slotExportFile); #if 0 // encryption not supported d->encryptDocument = new QAction(i18n("En&crypt Document"), this); actionCollection()->addAction("file_encrypt_doc", d->encryptDocument); connect(d->encryptDocument, SIGNAL(triggered(bool)), this, SLOT(slotEncryptDocument())); #ifndef NDEBUG d->uncompressToDir = new QAction(i18n("&Uncompress to Directory"), this); actionCollection()->addAction("file_uncompress_doc", d->uncompressToDir); connect(d->uncompressToDir, SIGNAL(triggered(bool)), this, SLOT(slotUncompressToDir())); #endif #endif QAction *actionNewView = new QAction(koIcon("window-new"), i18n("&New View"), this); actionCollection()->addAction("view_newview", actionNewView); - connect(actionNewView, SIGNAL(triggered(bool)), this, SLOT(newView())); + connect(actionNewView, &QAction::triggered, this, &KoMainWindow::newView); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = new QAction(koIcon("document-properties"), i18n("Document Information"), this); actionCollection()->addAction("file_documentinfo", d->showDocumentInfo); - connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); + connect(d->showDocumentInfo, &QAction::triggered, this, &KoMainWindow::slotDocumentInfo); KStandardAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection()); KStandardAction::configureToolbars(this, SLOT(slotConfigureToolbars()), actionCollection()); d->showDocumentInfo->setEnabled(false); d->saveActionAs->setEnabled(false); d->reloadFile->setEnabled(false); d->importFile->setEnabled(true); // always enabled like File --> Open d->exportFile->setEnabled(false); d->saveAction->setEnabled(false); d->printAction->setEnabled(false); d->printActionPreview->setEnabled(false); d->sendFileAction->setEnabled(false); d->exportPdf->setEnabled(false); d->closeFile->setEnabled(false); #if 0 d->encryptDocument->setEnabled(false); #ifndef NDEBUG d->uncompressToDir->setEnabled(false); #endif #endif KToggleAction *fullscreenAction = new KToggleAction(koIcon("view-fullscreen"), i18n("Full Screen Mode"), this); actionCollection()->addAction("view_fullscreen", fullscreenAction); actionCollection()->setDefaultShortcut(fullscreenAction, QKeySequence::FullScreen); - connect(fullscreenAction, SIGNAL(toggled(bool)), this, SLOT(viewFullscreen(bool))); + connect(fullscreenAction, &QAction::toggled, this, &KoMainWindow::viewFullscreen); d->toggleDockers = new KToggleAction(i18n("Show Dockers"), this); d->toggleDockers->setChecked(true); actionCollection()->addAction("view_toggledockers", d->toggleDockers); - connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); + connect(d->toggleDockers, &QAction::toggled, this, &KoMainWindow::toggleDockersVisibility); d->toggleDockerTitleBars = new KToggleAction(i18nc("@action:inmenu", "Show Docker Titlebars"), this); KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface"); d->toggleDockerTitleBars->setChecked(configGroupInterface.readEntry("ShowDockerTitleBars", true)); d->toggleDockerTitleBars->setVisible(false); actionCollection()->addAction("view_toggledockertitlebars", d->toggleDockerTitleBars); - connect(d->toggleDockerTitleBars, SIGNAL(toggled(bool)), SLOT(showDockerTitleBars(bool))); + connect(d->toggleDockerTitleBars, &QAction::toggled, this, &KoMainWindow::showDockerTitleBars); d->dockWidgetMenu = new KActionMenu(i18n("Dockers"), this); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); d->dockWidgetMenu->setVisible(false); d->dockWidgetMenu->setDelayed(false); // Load list of recent files KSharedConfigPtr configPtr = componentData.config(); d->recent->loadEntries(configPtr->group("RecentFiles")); createMainwindowGUI(); d->mainWindowGuiIsBuilt = true; // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QApplication::desktop()->availableGeometry(scnum); // if the desktop is virtual then use virtual screen size if (QApplication::desktop()->isVirtualDesktop()) { desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen()); desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum)); } quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to componensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } restoreState(QByteArray::fromBase64(cfg.readEntry("ko_windowstate", QByteArray()))); } void KoMainWindow::setNoCleanup(bool noCleanup) { d->noCleanup = noCleanup; } KoMainWindow::~KoMainWindow() { KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); cfg.writeEntry("ko_geometry", saveGeometry().toBase64()); cfg.writeEntry("ko_windowstate", saveState().toBase64()); // The doc and view might still exist (this is the case when closing the window) if (d->rootPart) d->rootPart->removeMainWindow(this); if (d->partToOpen) { d->partToOpen->removeMainWindow(this); delete d->partToOpen; } // safety first ;) setActivePart(0, 0); if (d->rootViews.indexOf(d->activeView) == -1) { delete d->activeView; d->activeView = 0; } while (!d->rootViews.isEmpty()) { delete d->rootViews.takeFirst(); } if(d->noCleanup) return; // We have to check if this was a root document. // This has to be checked from queryClose, too :) if (d->rootPart && d->rootPart->viewCount() == 0) { //debugMain <<"Destructor. No more views, deleting old doc" << d->rootDoc; delete d->rootDocument; } delete d; } void KoMainWindow::setRootDocument(KoDocument *doc, KoPart *part, bool deletePrevious) { if (d->rootDocument == doc) return; if (d->partToOpen && d->partToOpen->document() != doc) { d->partToOpen->removeMainWindow(this); if (deletePrevious) delete d->partToOpen; } d->partToOpen = 0; //debugMain <<"KoMainWindow::setRootDocument this =" << this <<" doc =" << doc; QList oldRootViews = d->rootViews; d->rootViews.clear(); KoDocument *oldRootDoc = d->rootDocument; KoPart *oldRootPart = d->rootPart; if (oldRootDoc) { oldRootDoc->disconnect(this); oldRootPart->removeMainWindow(this); // Hide all dockwidgets and remember their old state d->dockWidgetVisibilityMap.clear(); foreach(QDockWidget* dockWidget, d->dockWidgetsMap) { d->dockWidgetVisibilityMap.insert(dockWidget, dockWidget->isVisible()); dockWidget->setVisible(false); } d->toggleDockerTitleBars->setVisible(false); d->dockWidgetMenu->setVisible(false); } d->rootDocument = doc; // XXX remove this after the splitting if (!part && doc) { d->rootPart = doc->documentPart(); } else { d->rootPart = part; } if (doc) { d->toggleDockerTitleBars->setVisible(true); d->dockWidgetMenu->setVisible(true); d->m_registeredPart = d->rootPart.data(); KoView *view = d->rootPart->createView(doc, this); setCentralWidget(view); d->rootViews.append(view); view->show(); view->setFocus(); // The addMainWindow has been done already if using openUrl if (!d->rootPart->mainWindows().contains(this)) { d->rootPart->addMainWindow(this); } } bool enable = d->rootDocument != 0 ? true : false; d->showDocumentInfo->setEnabled(enable); d->saveAction->setEnabled(enable); d->saveActionAs->setEnabled(enable); d->importFile->setEnabled(enable); d->exportFile->setEnabled(enable); #if 0 d->encryptDocument->setEnabled(enable); #ifndef NDEBUG d->uncompressToDir->setEnabled(enable); #endif #endif d->printAction->setEnabled(enable); d->printActionPreview->setEnabled(enable); d->sendFileAction->setEnabled(enable); d->exportPdf->setEnabled(enable); d->closeFile->setEnabled(enable); updateCaption(); setActivePart(d->rootPart, doc ? d->rootViews.first() : 0); emit restoringDone(); while(!oldRootViews.isEmpty()) { delete oldRootViews.takeFirst(); } if (oldRootPart && oldRootPart->viewCount() == 0) { //debugMain <<"No more views, deleting old doc" << oldRootDoc; oldRootDoc->clearUndoHistory(); if(deletePrevious) delete oldRootDoc; } if (doc && !d->dockWidgetVisibilityMap.isEmpty()) { foreach(QDockWidget* dockWidget, d->dockWidgetsMap) { dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget)); } } if (!d->rootDocument) { statusBar()->setVisible(false); } else { #ifdef Q_OS_MAC statusBar()->setMaximumHeight(28); #endif - connect(d->rootDocument, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified(QString,bool))); + connect(d->rootDocument, &KoDocument::titleModified, this, &KoMainWindow::slotDocumentTitleModified); } } void KoMainWindow::updateReloadFileAction(KoDocument *doc) { d->reloadFile->setEnabled(doc && !doc->url().isEmpty()); } void KoMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KoMainWindow::addRecentURL(const QUrl &url) { debugMain << "url=" << url.toDisplayString(); // Add entry to recent documents list // (call coming from KoDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = QStandardPaths::standardLocations(QStandardPaths::TempLocation); foreach (const QString &tmpDir, tmpDirs) { if (path.startsWith(tmpDir)) { ok = false; // it's in the tmp resource break; } } if (ok) { KRecentDocument::add(QUrl::fromLocalFile(path)); KRecentDirs::add(":OpenDialog", QFileInfo(path).dir().canonicalPath()); } } else { KRecentDocument::add(url.adjusted(QUrl::StripTrailingSlash)); } if (ok) { d->recent->addUrl(url); } saveRecentFiles(); #ifdef HAVE_KACTIVITIES if (!d->activityResource) { d->activityResource = new KActivities::ResourceInstance(winId(), this); } d->activityResource->setUri(url); #endif } } void KoMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = componentData().config(); debugMain << this << " Saving recent files list into config. componentData()=" << componentData().componentName(); d->recent->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start foreach(KMainWindow* window, KMainWindow::memberList()) static_cast(window)->reloadRecentFileList(); } void KoMainWindow::reloadRecentFileList() { KSharedConfigPtr config = componentData().config(); d->recent->loadEntries(config->group("RecentFiles")); } KoPart* KoMainWindow::createPart() const { KoDocumentEntry entry = KoDocumentEntry::queryByMimeType(d->nativeMimeType); QString errorMsg; KoPart *part = entry.createKoPart(&errorMsg); if (!part || !errorMsg.isEmpty()) { return 0; } return part; } void KoMainWindow::updateCaption() { debugMain; if (!d->rootDocument) { updateCaption(QString(), false); } else { QString caption( d->rootDocument->caption() ); if (d->readOnly) { caption += ' ' + i18n("(write protected)"); } updateCaption(caption, d->rootDocument->isModified()); if (!rootDocument()->url().fileName().isEmpty()) d->saveAction->setToolTip(i18n("Save as %1", d->rootDocument->url().fileName())); else d->saveAction->setToolTip(i18n("Save")); } } void KoMainWindow::updateCaption(const QString & caption, bool mod) { debugMain << caption << "," << mod; #ifdef PLAN_ALPHA setCaption(QString("ALPHA %1: %2").arg(PLAN_ALPHA).arg(caption), mod); return; #endif #ifdef PLAN_BETA setCaption(QString("BETA %1: %2").arg(PLAN_BETA).arg(caption), mod); return; #endif #ifdef PLAN_RC setCaption(QString("RELEASE CANDIDATE %1: %2").arg(PLAN_RC).arg(caption), mod); return; #endif setCaption(caption, mod); } KoDocument *KoMainWindow::rootDocument() const { return d->rootDocument; } KoView *KoMainWindow::rootView() const { if (d->rootViews.indexOf(d->activeView) != -1) return d->activeView; return d->rootViews.first(); } bool KoMainWindow::openDocument(const QUrl &url) { if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) { KMessageBox::error(0, i18n("The file %1 does not exist.", url.url())); d->recent->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url); } bool KoMainWindow::openDocument(KoPart *newPart, const QUrl &url) { // the part always has a document; the document doesn't know about the part. KoDocument *newdoc = newPart->document(); if (!KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0)) { newdoc->initEmpty(); //create an empty document setRootDocument(newdoc, newPart); newdoc->setUrl(url); QMimeType mime = QMimeDatabase().mimeTypeForUrl(url); QString mimetype = (!mime.isValid() || mime.isDefault()) ? newdoc->nativeFormatMimeType() : mime.name(); newdoc->setMimeTypeAfterLoading(mimetype); updateCaption(); return true; } return openDocumentInternal(url, newPart, newdoc); } bool KoMainWindow::openDocumentInternal(const QUrl &url, KoPart *newpart, KoDocument *newdoc) { debugMain << url.url(); if (!newpart) newpart = createPart(); if (!newpart) return false; if (!newdoc) newdoc = newpart->document(); d->firstTime = true; - connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); - connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); - connect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); + connect(newdoc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress); + connect(newdoc, &KoDocument::completed, this, &KoMainWindow::slotLoadCompleted); + connect(newdoc, &KoDocument::canceled, this, &KoMainWindow::slotLoadCanceled); d->openingDocument = true; newpart->addMainWindow(this); // used by openUrl bool openRet = (!isImporting()) ? newdoc->openUrl(url) : newdoc->importDocument(url); if (!openRet) { newpart->removeMainWindow(this); delete newdoc; delete newpart; d->openingDocument = false; return false; } updateReloadFileAction(newdoc); KFileItem file(url, newdoc->mimeType(), KFileItem::Unknown); if (!file.isWritable()) { setReadWrite(false); } return true; } // Separate from openDocument to handle async loading (remote URLs) void KoMainWindow::slotLoadCompleted() { debugMain; KoDocument *newdoc = qobject_cast(sender()); KoPart *newpart = newdoc->documentPart(); if (d->rootDocument && d->rootDocument->isEmpty()) { // Replace current empty document setRootDocument(newdoc); } else if (d->rootDocument && !d->rootDocument->isEmpty()) { // Open in a new main window // (Note : could create the main window first and the doc next for this // particular case, that would give a better user feedback...) KoMainWindow *s = newpart->createMainWindow(); s->show(); newpart->removeMainWindow(this); s->setRootDocument(newdoc, newpart); } else { // We had no document, set the new one setRootDocument(newdoc); } slotProgress(-1); - disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); - disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); - disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); + disconnect(newdoc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress); + disconnect(newdoc, &KoDocument::completed, this, &KoMainWindow::slotLoadCompleted); + disconnect(newdoc, &KoDocument::canceled, this, &KoMainWindow::slotLoadCanceled); d->openingDocument = false; emit loadCompleted(); } void KoMainWindow::slotLoadCanceled(const QString & errMsg) { debugMain; if (!errMsg.isEmpty()) // empty when canceled by user KMessageBox::error(this, errMsg); // ... can't delete the document, it's the one who emitted the signal... KoDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); - disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); - disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); - disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); + disconnect(doc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress); + disconnect(doc, &KoDocument::completed, this, &KoMainWindow::slotLoadCompleted); + disconnect(doc, &KoDocument::canceled, this, &KoMainWindow::slotLoadCanceled); d->openingDocument = false; emit loadCanceled(); } void KoMainWindow::slotSaveCanceled(const QString &errMsg) { debugMain; if (!errMsg.isEmpty()) // empty when canceled by user KMessageBox::error(this, errMsg); slotSaveCompleted(); } void KoMainWindow::slotSaveCompleted() { debugMain; KoDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); - disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); - disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); - disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); + disconnect(doc, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress); + disconnect(doc, &KoDocument::completed, this, &KoMainWindow::slotSaveCompleted); + disconnect(doc, &KoDocument::canceled, this, &KoMainWindow::slotSaveCanceled); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } // returns true if we should save, false otherwise. bool KoMainWindow::exportConfirmation(const QByteArray &outputFormat) { KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()); if (!group.readEntry("WantExportConfirmation", true)) { return true; } QMimeType mime = QMimeDatabase().mimeTypeForName(outputFormat); QString comment = mime.isValid() ? mime.comment() : i18n("%1 (unknown file type)", QString::fromLatin1(outputFormat)); // Warn the user int ret; if (!isExporting()) { // File --> Save ret = KMessageBox::warningContinueCancel ( this, i18n("Saving as a %1 may result in some loss of formatting." "

Do you still want to save in this format?", QString("%1").arg(comment)), // in case we want to remove the bold later i18n("Confirm Save"), KStandardGuiItem::save(), KStandardGuiItem::cancel(), "NonNativeSaveConfirmation" ); } else { // File --> Export ret = KMessageBox::warningContinueCancel ( this, i18n("Exporting as a %1 may result in some loss of formatting." "

Do you still want to export to this format?", QString("%1").arg(comment)), // in case we want to remove the bold later i18n("Confirm Export"), KGuiItem(i18n("Export")), KStandardGuiItem::cancel(), "NonNativeExportConfirmation" // different to the one used for Save (above) ); } return (ret == KMessageBox::Continue); } bool KoMainWindow::saveDocument(bool saveas, bool silent, int specialOutputFlag) { if (!d->rootDocument || !d->rootPart) { return true; } bool reset_url; if (d->rootDocument->url().isEmpty()) { emit saveDialogShown(); reset_url = true; saveas = true; } else { reset_url = false; } - connect(d->rootDocument, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); - connect(d->rootDocument, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); - connect(d->rootDocument, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); + connect(d->rootDocument, &KoDocument::sigProgress, this, &KoMainWindow::slotProgress); + connect(d->rootDocument, &KoDocument::completed, this, &KoMainWindow::slotSaveCompleted); + connect(d->rootDocument, &KoDocument::canceled, this, &KoMainWindow::slotSaveCanceled); QUrl oldURL = d->rootDocument->url(); QString oldFile = d->rootDocument->localFilePath(); QByteArray _native_format = d->rootDocument->nativeFormatMimeType(); QByteArray oldOutputFormat = d->rootDocument->outputMimeType(); int oldSpecialOutputFlag = d->rootDocument->specialOutputFlag(); QUrl suggestedURL = d->rootDocument->url(); QStringList mimeFilter; QMimeType mime = QMimeDatabase().mimeTypeForName(_native_format); if (!mime.isValid()) // QT5TODO: find if there is no better way to get an object for the default type mime = QMimeDatabase().mimeTypeForName(QStringLiteral("application/octet-stream")); if (specialOutputFlag) mimeFilter = mime.globPatterns(); else mimeFilter = KoFilterManager::mimeFilter(_native_format, KoFilterManager::Export, d->rootDocument->extraNativeMimeTypes()); if (oldOutputFormat.isEmpty() && !d->rootDocument->url().isEmpty()) { // Not been saved yet, but there is a default url so open dialog with this url if (suggestedURL.path() == suggestedURL.fileName()) { // only a filename has been given, so add the default dir KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString path = group.readEntry("SaveDocument"); path += '/' + suggestedURL.fileName(); suggestedURL.setPath(path); suggestedURL.setScheme("file"); } saveas = true; debugMain << "newly created doc, default file name:" << d->rootDocument->url() << "save to:" << suggestedURL; } else if (!mimeFilter.contains(oldOutputFormat) && !isExporting()) { debugMain << "no export filter for" << oldOutputFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = suggestedURL.fileName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name int c = suggestedFilename.lastIndexOf('.'); const QString ext = mime.preferredSuffix(); if (!ext.isEmpty()) { if (c < 0) suggestedFilename += ext; else suggestedFilename = suggestedFilename.left(c) + ext; } else { // current filename extension wrong anyway if (c > 0) { // this assumes that a . signifies an extension, not just a . suggestedFilename = suggestedFilename.left(c); } } suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (d->rootDocument->url().isEmpty() || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveDocument"); dialog.setCaption(i18n("untitled")); dialog.setDefaultDir((isExporting() && !d->lastExportUrl.isEmpty()) ? d->lastExportUrl.toLocalFile() : suggestedURL.toLocalFile()); dialog.setMimeTypeFilters(mimeFilter); QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { QMimeType mime = QMimeDatabase().mimeTypeForName(_native_format); fn.append(mime.preferredSuffix()); newURL = QUrl::fromLocalFile(fn); } } QByteArray outputFormat = _native_format; if (!specialOutputFlag) { QMimeType mime = QMimeDatabase().mimeTypeForUrl(newURL); outputFormat = mime.name().toLatin1(); } if (!isExporting()) justChangingFilterOptions = (newURL == d->rootDocument->url()) && (outputFormat == d->rootDocument->mimeType()) && (specialOutputFlag == oldSpecialOutputFlag); else justChangingFilterOptions = (newURL == d->lastExportUrl) && (outputFormat == d->lastExportedFormat) && (specialOutputFlag == d->lastExportSpecialOutputFlag); bool bOk = true; if (newURL.isEmpty()) { bOk = false; } // adjust URL before doing checks on whether the file exists. if (specialOutputFlag) { QString fileName = newURL.fileName(); if ( specialOutputFlag== KoDocument::SaveAsDirectoryStore) { // Do nothing } #if 0 else if (specialOutputFlag == KoDocument::SaveEncrypted) { int dot = fileName.lastIndexOf('.'); QString ext = mime.preferredSuffix(); if (!ext.isEmpty()) { if (dot < 0) fileName += ext; else fileName = fileName.left(dot) + ext; } else { // current filename extension wrong anyway if (dot > 0) fileName = fileName.left(dot); } newURL = newURL.adjusted(QUrl::RemoveFilename); newURL.setPath(newURL.path() + fileName); } #endif } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions || d->rootDocument->confirmNonNativeSave(isExporting())) { if (!d->rootDocument->isNativeFormat(outputFormat)) wantToSave = exportConfirmation(outputFormat); } if (wantToSave) { // // Note: // If the user is stupid enough to Export to the current URL, // we do _not_ change this operation into a Save As. Reasons // follow: // // 1. A check like "isExporting() && oldURL == newURL" // doesn't _always_ work on case-insensitive filesystems // and inconsistent behaviour is bad. // 2. It is probably not a good idea to change d->rootDocument->mimeType // and friends because the next time the user File/Save's, // (not Save As) they won't be expecting that they are // using their File/Export settings // // As a bad side-effect of this, the modified flag will not // be updated and it is possible that what is currently on // their screen is not what is stored on disk (through loss // of formatting). But if you are dumb enough to change // mimetype but not the filename, then arguably, _you_ are // the "bug" :) // // - Clarence // d->rootDocument->setOutputMimeType(outputFormat, specialOutputFlag); if (!isExporting()) { // Save As ret = d->rootDocument->saveAs(newURL); if (ret) { debugMain << "Successful Save As!"; addRecentURL(newURL); setReadWrite(true); } else { debugMain << "Failed Save As!"; d->rootDocument->setUrl(oldURL); d->rootDocument->setLocalFilePath(oldFile); d->rootDocument->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag); } } else { // Export ret = d->rootDocument->exportDocument(newURL); if (ret) { // a few file dialog convenience things d->lastExportUrl = newURL; d->lastExportedFormat = outputFormat; d->lastExportSpecialOutputFlag = specialOutputFlag; } // always restore output format d->rootDocument->setOutputMimeType(oldOutputFormat, oldSpecialOutputFlag); } if (silent) // don't let the document change the window caption d->rootDocument->setTitleModified(); } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving bool needConfirm = d->rootDocument->confirmNonNativeSave(false) && !d->rootDocument->isNativeFormat(oldOutputFormat); if (!needConfirm || (needConfirm && exportConfirmation(oldOutputFormat /* not so old :) */)) ) { // be sure d->rootDocument has the correct outputMimeType! if (isExporting() || d->rootDocument->isModified() || d->rootDocument->alwaysAllowSaving()) { ret = d->rootDocument->save(); } if (!ret) { debugMain << "Failed Save!"; d->rootDocument->setUrl(oldURL); d->rootDocument->setLocalFilePath(oldFile); } } else ret = false; } if (!ret && reset_url) d->rootDocument->resetURL(); //clean the suggested filename as the save dialog was rejected updateReloadFileAction(d->rootDocument); updateCaption(); return ret; } void KoMainWindow::closeEvent(QCloseEvent *e) { // If we are in the process of opening a new document, rootDocument() may not have been set yet, // so we must prevent closing to avoid crash. if(d->openingDocument || (rootDocument() && rootDocument()->isLoading())) { e->setAccepted(false); return; } if (queryClose()) { d->deferredClosingEvent = e; if (!d->m_dockerStateBeforeHiding.isEmpty()) { restoreState(d->m_dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); if(d->noCleanup) return; setRootDocument(0); if (!d->dockWidgetVisibilityMap.isEmpty()) { // re-enable dockers for persistency foreach(QDockWidget* dockWidget, d->dockWidgetsMap) dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget)); } } else { e->setAccepted(false); } } void KoMainWindow::saveWindowSettings() { KSharedConfigPtr config = componentData().config(); if (d->windowSizeDirty ) { // Save window size into the config file of our componentData // TODO: check if this is ever read again, seems lost over the years debugMain; KConfigGroup mainWindowConfigGroup = config->group("MainWindow"); KWindowConfig::saveWindowSize(windowHandle(), mainWindowConfigGroup); config->sync(); d->windowSizeDirty = false; } if ( rootDocument() && d->rootPart) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()); //debugMain <<"KoMainWindow::closeEvent -> saveMainWindowSettings rootdoc's componentData=" << d->rootPart->componentData().componentName(); saveMainWindowSettings(group); // Save collapsable state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KoMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } bool KoMainWindow::queryClose() { if (rootDocument() == 0) return true; //debugMain <<"KoMainWindow::queryClose() viewcount=" << rootDocument()->viewCount() // << " mainWindowCount=" << rootDocument()->mainWindowCount() << endl; if (!d->forQuit && d->rootPart && d->rootPart->mainwindowCount() > 1) // there are more open, and we are closing just one, so no problem for closing return true; // main doc + internally stored child documents if (d->rootDocument->isModified()) { QString name; if (rootDocument()->documentInfo()) { name = rootDocument()->documentInfo()->aboutInfo("title"); } if (name.isEmpty()) name = rootDocument()->url().fileName(); if (name.isEmpty()) name = i18n("Untitled"); int res = KMessageBox::warningYesNoCancel(this, i18n("

The document '%1' has been modified.

Do you want to save it?

", name), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard()); switch (res) { case KMessageBox::Yes : { bool isNative = (d->rootDocument->outputMimeType() == d->rootDocument->nativeFormatMimeType()); if (!saveDocument(!isNative)) return false; break; } case KMessageBox::No : rootDocument()->removeAutoSaveFiles(); rootDocument()->setModified(false); // Now when queryClose() is called by closeEvent it won't do anything. break; default : // case KMessageBox::Cancel : return false; } } return true; } // Helper method for slotFileNew and slotFileClose void KoMainWindow::chooseNewDocument(InitDocFlags initDocFlags) { KoDocument* doc = rootDocument(); KoPart *newpart = createPart(); KoDocument *newdoc = newpart->document(); qInfo()<isEmpty())) { KoMainWindow *s = newpart->createMainWindow(); s->show(); newpart->addMainWindow(s); newpart->showStartUpWidget(s); return; } if (doc) { setRootDocument(0); if(d->rootDocument) d->rootDocument->clearUndoHistory(); delete d->rootDocument; d->rootDocument = 0; } newpart->addMainWindow(this); newpart->showStartUpWidget(this); } void KoMainWindow::slotFileNew() { chooseNewDocument(InitDocFileNew); } void KoMainWindow::slotFileOpen() { QUrl url; if (!isImporting()) { KoFileDialog dialog(this, KoFileDialog::OpenFile, "OpenDocument"); dialog.setCaption(i18n("Open Document")); dialog.setDefaultDir(qApp->applicationName().contains("karbon") ? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) : QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); dialog.setMimeTypeFilters(koApp->mimeFilter(KoFilterManager::Import)); dialog.setHideNameFilterDetailsOption(); url = QUrl::fromUserInput(dialog.filename()); } else { KoFileDialog dialog(this, KoFileDialog::ImportFile, "OpenDocument"); dialog.setCaption(i18n("Import Document")); dialog.setDefaultDir(qApp->applicationName().contains("karbon") ? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) : QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); dialog.setMimeTypeFilters(koApp->mimeFilter(KoFilterManager::Import)); dialog.setHideNameFilterDetailsOption(); url = QUrl::fromUserInput(dialog.filename()); } if (url.isEmpty()) return; (void) openDocument(url); } void KoMainWindow::slotFileOpenRecent(const QUrl & url) { // Create a copy, because the original QUrl in the map of recent files in // KRecentFilesAction may get deleted. (void) openDocument(QUrl(url)); } void KoMainWindow::slotFileSave() { if (saveDocument()) emit documentSaved(); } void KoMainWindow::slotFileSaveAs() { if (saveDocument(true)) emit documentSaved(); } void KoMainWindow::slotEncryptDocument() { if (saveDocument(false, false, KoDocument::SaveEncrypted)) emit documentSaved(); } void KoMainWindow::slotUncompressToDir() { if (saveDocument(true, false, KoDocument::SaveAsDirectoryStore)) emit documentSaved(); } void KoMainWindow::slotDocumentInfo() { if (!rootDocument()) return; KoDocumentInfo *docInfo = rootDocument()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->rootDocument->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { rootDocument()->setModified(false); } else { rootDocument()->setModified(true); } rootDocument()->setTitleModified(); } delete dlg; } void KoMainWindow::slotFileClose() { if (queryClose()) { saveWindowSettings(); setRootDocument(0); // don't delete this main window when deleting the document if(d->rootDocument) d->rootDocument->clearUndoHistory(); delete d->rootDocument; d->rootDocument = 0; chooseNewDocument(InitDocFileClose); } } void KoMainWindow::slotFileQuit() { close(); } void KoMainWindow::slotFilePrint() { if (!rootView()) return; KoPrintJob *printJob = rootView()->createPrintJob(); if (printJob == 0) return; d->applyDefaultSettings(printJob->printer()); QPrintDialog *printDialog = rootView()->createPrintDialog( printJob, this ); if (printDialog && printDialog->exec() == QDialog::Accepted) printJob->startPrinting(KoPrintJob::DeleteWhenDone); else delete printJob; delete printDialog; } void KoMainWindow::slotFilePrintPreview() { if (!rootView()) return; KoPrintJob *printJob = rootView()->createPrintJob(); if (printJob == 0) return; /* Sets the startPrinting() slot to be blocking. The Qt print-preview dialog requires the printing to be completely blocking and only return when the full document has been printed. By default the KoPrintingDialog is non-blocking and multithreading, setting blocking to true will allow it to be used in the preview dialog */ printJob->setProperty("blocking", true); QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this); printJob->setParent(preview); // will take care of deleting the job - connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); + connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); // clazy:exclude=old-style-connect preview->exec(); delete preview; } +KoPrintJob* KoMainWindow::exportToPdf() +{ + return exportToPdf(QString()); +} + KoPrintJob* KoMainWindow::exportToPdf(const QString &_pdfFileName) { if (!rootView()) return 0; KoPageLayout pageLayout; pageLayout = rootView()->pageLayout(); QString pdfFileName = _pdfFileName; if (pdfFileName.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString defaultDir = group.readEntry("SavePdfDialog"); if (defaultDir.isEmpty()) defaultDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QUrl startUrl = QUrl::fromLocalFile(defaultDir); KoDocument* pDoc = rootDocument(); /** if document has a file name, take file name and replace extension with .pdf */ if (pDoc && pDoc->url().isValid()) { startUrl = pDoc->url(); QString fileName = startUrl.fileName(); fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" ); startUrl = startUrl.adjusted(QUrl::RemoveFilename); startUrl.setPath(startUrl.path() + fileName ); } QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout)); layoutDlg->setWindowModality(Qt::WindowModal); if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) { delete layoutDlg; return 0; } pageLayout = layoutDlg->pageLayout(); delete layoutDlg; qInfo()<url()<url().isValid()<createPdfPrintJob(); if (printJob == 0) return 0; if (isHidden()) { printJob->setProperty("noprogressdialog", true); } d->applyDefaultSettings(printJob->printer()); // TODO for remote files we have to first save locally and then upload. printJob->printer().setOutputFileName(pdfFileName); printJob->printer().setColorMode(QPrinter::Color); if (pageLayout.format == KoPageFormat::CustomSize) { printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter); } else { printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format)); } switch (pageLayout.orientation) { case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break; case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break; } printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter); //before printing check if the printer can handle printing if (!printJob->canPrint()) { KMessageBox::error(this, i18n("Cannot export to the specified file")); } printJob->startPrinting(KoPrintJob::DeleteWhenDone); rootView()->setPageLayout(pageLayout); return printJob; } void KoMainWindow::slotConfigureKeys() { QAction* undoAction=0; QAction* redoAction=0; QString oldUndoText; QString oldRedoText; if(currentView()) { //The undo/redo action text is "undo" + command, replace by simple text while inside editor undoAction = currentView()->actionCollection()->action("edit_undo"); redoAction = currentView()->actionCollection()->action("edit_redo"); oldUndoText = undoAction->text(); oldRedoText = redoAction->text(); undoAction->setText(i18n("Undo")); redoAction->setText(i18n("Redo")); } guiFactory()->configureShortcuts(); if(currentView()) { undoAction->setText(oldUndoText); redoAction->setText(oldRedoText); } emit keyBindingsChanged(); } void KoMainWindow::slotConfigureToolbars() { if (rootDocument()) { KConfigGroup componentConfigGroup = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()); saveMainWindowSettings(componentConfigGroup); } KEditToolBar edit(factory(), this); - connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); + connect(&edit, &KEditToolBar::newToolBarConfig, this, &KoMainWindow::slotNewToolbarConfig); (void) edit.exec(); } void KoMainWindow::slotNewToolbarConfig() { if (rootDocument()) { KConfigGroup componentConfigGroup = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()); applyMainWindowSettings(componentConfigGroup); } KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); } void KoMainWindow::slotToolbarToggled(bool toggle) { //debugMain <<"KoMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) bar->show(); else bar->hide(); if (rootDocument()) { KConfigGroup componentConfigGroup = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()); saveMainWindowSettings(componentConfigGroup); } } else warnMain << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } bool KoMainWindow::toolbarIsVisible(const char *tbName) { QWidget *tb = toolBar(tbName); return !tb->isHidden(); } void KoMainWindow::showToolbar(const char * tbName, bool shown) { QWidget * tb = toolBar(tbName); if (!tb) { warnMain << "KoMainWindow: toolbar " << tbName << " not found."; return; } if (shown) tb->show(); else tb->hide(); // Update the action appropriately foreach(QAction* action, d->toolbarList) { if (action->objectName() != tbName) { //debugMain <<"KoMainWindow::showToolbar setChecked" << shown; static_cast(action)->setChecked(shown); break; } } } void KoMainWindow::viewFullscreen(bool fullScreen) { if (fullScreen) { window()->setWindowState(window()->windowState() | Qt::WindowFullScreen); // set } else { window()->setWindowState(window()->windowState() & ~Qt::WindowFullScreen); // reset } } void KoMainWindow::slotProgress(int value) { QMutexLocker locker(&d->progressMutex); debugMain << value; if (value <= -1 || value >= 100) { if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; } d->firstTime = true; return; } if (d->firstTime || !d->progress) { // The statusbar might not even be created yet. // So check for that first, and create it if necessary QStatusBar *bar = findChild(); if (!bar) { statusBar()->show(); QApplication::sendPostedEvents(this, QEvent::ChildAdded); } if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; } d->progress = new QProgressBar(statusBar()); d->progress->setMaximumHeight(statusBar()->fontMetrics().height()); d->progress->setRange(0, 100); statusBar()->addPermanentWidget(d->progress); d->progress->show(); d->firstTime = false; } if (!d->progress.isNull()) { d->progress->setValue(value); } locker.unlock(); qApp->processEvents(); } void KoMainWindow::setMaxRecentItems(uint _number) { d->recent->setMaxItems(_number); } void KoMainWindow::slotEmailFile() { if (!rootDocument()) return; // Subject = Document file name // Attachment = The current file // Message Body = The current document in HTML export? <-- This may be an option. QString theSubject; QStringList urls; QString fileURL; if (rootDocument()->url().isEmpty() || rootDocument()->isModified()) { //Save the file as a temporary file bool const tmp_modified = rootDocument()->isModified(); QUrl const tmp_url = rootDocument()->url(); QByteArray const tmp_mimetype = rootDocument()->outputMimeType(); // a little open, close, delete dance to make sure we have a nice filename // to use, but won't block windows from creating a new file with this name. QTemporaryFile *tmpfile = new QTemporaryFile(); tmpfile->open(); QString fileName = tmpfile->fileName(); tmpfile->close(); delete tmpfile; QUrl u = QUrl::fromLocalFile(fileName); rootDocument()->setUrl(u); rootDocument()->setModified(true); rootDocument()->setOutputMimeType(rootDocument()->nativeFormatMimeType()); saveDocument(false, true); fileURL = fileName; theSubject = i18n("Document"); urls.append(fileURL); rootDocument()->setUrl(tmp_url); rootDocument()->setModified(tmp_modified); rootDocument()->setOutputMimeType(tmp_mimetype); } else { fileURL = rootDocument()->url().url(); theSubject = i18n("Document - %1", rootDocument()->url().fileName()); urls.append(fileURL); } debugMain << "(" << fileURL << ")"; if (!fileURL.isEmpty()) { KToolInvocation::invokeMailer(QString(), QString(), QString(), theSubject, QString(), //body QString(), urls); // attachments } } void KoMainWindow::slotReloadFile() { KoDocument* pDoc = rootDocument(); if (!pDoc || pDoc->url().isEmpty() || !pDoc->isModified()) return; bool bOk = KMessageBox::questionYesNo(this, i18n("You will lose all changes made since your last save\n" "Do you want to continue?"), i18n("Warning")) == KMessageBox::Yes; if (!bOk) return; QUrl url = pDoc->url(); if (!pDoc->isEmpty()) { saveWindowSettings(); setRootDocument(0); // don't delete this main window when deleting the document if(d->rootDocument) d->rootDocument->clearUndoHistory(); delete d->rootDocument; d->rootDocument = 0; } openDocument(url); return; } void KoMainWindow::slotImportFile() { debugMain; d->isImporting = true; slotFileOpen(); d->isImporting = false; } void KoMainWindow::slotExportFile() { debugMain; d->isExporting = true; slotFileSaveAs(); d->isExporting = false; } bool KoMainWindow::isImporting() const { return d->isImporting; } bool KoMainWindow::isExporting() const { return d->isExporting; } void KoMainWindow::setPartToOpen(KoPart *part) { d->partToOpen = part; } KoComponentData KoMainWindow::componentData() const { return d->componentData; } QDockWidget* KoMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; qInfo()<id()<dockWidgetsMap; if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) return 0; d->dockWidgets.push_back(dockWidget); KoDockWidgetTitleBar *titleBar = 0; // Check if the dock widget is supposed to be collapsable if (!dockWidget->titleBarWidget()) { titleBar = new KoDockWidgetTitleBar(dockWidget); dockWidget->setTitleBarWidget(titleBar); titleBar->setCollapsable(factory->isCollapsable()); } dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } if (rootDocument()) { KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()).group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; } addDockWidget(side, dockWidget); if (dockWidget->features() & QDockWidget::DockWidgetClosable) { d->dockWidgetMenu->addAction(dockWidget->toggleViewAction()); if (!visible) dockWidget->hide(); } bool collapsed = factory->defaultCollapsed(); bool locked = false; if (rootDocument()) { KConfigGroup group = KSharedConfig::openConfig()->group(d->rootPart->componentData().componentName()).group("DockWidget " + factory->id()); collapsed = group.readEntry("Collapsed", collapsed); locked = group.readEntry("Locked", locked); } if (titleBar && collapsed) titleBar->setCollapsed(true); if (titleBar && locked) titleBar->setLocked(true); if (titleBar) { KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface"); titleBar->setVisible(configGroupInterface.readEntry("ShowDockerTitleBars", true)); } d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[ factory->id()]; } #ifdef Q_OS_MAC dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); - connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); + connect(dockWidget, &QDockWidget::dockLocationChanged, this, &KoMainWindow::forceDockTabFonts); return dockWidget; } void KoMainWindow::forceDockTabFonts() { QObjectList chis = children(); for (int i = 0; i < chis.size(); ++i) { if (chis.at(i)->inherits("QTabBar")) { ((QTabBar *)chis.at(i))->setFont(KoDockRegistry::dockFont()); } } } QList KoMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } /*QList KoMainWindow::canvasObservers() const { QList observers; foreach(QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } } return observers; }*/ void KoMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->m_dockerStateBeforeHiding = saveState(); foreach(QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->m_dockerStateBeforeHiding); } } KRecentFilesAction *KoMainWindow::recentAction() const { return d->recent; } KoView* KoMainWindow::currentView() const { // XXX if (d->activeView) { return d->activeView; } else if (!d->rootViews.isEmpty()) { return d->rootViews.first(); } return 0; } void KoMainWindow::newView() { Q_ASSERT((d != 0 && d->activeView && d->activePart && d->activeView->koDocument())); KoMainWindow *mainWindow = d->activePart->createMainWindow(); mainWindow->setRootDocument(d->activeView->koDocument(), d->activePart); mainWindow->show(); } void KoMainWindow::createMainwindowGUI() { if ( isHelpMenuEnabled() && !d->m_helpMenu ) { d->m_helpMenu = new KHelpMenu( this, componentData().aboutData(), true ); KActionCollection *actions = actionCollection(); QAction *helpContentsAction = d->m_helpMenu->action(KHelpMenu::menuHelpContents); QAction *whatsThisAction = d->m_helpMenu->action(KHelpMenu::menuWhatsThis); QAction *reportBugAction = d->m_helpMenu->action(KHelpMenu::menuReportBug); QAction *switchLanguageAction = d->m_helpMenu->action(KHelpMenu::menuSwitchLanguage); QAction *aboutAppAction = d->m_helpMenu->action(KHelpMenu::menuAboutApp); QAction *aboutKdeAction = d->m_helpMenu->action(KHelpMenu::menuAboutKDE); if (helpContentsAction) { actions->addAction(helpContentsAction->objectName(), helpContentsAction); } if (whatsThisAction) { actions->addAction(whatsThisAction->objectName(), whatsThisAction); } if (reportBugAction) { actions->addAction(reportBugAction->objectName(), reportBugAction); } if (switchLanguageAction) { actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); } if (aboutAppAction) { actions->addAction(aboutAppAction->objectName(), aboutAppAction); } if (aboutKdeAction) { actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); } } QString f = xmlFile(); setXMLFile( QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("ui/ui_standards.rc")) ); if ( !f.isEmpty() ) setXMLFile( f, true ); else { QString auto_file( componentData().componentName() + "ui.rc" ); setXMLFile( auto_file, true ); } guiFactory()->addClient( this ); } // PartManager void KoMainWindow::removePart( KoPart *part ) { if (d->m_registeredPart.data() != part) { return; } d->m_registeredPart = 0; if ( part == d->m_activePart ) { setActivePart(0, 0); } } void KoMainWindow::setActivePart(KoPart *part, QWidget *widget ) { if (part && d->m_registeredPart.data() != part) { warnMain << "trying to activate a non-registered part!" << part->objectName(); return; // don't allow someone call setActivePart with a part we don't know about } // don't activate twice if ( d->m_activePart && part && d->m_activePart == part && (!widget || d->m_activeWidget == widget) ) return; KoPart *oldActivePart = d->m_activePart; QWidget *oldActiveWidget = d->m_activeWidget; d->m_activePart = part; d->m_activeWidget = widget; if (oldActivePart) { KoPart *savedActivePart = part; QWidget *savedActiveWidget = widget; if ( oldActiveWidget ) { - disconnect( oldActiveWidget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestroyed()) ); + disconnect( oldActiveWidget, &QObject::destroyed, this, &KoMainWindow::slotWidgetDestroyed ); } d->m_activePart = savedActivePart; d->m_activeWidget = savedActiveWidget; } if (d->m_activePart && d->m_activeWidget ) { - connect( d->m_activeWidget, SIGNAL(destroyed()), this, SLOT(slotWidgetDestroyed()) ); + connect( d->m_activeWidget, &QObject::destroyed, this, &KoMainWindow::slotWidgetDestroyed ); } // Set the new active instance in KGlobal // KGlobal::setActiveComponent(d->m_activePart ? d->m_activePart->componentData() : KGlobal::mainComponent()); // old slot called from part manager KoPart *newPart = static_cast(d->m_activePart.data()); if (d->activePart && d->activePart == newPart) { //debugMain <<"no need to change the GUI"; return; } KXMLGUIFactory *factory = guiFactory(); if (d->activeView) { factory->removeClient(d->activeView); unplugActionList("toolbarlist"); qDeleteAll(d->toolbarList); d->toolbarList.clear(); } if (!d->mainWindowGuiIsBuilt) { createMainwindowGUI(); } if (newPart && d->m_activeWidget && d->m_activeWidget->inherits("KoView")) { d->activeView = qobject_cast(d->m_activeWidget); d->activeView->actionCollection()->addAction("view_newview", actionCollection()->action("view_newview")); d->activePart = newPart; //debugMain <<"new active part is" << d->activePart; factory->addClient(d->activeView); // Position and show toolbars according to user's preference setAutoSaveSettings(newPart->componentData().componentName(), false); KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface"); const bool showDockerTitleBar = configGroupInterface.readEntry("ShowDockerTitleBars", true); foreach (QDockWidget *wdg, d->dockWidgets) { if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) { if (wdg->titleBarWidget()) { wdg->titleBarWidget()->setVisible(showDockerTitleBar); } wdg->setVisible(true); } } // Create and plug toolbar list for Settings menu foreach(QWidget* it, factory->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); if (toolBar) { KToggleAction * act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); - connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); + connect(act, &QAction::toggled, this, &KoMainWindow::slotToolbarToggled); act->setChecked(!toolBar->isHidden()); d->toolbarList.append(act); } else warnMain << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!"; } plugActionList("toolbarlist", d->toolbarList); } else { d->activeView = 0; d->activePart = 0; } if (d->activeView) { d->activeView->guiActivateEvent(true); } } void KoMainWindow::slotWidgetDestroyed() { debugMain; if ( static_cast( sender() ) == d->m_activeWidget ) setActivePart(0, 0); //do not remove the part because if the part's widget dies, then the //part will delete itself anyway, invoking removePart() in its destructor } void KoMainWindow::slotDocumentTitleModified(const QString &caption, bool mod) { updateCaption(caption, mod); updateReloadFileAction(d->rootDocument); } void KoMainWindow::showDockerTitleBars(bool show) { foreach (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { dock->titleBarWidget()->setVisible(show); } } KConfigGroup configGroupInterface = KSharedConfig::openConfig()->group("Interface"); configGroupInterface.writeEntry("ShowDockerTitleBars", show); } diff --git a/src/libs/main/KoMainWindow.h b/src/libs/main/KoMainWindow.h index cc8c75f1..880e79bf 100644 --- a/src/libs/main/KoMainWindow.h +++ b/src/libs/main/KoMainWindow.h @@ -1,456 +1,457 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2004 David Faure 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. */ #ifndef KOMAINWINDOW_H #define KOMAINWINDOW_H #include "komain_export.h" #include //#include //#include class KoMainWindowPrivate; class KoDocument; class KoPart; class KoView; class KoPrintJob; class KoDockFactoryBase; class KRecentFilesAction; class KoComponentData; class QDockWidget; struct KoPageLayout; // Calligra class but not in main module class QUrl; /** * @brief Main window for a Calligra application * * This class is used to represent a main window * of a Calligra component. Each main window contains * a menubar and some toolbars. * * @note This class does NOT need to be subclassed in your application. */ class KOMAIN_EXPORT KoMainWindow : public KXmlGuiWindow//, public KoCanvasSupervisor { Q_OBJECT public: /** * Constructor. * * Initializes a Calligra main window (with its basic GUI etc.). */ explicit KoMainWindow(const QByteArray &nativeMimeType, const KoComponentData &instance); /** * Destructor. */ virtual ~KoMainWindow(); // If noCleanup is set, KoMainWindow will not delete the root document // or part manager on destruction. void setNoCleanup(bool noCleanup); /** * Called when a document is assigned to this mainwindow. * This creates a view for this document, makes it the active part, etc. */ void setRootDocument(KoDocument *doc, KoPart *part = 0, bool deletePrevious = true); /** * This is used to handle the document used at start up before it actually * added as root document. */ void setPartToOpen(KoPart *part); /** * Update caption from document info - call when document info * (title in the about page) changes. */ void updateCaption(); KoComponentData componentData() const; void setComponentData(const KoComponentData &componentData); /** * Retrieves the document that is displayed in the mainwindow. */ KoDocument *rootDocument() const; KoView *rootView() const; /** * The application should call this to show or hide a toolbar. * It also takes care of the corresponding action in the settings menu. */ void showToolbar(const char * tbName, bool shown); /** * @return TRUE if the toolbar @p tbName is visible */ bool toolbarIsVisible(const char *tbName); /** * Sets the maximum number of recent documents entries. */ void setMaxRecentItems(uint _number); /** * The document opened a URL -> store into recent documents list. */ void addRecentURL(const QUrl &url); /** * Load the desired document and show it. * @param url the URL to open * * @return TRUE on success. */ bool openDocument(const QUrl &url); /** * Load the URL into this document (and make it root doc after loading) * * Special method for KoApplication::start, don't use. */ bool openDocument(KoPart *newPart, const QUrl &url); /** * Reloads the recent documents list. */ void reloadRecentFileList(); /** * Updates the window caption based on the document info and path. */ void updateCaption(const QString & caption, bool mod); void updateReloadFileAction(KoDocument *doc); void setReadWrite(bool readwrite); /** * Returns the dockwidget specified by the @p factory. If the dock widget doesn't exist yet it's created. * Add a "view_palette_action_menu" action to your view menu if you want to use closable dock widgets. * @param factory the factory used to create the dock widget if needed * @return the dock widget specified by @p factory (may be 0) */ QDockWidget* createDockWidget(KoDockFactoryBase* factory); /// Return the list of dock widgets belonging to this main window. QList dockWidgets() const; // QList canvasObservers() const; Q_SIGNALS: /** * This signal is emitted if the document has been saved successfully. */ void documentSaved(); /// This signals is emitted before the save dialog is shown void saveDialogShown(); /// This signal is emitted right after the docker states have been successfully restored from config void restoringDone(); /// This signal is emitted when this windows has finished loading of a /// document. The document may be opened in another window in the end. /// In this case, the signal means there is no link between the window /// and the document anymore. void loadCompleted(); /// This signal is emitted when this windows has canceled loading of a document. void loadCanceled(); /// This signal is emitted when the color theme changes void themeChanged(); /// This signal is emitted when the shortcut key configuration has changed void keyBindingsChanged(); public Q_SLOTS: /** * Slot for eMailing the document using KMail * * This is a very simple extension that will allow any document * that is currently being edited to be emailed using KMail. */ void slotEmailFile(); /** * Slot for opening a new document. * * If the current document is empty, the new document replaces it. * If not, a new mainwindow will be opened for showing the document. */ void slotFileNew(); /** * Slot for opening a saved file. * * If the current document is empty, the opened document replaces it. * If not a new mainwindow will be opened for showing the opened file. */ void slotFileOpen(); /** * Slot for opening a file among the recently opened files. * * If the current document is empty, the opened document replaces it. * If not a new mainwindow will be opened for showing the opened file. */ void slotFileOpenRecent(const QUrl &); /** * Saves the current document with the current name. */ void slotFileSave(); /** * Saves the current document with a new name. */ void slotFileSaveAs(); /** * Prints the actual document. */ void slotFilePrint(); void slotFilePrintPreview(); - KoPrintJob* exportToPdf(const QString &pdfFileName = QString()); + KoPrintJob* exportToPdf(const QString &pdfFileName); + KoPrintJob* exportToPdf(); /** * Show a dialog with author and document information. */ void slotDocumentInfo(); /** * Closes the document. */ void slotFileClose(); /** * Closes the mainwindow. */ void slotFileQuit(); /** * Configure key bindings. */ void slotConfigureKeys(); /** * Configure toolbars. */ void slotConfigureToolbars(); /** * Post toolbar config. * (Plug action lists back in, etc.) */ void slotNewToolbarConfig(); /** * Shows or hides a toolbar */ void slotToolbarToggled(bool toggle); /** * Toggle full screen on/off. */ void viewFullscreen(bool fullScreen); /** * Toggle docker titlebars on/off. */ void showDockerTitleBars(bool show); /** * Reload file */ void slotReloadFile(); /** * File --> Import * * This will call slotFileOpen(). To differentiate this from an ordinary * call to slotFileOpen() call @ref isImporting(). */ void slotImportFile(); /** * File --> Export * * This will call slotFileSaveAs(). To differentiate this from an ordinary * call to slotFileSaveAs() call @ref isExporting(). */ void slotExportFile(); void slotEncryptDocument(); void slotUncompressToDir(); void slotProgress(int value); /** * Hide the dockers */ void toggleDockersVisibility(bool visible); /** * Saves the document, asking for a filename if necessary. * * @param saveas if set to TRUE the user is always prompted for a filename * * @param silent if set to TRUE rootDocument()->setTitleModified will not be called. * * @param specialOutputFlag set to enums defined in KoDocument if save to special output format * * @return TRUE on success, false on error or cancel * (don't display anything in this case, the error dialog box is also implemented here * but restore the original URL in slotFileSaveAs) */ bool saveDocument(bool saveas = false, bool silent = false, int specialOutputFlag = 0); private: /** * This setting indicates who is calling chooseNewDocument. * Usually the app will want to * - show the template dialog with 'everything' if InitDocAppStarting, InitDocFileClose or InitDocEmbedded * - show the template dialog with 'templates only' if InitDocFileNew * - create an empty document with default settings if InitDocEmpty */ enum InitDocFlags { /*InitDocAppStarting, */ InitDocFileNew, InitDocFileClose /*, InitDocEmbedded, InitDocEmpty*/ }; /// Helper method for slotFileNew and slotFileClose void chooseNewDocument(InitDocFlags initDocFlags); /** * Create a new empty document. */ KoPart* createPart() const; void closeEvent(QCloseEvent * e); void resizeEvent(QResizeEvent * e); /** * Ask user about saving changes to the document upon exit. */ bool queryClose(); bool openDocumentInternal(const QUrl &url, KoPart *newpart = 0, KoDocument *newdoc = 0); /** * Returns whether or not the current slotFileSave[As]() or saveDocument() * call is actually an export operation (like File --> Export). * * If this is true, you must call KoDocument::export() instead of * KoDocument::save() or KoDocument::saveAs(), in any reimplementation of * saveDocument(). */ bool isExporting() const; /** * Returns whether or not the current slotFileOpen() or openDocument() * call is actually an import operation (like File --> Import). * * If this is true, you must call KoDocument::import() instead of * KoDocument::openUrl(), in any reimplementation of openDocument() or * openDocumentInternal(). */ bool isImporting() const; KRecentFilesAction *recentAction() const; private Q_SLOTS: /** * Save the list of recent files. */ void saveRecentFiles(); void slotLoadCompleted(); void slotLoadCanceled(const QString &); void slotSaveCompleted(); void slotSaveCanceled(const QString &); void forceDockTabFonts(); /** * Slot to create a new view for the currently activate @ref #koDocument. */ virtual void newView(); // --------------------- PartManager private: friend class KoPart; /** * Removes a part from the manager (this does not delete the object) . * * Sets the active part to 0 if @p part is the activePart() . */ virtual void removePart( KoPart *part ); /** * Sets the active part. * * The active part receives activation events. * * @p widget can be used to specify which widget was responsible for the activation. * This is important if you have multiple views for a document/part , like in KOffice . */ virtual void setActivePart(KoPart *part, QWidget *widget); private Q_SLOTS: /** * @internal */ void slotWidgetDestroyed(); void slotDocumentTitleModified(const QString &caption, bool mod); // --------------------- PartManager private: void createMainwindowGUI(); /** * Asks the user if they really want to save the document. * Called only if outputFormat != nativeFormat. * * @return true if the document should be saved */ bool exportConfirmation(const QByteArray &outputFormat); void saveWindowSettings(); // retrieve the current KoView KoView* currentView() const; private: KoMainWindowPrivate * const d; }; #endif diff --git a/src/libs/main/KoPrintingDialog.cpp b/src/libs/main/KoPrintingDialog.cpp index 3c4f8c9e..5f19bd25 100644 --- a/src/libs/main/KoPrintingDialog.cpp +++ b/src/libs/main/KoPrintingDialog.cpp @@ -1,210 +1,210 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2009 Thomas Zander * Copyright (C) 2011 Boudewijn Rempt * * 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 "KoPrintingDialog.h" #include "KoPrintingDialog_p.h" #include "KoProgressUpdater.h" //#include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include class PrintDialog : public QDialog { public: PrintDialog(KoPrintingDialogPrivate *d, QWidget *parent) : QDialog(parent) { setModal(true); QGridLayout *grid = new QGridLayout(this); setLayout(grid); d->pageNumber = new QLabel(this); d->pageNumber->setMinimumWidth(200); grid->addWidget(d->pageNumber, 0, 0, 1, 2); KoProgressBar *bar = new KoProgressBar(this); d->progress = new KoProgressUpdater(bar); grid->addWidget(bar, 1, 0, 1, 2); d->button = new QPushButton(i18n("Stop"), this); grid->addWidget(d->button, 2, 1); grid->setColumnStretch(0, 1); } }; KoPrintingDialog::KoPrintingDialog(QWidget *parent) : KoPrintJob(parent), d(new KoPrintingDialogPrivate(this)) { d->dialog = new PrintDialog(d, parent); - connect(d->button, SIGNAL(released()), this, SLOT(stopPressed())); + connect(d->button, SIGNAL(released()), this, SLOT(stopPressed())); // clazy:exclude=old-style-connect } KoPrintingDialog::~KoPrintingDialog() { d->stopPressed(); delete d; } /* void KoPrintingDialog::setShapeManager(KoShapeManager *sm) { d->shapeManager = sm; } KoShapeManager *KoPrintingDialog::shapeManager() const { return d->shapeManager; } */ void KoPrintingDialog::setPageRange(const QList &pages) { if (d->index == 0) // can't change after we started d->pageRange = pages; } QPainter & KoPrintingDialog::painter() const { if (d->painter == 0) { d->painter = new QPainter(d->printer); d->painter->save(); // state before page preparation (3) } return *d->painter; } bool KoPrintingDialog::isStopped() const { return d->stop; } void KoPrintingDialog::startPrinting(RemovePolicy removePolicy) { d->removePolicy = removePolicy; d->pages = d->pageRange; if (d->pages.isEmpty()) { // auto-fill from min/max switch (d->printer->printRange()) { case QPrinter::AllPages: for (int i=documentFirstPage(); i <= documentLastPage(); i++) d->pages.append(i); break; case QPrinter::PageRange: for (int i=d->printer->fromPage(); i <= d->printer->toPage(); i++) d->pages.append(i); break; case QPrinter::CurrentPage: d->pages.append(documentCurrentPage()); break; default: return; } } if (d->pages.isEmpty()) { qWarning(/*30004*/) << "KoPrintingDialog::startPrinting: No pages to print, did you forget to call setPageRange()?"; return; } const bool blocking = property("blocking").toBool(); const bool noprogressdialog = property("noprogressdialog").toBool(); if (d->index == 0 && d->pages.count() > 0 && d->printer) { if (!blocking && !noprogressdialog) d->dialog->show(); d->stop = false; delete d->painter; d->painter = 0; // d->zoomer.setZoom( 1.0 ); // d->zoomer.setDpi( d->printer->resolution(), d->printer->resolution() ); d->progress->start(100, i18n("Printing")); if (d->printer->numCopies() > 1) { QList oldPages = d->pages; if (d->printer->collateCopies()) { // means we print whole doc at once for (int count = 1; count < d->printer->numCopies(); ++count) d->pages.append(oldPages); } else { d->pages.clear(); foreach (int page, oldPages) { for (int count = 1; count < d->printer->numCopies(); ++count) d->pages.append(page); } } } if (d->printer->pageOrder() == QPrinter::LastPageFirst) { const QList pages = d->pages; d->pages.clear(); QList::ConstIterator iter = pages.end(); do { --iter; d->pages << *iter; } while (iter != pages.begin()); } d->resetValues(); foreach (int page, d->pages) { d->index++; d->updaters.append(d->progress->startSubtask()); // one per page d->preparePage(page); d->printPage(page); if (!blocking) { qApp->processEvents(); } } d->painter->end(); if (blocking) { printingDone(); } else { d->printingDone(); } d->stop = true; d->resetValues(); } } QPrinter &KoPrintingDialog::printer() { return *d->printer; } void KoPrintingDialog::printPage(int, QPainter &) { } QRectF KoPrintingDialog::preparePage(int) { return QRectF(); } // have to include this because of Q_PRIVATE_SLOT #include diff --git a/src/libs/main/KoPrintingDialog_p.h b/src/libs/main/KoPrintingDialog_p.h index 84c7d5e8..65a10818 100644 --- a/src/libs/main/KoPrintingDialog_p.h +++ b/src/libs/main/KoPrintingDialog_p.h @@ -1,198 +1,198 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2009 Thomas Zander * Copyright (C) 2011 Boudewijn Rempt * * 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. */ #ifndef KoPrintingDialog_p_h #define KoPrintingDialog_p_h #include "KoPrintingDialog.h" #include "KoProgressUpdater.h" //#include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include class KoPrintingDialogPrivate { public: explicit KoPrintingDialogPrivate(KoPrintingDialog *dia) : parent(dia), stop(true), // shapeManager(0), painter(0), printer(new QPrinter()), index(0), progress(0), dialog(0), removePolicy(KoPrintJob::DoNotDelete) { } ~KoPrintingDialogPrivate() { stop = true; delete progress; if (painter && painter->isActive()) { painter->end(); } updaters.clear(); delete printer; delete dialog; } void preparePage(const QVariant &page) { const int pageNumber = page.toInt(); QPointer updater = updaters.at(index - 1); if (painter) { painter->save(); // state before page preparation } QRectF clipRect; if (! stop) { clipRect = parent->preparePage(pageNumber); } updater->setProgress(45); if (!painter) { // force the painter to be created *after* the preparePage since the page // size may have been updated there and that doesn't work with the first page painter = new QPainter(printer); painter->save(); // state before page preparation (2) } if (index > 1) printer->newPage(); if (clipRect.isValid()) // make sure the clipRect is done *after* the newPage. Required for printPreview painter->setClipRect(clipRect); updater->setProgress(55); painter->save(); // state after page preparation /* QList shapes = parent->shapesOnPage(pageNumber); if (shapes.isEmpty()) { debugMain << "Printing page" << pageNumber << "I notice there are no shapes on this page"; } else { const int progressPart = 45 / shapes.count(); foreach(KoShape *shape, shapes) { debugMain << "Calling waitUntilReady on shape;" << shape; if(! stop) shape->waitUntilReady(zoomer); debugMain << "done"; updater->setProgress(updater->progress() + progressPart); } } */ updater->setProgress(100); } void resetValues() { index = 0; updaters.clear(); if (painter && painter->isActive()) painter->end(); delete painter; painter = 0; stop = false; } void printPage(const QVariant &page) { painter->restore(); // state after page preparation painter->save(); parent->printPage(page.toInt(), *painter); painter->restore(); /* if (!stop && shapeManager) { shapeManager->paint(*painter, zoomer, true); }*/ painter->restore(); // state before page preparation if (parent->property("blocking").toBool()) { return; } } void printingDone() { // printing done! painter->end(); progress->cancel(); parent->printingDone(); pageNumber->setText(i18n("Printing done")); button->setText(i18n("Close")); stop = true; - QTimer::singleShot(1200, dialog, SLOT(accept())); + QTimer::singleShot(1200, dialog, &QDialog::accept); if (removePolicy == KoPrintJob::DeleteWhenDone) { parent->deleteLater(); } else { resetValues(); } } void stopPressed() { if (stop) { // pressed a second time. dialog->done(0); return; } stop = true; progress->cancel(); parent->printingDone(); pageNumber->setText(i18n("Stopped")); - QTimer::singleShot(1200, dialog, SLOT(accept())); + QTimer::singleShot(1200, dialog, &QDialog::accept); if (removePolicy == KoPrintJob::DeleteWhenDone) parent->deleteLater(); else resetValues(); } KoPrintingDialog *parent; // KoZoomHandler zoomer; volatile bool stop; // KoShapeManager *shapeManager; QPainter *painter; QPrinter *printer; int index; // index in the pages list. KoProgressUpdater *progress; QLabel *pageNumber; QPushButton *button; QList pageRange; ///< user requested list of pages QList pages; ///< effective list of pages QList< QPointer > updaters; QDialog *dialog; KoPrintJob::RemovePolicy removePolicy; }; #endif diff --git a/src/libs/main/KoUndoStackAction.cpp b/src/libs/main/KoUndoStackAction.cpp index 7c14a247..bc991c0e 100644 --- a/src/libs/main/KoUndoStackAction.cpp +++ b/src/libs/main/KoUndoStackAction.cpp @@ -1,56 +1,56 @@ /* This file is part of the KDE project Copyright (C) 2011 Sven Langkamp 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 "KoUndoStackAction.h" #include #include #include #include KoUndoStackAction::KoUndoStackAction(KUndo2Stack* stack, Type type) : QAction(stack) , m_type(type) { if (m_type == UNDO) { - connect(this, SIGNAL(triggered()), stack, SLOT(undo())); - connect(stack, SIGNAL(canUndoChanged(bool)), this, SLOT(setEnabled(bool))); - connect(stack, SIGNAL(undoTextChanged(QString)), this, SLOT(slotUndoTextChanged(QString))); + connect(this, &QAction::triggered, stack, &KUndo2QStack::undo); + connect(stack, &KUndo2QStack::canUndoChanged, this, &QAction::setEnabled); + connect(stack, &KUndo2QStack::undoTextChanged, this, &KoUndoStackAction::slotUndoTextChanged); setIcon(koIcon("edit-undo")); setText(i18n("Undo")); setShortcuts(KStandardShortcut::undo()); setEnabled(stack->canUndo()); } else { - connect(this, SIGNAL(triggered()), stack, SLOT(redo())); - connect(stack, SIGNAL(canRedoChanged(bool)), this, SLOT(setEnabled(bool))); - connect(stack, SIGNAL(redoTextChanged(QString)), this, SLOT(slotUndoTextChanged(QString))); + connect(this, &QAction::triggered, stack, &KUndo2QStack::redo); + connect(stack, &KUndo2QStack::canRedoChanged, this, &QAction::setEnabled); + connect(stack, &KUndo2QStack::redoTextChanged, this, &KoUndoStackAction::slotUndoTextChanged); setIcon(koIcon("edit-redo")); setText(i18n("Redo")); setShortcuts(KStandardShortcut::redo()); setEnabled(stack->canRedo()); } } void KoUndoStackAction::slotUndoTextChanged(const QString& text) { QString actionText = (m_type == UNDO) ? i18n("Undo %1", text) : i18n("Redo %1", text); setText(actionText); } diff --git a/src/libs/main/KoView.cpp b/src/libs/main/KoView.cpp index 2ab3b705..f398538d 100644 --- a/src/libs/main/KoView.cpp +++ b/src/libs/main/KoView.cpp @@ -1,443 +1,443 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2007 Thomas Zander Copyright (C) 2010 Benjamin Port 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 "KoView.h" // local directory #include "KoView_p.h" #include "KoPart.h" #include "KoDockRegistry.h" #include "KoDockFactoryBase.h" #include "KoDocument.h" #include "KoMainWindow.h" #ifndef QT_NO_DBUS #include "KoViewAdaptor.h" #include #endif #include "KoUndoStackAction.h" #include "KoGlobal.h" #include "KoPageLayout.h" #include "KoPrintJob.h" #include "KoDocumentInfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //static QString KoView::newObjectName() { static int s_viewIFNumber = 0; QString name; name.setNum(s_viewIFNumber++); name.prepend("view_"); return name; } class KoViewPrivate { public: KoViewPrivate() { tempActiveWidget = 0; documentDeleted = false; actionAuthor = 0; } ~KoViewPrivate() { } QPointer document; // our KoDocument QPointer part; // our part QWidget *tempActiveWidget; bool documentDeleted; // true when document gets deleted [can't use document==0 // since this only happens in ~QObject, and views // get deleted by ~KoDocument]. // Hmm sorry for polluting the private class with such a big inner class. // At the beginning it was a little struct :) class StatusBarItem { public: StatusBarItem() // for QValueList : m_widget(0), m_connected(false), m_hidden(false) {} StatusBarItem(QWidget * widget, int stretch, bool permanent) : m_widget(widget), m_stretch(stretch), m_permanent(permanent), m_connected(false), m_hidden(false) {} bool operator==(const StatusBarItem& rhs) { return m_widget == rhs.m_widget; } bool operator!=(const StatusBarItem& rhs) { return m_widget != rhs.m_widget; } QWidget * widget() const { return m_widget; } void ensureItemShown(QStatusBar * sb) { Q_ASSERT(m_widget); if (!m_connected) { if (m_permanent) sb->addPermanentWidget(m_widget, m_stretch); else sb->addWidget(m_widget, m_stretch); if(!m_hidden) m_widget->show(); m_connected = true; } } void ensureItemHidden(QStatusBar * sb) { if (m_connected) { m_hidden = m_widget->isHidden(); sb->removeWidget(m_widget); m_widget->hide(); m_connected = false; } } private: QWidget * m_widget; int m_stretch; bool m_permanent; bool m_connected; bool m_hidden; }; QList statusBarItems; // Our statusbar items bool inOperation; //in the middle of an operation (no screen refreshing)? KSelectAction *actionAuthor; // Select action for author profile. }; KoView::KoView(KoPart *part, KoDocument *document, QWidget *parent) : QWidget(parent) , d(new KoViewPrivate) { Q_ASSERT(document); Q_ASSERT(part); setObjectName(newObjectName()); #ifndef QT_NO_DBUS new KoViewAdaptor(this); QDBusConnection::sessionBus().registerObject('/' + objectName(), this); #endif d->document = document; d->part = part; setFocusPolicy(Qt::StrongFocus); setupGlobalActions(); QStatusBar * sb = statusBar(); if (sb) { // No statusbar in e.g. konqueror - connect(d->document, SIGNAL(statusBarMessage(QString)), - this, SLOT(slotActionStatusText(QString))); - connect(d->document, SIGNAL(clearStatusBarMessage()), - this, SLOT(slotClearStatusText())); + connect(d->document.data(), &KoDocument::statusBarMessage, + this, &KoView::slotActionStatusText); + connect(d->document.data(), &KoDocument::clearStatusBarMessage, + this, &KoView::slotClearStatusText); } #if 0 // add all plugins. foreach(const QString & docker, KoDockRegistry::instance()->keys()) { KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker); qInfo()<id(); if (mainWindow()) mainWindow()->createDockWidget(factory); } #endif actionCollection()->addAssociatedWidget(this); /** * WARNING: This code changes the context of global shortcuts * only. All actions added later will have the default * context, which is Qt::WindowShortcut! */ foreach(QAction* action, actionCollection()->actions()) { action->setShortcutContext(Qt::WidgetWithChildrenShortcut); } } KoView::~KoView() { if (!d->documentDeleted) { if (d->document) { d->part->removeView(this); } } delete d; } void KoView::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasImage() || event->mimeData()->hasUrls()) { event->accept(); } else { event->ignore(); } } void KoView::dropEvent(QDropEvent *event) { // we can drop a list of urls from, for instance dolphin QVector images; if (event->mimeData()->hasImage()) { QImage image = event->mimeData()->imageData().value(); if (!image.isNull()) { // apparently hasImage() && imageData().value().isNull() // can hold sometimes (Qt bug?). images << image; } } else if (event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); foreach (const QUrl &url, urls) { QImage image; QUrl kurl(url); // make sure we download the files before inserting them if (!kurl.isLocalFile()) { QString tmpFile; if( KIO::NetAccess::download(kurl, tmpFile, this)) { image.load(tmpFile); KIO::NetAccess::removeTempFile(tmpFile); } else { KMessageBox::error(this, KIO::NetAccess::lastErrorString()); } } else { image.load(kurl.toLocalFile()); } if (!image.isNull()) { images << image; } } } if (!images.isEmpty()) { addImages(images, event->pos()); } } void KoView::addImages(const QVector &, const QPoint &) { // override in your application } KoDocument *KoView::koDocument() const { return d->document; } void KoView::setDocumentDeleted() { d->documentDeleted = true; } void KoView::addStatusBarItem(QWidget * widget, int stretch, bool permanent) { KoViewPrivate::StatusBarItem item(widget, stretch, permanent); QStatusBar * sb = statusBar(); if (sb) { item.ensureItemShown(sb); } d->statusBarItems.append(item); } void KoView::removeStatusBarItem(QWidget *widget) { QStatusBar *sb = statusBar(); int itemCount = d->statusBarItems.count(); for (int i = itemCount-1; i >= 0; --i) { KoViewPrivate::StatusBarItem &sbItem = d->statusBarItems[i]; if (sbItem.widget() == widget) { if (sb) { sbItem.ensureItemHidden(sb); } d->statusBarItems.removeOne(sbItem); break; } } } KoPrintJob * KoView::createPrintJob() { warnMain << "Printing not implemented in this application"; return 0; } KoPrintJob * KoView::createPdfPrintJob() { return createPrintJob(); } KoPageLayout KoView::pageLayout() const { return koDocument()->pageLayout(); } void KoView::setPageLayout(const KoPageLayout &pageLayout) { koDocument()->setPageLayout(pageLayout); } QPrintDialog *KoView::createPrintDialog(KoPrintJob *printJob, QWidget *parent) { QPrintDialog *printDialog = new QPrintDialog(&printJob->printer(), parent); printDialog->setOptionTabs(printJob->createOptionWidgets()); printDialog->setMinMax(printJob->printer().fromPage(), printJob->printer().toPage()); printDialog->setEnabledOptions(printJob->printDialogOptions()); return printDialog; } void KoView::setupGlobalActions() { QAction *undo = actionCollection()->addAction("edit_undo", new KoUndoStackAction(d->document->undoStack(), KoUndoStackAction::UNDO)); QAction *redo = actionCollection()->addAction("edit_redo", new KoUndoStackAction(d->document->undoStack(), KoUndoStackAction::RED0)); actionCollection()->setDefaultShortcut(undo, QKeySequence::Undo); actionCollection()->setDefaultShortcut(redo, QKeySequence::Redo); d->actionAuthor = new KSelectAction(koIcon("user-identity"), i18n("Active Author Profile"), this); - connect(d->actionAuthor, SIGNAL(triggered(QString)), this, SLOT(changeAuthorProfile(QString))); + connect(d->actionAuthor, static_cast (&KSelectAction::triggered), this, &KoView::changeAuthorProfile); actionCollection()->addAction("settings_active_author", d->actionAuthor); slotUpdateAuthorProfileActions(); } void KoView::changeAuthorProfile(const QString &profileName) { KConfigGroup appAuthorGroup( KSharedConfig::openConfig(), "Author"); if (profileName.isEmpty()) { appAuthorGroup.writeEntry("active-profile", ""); } else if (profileName == i18nc("choice for author profile", "Anonymous")) { appAuthorGroup.writeEntry("active-profile", "anonymous"); } else { appAuthorGroup.writeEntry("active-profile", profileName); } appAuthorGroup.sync(); d->document->documentInfo()->updateParameters(); } KoMainWindow * KoView::mainWindow() const { // It is possible (when embedded inside a Gemini window) that you have a KoMainWindow which // is not the top level window. The code below ensures you can still get access to it, even // in that case. KoMainWindow* mw = dynamic_cast(window()); QWidget* parent = parentWidget(); while (!mw) { mw = dynamic_cast(parent); parent = parent->parentWidget(); if (!parent) { break; } } return mw; } QStatusBar * KoView::statusBar() const { KoMainWindow *mw = mainWindow(); return mw ? mw->statusBar() : 0; } void KoView::slotActionStatusText(const QString &text) { QStatusBar *sb = statusBar(); if (sb) sb->showMessage(text); } void KoView::slotClearStatusText() { QStatusBar *sb = statusBar(); if (sb) sb->clearMessage(); } void KoView::slotUpdateAuthorProfileActions() { Q_ASSERT(d->actionAuthor); if (!d->actionAuthor) { return; } d->actionAuthor->clear(); d->actionAuthor->addAction(i18n("Default Author Profile")); d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous")); KConfigGroup authorGroup(KoGlobal::planConfig(), "Author"); QStringList profiles = authorGroup.readEntry("profile-names", QStringList()); foreach (const QString &profile , profiles) { d->actionAuthor->addAction(profile); } KConfigGroup appAuthorGroup( KSharedConfig::openConfig(), "Author"); QString profileName = appAuthorGroup.readEntry("active-profile", ""); if (profileName == "anonymous") { d->actionAuthor->setCurrentItem(1); } else if (profiles.contains(profileName)) { d->actionAuthor->setCurrentAction(profileName); } else { d->actionAuthor->setCurrentItem(0); } } QList KoView::createChangeUnitActions(bool addPixelUnit) { UnitActionGroup* unitActions = new UnitActionGroup(d->document, addPixelUnit, this); return unitActions->actions(); } void KoView::guiActivateEvent(bool activated) { Q_UNUSED(activated); } diff --git a/src/libs/main/KoView_p.h b/src/libs/main/KoView_p.h index 06418a45..1a5a275e 100644 --- a/src/libs/main/KoView_p.h +++ b/src/libs/main/KoView_p.h @@ -1,88 +1,88 @@ /* This file is part of the Calligra project, made within the KDE community. * Copyright 2012 Friedrich W. H. Kossebau * * 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. */ #ifndef KOVIEW_P_H #define KOVIEW_P_H // Calligra #include "KoUnit.h" #include "KoDocument.h" // Qt #include #include // Action group which keeps the actions in sync with the document's unit property class UnitActionGroup : public QActionGroup { Q_OBJECT public: explicit UnitActionGroup(KoDocument *document, bool addPixelUnit, QObject* parent = 0) : QActionGroup(parent) , m_document(document) , m_listOptions(addPixelUnit ? KoUnit::ListAll : KoUnit::HidePixel) { setExclusive(true); - connect(this, SIGNAL(triggered(QAction*)), SLOT(onTriggered(QAction*))); - connect(document, SIGNAL(unitChanged(KoUnit)), SLOT(onUnitChanged(KoUnit))); + connect(this, &QActionGroup::triggered, this, &UnitActionGroup::onTriggered); + connect(document, &KoDocument::unitChanged, this, &UnitActionGroup::onUnitChanged); const QStringList unitNames = KoUnit::listOfUnitNameForUi(m_listOptions); const int currentUnitIndex = m_document->unit().indexInListForUi(m_listOptions); for (int i = 0; i < unitNames.count(); ++i) { QAction* action = new QAction(unitNames.at(i), this); action->setData(i); action->setCheckable(true); if (currentUnitIndex == i) { action->setChecked(true); } } } private Q_SLOTS: void onTriggered(QAction *action) { m_document->setUnit(KoUnit::fromListForUi(action->data().toInt(), m_listOptions)); } void onUnitChanged(const KoUnit &unit) { const int indexInList = unit.indexInListForUi(m_listOptions); foreach (QAction *action, actions()) { if (action->data().toInt() == indexInList) { action->setChecked(true); break; } // in case the new unit is not in the list of actions // this ensures that the action currently checked is unchecked // once the end of actions has been reached if (action->isChecked()) { action->setChecked(false); } } } private: KoDocument *m_document; KoUnit::ListOptions m_listOptions; }; #endif diff --git a/src/libs/models/kcalendar/kdatepicker.cpp b/src/libs/models/kcalendar/kdatepicker.cpp index 2c6b37c6..d320c1f1 100644 --- a/src/libs/models/kcalendar/kdatepicker.cpp +++ b/src/libs/models/kcalendar/kdatepicker.cpp @@ -1,673 +1,673 @@ /* -*- C++ -*- This file is part of the KDE libraries Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) (C) 1998-2001 Mirko Boehm (mirko@kde.org) (C) 2007 John Layt 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 "kdatepicker.h" #include "kdatepicker_p.h" #include "kdatetable.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { static QDate parseDateString(const QString &text) { QLocale::FormatType formats[] = { QLocale::LongFormat, QLocale::ShortFormat, QLocale::NarrowFormat }; QLocale locale; QDate date; for (int i = 0; i < 3; i++) { date = locale.toDate(text, formats[i]); if (date.isValid()) { break; } } return date; } class DatePickerValidator : public QValidator { public: DatePickerValidator(KDatePicker *parent) : QValidator(parent), picker(parent) {} State validate(QString &text, int &) const Q_DECL_OVERRIDE { return parseDateString(text).isValid() ? QValidator::Acceptable : QValidator::Intermediate; } private: KDatePicker *picker; }; // Week numbers are defined by ISO 8601 // See http://www.merlyn.demon.co.uk/weekinfo.htm for details KDatePickerPrivateYearSelector::KDatePickerPrivateYearSelector( const QDate ¤tDate, QWidget *parent) : QLineEdit(parent), val(new QIntValidator(this)), result(0) { oldDate = currentDate; setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); setFrame(false); // TODO: Find a way to get that from QLocale //val->setRange( calendar->year( calendar->earliestValidDate() ), // calendar->year( calendar->latestValidDate() ) ); setValidator(val); - connect(this, SIGNAL(returnPressed()), SLOT(yearEnteredSlot())); + connect(this, &QLineEdit::returnPressed, this, &KDatePickerPrivateYearSelector::yearEnteredSlot); } void KDatePickerPrivateYearSelector::yearEnteredSlot() { bool ok; int newYear; // check if entered value is a number newYear = text().toInt(&ok); if (!ok) { KNotification::beep(); return; } // check if new year will lead to a valid date if (QDate(newYear, oldDate.month(), oldDate.day()).isValid()) { result = newYear; emit closeMe(1); } else { KNotification::beep(); } } int KDatePickerPrivateYearSelector::year() { return result; } void KDatePickerPrivateYearSelector::setYear(int year) { setText(QString::number(year)); } class KDatePicker::KDatePickerPrivate { public: KDatePickerPrivate(KDatePicker *q) : q(q), closeButton(0L), selectWeek(0L), todayButton(0), navigationLayout(0) { } void fillWeeksCombo(); QDate validDateInYearMonth(int year, int month); /// the date table KDatePicker *q; QToolButton *closeButton; QComboBox *selectWeek; QToolButton *todayButton; QBoxLayout *navigationLayout; /// the year forward button QToolButton *yearForward; /// the year backward button QToolButton *yearBackward; /// the month forward button QToolButton *monthForward; /// the month backward button QToolButton *monthBackward; /// the button for selecting the month directly QToolButton *selectMonth; /// the button for selecting the year directly QToolButton *selectYear; /// the line edit to enter the date directly QLineEdit *line; /// the validator for the line edit: DatePickerValidator *val; /// the date table KDateTable *table; /// the widest month string in pixels: QSize maxMonthRect; /// the font size for the widget int fontsize; }; void KDatePicker::KDatePickerPrivate::fillWeeksCombo() { // every year can have a different number of weeks // it could be that we had 53,1..52 and now 1..53 which is the same number but different // so always fill with new values // We show all week numbers for all weeks between first day of year to last day of year // This of course can be a list like 53,1,2..52 const QDate thisDate = q->date(); const int thisYear = thisDate.year(); QDate day(thisDate.year(), 1, 1); const QDate lastDayOfYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1); selectWeek->clear(); // Starting from the first day in the year, loop through the year a week at a time // adding an entry to the week combo for each week in the year for (; day.isValid() && day <= lastDayOfYear; day = day.addDays(7)) { // Get the ISO week number for the current day and what year that week is in // e.g. 1st day of this year may fall in week 53 of previous year int weekYear = thisYear; const int week = day.weekNumber(&weekYear); QString weekString = i18n("Week %1", week); // show that this is a week from a different year if (weekYear != thisYear) { weekString += QLatin1Char('*'); } // when the week is selected, go to the same weekday as the one // that is currently selected in the date table QDate targetDate = day.addDays(thisDate.dayOfWeek() - day.dayOfWeek()); selectWeek->addItem(weekString, targetDate); // make sure that the week of the lastDayOfYear is always inserted: in Chinese calendar // system, this is not always the case if (day < lastDayOfYear && day.daysTo(lastDayOfYear) < 7 && lastDayOfYear.weekNumber() != day.weekNumber()) { day = lastDayOfYear.addDays(-7); } } } QDate KDatePicker::KDatePickerPrivate::validDateInYearMonth(int year, int month) { QDate newDate; // Try to create a valid date in this year and month // First try the first of the month, then try last of month if (QDate(year, month, 1).isValid()) { newDate = QDate(year, month, 1); } else if (QDate(year, month + 1, 1).isValid()) { newDate = QDate(year, month + 1, 1).addDays(-1); } else { newDate = QDate::fromJulianDay(0); } return newDate; } KDatePicker::KDatePicker(QWidget *parent) : QFrame(parent), d(new KDatePickerPrivate(this)) { initWidget(QDate::currentDate()); } KDatePicker::KDatePicker(const QDate &date_, QWidget *parent) : QFrame(parent), d(new KDatePickerPrivate(this)) { initWidget(date_); } void KDatePicker::initWidget(const QDate &date_) { const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QBoxLayout *topLayout = new QVBoxLayout(this); topLayout->setSpacing(0); topLayout->setMargin(0); d->navigationLayout = new QHBoxLayout(); d->navigationLayout->setSpacing(0); d->navigationLayout->setMargin(0); topLayout->addLayout(d->navigationLayout); d->navigationLayout->addStretch(); d->yearBackward = new QToolButton(this); d->yearBackward->setAutoRaise(true); d->navigationLayout->addWidget(d->yearBackward); d->monthBackward = new QToolButton(this); d->monthBackward ->setAutoRaise(true); d->navigationLayout->addWidget(d->monthBackward); d->navigationLayout->addSpacing(spacingHint); d->selectMonth = new QToolButton(this); d->selectMonth ->setAutoRaise(true); d->navigationLayout->addWidget(d->selectMonth); d->selectYear = new QToolButton(this); d->selectYear->setCheckable(true); d->selectYear->setAutoRaise(true); d->navigationLayout->addWidget(d->selectYear); d->navigationLayout->addSpacing(spacingHint); d->monthForward = new QToolButton(this); d->monthForward ->setAutoRaise(true); d->navigationLayout->addWidget(d->monthForward); d->yearForward = new QToolButton(this); d->yearForward ->setAutoRaise(true); d->navigationLayout->addWidget(d->yearForward); d->navigationLayout->addStretch(); d->line = new QLineEdit(this); d->val = new DatePickerValidator(this); d->table = new KDateTable(this); setFocusProxy(d->table); d->fontsize = QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize(); if (d->fontsize == -1) { d->fontsize = QFontInfo(QFontDatabase::systemFont(QFontDatabase::GeneralFont)).pointSize(); } d->fontsize++; // Make a little bigger d->selectWeek = new QComboBox(this); // read only week selection d->selectWeek->setFocusPolicy(Qt::NoFocus); d->todayButton = new QToolButton(this); d->todayButton->setIcon(koIcon("go-jump-today")); d->yearForward->setToolTip(i18n("Next year")); d->yearBackward->setToolTip(i18n("Previous year")); d->monthForward->setToolTip(i18n("Next month")); d->monthBackward->setToolTip(i18n("Previous month")); d->selectWeek->setToolTip(i18n("Select a week")); d->selectMonth->setToolTip(i18n("Select a month")); d->selectYear->setToolTip(i18n("Select a year")); d->todayButton->setToolTip(i18n("Select the current day")); // ----- setFontSize(d->fontsize); d->line->setValidator(d->val); d->line->installEventFilter(this); if (QApplication::isRightToLeft()) { d->yearForward->setIcon(koIcon("arrow-left-double")); d->yearBackward->setIcon(koIcon("arrow-right-double")); d->monthForward->setIcon(koIcon("arrow-left")); d->monthBackward->setIcon(koIcon("arrow-right")); } else { d->yearForward->setIcon(koIcon("arrow-right-double")); d->yearBackward->setIcon(koIcon("arrow-left-double")); d->monthForward->setIcon(koIcon("arrow-right")); d->monthBackward->setIcon(koIcon("arrow-left")); } connect(d->table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate))); - connect(d->table, SIGNAL(tableClicked()), SLOT(tableClickedSlot())); - connect(d->monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked())); - connect(d->monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked())); - connect(d->yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked())); - connect(d->yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked())); + connect(d->table, &KDateTable::tableClicked, this, &KDatePicker::tableClickedSlot); + connect(d->monthForward, &QAbstractButton::clicked, this, &KDatePicker::monthForwardClicked); + connect(d->monthBackward, &QAbstractButton::clicked, this, &KDatePicker::monthBackwardClicked); + connect(d->yearForward, &QAbstractButton::clicked, this, &KDatePicker::yearForwardClicked); + connect(d->yearBackward, &QAbstractButton::clicked, this, &KDatePicker::yearBackwardClicked); connect(d->selectWeek, SIGNAL(activated(int)), SLOT(weekSelected(int))); - connect(d->todayButton, SIGNAL(clicked()), SLOT(todayButtonClicked())); - connect(d->selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked())); - connect(d->selectYear, SIGNAL(toggled(bool)), SLOT(selectYearClicked())); - connect(d->line, SIGNAL(returnPressed()), SLOT(lineEnterPressed())); + connect(d->todayButton, &QAbstractButton::clicked, this, &KDatePicker::todayButtonClicked); + connect(d->selectMonth, &QAbstractButton::clicked, this, &KDatePicker::selectMonthClicked); + connect(d->selectYear, &QAbstractButton::toggled, this, &KDatePicker::selectYearClicked); + connect(d->line, &QLineEdit::returnPressed, this, &KDatePicker::lineEnterPressed); topLayout->addWidget(d->table); QBoxLayout *bottomLayout = new QHBoxLayout(); bottomLayout->setMargin(0); bottomLayout->setSpacing(0); topLayout->addLayout(bottomLayout); bottomLayout->addWidget(d->todayButton); bottomLayout->addWidget(d->line); bottomLayout->addWidget(d->selectWeek); d->table->setDate(date_); dateChangedSlot(date_); // needed because table emits changed only when newDate != oldDate } KDatePicker::~KDatePicker() { delete d; } bool KDatePicker::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::KeyPress) { QKeyEvent *k = (QKeyEvent *)e; if ((k->key() == Qt::Key_PageUp) || (k->key() == Qt::Key_PageDown) || (k->key() == Qt::Key_Up) || (k->key() == Qt::Key_Down)) { QApplication::sendEvent(d->table, e); d->table->setFocus(); return true; // eat event } } return QFrame::eventFilter(o, e); } void KDatePicker::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); } void KDatePicker::dateChangedSlot(const QDate &date_) { QLocale locale; d->line->setText(locale.toString(date_, QLocale::ShortFormat)); d->selectMonth->setText(locale.standaloneMonthName(date_.month(), QLocale::LongFormat)); d->fillWeeksCombo(); // calculate the item num in the week combo box; normalize selected day so as if 1.1. is the first day of the week QDate firstDay(date_.year(), 1, 1); // If we cannot successfully create the 1st of the year, this can only mean that // the 1st is before the earliest valid date in the current calendar system, so use // the earliestValidDate as the first day. // In particular covers the case of Gregorian where 1/1/-4713 is not a valid QDate d->selectWeek->setCurrentIndex((date_.dayOfYear() + firstDay.dayOfWeek() - 2) / 7); d->selectYear->setText(QString::number(date_.year()).rightJustified(4, QLatin1Char('0'))); emit dateChanged(date_); } void KDatePicker::tableClickedSlot() { emit dateSelected(date()); emit tableClicked(); } const QDate &KDatePicker::date() const { return d->table->date(); } bool KDatePicker::setDate(const QDate &date_) { // the table setDate does validity checking for us // this also emits dateChanged() which then calls our dateChangedSlot() return d->table->setDate(date_); } void KDatePicker::monthForwardClicked() { if (! setDate(date().addMonths(1))) { KNotification::beep(); } d->table->setFocus(); } void KDatePicker::monthBackwardClicked() { if (! setDate(date().addMonths(-1))) { KNotification::beep(); } d->table->setFocus(); } void KDatePicker::yearForwardClicked() { if (! setDate(d->table->date().addYears(1))) { KNotification::beep(); } d->table->setFocus(); } void KDatePicker::yearBackwardClicked() { if (! setDate(d->table->date().addYears(-1))) { KNotification::beep(); } d->table->setFocus(); } void KDatePicker::weekSelected(int index) { QDate targetDay = d->selectWeek->itemData(index).toDateTime().date(); if (! setDate(targetDay)) { KNotification::beep(); } d->table->setFocus(); } void KDatePicker::selectMonthClicked() { QDate thisDate(date()); d->table->setFocus(); QMenu popup(d->selectMonth); // Populate the pick list with all the month names, this may change by year // JPL do we need to do something here for months that fall outside valid range? const int monthsInYear = QDate(thisDate.year() + 1, 1, 1).addDays(-1).month(); QLocale locale; for (int m = 1; m <= monthsInYear; m++) { popup.addAction(locale.standaloneMonthName(m))->setData(m); } QAction *item = popup.actions().value(thisDate.month() - 1); // if this happens the above should already given an assertion if (item) { popup.setActiveAction(item); } // cancelled if ((item = popup.exec(d->selectMonth->mapToGlobal(QPoint(0, 0)), item)) == 0) { return; } // We need to create a valid date in the month selected so we can find out how many days are // in the month. QDate newDate(thisDate.year(), item->data().toInt(), 1); // If we have succeeded in creating a date in the new month, then try to create the new date, // checking we don't set a day after the last day of the month newDate.setDate(newDate.year(), newDate.month(), qMin(thisDate.day(), newDate.daysInMonth())); // Set the date, if it's invalid in any way then alert user and don't update if (! setDate(newDate)) { KNotification::beep(); } } void KDatePicker::selectYearClicked() { if (!d->selectYear->isChecked()) { return; } QDate thisDate(date()); KPopupFrame *popup = new KPopupFrame(this); KDatePickerPrivateYearSelector *picker = new KDatePickerPrivateYearSelector(date(), popup); picker->resize(picker->sizeHint()); picker->setYear(thisDate.year()); picker->selectAll(); popup->setMainWidget(picker); connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int))); picker->setFocus(); if (popup->exec(d->selectYear->mapToGlobal(QPoint(0, d->selectMonth->height())))) { // We need to create a valid date in the year/month selected so we can find out how many // days are in the month. QDate newDate(picker->year(), thisDate.month(), 1); // If we have succeeded in creating a date in the new month, then try to create the new // date, checking we don't set a day after the last day of the month newDate = QDate(newDate.year(), newDate.month(), qMin(thisDate.day(), newDate.daysInMonth())); // Set the date, if it's invalid in any way then alert user and don't update if (! setDate(newDate)) { KNotification::beep(); } } delete popup; d->selectYear->setChecked(false); } void KDatePicker::uncheckYearSelector() { d->selectYear->setChecked(false); d->selectYear->update(); } void KDatePicker::changeEvent(QEvent *event) { if (event && event->type() == QEvent::EnabledChange) { if (isEnabled()) { d->table->setFocus(); } } } KDateTable *KDatePicker::dateTable() const { return d->table; } void KDatePicker::lineEnterPressed() { QDate newDate = parseDateString(d->line->text()); if (newDate.isValid()) { emit dateEntered(newDate); setDate(newDate); d->table->setFocus(); } else { KNotification::beep(); } } void KDatePicker::todayButtonClicked() { setDate(QDate::currentDate()); d->table->setFocus(); } QSize KDatePicker::sizeHint() const { return QWidget::sizeHint(); } void KDatePicker::setFontSize(int s) { QWidget *const buttons[] = { d->selectMonth, d->selectYear, }; const int NoOfButtons = sizeof(buttons) / sizeof(buttons[0]); int count; QFont font; QRect r; // ----- d->fontsize = s; for (count = 0; count < NoOfButtons; ++count) { font = buttons[count]->font(); font.setPointSize(s); buttons[count]->setFont(font); } d->table->setFontSize(s); QFontMetrics metrics(d->selectMonth->fontMetrics()); QString longestMonth; QLocale locale; for (int i = 1;; ++i) { QString str = locale.standaloneMonthName(i, QLocale::LongFormat); if (str.isNull()) { break; } r = metrics.boundingRect(str); if (r.width() > d->maxMonthRect.width()) { d->maxMonthRect.setWidth(r.width()); longestMonth = str; } if (r.height() > d->maxMonthRect.height()) { d->maxMonthRect.setHeight(r.height()); } } QStyleOptionToolButton opt; opt.initFrom(d->selectMonth); opt.text = longestMonth; // stolen from QToolButton QSize textSize = metrics.size(Qt::TextShowMnemonic, longestMonth); textSize.setWidth(textSize.width() + metrics.width(QLatin1Char(' ')) * 2); int w = textSize.width(); int h = textSize.height(); opt.rect.setHeight(h); // PM_MenuButtonIndicator depends on the height QSize metricBound = style()->sizeFromContents( QStyle::CT_ToolButton, &opt, QSize(w, h), d->selectMonth ).expandedTo(QApplication::globalStrut()); d->selectMonth->setMinimumSize(metricBound); } int KDatePicker::fontSize() const { return d->fontsize; } void KDatePicker::setCloseButton(bool enable) { if (enable == (d->closeButton != 0L)) { return; } if (enable) { d->closeButton = new QToolButton(this); d->closeButton->setAutoRaise(true); const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); d->navigationLayout->addSpacing(spacingHint); d->navigationLayout->addWidget(d->closeButton); d->closeButton->setToolTip(i18n("Close")); d->closeButton->setIcon(koIcon("window-close")); - connect(d->closeButton, SIGNAL(clicked()), - topLevelWidget(), SLOT(close())); + connect(d->closeButton, &QAbstractButton::clicked, + topLevelWidget(), &QWidget::close); } else { delete d->closeButton; d->closeButton = 0L; } updateGeometry(); } bool KDatePicker::hasCloseButton() const { return (d->closeButton); } } //namespace KPlato diff --git a/src/libs/models/kcalendar/kdatetable.cpp b/src/libs/models/kcalendar/kdatetable.cpp index dbfb4d75..dd01bb5d 100644 --- a/src/libs/models/kcalendar/kdatetable.cpp +++ b/src/libs/models/kcalendar/kdatetable.cpp @@ -1,1242 +1,1242 @@ /* -*- C++ -*- This file is part of the KDE libraries Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) (C) 1998-2001 Mirko Boehm (mirko@kde.org) (C) 2007 John Layt 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 "kdatetable.h" #include "kdatepicker.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { class KDateTable::KDateTablePrivate { public: KDateTablePrivate(KDateTable *q): q(q) { m_popupMenuEnabled = false; m_selectionmode = KDateTable::SingleSelection; m_paintweeknumbers = false; m_hoveredPos = -1; m_model = 0; m_grid = false; } ~KDateTablePrivate() { qDeleteAll(customPaintingModes); delete m_dateDelegate; delete m_weekDayDelegate; delete m_weekNumberDelegate; } void nextMonth(); void previousMonth(); void beginningOfMonth(); void endOfMonth(); void beginningOfWeek(); void endOfWeek(); KDateTable *q; /** * The currently selected date. */ QDate m_date; /** * The weekday number of the first day in the month [1..7]. */ int m_weekDayFirstOfMonth; /** * Save the size of the largest used cell content. */ QRectF m_maxCell; /** * The font size of the displayed text. */ int fontsize; bool m_popupMenuEnabled; //-----> QHash customPaintingModes; int m_hoveredPos; KDateTableDataModel *m_model; KDateTableDateDelegate *m_dateDelegate; KDateTableWeekDayDelegate *m_weekDayDelegate; KDateTableWeekNumberDelegate *m_weekNumberDelegate; StyleOptionViewItem m_styleOptionDate; StyleOptionHeader m_styleOptionWeekDay; StyleOptionHeader m_styleOptionWeekNumber; QList m_selectedDates; SelectionMode m_selectionmode; bool m_paintweeknumbers; bool m_grid; }; KDateTable::KDateTable(const QDate& date, QWidget* parent) : QWidget(parent), d(new KDateTablePrivate(this)) { if (!date.isValid()) { debugPlan << "KDateTable ctor: WARNING: Given date is invalid, using current date."; initWidget(QDate::currentDate()); // this initializes m_weekDayFirstOfMonth, m_numDaysThisMonth, numDaysPrevMonth } else { initWidget(date); // this initializes m_weekDayFirstOfMonth, m_numDaysThisMonth, numDaysPrevMonth } } KDateTable::KDateTable(QWidget *parent) : QWidget(parent), d(new KDateTablePrivate(this)) { initWidget(QDate::currentDate()); } KDateTable::~KDateTable() { delete d; } void KDateTable::initWidget(const QDate &date) { setFontSize(10); setFocusPolicy(Qt::StrongFocus); setBackgroundRole(QPalette::Base); setAutoFillBackground(true); initAccels(); setAttribute(Qt::WA_Hover, true); d->m_dateDelegate = new KDateTableDateDelegate( this ); d->m_weekDayDelegate = new KDateTableWeekDayDelegate( this ); d->m_weekNumberDelegate = new KDateTableWeekNumberDelegate( this ); d->m_styleOptionDate.initFrom( this ); d->m_styleOptionDate.displayAlignment = Qt::AlignCenter; d->m_styleOptionWeekDay.initFrom( this ); d->m_styleOptionWeekDay.textAlignment = Qt::AlignCenter; d->m_styleOptionWeekNumber.initFrom( this ); d->m_styleOptionWeekNumber.textAlignment = Qt::AlignCenter; //setModel( new KDateTableDataModel( this ) ); setDate(date); } void KDateTable::setStyleOptionDate( const StyleOptionViewItem &so ) { d->m_styleOptionDate = so; } void KDateTable::setStyleOptionWeekDay( const StyleOptionHeader &so ) { d->m_styleOptionWeekDay = so; } void KDateTable::setStyleOptionWeekNumber( const StyleOptionHeader &so ) { d->m_styleOptionWeekNumber = so; } void KDateTable::slotReset() { update(); } void KDateTable::slotDataChanged( const QDate &start, const QDate &end ) { Q_UNUSED(start); Q_UNUSED(end); update(); } void KDateTable::setModel( KDateTableDataModel *model ) { if ( d->m_model ) { - disconnect( d->m_model, SIGNAL( reset() ), this, SLOT( slotReset() ) ); + disconnect( d->m_model, &KDateTableDataModel::reset, this, &KDateTable::slotReset ); } d->m_model = model; if ( d->m_model ) { - connect( d->m_model, SIGNAL( reset() ), this, SLOT( slotReset() ) ); + connect( d->m_model, &KDateTableDataModel::reset, this, &KDateTable::slotReset ); } update(); } KDateTableDataModel *KDateTable::model() const { return d->m_model; } void KDateTable::setDateDelegate( KDateTableDateDelegate *delegate ) { delete d->m_dateDelegate; d->m_dateDelegate = delegate; } void KDateTable::setDateDelegate( const QDate &date, KDateTableDateDelegate *delegate ) { delete d->customPaintingModes.take(date.toJulianDay()); d->customPaintingModes.insert(date.toJulianDay(), delegate); } void KDateTable::setWeekDayDelegate( KDateTableWeekDayDelegate *delegate ) { delete d->m_weekDayDelegate; d->m_weekDayDelegate = delegate; } void KDateTable::setWeekNumberDelegate( KDateTableWeekNumberDelegate *delegate ) { delete d->m_weekNumberDelegate; d->m_weekNumberDelegate = delegate; } void KDateTable::setWeekNumbersEnabled( bool enable ) { d->m_paintweeknumbers = enable; } void KDateTable::setGridEnabled( bool enable ) { d->m_grid = enable; } void KDateTable::initAccels() { KActionCollection* localCollection = new KActionCollection(this); localCollection->addAssociatedWidget(this); QAction* next = localCollection->addAction(QLatin1String("next")); next->setShortcuts(KStandardShortcut::next()); connect(next, SIGNAL(triggered(bool)), SLOT(nextMonth())); QAction* prior = localCollection->addAction(QLatin1String("prior")); prior->setShortcuts(KStandardShortcut::prior()); connect(prior, SIGNAL(triggered(bool)), SLOT(previousMonth())); QAction* beginMonth = localCollection->addAction(QLatin1String("beginMonth")); beginMonth->setShortcuts(KStandardShortcut::home()); connect(beginMonth, SIGNAL(triggered(bool)), SLOT(beginningOfMonth())); QAction* endMonth = localCollection->addAction(QLatin1String("endMonth")); endMonth->setShortcuts(KStandardShortcut::end()); connect(endMonth, SIGNAL(triggered(bool)), SLOT(endOfMonth())); QAction* beginWeek = localCollection->addAction(QLatin1String("beginWeek")); beginWeek->setShortcuts(KStandardShortcut::beginningOfLine()); connect(beginWeek, SIGNAL(triggered(bool)), SLOT(beginningOfWeek())); QAction* endWeek = localCollection->addAction("endWeek"); endWeek->setShortcuts(KStandardShortcut::endOfLine()); connect(endWeek, SIGNAL(triggered(bool)), SLOT(endOfWeek())); localCollection->readSettings(); } int KDateTable::posFromDate( const QDate &date ) { int initialPosition = date.day(); int offset = (d->m_weekDayFirstOfMonth - QLocale().firstDayOfWeek() + 7) % 7; // make sure at least one day of the previous month is visible. // adjust this <1 if more days should be forced visible: if ( offset < 1 ) { offset += 7; } return initialPosition + offset; } QDate KDateTable::dateFromPos( int position ) { int offset = (d->m_weekDayFirstOfMonth - QLocale().firstDayOfWeek() + 7) % 7; // make sure at least one day of the previous month is visible. // adjust this <1 if more days should be forced visible: if ( offset < 1 ) { offset += 7; } return QDate(d->m_date.year(), d->m_date.month(), 1).addDays(position - offset); } void KDateTable::paintEvent(QPaintEvent *e) { QPainter p(this); const QRect &rectToUpdate = e->rect(); double cellWidth = width() / ( d->m_paintweeknumbers ? 8.0 : 7.0 ); double cellHeight = height() / 7.0; int leftCol = (int)std::floor(rectToUpdate.left() / cellWidth); int topRow = (int)std::floor(rectToUpdate.top() / cellHeight); int rightCol = (int)std::ceil(rectToUpdate.right() / cellWidth); int bottomRow = (int)std::ceil(rectToUpdate.bottom() / cellHeight); bottomRow = qMin(bottomRow, 7 - 1); rightCol = qMin(rightCol, ( d->m_paintweeknumbers ? 8 : 7 ) - 1); if (layoutDirection() == Qt::RightToLeft) { p.translate((( d->m_paintweeknumbers ? 8 : 7 ) - leftCol - 1) * cellWidth, topRow * cellHeight); } else { p.translate(leftCol * cellWidth, topRow * cellHeight); } for (int i = leftCol; i <= rightCol; ++i) { for (int j = topRow; j <= bottomRow; ++j) { paintCell(&p, j, i); p.translate(0, cellHeight); } if (layoutDirection() == Qt::RightToLeft) { p.translate(-cellWidth, 0); } else { p.translate(cellWidth, 0); } p.translate(0, -cellHeight * (bottomRow - topRow + 1)); } } void KDateTable::paintCell(QPainter *painter, int row, int column) { //debugPlan; double w = (width() / ( d->m_paintweeknumbers ? 8.0 : 7.0 )) - 1; double h = (height() / 7.0) - 1; QRectF rect( 0, 0, w, h ); QSizeF cell; if ( row == 0 ) { if (column == 0 && d->m_paintweeknumbers ) { // paint something in the corner?? /* painter->setPen(palette().color(QPalette::Text)); painter->drawRect( rect );*/ return; } // we are drawing the headline (weekdays) d->m_styleOptionWeekDay.rectF = rect; d->m_styleOptionWeekDay.state = QStyle::State_None; int col = d->m_paintweeknumbers ? column - 1 : column; int day = col + QLocale().firstDayOfWeek(); if (day >= 8 ) { day -= 7; } if ( d->m_weekDayDelegate ) { cell = d->m_weekDayDelegate->paint( painter, d->m_styleOptionWeekDay, day, d->m_model ).size(); } } else { if ( d->m_paintweeknumbers && column == 0 ) { d->m_styleOptionWeekNumber.rectF = rect; d->m_styleOptionWeekNumber.state = QStyle::State_None; int pos = 7 * (row-1); QDate pCellDate = dateFromPos( pos ); if ( d->m_weekNumberDelegate ) { cell = d->m_weekNumberDelegate->paint( painter, d->m_styleOptionWeekNumber, pCellDate.weekNumber(), d->m_model ).size(); } } else { // draw the dates int col = d->m_paintweeknumbers ? column - 1 : column; int pos = 7 * (row-1) + col; if ( d->m_grid ) { painter->save(); // TODO: do not hardcode color! QPen pen( "lightgrey" ); pen.setWidthF( 0.5 ); painter->setPen( pen ); double pw = painter->pen().width(); if ( col > 0 ) { painter->drawLine( rect.topLeft(), rect.bottomLeft() ); } if ( row > 1 ) { painter->drawLine( rect.topLeft(), rect.topRight() ); } rect = rect.adjusted(pw, pw, 0, 0 ); painter->restore(); //debugPlan<m_grid<<" "<m_styleOptionDate.rectF = rect; d->m_styleOptionDate.state = QStyle::State_None; QDate pCellDate = dateFromPos( pos ); if( pCellDate.month() == d->m_date.month() ) { d->m_styleOptionDate.state |= QStyle::State_Active; } if ( d->m_selectedDates.contains( pCellDate ) ) { d->m_styleOptionDate.state |= QStyle::State_Selected; } if ( isEnabled() ) { d->m_styleOptionDate.state |= QStyle::State_Enabled; if (pos == d->m_hoveredPos) { d->m_styleOptionDate.state |= QStyle::State_MouseOver; } } if ( pCellDate == d->m_date ) { d->m_styleOptionDate.state |= QStyle::State_Active; if ( d->m_selectionmode != SingleSelection && hasFocus() ) { d->m_styleOptionDate.state |= QStyle::State_HasFocus; } } KDateTableDateDelegate *del = d->customPaintingModes.value( pCellDate.toJulianDay() ); if ( del == 0 ) { del = d->m_dateDelegate; } if ( del ) { //debugPlan<paint( painter, d->m_styleOptionDate, pCellDate, d->m_model ).size(); } else { warnPlan<<"No delegate!"; } } } // If the day cell we just drew is bigger than the current max cell sizes, // then adjust the max to the current cell if (cell.width() > d->m_maxCell.width()) { d->m_maxCell.setWidth(cell.width()); } if (cell.height() > d->m_maxCell.height()) { d->m_maxCell.setHeight(cell.height()); } } void KDateTable::KDateTablePrivate::nextMonth() { // setDate does validity checking for us q->setDate(m_date.addMonths(1)); } void KDateTable::KDateTablePrivate::previousMonth() { // setDate does validity checking for us q->setDate(m_date.addMonths(-1)); } void KDateTable::KDateTablePrivate::beginningOfMonth() { // setDate does validity checking for us q->setDate(QDate(m_date.year(), m_date.month(), 1)); } void KDateTable::KDateTablePrivate::endOfMonth() { // setDate does validity checking for us q->setDate(QDate(m_date.year(), m_date.month() + 1, 0)); } void KDateTable::KDateTablePrivate::beginningOfWeek() { // setDate does validity checking for us q->setDate(m_date.addDays(1 - m_date.dayOfWeek())); } void KDateTable::KDateTablePrivate::endOfWeek() { // setDate does validity checking for us q->setDate(m_date.addDays(7 - m_date.dayOfWeek())); } void KDateTable::keyPressEvent( QKeyEvent *e ) { QDate cd = d->m_date; switch( e->key() ) { case Qt::Key_Up: // setDate does validity checking for us setDate(d->m_date.addDays(-7)); break; case Qt::Key_Down: // setDate does validity checking for us setDate(d->m_date.addDays(7)); break; case Qt::Key_Left: // setDate does validity checking for us setDate(d->m_date.addDays(-1)); break; case Qt::Key_Right: // setDate does validity checking for us setDate(d->m_date.addDays(1)); break; case Qt::Key_Minus: // setDate does validity checking for us setDate(d->m_date.addDays(-1)); break; case Qt::Key_Plus: // setDate does validity checking for us setDate(d->m_date.addDays(1)); break; case Qt::Key_N: // setDate does validity checking for us setDate(QDate::currentDate()); break; case Qt::Key_Return: case Qt::Key_Enter: emit tableClicked(); break; case Qt::Key_Control: case Qt::Key_Alt: case Qt::Key_Meta: case Qt::Key_Shift: // Don't beep for modifiers break; default: if (!e->modifiers()) { // hm KNotification::beep(); } } switch( e->key() ) { case Qt::Key_Down: case Qt::Key_Up: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Minus: case Qt::Key_Plus: { if ( d->m_selectionmode == ExtendedSelection ) { if ( e->modifiers() & Qt::ShiftModifier ) { int inc = cd > d->m_date ? 1 : -1; for ( QDate dd = d->m_date; dd != cd; dd = dd.addDays( inc ) ) { if ( ! d->m_selectedDates.contains( dd ) ) { d->m_selectedDates << dd; } } } else if ( e->modifiers() & Qt::ControlModifier ) { // keep selection, just move on } else { d->m_selectedDates.clear(); } } break;} case Qt::Key_Space: case Qt::Key_Select: if ( d->m_selectionmode == ExtendedSelection ) { if ( e->modifiers() & Qt::ControlModifier ) { if ( d->m_selectedDates.contains( d->m_date ) ) { d->m_selectedDates.removeAt( d->m_selectedDates.indexOf( d->m_date ) ); } else { d->m_selectedDates << d->m_date; } } else if ( ! d->m_selectedDates.contains( d->m_date ) ) { d->m_selectedDates << d->m_date; } update(); } break; case Qt::Key_Menu: if ( d->m_popupMenuEnabled ) { QMenu *menu = new QMenu(); if ( d->m_selectionmode == ExtendedSelection ) { emit aboutToShowContextMenu( menu, d->m_selectedDates ); } else { menu->setTitle( QLocale().toString(d->m_date, QLocale::ShortFormat) ); emit aboutToShowContextMenu( menu, d->m_date ); } if ( menu->isEmpty() ) { delete menu; } else { int p = posFromDate( d->m_date ) - 1; int col = p % 7; int row = p / 7; QPoint pos = geometry().topLeft(); QSize size = geometry().size(); int sx = size.width() / 8; int sy = size.height() / 7; pos = QPoint( pos.x() + sx + sx / 2 + sx * col, pos.y() + sy + sy * row ); debugPlan<popup(mapToGlobal(pos)); } } break; } } void KDateTable::setFontSize(int size) { QFontMetricsF metrics(fontMetrics()); QRectF rect; // ----- store rectangles: d->fontsize = size; // ----- find largest day name: d->m_maxCell.setWidth(0); d->m_maxCell.setHeight(0); QLocale locale; for (int weekday = 1; weekday <= 7; ++weekday) { rect = metrics.boundingRect(locale.dayName(weekday, QLocale::ShortFormat)); d->m_maxCell.setWidth(qMax(d->m_maxCell.width(), rect.width())); d->m_maxCell.setHeight(qMax(d->m_maxCell.height(), rect.height())); } // ----- compare with a real wide number and add some space: rect = metrics.boundingRect(QStringLiteral("88")); d->m_maxCell.setWidth(qMax(d->m_maxCell.width() + 2, rect.width())); d->m_maxCell.setHeight(qMax(d->m_maxCell.height() + 4, rect.height())); } void KDateTable::wheelEvent ( QWheelEvent * e ) { setDate(d->m_date.addMonths( -(int)(e->delta()/120)) ); e->accept(); } bool KDateTable::event( QEvent *ev ) { switch (ev->type()) { case QEvent::HoverMove: { QHoverEvent *e = static_cast(ev); const int row = e->pos().y() * 7 / height(); int col; if (layoutDirection() == Qt::RightToLeft) { col = (d->m_paintweeknumbers ? 8 : 7) - (e->pos().x() * (d->m_paintweeknumbers ? 8 : 7) / width()) - 1; } else { col = e->pos().x() * (d->m_paintweeknumbers ? 8 : 7) / width(); } const int pos = row < 1 ? -1 : ((d->m_paintweeknumbers ? 8 : 7) * (row - 1)) + col; if (pos != d->m_hoveredPos) { d->m_hoveredPos = pos; update(); } break; } case QEvent::HoverLeave: if (d->m_hoveredPos != -1) { d->m_hoveredPos = -1; update(); } break; case QEvent::ToolTip: { //debugPlan<<"Tooltip"; QHelpEvent *e = static_cast( ev ); double cellWidth = width() / ( d->m_paintweeknumbers ? 8.0 : 7.0 ); double cellHeight = height() / 7.0; int column = (int)std::floor(e->pos().x() / cellWidth); int row = (int)std::floor(e->pos().y() / cellHeight); QString text; if ( row == 0 ) { if (column == 0 && d->m_paintweeknumbers ) { // corner } else { // we are drawing the headline (weekdays) int col = d->m_paintweeknumbers ? column - 1 : column; int day = col + QLocale().firstDayOfWeek(); if (day >= 8 ) { day -= 7; } if ( d->m_weekDayDelegate ) { text = d->m_weekDayDelegate->data( day, Qt::ToolTipRole, d->m_model ).toString(); } } } else { if ( d->m_paintweeknumbers && column == 0 ) { int pos = 7 * (row-1); QDate pCellDate = dateFromPos( pos ); if ( d->m_weekNumberDelegate ) { text = d->m_weekNumberDelegate->data( pCellDate.weekNumber(), Qt::ToolTipRole, d->m_model ).toString(); } } else { // draw the dates int col = d->m_paintweeknumbers ? column - 1 : column; int pos=7*(row-1)+col; QDate pCellDate = dateFromPos( pos ); if ( d->m_dateDelegate ) { text = d->m_dateDelegate->data( pCellDate, Qt::ToolTipRole, d->m_model ).toString(); } } } //debugPlan<globalPos(), text ); } e->accept(); return true; break; } default: break; } return QWidget::event(ev); } void KDateTable::mousePressEvent(QMouseEvent *e) { if(e->type()!=QEvent::MouseButtonPress) { // the KDatePicker only reacts on mouse press events: return; } if(!isEnabled()) { KNotification::beep(); return; } int row, col, pos; QPoint mouseCoord = e->pos(); row = mouseCoord.y() * 7 / height(); if (layoutDirection() == Qt::RightToLeft) { col = ( d->m_paintweeknumbers ? 8 : 7 ) - (mouseCoord.x() * ( d->m_paintweeknumbers ? 8 : 7 ) / width()) - 1; } else { col = mouseCoord.x() * ( d->m_paintweeknumbers ? 8 : 7 ) / width(); } //debugPlan<m_maxCell<<", "<m_paintweeknumbers ) { --col; } if (row < 1 || col < 0) { // the user clicked on the frame of the table return; } // Rows and columns are zero indexed. The (row - 1) below is to avoid counting // the row with the days of the week in the calculation. // new position and date pos = (7 * (row - 1)) + col; QDate clickedDate = dateFromPos( pos ); if ( d->m_selectionmode != ExtendedSelection || e->button() != Qt::RightButton || ! d->m_selectedDates.contains( clickedDate ) ) { switch ( d->m_selectionmode ) { case SingleSelection: break; case ExtendedSelection: //debugPlan<<"extended "<modifiers()<<", "<modifiers() & Qt::ShiftModifier ) { if ( d->m_selectedDates.isEmpty() ) { d->m_selectedDates << clickedDate; } else if ( d->m_date != clickedDate ) { QDate dt = d->m_date; int nxt = dt < clickedDate ? 1 : -1; if ( d->m_selectedDates.contains( clickedDate ) ) { d->m_selectedDates.removeAt( d->m_selectedDates.indexOf( clickedDate ) ); } while ( dt != clickedDate ) { if ( ! d->m_selectedDates.contains( dt ) ) { d->m_selectedDates << dt; } dt = dt.addDays( nxt ); } d->m_selectedDates << clickedDate; } else { break; // selection not changed } } else if ( e->modifiers() & Qt::ControlModifier ) { if ( d->m_selectedDates.contains( clickedDate ) ) { d->m_selectedDates.removeAt( d->m_selectedDates.indexOf( clickedDate ) ); } else { d->m_selectedDates << clickedDate; } } else { d->m_selectedDates.clear(); d->m_selectedDates << clickedDate; } emit selectionChanged( d->m_selectedDates ); break; default: break; } // set the new date. If it is in the previous or next month, the month will // automatically be changed, no need to do that manually... // validity checking done inside setDate setDate( clickedDate ); // This could be optimized to only call update over the regions // of old and new cell, but 99% of times there is also a call to // setDate that already calls update() so no need to optimize that // much here update(); } emit tableClicked(); if (e->button() == Qt::RightButton && d->m_popupMenuEnabled ) { QMenu *menu = new QMenu(); if ( d->m_selectionmode == ExtendedSelection ) { emit aboutToShowContextMenu( menu, d->m_selectedDates ); } else { menu->setTitle( QLocale().toString(clickedDate, QLocale::ShortFormat) ); emit aboutToShowContextMenu( menu, clickedDate ); } menu->popup(e->globalPos()); } } bool KDateTable::setDate(const QDate& date_) { if (!date_.isValid()) { debugPlan << "KDateTable::setDate: refusing to set invalid date."; return false; } if (d->m_date != date_) { const QDate oldDate = d->m_date; d->m_date = date_; if (oldDate.year() != date_.year() || oldDate.month() != date_.month()) { QDate dt(date_.year(), date_.month(), 1); d->m_weekDayFirstOfMonth = dt.dayOfWeek(); } emit dateChanged(oldDate, date_); emit dateChanged(date_); } if ( d->m_selectionmode == KDateTable::SingleSelection ) { d->m_selectedDates.clear(); d->m_selectedDates << date_; emit selectionChanged( d->m_selectedDates ); } update(); return true; } const QDate &KDateTable::date() const { return d->m_date; } void KDateTable::focusInEvent( QFocusEvent *e ) { QWidget::focusInEvent( e ); } void KDateTable::focusOutEvent( QFocusEvent *e ) { QWidget::focusOutEvent( e ); } QSize KDateTable::sizeHint() const { if(d->m_maxCell.height() > 0 && d->m_maxCell.width() > 0) { int s = d->m_paintweeknumbers ? 8 : 7; return QSize(qRound(d->m_maxCell.width() * s), (qRound(d->m_maxCell.height() + 2) * s)); } else { debugPlan << "KDateTable::sizeHint: obscure failure - "; return QSize(-1, -1); } } void KDateTable::setPopupMenuEnabled( bool enable ) { d->m_popupMenuEnabled=enable; } bool KDateTable::popupMenuEnabled() const { return d->m_popupMenuEnabled; } void KDateTable::setCustomDatePainting(const QDate &date, const QColor &fgColor, BackgroundMode bgMode, const QColor &bgColor) { KDateTableCustomDateDelegate *del = new KDateTableCustomDateDelegate(); del->fgColor = fgColor; del->bgMode = bgMode; del->bgColor = bgColor; setDateDelegate( date, del ); update(); } void KDateTable::unsetCustomDatePainting(const QDate &date) { d->customPaintingModes.remove(date.toJulianDay()); } void KDateTable::setSelectionMode( SelectionMode mode ) { d->m_selectionmode = mode; } //----------------------- KDateTableDataModel::KDateTableDataModel( QObject *parent ) : QObject( parent ) { } KDateTableDataModel::~KDateTableDataModel() { } QVariant KDateTableDataModel::data( const QDate &date, int role, int dataType ) const { Q_UNUSED(date); Q_UNUSED(role); Q_UNUSED(dataType); return QVariant(); } QVariant KDateTableDataModel::weekDayData( int day, int role ) const { Q_UNUSED(day); Q_UNUSED(role); return QVariant(); } QVariant KDateTableDataModel::weekNumberData( int week, int role ) const { Q_UNUSED(week); Q_UNUSED(role); return QVariant(); } //------------- KDateTableDateDelegate::KDateTableDateDelegate( QObject *parent ) : QObject( parent ) { } QVariant KDateTableDateDelegate::data( const QDate &date, int role, KDateTableDataModel *model ) { //debugPlan<data( date, role ); } QRectF KDateTableDateDelegate::paint( QPainter *painter, const StyleOptionViewItem &option, const QDate &date, KDateTableDataModel *model ) { //debugPlan<save(); QRectF r; QPalette palette = option.palette; if ( option.state & QStyle::State_Enabled && option.state & QStyle::State_Active ) { palette.setCurrentColorGroup( QPalette::Active ); } else { palette.setCurrentColorGroup( QPalette::Inactive ); } // TODO: honor QStyle::State_MouseOver, and perhaps switch to style()->drawPrimitive(QStyle::PE_PanelItemViewItem, ... QFont font = option.font; QColor textColor = palette.text().color(); QBrush bg( palette.base() ); Qt::Alignment align = option.displayAlignment; QString text = QLocale().toString(date.day()); if ( model ) { QVariant v = model->data( date, Qt::ForegroundRole ); if ( v.isValid() ) { textColor = v.value(); } v = model->data( date, Qt::BackgroundRole ); if ( v.isValid() ) { bg.setColor( v.value() ); } v = model->data( date ); if ( v.isValid() ) { text = v.toString(); } v = model->data( date, Qt::TextAlignmentRole ); if ( v.isValid() ) { align = (Qt::Alignment)v.toInt(); } v = model->data( date, Qt::FontRole ); if ( v.isValid() ) { font = v.value(); } } QPen pen = painter->pen(); pen.setColor( textColor ); if ( option.state & QStyle::State_Selected ) { bg = palette.highlight(); } painter->fillRect( option.rectF, bg ); painter->setBrush( bg ); if ( option.state & QStyle::State_HasFocus ) { painter->setPen( palette.text().color() ); painter->setPen( Qt::DotLine ); painter->drawRect( option.rectF ); } else if ( date == QDate::currentDate() ) { painter->setPen( palette.text().color() ); painter->drawRect( option.rectF ); } if ( option.state & QStyle::State_Selected ) { pen.setColor( palette.highlightedText().color() ); } painter->setFont( font ); painter->setPen( pen ); painter->drawText( option.rectF, align, text, &r ); painter->restore(); return r; } //--------- KDateTableCustomDateDelegate::KDateTableCustomDateDelegate( QObject *parent ) : KDateTableDateDelegate( parent ) { } QRectF KDateTableCustomDateDelegate::paint( QPainter *painter, const StyleOptionViewItem &option, const QDate &date, KDateTableDataModel *model ) { //debugPlan<save(); QRectF r; bool paintRect=true; QBrush bg(option.palette.base()); if( (option.state & QStyle::State_Active) == 0 ) { // we are either // ° painting a day of the previous month or // ° painting a day of the following month // TODO: don't hardcode gray here! Use a color with less contrast to the background than normal text. painter->setPen( option.palette.color(QPalette::Mid) ); // painter->setPen(gray); } else { // paint a day of the current month if (bgMode != KDateTable::NoBgMode) { QBrush oldbrush=painter->brush(); painter->setBrush( bgColor ); switch(bgMode) { case(KDateTable::CircleMode) : painter->drawEllipse(option.rectF);break; case(KDateTable::RectangleMode) : painter->drawRect(option.rectF);break; case(KDateTable::NoBgMode) : // Should never be here, but just to get one // less warning when compiling default: break; } painter->setBrush( oldbrush ); paintRect=false; } painter->setPen( fgColor ); QPen pen=painter->pen(); if ( option.state & QStyle::State_Selected ) { // draw the currently selected date //debugPlan<<"selected: "<setPen(option.palette.color(QPalette::Highlight)); painter->setBrush(option.palette.color(QPalette::Highlight)); } else { //debugPlan<<"disabled & selected: "<setPen(option.palette.color(QPalette::Text)); painter->setBrush(option.palette.color(QPalette::Text)); } pen=option.palette.color(QPalette::HighlightedText); } else { painter->setBrush(option.palette.color(QPalette::Background)); painter->setPen(option.palette.color(QPalette::Background)); } if ( date == QDate::currentDate() ) { painter->setPen(option.palette.color(QPalette::Text)); } if ( paintRect ) { painter->drawRect(option.rectF); } painter->setPen(pen); QString text = QLocale().toString(date.day()); if ( model ) { QVariant v = model->data( date ); if ( v.isValid() ) { text = v.toString(); } } painter->drawText(option.rectF, Qt::AlignCenter, text, &r); } painter->restore(); return r; } //--------- KDateTableWeekDayDelegate::KDateTableWeekDayDelegate( QObject *parent ) : QObject( parent ) { } QVariant KDateTableWeekDayDelegate::data( int day, int role, KDateTableDataModel *model ) { //debugPlan<weekDayData( day, role ); } QRectF KDateTableWeekDayDelegate::paint( QPainter *painter, const StyleOptionHeader &option, int daynum, KDateTableDataModel *model ) { //debugPlan<save(); QPalette palette = option.palette; if ( option.state & QStyle::State_Active ) { palette.setCurrentColorGroup( QPalette::Active ); } else { palette.setCurrentColorGroup( QPalette::Inactive ); } QRectF rect; QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); // font.setBold(true); painter->setFont(font); QColor titleColor( palette.button().color() ); QColor textColor( palette.buttonText().color() ); painter->setPen(titleColor); painter->setBrush(titleColor); painter->drawRect(option.rectF); QString value; if ( model ) { QVariant v = model->weekDayData( daynum, Qt::DisplayRole ); if ( v.isValid() ) { value = v.toString(); } } if (value.isEmpty()) { value = QLocale().dayName(daynum, QLocale::ShortFormat); } //debugPlan<setPen( textColor ); painter->drawText(option.rectF, option.textAlignment, value, &rect); // painter->setPen( palette.color(QPalette::Text) ); // painter->drawLine(QPointF(0, option.rectF.height()), QPointF(option.rectF.width(), option.rectF.height())); painter->restore(); return rect; } //--------- KDateTableWeekNumberDelegate::KDateTableWeekNumberDelegate( QObject *parent ) : QObject( parent ) { } QVariant KDateTableWeekNumberDelegate::data( int week, int role, KDateTableDataModel *model ) { //debugPlan<weekNumberData( week, role ); } QRectF KDateTableWeekNumberDelegate::paint( QPainter *painter, const StyleOptionHeader &option, int week, KDateTableDataModel *model ) { //debugPlan; painter->save(); QRectF result; QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); painter->setFont(font); QColor titleColor( option.palette.button().color() ); QColor textColor( option.palette.buttonText().color() ); painter->setPen(titleColor); painter->setBrush(titleColor); painter->drawRect(option.rectF); painter->setPen(textColor); QString value = QString("%1").arg( week ); if ( model ) { QVariant v = model->weekNumberData( week, Qt::DisplayRole ); if ( v.isValid() ) { value = v.toString(); } } painter->drawText(option.rectF, option.textAlignment, value, &result); // painter->setPen(option.palette.color(QPalette::Text)); // painter->drawLine(QPointF(option.rectF.width(), 0), QPointF(option.rectF.width(), option.rectF.height())); painter->restore(); return result; } } //namespace KPlato #include "moc_kdatetable.cpp" diff --git a/src/libs/models/kptaccountsmodel.cpp b/src/libs/models/kptaccountsmodel.cpp index 98e26dc5..ea5b1ae4 100644 --- a/src/libs/models/kptaccountsmodel.cpp +++ b/src/libs/models/kptaccountsmodel.cpp @@ -1,1157 +1,1157 @@ /* This file is part of the KDE project Copyright (C) 2007, 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. */ #include "kptaccountsmodel.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptaccount.h" #include "kptdatetime.h" #include "kptschedule.h" #include "kptdebug.h" #include #include namespace KPlato { //-------------------------------------- AccountModel::AccountModel() : QObject(), m_project( 0 ) { } const QMetaEnum AccountModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } int AccountModel::propertyCount() const { return columnMap().keyCount(); } QVariant AccountModel::data( const Account *a, int property, int role ) const { QVariant result; if ( a == 0 ) { return QVariant(); } switch ( property ) { case AccountModel::Name: result = name( a, role ); break; case AccountModel::Description: result = description( a, role ); break; default: debugPlan<<"data: invalid display value column"<name()<<","<name(); case Qt::ToolTipRole: if ( a->isDefaultAccount() ) { return xi18nc( "1=account name", "%1 (Default account)", a->name() ); } return a->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::CheckStateRole: if ( a->isDefaultAccount() ) { return m_project && m_project->isBaselined() ? Qt::PartiallyChecked : Qt::Checked; } return m_project && m_project->isBaselined() ? QVariant() : Qt::Unchecked; case Qt::DecorationRole: if ( a->isBaselined() ) { return koIcon("view-time-schedule-baselined"); } break; } return QVariant(); } QVariant AccountModel::description( const Account *a, int role ) const { //debugPlan<name()<<","<description(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant AccountModel::headerData( int property, int role ) const { if ( role == Qt::DisplayRole ) { switch ( property ) { case AccountModel::Name: return i18n( "Name" ); case AccountModel::Description: return i18n( "Description" ); default: return QVariant(); } } if ( role == Qt::TextAlignmentRole ) { return QVariant(); } if ( role == Qt::ToolTipRole ) { switch ( property ) { case AccountModel::Name: return ToolTip::accountName(); case AccountModel::Description: return ToolTip::accountDescription(); default: return QVariant(); } } return QVariant(); } //---------------------------------------- AccountItemModel::AccountItemModel( QObject *parent ) : ItemModelBase( parent ), m_account( 0 ) { } AccountItemModel::~AccountItemModel() { } const QMetaEnum AccountItemModel::columnMap() const { return m_model.columnMap(); } void AccountItemModel::slotAccountToBeInserted( const Account *parent, int row ) { //debugPlan<name(); Q_ASSERT( m_account == 0 ); m_account = const_cast(parent); beginInsertRows( index( parent ), row, row ); } void AccountItemModel::slotAccountInserted( const Account *account ) { //debugPlan<name(); Q_ASSERT( account->parent() == m_account ); Q_UNUSED( account ); endInsertRows(); m_account = 0; } void AccountItemModel::slotAccountToBeRemoved( const Account *account ) { //debugPlan<name(); Q_ASSERT( m_account == 0 ); m_account = const_cast(account); int row = index( account ).row(); beginRemoveRows( index( account->parent() ), row, row ); } void AccountItemModel::slotAccountRemoved( const Account *account ) { //debugPlan<name(); Q_ASSERT( account == m_account ); Q_UNUSED( account ); endRemoveRows(); m_account = 0; } void AccountItemModel::setProject( Project *project ) { if ( m_project ) { Accounts *acc = &( m_project->accounts() ); - disconnect( acc , SIGNAL(changed(KPlato::Account*)), this, SLOT(slotAccountChanged(KPlato::Account*)) ); + disconnect( acc , &Accounts::changed, this, &AccountItemModel::slotAccountChanged ); - disconnect( acc, SIGNAL(accountAdded(const KPlato::Account*)), this, SLOT(slotAccountInserted(const KPlato::Account*)) ); - disconnect( acc, SIGNAL(accountToBeAdded(const KPlato::Account*,int)), this, SLOT(slotAccountToBeInserted(const KPlato::Account*,int)) ); + disconnect( acc, &Accounts::accountAdded, this, &AccountItemModel::slotAccountInserted ); + disconnect( acc, &Accounts::accountToBeAdded, this, &AccountItemModel::slotAccountToBeInserted ); - disconnect( acc, SIGNAL(accountRemoved(const KPlato::Account*)), this, SLOT(slotAccountRemoved(const KPlato::Account*)) ); - disconnect( acc, SIGNAL(accountToBeRemoved(const KPlato::Account*)), this, SLOT(slotAccountToBeRemoved(const KPlato::Account*)) ); + disconnect( acc, &Accounts::accountRemoved, this, &AccountItemModel::slotAccountRemoved ); + disconnect( acc, &Accounts::accountToBeRemoved, this, &AccountItemModel::slotAccountToBeRemoved ); } m_project = project; m_model.m_project = project; if ( project ) { Accounts *acc = &( project->accounts() ); debugPlan<isBaselined() ) { flags |= Qt::ItemIsEditable; flags |= Qt::ItemIsUserCheckable; } break; } default: flags |= Qt::ItemIsEditable; break; } } return flags; } QModelIndex AccountItemModel::parent( const QModelIndex &index ) const { if ( !index.isValid() || m_project == 0 ) { return QModelIndex(); } //debugPlan<parent(); if ( par ) { a = par->parent(); int row = -1; if ( a ) { row = a->accountList().indexOf( par ); } else { row = m_project->accounts().accountList().indexOf( par ); } //debugPlan<name()<<":"<= columnCount() || row < 0 ) { return QModelIndex(); } Account *par = account( parent ); if ( par == 0 ) { if ( row < m_project->accounts().accountList().count() ) { return createIndex( row, column, m_project->accounts().accountList().at( row ) ); } } else if ( row < par->accountList().count() ) { return createIndex( row, column, par->accountList().at( row ) ); } return QModelIndex(); } QModelIndex AccountItemModel::index( const Account *account, int column ) const { Account *a = const_cast(account); if ( m_project == 0 || account == 0 ) { return QModelIndex(); } int row = -1; Account *par = a->parent(); if ( par == 0 ) { row = m_project->accounts().accountList().indexOf( a ); } else { row = par->accountList().indexOf( a ); } if ( row == -1 ) { return QModelIndex(); } return createIndex( row, column, a ); } int AccountItemModel::columnCount( const QModelIndex & ) const { return m_model.propertyCount(); } int AccountItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 ) { return 0; } Account *par = account( parent ); if ( par == 0 ) { return m_project->accounts().accountList().count(); } return par->accountList().count(); } bool AccountItemModel::setName( Account *a, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() != a->name() ) { emit executeCommand( new RenameAccountCmd( a, value.toString(), kundo2_i18n( "Modify account name" ) ) ); } return true; case Qt::CheckStateRole: { switch ( value.toInt() ) { case Qt::Unchecked: if ( a->isDefaultAccount() ) { emit executeCommand( new ModifyDefaultAccountCmd( m_project->accounts(), a, 0, kundo2_i18n( "De-select as default account" ) ) ); return true; } break; case Qt::Checked: if ( ! a->isDefaultAccount() ) { emit executeCommand( new ModifyDefaultAccountCmd( m_project->accounts(), m_project->accounts().defaultAccount(), a, kundo2_i18n( "Select as default account" ) ) ); return true; } break; default: break; } } default: break; } return false; } bool AccountItemModel::setDescription( Account *a, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() != a->description() ) { emit executeCommand( new ModifyAccountDescriptionCmd( a, value.toString(), kundo2_i18n( "Modify account description" ) ) ); } return true; } return false; } QVariant AccountItemModel::data( const QModelIndex &index, int role ) const { QVariant result; Account *a = account( index ); if ( a == 0 ) { return QVariant(); } result = m_model.data( a, index.column(), role ); return result; } bool AccountItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } if ( ( flags( index ) &( Qt::ItemIsEditable | Qt::CheckStateRole ) ) == 0 ) { Q_ASSERT( true ); return false; } Account *a = account( index ); debugPlan<name()<( index.internalPointer() ); } void AccountItemModel::slotAccountChanged( Account *account ) { Account *par = account->parent(); if ( par ) { int row = par->accountList().indexOf( account ); emit dataChanged( createIndex( row, 0, account ), createIndex( row, columnCount() - 1, account ) ); } else { int row = m_project->accounts().accountList().indexOf( account ); emit dataChanged( createIndex( row, 0, account ), createIndex( row, columnCount() - 1, account ) ); } } QModelIndex AccountItemModel::insertAccount( Account *account, Account *parent, int index ) { debugPlan; if ( account->name().isEmpty() || m_project->accounts().findAccount( account->name() ) ) { QString s = parent == 0 ? account->name() : parent->name(); account->setName( m_project->accounts().uniqueId( s ) ); //m_project->accounts().insertId( account ); } emit executeCommand( new AddAccountCmd( *m_project, account, parent, index, kundo2_i18n( "Add account" ) ) ); int row = -1; if ( parent ) { row = parent->accountList().indexOf( account ); } else { row = m_project->accounts().accountList().indexOf( account ); } if ( row != -1 ) { //debugPlan<<"Inserted:"<name(); return createIndex( row, 0, account ); } debugPlan<<"Can't find"<name(); return QModelIndex(); } void AccountItemModel::removeAccounts( QList lst ) { MacroCommand *cmd = 0; KUndo2MagicString c = kundo2_i18np( "Delete Account", "Delete %1 Accounts", lst.count() ); while ( ! lst.isEmpty() ) { bool del = true; Account *acc = lst.takeFirst(); foreach ( Account *a, lst ) { if ( acc->isChildOf( a ) ) { del = false; // acc will be deleted when a is deleted break; } } if ( del ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new RemoveAccountCmd( *m_project, acc ) ); } } if ( cmd ) emit executeCommand( cmd ); } //---------------------------------------- CostBreakdownItemModel::CostBreakdownItemModel( QObject *parent ) : ItemModelBase( parent ), m_manager( 0 ), m_cumulative( false ), m_periodtype( Period_Day ), m_startmode( StartMode_Project ), m_endmode( EndMode_Project ), m_showmode( ShowMode_Both ) { m_format = QString( "%1 [%2]" ); } CostBreakdownItemModel::~CostBreakdownItemModel() { } const QMetaEnum CostBreakdownItemModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } int CostBreakdownItemModel::propertyCount() const { return columnMap().keyCount(); } void CostBreakdownItemModel::slotAccountToBeInserted( const Account *parent, int row ) { //debugPlan<name(); beginInsertRows( index( parent ), row, row ); } void CostBreakdownItemModel::slotAccountInserted( const Account *account ) { Q_UNUSED(account); //debugPlan<name(); endInsertRows(); } void CostBreakdownItemModel::slotAccountToBeRemoved( const Account *account ) { //debugPlan<name(); int row = index( account ).row(); beginRemoveRows( index( account->parent() ), row, row ); } void CostBreakdownItemModel::slotAccountRemoved( const Account *account ) { Q_UNUSED(account); //debugPlan<name(); endRemoveRows(); } void CostBreakdownItemModel::slotDataChanged() { fetchData(); QMap::const_iterator it; for (it = m_plannedCostMap.constBegin(); it != m_plannedCostMap.constEnd(); ++it) { QModelIndex idx1 = index(it.key()); QModelIndex idx2 = index( idx1.row(), columnCount() - 1, parent( idx1 ) ); //debugPlan<name()<accounts() ); - disconnect( acc , SIGNAL(changed(KPlato::Account*)), this, SLOT(slotAccountChanged(KPlato::Account*)) ); + disconnect( acc , &Accounts::changed, this, &CostBreakdownItemModel::slotAccountChanged ); - disconnect( acc, SIGNAL(accountAdded(const KPlato::Account*)), this, SLOT(slotAccountInserted(const KPlato::Account*)) ); - disconnect( acc, SIGNAL(accountToBeAdded(const KPlato::Account*,int)), this, SLOT(slotAccountToBeInserted(const KPlato::Account*,int)) ); + disconnect( acc, &Accounts::accountAdded, this, &CostBreakdownItemModel::slotAccountInserted ); + disconnect( acc, &Accounts::accountToBeAdded, this, &CostBreakdownItemModel::slotAccountToBeInserted ); - disconnect( acc, SIGNAL(accountRemoved(const KPlato::Account*)), this, SLOT(slotAccountRemoved(const KPlato::Account*)) ); - disconnect( acc, SIGNAL(accountToBeRemoved(const KPlato::Account*)), this, SLOT(slotAccountToBeRemoved(const KPlato::Account*)) ); + disconnect( acc, &Accounts::accountRemoved, this, &CostBreakdownItemModel::slotAccountRemoved ); + disconnect( acc, &Accounts::accountToBeRemoved, this, &CostBreakdownItemModel::slotAccountToBeRemoved ); - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project , SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotDataChanged()) ); - disconnect( m_project , SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotDataChanged()) ); - disconnect( m_project , SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotDataChanged()) ); + disconnect(m_project, &Project::aboutToBeDeleted, this, &CostBreakdownItemModel::projectDeleted); + disconnect( m_project, &Project::nodeChanged, this, &CostBreakdownItemModel::slotDataChanged ); + disconnect( m_project, &Project::nodeAdded, this, &CostBreakdownItemModel::slotDataChanged ); + disconnect( m_project, &Project::nodeRemoved, this, &CostBreakdownItemModel::slotDataChanged ); - disconnect( m_project , SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotDataChanged()) ); - disconnect( m_project , SIGNAL(resourceAdded(const KPlato::Resource*)), this, SLOT(slotDataChanged()) ); - disconnect( m_project , SIGNAL(resourceRemoved(const KPlato::Resource*)), this, SLOT(slotDataChanged()) ); + disconnect( m_project, &Project::resourceChanged, this, &CostBreakdownItemModel::slotDataChanged ); + disconnect( m_project, &Project::resourceAdded, this, &CostBreakdownItemModel::slotDataChanged ); + disconnect( m_project, &Project::resourceRemoved, this, &CostBreakdownItemModel::slotDataChanged ); } m_project = project; if ( project ) { Accounts *acc = &( project->accounts() ); debugPlan<scheduleId(); } EffortCostMap CostBreakdownItemModel::fetchPlannedCost( Account *account ) { EffortCostMap ec; ec = account->plannedCost( id() ); m_plannedCostMap.insert( account, ec ); QDate s = ec.startDate(); if ( ! m_plannedStart.isValid() || s < m_plannedStart ) { m_plannedStart = s; } QDate e = ec.endDate(); if ( ! m_plannedEnd.isValid() || e > m_plannedEnd ) { m_plannedEnd = e; } return ec; } EffortCostMap CostBreakdownItemModel::fetchActualCost( Account *account ) { debugPlan<name(); EffortCostMap ec; ec = account->actualCost( id() ); m_actualCostMap.insert( account, ec ); QDate s = ec.startDate(); if ( ! m_actualStart.isValid() || s < m_actualStart ) { m_actualStart = s; } QDate e = ec.endDate(); if ( ! m_actualEnd.isValid() || e > m_actualEnd ) { m_actualEnd = e; } debugPlan<name()<accounts().allAccounts() ) { fetchPlannedCost( a ); fetchActualCost( a ); } } QModelIndex CostBreakdownItemModel::parent( const QModelIndex &index ) const { if ( !index.isValid() || m_project == 0 ) { return QModelIndex(); } //debugPlan<parent(); if ( par ) { a = par->parent(); int row = -1; if ( a ) { row = a->accountList().indexOf( par ); } else { row = m_project->accounts().accountList().indexOf( par ); } //debugPlan<name()<<":"<= columnCount() || row < 0 ) { return QModelIndex(); } Account *par = account( parent ); if ( par == 0 ) { if ( row < m_project->accounts().accountList().count() ) { return createIndex( row, column, m_project->accounts().accountList().at( row ) ); } } else if ( row < par->accountList().count() ) { return createIndex( row, column, par->accountList().at( row ) ); } return QModelIndex(); } QModelIndex CostBreakdownItemModel::index( const Account *account ) const { Account *a = const_cast(account); if ( m_project == 0 || account == 0 ) { return QModelIndex(); } int row = -1; Account *par = a->parent(); if ( par == 0 ) { row = m_project->accounts().accountList().indexOf( a ); } else { row = par->accountList().indexOf( a ); } if ( row == -1 ) { return QModelIndex(); } return createIndex( row, 0, a ); } int CostBreakdownItemModel::columnCount( const QModelIndex & ) const { int c = propertyCount(); if ( startDate().isValid() && endDate().isValid() ) { switch ( m_periodtype ) { case Period_Day: { c += startDate().daysTo( endDate()) + 1; break; } case Period_Week: { int days = QLocale().firstDayOfWeek() - startDate().dayOfWeek(); if ( days > 0 ) { days -= 7; } QDate start = startDate().addDays( days ); c += (start.daysTo( endDate() ) / 7) + 1; break; } case Period_Month: { int days = startDate().daysInMonth() - startDate().day() + 1; for ( QDate d = startDate(); d < endDate(); d = d.addDays( days ) ) { ++c; days = qMin( d.daysTo( endDate() ), static_cast(d.daysInMonth()) ); } break; } } } return c; } int CostBreakdownItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 ) { return 0; } Account *par = account( parent ); if ( par == 0 ) { return m_project->accounts().accountList().count(); } return par->accountList().count(); } QString CostBreakdownItemModel::formatMoney( double cost1, double cost2 ) const { if ( m_showmode == ShowMode_Planned ) { return m_project->locale()->formatMoney( cost1, "", 0 ); } if ( m_showmode == ShowMode_Actual ) { return m_project->locale()->formatMoney( cost2, "", 0 ); } if ( m_showmode == ShowMode_Both ) { return QString(m_format).arg(m_project->locale()->formatMoney( cost2, "", 0), m_project->locale()->formatMoney(cost1, "", 0)); } if ( m_showmode == ShowMode_Deviation ) { return m_project->locale()->formatMoney( cost1 - cost2, "", 0 ); } return ""; } QVariant CostBreakdownItemModel::data( const QModelIndex &index, int role ) const { QVariant result; Account *a = account( index ); if ( a == 0 ) { return QVariant(); } if ( role == Qt::DisplayRole ) { switch ( index.column() ) { case Name: return a->name(); case Description: return a->description(); case Total: { return formatMoney( m_plannedCostMap.value( a ).totalCost(), m_actualCostMap.value( a ).totalCost() ); } case Planned: return m_project->locale()->formatMoney( m_plannedCostMap.value( a ).totalCost(), "", 0 ); case Actual: return m_project->locale()->formatMoney( m_actualCostMap.value( a ).totalCost(), "", 0 ); default: { int col = index.column() - propertyCount(); EffortCostMap pc = m_plannedCostMap.value( a ); EffortCostMap ac = m_actualCostMap.value( a ); switch ( m_periodtype ) { case Period_Day: { double planned = 0.0; if ( m_cumulative ) { planned = pc.costTo( startDate().addDays( col ) ); } else { planned = pc.costOnDate( startDate().addDays( col ) ); } double actual = 0.0; if ( m_cumulative ) { actual = ac.costTo( startDate().addDays( col ) ); } else { actual = ac.costOnDate( startDate().addDays( col ) ); } return formatMoney( planned, actual ); } case Period_Week: { int days = QLocale().firstDayOfWeek() - startDate().dayOfWeek(); if ( days > 0 ) { days -= 7; ; } QDate start = startDate().addDays( days ); int week = col; double planned = 0.0; if ( m_cumulative ) { planned = pc.costTo( start.addDays( ++week * 7 ) ); } else { planned = week == 0 ? pc.cost( startDate(), startDate().daysTo( start.addDays( 7 ) ) ) : pc.cost( start.addDays( week * 7 ) ); } double actual = 0.0; if ( m_cumulative ) { actual = ac.costTo( start.addDays( ++week * 7 ) ); } else { actual = week == 0 ? ac.cost( startDate(), startDate().daysTo( start.addDays( 7 ) ) ) : ac.cost( start.addDays( week * 7 ) ); } return formatMoney( planned, actual ); } case Period_Month: { int days = startDate().daysInMonth() - startDate().day() + 1; QDate start = startDate(); for ( int i = 0; i < col; ++i ) { start = start.addDays( days ); days = start.daysInMonth(); } int planned = 0.0; if ( m_cumulative ) { planned = pc.costTo( start.addDays( start.daysInMonth() - start.day() + 1 ) ); } else { planned = pc.cost( start, start.daysInMonth() - start.day() + 1); } int actual = 0.0; if ( m_cumulative ) { actual = ac.costTo( start.addDays( start.daysInMonth() - start.day() + 1 ) ); } else { actual = ac.cost( start, start.daysInMonth() - start.day() + 1); } return formatMoney( planned, actual ); } default: return 0.0; break; } } } } else if ( role == Qt::ToolTipRole ) { switch ( index.column() ) { case Name: return a->name(); case Description: return a->description(); case Total: { double act = m_actualCostMap.value( a ).totalCost(); double pl = m_plannedCostMap.value( a ).totalCost(); return i18n( "Actual total cost: %1, planned total cost: %2", m_project->locale()->formatMoney( act, "", 0 ), m_project->locale()->formatMoney( pl, "", 0 ) ); } case Planned: case Actual: default: break; } } else if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } else { switch ( index.column() ) { case Name: case Description: case Planned: case Actual: return QVariant(); default: { return cost( a, index.column() - propertyCount(), role ); } } } return QVariant(); } QVariant CostBreakdownItemModel::cost( const Account *a, int offset, int role ) const { EffortCostMap costmap; if ( role == Role::Planned ) { costmap = m_plannedCostMap.value( const_cast( a ) ); } else if ( role == Role::Actual ) { costmap = m_actualCostMap.value( const_cast( a ) ); } else { return QVariant(); } double cost = 0.0; switch ( m_periodtype ) { case Period_Day: { if ( m_cumulative ) { cost = costmap.costTo( startDate().addDays( offset ) ); } else { cost = costmap.costOnDate( startDate().addDays( offset ) ); } break; } case Period_Week: { int days = QLocale().firstDayOfWeek() - startDate().dayOfWeek(); if ( days > 0 ) { days -= 7; ; } QDate start = startDate().addDays( days ); int week = offset; if ( m_cumulative ) { cost = costmap.costTo( start.addDays( ++week * 7 ) ); } else { cost = week == 0 ? costmap.cost( startDate(), startDate().daysTo( start.addDays( 7 ) ) ) : costmap.cost( start.addDays( week * 7 ) ); } break; } case Period_Month: { int days = startDate().daysInMonth() - startDate().day() + 1; QDate start = startDate(); for ( int i = 0; i < offset; ++i ) { start = start.addDays( days ); days = start.daysInMonth(); } if ( m_cumulative ) { cost = costmap.costTo( start.addDays( start.daysInMonth() - start.day() + 1 ) ); } else { cost = costmap.cost( start, start.daysInMonth() - start.day() + 1); } break; } default: break; } return cost; } int CostBreakdownItemModel::periodType() const { return m_periodtype; } void CostBreakdownItemModel::setPeriodType( int period ) { if ( m_periodtype != period ) { beginResetModel(); m_periodtype = period; endResetModel(); } } int CostBreakdownItemModel::startMode() const { return m_startmode; } void CostBreakdownItemModel::setStartMode( int mode ) { beginResetModel(); m_startmode = mode; endResetModel(); } int CostBreakdownItemModel::endMode() const { return m_endmode; } void CostBreakdownItemModel::setEndMode( int mode ) { beginResetModel(); m_endmode = mode; endResetModel(); } QDate CostBreakdownItemModel::startDate() const { if ( m_project == 0 || m_manager == 0 ) { return m_start; } switch ( m_startmode ) { case StartMode_Project: { QDate d = m_project->startTime( id() ).date(); if ( m_plannedStart.isValid() && m_plannedStart < d ) { d = m_plannedStart; } if ( m_actualStart.isValid() && m_actualStart < d ) { d = m_actualStart; } return d; } default: break; } return m_start; } void CostBreakdownItemModel::setStartDate( const QDate &date ) { beginResetModel(); m_start = date; endResetModel(); } QDate CostBreakdownItemModel::endDate() const { if ( m_project == 0 || m_manager == 0 ) { return m_end; } switch ( m_endmode ) { case EndMode_Project: { QDate d = m_project->endTime( id() ).date(); if ( m_plannedEnd.isValid() && m_plannedEnd > d ) { d = m_plannedEnd; } if ( m_actualEnd.isValid() && m_actualEnd > d ) { d = m_actualEnd; } return d; } case EndMode_CurrentDate: return QDate::currentDate(); default: break; } return m_end; } void CostBreakdownItemModel::setEndDate( const QDate &date ) { beginResetModel(); m_end = date; endResetModel(); } bool CostBreakdownItemModel::cumulative() const { return m_cumulative; } void CostBreakdownItemModel::setCumulative( bool on ) { beginResetModel(); m_cumulative = on; endResetModel(); } int CostBreakdownItemModel::showMode() const { return m_showmode; } void CostBreakdownItemModel::setShowMode( int show ) { m_showmode = show; } QVariant CostBreakdownItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole ) { switch (section) { case Name: return i18n( "Name" ); case Description: return i18n( "Description" ); case Total: return i18n( "Total" ); case Planned: return i18n("Planned"); case Actual: return i18n("Actual"); default: break; } int col = section - propertyCount(); switch ( m_periodtype ) { case Period_Day: { return startDate().addDays( col ).toString( Qt::ISODate ); } case Period_Week: { return startDate().addDays( ( col ) * 7 ).weekNumber(); } case Period_Month: { int days = startDate().daysInMonth() - startDate().day() + 1; QDate start = startDate(); for ( int i = 0; i < col; ++i ) { start = start.addDays( days ); days = start.daysInMonth(); } return QDate::shortMonthName( start.month() ); } default: return section; break; } return QVariant(); } if ( role == Qt::EditRole ) { switch (section) { case Name: return QStringLiteral( "Name" ); case Description: return QStringLiteral( "Description" ); case Total: return QStringLiteral( "Total" ); case Planned: return QStringLiteral("Planned"); case Actual: return QStringLiteral("Actual"); default: break; } int col = section - propertyCount(); switch ( m_periodtype ) { case Period_Day: { return startDate().addDays( col ); } case Period_Week: { return startDate().addDays( ( col ) * 7 ).weekNumber(); } case Period_Month: { int days = startDate().daysInMonth() - startDate().day() + 1; QDate start = startDate(); for ( int i = 0; i < col; ++i ) { start = start.addDays( days ); days = start.daysInMonth(); } return start.month(); } default: return section; break; } return QVariant(); } if ( role == Qt::ToolTipRole ) { switch ( section ) { case Name: return ToolTip::accountName(); case Description: return ToolTip::accountDescription(); case Total: return i18n( "The total cost for the account shown as: Actual cost [ Planned cost ]" ); case Planned: case Actual: default: return QVariant(); } } if ( role == Qt::TextAlignmentRole ) { switch ( section ) { case Name: return QVariant(); case Description: return QVariant(); default: return (int)(Qt::AlignRight|Qt::AlignVCenter); } return QVariant(); } } return ItemModelBase::headerData(section, orientation, role); } Account *CostBreakdownItemModel::account( const QModelIndex &index ) const { return static_cast( index.internalPointer() ); } void CostBreakdownItemModel::slotAccountChanged( Account *account ) { Q_UNUSED(account); fetchData(); QMap::const_iterator it; for (it = m_plannedCostMap.constBegin(); it != m_plannedCostMap.constEnd(); ++it) { QModelIndex idx1 = index(it.key() ); QModelIndex idx2 = index( idx1.row(), columnCount() - 1, parent( idx1 ) ); //debugPlan<name()< * 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. */ #include "kptcalendarmodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptdatetime.h" #include "kcalendar/kdatetable.h" #include "kptdebug.h" #include #include #include #include #include #ifdef HAVE_KHOLIDAYS #include #endif namespace KPlato { //----------------------------------------- CalendarDayItemModelBase::CalendarDayItemModelBase( QObject *parent ) : ItemModelBase( parent ), m_calendar( 0 ) { } CalendarDayItemModelBase::~CalendarDayItemModelBase() { } void CalendarDayItemModelBase::slotCalendarToBeRemoved( const Calendar *calendar ) { if ( calendar && calendar == m_calendar ) { setCalendar( 0 ); } } void CalendarDayItemModelBase::setCalendar( Calendar *calendar ) { m_calendar = calendar; } void CalendarDayItemModelBase::setProject( Project *project ) { beginResetModel(); setCalendar( 0 ); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project, SIGNAL(calendarToBeRemoved(const KPlato::Calendar*)), this, SLOT(slotCalendarToBeRemoved(const KPlato::Calendar*))); + disconnect(m_project, &Project::aboutToBeDeleted, this, &CalendarDayItemModelBase::projectDeleted); + disconnect( m_project, &Project::calendarToBeRemoved, this, &CalendarDayItemModelBase::slotCalendarToBeRemoved); } m_project = project; if ( project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(calendarToBeRemoved(const KPlato::Calendar*)), this, SLOT(slotCalendarToBeRemoved(const KPlato::Calendar*))); + connect(m_project, &Project::aboutToBeDeleted, this, &CalendarDayItemModelBase::projectDeleted); + connect( m_project, &Project::calendarToBeRemoved, this, &CalendarDayItemModelBase::slotCalendarToBeRemoved); } endResetModel(); } //------------------------------------- CalendarItemModel::CalendarItemModel( QObject *parent ) : ItemModelBase( parent ), m_calendar( 0 ) { } CalendarItemModel::~CalendarItemModel() { } const QMetaEnum CalendarItemModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } void CalendarItemModel::slotCalendarToBeInserted( const Calendar *parent, int row ) { //debugPlan<<(parent?parent->name():"Top level")<<","<(parent); beginInsertRows( index( parent ), row, row ); } void CalendarItemModel::slotCalendarInserted( const Calendar *calendar ) { //debugPlan<name(); Q_ASSERT( calendar->parentCal() == m_calendar ); #ifdef NDEBUG Q_UNUSED(calendar) #endif endInsertRows(); m_calendar = 0; } void CalendarItemModel::slotCalendarToBeRemoved( const Calendar *calendar ) { //debugPlan<name(); int row = index( calendar ).row(); beginRemoveRows( index( calendar->parentCal() ), row, row ); } void CalendarItemModel::slotCalendarRemoved( const Calendar * ) { //debugPlan<name(); endRemoveRows(); } void CalendarItemModel::setProject( Project *project ) { beginResetModel(); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project , SIGNAL(calendarChanged(KPlato::Calendar*)), this, SLOT(slotCalendarChanged(KPlato::Calendar*))); + disconnect(m_project, &Project::aboutToBeDeleted, this, &CalendarItemModel::projectDeleted); + disconnect( m_project , &Project::calendarChanged, this, &CalendarItemModel::slotCalendarChanged); - disconnect( m_project, SIGNAL(calendarAdded(const KPlato::Calendar*)), this, SLOT(slotCalendarInserted(const KPlato::Calendar*))); - disconnect( m_project, SIGNAL(calendarToBeAdded(const KPlato::Calendar*,int)), this, SLOT(slotCalendarToBeInserted(const KPlato::Calendar*,int))); + disconnect( m_project, &Project::calendarAdded, this, &CalendarItemModel::slotCalendarInserted); + disconnect( m_project, &Project::calendarToBeAdded, this, &CalendarItemModel::slotCalendarToBeInserted); - disconnect( m_project, SIGNAL(calendarRemoved(const KPlato::Calendar*)), this, SLOT(slotCalendarRemoved(const KPlato::Calendar*))); - disconnect( m_project, SIGNAL(calendarToBeRemoved(const KPlato::Calendar*)), this, SLOT(slotCalendarToBeRemoved(const KPlato::Calendar*))); + disconnect( m_project, &Project::calendarRemoved, this, &CalendarItemModel::slotCalendarRemoved); + disconnect( m_project, &Project::calendarToBeRemoved, this, &CalendarItemModel::slotCalendarToBeRemoved); } m_project = project; if ( project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(calendarChanged(KPlato::Calendar*)), this, SLOT(slotCalendarChanged(KPlato::Calendar*))); + connect(m_project, &Project::aboutToBeDeleted, this, &CalendarItemModel::projectDeleted); + connect( m_project, &Project::calendarChanged, this, &CalendarItemModel::slotCalendarChanged); - connect( m_project, SIGNAL(calendarAdded(const KPlato::Calendar*)), this, SLOT(slotCalendarInserted(const KPlato::Calendar*))); - connect( m_project, SIGNAL(calendarToBeAdded(const KPlato::Calendar*,int)), this, SLOT(slotCalendarToBeInserted(const KPlato::Calendar*,int))); + connect( m_project, &Project::calendarAdded, this, &CalendarItemModel::slotCalendarInserted); + connect( m_project, &Project::calendarToBeAdded, this, &CalendarItemModel::slotCalendarToBeInserted); - connect( m_project, SIGNAL(calendarRemoved(const KPlato::Calendar*)), this, SLOT(slotCalendarRemoved(const KPlato::Calendar*))); - connect( m_project, SIGNAL(calendarToBeRemoved(const KPlato::Calendar*)), this, SLOT(slotCalendarToBeRemoved(const KPlato::Calendar*))); + connect( m_project, &Project::calendarRemoved, this, &CalendarItemModel::slotCalendarRemoved); + connect( m_project, &Project::calendarToBeRemoved, this, &CalendarItemModel::slotCalendarToBeRemoved); } endResetModel(); } Qt::ItemFlags CalendarItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); if ( !m_readWrite ) { return flags &= ~Qt::ItemIsEditable; } flags |= Qt::ItemIsDropEnabled; if ( !index.isValid() ) { return flags; } Calendar *c = calendar(index); if (!c || c->isShared()) { if (index.column() == Name) { flags |= Qt::ItemIsUserCheckable; } return flags; } flags |= Qt::ItemIsDragEnabled; if ( calendar ( index ) ) { switch ( index.column() ) { case Name: flags |= ( Qt::ItemIsEditable | Qt::ItemIsUserCheckable ); break; case Scope: flags &= ~Qt::ItemIsEditable; break; case TimeZone: if ( parent( index ).isValid() ) { flags &= ~Qt::ItemIsEditable; } else { flags |= Qt::ItemIsEditable; } break; #ifdef HAVE_KHOLIDAYS case HolidayRegion: flags |= Qt::ItemIsEditable; break; #endif default: flags |= Qt::ItemIsEditable; break; } } return flags; } QModelIndex CalendarItemModel::parent( const QModelIndex &index ) const { if ( !index.isValid() || m_project == 0 ) { return QModelIndex(); } //debugPlan<parentCal(); if ( par ) { a = par->parentCal(); int row = -1; if ( a ) { row = a->indexOf( par ); } else { row = m_project->indexOf( par ); } //debugPlan<name()<<":"<= columnCount() || row < 0 ) { return QModelIndex(); } Calendar *par = calendar( parent ); if ( par == 0 ) { if ( row < m_project->calendars().count() ) { return createIndex( row, column, m_project->calendars().at( row ) ); } } else if ( row < par->calendars().count() ) { return createIndex( row, column, par->calendars().at( row ) ); } return QModelIndex(); } QModelIndex CalendarItemModel::index( const Calendar *calendar, int column ) const { if ( m_project == 0 || calendar == 0 ) { return QModelIndex(); } Calendar *a = const_cast(calendar); int row = -1; Calendar *par = a->parentCal(); if ( par == 0 ) { row = m_project->calendars().indexOf( a ); } else { row = par->indexOf( a ); } if ( row == -1 ) { return QModelIndex(); } return createIndex( row, column, a ); } int CalendarItemModel::columnCount( const QModelIndex & ) const { return columnMap().keyCount(); } int CalendarItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 ) { return 0; } Calendar *par = calendar( parent ); if ( par == 0 ) { return m_project->calendars().count(); } return par->calendars().count(); } QVariant CalendarItemModel::name( const Calendar *a, int role ) const { //debugPlan<name()<<","<name(); case Qt::ToolTipRole: if ( a->isDefault() ) { return xi18nc( "1=calendar name", "%1 (Default calendar)", a->name() ); } return a->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::CheckStateRole: return a->isDefault() ? Qt::Checked : Qt::Unchecked; } return QVariant(); } QVariant CalendarItemModel::scope( const Calendar *a, int role ) const { //debugPlan<name()<<","<isShared() ? i18n("Shared") : i18n("Local"); case Qt::EditRole: return a->isShared() ? "Shared" : "Local"; case Qt::ToolTipRole: if ( !a->isShared() ) { return xi18nc( "@info:tooltip 1=calendar name", "%1 is a Local calendar", a->name() ); } return xi18nc( "@info:tooltip 1=calendar name", "%1 is a Shared calendar", a->name() ); case Role::EnumList: return QStringList() << i18n("Shared") << i18n("Local"); case Role::EnumListValue: return a->isShared() ? 0 : 1; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool CalendarItemModel::setName( Calendar *a, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() != a->name() ) { emit executeCommand( new CalendarModifyNameCmd( a, value.toString(), kundo2_i18n( "Modify calendar name" ) ) ); return true; } break; case Qt::CheckStateRole: { switch ( value.toInt() ) { case Qt::Unchecked: if ( a->isDefault() ) { emit executeCommand( new ProjectModifyDefaultCalendarCmd( m_project, 0, kundo2_i18n( "De-select as default calendar" ) ) ); return true; } break; case Qt::Checked: if ( ! a->isDefault() ) { emit executeCommand( new ProjectModifyDefaultCalendarCmd( m_project, a, kundo2_i18n( "Select as default calendar" ) ) ); return true; } break; default: break; } } default: break; } return false; } QVariant CalendarItemModel::timeZone( const Calendar *a, int role ) const { //debugPlan<name()<<","<timeZone().id() ); case Role::EnumList: { QStringList lst; foreach ( const QByteArray &id, QTimeZone::availableTimeZoneIds() ) { lst << i18n( id ); } lst.sort(); return lst; } case Role::EnumListValue: { QStringList lst = timeZone( a, Role::EnumList ).toStringList(); return lst.indexOf( i18n ( a->timeZone().id() ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool CalendarItemModel::setTimeZone( Calendar *a, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { if ( timeZone( a, Role::EnumListValue ) == value.toInt() ) { return false; } QStringList lst = timeZone( a, Role::EnumList ).toStringList(); QString name = lst.value( value.toInt() ); QTimeZone tz; foreach ( const QByteArray &id, QTimeZone::availableTimeZoneIds() ) { if ( name == i18n( id ) ) { tz = QTimeZone( id ); break; } } if ( !tz.isValid() ) { return false; } emit executeCommand( new CalendarModifyTimeZoneCmd( a, tz, kundo2_i18n( "Modify calendar timezone" ) ) ); return true; } } return false; } #ifdef HAVE_KHOLIDAYS QVariant CalendarItemModel::holidayRegion( const Calendar *a, int role ) const { //debugPlan<name()<<","<holidayRegionCode().isEmpty() || !a->holidayRegion()->isValid()) { return i18n("None"); } if (a->holidayRegionCode() == "Default") { return i18n("Default"); } return a->holidayRegion()->name(); case Qt::EditRole: if (a->holidayRegionCode().isEmpty()) { return "None"; } return a->holidayRegionCode(); case Qt::ToolTipRole: if (!a->holidayRegion()->isValid()) { return xi18nc("@info:tooltip", "No holidays"); } else if (a->holidayRegionCode() == "Default") { return xi18nc("@info:tooltip", "Default region: %1", a->holidayRegion()->name()); } return a->holidayRegion()->description(); case Role::EnumList: { QStringList lst; lst << i18n("None") << i18n("Default"); foreach(const QString &code, a->holidayRegionCodes()) { lst << KHolidays::HolidayRegion::name(code); } return lst; } case Role::EnumListValue: { if (!a->holidayRegion()->isValid()) { return 0; // None } if (a->holidayRegionCode() == "Default") { return 1; } return a->holidayRegionCodes().indexOf(a->holidayRegionCode()) + 2; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool CalendarItemModel::setHolidayRegion( Calendar *a, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { QString code = "None"; if (value.toInt() == 1) { code = "Default"; } else if (value.toInt() > 1) { code = a->holidayRegionCodes().value(value.toInt() - 2); } if (a->holidayRegionCode() == code || (code == "None" && a->holidayRegionCode().isEmpty())) { return false; } emit executeCommand(new CalendarModifyHolidayRegionCmd(a, code, kundo2_i18n("Modify calendar holiday region"))); return true; } } return false; } #endif QVariant CalendarItemModel::data( const QModelIndex &index, int role ) const { QVariant result; Calendar *a = calendar( index ); if ( a == 0 ) { return QVariant(); } switch ( index.column() ) { case Name: result = name( a, role ); break; case Scope: result = scope( a, role ); break; case TimeZone: result = timeZone( a, role ); break; #ifdef HAVE_KHOLIDAYS case HolidayRegion: result = holidayRegion( a, role ); break; #endif default: debugPlan<<"data: invalid display value column"<( index.internalPointer() ); } void CalendarItemModel::slotCalendarChanged( Calendar *calendar ) { Calendar *par = calendar->parentCal(); if ( par ) { int row = par->indexOf( calendar ); emit dataChanged( createIndex( row, 0, calendar ), createIndex( row, columnCount() - 1, calendar ) ); } else { int row = m_project->indexOf( calendar ); emit dataChanged( createIndex( row, 0, calendar ), createIndex( row, columnCount() - 1, calendar ) ); } } Qt::DropActions CalendarItemModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList CalendarItemModel::mimeTypes() const { return QStringList() << "application/x-vnd.kde.plan.calendarid.internal"; } QMimeData *CalendarItemModel::mimeData( const QModelIndexList & indexes ) const { QMimeData *m = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QList rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { debugPlan<id(); } } } m->setData("application/x-vnd.kde.plan.calendarid.internal", encodedData); return m; } bool CalendarItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent ) { debugPlan<hasFormat( "application/x-vnd.kde.plan.calendarid.internal" ) ) { return false; } if ( action == Qt::MoveAction ) { debugPlan<<"MoveAction"; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.calendarid.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Calendar *par = 0; if ( parent.isValid() ) { par = calendar( parent ); } MacroCommand *cmd = 0; QList lst = calendarList( stream ); foreach ( Calendar *c, lst ) { if ( c->parentCal() != par ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Re-parent calendar" ) ); cmd->addCommand( new CalendarModifyParentCmd( m_project, c, par ) ); } else { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move calendar" ) ); cmd->addCommand( new CalendarMoveCmd( m_project, c, row, par ) ); } } if ( cmd ) { emit executeCommand( cmd ); return true; } //debugPlan<name(); } return false; } QList CalendarItemModel::calendarList( QDataStream &stream ) const { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Calendar *c = m_project->findCalendar( id ); if ( c ) { lst << c; } } return lst; } bool CalendarItemModel::dropAllowed( Calendar *on, const QMimeData *data ) { debugPlan<hasFormat("application/x-vnd.kde.plan.calendarid.internal"); if ( !data->hasFormat("application/x-vnd.kde.plan.calendarid.internal") ) { return false; } if ( on == 0 && ! ( flags( QModelIndex() ) & (int)Qt::ItemIsDropEnabled ) ) { return false; } QByteArray encodedData = data->data( "application/x-vnd.kde.plan.calendarid.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList lst = calendarList( stream ); foreach ( Calendar *c, lst ) { if ( (flags( index( c ) ) & (int)Qt::ItemIsDropEnabled) == 0 ) { return false; } if ( on != 0 && on == c->parentCal() ) { return false; } if ( on != 0 && ( on == c || on->isChildOf( c ) ) ) { return false; } } return true; } QModelIndex CalendarItemModel::insertCalendar ( Calendar *calendar, int pos, Calendar *parent ) { //debugPlan<indexOf( calendar ); } else { row = m_project->indexOf( calendar ); } if ( row != -1 ) { //debugPlan<<"Inserted:"<name()<<"row="< /*lst*/ ) { } void CalendarItemModel::removeCalendar( Calendar *calendar ) { if ( calendar == 0 ) { return; } emit executeCommand( new CalendarRemoveCmd( m_project, calendar, kundo2_i18n( "Delete calendar" ) ) ); } //------------------------------------------ CalendarDayItemModel::CalendarDayItemModel( QObject *parent ) : CalendarDayItemModelBase( parent ) { } CalendarDayItemModel::~CalendarDayItemModel() { } void CalendarDayItemModel::slotWorkIntervalAdded( CalendarDay *day, TimeInterval *ti ) { Q_UNUSED(ti); //debugPlan<indexOfWeekday( day ); if ( c == -1 ) { return; } emit dataChanged( createIndex( 0, c, day ), createIndex( 0, c, day ) ); } void CalendarDayItemModel::slotWorkIntervalRemoved( CalendarDay *day, TimeInterval *ti ) { Q_UNUSED(ti); int c = m_calendar->indexOfWeekday( day ); if ( c == -1 ) { return; } emit dataChanged( createIndex( 0, c, day ), createIndex( 0, c, day ) ); } void CalendarDayItemModel::slotDayChanged( CalendarDay *day ) { int c = m_calendar->indexOfWeekday( day ); if ( c == -1 ) { return; } debugPlan<indexOf( ti ); emit dataChanged( createIndex( row, 0, ti ), createIndex( row, columnCount() - 1, ti ) );*/ } void CalendarDayItemModel::setCalendar( Calendar *calendar ) { beginResetModel(); //debugPlan<"<(&Calendar::changed), this, &CalendarDayItemModel::slotDayChanged); + disconnect(m_calendar, static_cast(&Calendar::changed), this, &CalendarDayItemModel::slotTimeIntervalChanged); - disconnect( m_calendar, SIGNAL(workIntervalAdded(KPlato::CalendarDay*,TimeInterval*)), this, SLOT(slotWorkIntervalAdded(KPlato::CalendarDay*,TimeInterval*))); - disconnect( m_calendar, SIGNAL(workIntervalRemoved(KPlato::CalendarDay*,TimeInterval*)), this, SLOT(slotWorkIntervalRemoved(KPlato::CalendarDay*,TimeInterval*))); + disconnect(m_calendar, &Calendar::workIntervalAdded, this, &CalendarDayItemModel::slotWorkIntervalAdded); + disconnect(m_calendar, &Calendar::workIntervalRemoved, this, &CalendarDayItemModel::slotWorkIntervalRemoved); } m_calendar = calendar; if ( calendar ) { - connect( m_calendar, SIGNAL(changed(KPlato::CalendarDay*)), this, SLOT(slotDayChanged(KPlato::CalendarDay*))); - connect( m_calendar, SIGNAL(changed(KPlato::TimeInterval*)), this, SLOT(slotTimeIntervalChanged(KPlato::TimeInterval*))); + connect(m_calendar, static_cast(&Calendar::changed), this, &CalendarDayItemModel::slotDayChanged); + connect(m_calendar, static_cast(&Calendar::changed), this, &CalendarDayItemModel::slotTimeIntervalChanged); - connect( m_calendar, SIGNAL(workIntervalAdded(KPlato::CalendarDay*,TimeInterval*)), this, SLOT(slotWorkIntervalAdded(KPlato::CalendarDay*,TimeInterval*))); - connect( m_calendar, SIGNAL(workIntervalRemoved(KPlato::CalendarDay*,TimeInterval*)), this, SLOT(slotWorkIntervalRemoved(KPlato::CalendarDay*,TimeInterval*))); + connect(m_calendar, &Calendar::workIntervalAdded, this, &CalendarDayItemModel::slotWorkIntervalAdded); + connect(m_calendar, &Calendar::workIntervalRemoved, this, &CalendarDayItemModel::slotWorkIntervalRemoved); } endResetModel(); } Qt::ItemFlags CalendarDayItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); if ( !m_readWrite ) { return flags &= ~Qt::ItemIsEditable; } return flags |= Qt::ItemIsEditable; } QModelIndex CalendarDayItemModel::parent( const QModelIndex &index ) const { Q_UNUSED(index); return QModelIndex(); } bool CalendarDayItemModel::hasChildren( const QModelIndex &parent ) const { //debugPlan<weekday( column + 1 ); // weekdays are 1..7 if ( d == 0 ) { return QModelIndex(); } return createIndex( row, column, d ); } QModelIndex CalendarDayItemModel::index( const CalendarDay *d) const { if ( m_project == 0 || m_calendar == 0 ) { return QModelIndex(); } int col = m_calendar->indexOfWeekday( d ); if ( col == -1 ) { return QModelIndex(); } return createIndex( 0, col, const_cast( d ) ); } int CalendarDayItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return 7; } int CalendarDayItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 || m_calendar == 0 || parent.isValid() ) { return 0; } return 1; } QVariant CalendarDayItemModel::name( int weekday, int role ) const { //debugPlan<name()<<","<= 1 && weekday <= 7 ) { return QLocale().dayName( weekday, QLocale::ShortFormat ); } break; case Qt::ToolTipRole: if ( weekday >= 1 && weekday <= 7 ) { return QLocale().dayName( weekday, QLocale::LongFormat ); } break; case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CalendarDayItemModel::dayState( const CalendarDay *d, int role ) const { switch ( role ) { case Qt::DisplayRole: switch ( d->state() ) { case CalendarDay::Undefined: return i18nc( "Undefined", "U" ); case CalendarDay::NonWorking: return i18nc( "NonWorking", "NW" ); case CalendarDay::Working: return i18nc( "Working", "W" ); } break; case Qt::ToolTipRole: return CalendarDay::stateToString( d->state(), true ); case Role::EnumList: { QStringList lst = CalendarDay::stateList( true ); return lst; } case Qt::EditRole: case Role::EnumListValue: { return d->state(); } case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::EditorType: return Delegate::EnumEditor; } return QVariant(); } bool CalendarDayItemModel::setDayState( CalendarDay *d, const QVariant &value, int role ) { //debugPlan; switch ( role ) { case Qt::EditRole: int v = value.toInt(); emit executeCommand( new CalendarModifyStateCmd( m_calendar, d, static_cast( v ), kundo2_i18n( "Modify calendar state" ) ) ); return true; } return false; } QVariant CalendarDayItemModel::workDuration( const CalendarDay *day, int role ) const { //debugPlan<date()<<","<state() == CalendarDay::Working ) { return QLocale().toString( day->workDuration().toDouble( Duration::Unit_h ), 'f', 1 ); } return QVariant(); } case Qt::ToolTipRole: { if ( day->state() == CalendarDay::Working ) { QLocale locale; QStringList tip; foreach ( TimeInterval *i, day->timeIntervals() ) { tip << i18nc( "1=time 2=The number of hours of work duration (non integer)", "%1, %2 hours", locale.toString( i->startTime(), QLocale::ShortFormat ), locale.toString( i->hours(), 'f', 2 ) ); } return tip.join( "\n" ); } return QVariant(); } case Qt::EditRole: break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return Qt::AlignCenter; } return QVariant(); } QVariant CalendarDayItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( ! index.isValid() ) { return result; } CalendarDay *d = day( index ); if ( d == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: { switch ( d->state() ) { case CalendarDay::Working: result = workDuration( d, role ); break; case CalendarDay::NonWorking: result = dayState( d, role ); break; default: { // Return parent value (if any) for ( Calendar *c = m_calendar->parentCal(); c != 0; c = c->parentCal() ) { d = c->weekday( index.column() + 1 ); Q_ASSERT( d ); if ( d->state() == CalendarDay::Working ) { return workDuration( d, role ); } if ( d->state() == CalendarDay::NonWorking ) { return dayState( d, role ); } } break; } } break; } case Qt::ToolTipRole: { if ( d->state() == CalendarDay::Undefined ) { return xi18nc( "@info:tooltip", "Undefined" ); } if ( d->state() == CalendarDay::NonWorking ) { return xi18nc( "@info:tooltip", "Non-working" ); } QLocale locale; KFormat format(locale); QStringList tip; foreach ( TimeInterval *i, d->timeIntervals() ) { tip << xi18nc( "@info:tooltip 1=time 2=The work duration (non integer)", "%1, %2", locale.toString( i->startTime(), QLocale::ShortFormat ), format.formatDuration( i->second ) ); } return tip.join( "" ); } case Qt::FontRole: { if ( d->state() != CalendarDay::Undefined ) { return QVariant(); } // If defined in parent, return italic for ( Calendar *c = m_calendar->parentCal(); c != 0; c = c->parentCal() ) { d = c->weekday( index.column() + 1 ); Q_ASSERT( d ); if ( d->state() != CalendarDay::Undefined ) { QFont f; f.setItalic( true ); return f; } } break; } } return result; } bool CalendarDayItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { return ItemModelBase::setData( index, value, role ); } QVariant CalendarDayItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole ) { switch ( section ) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: return name( section + 1, role ); default: return QVariant(); } } else if ( role == Qt::TextAlignmentRole ) { switch (section) { default: return Qt::AlignCenter; } } } if ( role == Qt::ToolTipRole ) { switch ( section ) { /* case 0: return ToolTip::Calendar Name;*/ default: return QVariant(); } } return ItemModelBase::headerData(section, orientation, role); } CalendarDay *CalendarDayItemModel::day( const QModelIndex &index ) const { return static_cast( index.internalPointer() ); } QAbstractItemDelegate *CalendarDayItemModel::createDelegate( int column, QWidget *parent ) const { Q_UNUSED(parent); switch ( column ) { default: return 0; } return 0; } //----------------------- DateTableDataModel::DateTableDataModel( QObject *parent ) : KDateTableDataModel( parent ), m_calendar( 0 ) { } void DateTableDataModel::setCalendar( Calendar *calendar ) { if ( m_calendar ) { - disconnect( m_calendar, SIGNAL(dayAdded(KPlato::CalendarDay*)), this, SIGNAL(reset())); - disconnect( m_calendar, SIGNAL(dayRemoved(KPlato::CalendarDay*)), this, SIGNAL(reset())); - disconnect( m_calendar, SIGNAL(changed(KPlato::CalendarDay*)), this, SIGNAL(reset())); + disconnect(m_calendar, &Calendar::dayAdded, this, &KDateTableDataModel::reset); + disconnect(m_calendar, &Calendar::dayRemoved, this, &KDateTableDataModel::reset); + disconnect(m_calendar, static_cast(&Calendar::changed), this, &DateTableDataModel::reset); } m_calendar = calendar; if ( m_calendar ) { - connect( m_calendar, SIGNAL(dayAdded(KPlato::CalendarDay*)), this, SIGNAL(reset())); - connect( m_calendar, SIGNAL(dayRemoved(KPlato::CalendarDay*)), this, SIGNAL(reset())); - connect( m_calendar, SIGNAL(changed(KPlato::CalendarDay*)), this, SIGNAL(reset())); + connect( m_calendar, &Calendar::dayAdded, this, &KDateTableDataModel::reset); + connect( m_calendar, &Calendar::dayRemoved, this, &KDateTableDataModel::reset); + connect(m_calendar, static_cast(&Calendar::changed), this, &DateTableDataModel::reset); } emit reset(); } QVariant DateTableDataModel::data( const Calendar &cal, const QDate &date, int role ) const { switch ( role ) { case Qt::DisplayRole: { CalendarDay *day = cal.findDay( date ); if ( day == 0 || day->state() == CalendarDay::Undefined ) { #ifdef HAVE_KHOLIDAYS if (cal.isHoliday(date)) { return i18nc( "NonWorking", "NW" ); } #endif if ( cal.parentCal() ) { return data( *( cal.parentCal() ), date, role ); } return ""; } if ( day->state() == CalendarDay::NonWorking ) { return i18nc( "NonWorking", "NW" ); } double v; v = day->workDuration().toDouble( Duration::Unit_h ); return QLocale().toString( v, 'f', 1 ); } case Qt::TextAlignmentRole: return (uint)( Qt::AlignHCenter | Qt::AlignBottom ); case Qt::FontRole: { CalendarDay *day = cal.findDay( date ); if ( day && day->state() != CalendarDay::Undefined ) { if ( &cal != m_calendar ) { QFont f; f.setItalic( true ); return f; } return QVariant(); } if ( cal.parentCal() ) { return data( *( cal.parentCal() ), date, role ); } break; } default: break; } return QVariant(); } QVariant DateTableDataModel::data( const QDate &date, int role, int dataType ) const { //debugPlan<findDay( date ); if ( day == 0 || day->state() == CalendarDay::Undefined ) { #ifdef HAVE_KHOLIDAYS if (m_calendar->isHoliday(date)) { return xi18nc( "@info:tooltip", "Holiday" ); } #endif return xi18nc( "@info:tooltip", "Undefined" ); } if ( day->state() == CalendarDay::NonWorking ) { return xi18nc( "@info:tooltip", "Non-working" ); } QLocale locale; KFormat format(locale); QStringList tip; foreach ( TimeInterval *i, day->timeIntervals() ) { tip << xi18nc( "@info:tooltip 1=time 2=The work duration (non integer)", "%1, %2", locale.toString( i->startTime(), QLocale::ShortFormat ), format.formatDuration( i->second ) ); } return tip.join( "\n" ); } switch ( dataType ) { case -1: { //default (date) switch ( role ) { case Qt::DisplayRole: { return QVariant(); } case Qt::TextAlignmentRole: return (uint)Qt::AlignLeft | Qt::AlignTop; case Qt::FontRole: break;//return QFont( "Helvetica", 6 ); case Qt::BackgroundRole: break;//return QColor( "red" ); default: break; } break; } case 0: { if ( m_calendar == 0 ) { return ""; } return data( *m_calendar, date, role ); } default: break; } return QVariant(); } QVariant DateTableDataModel::weekDayData( int day, int role ) const { Q_UNUSED(day); Q_UNUSED(role); return QVariant(); } QVariant DateTableDataModel::weekNumberData( int week, int role ) const { Q_UNUSED(week); Q_UNUSED(role); return QVariant(); } //------------- DateTableDateDelegate::DateTableDateDelegate( QObject *parent ) : KDateTableDateDelegate( parent ) { } QRectF DateTableDateDelegate::paint( QPainter *painter, const StyleOptionViewItem &option, const QDate &date, KDateTableDataModel *model ) { //debugPlan<save(); painter->translate( r.width(), 0.0 ); QRectF rect( 1, 1, option.rectF.right() - r.width(), option.rectF.bottom() ); //debugPlan<<" rects: "<data( date, Qt::DisplayRole, 0 ).toString(); int align = model->data( date, Qt::TextAlignmentRole, 0 ).toInt(); QFont f = option.font; QVariant v = model->data( date, Qt::FontRole, 0 ); if ( v.isValid() ) { f = v.value(); } painter->setFont( f ); if ( option.state & QStyle::State_Selected ) { painter->setPen( option.palette.highlightedText().color() ); } else { painter->setPen( option.palette.color( QPalette::Text ) ); } painter->drawText(rect, align, text, &r); painter->restore(); return r; } //------------------------------------- CalendarExtendedItemModel::CalendarExtendedItemModel( QObject *parent ) : CalendarItemModel( parent ) { } Qt::ItemFlags CalendarExtendedItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = CalendarItemModel::flags( index ); if ( ! m_readWrite || ! index.isValid() || calendar( index ) == 0 ) { return flags; } return flags |= Qt::ItemIsEditable; } QModelIndex CalendarExtendedItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || column < 0 || column >= columnCount() || row < 0 ) { return QModelIndex(); } Calendar *par = calendar( parent ); if ( par == 0 ) { if ( row < m_project->calendars().count() ) { return createIndex( row, column, m_project->calendars().at( row ) ); } } else if ( row < par->calendars().count() ) { return createIndex( row, column, par->calendars().at( row ) ); } return QModelIndex(); } int CalendarExtendedItemModel::columnCount( const QModelIndex & ) const { return CalendarItemModel::columnCount() + 2; // weekdays + date } QVariant CalendarExtendedItemModel::data( const QModelIndex &index, int role ) const { QVariant result; Calendar *a = calendar( index ); if ( a == 0 ) { return QVariant(); } int col = index.column() - CalendarItemModel::columnCount( index ); if ( col < 0 ) { return CalendarItemModel::data( index, role ); } switch ( col ) { default: debugPlan<<"Fetching data from weekdays and date is not supported"; break; } return result; } bool CalendarExtendedItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { int col = index.column() - CalendarItemModel::columnCount( index ); if ( col < 0 ) { return CalendarItemModel::setData( index, value, role ); } if ( ( flags( index ) &( Qt::ItemIsEditable ) ) == 0 ) { return false; } Calendar *cal = calendar( index ); if ( cal == 0 || col > 2 ) { return false; } switch ( col ) { case 0: { // weekday if ( value.type() != QVariant::List ) { return false; } QVariantList lst = value.toList(); if ( lst.count() < 2 ) { return false; } int wd = CalendarWeekdays::dayOfWeek( lst.at( 0 ).toString() ); if ( wd < 1 || wd > 7 ) { return false; } CalendarDay *day = new CalendarDay(); if ( lst.count() == 2 ) { QString state = lst.at( 1 ).toString(); if ( state == "NonWorking" ) { day->setState( CalendarDay::NonWorking ); } else if ( state == "Undefined" ) { day->setState( CalendarDay::Undefined ); } else { delete day; return false; } CalendarModifyWeekdayCmd *cmd = new CalendarModifyWeekdayCmd( cal, wd, day, kundo2_i18n( "Modify calendar weekday" ) ); emit executeCommand( cmd ); return true; } if ( lst.count() % 2 == 0 ) { delete day; return false; } day->setState( CalendarDay::Working ); for ( int i = 1; i < lst.count(); i = i + 2 ) { QTime t1 = lst.at( i ).toTime(); QTime t2 = lst.at( i + 1 ).toTime(); int length = t1.msecsTo( t2 ); if ( t1 == QTime( 0, 0, 0 ) && t2 == t1 ) { length = 24 * 60 * 60 *1000; } else if ( length < 0 && t2 == QTime( 0, 0, 0 ) ) { length += 24 * 60 * 60 *1000; } else if ( length == 0 || ( length < 0 && t2 != QTime( 0, 0, 0 ) ) ) { delete day; return false; } length = qAbs( length ); day->addInterval( t1, length ); } CalendarModifyWeekdayCmd *cmd = new CalendarModifyWeekdayCmd( cal, wd, day, kundo2_i18n( "Modify calendar weekday" ) ); emit executeCommand( cmd ); return true; } case 1: { // day if ( value.type() != QVariant::List ) { return false; } CalendarDay *day = new CalendarDay(); QVariantList lst = value.toList(); if ( lst.count() < 2 ) { return false; } day->setDate( lst.at( 0 ).toDate() ); if ( ! day->date().isValid() ) { delete day; return false; } if ( lst.count() == 2 ) { QString state = lst.at( 1 ).toString(); if ( state == "NonWorking" ) { day->setState( CalendarDay::NonWorking ); } else if ( state == "Undefined" ) { day->setState( CalendarDay::Undefined ); } else { delete day; return false; } CalendarModifyDayCmd *cmd = new CalendarModifyDayCmd( cal, day, kundo2_i18n( "Modify calendar date" ) ); emit executeCommand( cmd ); return true; } if ( lst.count() % 2 == 0 ) { delete day; return false; } day->setState( CalendarDay::Working ); for ( int i = 1; i < lst.count(); i = i + 2 ) { QTime t1 = lst.at( i ).toTime(); QTime t2 = lst.at( i + 1 ).toTime(); int length = t1.msecsTo( t2 ); if ( t1 == QTime( 0, 0, 0 ) && t2 == t1 ) { length = 24 * 60 * 60 *1000; } else if ( length < 0 && t2 == QTime( 0, 0, 0 ) ) { length += 24 * 60 * 60 *1000; } else if ( length == 0 || ( length < 0 && t2 != QTime( 0, 0, 0 ) ) ) { delete day; return false; } length = qAbs( length ); day->addInterval( t1, length ); } CalendarModifyDayCmd *cmd = new CalendarModifyDayCmd( cal, day, kundo2_i18n( "Modify calendar date" ) ); emit executeCommand( cmd ); return true; } } return false; } QVariant CalendarExtendedItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { int col = section - CalendarItemModel::columnCount(); if ( col < 0 ) { return CalendarItemModel::headerData( section, orientation, role ); } if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole ) { switch ( col ) { case 0: return xi18nc( "@title:column", "Weekday" ); case 1: return xi18nc( "@title:column", "Date" ); default: return QVariant(); } } else if ( role == Qt::TextAlignmentRole ) { switch ( col ) { default: return QVariant(); } } } if ( role == Qt::ToolTipRole ) { switch ( section ) { default: return QVariant(); } } return QVariant(); } int CalendarExtendedItemModel::columnNumber(const QString& name) const { QStringList lst; lst << "Weekday" << "Date"; if ( lst.contains( name ) ) { return lst.indexOf( name ) + CalendarItemModel::columnCount(); } return CalendarItemModel::columnMap().keyToValue( name.toUtf8() ); } } // namespace KPlato diff --git a/src/libs/models/kptdurationspinbox.cpp b/src/libs/models/kptdurationspinbox.cpp index 742016f4..b8b24945 100644 --- a/src/libs/models/kptdurationspinbox.cpp +++ b/src/libs/models/kptdurationspinbox.cpp @@ -1,265 +1,265 @@ /* This file is part of the KDE project Copyright (C) 2007 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 #include "kptnode.h" #include #include #include #include #include #include namespace KPlato { DurationSpinBox::DurationSpinBox(QWidget *parent) : QDoubleSpinBox(parent), m_unit( Duration::Unit_d ), m_minunit( Duration::Unit_h ), m_maxunit( Duration::Unit_Y ) { setUnit( Duration::Unit_h ); setMaximum(140737488355328.0); //Hmmmm - connect( lineEdit(), SIGNAL(textChanged(QString)), SLOT(editorTextChanged(QString)) ); + connect( lineEdit(), &QLineEdit::textChanged, this, &DurationSpinBox::editorTextChanged ); } void DurationSpinBox::setUnit( Duration::Unit unit ) { if ( unit < m_maxunit ) { m_maxunit = unit; } else if ( unit > m_minunit ) { m_minunit = unit; } m_unit = unit; setValue( value() ); } void DurationSpinBox::setMaximumUnit( Duration::Unit unit ) { //NOTE Year = 0, Milliseconds = 7 !!! m_maxunit = unit; if ( m_minunit < unit ) { m_minunit = unit; } if ( m_unit < unit ) { setUnit( unit ); emit unitChanged( m_unit ); } } void DurationSpinBox::setMinimumUnit( Duration::Unit unit ) { //NOTE Year = 0, Milliseconds = 7 !!! m_minunit = unit; if ( m_maxunit > unit ) { m_maxunit = unit; } if ( m_unit > unit ) { setUnit( unit ); emit unitChanged( m_unit ); } } void DurationSpinBox::stepUnitUp() { //debugPlan<"< m_maxunit ) { setUnit( static_cast(m_unit - 1) ); // line may change length, make sure cursor stays within unit lineEdit()->setCursorPosition( lineEdit()->displayText().length() - suffix().length() ); emit unitChanged( m_unit ); } } void DurationSpinBox::stepUnitDown() { //debugPlan<(m_unit + 1) ); // line may change length, make sure cursor stays within unit lineEdit()->setCursorPosition( lineEdit()->displayText().length() - suffix().length() ); emit unitChanged( m_unit ); } } void DurationSpinBox::stepBy( int steps ) { //debugPlan<cursorPosition(); if ( isOnUnit() ) { // we are in unit if ( steps > 0 ) { stepUnitUp(); } else if ( steps < 0 ) { stepUnitDown(); } lineEdit()->setCursorPosition( cpos ); return; } QDoubleSpinBox::stepBy( steps ); // QDoubleSpinBox selects the whole text and the cursor might end up at the end (in the unit field) lineEdit()->setCursorPosition( cpos ); // also deselects } QAbstractSpinBox::StepEnabled DurationSpinBox::stepEnabled () const { if ( isOnUnit() ) { if ( m_unit >= m_minunit ) { //debugPlan<<"inside unit, up"<cursorPosition(); return ( pos <= text().size() - suffix().size() ) && ( pos > text().size() - suffix().size() - Duration::unitToString( m_unit, true ).size() ); } void DurationSpinBox::keyPressEvent( QKeyEvent * event ) { //debugPlan<cursorPosition()<<","<<(text().size() - Duration::unitToString( m_unit, true ).size())<<""<text().isEmpty(); if ( isOnUnit() ) { // we are in unit switch (event->key()) { case Qt::Key_Up: event->accept(); stepBy( 1 ); return; case Qt::Key_Down: event->accept(); stepBy( -1 ); return; default: break; } } QDoubleSpinBox::keyPressEvent(event); } // handle unit, QDoubleSpinBox handles value, signals etc void DurationSpinBox::editorTextChanged( const QString &text ) { //debugPlan<cursorPosition(); if ( validate( s, pos ) == QValidator::Acceptable ) { s = extractUnit( s ); if ( ! s.isEmpty() ) { updateUnit( (Duration::Unit)Duration::unitList( true ).indexOf( s ) ); } } } double DurationSpinBox::valueFromText( const QString & text ) const { QString s = extractValue( text ); bool ok = false; double v = QLocale().toDouble( s, &ok ); if ( ! ok ) { v = QDoubleSpinBox::valueFromText( s ); } return v; } QString DurationSpinBox::textFromValue ( double value ) const { QString s = QLocale().toString( qMin( qMax( minimum(), value ), maximum() ), 'f', decimals() ); s += Duration::unitToString( m_unit, true ); //debugPlan<<2< m_minunit ) { return QValidator::Invalid; } s = extractValue( input ); int p = 0; return validator.validate ( s, p ); // pos doesn't matter } QString DurationSpinBox::extractUnit ( const QString &text ) const { //debugPlan<= 0; --i ) { QChar c = text[ i ]; if ( ! c.isLetter() ) { break; } s.prepend( c ); } if ( Duration::unitList( true ).contains( s ) ) { return s; } return QString(); } QString DurationSpinBox::extractValue ( const QString &text ) const { //debugPlan< m_minunit ) { m_unit = m_minunit; } if ( m_unit != unit ) { m_unit = unit; emit unitChanged( unit ); } } } //namespace KPlato diff --git a/src/libs/models/kptflatproxymodel.cpp b/src/libs/models/kptflatproxymodel.cpp index fc0687b5..9a6906f6 100644 --- a/src/libs/models/kptflatproxymodel.cpp +++ b/src/libs/models/kptflatproxymodel.cpp @@ -1,457 +1,457 @@ /* This file is part of the KDE project Copyright (C) 2010, 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. */ #include "kptflatproxymodel.h" #include "kptglobal.h" #include #include #include #include #include "kptdebug.h" namespace KPlato { FlatProxyModel::FlatProxyModel(QObject *parent) : QAbstractProxyModel( parent ) { } void FlatProxyModel::sourceModelDestroyed() { m_sourceIndexList.clear(); } void FlatProxyModel::sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right) { emit dataChanged( mapFromSource( source_top_left ), mapFromSource( source_bottom_right ) ); } void FlatProxyModel::sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end) { emit headerDataChanged(orientation, start, end); } void FlatProxyModel::sourceReset() { beginResetModel(); initiateMaps(); endResetModel(); } void FlatProxyModel::sourceLayoutAboutToBeChanged() { emit layoutAboutToBeChanged(); } void FlatProxyModel::sourceLayoutChanged() { initiateMaps(); emit layoutChanged(); } void FlatProxyModel::sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) { Q_UNUSED(source_parent); Q_UNUSED(start); Q_UNUSED(end); beginResetModel(); } void FlatProxyModel::sourceRowsInserted(const QModelIndex &source_parent, int start, int end) { Q_UNUSED(source_parent); Q_UNUSED(start); Q_UNUSED(end); initiateMaps(); endResetModel(); } void FlatProxyModel::sourceRowsAboutToBeRemoved( const QModelIndex &source_parent, int start, int end ) { Q_UNUSED(source_parent); Q_UNUSED(start); Q_UNUSED(end); beginResetModel(); } void FlatProxyModel::sourceRowsRemoved( const QModelIndex &source_parent, int start, int end ) { Q_UNUSED(source_parent); Q_UNUSED(start); Q_UNUSED(end); initiateMaps(); endResetModel(); } void FlatProxyModel::sourceRowsAboutToBeMoved(const QModelIndex &source_parent, int start, int end, const QModelIndex &destParent, int destStart) { Q_UNUSED(source_parent); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destParent); Q_UNUSED(destStart); beginResetModel(); } void FlatProxyModel::sourceRowsMoved(const QModelIndex &source_parent, int start, int end, const QModelIndex &destParent, int destStart) { Q_UNUSED(source_parent); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destParent); Q_UNUSED(destStart); initiateMaps(); endResetModel(); } void FlatProxyModel::setSourceModel(QAbstractItemModel *model) { if ( sourceModel() ) { - disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); + disconnect(sourceModel(), &QAbstractItemModel::dataChanged, + this, &FlatProxyModel::sourceDataChanged); - disconnect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)), - this, SLOT(sourceHeaderDataChanged(Qt::Orientation,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::headerDataChanged, + this, &FlatProxyModel::sourceHeaderDataChanged); - disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeInserted, + this, &FlatProxyModel::sourceRowsAboutToBeInserted); - disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsInserted(QModelIndex,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, + this, &FlatProxyModel::sourceRowsInserted); - disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved, + this, &FlatProxyModel::sourceRowsAboutToBeRemoved); - disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, + this, &FlatProxyModel::sourceRowsRemoved); - disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()), - this, SLOT(sourceLayoutAboutToBeChanged())); + disconnect(sourceModel(), &QAbstractItemModel::layoutAboutToBeChanged, + this, &FlatProxyModel::sourceLayoutAboutToBeChanged); - disconnect(sourceModel(), SIGNAL(layoutChanged()), - this, SLOT(sourceLayoutChanged())); + disconnect(sourceModel(), &QAbstractItemModel::layoutChanged, + this, &FlatProxyModel::sourceLayoutChanged); - disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); + disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &FlatProxyModel::sourceReset); - connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); - connect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); + connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeMoved, + this, &FlatProxyModel::sourceRowsAboutToBeMoved); + connect(sourceModel(), &QAbstractItemModel::rowsMoved, + this, &FlatProxyModel::sourceRowsMoved); } QAbstractProxyModel::setSourceModel(model); - connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); + connect(sourceModel(), &QAbstractItemModel::dataChanged, + this, &FlatProxyModel::sourceDataChanged); - connect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)), - this, SLOT(sourceHeaderDataChanged(Qt::Orientation,int,int))); + connect(sourceModel(), &QAbstractItemModel::headerDataChanged, + this, &FlatProxyModel::sourceHeaderDataChanged); - connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); + connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeInserted, + this, &FlatProxyModel::sourceRowsAboutToBeInserted); - connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsInserted(QModelIndex,int,int))); + connect(sourceModel(), &QAbstractItemModel::rowsInserted, + this, &FlatProxyModel::sourceRowsInserted); - connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); + connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved, + this, &FlatProxyModel::sourceRowsAboutToBeRemoved); - connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); + connect(sourceModel(), &QAbstractItemModel::rowsRemoved, + this, &FlatProxyModel::sourceRowsRemoved); - connect(sourceModel(), SIGNAL(layoutAboutToBeChanged()), - this, SLOT(sourceLayoutAboutToBeChanged())); + connect(sourceModel(), &QAbstractItemModel::layoutAboutToBeChanged, + this, &FlatProxyModel::sourceLayoutAboutToBeChanged); - connect(sourceModel(), SIGNAL(layoutChanged()), - this, SLOT(sourceLayoutChanged())); + connect(sourceModel(), &QAbstractItemModel::layoutChanged, + this, &FlatProxyModel::sourceLayoutChanged); - connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceReset())); + connect(sourceModel(), &QAbstractItemModel::modelReset, this, &FlatProxyModel::sourceReset); - connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); - connect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); + connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeMoved, + this, &FlatProxyModel::sourceRowsAboutToBeMoved); + connect(sourceModel(), &QAbstractItemModel::rowsMoved, + this, &FlatProxyModel::sourceRowsMoved); beginResetModel(); initiateMaps(); endResetModel(); } QModelIndex FlatProxyModel::index(int row, int column, const QModelIndex &parent) const { if ( parent.isValid() ) { return QModelIndex(); } return createIndex( row, column ); } QModelIndex FlatProxyModel::parent(const QModelIndex &child) const { Q_UNUSED(child); return QModelIndex(); } int FlatProxyModel::rowCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : m_sourceIndexList.count(); } int FlatProxyModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); if ( sourceModel() == 0 ) { return 0; } return sourceModel()->columnCount() + 1; } bool FlatProxyModel::hasChildren(const QModelIndex &parent) const { return rowCount( parent ) > 0; } QVariant FlatProxyModel::data(const QModelIndex &index, int role) const { if ( sourceModel() == 0 || !index.isValid()) { debugPlan<<"No source model || invalid index"; return QVariant(); } QModelIndex source_index; int col = index.column() - sourceModel()->columnCount(); if ( col < 0 ) { source_index = mapToSource(index); //debugPlan<<"source column"<columnCount(); } else { source_index = mapToSource( this->index( index.row(), 0 ) ); //debugPlan<<"proxy column"<columnCount(); } if ( !source_index.isValid() ) { debugPlan<<"index valid but source index not valid:"<data(source_index, role); } else if ( col == 0 ) { if ( role == Role::ColumnTag ) { r = headerData( col, Qt::Horizontal, role ); } else { source_index = source_index.parent(); if ( source_index.isValid() ) { r = sourceModel()->data(source_index, role); } } } //debugPlan<setData(source_index, value, role); } QVariant FlatProxyModel::headerData(int section, Qt::Orientation orientation, int role) const { if ( sourceModel() == 0 ) { return QVariant(); } int sec = section - sourceModel()->columnCount(); if ( sec < 0 ) { return sourceModel()->headerData(section, orientation, role); } if ( sec == 0 ) { return role == Role::ColumnTag ? "Parent" : i18n( "Parent" ); } return QVariant(); } bool FlatProxyModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { if ( sourceModel() == 0 ) { return false; } //TODO return sourceModel()->setHeaderData(section, orientation, value, role); } QMimeData *FlatProxyModel::mimeData(const QModelIndexList &indexes) const { if ( sourceModel() == 0 ) { return 0; } QModelIndexList source_indexes; for (int i = 0; i < indexes.count(); ++i) { source_indexes << mapToSource(indexes.at(i)); } return sourceModel()->mimeData(source_indexes); } QStringList FlatProxyModel::mimeTypes() const { if ( sourceModel() == 0 ) { return QStringList(); } return sourceModel()->mimeTypes(); } Qt::DropActions FlatProxyModel::supportedDropActions() const { if ( sourceModel() == 0 ) { return 0; } return sourceModel()->supportedDropActions(); } bool FlatProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if ( sourceModel() == 0 ) { return false; } if ((row == -1) && (column == -1)) return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent)); int source_destination_row = -1; int source_destination_column = -1; QModelIndex source_parent; if (row == rowCount(parent)) { source_parent = mapToSource(parent); source_destination_row = sourceModel()->rowCount(source_parent); } else { QModelIndex proxy_index = index(row, column, parent); QModelIndex source_index = mapToSource(proxy_index); source_destination_row = source_index.row(); source_destination_column = source_index.column(); source_parent = source_index.parent(); } return sourceModel()->dropMimeData(data, action, source_destination_row, source_destination_column, source_parent); } bool FlatProxyModel::insertRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(row); Q_UNUSED(count); Q_UNUSED(parent); return false; } bool FlatProxyModel::removeRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(row); Q_UNUSED(count); Q_UNUSED(parent); //TODO return false; } /*! Returns the source model index corresponding to the given \a proxyIndex from the sorting filter model. \sa mapFromSource() */ QModelIndex FlatProxyModel::mapToSource(const QModelIndex &proxyIndex) const { if ( ! proxyIndex.isValid() ) { return QModelIndex(); } QModelIndex source_index = m_sourceIndexList.value( proxyIndex.row() ); if ( proxyIndex.column() != 0 ) { source_index = sourceModel()->index( source_index.row(), proxyIndex.column(), source_index.parent() ); } //debugPlan<"<index( idx.row(), 0, idx.parent() ); } QModelIndex proxy_index = index( m_sourceIndexList.indexOf( idx ), sourceIndex.column() ); //debugPlan<"<rowCount( sourceParent ); for ( int row = 0; row < count; ++row ) { QPersistentModelIndex idx = m->index( row, 0, sourceParent ); //debugPlan<<"map:"< #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { //-------------------------------------- bool ItemDelegate::eventFilter(QObject *object, QEvent *event) { QWidget *editor = ::qobject_cast(object); if (!editor) { return false; } m_lastHint = Delegate::NoHint; if (event->type() == QEvent::KeyPress) { QKeyEvent *e = static_cast(event); if ( e->modifiers() & Qt::AltModifier && e->modifiers() & Qt::ControlModifier ) { switch ( e->key() ) { case Qt::Key_Left: m_lastHint = Delegate::EditLeftItem; emit commitData(editor); emit closeEditor(editor, QAbstractItemDelegate::NoHint ); return true; case Qt::Key_Right: m_lastHint = Delegate::EditRightItem; emit commitData(editor); emit closeEditor( editor, QAbstractItemDelegate::NoHint ); return true; case Qt::Key_Down: m_lastHint = Delegate::EditDownItem; emit commitData(editor); emit closeEditor(editor, QAbstractItemDelegate::NoHint ); return true; case Qt::Key_Up: m_lastHint = Delegate::EditUpItem; emit commitData(editor); emit closeEditor(editor, QAbstractItemDelegate::NoHint ); return true; default: break; } } } return QStyledItemDelegate::eventFilter( object, event ); } QSize ItemDelegate::sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) const { // 18 is a bit arbitrary, it gives (most?) editors a usable size QSize s = QStyledItemDelegate::sizeHint( option, index ); return QSize( s.width(), qMax( s.height(), 18 ) ); } //---------------------- CheckStateItemDelegate::CheckStateItemDelegate( QObject *parent ) : ItemDelegate( parent ) { } bool CheckStateItemDelegate::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index ) { Q_ASSERT(event); Q_ASSERT(model); debugPlan; Qt::ItemFlags flags = model->flags(index); if ( ! ( option.state & QStyle::State_Enabled ) || ! ( flags & Qt::ItemIsEnabled ) ) { return false; } // make sure that we have a check state QVariant value = index.data( Qt::EditRole ); if ( ! value.isValid() ) { return false; } QStyle *style = QApplication::style(); // make sure that we have the right event type if ( ( event->type() == QEvent::MouseButtonRelease ) || ( event->type() == QEvent::MouseButtonDblClick ) || ( event->type() == QEvent::MouseButtonPress ) ) { QStyleOptionViewItem viewOpt( option ); initStyleOption( &viewOpt, index ); QRect checkRect = style->subElementRect( QStyle::SE_ItemViewItemDecoration, &viewOpt, 0 ); QMouseEvent *me = static_cast( event ); if ( me->button() != Qt::LeftButton || ! checkRect.contains( me->pos() ) ) { return false; } if ( ( event->type() == QEvent::MouseButtonPress ) || ( event->type() == QEvent::MouseButtonDblClick ) ) { return true; } } else if ( event->type() == QEvent::KeyPress ) { if (static_cast(event)->key() != Qt::Key_Space && static_cast(event)->key() != Qt::Key_Select) { return false; } } else { return false; } Qt::CheckState state = ( static_cast( value.toInt() ) == Qt::Checked ? Qt::Unchecked : Qt::Checked ); return model->setData(index, state, Qt::CheckStateRole); } //---------------------- DateTimeCalendarDelegate::DateTimeCalendarDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *DateTimeCalendarDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { QDateTimeEdit *editor = new QDateTimeEdit(parent); editor->setCalendarPopup( true ); editor->installEventFilter(const_cast(this)); return editor; } void DateTimeCalendarDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QDateTime value = index.model()->data(index, Qt::EditRole).toDateTime(); QDateTimeEdit *e = static_cast(editor); e->setDateTime( value ); } void DateTimeCalendarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QDateTimeEdit *e = static_cast(editor); model->setData( index, e->dateTime(), Qt::EditRole ); } void DateTimeCalendarDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { debugPlan<sizeHint(); QRect r = option.rect; //r.setHeight(r.height() 50); editor->setGeometry(r); } //----------------------------- ProgressBarDelegate::ProgressBarDelegate( QObject *parent ) : ItemDelegate( parent ) { } ProgressBarDelegate::~ProgressBarDelegate() { } void ProgressBarDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { QStyle *style; QStyleOptionViewItem opt = option; initStyleOption( &opt, index ); style = opt.widget ? opt.widget->style() : QApplication::style(); style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter ); if ( !( opt.state & QStyle::State_Editing ) ) { bool ok = false; (void) index.data().toInt(&ok); if ( ok ) { QStyleOptionProgressBar pbOption; pbOption.QStyleOption::operator=( option ); initStyleOptionProgressBar( &pbOption, index ); style->drawControl( QStyle::CE_ProgressBar, &pbOption, painter ); // Draw focus, copied from qt if (opt.state & QStyle::State_HasFocus) { painter->save(); QStyleOptionFocusRect o; o.QStyleOption::operator=( opt ); o.rect = style->subElementRect( QStyle::SE_ItemViewItemFocusRect, &opt, opt.widget ); o.state |= QStyle::State_KeyboardFocusChange; o.state |= QStyle::State_Item; QPalette::ColorGroup cg = ( opt.state & QStyle::State_Enabled ) ? QPalette::Normal : QPalette::Disabled; o.backgroundColor = opt.palette.color( cg, ( opt.state & QStyle::State_Selected ) ? QPalette::Highlight : QPalette::Window ); style->drawPrimitive( QStyle::PE_FrameFocusRect, &o, painter, opt.widget ); //debugPlan<<"Focus"<restore(); } } else { EnumDelegate del; del.paint( painter, option, index ); } } } QSize ProgressBarDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const { QStyleOptionViewItem opt = option; // initStyleOption( &opt, index ); QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); QStyleOptionProgressBar pbOption; pbOption.QStyleOption::operator=( option ); initStyleOptionProgressBar( &pbOption, index ); return style->sizeFromContents( QStyle::CT_ProgressBar, &pbOption, QSize(), opt.widget ); } void ProgressBarDelegate::initStyleOptionProgressBar( QStyleOptionProgressBar *option, const QModelIndex &index ) const { option->rect.adjust( 0, 1, 0, -1 ); option->minimum = 0; int max = index.data( Role::Maximum ).toInt(); option->maximum = max > option->minimum ? max : option->minimum + 100; option->progress = index.data().toInt(); option->text = QString::number( ( option->progress * 100 ) / ( option->maximum - option->minimum ) ) + QLatin1Char( '%' ); option->textAlignment = Qt::AlignCenter; option->textVisible = true; } QWidget *ProgressBarDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const { Slider *slider = new Slider( parent ); slider->setRange( 0, 100 ); slider->setOrientation( Qt::Horizontal ); //debugPlan<minimumSizeHint()<minimumSize(); return slider; } void ProgressBarDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const { QSlider *slider = static_cast( editor ); slider->setValue( index.data( Qt::EditRole ).toInt() ); } void ProgressBarDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const { QSlider *slider = static_cast( editor ); model->setData( index, slider->value() ); } void ProgressBarDelegate::updateEditorGeometry( QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & ) const { editor->setGeometry( option.rect ); //debugPlan<minimumSizeHint()<minimumSize()<geometry()<size(); } Slider::Slider( QWidget *parent ) : QSlider( parent ) { - connect( this, SIGNAL(valueChanged(int)), this, SLOT(updateTip(int)) ); + connect( this, &QAbstractSlider::valueChanged, this, &Slider::updateTip ); } void Slider::updateTip( int value ) { QPoint p; p.setY( height() / 2 ); p.setX( style()->sliderPositionFromValue ( minimum(), maximum(), value, width() ) ); QString text = QString::number( value ) + QLatin1Char( '%' ); QToolTip::showText( mapToGlobal( p ), text, this ); } //-------------------------------------- // Hmmm, a bit hacky, but this makes it possible to use index specific editors... SelectorDelegate::SelectorDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *SelectorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex & index ) const { switch ( index.model()->data( index, Role::EditorType ).toInt() ) { case Delegate::EnumEditor: { QComboBox *editor = new KComboBox(parent); editor->installEventFilter(const_cast(this)); return editor; } case Delegate::TimeEditor: { QTimeEdit *editor = new QTimeEdit(parent); editor->installEventFilter(const_cast(this)); return editor; } } return 0; // FIXME: What to do? } void SelectorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { switch ( index.model()->data( index, Role::EditorType ).toInt() ) { case Delegate::EnumEditor: { QStringList lst = index.model()->data( index, Role::EnumList ).toStringList(); int value = index.model()->data(index, Role::EnumListValue).toInt(); QComboBox *box = static_cast(editor); box->addItems( lst ); box->setCurrentIndex( value ); return; } case Delegate::TimeEditor: QTime value = index.model()->data(index, Qt::EditRole).toTime(); QTimeEdit *e = static_cast(editor); e->setMinimumTime( index.model()->data( index, Role::Minimum ).toTime() ); e->setMaximumTime( index.model()->data( index, Role::Maximum ).toTime() ); e->setTime( value ); return; } } void SelectorDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { switch ( index.model()->data( index, Role::EditorType ).toInt() ) { case Delegate::EnumEditor: { QComboBox *box = static_cast(editor); int value = box->currentIndex(); model->setData( index, value, Qt::EditRole ); return; } case Delegate::TimeEditor: { QTimeEdit *e = static_cast(editor); model->setData( index, e->time(), Qt::EditRole ); return; } } } void SelectorDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { QRect r = option.rect; editor->setGeometry(r); } EnumDelegate::EnumDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { QComboBox *editor = new KComboBox(parent); editor->installEventFilter(const_cast(this)); return editor; } void EnumDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QStringList lst = index.model()->data( index, Role::EnumList ).toStringList(); int value = index.model()->data(index, Role::EnumListValue).toInt(); QComboBox *box = static_cast(editor); box->addItems( lst ); box->setCurrentIndex( value ); } void EnumDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *box = static_cast(editor); int value = box->currentIndex(); model->setData( index, value, Qt::EditRole ); } void EnumDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { debugPlan<sizeHint(); QRect r = option.rect; //r.setHeight(r.height() 50); editor->setGeometry(r); } //--------------------------- RequieredResourceDelegate::RequieredResourceDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *RequieredResourceDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const { if ( index.data( Qt::CheckStateRole ).toInt() == Qt::Unchecked ) { return 0; } TreeComboBox *editor = new TreeComboBox(parent); editor->installEventFilter(const_cast(this)); ResourceItemSFModel *m = new ResourceItemSFModel( editor ); editor->setModel( m ); return editor; } void RequieredResourceDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { TreeComboBox *box = static_cast(editor); ResourceItemSFModel *pm = static_cast( box->model() ); ResourceItemModel *rm = qobject_cast( pm->sourceModel() ); Q_ASSERT( rm ); const ResourceAllocationItemModel *model = qobject_cast( index.model() ); Q_ASSERT( model ); rm->setProject( model->project() ); pm->addFilteredResource( model->resource( index ) ); QItemSelectionModel *sm = box->view()->selectionModel(); sm->clearSelection(); foreach ( const Resource *r, model->required( index ) ) { QModelIndex i = pm->mapFromSource( rm->index( r ) ); sm->select( i, QItemSelectionModel::Select | QItemSelectionModel::Rows ); } box->setCurrentIndexes( sm->selectedRows() ); box->view()->expandAll(); } void RequieredResourceDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { TreeComboBox *box = static_cast(editor); QAbstractProxyModel *pm = static_cast( box->model() ); ResourceItemModel *rm = qobject_cast( pm->sourceModel() ); QList lst; foreach ( const QModelIndex &i, box->currentIndexes() ) { lst << rm->resource( pm->mapToSource( i ) ); } ResourceAllocationItemModel *mdl = qobject_cast( model ); Q_ASSERT( mdl ); mdl->setRequired( index, lst ); } void RequieredResourceDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { debugPlan<sizeHint(); QRect r = option.rect; r.setWidth( qMax( 100, r.width() ) ); editor->setGeometry(r); } //------------------------------- DurationSpinBoxDelegate::DurationSpinBoxDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *DurationSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { DurationSpinBox *editor = new DurationSpinBox(parent); editor->installEventFilter(const_cast(this)); return editor; } void DurationSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { DurationSpinBox *dsb = static_cast(editor); // dsb->setScales( index.model()->data( index, Role::DurationScales ) ); dsb->setMinimumUnit( (Duration::Unit)(index.data( Role::Minimum ).toInt()) ); dsb->setMaximumUnit( (Duration::Unit)(index.data( Role::Maximum ).toInt()) ); dsb->setUnit( (Duration::Unit)( index.model()->data( index, Role::DurationUnit ).toInt() ) ); dsb->setValue( index.model()->data( index, Qt::EditRole ).toDouble() ); } void DurationSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { DurationSpinBox *dsb = static_cast(editor); QVariantList lst; lst << QVariant( dsb->value() ) << QVariant( (int)( dsb->unit() ) ); model->setData( index, QVariant( lst ), Qt::EditRole ); } void DurationSpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { debugPlan<sizeHint(); QRect r = option.rect; //r.setHeight(r.height() + 50); editor->setGeometry(r); } //--------------------------- SpinBoxDelegate::SpinBoxDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *SpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { QSpinBox *editor = new QSpinBox(parent); editor->installEventFilter(const_cast(this)); return editor; } void SpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { int value = index.model()->data(index, Qt::EditRole).toInt(); int min = index.model()->data(index, Role::Minimum).toInt(); int max = index.model()->data(index, Role::Maximum).toInt(); QSpinBox *box = static_cast(editor); box->setRange( min, max ); box->setValue( value ); } void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QSpinBox *box = static_cast(editor); model->setData( index, box->value(), Qt::EditRole ); } void SpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { debugPlan<sizeHint(); QRect r = option.rect; //r.setHeight(r.height() + 50); editor->setGeometry(r); } //--------------------------- DoubleSpinBoxDelegate::DoubleSpinBoxDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *DoubleSpinBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { QDoubleSpinBox *editor = new QDoubleSpinBox(parent); editor->installEventFilter(const_cast(this)); return editor; } void DoubleSpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { double value = index.model()->data(index, Qt::EditRole).toDouble(); double min = 0.0;//index.model()->data(index, Role::Minimum).toInt(); double max = 24.0;//index.model()->data(index, Role::Maximum).toInt(); QDoubleSpinBox *box = static_cast(editor); box->setDecimals( 1 ); box->setRange( min, max ); box->setValue( value ); box->selectAll(); } void DoubleSpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QDoubleSpinBox *box = static_cast(editor); model->setData( index, box->value(), Qt::EditRole ); } void DoubleSpinBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { QRect r = option.rect; editor->setGeometry(r); } //--------------------------- MoneyDelegate::MoneyDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *MoneyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { KLineEdit *editor = new KLineEdit(parent); //TODO: validator editor->installEventFilter(const_cast(this)); return editor; } void MoneyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QString value = index.model()->data(index, Qt::EditRole).toString(); KLineEdit *e = static_cast(editor); e->setText( value ); } void MoneyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { KLineEdit *e = static_cast(editor); model->setData( index, e->text(), Qt::EditRole ); } void MoneyDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { QRect r = option.rect; editor->setGeometry(r); } //--------------------------- TimeDelegate::TimeDelegate( QObject *parent ) : ItemDelegate( parent ) { } QWidget *TimeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { QTimeEdit *editor = new QTimeEdit(parent); editor->installEventFilter(const_cast(this)); return editor; } void TimeDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QTime value = index.model()->data(index, Qt::EditRole).toTime(); QTimeEdit *e = static_cast(editor); e->setMinimumTime( index.model()->data( index, Role::Minimum ).toTime() ); e->setMaximumTime( index.model()->data( index, Role::Maximum ).toTime() ); e->setTime( value ); } void TimeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QTimeEdit *e = static_cast(editor); model->setData( index, e->time(), Qt::EditRole ); } void TimeDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { QRect r = option.rect; editor->setGeometry(r); } //-------------------------- ItemModelBase::ItemModelBase( QObject *parent ) : QAbstractItemModel( parent ), m_project(0), m_manager( 0 ), m_readWrite( false )//part->isReadWrite() ) { } ItemModelBase::~ItemModelBase() { } void ItemModelBase::setProject( Project *project ) { m_project = project; } void ItemModelBase::setScheduleManager( ScheduleManager *sm ) { m_manager = sm; } void ItemModelBase::slotLayoutChanged() { debugPlan; + emit layoutAboutToBeChanged(); emit layoutChanged(); } void ItemModelBase::slotLayoutToBeChanged() { debugPlan; emit layoutAboutToBeChanged(); } bool ItemModelBase::dropAllowed( const QModelIndex &index, int, const QMimeData *data ) { if ( flags( index ) & Qt::ItemIsDropEnabled ) { foreach ( const QString &s, data->formats() ) { if ( mimeTypes().contains( s ) ) { return true; } } } return false; } QVariant ItemModelBase::data( const QModelIndex &index, int role ) const { if ( index.isValid() && role == Role::ColumnTag ) { return columnMap().key( index.column() ); } return QVariant(); } QVariant ItemModelBase::headerData( int section, Qt::Orientation orientation, int role ) const { Q_UNUSED(orientation); if ( role == Role::ColumnTag ) { return columnMap().key( section ); } return QVariant(); } bool ItemModelBase::setData( const QModelIndex &index, const QVariant &value, int role ) { Q_UNUSED(index); if ( role == Role::ReadWrite ) { setReadWrite( value.toBool() ); return true; } return false; } void ItemModelBase::projectDeleted() { setProject(0); } } //namespace KPlato diff --git a/src/libs/models/kptnodechartmodel.cpp b/src/libs/models/kptnodechartmodel.cpp index a75bb764..8d753c3b 100644 --- a/src/libs/models/kptnodechartmodel.cpp +++ b/src/libs/models/kptnodechartmodel.cpp @@ -1,549 +1,549 @@ /* This file is part of the Calligra project * Copyright (c) 2008, 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. */ #include "kptnodechartmodel.h" #include "kptlocale.h" #include "kptnode.h" #include "kptproject.h" #include "kptschedule.h" #include "kptresource.h" #include "kptdebug.h" #include #include #include #include #include namespace KPlato { ChartItemModel::ChartItemModel( QObject *parent ) : ItemModelBase( parent ), m_localizeValues( false ) { } QModelIndex ChartItemModel::parent( const QModelIndex &index ) const { Q_UNUSED(index); return QModelIndex(); } const QMetaEnum ChartItemModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } int ChartItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return columnMap().keyCount(); } int ChartItemModel::rowCount( const QModelIndex &parent ) const { return parent.isValid() ? 0 : startDate().daysTo( endDate() ) + 1; } QModelIndex ChartItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || row < 0 || column < 0 ) { //debugPlan<<"No project"< m_bcws.endDate() ) { res = m_bcws.bcwpEffort( date ); } return res; } double ChartItemModel::acwpEffort( int day ) const { return m_acwp.hoursTo( startDate().addDays( day ) ); } double ChartItemModel::bcwsCost( int day ) const { return m_bcws.costTo( startDate().addDays( day ) ); } double ChartItemModel::bcwpCost( int day ) const { double res = 0.0; QDate date = startDate().addDays( day ); if ( m_bcws.days().contains( date ) ) { res = m_bcws.bcwpCost( date ); } else if ( date > m_bcws.endDate() ) { res = m_bcws.bcwpCost( m_bcws.endDate() ); } return res; } double ChartItemModel::acwpCost( int day ) const { return m_acwp.costTo( startDate().addDays( day ) ); } double ChartItemModel::spiEffort( int day ) const { double p = bcwpEffort( day ); double s = bcwsEffort( day ); return s == 0.0 ? 0.0 : p / s; } double ChartItemModel::spiCost( int day ) const { double p = bcwpCost( day ); double s = bcwsCost( day ); return s == 0.0 ? 0.0 : p / s; } double ChartItemModel::cpiEffort( int day ) const { double p = bcwpEffort( day ); double a = acwpEffort( day ); return a == 0.0 ? 0.0 : p / a; } double ChartItemModel::cpiCost( int day ) const { double p = bcwpCost( day ); double a = acwpCost( day ); return a == 0.0 ? 0.0 : p / a; } QVariant ChartItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( role == Qt::DisplayRole ) { if ( ! m_localizeValues ) { return data( index, Qt::EditRole ); } else { QLocale locale; // TODO: temporary workaround while KLocale/money logic still used Locale *planLocale; Locale *tmpPlanLocale = 0; if (project()) { planLocale = project()->locale(); } else { tmpPlanLocale = new Locale(); planLocale = tmpPlanLocale; } switch ( index.column() ) { case BCWSCost: result = planLocale->formatMoney( bcwsCost( index.row() ), QString(), 0 ); break; case BCWPCost: result = planLocale->formatMoney( bcwpCost( index.row() ), QString(), 0 ); break; case ACWPCost: result = planLocale->formatMoney( acwpCost( index.row() ), QString(), 0 ); break; case BCWSEffort: result = locale.toString( bcwsEffort( index.row() ), 'f', 0 ); break; case BCWPEffort: result = locale.toString( bcwpEffort( index.row() ), 'f', 0 ); break; case ACWPEffort: result = locale.toString( acwpEffort( index.row() ), 'f', 0 ); break; case SPICost: result = locale.toString( spiCost( index.row() ), 'f', 2 ); break; case CPICost: result = locale.toString( cpiCost( index.row() ), 'f', 2 ); break; case SPIEffort: result = locale.toString( spiEffort( index.row() ), 'f', 2 ); break; case CPIEffort: result = locale.toString( cpiEffort( index.row() ), 'f', 2 ); break; default: break; } delete tmpPlanLocale; } //debugPlan< 0.0 && v < 1.0 ) { result = QBrush( Qt::red ); } return result; } else if ( role == KChart::DatasetBrushRole ) { return headerData( index.column(), Qt::Horizontal, role ); } else if ( role == KChart::DatasetPenRole ) { return headerData( index.column(), Qt::Horizontal, role ); } //debugPlan<() ); result = p; //debugPlan< &nodes ) { beginResetModel(); debugPlan<isChildOf( n ) ) { beginResetModel(); calculate(); endResetModel(); return; } } } void ChartItemModel::slotResourceChanged( Resource* ) { beginResetModel(); calculate(); endResetModel(); } void ChartItemModel::slotResourceChanged( const Resource* ) { beginResetModel(); calculate(); endResetModel(); } QDate ChartItemModel::startDate() const { QDate d = m_bcws.startDate(); if ( m_acwp.startDate().isValid() ) { if ( ! d.isValid() || d > m_acwp.startDate() ) { d = m_acwp.startDate(); } } return d; } QDate ChartItemModel::endDate() const { return qMax( m_bcws.endDate(), m_acwp.endDate() ); } void ChartItemModel::calculate() { //debugPlan<isChildOf( p ) ) { skip = true; break; } } if ( ! skip ) { m_bcws += n->bcwpPrDay( m_manager->scheduleId(), ECCT_EffortWork ); m_acwp += n->acwp( m_manager->scheduleId() ); } } } } //debugPlan<<"bcwp"< 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. */ #include "kptnodeitemmodel.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptduration.h" #include "kptproject.h" #include "kptnode.h" #include "kpttaskcompletedelegate.h" #include "kptxmlloaderobject.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { //-------------------------------------- NodeModel::NodeModel() : QObject(), m_project( 0 ), m_manager( 0 ), m_now( QDate::currentDate() ), m_prec( 1 ) { } const QMetaEnum NodeModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } void NodeModel::setProject( Project *project ) { debugPlan<"<"<name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::DecorationRole: if ( node->isBaselined() ) { return koIcon("view-time-schedule-baselined"); } break; case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return static_cast( node )->completion().isFinished() ? m_project->config().taskFinishedColor() : m_project->config().taskNormalColor(); case Node::Type_Milestone: return static_cast( node )->completion().isFinished() ? m_project->config().milestoneFinishedColor() : m_project->config().milestoneNormalColor(); case Node::Type_Summarytask: return m_project->config().summaryTaskLevelColor( node->level() ); default: break; } break; } } return QVariant(); } QVariant NodeModel::leader( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return node->leader(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::allocation( const Node *node, int role ) const { if ( node->type() == Node::Type_Task ) { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->requests().requestNameList().join( "," ); case Qt::ToolTipRole: { QMap lst; foreach ( ResourceRequest *rr, node->requests().resourceRequests( false ) ) { QStringList sl; foreach( Resource *r, rr->requiredResources() ) { sl << r->name(); } lst.insert( rr->resource()->name(), sl ); } if ( lst.isEmpty() ) { return xi18nc( "@info:tooltip", "No resources has been allocated" ); } QStringList sl; for ( QMap::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) { if ( it.value().isEmpty() ) { sl << it.key(); } else { sl << xi18nc( "@info:tooltip 1=resource name, 2=list of required resources", "%1 (%2)", it.key(), it.value().join(", ") ); } } if ( sl.count() == 1 ) { return xi18nc( "@info:tooltip 1=resource name", "Allocated resource:%1", sl.first() ); } KLocalizedString ks = kxi18nc( "@info:tooltip 1=list of resources", "Allocated resources:%1"); // Hack to get around ks escaping '<' and '>' QString s = ks.subs(sl.join("#¤#")).toString(); return s.replace("#¤#", "
"); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::description( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { KRichTextWidget w( node->description(), 0 ); w.switchToPlainText(); QString s = w.textOrHtml(); int i = s.indexOf( '\n' ); s = s.left( i ); if ( i > 0 ) { s += "..."; } return s; } case Qt::ToolTipRole: { KRichTextWidget w( node->description(), 0 ); w.switchToPlainText(); if ( w.textOrHtml().isEmpty() ) { return QVariant(); } return node->description(); } case Qt::EditRole: return node->description(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::type( const Node *node, int role ) const { //debugPlan<name()<<", "<typeToString( true ); case Qt::EditRole: return node->type(); case Qt::TextAlignmentRole: return (int)(Qt::AlignLeft|Qt::AlignVCenter); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::constraint( const Node *node, int role ) const { if ( node->type() == Node::Type_Project ) { switch ( role ) { case Qt::DisplayRole: return i18n( "Target times" ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Earliest start and latest finish" ); case Role::EnumList: case Qt::EditRole: case Role::EnumListValue: return QVariant(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } else if ( node->type() != Node::Type_Summarytask ) { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return node->constraintToString( true ); case Role::EnumList: return Node::constraintList( true ); case Qt::EditRole: return node->constraint(); case Role::EnumListValue: return (int)node->constraint(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::constraintStartTime( const Node *node, int role ) const { if ( node->type() == Node::Type_Project ) { switch ( role ) { case Qt::DisplayRole: { return QLocale().toString( node->constraintStartTime(), QLocale::ShortFormat ); } case Qt::ToolTipRole: { return QLocale().toString( node->constraintStartTime(), QLocale::LongFormat ); } case Qt::EditRole: return node->constraintStartTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } else if ( node->type() != Node::Type_Summarytask ) { switch ( role ) { case Qt::DisplayRole: { QString s = QLocale().toString( node->constraintStartTime(), QLocale::ShortFormat ); switch ( node->constraint() ) { case Node::StartNotEarlier: case Node::MustStartOn: case Node::FixedInterval: return s; default: break; } return QString( "(%1)" ).arg( s ); } case Qt::ToolTipRole: { int c = node->constraint(); if ( c == Node::MustStartOn || c == Node::StartNotEarlier || c == Node::FixedInterval ) { return QLocale().toString( node->constraintStartTime(), QLocale::LongFormat ); } break; } case Qt::EditRole: return node->constraintStartTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::constraintEndTime( const Node *node, int role ) const { if ( node->type() == Node::Type_Project ) { switch ( role ) { case Qt::DisplayRole: { return QLocale().toString( node->constraintEndTime(), QLocale::ShortFormat ); } case Qt::ToolTipRole: { return QLocale().toString( node->constraintEndTime(), QLocale::LongFormat ); } case Qt::EditRole: return node->constraintEndTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } else if ( node->type() != Node::Type_Summarytask ) { switch ( role ) { case Qt::DisplayRole: { QString s = QLocale().toString( node->constraintEndTime(), QLocale::ShortFormat ); switch ( node->constraint() ) { case Node::FinishNotLater: case Node::MustFinishOn: case Node::FixedInterval: return s; default: break; } return QString( "(%1)" ).arg( s ); } case Qt::ToolTipRole: { int c = node->constraint(); if ( c == Node::FinishNotLater || c == Node::MustFinishOn || c == Node::FixedInterval ) { return QLocale().toString( node->constraintEndTime(), QLocale::LongFormat ); } break; } case Qt::EditRole: return node->constraintEndTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } } return QVariant(); } QVariant NodeModel::estimateType( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->typeToString( true ); } return QString(); case Role::EnumList: return Estimate::typeToStringList( true ); case Qt::EditRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->typeToString(); } return QString(); case Role::EnumListValue: return (int)node->estimate()->type(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::estimateCalendar( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { if ( node->estimate()->calendar() ) { return node->estimate()->calendar()->name(); } return i18n( "None" ); } return QString(); case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { if ( node->estimate()->type() == Estimate::Type_Effort ) { return xi18nc( "@info:tooltip", "Not applicable, estimate type is Effort" ); } if ( node->estimate()->calendar() ) { return node->estimate()->calendar()->name(); } return QVariant(); } return QString(); case Role::EnumList: { QStringList lst; lst << i18n( "None" ); const Node *n = const_cast( node )->projectNode(); if ( n ) { lst += static_cast( n )->calendarNames(); } return lst; } case Qt::EditRole: if ( node->type() == Node::Type_Task ) { if ( node->estimate()->calendar() == 0 ) { return i18n( "None" ); } return node->estimate()->calendar()->name(); } return QString(); case Role::EnumListValue: { if ( node->estimate()->calendar() == 0 ) { return 0; } QStringList lst; const Node *n = const_cast( node )->projectNode(); if ( n ) { lst = static_cast( n )->calendarNames(); } return lst.indexOf( node->estimate()->calendar()->name() ) + 1; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::estimate( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->expectedEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); if ( node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) { s = '(' + s + ')'; } return s; } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->expectedEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); Estimate::Type t = node->estimate()->type(); if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) { s = xi18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" ); } else if ( t == Estimate::Type_Effort ) { s = xi18nc( "@info:tooltip", "Estimated effort: %1", s ); } else { s = xi18nc( "@info:tooltip", "Estimated duration: %1", s ); } return s; } break; case Qt::EditRole: return node->estimate()->expectedEstimate(); case Role::DurationUnit: return static_cast( node->estimate()->unit() ); case Role::Minimum: return m_project->config().minimumDurationUnit(); case Role::Maximum: return m_project->config().maximumDurationUnit(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::optimisticRatio( const Node *node, int role ) const { if ( node->estimate() == 0 || node->type() == Node::Type_Summarytask || node->type() == Node::Type_Milestone ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task && node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) { QString s = QString::number( node->estimate()->optimisticRatio() ); s = '(' + s + ')'; return s; } if ( node->estimate() ) { return node->estimate()->optimisticRatio(); } break; case Qt::EditRole: if ( node->estimate() ) { return node->estimate()->optimisticRatio(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->optimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); Estimate::Type t = node->estimate()->type(); if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) { s = xi18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" ); } else if ( t == Estimate::Type_Effort ) { s = xi18nc( "@info:tooltip", "Optimistic effort: %1", s ); } else { s = xi18nc( "@info:tooltip", "Optimistic duration: %1", s ); } return s; } break; case Role::Minimum: return -99; case Role::Maximum: return 0; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::pessimisticRatio( const Node *node, int role ) const { if ( node->estimate() == 0 || node->type() == Node::Type_Summarytask || node->type() == Node::Type_Milestone ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task && node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) { QString s = QString::number( node->estimate()->pessimisticRatio() ); s = '(' + s + ')'; return s; } if ( node->estimate() ) { return node->estimate()->pessimisticRatio(); } break; case Qt::EditRole: if ( node->estimate() ) { return node->estimate()->pessimisticRatio(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); QString s = QLocale().toString( node->estimate()->pessimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ); Estimate::Type t = node->estimate()->type(); if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) { s = xi18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" ); } else if ( t == Estimate::Type_Effort ) { s = xi18nc( "@info:tooltip", "Pessimistic effort: %1", s ); } else { s = xi18nc( "@info:tooltip", "Pessimistic duration: %1", s ); } return s; } break; case Role::Minimum: return 0; case Role::Maximum: return INT_MAX; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::riskType( const Node *node, int role ) const { if ( node->estimate() == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->risktypeToString( true ); } return QString(); case Role::EnumList: return Estimate::risktypeToStringList( true ); case Qt::EditRole: if ( node->type() == Node::Type_Task ) { return node->estimate()->risktypeToString(); } return QString(); case Role::EnumListValue: return (int)node->estimate()->risktype(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::runningAccount( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { Account *a = node->runningAccount(); return a == 0 ? i18n( "None" ) : a->name(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Account *a = node->runningAccount(); return a ? xi18nc( "@info:tooltip", "Account for resource cost: %1", a->name() ) : xi18nc( "@info:tooltip", "Account for resource cost" ); } break; case Role::EnumListValue: case Qt::EditRole: { Account *a = node->runningAccount(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startupAccount( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->startupAccount(); //debugPlan<name()<<": "<name(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->startupAccount(); //debugPlan<name()<<": "<name() ) : xi18nc( "@info:tooltip", "Account for task startup cost" ); } break; case Role::EnumListValue: case Qt::EditRole: { Account *a = node->startupAccount(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startupCost( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { return m_project->locale()->formatMoney( node->startupCost() ); } break; case Qt::EditRole: return node->startupCost(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::shutdownAccount( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->shutdownAccount(); return a == 0 ? i18n( "None" ) : a->name(); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { Account *a = node->shutdownAccount(); return a ? xi18nc( "@info:tooltip", "Account for task shutdown cost: %1", a->name() ) : xi18nc( "@info:tooltip", "Account for task shutdown cost" ); } break; case Role::EnumListValue: case Qt::EditRole: { Account *a = node->shutdownAccount(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::shutdownCost( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) { return m_project->locale()->formatMoney( node->shutdownCost() ); } break; case Qt::EditRole: return node->shutdownCost(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startTime( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( node->startTime( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: //debugPlan<name()<<", "<startTime( id() ), QLocale::LongFormat ) ); case Qt::EditRole: return node->startTime( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::endTime( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( node->endTime( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: //debugPlan<name()<<", "<endTime( id() ), QLocale::LongFormat ) ); case Qt::EditRole: return node->endTime( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::duration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->duration( id() ).toDouble( unit ); return QVariant(QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true )); } else if ( node->type() == Node::Type_Project ) { Duration::Unit unit = Duration::Unit_d; double v = node->duration( id() ).toDouble( unit ); return QVariant(QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true )); } break; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->duration( id() ).toDouble( unit ); return xi18nc( "@info:tooltip", "Scheduled duration: %1", QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true ) ); } else if ( node->type() == Node::Type_Project ) { Duration::Unit unit = Duration::Unit_d; double v = node->duration( id() ).toDouble( unit ); return xi18nc( "@info:tooltip", "Scheduled duration: %1", QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true ) ); } break; case Qt::EditRole: { return node->duration( id() ).toDouble( Duration::Unit_h ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::varianceDuration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->variance( id(), unit ); return QLocale().toString( v, 'f', 2 ); } break; case Qt::EditRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); return node->variance( id(), unit ); } return 0.0; case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Duration::Unit unit = node->estimate()->unit(); double v = node->variance( id(), unit ); return xi18nc( "@info:tooltip", "PERT duration variance: %1", QLocale().toString( v ,'f', 2 ) ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::varianceEstimate( const Estimate *est, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = est->variance( unit ); //debugPlan<name()<<": "<variance( est->unit() ); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = est->variance( unit ); return xi18nc( "@info:tooltip", "PERT estimate variance: %1", QLocale().toString( v, 'f', 2 ) + Duration::unitToString( unit, true ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::optimisticDuration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<type() != Node::Type_Task ) { return 0.0; } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); return d.toDouble( unit ); } case Qt::ToolTipRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<unit(); return QVariant(QLocale().toString( est->optimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true )); break; } case Qt::EditRole: { if ( est == 0 ) { return 0.0; } return est->optimisticEstimate(); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); return xi18nc( "@info:tooltip", "Optimistic estimate: %1", QLocale().toString( est->optimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ) ); break; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::pertExpected( const Estimate *est, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = Estimate::scale( est->pertExpected(), unit, est->scales() ); return QVariant(QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true )); } case Qt::EditRole: { if ( est == 0 ) { return 0.0; } return Estimate::scale( est->pertExpected(), est->unit(), est->scales() ); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); double v = Estimate::scale( est->pertExpected(), unit, est->scales() ); return xi18nc( "@info:tooltip", "PERT expected estimate: %1", QLocale().toString( v, 'f', m_prec ) + Duration::unitToString( unit, true ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::pessimisticDuration( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<type() != Node::Type_Task ) { return 0.0; } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100; return d.toDouble( node->estimate()->unit() ); } case Qt::ToolTipRole: { if ( node->type() != Node::Type_Task ) { return QVariant(); } Duration d = node->duration( id() ); d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100; Duration::Unit unit = node->estimate()->unit(); double v = d.toDouble( unit ); //debugPlan<name()<<": "<unit(); return QVariant(QLocale().toString( est->pessimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true )); break; } case Qt::EditRole: { if ( est == 0 ) { return 0.0; } return est->pessimisticEstimate(); } case Qt::ToolTipRole: { if ( est == 0 ) { return QVariant(); } Duration::Unit unit = est->unit(); return xi18nc( "@info:tooltip", "Pessimistic estimate: %1", QLocale().toString( est->pessimisticEstimate(), 'f', m_prec ) + Duration::unitToString( unit, true ) ); break; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::earlyStart( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->earlyStart( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->earlyStart( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->earlyStart( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::earlyFinish( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->earlyFinish( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->earlyFinish( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->earlyFinish( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::lateStart( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->lateStart( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->lateStart( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->lateStart( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::lateFinish( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return QLocale().toString( t->lateFinish( id() ), QLocale::ShortFormat ); case Qt::ToolTipRole: return QLocale().toString( t->lateFinish( id() ).date(), QLocale::ShortFormat ); case Qt::EditRole: return t->lateFinish( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::positiveFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->positiveFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->positiveFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->positiveFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::freeFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->freeFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->freeFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->freeFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::negativeFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->negativeFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->negativeFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->negativeFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->startFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->startFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->startFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::finishFloat( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->finishFloat( id() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return t->finishFloat( id() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: return t->finishFloat( id() ).toDouble( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::assignedResources( const Node *node, int role ) const { if ( node->type() != Node::Type_Task ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->assignedNameList( id() ).join(","); case Qt::ToolTipRole: { QStringList lst = node->assignedNameList( id() ); if ( ! lst.isEmpty() ) { return xi18nc( "@info:tooltip 1=list of resources", "Assigned resources:%1", node->assignedNameList( id() ).join("") ); } break; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::completed( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: return t->completion().percentFinished(); case Qt::EditRole: return t->completion().percentFinished(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Task is %1% completed", t->completion().percentFinished() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::status( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: { int st = t->state( id() ); if ( st & Node::State_NotScheduled ) { return SchedulingState::notScheduled(); } if ( st & Node::State_Finished ) { if ( st & Node::State_FinishedLate ) { return i18n( "Finished late" ); } if ( st & Node::State_FinishedEarly ) { return i18n( "Finished early" ); } return i18n( "Finished" ); } if ( st & Node::State_Running ) { if ( st & Node::State_Late ) { return i18n( "Running late" ); } return i18n( "Running" ); } if ( st & Node::State_Started ) { if ( st & Node::State_StartedLate ) { return i18n( "Started late" ); } if ( st & Node::State_StartedEarly ) { return i18n( "Started early" ); } if ( st & Node::State_Late ) { return i18n( "Running late" ); } return i18n( "Started" ); } if ( st & Node::State_ReadyToStart ) { if ( st & Node::State_Late ) { return i18n( "Not started" ); } return i18n( "Can start" ); } if ( st & Node::State_NotReadyToStart ) { if ( st & Node::State_Late ) { return i18n( "Delayed" ); } return i18n( "Cannot start" ); } return i18n( "Not started" ); break; } case Qt::ToolTipRole: { int st = t->state( id() ); if ( st & Node::State_NotScheduled ) { return SchedulingState::notScheduled(); } if ( st & Node::State_Finished ) { if ( st & Node::State_FinishedLate ) { Duration d = t->completion().finishTime() - t->endTime( id() ); return xi18nc( "@info:tooltip", "Finished %1 late", d.toString( Duration::Format_i18nDay ) ); } if ( st & Node::State_FinishedEarly ) { Duration d = t->endTime( id() ) - t->completion().finishTime(); return xi18nc( "@info:tooltip", "Finished %1 early", d.toString( Duration::Format_i18nDay ) ); } return xi18nc( "@info:tooltip", "Finished" ); } if ( st & Node::State_Started ) { if ( st & Node::State_StartedLate ) { Duration d = t->completion().startTime() - t->startTime( id() ); return xi18nc( "@info:tooltip", "Started %1 late", d.toString( Duration::Format_i18nDay ) ); } if ( st & Node::State_StartedEarly ) { Duration d = t->startTime( id() ) - t->completion().startTime(); return xi18nc( "@info:tooltip", "Started %1 early", d.toString( Duration::Format_i18nDay ) ); } return xi18nc( "@info:tooltip", "Started" ); } if ( st & Node::State_Running ) { return xi18nc( "@info:tooltip", "Running" ); } if ( st & Node::State_ReadyToStart ) { return xi18nc( "@info:tooltip", "Can start" ); } if ( st & Node::State_NotReadyToStart ) { QStringList names; // TODO: proxy relations foreach ( Relation *r, node->dependParentNodes() ) { switch ( r->type() ) { case Relation::FinishFinish: case Relation::FinishStart: if ( ! static_cast( r->parent() )->completion().isFinished() ) { if ( ! names.contains( r->parent()->name() ) ) { names << r->parent()->name(); } } break; case Relation::StartStart: if ( ! static_cast( r->parent() )->completion().isStarted() ) { if ( ! names.contains( r->parent()->name() ) ) { names << r->parent()->name(); } } break; } } return names.isEmpty() ? xi18nc( "@info:tooltip", "Cannot start" ) : xi18nc( "@info:tooltip 1=list of task names", "Cannot start, waiting for:%1", names.join( "" ) ); } return xi18nc( "@info:tooltip", "Not started" ); break; } case Qt::EditRole: return t->state( id() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::startedTime( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: if ( t->completion().isStarted() ) { return QLocale().toString( t->completion().startTime(), QLocale::ShortFormat ); } break; case Qt::ToolTipRole: if ( t->completion().isStarted() ) { return xi18nc( "@info:tooltip", "Actual start: %1", QLocale().toString( t->completion().startTime().date(), QLocale::LongFormat ) ); } break; case Qt::EditRole: if ( t->completion().isStarted() ) { return t->completion().startTime(); } return QDateTime::currentDateTime(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::isStarted( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return t->completion().isStarted(); case Qt::ToolTipRole: if ( t->completion().isStarted() ) { return xi18nc( "@info:tooltip", "The task started at: %1", QLocale().toString( t->completion().startTime().date(), QLocale::LongFormat ) ); } return xi18nc( "@info:tooltip", "The task is not started" ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::finishedTime( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: if ( t->completion().isFinished() ) { return QLocale().toString( t->completion().finishTime(), QLocale::ShortFormat ); } break; case Qt::ToolTipRole: if ( t->completion().isFinished() ) { return xi18nc( "@info:tooltip", "Actual finish: %1", QLocale().toString( t->completion().finishTime(), QLocale::LongFormat ) ); } break; case Qt::EditRole: if ( t->completion().isFinished() ) { return t->completion().finishTime(); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::isFinished( const Node *node, int role ) const { if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) { return QVariant(); } const Task *t = static_cast( node ); switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return t->completion().isFinished(); case Qt::ToolTipRole: if ( t->completion().isFinished() ) { return xi18nc( "@info:tooltip", "The task finished at: %1", QLocale().toString( t->completion().finishTime().date(), QLocale::LongFormat ) ); } return xi18nc( "@info:tooltip", "The task is not finished" ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::plannedEffortTo( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->plannedEffortTo( m_now, id() ).format(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Planned effort until %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), node->plannedEffortTo( m_now, id() ).toString( Duration::Format_i18nHour ) ); case Qt::EditRole: return node->plannedEffortTo( m_now, id() ).toDouble( Duration::Unit_h ); case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::actualEffortTo( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->actualEffortTo( m_now ).format(); case Qt::ToolTipRole: //debugPlan<actualEffortTo( m_now ).toString( Duration::Format_i18nHour ) ); case Qt::EditRole: return node->actualEffortTo( m_now ).toDouble( Duration::Unit_h ); case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::remainingEffort( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { const Task *t = dynamic_cast( node ); if ( t ) { return t->completion().remainingEffort().format(); } break; } case Qt::ToolTipRole: { const Task *t = dynamic_cast( node ); if ( t ) { return xi18nc( "@info:tooltip", "Remaining effort: %1", t->completion().remainingEffort().toString( Duration::Format_i18nHour ) ); } break; } case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } return t->completion().remainingEffort().toDouble( Duration::Unit_h ); } case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::plannedCostTo( const Node *node, int role ) const { Locale *l = m_project->locale(); switch ( role ) { case Qt::DisplayRole: return l->formatMoney( node->plannedCostTo( m_now, id() ) ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Planned cost until %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), l->formatMoney( node->plannedCostTo( m_now, id() ) ) ); case Qt::EditRole: return node->plannedCostTo( m_now ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::actualCostTo( const Node *node, int role ) const { Locale *l = m_project->locale(); switch ( role ) { case Qt::DisplayRole: return l->formatMoney( node->actualCostTo( id(), m_now ).cost() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Actual cost until %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), l->formatMoney( node->actualCostTo( id(), m_now ).cost() ) ); case Qt::EditRole: return node->actualCostTo( id(), m_now ).cost(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::note( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: if ( node->type() == Node::Type_Task ) { Node *n = const_cast( node ); return static_cast( n )->completion().note(); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeSchedulingStatus( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->schedulingStatus( id(), true ).value( 0 ); case Qt::EditRole: return node->schedulingStatus( id(), false ).value( 0 ); case Qt::ToolTipRole: return node->schedulingStatus( id(), true ).join( "\n" ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::resourceIsMissing( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->resourceError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->resourceError( id() ); case Qt::ToolTipRole: if ( node->resourceError( id() ) ) { return xi18nc( "@info:tooltip", "Resource allocation is expected when the task estimate type is Effort" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::resourceIsOverbooked( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->resourceOverbooked( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->resourceOverbooked( id() ); case Qt::ToolTipRole: if ( node->resourceOverbooked( id() ) ) { return xi18nc( "@info:tooltip", "A resource has been overbooked" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::resourceIsNotAvailable( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->resourceNotAvailable( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->resourceNotAvailable( id() ); case Qt::ToolTipRole: if ( node->resourceNotAvailable( id() ) ) { return xi18nc( "@info:tooltip", "No resource is available for this task" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::schedulingConstraintsError( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->constraintError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->constraintError( id() ); case Qt::ToolTipRole: if ( node->constraintError( id() ) ) { return xi18nc( "@info:tooltip", "Failed to comply with a timing constraint" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::nodeIsNotScheduled( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->notScheduled( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->notScheduled( id() ); case Qt::ToolTipRole: if ( node->notScheduled( id() ) ) { return xi18nc( "@info:tooltip", "This task has not been scheduled" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::effortNotMet( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->effortMetError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->effortMetError( id() ); case Qt::ToolTipRole: if ( node->effortMetError( id() ) ) { return xi18nc( "@info:tooltip", "The assigned resources cannot deliver the required estimated effort" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::schedulingError( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( node->schedulingError( id() ) ) { return i18n( "Error" ); } break; case Qt::EditRole: return node->schedulingError( id() ); case Qt::ToolTipRole: if ( node->schedulingError( id() ) ) { return xi18nc( "@info:tooltip", "Scheduling error" ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskErrorColor(); case Node::Type_Milestone: return m_project->config().milestoneErrorColor(); default: break; } } } return QVariant(); } QVariant NodeModel::wbsCode( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->wbsCode(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Work breakdown structure code: %1", node->wbsCode() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case SortableRole: return node->wbsCode(true); } return QVariant(); } QVariant NodeModel::nodeLevel( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->level(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Task level: %1", node->level() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeBCWS( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( node->bcws( m_now, id() ), QString(), 0 ); case Qt::EditRole: return node->bcws( m_now, id() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Budgeted Cost of Work Scheduled at %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), m_project->locale()->formatMoney( node->bcws( m_now, id() ), QString(), 0 ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeBCWP( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( node->bcwp( id() ), QString(), 0 ); case Qt::EditRole: return node->bcwp( id() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Budgeted Cost of Work Performed at %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), m_project->locale()->formatMoney( node->bcwp( id() ), QString(), 0 ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodeACWP( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( node->acwp( m_now, id() ).cost(), QString(), 0 ); case Qt::EditRole: return node->acwp( m_now, id() ).cost(); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Actual Cost of Work Performed at %1: %2", QLocale().toString( m_now, QLocale::ShortFormat ), m_project->locale()->formatMoney( node->acwp( m_now, id() ).cost() ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::nodePerformanceIndex( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( node->schedulePerformanceIndex( m_now, id() ), 'f', 2 ); case Qt::EditRole: return node->schedulePerformanceIndex( m_now, id() ); case Qt::ToolTipRole: return xi18nc( "@info:tooltip", "Schedule Performance Index at %1: %2", m_now.toString(), QLocale().toString( node->schedulePerformanceIndex( m_now, id() ), 'f', 2 ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::ForegroundRole: return QColor(node->schedulePerformanceIndex( m_now, id() ) < 1.0 ? Qt::red : Qt::black); } return QVariant(); } QVariant NodeModel::nodeIsCritical( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->isCritical( id() ); case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskNormalColor(); case Node::Type_Milestone: return m_project->config().milestoneNormalColor(); default: break; } } } return QVariant(); } QVariant NodeModel::nodeInCriticalPath( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return node->inCriticalPath( id() ); case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Foreground: { if ( ! m_project ) { break; } switch ( node->type() ) { case Node::Type_Task: return m_project->config().taskNormalColor(); case Node::Type_Milestone: return m_project->config().milestoneNormalColor(); default: break; } } } return QVariant(); } QVariant NodeModel::wpOwnerName( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) { return xi18nc( "Not available", "NA" ); } return t->wpOwnerName(); } case Qt::ToolTipRole: { const Task *task = dynamic_cast( node ); if ( task == 0 ) { return QVariant(); } int sts = task->wpTransmitionStatus(); QString t = wpTransmitionTime( node, Qt::DisplayRole ).toString(); if ( sts == WorkPackage::TS_Send ) { return xi18nc( "@info:tooltip", "Latest work package sent to %1 at %2", static_cast( node )->wpOwnerName(), t ); } if ( sts == WorkPackage::TS_Receive ) { return xi18nc( "@info:tooltip", "Latest work package received from %1 at %2", static_cast( node )->wpOwnerName(), t ); } return xi18nc( "@info:tooltip", "Not available" ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::wpTransmitionStatus( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) { return xi18nc( "Not available", "NA" ); } return WorkPackage::transmitionStatusToString( t->wpTransmitionStatus(), true ); } case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } return WorkPackage::transmitionStatusToString( t->wpTransmitionStatus(), false ); } case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::wpTransmitionTime( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: { const Task *t = dynamic_cast( node ); if ( t == 0 ) { return QVariant(); } if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) { return xi18nc( "Not available", "NA" ); } return QLocale().toString( t->wpTransmitionTime(), QLocale::ShortFormat ); } case Qt::ToolTipRole: { const Task *task = dynamic_cast( node ); if ( task == 0 ) { return QVariant(); } int sts = task->wpTransmitionStatus(); QString t = wpTransmitionTime( node, Qt::DisplayRole ).toString(); if ( sts == WorkPackage::TS_Send ) { return xi18nc( "@info:tooltip", "Latest work package sent: %1", t ); } if ( sts == WorkPackage::TS_Receive ) { return xi18nc( "@info:tooltip", "Latest work package received: %1", t ); } return xi18nc( "@info:tooltip", "Not available" ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant NodeModel::data( const Node *n, int property, int role ) const { QVariant result; switch ( property ) { // Edited by user case NodeName: result = name( n, role ); break; case NodeType: result = type( n, role ); break; case NodeResponsible: result = leader( n, role ); break; case NodeAllocation: result = allocation( n, role ); break; case NodeEstimateType: result = estimateType( n, role ); break; case NodeEstimateCalendar: result = estimateCalendar( n, role ); break; case NodeEstimate: result = estimate( n, role ); break; case NodeOptimisticRatio: result = optimisticRatio( n, role ); break; case NodePessimisticRatio: result = pessimisticRatio( n, role ); break; case NodeRisk: result = riskType( n, role ); break; case NodeConstraint: result = constraint( n, role ); break; case NodeConstraintStart: result = constraintStartTime( n, role ); break; case NodeConstraintEnd: result = constraintEndTime( n, role ); break; case NodeRunningAccount: result = runningAccount( n, role ); break; case NodeStartupAccount: result = startupAccount( n, role ); break; case NodeStartupCost: result = startupCost( n, role ); break; case NodeShutdownAccount: result = shutdownAccount( n, role ); break; case NodeShutdownCost: result = shutdownCost( n, role ); break; case NodeDescription: result = description( n, role ); break; // Based on edited values case NodeExpected: result = pertExpected( n->estimate(), role ); break; case NodeVarianceEstimate: result = varianceEstimate( n->estimate(), role ); break; case NodeOptimistic: result = optimisticEstimate( n->estimate(), role ); break; case NodePessimistic: result = pessimisticEstimate( n->estimate(), role ); break; // After scheduling case NodeStartTime: result = startTime( n, role ); break; case NodeEndTime: result = endTime( n, role ); break; case NodeEarlyStart: result = earlyStart( n, role ); break; case NodeEarlyFinish: result = earlyFinish( n, role ); break; case NodeLateStart: result = lateStart( n, role ); break; case NodeLateFinish: result = lateFinish( n, role ); break; case NodePositiveFloat: result = positiveFloat( n, role ); break; case NodeFreeFloat: result = freeFloat( n, role ); break; case NodeNegativeFloat: result = negativeFloat( n, role ); break; case NodeStartFloat: result = startFloat( n, role ); break; case NodeFinishFloat: result = finishFloat( n, role ); break; case NodeAssignments: result = assignedResources( n, role ); break; // Based on scheduled values case NodeDuration: result = duration( n, role ); break; case NodeVarianceDuration: result = varianceDuration( n, role ); break; case NodeOptimisticDuration: result = optimisticDuration( n, role ); break; case NodePessimisticDuration: result = pessimisticDuration( n, role ); break; // Completion case NodeStatus: result = status( n, role ); break; case NodeCompleted: result = completed( n, role ); break; case NodePlannedEffort: result = plannedEffortTo( n, role ); break; case NodeActualEffort: result = actualEffortTo( n, role ); break; case NodeRemainingEffort: result = remainingEffort( n, role ); break; case NodePlannedCost: result = plannedCostTo( n, role ); break; case NodeActualCost: result = actualCostTo( n, role ); break; case NodeActualStart: result = startedTime( n, role ); break; case NodeStarted: result = isStarted( n, role ); break; case NodeActualFinish: result = finishedTime( n, role ); break; case NodeFinished: result = isFinished( n, role ); break; case NodeStatusNote: result = note( n, role ); break; // Scheduling errors case NodeSchedulingStatus: result = nodeSchedulingStatus( n, role ); break; case NodeNotScheduled: result = nodeIsNotScheduled( n, role ); break; case NodeAssignmentMissing: result = resourceIsMissing( n, role ); break; case NodeResourceOverbooked: result = resourceIsOverbooked( n, role ); break; case NodeResourceUnavailable: result = resourceIsNotAvailable( n, role ); break; case NodeConstraintsError: result = schedulingConstraintsError( n, role ); break; case NodeEffortNotMet: result = effortNotMet( n, role ); break; case NodeSchedulingError: result = schedulingError( n, role ); break; case NodeWBSCode: result = wbsCode( n, role ); break; case NodeLevel: result = nodeLevel( n, role ); break; // Performance case NodeBCWS: result = nodeBCWS( n, role ); break; case NodeBCWP: result = nodeBCWP( n, role ); break; case NodeACWP: result = nodeACWP( n, role ); break; case NodePerformanceIndex: result = nodePerformanceIndex( n, role ); break; case NodeCritical: result = nodeIsCritical( n, role ); break; case NodeCriticalPath: result = nodeInCriticalPath( n, role ); break; case WPOwnerName: result = wpOwnerName( n, role ); break; case WPTransmitionStatus: result = wpTransmitionStatus( n, role ); break; case WPTransmitionTime: result = wpTransmitionTime( n, role ); break; default: //debugPlan<<"Invalid property number: "<name() ) { return 0; } KUndo2MagicString s = kundo2_i18n( "Modify name" ); switch ( node->type() ) { case Node::Type_Task: s = kundo2_i18n( "Modify task name" ); break; case Node::Type_Milestone: s = kundo2_i18n( "Modify milestone name" ); break; case Node::Type_Summarytask: s = kundo2_i18n( "Modify summarytask name" ); break; case Node::Type_Project: s = kundo2_i18n( "Modify project name" ); break; } return new NodeModifyNameCmd( *node, value.toString(), s ); } } return 0; } KUndo2Command *NodeModel::setLeader( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { if ( value.toString() != node->leader() ) { return new NodeModifyLeaderCmd( *node, value.toString(), kundo2_i18n( "Modify responsible" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setAllocation( Node */*node*/, const QVariant &/*value*/, int /*role*/ ) { return 0; } KUndo2Command *NodeModel::setDescription( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == node->description() ) { return 0; } return new NodeModifyDescriptionCmd( *node, value.toString(), kundo2_i18n( "Modify task description" ) ); } return 0; } KUndo2Command *NodeModel::setType( Node *, const QVariant &, int ) { return 0; } KUndo2Command *NodeModel::setConstraint( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Node::ConstraintType v; QStringList lst = node->constraintList( false ); if ( lst.contains( value.toString() ) ) { v = Node::ConstraintType( lst.indexOf( value.toString() ) ); } else { v = Node::ConstraintType( value.toInt() ); } //debugPlan<constraint() ) { return new NodeModifyConstraintCmd( *node, v, kundo2_i18n( "Modify constraint type" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setConstraintStartTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { QDateTime dt = value.toDateTime(); dt.setTime( QTime( dt.time().hour(), dt.time().minute(), 0 ) ); // reset possible secs/msecs if ( dt != node->constraintStartTime() ) { return new NodeModifyConstraintStartTimeCmd( *node, dt, kundo2_i18n( "Modify constraint start time" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setConstraintEndTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { QDateTime dt = value.toDateTime(); dt.setTime( QTime( dt.time().hour(), dt.time().minute(), 0 ) ); // reset possible secs/msecs if ( dt != node->constraintEndTime() ) { return new NodeModifyConstraintEndTimeCmd( *node, dt, kundo2_i18n( "Modify constraint end time" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setEstimateType( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { Estimate::Type v; QStringList lst = node->estimate()->typeToStringList( false ); if ( lst.contains( value.toString() ) ) { v = Estimate::Type( lst.indexOf( value.toString() ) ); } else { v = Estimate::Type( value.toInt() ); } if ( v != node->estimate()->type() ) { return new ModifyEstimateTypeCmd( *node, node->estimate()->type(), v, kundo2_i18n( "Modify estimate type" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setEstimateCalendar( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { Calendar *c = 0; Calendar *old = node->estimate()->calendar(); if ( value.toInt() > 0 ) { QStringList lst = estimateCalendar( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { c = m_project->calendarByName( lst.at( value.toInt() ) ); } } if ( c != old ) { return new ModifyEstimateCalendarCmd( *node, old, c, kundo2_i18n( "Modify estimate calendar" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setEstimate( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { double d; Duration::Unit unit; if ( value.toList().count() == 2 ) { d = value.toList()[0].toDouble(); unit = static_cast( value.toList()[1].toInt() ); } else if ( value.canConvert() ) { bool ok = Duration::valueFromString( value.toString(), d, unit ); if ( ! ok ) { return 0; } } else { return 0; } //debugPlan<"<estimate()->expectedEstimate() ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Modify estimate" ) ); cmd->addCommand( new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), d ) ); } if ( unit != node->estimate()->unit() ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Modify estimate" ) ); cmd->addCommand( new ModifyEstimateUnitCmd( *node, node->estimate()->unit(), unit ) ); } if ( cmd ) { return cmd; } break; } default: break; } return 0; } KUndo2Command *NodeModel::setOptimisticRatio( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: if ( value.toInt() != node->estimate()->optimisticRatio() ) { return new EstimateModifyOptimisticRatioCmd( *node, node->estimate()->optimisticRatio(), value.toInt(), kundo2_i18n( "Modify optimistic estimate" ) ); } break; default: break; } return 0; } KUndo2Command *NodeModel::setPessimisticRatio( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: if ( value.toInt() != node->estimate()->pessimisticRatio() ) { return new EstimateModifyPessimisticRatioCmd( *node, node->estimate()->pessimisticRatio(), value.toInt(), kundo2_i18n( "Modify pessimistic estimate" ) ); } default: break; } return 0; } KUndo2Command *NodeModel::setRiskType( Node *node, const QVariant &value, int role ) { if ( node->estimate() == 0 ) { return 0; } switch ( role ) { case Qt::EditRole: { int val = 0; QStringList lst = node->estimate()->risktypeToStringList( false ); if ( lst.contains( value.toString() ) ) { val = lst.indexOf( value.toString() ); } else { val = value.toInt(); } if ( val != node->estimate()->risktype() ) { Estimate::Risktype v = Estimate::Risktype( val ); return new EstimateModifyRiskCmd( *node, node->estimate()->risktype(), v, kundo2_i18n( "Modify risk type" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setRunningAccount( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { //debugPlan<name(); QStringList lst = runningAccount( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); Account *old = node->runningAccount(); if ( old != a ) { return new NodeModifyRunningAccountCmd( *node, old, a, kundo2_i18n( "Modify running account" ) ); } } break; } default: break; } return 0; } KUndo2Command *NodeModel::setStartupAccount( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { //debugPlan<name(); QStringList lst = startupAccount( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); Account *old = node->startupAccount(); //debugPlan<<(value.toInt())<<";"<<(lst.at( value.toInt()))<<":"<startupCost() ) { return new NodeModifyStartupCostCmd( *node, v, kundo2_i18n( "Modify startup cost" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setShutdownAccount( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { //debugPlan<name(); QStringList lst = shutdownAccount( node, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); Account *old = node->shutdownAccount(); if ( old != a ) { return new NodeModifyShutdownAccountCmd( *node, old, a, kundo2_i18n( "Modify shutdown account" ) ); } } break; } default: break; } return 0; } KUndo2Command *NodeModel::setShutdownCost( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { double v = value.toDouble(); if ( v != node->shutdownCost() ) { return new NodeModifyShutdownCostCmd( *node, v, kundo2_i18n( "Modify shutdown cost" ) ); } break; } default: break; } return 0; } KUndo2Command *NodeModel::setCompletion( Node */*node*/, const QVariant &/*value*/, int /*role*/ ) { return 0; } KUndo2Command *NodeModel::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 ); return new ModifyCompletionRemainingEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify remaining effort" ) ); } return 0; } KUndo2Command *NodeModel::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 ); return new ModifyCompletionActualEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify actual effort" ) ); } return 0; } KUndo2Command *NodeModel::setStartedTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Task *t = qobject_cast( node ); if ( t == 0 ) { return 0; } MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify actual start time" ) ); 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 ) ); } } return m; } default: break; } return 0; } KUndo2Command *NodeModel::setFinishedTime( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Task *t = qobject_cast( node ); if ( t == 0 ) { return 0; } MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify actual finish time" ) ); if ( ! t->completion().isFinished() ) { m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) ); 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 ) ); } } 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() ) ); } return m; } default: break; } return 0; } //---------------------------- NodeItemModel::NodeItemModel( QObject *parent ) : ItemModelBase( parent ), m_node( 0 ), m_projectshown( false ) { setReadOnly( NodeModel::NodeDescription, true ); } NodeItemModel::~NodeItemModel() { } void NodeItemModel::setShowProject( bool on ) { beginResetModel(); m_projectshown = on; endResetModel(); emit projectShownChanged( on ); } void NodeItemModel::slotNodeToBeInserted( Node *parent, int row ) { //debugPlan<name()<<"; "<parentNode()->name()<<"-->"<name(); Q_ASSERT( node->parentNode() == m_node ); endInsertRows(); m_node = 0; emit nodeInserted( node ); } void NodeItemModel::slotNodeToBeRemoved( Node *node ) { //debugPlan<name(); Q_ASSERT( m_node == 0 ); m_node = node; int row = index( node ).row(); beginRemoveRows( index( node->parentNode() ), row, row ); } void NodeItemModel::slotNodeRemoved( Node *node ) { //debugPlan<name(); Q_ASSERT( node == m_node ); #ifdef NDEBUG Q_UNUSED(node) #endif endRemoveRows(); m_node = 0; } void NodeItemModel::slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos ) { //debugPlan<parentNode()->name()<name()<parentNode() ), pos, pos, index( newParent ), newPos ); } void NodeItemModel::slotNodeMoved( Node *node ) { Q_UNUSED( node ); //debugPlan<parentNode()->name()<parentNode()->indexOf( node ); endMoveRows(); } void NodeItemModel::slotLayoutChanged() { //debugPlan<name(); emit layoutAboutToBeChanged(); emit layoutChanged(); } void NodeItemModel::slotProjectCalculated(ScheduleManager *sm) { debugPlan<allNodes() ) { int row = n->parentNode()->indexOf( n ); QModelIndex idx = createIndex( row, NodeModel::NodeWBSCode, n ); emit dataChanged( idx, idx ); } } void NodeItemModel::setProject( Project *project ) { beginResetModel(); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); + disconnect(m_project, &Project::aboutToBeDeleted, this, &NodeItemModel::projectDeleted); disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged())); - disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged())); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*))); - disconnect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int))); - disconnect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*))); + disconnect( m_project, &Project::wbsDefinitionChanged, this, &NodeItemModel::slotWbsDefinitionChanged); + disconnect( m_project, &Project::nodeChanged, this, &NodeItemModel::slotNodeChanged); + disconnect( m_project, &Project::nodeToBeAdded, this, &NodeItemModel::slotNodeToBeInserted); + disconnect( m_project, &Project::nodeToBeRemoved, this, &NodeItemModel::slotNodeToBeRemoved); - disconnect( m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotNodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int))); - disconnect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*))); + disconnect( m_project, &Project::nodeToBeMoved, this, &NodeItemModel::slotNodeToBeMoved); + disconnect( m_project, &Project::nodeMoved, this, &NodeItemModel::slotNodeMoved); - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*))); - disconnect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*))); - disconnect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*))); + disconnect( m_project, &Project::nodeAdded, this, &NodeItemModel::slotNodeInserted); + disconnect( m_project, &Project::nodeRemoved, this, &NodeItemModel::slotNodeRemoved); + disconnect( m_project, &Project::projectCalculated, this, &NodeItemModel::slotProjectCalculated); } m_project = project; debugPlan<"<isBaselined(); flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; switch ( index.column() ) { case NodeModel::NodeName: // name flags |= Qt::ItemIsEditable; break; case NodeModel::NodeType: break; // Node type case NodeModel::NodeResponsible: // Responsible flags |= Qt::ItemIsEditable; break; case NodeModel::NodeAllocation: // allocation if ( n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeEstimateType: // estimateType { if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeEstimate: // estimate { if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeOptimisticRatio: // optimisticRatio case NodeModel::NodePessimisticRatio: // pessimisticRatio { if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeEstimateCalendar: { if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeRisk: // risktype { if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeConstraint: // constraint type if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeConstraintStart: { // constraint start if ( ! baselined && n->type() == Node::Type_Project ) { flags |= Qt::ItemIsEditable; break; } if ( ! baselined && ! ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { break; } flags |= Qt::ItemIsEditable; break; } case NodeModel::NodeConstraintEnd: { // constraint end if ( ! baselined && n->type() == Node::Type_Project ) { flags |= Qt::ItemIsEditable; break; } if ( ! baselined && ! ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { break; } flags |= Qt::ItemIsEditable; break; } case NodeModel::NodeRunningAccount: // running account if ( ! baselined && n->type() == Node::Type_Task ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeStartupAccount: // startup account case NodeModel::NodeStartupCost: // startup cost case NodeModel::NodeShutdownAccount: // shutdown account case NodeModel::NodeShutdownCost: { // shutdown cost if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeDescription: // description flags |= Qt::ItemIsEditable; break; default: break; } Task *t = static_cast( n ); if ( manager() && t->isScheduled( id() ) ) { if ( ! t->completion().isStarted() ) { switch ( index.column() ) { case NodeModel::NodeActualStart: flags |= Qt::ItemIsEditable; break; case NodeModel::NodeActualFinish: if ( t->type() == Node::Type_Milestone ) { flags |= Qt::ItemIsEditable; } break; case NodeModel::NodeCompleted: if ( t->state() & Node::State_ReadyToStart ) { flags |= Qt::ItemIsEditable; } break; default: break; } } else if ( ! t->completion().isFinished() ) { switch ( index.column() ) { case NodeModel::NodeActualFinish: case NodeModel::NodeCompleted: case NodeModel::NodeRemainingEffort: flags |= Qt::ItemIsEditable; break; case NodeModel::NodeActualEffort: if ( t->completion().entrymode() == Completion::EnterEffortPerTask || t->completion().entrymode() == Completion::EnterEffortPerResource ) { flags |= Qt::ItemIsEditable; } break; default: break; } } } } return flags; } QModelIndex NodeItemModel::parent( const QModelIndex &index ) const { if ( ! index.isValid() ) { return QModelIndex(); } Node *n = node( index ); if ( n == 0 || n == m_project ) { return QModelIndex(); } Node *p = n->parentNode(); if ( p == m_project ) { return m_projectshown ? createIndex( 0, 0, p ) : QModelIndex(); } int row = p->parentNode()->indexOf( p ); if ( row == -1 ) { return QModelIndex(); } return createIndex( row, 0, p ); } QModelIndex NodeItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( parent.isValid() ) { Q_ASSERT( parent.model() == this ); } //debugPlan<= columnCount() || row < 0 ) { //debugPlan<= p->numChildren() ) { errorPlan<name()<<" row too high"<childNode( row ); QModelIndex idx = createIndex(row, column, n); //debugPlan<parentNode(); if ( par ) { //debugPlan<"<indexOf( node ), column, const_cast(node) ); } if ( m_projectshown && node == m_project ) { return createIndex( 0, column, m_project ); } //debugPlan<( node ); if ( task == 0 ) { return false; } switch ( role ) { case Qt::EditRole: { MacroCommand *cmd = 0; QStringList res = m_project->resourceNameList(); QStringList req = node->requestNameList(); QStringList alloc; foreach ( const QString &s, value.toString().split( QRegExp(" *, *"), QString::SkipEmptyParts ) ) { alloc << s.trimmed(); } // first add all new resources (to "default" group) ResourceGroup *pargr = m_project->groupByName( i18n( "Resources" ) ); foreach ( const QString &s, alloc ) { Resource *r = m_project->resourceByName( s.trimmed() ); if ( r != 0 ) { continue; } if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Add resource" ) ); if ( pargr == 0 ) { pargr = new ResourceGroup(); pargr->setName( i18n( "Resources" ) ); cmd->addCommand( new AddResourceGroupCmd( m_project, pargr ) ); //debugPlan<<"add group:"<name(); } r = new Resource(); r->setName( s.trimmed() ); cmd->addCommand( new AddResourceCmd( pargr, r ) ); //debugPlan<<"add resource:"<name(); emit executeCommand( cmd ); cmd = 0; } KUndo2MagicString c = kundo2_i18n( "Modify resource allocations" ); // Handle deleted requests foreach ( const QString &s, req ) { // if a request is not in alloc, it must have been be removed by the user if ( alloc.indexOf( s ) == -1 ) { // remove removed resource request ResourceRequest *r = node->resourceRequest( s ); if ( r ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); //debugPlan<<"delete request:"<resource()->name()<<" group:"<parent()->group()->name(); cmd->addCommand( new RemoveResourceRequestCmd( r->parent(), r ) ); } } } // Handle new requests QHash groupmap; foreach ( const QString &s, alloc ) { // if an allocation is not in req, it must be added if ( req.indexOf( s ) == -1 ) { ResourceGroup *pargr = 0; Resource *r = m_project->resourceByName( s ); if ( r == 0 ) { // Handle request to non existing resource pargr = m_project->groupByName( i18n( "Resources" ) ); if ( pargr == 0 ) { pargr = new ResourceGroup(); pargr->setName( i18n( "Resources" ) ); cmd->addCommand( new AddResourceGroupCmd( m_project, pargr ) ); //debugPlan<<"add group:"<name(); } r = new Resource(); r->setName( s ); cmd->addCommand( new AddResourceCmd( pargr, r ) ); //debugPlan<<"add resource:"<name(); emit executeCommand( cmd ); cmd = 0; } else { pargr = r->parentGroup(); //debugPlan<<"add '"<name()<<"' to group:"<resourceGroupRequest( pargr ); if ( g == 0 ) { g = groupmap.value( pargr ); } if ( g == 0 ) { // create a group request if ( cmd == 0 ) cmd = new MacroCommand( c ); g = new ResourceGroupRequest( pargr ); cmd->addCommand( new AddResourceGroupRequestCmd( *task, g ) ); groupmap.insert( pargr, g ); //debugPlan<<"add group request:"<addCommand( new AddResourceRequestCmd( g, new ResourceRequest( r, r->units() ) ) ); //debugPlan<<"add request:"<name()<<" group:"<name()<type() == Node::Type_Task ) { Completion &c = static_cast( node )->completion(); QDateTime dt = QDateTime::currentDateTime(); QDate date = dt.date(); MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify completion" ) ); if ( ! c.isStarted() ) { m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionStartedCmd( c, true ) ); } m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, value.toInt() ) ); if ( value.toInt() == 100 ) { m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionFinishedCmd( c, true ) ); } emit executeCommand( m ); // also adds a new entry if necessary if ( c.entrymode() == Completion::EnterCompleted ) { Duration planned = static_cast( node )->plannedEffort( m_nodemodel.id() ); Duration actual = ( planned * value.toInt() ) / 100; debugPlan<execute(); m->addCommand( cmd ); cmd = new ModifyCompletionRemainingEffortCmd( c, date, planned - actual ); 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 ModifyCompletionStartTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionStartedCmd( c, true ) ); m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) ); m->addCommand( new ModifyCompletionFinishedCmd( c, true ) ); m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, 100 ) ); emit executeCommand( m ); // also adds a new entry if necessary return true; } return false; } return false; } QVariant NodeItemModel::data( const QModelIndex &index, int role ) const { if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } Node *n = node( index ); if ( role == Role::Object ) { return n ? QVariant::fromValue( static_cast( n ) ) : QVariant(); } QVariant result; if ( n != 0 ) { result = m_nodemodel.data( n, index.column(), role ); //debugPlan<name()<<": "<numChildren(); } Qt::DropActions NodeItemModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList NodeItemModel::mimeTypes() const { return QStringList() << "application/x-vnd.kde.plan.nodeitemmodel.internal" << "application/x-vnd.kde.plan.resourceitemmodel.internal" << "application/x-vnd.kde.plan.project" << "text/uri-list"; } QMimeData *NodeItemModel::mimeData( const QModelIndexList & indexes ) const { QMimeData *m = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QList rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<id(); } } } m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData); return m; } bool NodeItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ) { debugPlan; if ( m_projectshown && ! index.isValid() ) { return false; } Node *dn = node( index ); // returns project if ! index.isValid() if ( dn == 0 ) { errorPlan<<"no node (or project) to drop on!"; return false; // hmmm } if ( data->hasFormat("application/x-vnd.kde.plan.resourceitemmodel.internal") ) { switch ( dropIndicatorPosition ) { case ItemModelBase::OnItem: if ( index.column() == NodeModel::NodeAllocation ) { debugPlan<<"resource:"<type() == Node::Type_Task); return dn->type() == Node::Type_Task; } else if ( index.column() == NodeModel::NodeResponsible ) { debugPlan<<"resource:"<hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal") || data->hasFormat( "application/x-vnd.kde.plan.project" ) || data->hasUrls() ) { switch ( dropIndicatorPosition ) { case ItemModelBase::AboveItem: case ItemModelBase::BelowItem: // dn == sibling, if not project if ( dn == m_project ) { return dropAllowed( dn, data ); } return dropAllowed( dn->parentNode(), data ); case ItemModelBase::OnItem: // dn == new parent return dropAllowed( dn, data ); default: break; } } else { debugPlan<<"Unknown mimetype"; } return false; } QList NodeItemModel::resourceList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; debugPlan<<"id"<findResource( id ); if ( r ) { lst << r; } } debugPlan<isBaselined() && on->type() != Node::Type_Summarytask ) { return false; } if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) { QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList lst = nodeList( stream ); foreach ( Node *n, lst ) { if ( n->type() == Node::Type_Project || on == n || on->isChildOf( n ) ) { return false; } } lst = removeChildNodes( lst ); foreach ( Node *n, lst ) { if ( ! m_project->canMoveTask( n, on ) ) { return false; } } } return true; } QList NodeItemModel::nodeList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Node *node = m_project->findNode( id ); if ( node ) { lst << node; } } return lst; } QList NodeItemModel::removeChildNodes( const QList &nodes ) { QList lst; foreach ( Node *node, nodes ) { bool ins = true; foreach ( Node *n, lst ) { if ( node->isChildOf( n ) ) { //debugPlan<name()<<" is child of"<name(); ins = false; break; } } if ( ins ) { //debugPlan<<" insert"<name(); lst << node; } } QList nl = lst; QList nlst = lst; foreach ( Node *node, nl ) { foreach ( Node *n, nlst ) { if ( n->isChildOf( node ) ) { //debugPlan<name()<<" is child of"<name(); int i = nodes.indexOf( n ); lst.removeAt( i ); } } } return lst; } bool NodeItemModel::dropResourceMimeData( const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent ) { QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Node *n = node( parent ); debugPlan<name(); if ( parent.column() == NodeModel::NodeResponsible ) { QString s; foreach ( Resource *r, resourceList( stream ) ) { s += r->name(); } if ( ! s.isEmpty() ) { if ( action == Qt::CopyAction && ! n->leader().isEmpty() ) { s += ',' + n->leader(); } KUndo2Command *cmd = m_nodemodel.setLeader( n, s, Qt::EditRole ); if ( cmd ) { emit executeCommand( cmd ); } debugPlan<type() == Node::Type_Task ) { QList lst = resourceList( stream ); if ( action == Qt::CopyAction ) { lst += static_cast( n )->requestedResources(); } KUndo2Command *cmd = createAllocationCommand( static_cast( *n ), lst ); if ( cmd ) { emit executeCommand( cmd ); } return true; } return true; } bool NodeItemModel::dropProjectMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent ) { Node *n = node( parent ); if ( n == 0 ) { n = m_project; } debugPlan<data( "application/x-vnd.kde.plan.project" ) ); KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement(); Project project; XMLLoaderObject status; status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) ); status.setProject( &project ); if ( ! project.load( element, status ) ) { debugPlan<<"Failed to load project"; return false; } project.generateUniqueNodeIds(); KUndo2Command *cmd = new InsertProjectCmd( project, n, n->childNode( row - 1 ), kundo2_i18nc("1=project or task name", "Insert %1", project.name() ) ); emit executeCommand( cmd ); return true; } bool NodeItemModel::dropUrlMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ) { if ( data->hasUrls() ) { QList urls = data->urls(); debugPlan<bad() ) { // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file ); debugPlan<<"bad store"<open( "root" ) ) { // maindoc.xml debugPlan<<"No root"<device() ); KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement(); Project project; XMLLoaderObject status; status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) ); status.setProject( &project ); if ( ! project.load( element, status ) ) { debugPlan<<"Failed to load project from:"<childNode( row - 1 ), kundo2_i18n( "Insert %1", url.fileName() ) ); emit executeCommand( cmd ); return true; } KUndo2Command *NodeItemModel::createAllocationCommand( Task &task, const QList &lst ) { MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Modify resource allocations" ) ); QHash groups; foreach ( Resource *r, lst ) { if ( ! groups.contains( r->parentGroup() ) && task.resourceGroupRequest( r->parentGroup() ) == 0 ) { ResourceGroupRequest *gr = new ResourceGroupRequest( r->parentGroup() ); groups[ r->parentGroup() ] = gr; cmd->addCommand( new AddResourceGroupRequestCmd( task, gr ) ); } } QList resources = task.requestedResources(); foreach ( Resource *r, lst ) { if ( resources.contains( r ) ) { continue; } ResourceGroupRequest *gr = groups.value( r->parentGroup() ); if ( gr == 0 ) { gr = task.resourceGroupRequest( r->parentGroup() ); } if ( gr == 0 ) { errorPlan<<"No group request found, cannot add resource request:"<name(); continue; } cmd->addCommand( new AddResourceRequestCmd( gr, new ResourceRequest( r, 100 ) ) ); } foreach ( Resource *r, resources ) { if ( ! lst.contains( r ) ) { ResourceGroupRequest *gr = task.resourceGroupRequest( r->parentGroup() ); ResourceRequest *rr = task.requests().find( r ); if ( gr && rr ) { cmd->addCommand( new RemoveResourceRequestCmd( gr, rr ) ); } } } if ( cmd->isEmpty() ) { delete cmd; return 0; } return cmd; } bool NodeItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ) { debugPlan<hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) { return dropResourceMimeData( data, action, row, column, parent ); } if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) { if ( action == Qt::MoveAction ) { //debugPlan<<"MoveAction"; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Node *par = 0; if ( parent.isValid() ) { par = node( parent ); } else { par = m_project; } QList lst = nodeList( stream ); QList nodes = removeChildNodes( lst ); // children goes with their parent foreach ( Node *n, nodes ) { if ( ! m_project->canMoveTask( n, par ) ) { //debugPlan<<"Can't move task:"<name(); return false; } } int offset = 0; MacroCommand *cmd = 0; foreach ( Node *n, nodes ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move tasks" ) ); // append nodes if dropped *on* another node, insert if dropped *after* int pos = row == -1 ? -1 : row + offset; if ( pos >= 0 && n->parentNode() == par && par->indexOf( n ) < pos ) { --pos; } if ( n->parentNode() == par ) { // avoid drop into the same position, QAbstractItemModel does not like it int crow = par->indexOf( n ); if ( ( ( pos == -1 ) && ( crow == par->numChildren() - 1 ) ) || ( pos == crow ) ) { delete cmd; cmd = 0; continue; } } cmd->addCommand( new NodeMoveCmd( m_project, n, par, pos ) ); offset++; } if ( cmd ) { emit executeCommand( cmd ); } //debugPlan<name(); return true; } } if ( data->hasFormat( "application/x-vnd.kde.plan.project" ) ) { debugPlan; return dropProjectMimeData( data, action, row, column, parent ); } if ( data->hasUrls() ) { return dropUrlMimeData( data, action, row, column, parent ); } return false; } Node *NodeItemModel::node( const QModelIndex &index ) const { Node *n = m_project; if ( index.isValid() ) { //debugPlan<( index.internalPointer() ); Q_ASSERT( n ); } return n; } void NodeItemModel::slotNodeChanged( Node *node ) { if ( node == 0 || ( ! m_projectshown && node->type() == Node::Type_Project ) ) { return; } if ( node->type() == Node::Type_Project ) { emit dataChanged( createIndex( 0, 0, node ), createIndex( 0, columnCount()-1, node ) ); return; } int row = node->parentNode()->findChildNode( node ); Q_ASSERT( row >= 0 ); emit dataChanged( createIndex( row, 0, node ), createIndex( row, columnCount()-1, node ) ); } QModelIndex NodeItemModel::insertTask( Node *node, Node *after ) { MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Add task" ) ); cmd->addCommand( new TaskAddCmd( m_project, node, after ) ); if ( m_project && node->type() == Node::Type_Task ) { QHash groups; foreach ( Resource *r, m_project->autoAllocateResources() ) { if ( ! groups.contains( r->parentGroup() ) ) { ResourceGroupRequest *gr = new ResourceGroupRequest( r->parentGroup() ); cmd->addCommand( new AddResourceGroupRequestCmd( static_cast(*node), gr ) ); groups[ r->parentGroup() ] = gr; } ResourceRequest *rr = new ResourceRequest( r, 100 ); cmd->addCommand( new AddResourceRequestCmd( groups[ r->parentGroup() ], rr ) ); } } emit executeCommand( cmd ); int row = -1; if ( node->parentNode() ) { row = node->parentNode()->indexOf( node ); } if ( row != -1 ) { //debugPlan<<"Inserted: "<name()<<"; "<name(); return QModelIndex(); } QModelIndex NodeItemModel::insertSubtask( Node *node, Node *parent ) { emit executeCommand( new SubtaskAddCmd( m_project, node, parent, kundo2_i18n( "Add sub-task" ) ) ); int row = -1; if ( node->parentNode() ) { row = node->parentNode()->indexOf( node ); } if ( row != -1 ) { //debugPlan<parentNode()<<" inserted: "<name()<<"; "<name(); return QModelIndex(); } int NodeItemModel::sortRole( int column ) const { int v = Qt::DisplayRole; switch ( column ) { case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: case NodeModel::NodeActualStart: case NodeModel::NodeActualFinish: case NodeModel::NodeEarlyStart: case NodeModel::NodeEarlyFinish: case NodeModel::NodeLateStart: case NodeModel::NodeLateFinish: case NodeModel::NodeConstraintStart: case NodeModel::NodeConstraintEnd: v = Qt::EditRole; break; case NodeModel::NodeWBSCode: v = NodeModel::SortableRole; break; default: break; } debugPlan< lst = parentmap.values(); while ( ! lst.isEmpty() ) delete (int*)(lst.takeFirst()); } int GanttItemModel::rowCount( const QModelIndex &parent ) const { if ( m_showSpecial ) { if (parentmap.values().contains(parent.internalPointer())) { // clazy:exclude=container-anti-pattern return 0; } Node *n = node( parent ); if ( n && n->type() == Node::Type_Task ) { return 5; // the task + early start + late finish ++ } } return NodeItemModel::rowCount( parent ); } QModelIndex GanttItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_showSpecial && parent.isValid() ) { Node *p = node( parent ); if ( p->type() == Node::Type_Task ) { void *v = 0; foreach ( void *i, parentmap.values( p ) ) { // clazy:exclude=container-anti-pattern if ( *( (int*)( i ) ) == row ) { v = i; break; } } if ( v == 0 ) { v = new int( row ); const_cast( this )->parentmap.insertMulti( p, v ); } return createIndex( row, column, v ); } } return NodeItemModel::index( row, column, parent ); } QModelIndex GanttItemModel::parent( const QModelIndex &idx ) const { if ( m_showSpecial ) { QList lst = parentmap.keys( idx.internalPointer() ); if ( ! lst.isEmpty() ) { Q_ASSERT( lst.count() == 1 ); return index( lst.first() ); } } return NodeItemModel::parent( idx ); } QVariant GanttItemModel::data( const QModelIndex &index, int role ) const { if ( ! index.isValid() ) { return QVariant(); } if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } QModelIndex idx = index; QList lst; if ( m_showSpecial ) { lst = parentmap.keys( idx.internalPointer() ); } if ( ! lst.isEmpty() ) { Q_ASSERT( lst.count() == 1 ); int row = *((int*)(idx.internalPointer())); Node *n = lst.first(); if ( role == SpecialItemTypeRole ) { return row; // 0=task, 1=early start, 2=late finish... } switch ( row ) { case 0: // the task if ( idx.column() == NodeModel::NodeType && role == KGantt::ItemTypeRole ) { switch ( n->type() ) { case Node::Type_Task: return KGantt::TypeTask; default: break; } } break; case 1: { // early start if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Early Start"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->earlyStart( id() ); default: break; } return QVariant(); } case 2: { // late finish if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Late Finish"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->lateFinish( id() ); default: break; } return QVariant(); } case 3: { // late start if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Late Start"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->lateStart( id() ); default: break; } return QVariant(); } case 4: { // early finish if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KGantt::ItemTypeRole ) { return QVariant(); } switch ( idx.column() ) { case NodeModel::NodeName: return "Early Finish"; case NodeModel::NodeType: return KGantt::TypeEvent; case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: return n->earlyFinish( id() ); default: break; } return QVariant(); } default: return QVariant(); } idx = createIndex( idx.row(), idx.column(), n ); } else { if ( role == SpecialItemTypeRole ) { return 0; // task of some type } if ( idx.column() == NodeModel::NodeType && role == KGantt::ItemTypeRole ) { QModelIndex notScheduled = idx.sibling(idx.row(), NodeModel::NodeNotScheduled); if (notScheduled.data(Qt::EditRole).toBool()) { return QVariant(); } QVariant result = NodeItemModel::data( idx, Qt::EditRole ); switch ( result.toInt() ) { case Node::Type_Project: return KGantt::TypeSummary; case Node::Type_Summarytask: return KGantt::TypeSummary; case Node::Type_Milestone: return KGantt::TypeEvent; default: return m_showSpecial ? KGantt::TypeMulti : KGantt::TypeTask; } } } return NodeItemModel::data( idx, role ); } //---------------------------- MilestoneItemModel::MilestoneItemModel( QObject *parent ) : ItemModelBase( parent ) { } MilestoneItemModel::~MilestoneItemModel() { } QList MilestoneItemModel::mileStones() const { QList lst; foreach( Node* n, m_nodemap ) { if ( n->type() == Node::Type_Milestone ) { lst << n; } } return lst; } void MilestoneItemModel::slotNodeToBeInserted( Node *parent, int row ) { Q_UNUSED(parent); Q_UNUSED(row); } void MilestoneItemModel::slotNodeInserted( Node *node ) { Q_UNUSED(node); resetModel(); } void MilestoneItemModel::slotNodeToBeRemoved( Node *node ) { Q_UNUSED(node); //debugPlan<name(); /* int row = m_nodemap.values().indexOf( node ); if ( row != -1 ) { Q_ASSERT( m_nodemap.contains( node->wbsCode() ) ); Q_ASSERT( m_nodemap.keys().indexOf( node->wbsCode() ) == row ); beginRemoveRows( QModelIndex(), row, row ); m_nodemap.remove( node->wbsCode() ); endRemoveRows(); }*/ } void MilestoneItemModel::slotNodeRemoved( Node *node ) { Q_UNUSED(node); resetModel(); //endRemoveRows(); } void MilestoneItemModel::slotLayoutChanged() { //debugPlan<name(); emit layoutAboutToBeChanged(); emit layoutChanged(); } void MilestoneItemModel::slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos ) { Q_UNUSED( node ); Q_UNUSED( pos ); Q_UNUSED( newParent ); Q_UNUSED( newPos ); } void MilestoneItemModel::slotNodeMoved( Node *node ) { Q_UNUSED( node ); resetModel(); } void MilestoneItemModel::setProject( Project *project ) { if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); + disconnect(m_project, &Project::aboutToBeDeleted, this, &MilestoneItemModel::projectDeleted); disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged())); - disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged())); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*))); - disconnect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int))); - disconnect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*))); + disconnect( m_project, &Project::wbsDefinitionChanged, this, &MilestoneItemModel::slotWbsDefinitionChanged); + disconnect( m_project, &Project::nodeChanged, this, &MilestoneItemModel::slotNodeChanged); + disconnect( m_project, &Project::nodeToBeAdded, this, &MilestoneItemModel::slotNodeToBeInserted); + disconnect( m_project, &Project::nodeToBeRemoved, this, &MilestoneItemModel::slotNodeToBeRemoved); - disconnect(m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotNodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int))); - disconnect(m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*))); + disconnect(m_project, &Project::nodeToBeMoved, this, &MilestoneItemModel::slotNodeToBeMoved); + disconnect(m_project, &Project::nodeMoved, this, &MilestoneItemModel::slotNodeMoved); - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*))); - disconnect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*))); + disconnect( m_project, &Project::nodeAdded, this, &MilestoneItemModel::slotNodeInserted); + disconnect( m_project, &Project::nodeRemoved, this, &MilestoneItemModel::slotNodeRemoved); } m_project = project; //debugPlan<"<allNodes() ) { m_nodemap.insert( n->wbsCode(true), n ); } } return cnt != m_nodemap.count(); } void MilestoneItemModel::resetModel() { beginResetModel(); resetData(); endResetModel(); } Qt::ItemFlags MilestoneItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = QAbstractItemModel::flags( index ); if ( !index.isValid() ) { if ( m_readWrite ) { flags |= Qt::ItemIsDropEnabled; } return flags; } if ( m_readWrite ) { flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; switch ( index.column() ) { case NodeModel::NodeName: // name flags |= Qt::ItemIsEditable; break; case NodeModel::NodeType: break; // Node type case NodeModel::NodeResponsible: // Responsible flags |= Qt::ItemIsEditable; break; case NodeModel::NodeConstraint: // constraint type flags |= Qt::ItemIsEditable; break; case NodeModel::NodeConstraintStart: { // constraint start Node *n = node( index ); if ( n == 0 ) break; int c = n->constraint(); if ( c == Node::MustStartOn || c == Node::StartNotEarlier || c == Node::FixedInterval ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeConstraintEnd: { // constraint end Node *n = node( index ); if ( n == 0 ) break; int c = n->constraint(); if ( c == Node::MustFinishOn || c == Node::FinishNotLater || c == Node::FixedInterval ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeStartupAccount: // startup account case NodeModel::NodeStartupCost: // startup cost case NodeModel::NodeShutdownAccount: // shutdown account case NodeModel::NodeShutdownCost: { // shutdown cost Node *n = node( index ); if ( n && (n->type() == Node::Type_Task || n->type() == Node::Type_Milestone) ) { flags |= Qt::ItemIsEditable; } break; } case NodeModel::NodeDescription: // description break; default: flags &= ~Qt::ItemIsEditable; } } return flags; } QModelIndex MilestoneItemModel::parent( const QModelIndex &index ) const { Q_UNUSED(index); return QModelIndex(); } QModelIndex MilestoneItemModel::index( int row, int column, const QModelIndex &parent ) const { //debugPlan<= m_nodemap.count() ) { //debugPlan<<"No index for"<( node ) ), 0, const_cast(node) ); // clazy:exclude=container-anti-pattern } QVariant MilestoneItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } Node *n = node( index ); if ( n != 0 ) { if ( index.column() == NodeModel::NodeType && role == KGantt::ItemTypeRole ) { result = m_nodemodel.data( n, index.column(), Qt::EditRole ); switch ( result.toInt() ) { case Node::Type_Summarytask: return KGantt::TypeSummary; case Node::Type_Milestone: return KGantt::TypeEvent; default: return KGantt::TypeTask; } return result; } } result = m_nodemodel.data( n, index.column(), role ); return result; } bool MilestoneItemModel::setData( const QModelIndex &index, const QVariant &/*value*/, int role ) { if ( ( flags(index) &Qt::ItemIsEditable ) == 0 || role != Qt::EditRole ) { return false; } // Node *n = node( index ); switch (index.column()) { default: qWarning("data: invalid display value column %d", index.column()); return false; } return false; } QVariant MilestoneItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if (role == Qt::DisplayRole || role == Qt::TextAlignmentRole || role == Qt::EditRole) { return m_nodemodel.headerData(section, role); } } if ( role == Qt::ToolTipRole ) { return NodeModel::headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QAbstractItemDelegate *MilestoneItemModel::createDelegate( int column, QWidget *parent ) const { switch ( column ) { case NodeModel::NodeEstimateType: return new EnumDelegate( parent ); case NodeModel::NodeEstimateCalendar: return new EnumDelegate( parent ); case NodeModel::NodeEstimate: return new DurationSpinBoxDelegate( parent ); case NodeModel::NodeOptimisticRatio: return new SpinBoxDelegate( parent ); case NodeModel::NodePessimisticRatio: return new SpinBoxDelegate( parent ); case NodeModel::NodeRisk: return new EnumDelegate( parent ); case NodeModel::NodeConstraint: return new EnumDelegate( parent ); case NodeModel::NodeRunningAccount: return new EnumDelegate( parent ); case NodeModel::NodeStartupAccount: return new EnumDelegate( parent ); case NodeModel::NodeStartupCost: return new MoneyDelegate( parent ); case NodeModel::NodeShutdownAccount: return new EnumDelegate( parent ); case NodeModel::NodeShutdownCost: return new MoneyDelegate( parent ); case NodeModel::NodeCompleted: return new TaskCompleteDelegate( parent ); case NodeModel::NodeRemainingEffort: return new DurationSpinBoxDelegate( parent ); case NodeModel::NodeActualEffort: return new DurationSpinBoxDelegate( parent ); default: return 0; } return 0; } int MilestoneItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_nodemodel.propertyCount(); } int MilestoneItemModel::rowCount( const QModelIndex &parent ) const { //debugPlan< rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<id(); } } } m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData); return m; } bool MilestoneItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ) { //debugPlan; Node *dn = node( index ); if ( dn == 0 ) { errorPlan<<"no node to drop on!"; return false; // hmmm } switch ( dropIndicatorPosition ) { case ItemModelBase::AboveItem: case ItemModelBase::BelowItem: // dn == sibling return dropAllowed( dn->parentNode(), data ); case ItemModelBase::OnItem: // dn == new parent return dropAllowed( dn, data ); default: break; } return false; } bool MilestoneItemModel::dropAllowed( Node *on, const QMimeData *data ) { if ( !data->hasFormat("application/x-vnd.kde.plan.nodeitemmodel.internal") ) { return false; } if ( on == m_project ) { return true; } QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); QList lst = nodeList( stream ); foreach ( Node *n, lst ) { if ( on == n || on->isChildOf( n ) ) { return false; } } lst = removeChildNodes( lst ); foreach ( Node *n, lst ) { if ( ! m_project->canMoveTask( n, on ) ) { return false; } } return true; } QList MilestoneItemModel::nodeList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Node *node = m_project->findNode( id ); if ( node ) { lst << node; } } return lst; } QList MilestoneItemModel::removeChildNodes( const QList &nodes ) { QList lst; foreach ( Node *node, nodes ) { bool ins = true; foreach ( Node *n, lst ) { if ( node->isChildOf( n ) ) { //debugPlan<name()<<" is child of"<name(); ins = false; break; } } if ( ins ) { //debugPlan<<" insert"<name(); lst << node; } } QList nl = lst; QList nlst = lst; foreach ( Node *node, nl ) { foreach ( Node *n, nlst ) { if ( n->isChildOf( node ) ) { //debugPlan<name()<<" is child of"<name(); int i = nodes.indexOf( n ); lst.removeAt( i ); } } } return lst; } bool MilestoneItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent ) { //debugPlan<hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) { return false; } if ( action == Qt::MoveAction ) { //debugPlan<<"MoveAction"; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); Node *par = 0; if ( parent.isValid() ) { par = node( parent ); } else { par = m_project; } QList lst = nodeList( stream ); QList nodes = removeChildNodes( lst ); // children goes with their parent foreach ( Node *n, nodes ) { if ( ! m_project->canMoveTask( n, par ) ) { //debugPlan<<"Can't move task:"<name(); return false; } } int offset = 0; MacroCommand *cmd = 0; foreach ( Node *n, nodes ) { if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move tasks" ) ); // append nodes if dropped *on* another node, insert if dropped *after* int pos = row == -1 ? -1 : row + offset; cmd->addCommand( new NodeMoveCmd( m_project, n, par, pos ) ); offset++; } if ( cmd ) { emit executeCommand( cmd ); } //debugPlan<name(); return true; } return false; } Node *MilestoneItemModel::node( const QModelIndex &index ) const { Node *n = 0; if ( index.isValid() ) { //debugPlan<( index.internalPointer() ); } return n; } void MilestoneItemModel::slotNodeChanged( Node *node ) { //debugPlan<name(); if ( node == 0 ) { return; } beginResetModel(); resetData(); endResetModel(); } void MilestoneItemModel::slotWbsDefinitionChanged() { //debugPlan; if ( m_project == 0 ) { return; } if ( ! m_nodemap.isEmpty() ) { beginResetModel(); resetData(); endResetModel(); } } int MilestoneItemModel::sortRole( int column ) const { int v = Qt::DisplayRole; switch ( column ) { case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: case NodeModel::NodeActualStart: case NodeModel::NodeActualFinish: case NodeModel::NodeEarlyStart: case NodeModel::NodeEarlyFinish: case NodeModel::NodeLateStart: case NodeModel::NodeLateFinish: case NodeModel::NodeConstraintStart: case NodeModel::NodeConstraintEnd: v = Qt::EditRole; break; case NodeModel::NodeWBSCode: v = NodeModel::SortableRole; break; default: break; } return v; } //-------------- NodeSortFilterProxyModel::NodeSortFilterProxyModel( ItemModelBase* model, QObject *parent, bool filterUnscheduled ) : QSortFilterProxyModel( parent ), m_filterUnscheduled( filterUnscheduled ) { setSourceModel( model ); setDynamicSortFilter( true ); } ItemModelBase *NodeSortFilterProxyModel::itemModel() const { return static_cast( sourceModel() ); } void NodeSortFilterProxyModel::setFilterUnscheduled( bool on ) { m_filterUnscheduled = on; invalidateFilter(); } bool NodeSortFilterProxyModel::filterAcceptsRow ( int row, const QModelIndex & parent ) const { //debugPlan<project() == 0 ) { //debugPlan<project(); return false; } if ( m_filterUnscheduled ) { QString s = sourceModel()->data( sourceModel()->index( row, NodeModel::NodeNotScheduled, parent ), Qt::EditRole ).toString(); if ( s == "true" ) { //debugPlan<<"Filtered unscheduled:"<index( row, 0, parent ); return false; } } bool accepted = QSortFilterProxyModel::filterAcceptsRow( row, parent ); //debugPlan<index( row, 0, parent )<<"accepted ="<sortRole(column)); QSortFilterProxyModel::sort(column, order); } //------------------ TaskModuleModel::TaskModuleModel( QObject *parent ) : QAbstractItemModel( parent ) { } void TaskModuleModel::addTaskModule( Project *project, const QUrl &url ) { beginInsertRows( QModelIndex(), m_modules.count(), m_modules.count() ); m_modules << project; m_urls << url; endInsertRows(); } Qt::ItemFlags TaskModuleModel::flags( const QModelIndex &idx ) const { Qt::ItemFlags f = QAbstractItemModel::flags( idx ) | Qt::ItemIsDropEnabled; if ( idx.isValid() ) { f |= Qt::ItemIsDragEnabled; } return f; } int TaskModuleModel::columnCount (const QModelIndex &/*idx*/ ) const { return 1; } int TaskModuleModel::rowCount( const QModelIndex &idx ) const { return idx.isValid() ? 0 : m_modules.count(); } QVariant TaskModuleModel::data( const QModelIndex& idx, int role ) const { if (!idx.isValid() || idx.row() >= m_modules.count()) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: return m_modules.value( idx.row() )->name(); case Qt::ToolTipRole: return m_modules.value( idx.row() )->description(); case Qt::WhatsThisRole: return m_modules.value( idx.row() )->description(); case Qt::UserRole: return m_urls.value(idx.row()); default: break; } return QVariant(); } QVariant TaskModuleModel::headerData( int /*section*/, Qt::Orientation orientation , int role ) const { if ( orientation == Qt::Horizontal ) { switch ( role ) { case Qt::DisplayRole: return xi18nc( "@title:column", "Name" ); default: break; } } return QVariant(); } QModelIndex TaskModuleModel::parent( const QModelIndex& /*idx*/ ) const { return QModelIndex(); } QModelIndex TaskModuleModel::index( int row, int column, const QModelIndex &parent ) const { if ( parent.isValid() ) { return QModelIndex(); } return createIndex( row, column, m_modules.value( row ) ); } QStringList TaskModuleModel::mimeTypes() const { return QStringList() << "application/x-vnd.kde.plan" << "text/uri-list"; } bool TaskModuleModel::dropMimeData( const QMimeData *data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex &/*parent*/ ) { if ( data->hasUrls() ) { QList urls = data->urls(); debugPlan<bad() ) { // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file ); debugPlan<<"bad store"<open( "root" ) ) { // maindoc.xml debugPlan<<"No root"<device() ); KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement(); Project *project = new Project(); XMLLoaderObject status; status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) ); status.setProject( project ); if ( project->load( element, status ) ) { stripProject( project ); addTaskModule( project, url ); if ( emitsignal ) { // FIXME: save destroys the project, so give it a copy (see kptview.cpp) Project p; status.setProject( &p ); p.load( element, status ); emit saveTaskModule( url, &p ); } } else { debugPlan<<"Failed to load project from:"<save( doc ); mime->setData( "application/x-vnd.kde.plan.project", document.toByteArray() ); } } return mime; } void TaskModuleModel::stripProject( Project *project ) const { foreach ( ScheduleManager *sm, project->scheduleManagers() ) { DeleteScheduleManagerCmd c( *project, sm ); } } void TaskModuleModel::loadTaskModules( const QStringList &files ) { debugPlan< 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 "kptpertcpmmodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptproject.h" #include "kpttask.h" #include "kptnode.h" #include "kptschedule.h" #include "kptdebug.h" #include #include #include #include namespace KPlato { class Project; class Node; class Task; typedef QList NodeList; // TODO: find some better values static const quintptr ListItemId = static_cast(-1); static const quintptr ProjectItemId = static_cast(-2); CriticalPathItemModel::CriticalPathItemModel( QObject *parent ) : ItemModelBase( parent ), m_manager( 0 ) { /* connect( this, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset()) ); connect( this, SIGNAL(modelReset()), SLOT(slotReset()) );*/ } CriticalPathItemModel::~CriticalPathItemModel() { } void CriticalPathItemModel::slotNodeToBeInserted( Node *, int ) { //debugPlan<name(); } void CriticalPathItemModel::slotNodeInserted( Node * /*node*/ ) { //debugPlan<getParent->name()<<"-->"<name(); } void CriticalPathItemModel::slotNodeToBeRemoved( Node *node ) { Q_UNUSED(node); //debugPlan<name(); /* if ( m_path.contains( node ) ) { }*/ } void CriticalPathItemModel::slotNodeRemoved( Node *node ) { Q_UNUSED(node); //debugPlan<name(); } void CriticalPathItemModel::setProject( Project *project ) { beginResetModel(); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - disconnect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotLayoutToBeChanged()) ); + disconnect(m_project, &Project::aboutToBeDeleted, this, &CriticalPathItemModel::projectDeleted); + disconnect( m_project, &Project::nodeChanged, this, &CriticalPathItemModel::slotNodeChanged ); + disconnect( m_project, &Project::nodeToBeAdded, this, &CriticalPathItemModel::slotNodeToBeInserted ); + disconnect( m_project, &Project::nodeToBeRemoved, this, &CriticalPathItemModel::slotNodeToBeRemoved ); + disconnect( m_project, &Project::nodeToBeMoved, this, &CriticalPathItemModel::slotLayoutToBeChanged ); - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotLayoutChanged()) ); + disconnect( m_project, &Project::nodeAdded, this, &CriticalPathItemModel::slotNodeInserted ); + disconnect( m_project, &Project::nodeRemoved, this, &CriticalPathItemModel::slotNodeRemoved ); + disconnect( m_project, &Project::nodeMoved, this, &CriticalPathItemModel::slotLayoutChanged ); } m_project = project; m_nodemodel.setProject( project ); if ( project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - connect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotLayoutToBeChanged()) ); + connect(m_project, &Project::aboutToBeDeleted, this, &CriticalPathItemModel::projectDeleted); + connect( m_project, &Project::nodeChanged, this, &CriticalPathItemModel::slotNodeChanged ); + connect( m_project, &Project::nodeToBeAdded, this, &CriticalPathItemModel::slotNodeToBeInserted ); + connect( m_project, &Project::nodeToBeRemoved, this, &CriticalPathItemModel::slotNodeToBeRemoved ); + connect( m_project, &Project::nodeToBeMoved, this, &CriticalPathItemModel::slotLayoutToBeChanged ); - connect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotLayoutChanged()) ); + connect( m_project, &Project::nodeAdded, this, &CriticalPathItemModel::slotNodeInserted ); + connect( m_project, &Project::nodeRemoved, this, &CriticalPathItemModel::slotNodeRemoved ); + connect( m_project, &Project::nodeMoved, this, &CriticalPathItemModel::slotLayoutChanged ); } endResetModel(); } void CriticalPathItemModel::setManager( ScheduleManager *sm ) { beginResetModel(); debugPlan<criticalPath( m_manager->scheduleId(), 0 ); } debugPlan<= columnCount() || row < 0 ) { return QModelIndex(); } if ( parent.isValid() ) { return QModelIndex(); } Node *n = m_path.value( row ); QModelIndex i = createIndex(row, column, n ); return i; } Duration::Unit CriticalPathItemModel::presentationUnit( const Duration &dur ) const { if ( dur.toDouble( Duration::Unit_d ) < 1.0 ) { return Duration::Unit_h; } return Duration::Unit_d; } QVariant CriticalPathItemModel::name( int role ) const { switch ( role ) { case Qt::DisplayRole: return i18n( "Path" ); case Qt::ToolTipRole: case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CriticalPathItemModel::duration( int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { Duration v = m_project->duration( m_manager->scheduleId() ); return QVariant(QLocale().toString( v.toDouble( presentationUnit( v ) ), 'f', 1 ) + Duration::unitToString( presentationUnit( v ) )); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CriticalPathItemModel::variance( int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { double v = 0.0; foreach ( Node *n, m_path ) { long id = m_manager->scheduleId(); v += n->variance( id, presentationUnit( m_project->duration( id ) ) ); } return QLocale().toString( v, 'f', 1 ); break; } case Qt::EditRole: { double v = 0.0; foreach ( Node *n, m_path ) { v += n->variance( m_manager->scheduleId() ); } return v; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CriticalPathItemModel::notUsed( int role ) const { switch ( role ) { case Qt::DisplayRole: return ""; default: return QVariant(); } return QVariant(); } QVariant CriticalPathItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( ! index.isValid() ) { return result; } if ( role == Qt::TextAlignmentRole ) { return alignment( index.column() ); } Node *n = node( index ); if ( n == 0 ) { switch ( index.column() ) { case NodeModel::NodeName: result = name( role ); break; case NodeModel::NodeDuration: result = duration( role ); break; case NodeModel::NodeVarianceDuration: result = variance( role ); break; default: result = notUsed( role ); break; } } else { result = m_nodemodel.data( n, index.column(), role ); } if ( result.isValid() ) { if ( role == Qt::DisplayRole && result.type() == QVariant::String && result.toString().isEmpty()) { // HACK to show focus in empty cells result = ' '; } return result; } return result; } QVariant CriticalPathItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole ) { return m_nodemodel.headerData( section, role ); } else if ( role == Qt::TextAlignmentRole ) { return alignment( section ); } } if ( role == Qt::ToolTipRole ) { return m_nodemodel.headerData( section, role ); } else if ( role == Qt::WhatsThisRole ) { return m_nodemodel.headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QVariant CriticalPathItemModel::alignment( int column ) const { return m_nodemodel.headerData( column, Qt::TextAlignmentRole ); } int CriticalPathItemModel::columnCount( const QModelIndex & ) const { return m_nodemodel.propertyCount(); } int CriticalPathItemModel::rowCount( const QModelIndex &parent ) const { if ( parent.isValid() ) { return 0; } if ( m_manager && m_manager->expected() && m_manager->expected()->criticalPathList() ) { return m_path.count() + 1; } return 0; } Node *CriticalPathItemModel::node( const QModelIndex &index ) const { if ( ! index.isValid() ) { return 0; } return m_path.value( index.row() ); } void CriticalPathItemModel::slotNodeChanged( Node *node ) { debugPlan; if ( node == 0 || node->type() == Node::Type_Project || ! m_path.contains( node ) ) { return; } int row = m_path.indexOf( node ); emit dataChanged( createIndex( row, 0, node ), createIndex( row, columnCount() - 1, node ) ); } //----------------------------- PertResultItemModel::PertResultItemModel( QObject *parent ) : ItemModelBase( parent ), m_manager( 0 ) { /* connect( this, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset()) ); connect( this, SIGNAL(modelReset()), SLOT(slotReset()) );*/ } PertResultItemModel::~PertResultItemModel() { } void PertResultItemModel::slotAboutToBeReset() { debugPlan; clear(); } void PertResultItemModel::slotReset() { debugPlan; refresh(); } void PertResultItemModel::slotNodeToBeInserted( Node *, int ) { //debugPlan<name(); clear(); } void PertResultItemModel::slotNodeInserted( Node * /*node*/ ) { //debugPlan<getParent->name()<<"-->"<name(); refresh(); } void PertResultItemModel::slotNodeToBeRemoved( Node * /*node*/ ) { //debugPlan<name(); clear(); } void PertResultItemModel::slotNodeRemoved( Node * /*node*/ ) { //debugPlan<name(); refresh(); } void PertResultItemModel::setProject( Project *project ) { clear(); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - disconnect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotLayoutToBeChanged()) ); + disconnect(m_project, &Project::aboutToBeDeleted, this, &PertResultItemModel::projectDeleted); + disconnect( m_project, &Project::nodeChanged, this, &PertResultItemModel::slotNodeChanged ); + disconnect( m_project, &Project::nodeToBeAdded, this, &PertResultItemModel::slotNodeToBeInserted ); + disconnect( m_project, &Project::nodeToBeRemoved, this, &PertResultItemModel::slotNodeToBeRemoved ); + disconnect( m_project, &Project::nodeToBeMoved, this, &PertResultItemModel::slotLayoutToBeChanged ); - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotLayoutChanged()) ); + disconnect( m_project, &Project::nodeAdded, this, &PertResultItemModel::slotNodeInserted ); + disconnect( m_project, &Project::nodeRemoved, this, &PertResultItemModel::slotNodeRemoved ); + disconnect( m_project, &Project::nodeMoved, this, &PertResultItemModel::slotLayoutChanged ); } m_project = project; m_nodemodel.setProject( project ); if ( project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - connect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotLayoutToBeChanged()) ); - - connect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotLayoutChanged()) ); + connect(m_project, &Project::aboutToBeDeleted, this, &PertResultItemModel::projectDeleted); + connect( m_project, &Project::nodeChanged, this, &PertResultItemModel::slotNodeChanged ); + connect( m_project, &Project::nodeToBeAdded, this, &PertResultItemModel::slotNodeToBeInserted ); + connect( m_project, &Project::nodeToBeRemoved, this, &PertResultItemModel::slotNodeToBeRemoved ); + connect( m_project, &Project::nodeToBeMoved, this, &PertResultItemModel::slotLayoutToBeChanged ); + + connect( m_project, &Project::nodeAdded, this, &PertResultItemModel::slotNodeInserted ); + connect( m_project, &Project::nodeRemoved, this, &PertResultItemModel::slotNodeRemoved ); + connect( m_project, &Project::nodeMoved, this, &PertResultItemModel::slotLayoutChanged ); } refresh(); } void PertResultItemModel::setManager( ScheduleManager *sm ) { m_manager = sm; m_nodemodel.setManager( sm ); refresh(); } void PertResultItemModel::clear() { debugPlan<count(); if ( c > 0 ) { // FIXME: gives error msg: // Can't select indexes from different model or with different parents QModelIndex i = index( l ); debugPlan<scheduleId(); debugPlan< *lst = m_project->criticalPathList( id ); if ( lst ) { for ( int i = 0; i < lst->count(); ++i ) { m_topNames << i18n( "Critical Path" ); m_top.append( const_cast( &( lst->at( i ) ) ) ); debugPlan<at( i ); } if ( lst->isEmpty() ) debugPlan<<"No critical path"; } foreach( Node* n, m_project->allNodes() ) { if ( n->type() != Node::Type_Task && n->type() != Node::Type_Milestone ) { continue; } Task *t = static_cast( n ); if ( t->inCriticalPath( id ) ) { continue; } else if ( t->isCritical( id ) ) { m_critical.append( t ); } else { m_noncritical.append( t ); } } if ( ! m_critical.isEmpty() ) { m_topNames << i18n( "Critical" ); m_top.append(&m_critical ); } if ( ! m_noncritical.isEmpty() ) { m_topNames << i18n( "Non-critical" ); m_top.append(&m_noncritical ); } if ( ! m_top.isEmpty() ) { debugPlan<count(); if ( c > 0 ) { beginInsertRows( index( l ), 0, c-1 ); endInsertRows(); } } } } Qt::ItemFlags PertResultItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = QAbstractItemModel::flags( index ); flags &= ~( Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled ); return flags; } QModelIndex PertResultItemModel::parent( const QModelIndex &index ) const { if ( !index.isValid() ) { return QModelIndex(); } //debugPlan<= columnCount() || row < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row == 0 ) { QModelIndex idx = createIndex(row, column, ProjectItemId ); // project return idx; } if ( row >= m_top.count() ) { return QModelIndex(); // shouldn't happened } QModelIndex idx = createIndex(row, column, ListItemId ); //debugPlan<indexOf( const_cast( node ) ); // if ( row != -1 ) { // return createIndex( row, 0, const_cast( node ) ); // } // } // return QModelIndex(); // } QModelIndex PertResultItemModel::index( const NodeList *lst ) const { if ( m_project == 0 || lst == 0 ) { return QModelIndex(); } NodeList *l = const_cast( lst ); int row = m_top.indexOf( l ); if ( row <= 0 ) { return QModelIndex(); } return createIndex( row, 0, ListItemId ); } QVariant PertResultItemModel::name( int row, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return m_topNames.value( row ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::name( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return node->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::earlyStart( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->earlyStart( m_manager->scheduleId() ); case Qt::ToolTipRole: return QLocale().toString( node->earlyStart( m_manager->scheduleId() ).date(), QLocale::ShortFormat ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::earlyFinish( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->earlyFinish( m_manager->scheduleId() ); case Qt::ToolTipRole: return QLocale().toString( node->earlyFinish( m_manager->scheduleId() ).date(), QLocale::ShortFormat ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::lateStart( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->lateStart( m_manager->scheduleId() ); case Qt::ToolTipRole: return QLocale().toString( node->lateStart( m_manager->scheduleId() ).date(), QLocale::ShortFormat ); case Qt::EditRole: break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::lateFinish( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->lateFinish( m_manager->scheduleId() ); case Qt::ToolTipRole: return QLocale().toString( node->lateFinish( m_manager->scheduleId() ).date(), QLocale::ShortFormat ); case Qt::EditRole: break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::positiveFloat( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->positiveFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return node->positiveFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::freeFloat( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->freeFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return node->freeFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::negativeFloat( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->negativeFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return node->negativeFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::startFloat( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->startFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return node->startFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::finishFloat( const Task *node, int role ) const { switch ( role ) { case Qt::DisplayRole: return node->finishFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nHourFraction ); case Qt::ToolTipRole: return node->finishFloat( m_manager->scheduleId() ).toString( Duration::Format_i18nDayTime ); case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant PertResultItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( ! index.isValid() ) { return result; } if ( role == Qt::TextAlignmentRole ) { return alignment( index.column() ); } Node *n = node( index ); if ( n == 0 ) { switch ( index.column() ) { case 0: return name( index.row(), role ); default: break; } return QVariant(); } if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { result = m_nodemodel.data( n, index.column(), role ); } if ( n->type() == Node::Type_Project ) { //Project *p = static_cast( n ); switch ( index.column() ) { case NodeModel::NodeName: result = name( NodeModel::NodeName, role ); break; default: //debugPlan<<"data: invalid display value column "<count(); return l->count(); } //debugPlan<<"node "<value( index.row() ); } return 0; } void PertResultItemModel::slotNodeChanged( Node *) { debugPlan; refresh(); /* if ( node == 0 || node->type() == Node::Type_Project ) { return; } int row = node->getParent()->findChildNode( node ); emit dataChanged( createIndex( row, 0, node ), createIndex( row, columnCount() - 1, node ) );*/ } } // namespace KPlato diff --git a/src/libs/models/kptrelationmodel.cpp b/src/libs/models/kptrelationmodel.cpp index 491c7027..d880800c 100644 --- a/src/libs/models/kptrelationmodel.cpp +++ b/src/libs/models/kptrelationmodel.cpp @@ -1,454 +1,454 @@ /* This file is part of the KDE project Copyright (C) 2007, 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. */ #include "kptrelationmodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptduration.h" #include "kptproject.h" #include "kptnode.h" #include "kptrelation.h" #include "kptdebug.h" #include #include #include namespace KPlato { QVariant RelationModel::parentName( const Relation *r, int role ) const { //debugPlan<parent()->name(); case Qt::TextAlignmentRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant RelationModel::childName( const Relation *r, int role ) const { //debugPlan<child()->name(); case Qt::TextAlignmentRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant RelationModel::type( const Relation *r, int role ) const { //debugPlan<typeToString( true ); case Role::EnumList: return r->typeList( true ); case Qt::EditRole: case Role::EnumListValue: return (int)r->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant RelationModel::lag( const Relation *r, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { Duration::Unit unit = Duration::Unit_h; return QVariant(QLocale().toString( r->lag().toDouble( unit ), 'f', 1 ) + Duration::unitToString( unit, true )); } case Qt::EditRole: return r->lag().toDouble( Duration::Unit_h ); case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant RelationModel::data( const Relation *r, int property, int role ) const { QVariant result; switch ( property ) { case 0: result = parentName( r, role ); break; case 1: result = childName( r, role ); break; case 2: result = type( r, role ); break; case 3: result = lag( r, role ); break; default: //debugPlan<<"Invalid property number: "<child() ) { return; } // relations always appended int row = rowCount(); beginInsertRows( QModelIndex(), row, row ); } void RelationItemModel::slotRelationAdded( Relation *relation ) { debugPlan; if ( m_node == 0 || m_node != relation->child() ) { return; } endInsertRows(); } void RelationItemModel::slotRelationToBeRemoved( Relation *relation ) { if ( m_node == 0 || ! m_node->dependParentNodes().contains( relation ) ) { return; } m_removedRelation = relation; int row = m_node->dependParentNodes().indexOf( relation ); debugPlan<dependParentNodes().contains( relation ) ) { return; } int row = m_node->dependParentNodes().indexOf( relation ); emit dataChanged( createIndex( row, 0 ), createIndex( row, columnCount()-1 ) ); } void RelationItemModel::slotNodeToBeRemoved( Node *node ) { if ( node != m_node ) { return; } setNode( 0 ); } void RelationItemModel::slotNodeRemoved( Node *node ) { Q_UNUSED(node); } void RelationItemModel::slotLayoutChanged() { //debugPlan<name()<type(); if ( v == r->type() ) { return false; } emit executeCommand( new ModifyRelationTypeCmd( r, v, kundo2_i18n("Modify relation type") ) ); return true; } return false; } bool RelationItemModel::setLag( Relation *r, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration d( value.toList()[0].toDouble(), unit ); debugPlan<"<lag() ) { return false; } emit executeCommand( new ModifyRelationLagCmd( r, d, kundo2_i18n( "Modify relation time lag" ) ) ); return true; } default: break; } return false; } QVariant RelationItemModel::data( const QModelIndex &index, int role ) const { if ( role == Qt::TextAlignmentRole ) { return headerData( index.column(), Qt::Horizontal, role ); } QVariant result; Relation *r = relation( index ); if ( r != 0 ) { result = m_relationmodel.data( r, index.column(), role ); } if ( result.isValid() ) { if ( role == Qt::DisplayRole && result.type() == QVariant::String && result.toString().isEmpty()) { // HACK to show focus in empty cells result = ' '; } return result; } return result; } bool RelationItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } if ( ( flags(index) & Qt::ItemIsEditable ) == 0 || role != Qt::EditRole ) { return false; } Relation *r = relation( index ); switch (index.column()) { case 0: return false; case 1: return false; case 2: return setType( r, value, role ); case 3: return setLag( r, value, role ); default: qWarning("data: invalid display value column %d", index.column()); return false; } return false; } QVariant RelationItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole ) { return m_relationmodel.headerData( section, role ); } else if ( role == Qt::TextAlignmentRole ) { switch (section) { case 2: return Qt::AlignCenter; case 3: return Qt::AlignRight; default: return QVariant(); } } } if ( role == Qt::ToolTipRole ) { return RelationModel::headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QAbstractItemDelegate *RelationItemModel::createDelegate( int column, QWidget *parent ) const { switch ( column ) { case 2: return new EnumDelegate( parent ); case 3: return new DurationSpinBoxDelegate( parent ); default: return 0; } return 0; } int RelationItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_relationmodel.propertyCount(); } int RelationItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 || m_node == 0 || parent.isValid() ) { return 0; } return m_node->numDependParentNodes(); } Relation *RelationItemModel::relation( const QModelIndex &index ) const { if ( ! index.isValid() || m_node == 0 ) { return 0; } return m_node->dependParentNodes().value( index.row() ); } void RelationItemModel::slotNodeChanged( Node *node ) { Q_UNUSED(node); beginResetModel(); endResetModel(); } } //namespace KPlato diff --git a/src/libs/models/kptresourceallocationmodel.cpp b/src/libs/models/kptresourceallocationmodel.cpp index e62ab36f..11dce9cb 100644 --- a/src/libs/models/kptresourceallocationmodel.cpp +++ b/src/libs/models/kptresourceallocationmodel.cpp @@ -1,1076 +1,1076 @@ /* This file is part of the KDE project Copyright (C) 2009, 2012 Dag Andersen danders@get2net> 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 "kptresourceallocationmodel.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptdebug.h" #include #include namespace KPlato { //-------------------------------------- ResourceAllocationModel::ResourceAllocationModel( QObject *parent ) : QObject( parent ), m_project( 0 ), m_task( 0 ) { } ResourceAllocationModel::~ResourceAllocationModel() { } const QMetaEnum ResourceAllocationModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } void ResourceAllocationModel::setProject( Project *project ) { m_project = project; } void ResourceAllocationModel::setTask( Task *task ) { m_task = task; } int ResourceAllocationModel::propertyCount() const { return columnMap().keyCount(); } QVariant ResourceAllocationModel::name( const Resource *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationModel::name( const ResourceGroup *res, int role ) const { //debugPlan<name()<<","<name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationModel::type( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->typeToString( true ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationModel::type( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->typeToString( true ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationModel::allocation( const ResourceGroup *group, const Resource *res, int role ) const { if ( m_project == 0 || m_task == 0 ) { return QVariant(); } const ResourceGroupRequest *rg = m_task->requests().find( group ); const ResourceRequest *rr = 0; if ( rg ) { rr = rg->find( res ); } switch ( role ) { case Qt::DisplayRole: { int units = rr ? rr->units() : 0; // xgettext: no-c-format return i18nc( "%", "%1%", units ); } case Qt::EditRole: return rr ? rr->units() : 0; case Qt::ToolTipRole: { int units = rr ? rr->units() : 0; if ( units == 0 ) { return xi18nc( "@info:tooltip", "Not allocated" ); } // xgettext: no-c-format return xi18nc( "@info:tooltip", "Allocated units: %1%", units ); } case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Minimum: return 0; case Role::Maximum: return 100; case Qt::CheckStateRole: return Qt::Unchecked; } return QVariant(); } QVariant ResourceAllocationModel::allocation( const ResourceGroup *res, int role ) const { if ( m_project == 0 || m_task == 0 ) { return QVariant(); } const ResourceGroupRequest *req = m_task->requests().find( res ); switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return req ? req->units() : 0; case Qt::ToolTipRole: return QVariant(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::Minimum: return 0; case Role::Maximum: return res->numResources(); } return QVariant(); } QVariant ResourceAllocationModel::maximum( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: // xgettext: no-c-format return i18nc( "%", "%1%", res->units() ); case Qt::EditRole: return res->units(); case Qt::ToolTipRole: // xgettext: no-c-format return i18n( "Maximum units available: %1%", res->units() ); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationModel::required( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: { QStringList lst; foreach ( Resource *r, res->requiredResources() ) { lst << r->name(); } return lst.join( "," ); } case Qt::EditRole: return QVariant();//Not used case Qt::ToolTipRole: return QVariant(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: return QVariant(); case Qt::WhatsThisRole: return xi18nc( "@info:whatsthis", "Required Resources" "A working resource can be assigned to one or more required resources." " A required resource is a material resource that the working resource depends on" " in order to do the work." "To be able to use a material resource as a required resource, the material resource" " must be part of a group of type Material." ); } return QVariant(); } QVariant ResourceAllocationModel::maximum( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return res->numResources(); case Qt::ToolTipRole: return i18np( "There is %1 resource available in this group", "There are %1 resources available in this group", res->numResources() ); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationModel::data( const ResourceGroup *group, const Resource *resource, int property, int role ) const { QVariant result; if ( resource == 0 ) { return result; } switch ( property ) { case RequestName: result = name( resource, role ); break; case RequestType: result = type( resource, role ); break; case RequestAllocation: result = allocation( group, resource, role ); break; case RequestMaximum: result = maximum( resource, role ); break; case RequestRequired: result = required( resource, role ); break; default: debugPlan<<"data: invalid display value: property="<Required Resources" "A working resource can be assigned to one or more required resources." " A required resource is a material resource that the working resource depends on" " in order to do the work." "To be able to use a material resource as a required resource, the material resource" " must be part of a group of type Material." ); default: return QVariant(); } } return QVariant(); } //-------------------------------------- ResourceAllocationItemModel::ResourceAllocationItemModel( QObject *parent ) : ItemModelBase( parent ) { } ResourceAllocationItemModel::~ResourceAllocationItemModel() { } void ResourceAllocationItemModel::slotResourceToBeInserted( const ResourceGroup *group, int row ) { //debugPlan<name()<<","<name(); endInsertRows(); emit layoutChanged(); //HACK to make the right view react! Bug in qt? } void ResourceAllocationItemModel::slotResourceToBeRemoved( const Resource *resource ) { //debugPlan<name(); int row = index( resource ).row(); beginRemoveRows( index( resource->parentGroup() ), row, row ); } void ResourceAllocationItemModel::slotResourceRemoved( const Resource */*resource */) { //debugPlan<name(); endRemoveRows(); } void ResourceAllocationItemModel::slotResourceGroupToBeInserted( const ResourceGroup */*group*/, int row ) { //debugPlan<name(); beginInsertRows( QModelIndex(), row, row ); } void ResourceAllocationItemModel::slotResourceGroupInserted( const ResourceGroup */*group */) { //debugPlan<name(); endInsertRows(); } void ResourceAllocationItemModel::slotResourceGroupToBeRemoved( const ResourceGroup *group ) { //debugPlan<name(); int row = index( group ).row(); beginRemoveRows( QModelIndex(), row, row ); } void ResourceAllocationItemModel::slotResourceGroupRemoved( const ResourceGroup */*group */) { //debugPlan<name(); endRemoveRows(); } void ResourceAllocationItemModel::setProject( Project *project ) { if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project, SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotResourceChanged(KPlato::Resource*)) ); - disconnect( m_project, SIGNAL(resourceGroupChanged(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupChanged(KPlato::ResourceGroup*)) ); + disconnect(m_project, &Project::aboutToBeDeleted, this, &ResourceAllocationItemModel::projectDeleted); + disconnect( m_project, &Project::resourceChanged, this, &ResourceAllocationItemModel::slotResourceChanged ); + disconnect( m_project, &Project::resourceGroupChanged, this, &ResourceAllocationItemModel::slotResourceGroupChanged ); - disconnect( m_project, SIGNAL(resourceGroupToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const KPlato::ResourceGroup*,int)) ); + disconnect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAllocationItemModel::slotResourceGroupToBeInserted ); - disconnect( m_project, SIGNAL(resourceGroupToBeRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAllocationItemModel::slotResourceGroupToBeRemoved ); - disconnect( m_project, SIGNAL(resourceToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const KPlato::ResourceGroup*,int)) ); + disconnect( m_project, &Project::resourceToBeAdded, this, &ResourceAllocationItemModel::slotResourceToBeInserted ); - disconnect( m_project, SIGNAL(resourceToBeRemoved(const KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(const KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceToBeRemoved, this, &ResourceAllocationItemModel::slotResourceToBeRemoved ); - disconnect( m_project, SIGNAL(resourceGroupAdded(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupAdded, this, &ResourceAllocationItemModel::slotResourceGroupInserted ); - disconnect( m_project, SIGNAL(resourceGroupRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupRemoved, this, &ResourceAllocationItemModel::slotResourceGroupRemoved ); - disconnect( m_project, SIGNAL(resourceAdded(const KPlato::Resource*)), this, SLOT(slotResourceInserted(const KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceAdded, this, &ResourceAllocationItemModel::slotResourceInserted ); - disconnect( m_project, SIGNAL(resourceRemoved(const KPlato::Resource*)), this, SLOT(slotResourceRemoved(const KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceRemoved, this, &ResourceAllocationItemModel::slotResourceRemoved ); } m_project = project; if ( m_project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotResourceChanged(KPlato::Resource*)) ); - connect( m_project, SIGNAL(resourceGroupChanged(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupChanged(KPlato::ResourceGroup*)) ); + connect(m_project, &Project::aboutToBeDeleted, this, &ResourceAllocationItemModel::projectDeleted); + connect( m_project, &Project::resourceChanged, this, &ResourceAllocationItemModel::slotResourceChanged ); + connect( m_project, &Project::resourceGroupChanged, this, &ResourceAllocationItemModel::slotResourceGroupChanged ); - connect( m_project, SIGNAL(resourceGroupToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAllocationItemModel::slotResourceGroupToBeInserted ); - connect( m_project, SIGNAL(resourceGroupToBeRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAllocationItemModel::slotResourceGroupToBeRemoved ); - connect( m_project, SIGNAL(resourceToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceToBeAdded, this, &ResourceAllocationItemModel::slotResourceToBeInserted ); - connect( m_project, SIGNAL(resourceToBeRemoved(const KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(const KPlato::Resource*)) ); + connect( m_project, &Project::resourceToBeRemoved, this, &ResourceAllocationItemModel::slotResourceToBeRemoved ); - connect( m_project, SIGNAL(resourceGroupAdded(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupAdded, this, &ResourceAllocationItemModel::slotResourceGroupInserted ); - connect( m_project, SIGNAL(resourceGroupRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupRemoved, this, &ResourceAllocationItemModel::slotResourceGroupRemoved ); - connect( m_project, SIGNAL(resourceAdded(const KPlato::Resource*)), this, SLOT(slotResourceInserted(const KPlato::Resource*)) ); + connect( m_project, &Project::resourceAdded, this, &ResourceAllocationItemModel::slotResourceInserted ); - connect( m_project, SIGNAL(resourceRemoved(const KPlato::Resource*)), this, SLOT(slotResourceRemoved(const KPlato::Resource*)) ); + connect( m_project, &Project::resourceRemoved, this, &ResourceAllocationItemModel::slotResourceRemoved ); } m_model.setProject( m_project ); } void ResourceAllocationItemModel::setTask( Task *task ) { if ( task == m_model.task() ) { return; } if ( m_model.task() == 0 ) { beginResetModel(); filldata( task ); m_model.setTask( task ); endResetModel(); return; } if ( task ) { emit layoutAboutToBeChanged(); filldata( task ); m_model.setTask( task ); emit layoutChanged(); } } void ResourceAllocationItemModel::filldata( Task *task ) { qDeleteAll( m_resourceCache ); m_resourceCache.clear(); qDeleteAll( m_groupCache ); m_groupCache.clear(); m_requiredChecked.clear(); if ( m_project && task ) { foreach ( const ResourceGroup *g, m_project->resourceGroups() ) { const ResourceGroupRequest *gr = task->requests().find( g ); if ( gr ) { m_groupCache[ g ] = new ResourceGroupRequest( *gr ); } } foreach ( const Resource *r, m_project->resourceList() ) { const ResourceRequest *rr = task->requests().find( r ); if ( rr ) { m_resourceCache[ r ] = new ResourceRequest( *rr ); if ( ! m_resourceCache[ r ]->requiredResources().isEmpty() ) { m_requiredChecked[ r ] = Qt::Checked; } } } } } bool ResourceAllocationItemModel::hasMaterialResources() const { if ( ! m_project ) { return false; } foreach ( const ResourceGroup *g, m_project->resourceGroups() ) { if ( g->type() == ResourceGroup::Type_Material ) { foreach ( const Resource *r, g->resources() ) { if ( r->type() == Resource::Type_Material ) { return true; } } } } return false; } Qt::ItemFlags ResourceAllocationItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); if ( !m_readWrite ) { //debugPlan<<"read only"<type() != Resource::Type_Work ) { flags &= ~( Qt::ItemIsEditable | Qt::ItemIsUserCheckable ); } else if ( m_resourceCache.contains( r ) && m_resourceCache[ r ]->units() > 0 ) { flags |= ( Qt::ItemIsEditable | Qt::ItemIsUserCheckable ); if ( ! hasMaterialResources() ) { flags &= ~Qt::ItemIsEnabled; } } break; } default: flags &= ~Qt::ItemIsEditable; break; } return flags; } QModelIndex ResourceAllocationItemModel::parent( const QModelIndex &index ) const { if ( !index.isValid() || m_project == 0 ) { return QModelIndex(); } //debugPlan<( object( index ) ); if ( r && r->parentGroup() ) { // only resources have parent int row = m_project->indexOf( r->parentGroup() ); return createIndex( row, 0, r->parentGroup() ); } return QModelIndex(); } QModelIndex ResourceAllocationItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || column < 0 || column >= columnCount() || row < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { return createIndex( row, column, m_project->resourceGroupAt( row ) ); } return QModelIndex(); } QObject *p = object( parent ); ResourceGroup *g = qobject_cast( p ); if ( g ) { if ( row < g->numResources() ) { return createIndex( row, column, g->resourceAt( row ) ); } return QModelIndex(); } return QModelIndex(); } QModelIndex ResourceAllocationItemModel::index( const Resource *resource ) const { if ( m_project == 0 || resource == 0 ) { return QModelIndex(); } Resource *r = const_cast(resource); int row = -1; ResourceGroup *par = r->parentGroup(); if ( par ) { row = par->indexOf( r ); return createIndex( row, 0, r ); } return QModelIndex(); } QModelIndex ResourceAllocationItemModel::index( const ResourceGroup *group ) const { if ( m_project == 0 || group == 0 ) { return QModelIndex(); } ResourceGroup *g = const_cast(group); int row = m_project->indexOf( g ); return createIndex( row, 0, g ); } int ResourceAllocationItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_model.propertyCount(); } int ResourceAllocationItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 || m_model.task() == 0 ) { return 0; } if ( ! parent.isValid() ) { return m_project->numResourceGroups(); } QObject *p = object( parent ); ResourceGroup *g = qobject_cast( p ); if ( g ) { return g->numResources(); } return 0; } QVariant ResourceAllocationItemModel::allocation( const ResourceGroup *group, const Resource *res, int role ) const { if ( m_model.task() == 0 ) { return QVariant(); } if ( ! m_resourceCache.contains( res ) ) { if ( role == Qt::EditRole ) { ResourceRequest *req = m_model.task()->requests().find( res ); if ( req == 0 ) { req = new ResourceRequest( const_cast( res ), 0 ); } const_cast( this )->m_resourceCache.insert( res, req ); return req->units(); } return m_model.allocation( group, res, role ); } switch ( role ) { case Qt::DisplayRole: { // xgettext: no-c-format return i18nc( "%", "%1%", m_resourceCache[ res ]->units() ); } case Qt::EditRole: return m_resourceCache[ res ]->units(); case Qt::ToolTipRole: { if ( res->units() == 0 ) { return xi18nc( "@info:tooltip", "Not allocated" ); } return xi18nc( "@info:tooltip", "%1 allocated out of %2 available", allocation( group, res, Qt::DisplayRole ).toString(), m_model.maximum( res, Qt::DisplayRole ).toString() ); } case Qt::CheckStateRole: return m_resourceCache[ res ]->units() == 0 ? Qt::Unchecked : Qt::Checked; default: return m_model.allocation( group, res, role ); } return QVariant(); } int ResourceAllocationItemModel::requestedResources( const ResourceGroup *res ) const { int c = 0; foreach ( const Resource *r, res->resources() ) { if ( m_resourceCache.contains( r ) && m_resourceCache[ r ]->units() > 0 ) { ++c; } } return c; } QVariant ResourceAllocationItemModel::allocation( const ResourceGroup *res, int role ) const { if ( m_model.task() == 0 ) { return QVariant(); } if ( ! m_groupCache.contains( res ) ) { return m_model.allocation( res, role ); } switch ( role ) { case Qt::DisplayRole: return QString(" %1 (%2)" ) .arg( qMax( m_groupCache[ res ]->units(), allocation( res, Role::Minimum ).toInt() ) ) .arg(requestedResources( res ) ); case Qt::EditRole: return qMax( m_groupCache[ res ]->units(), allocation( res, Role::Minimum ).toInt() ); case Qt::ToolTipRole: { QString s1 = i18ncp( "@info:tooltip", "%1 resource requested for dynamic allocation", "%1 resources requested for dynamic allocation", allocation( res, Qt::EditRole ).toInt() ); QString s2 = i18ncp( "@info:tooltip", "%1 resource allocated", "%1 resources allocated", requestedResources( res ) ); return xi18nc( "@info:tooltip", "%1%2", s1, s2 ); } case Qt::WhatsThisRole: { return xi18nc( "@info:whatsthis", "Group allocations" "You can allocate a number of resources from a group and let" " the scheduler select from the available resources at the time of scheduling." " These dynamically allocated resources will be in addition to any resource you have allocated specifically." ); } case Role::Minimum: { return 0; } case Role::Maximum: { return res->numResources() - requestedResources( res ); } default: return m_model.allocation( res, role ); } return QVariant(); } bool ResourceAllocationItemModel::setAllocation( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { m_resourceCache[ res ]->setUnits( value.toInt() ); QModelIndex idx = index( res->parentGroup() ); emit dataChanged( index( idx.row(), 0, QModelIndex() ), index( idx.row(), columnCount() - 1, QModelIndex() ) ); return true; } case Qt::CheckStateRole: { if ( ! m_resourceCache.contains( res ) ) { m_resourceCache[ res ] = new ResourceRequest( res, 0 ); } if ( m_resourceCache[ res ]->units() == 0 ) { m_resourceCache[ res ]->setUnits( 100 ); ResourceGroup *g = res->parentGroup(); if ( m_groupCache.contains( g ) ) { ResourceGroupRequest *gr = m_groupCache[ g ]; if ( gr->units() + requestedResources( g ) > g->numResources() ) { gr->setUnits( gr->units() - 1 ); } } } else { m_resourceCache[ res ]->setUnits( 0 ); } QModelIndex idx = index( res->parentGroup() ); emit dataChanged( index( idx.row(), 0, QModelIndex() ), index( idx.row(), columnCount() - 1, QModelIndex() ) ); return true; } } return false; } bool ResourceAllocationItemModel::setAllocation( ResourceGroup *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( ! m_groupCache.contains( res ) ) { m_groupCache[ res ] = new ResourceGroupRequest( res, 0 ); } m_groupCache[ res ]->setUnits( value.toInt() ); emit dataChanged( index( res ), index( res ) ); return true; } return false; } QVariant ResourceAllocationItemModel::maximum( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: { int c = res->numResources() - requestedResources( res ); if ( m_groupCache.contains( res ) ) { c -= m_groupCache[ res ]->units(); } return i18nc( "1: free resources, 2: number of resources", "%1 of %2", c, res->numResources() ); } case Qt::ToolTipRole: return xi18ncp( "@info:tooltip", "There is %1 resource available in this group", "There are %1 resources available in this group", res->numResources() ); default: return m_model.maximum( res, role ); } return QVariant(); } QVariant ResourceAllocationItemModel::required( const QModelIndex &idx, int role ) const { if ( m_model.task() == 0 ) { return QVariant(); } Resource *res = resource( idx ); if ( res == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: { if ( res->type() == Resource::Type_Work ) { QStringList lst; if ( m_requiredChecked[ res ] ) { foreach ( const Resource *r, required( idx ) ) { lst << r->name(); } } return lst.isEmpty() ? i18n( "None" ) : lst.join( "," ); } break; } case Qt::EditRole: break; case Qt::ToolTipRole: switch ( res->type() ) { case Resource::Type_Work: { if ( ! hasMaterialResources() ) { return xi18nc( "@info:tooltip", "No material resources available" ); } QStringList lst; if ( m_requiredChecked[ res ] ) { foreach ( const Resource *r, required( idx ) ) { lst << r->name(); } } return lst.isEmpty() ? xi18nc( "@info:tooltip", "No required resources" ) : lst.join( "\n" ); } case Resource::Type_Material: return xi18nc( "@info:tooltip", "Material resources cannot have required resources" ); case Resource::Type_Team: return xi18nc( "@info:tooltip", "Team resources cannot have required resources" ); } break; case Qt::CheckStateRole: if ( res->type() == Resource::Type_Work ) { return m_requiredChecked[ res ]; } break; default: return m_model.required( res, role ); } return QVariant(); } bool ResourceAllocationItemModel::setRequired( const QModelIndex &idx, const QVariant &value, int role ) { Resource *res = resource( idx ); if ( res == 0 ) { return false; } switch ( role ) { case Qt::CheckStateRole: m_requiredChecked[ res ] = value.toInt(); if ( value.toInt() == Qt::Unchecked ) { m_resourceCache[ res ]->setRequiredResources( QList() ); } emit dataChanged( idx, idx ); return true; } return false; } QVariant ResourceAllocationItemModel::notUsed( const ResourceGroup *, int role ) const { switch ( role ) { case Qt::DisplayRole: return QString(" "); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::EditRole: case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAllocationItemModel::data( const QModelIndex &index, int role ) const { QVariant result; QObject *obj = object( index ); if ( obj == 0 ) { return QVariant(); } if ( role == Qt::TextAlignmentRole ) { // use same alignment as in header (headers always horizontal) return headerData( index.column(), Qt::Horizontal, role ); } Resource *r = qobject_cast( obj ); if ( r ) { if ( index.column() == ResourceAllocationModel::RequestAllocation ) { return allocation( r->parentGroup(), r, role ); } if ( index.column() == ResourceAllocationModel::RequestRequired ) { return required( index, role ); } result = m_model.data( r->parentGroup(), r, index.column(), role ); } else { ResourceGroup *g = qobject_cast( obj ); if ( g ) { switch ( index.column() ) { case ResourceAllocationModel::RequestAllocation: result = allocation( g, role ); break; case ResourceAllocationModel::RequestMaximum: result = maximum( g, role ); break; default: result = m_model.data( g, index.column(), role ); break; } } } if ( role == Qt::DisplayRole && ! result.isValid() ) { // HACK to show focus in empty cells result = ' '; } return result; } bool ResourceAllocationItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } if ( ( flags( index ) & Qt::ItemIsEditable ) == 0 ) { return false; } QObject *obj = object( index ); Resource *r = qobject_cast( obj ); if ( r ) { switch (index.column()) { case ResourceAllocationModel::RequestAllocation: if ( setAllocation( r, value, role ) ) { emit dataChanged( index, index ); QModelIndex idx = this->index( index.row(), ResourceAllocationModel::RequestAllocation, parent( parent( index ) ) ); emit dataChanged( idx, idx ); return true; } return false; case ResourceAllocationModel::RequestRequired: return setRequired( index, value, role ); default: //qWarning("data: invalid display value column %d", index.column()); return false; } } ResourceGroup *g = qobject_cast( obj ); if ( g ) { switch (index.column()) { case ResourceAllocationModel::RequestAllocation: if ( setAllocation( g, value, role ) ) { emit dataChanged( index, index ); return true; } return false; default: //qWarning("data: invalid display value column %d", index.column()); return false; } } return false; } QVariant ResourceAllocationItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole ) { return m_model.headerData( section, role ); } if ( role == Qt::TextAlignmentRole ) { switch (section) { case 0: return QVariant(); default: return Qt::AlignCenter; } return Qt::AlignCenter; } } return m_model.headerData( section, role ); } QAbstractItemDelegate *ResourceAllocationItemModel::createDelegate( int col, QWidget *parent ) const { switch ( col ) { case ResourceAllocationModel::RequestAllocation: return new SpinBoxDelegate( parent ); case ResourceAllocationModel::RequestRequired: return new RequieredResourceDelegate( parent ); default: break; } return 0; } QObject *ResourceAllocationItemModel::object( const QModelIndex &index ) const { QObject *o = 0; if ( index.isValid() ) { o = static_cast( index.internalPointer() ); Q_ASSERT( o ); } return o; } void ResourceAllocationItemModel::slotResourceChanged( Resource *res ) { ResourceGroup *g = res->parentGroup(); if ( g ) { int row = g->indexOf( res ); emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) ); return; } } void ResourceAllocationItemModel::slotResourceGroupChanged( ResourceGroup *res ) { Project *p = res->project(); if ( p ) { int row = p->resourceGroups().indexOf( res ); emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) ); } } Resource *ResourceAllocationItemModel::resource( const QModelIndex &idx ) const { return qobject_cast( object( idx ) ); } void ResourceAllocationItemModel::setRequired( const QModelIndex &idx, const QList &lst ) { Resource *r = resource( idx ); Q_ASSERT( r ); if ( m_resourceCache.contains( r ) ) { m_resourceCache[ r ]->setRequiredResources( lst ); emit dataChanged( idx, idx ); } } QList ResourceAllocationItemModel::required( const QModelIndex &idx ) const { Resource *r = resource( idx ); Q_ASSERT( r ); if ( m_resourceCache.contains( r ) ) { ResourceRequest* request = m_resourceCache[ r ]; return request->requiredResources(); } return r->requiredResources(); } } // namespace KPlato diff --git a/src/libs/models/kptresourceappointmentsmodel.cpp b/src/libs/models/kptresourceappointmentsmodel.cpp index 688b785b..1eb890fd 100644 --- a/src/libs/models/kptresourceappointmentsmodel.cpp +++ b/src/libs/models/kptresourceappointmentsmodel.cpp @@ -1,2031 +1,2031 @@ /* This file is part of the KDE project Copyright (C) 2007, 2011, 2012 Dag Andersen danders@get2net> 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 "kptresourceappointmentsmodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptappointment.h" #include "kptcommand.h" #include "kpteffortcostmap.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptdebug.h" #include #include #include #include #include #include namespace KPlato { ResourceAppointmentsItemModel::ResourceAppointmentsItemModel( QObject *parent ) : ItemModelBase( parent ), m_group( 0 ), m_resource( 0 ), m_showInternal( true ), m_showExternal( true ) { } ResourceAppointmentsItemModel::~ResourceAppointmentsItemModel() { } void ResourceAppointmentsItemModel::slotResourceToBeInserted( const ResourceGroup *group, int row ) { debugPlan<name()<(group); QModelIndex i = index( group ); beginInsertRows( i, row, row ); } void ResourceAppointmentsItemModel::slotResourceInserted( const Resource *r ) { debugPlan<name(); Q_ASSERT( r->parentGroup() == m_group ); endInsertRows(); m_group = 0; refresh(); - connect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - connect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - connect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); + connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); + connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); + connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); + connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } void ResourceAppointmentsItemModel::slotResourceToBeRemoved( const Resource *r ) { debugPlan<name(); int row = r->parentGroup()->indexOf( r ); beginRemoveRows( index( r->parentGroup() ), row, row ); - disconnect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - disconnect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - disconnect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); + disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); + disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); + disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); + disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } void ResourceAppointmentsItemModel::slotResourceRemoved( const Resource *resource ) { Q_UNUSED(resource); //debugPlan<name(); endRemoveRows(); refresh(); } void ResourceAppointmentsItemModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row ) { //debugPlan<name()<(group); beginInsertRows( QModelIndex(), row, row ); } void ResourceAppointmentsItemModel::slotResourceGroupInserted( const ResourceGroup *group ) { //debugPlan<name()<name()<(group); int row = index( group ).row(); beginRemoveRows( QModelIndex(), row, row ); } void ResourceAppointmentsItemModel::slotResourceGroupRemoved( const ResourceGroup *group ) { //debugPlan<name()<= 0 ); refreshData(); emit dataChanged( createExternalAppointmentIndex( row, 0, a ), createExternalAppointmentIndex( row, columnCount() - 1, a ) ); } void ResourceAppointmentsItemModel::slotProjectCalculated( ScheduleManager *sm ) { if ( sm == m_manager ) { setScheduleManager( sm ); } } int ResourceAppointmentsItemModel::rowNumber( Resource *res, Appointment *a ) const { int r = 0; if ( m_showInternal ) { r = res->appointments( id() ).indexOf( a ); if ( r > -1 ) { return r; } r = res->numAppointments(); } if ( m_showExternal ) { int rr = res->externalAppointmentList().indexOf( a ); if ( rr > -1 ) { return r + rr; } } return -1; } void ResourceAppointmentsItemModel::setShowInternalAppointments( bool show ) { if ( m_showInternal == show ) { return; } beginResetModel(); m_showInternal = show; refreshData(); endResetModel(); } void ResourceAppointmentsItemModel::setShowExternalAppointments( bool show ) { if ( m_showExternal == show ) { return; } beginResetModel(); m_showExternal = show; refreshData(); endResetModel(); } void ResourceAppointmentsItemModel::setProject( Project *project ) { beginResetModel(); debugPlan; if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); + disconnect(m_project, &Project::aboutToBeDeleted, this, &ResourceAppointmentsItemModel::projectDeleted); - disconnect( m_project, SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotResourceChanged(KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceChanged, this, &ResourceAppointmentsItemModel::slotResourceChanged ); - disconnect( m_project, SIGNAL(resourceGroupChanged(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupChanged(KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupChanged, this, &ResourceAppointmentsItemModel::slotResourceGroupChanged ); - disconnect( m_project, SIGNAL(resourceGroupToBeAdded(KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(KPlato::ResourceGroup*,int)) ); + disconnect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeInserted ); - disconnect( m_project, SIGNAL(resourceGroupToBeRemoved(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeRemoved ); - disconnect( m_project, SIGNAL(resourceToBeAdded(KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(KPlato::ResourceGroup*,int)) ); + disconnect( m_project, &Project::resourceToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceToBeInserted ); - disconnect( m_project, SIGNAL(resourceToBeRemoved(KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceToBeRemoved ); - disconnect( m_project, SIGNAL(resourceGroupAdded(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupInserted ); - disconnect( m_project, SIGNAL(resourceGroupRemoved(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupRemoved ); - disconnect( m_project, SIGNAL(resourceAdded(KPlato::Resource*)), this, SLOT(slotResourceInserted(KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceAdded, this, &ResourceAppointmentsItemModel::slotResourceInserted ); - disconnect( m_project, SIGNAL(resourceRemoved(KPlato::Resource*)), this, SLOT(slotResourceRemoved(KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceRemoved, this, &ResourceAppointmentsItemModel::slotResourceRemoved ); - disconnect( m_project, SIGNAL(defaultCalendarChanged(KPlato::Calendar*)), this, SLOT(slotCalendarChanged(KPlato::Calendar*)) ); + disconnect( m_project, &Project::defaultCalendarChanged, this, &ResourceAppointmentsItemModel::slotCalendarChanged ); - disconnect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); + disconnect( m_project, &Project::projectCalculated, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); - disconnect( m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); + disconnect( m_project, &Project::scheduleManagerChanged, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); foreach ( Resource *r, m_project->resourceList() ) { - disconnect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - disconnect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - disconnect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); + disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); + disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); + disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); + disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } } m_project = project; if ( m_project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotResourceChanged(KPlato::Resource*)) ); - connect( m_project, SIGNAL(resourceGroupChanged(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupChanged(KPlato::ResourceGroup*)) ); + connect(m_project, &Project::aboutToBeDeleted, this, &ResourceAppointmentsItemModel::projectDeleted); + connect( m_project, &Project::resourceChanged, this, &ResourceAppointmentsItemModel::slotResourceChanged ); + connect( m_project, &Project::resourceGroupChanged, this, &ResourceAppointmentsItemModel::slotResourceGroupChanged ); - connect( m_project, SIGNAL(resourceGroupToBeAdded(KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeInserted ); - connect( m_project, SIGNAL(resourceGroupToBeRemoved(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeRemoved ); - connect( m_project, SIGNAL(resourceToBeAdded(KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceToBeInserted ); - connect( m_project, SIGNAL(resourceToBeRemoved(KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(KPlato::Resource*)) ); + connect( m_project, &Project::resourceToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceToBeRemoved ); - connect( m_project, SIGNAL(resourceGroupAdded(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupInserted ); - connect( m_project, SIGNAL(resourceGroupRemoved(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupRemoved ); - connect( m_project, SIGNAL(resourceAdded(KPlato::Resource*)), this, SLOT(slotResourceInserted(KPlato::Resource*)) ); + connect( m_project, &Project::resourceAdded, this, &ResourceAppointmentsItemModel::slotResourceInserted ); - connect( m_project, SIGNAL(resourceRemoved(KPlato::Resource*)), this, SLOT(slotResourceRemoved(KPlato::Resource*)) ); + connect( m_project, &Project::resourceRemoved, this, &ResourceAppointmentsItemModel::slotResourceRemoved ); - connect( m_project, SIGNAL(defaultCalendarChanged(KPlato::Calendar*)), this, SLOT(slotCalendarChanged(KPlato::Calendar*)) ); + connect( m_project, &Project::defaultCalendarChanged, this, &ResourceAppointmentsItemModel::slotCalendarChanged ); - connect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); + connect( m_project, &Project::projectCalculated, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); - connect( m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); + connect( m_project, &Project::scheduleManagerChanged, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); foreach ( Resource *r, m_project->resourceList() ) { - connect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - connect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - connect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); + connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); + connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); + connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); + connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } } refreshData(); endResetModel(); emit refreshed(); } QDate ResourceAppointmentsItemModel::startDate() const { if ( m_project && m_manager ) { return m_project->startTime( id() ).date(); } return QDate::currentDate(); } QDate ResourceAppointmentsItemModel::endDate() const { if ( m_project && m_manager ) { return m_project->endTime( id() ).date(); } return QDate::currentDate(); } void ResourceAppointmentsItemModel::setScheduleManager( ScheduleManager *sm ) { if (sm == m_manager) { return; } beginResetModel(); debugPlan<scheduleId(); } Qt::ItemFlags ResourceAppointmentsItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); return flags &= ~Qt::ItemIsEditable; } QModelIndex ResourceAppointmentsItemModel::parent( const QModelIndex &idx ) const { if ( !idx.isValid() || m_project == 0 || m_manager == 0 ) { warnPlan<<"No data "<indexOf( r->parentGroup() ); p = createGroupIndex( row, 0, r->parentGroup() ); //debugPlan<<"Parent:"<parentGroup()->name(); Q_ASSERT( p.isValid() ); } } if ( ! p.isValid() && m_showInternal ) { Appointment *a = appointment( idx ); if ( a && a->resource() && a->resource()->resource() ) { Resource *r = a->resource()->resource(); int row = r->parentGroup()->indexOf( r ); p = createResourceIndex( row, 0, r ); //debugPlan<<"Parent:"<name(); Q_ASSERT( p.isValid() ); } } if ( ! p.isValid() && m_showExternal ) { Appointment *a = externalAppointment( idx ); Resource *r = parent( a ); if ( r ) { int row = r->parentGroup()->indexOf( r ); p = createResourceIndex( row, 0, r ); } } if ( ! p.isValid() ) { //debugPlan<<"Parent:"<resourceList() ) { if ( r->appointments( id() ).contains( const_cast( a ) ) ) { return r; } if ( r->externalAppointmentList().contains( const_cast( a ) ) ) { return r; } } return 0; } QModelIndex ResourceAppointmentsItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || m_manager == 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { //debugPlan<<"Group: "<resourceGroupAt( row )<resourceGroupAt( row ) ); } return QModelIndex(); } ResourceGroup *g = resourcegroup( parent ); if ( g ) { if ( row < g->numResources() ) { //debugPlan<<"Resource: "<resourceAt( row )<resourceAt( row ) ); } return QModelIndex(); } Resource *r = resource( parent ); if ( r && ( m_showInternal || m_showExternal ) ) { int num = m_showInternal ? r->numAppointments( id() ) : 0; if ( row < num ) { //debugPlan<<"Appointment: "<appointmentAt( row, m_manager->scheduleId() ); return createAppointmentIndex( row, column, r->appointmentAt( row, id() ) ); } int extRow = row - num; //debugPlan<<"Appointment: "<externalAppointmentList().value( extRow ); Q_ASSERT( extRow >= 0 && extRow < r->externalAppointmentList().count() ); return createExternalAppointmentIndex( row, column, r->externalAppointmentList().value( extRow ) ); } return QModelIndex(); } QModelIndex ResourceAppointmentsItemModel::index( const Resource *resource ) const { if ( m_project == 0 || resource == 0 ) { return QModelIndex(); } Resource *r = const_cast(resource); int row = -1; ResourceGroup *par = r->parentGroup(); if ( par ) { row = par->indexOf( r ); return createResourceIndex( row, 0, r ); } return QModelIndex(); } QModelIndex ResourceAppointmentsItemModel::index( const ResourceGroup *group ) const { if ( m_project == 0 || group == 0 ) { return QModelIndex(); } ResourceGroup *g = const_cast(group); int row = m_project->indexOf( g ); return createGroupIndex( row, 0, g ); } void ResourceAppointmentsItemModel::refresh() { refreshData(); emit refreshed(); } void ResourceAppointmentsItemModel::refreshData() { long id = m_manager == 0 ? -1 : m_manager->scheduleId(); //debugPlan<<"Schedule id: "< ec; QHash extEff; foreach ( Resource *r, m_project->resourceList() ) { foreach (Appointment* a, r->appointments( id )) { QDate s = a->startTime().date(); QDate e = a->endTime().date(); ec[ a ] = a->plannedPrDay( s, e ); if ( ! start.isValid() || s < start ) { start = s; } if ( ! end.isValid() || e > end ) { end = e; } //debugPlan<node()->node()->name()<<": "<externalAppointmentList() ) { extEff[ a ] = a->plannedPrDay( startDate(), endDate() ); //debugPlan<name()<auxcilliaryInfo()<<": "<name()<auxcilliaryInfo()<<": "<name()<<": "<numResourceGroups()<numResourceGroups(); } ResourceGroup *g = resourcegroup( parent ); if ( g ) { //debugPlan<name()<<": "<numResources()<numResources(); } Resource *r = resource( parent ); if ( r ) { int rows = m_showInternal ? r->numAppointments( id() ) : 0; rows += m_showExternal ? r->numExternalAppointments() : 0; return rows; } return 0; } QVariant ResourceAppointmentsItemModel::name( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::name( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::name( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return node->name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::name( const Appointment *app, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return app->auxcilliaryInfo(); case Qt::ToolTipRole: return i18n( "External project: %1", app->auxcilliaryInfo() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::ForegroundRole: if ( m_externalEffortMap.contains( app ) ) { return QColor( Qt::blue ); } break; } return QVariant(); } QVariant ResourceAppointmentsItemModel::total( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_showInternal ) { QList lst = res->appointments( m_manager->scheduleId() ); foreach ( Appointment *a, lst ) { if ( m_effortMap.contains( a ) ) { d += m_effortMap[ a ].totalEffort(); } } } if ( m_showExternal ) { QList lst = res->externalAppointmentList(); foreach ( Appointment *a, lst ) { if ( m_externalEffortMap.contains( a ) ) { d += m_externalEffortMap[ a ].totalEffort(); } } } return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } case Qt::EditRole: case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); } return QVariant(); } QVariant ResourceAppointmentsItemModel::total( const Resource *res, const QDate &date, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_showInternal ) { QList lst = res->appointments( id() ); foreach ( Appointment *a, lst ) { if ( m_effortMap.contains( a ) ) { d += m_effortMap[ a ].effortOnDate( date ); } } } if ( m_showExternal ) { QList lst = res->externalAppointmentList(); foreach ( Appointment *a, lst ) { if ( m_externalEffortMap.contains( a ) ) { d += m_externalEffortMap[ a ].effortOnDate( date ); } } } QString ds = QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); Duration avail = res->effort( 0, DateTime( date, QTime(0,0,0) ), Duration( 1.0, Duration::Unit_d ) ); QString avails = QLocale().toString( avail.toDouble( Duration::Unit_h ), 'f', 1 ); return QString( "%1(%2)").arg( ds).arg( avails ); } case Qt::EditRole: case Qt::ToolTipRole: return i18n( "The total booking on %1, along with the maximum hours for the resource", QLocale().toString( date, QLocale::ShortFormat ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); case Qt::BackgroundRole: { if ( res->calendar() && res->calendar()->state( date ) != CalendarDay::Working ) { QColor c( 0xf0f0f0 ); return QVariant::fromValue( c ); //return QVariant( Qt::cyan ); } break; } } return QVariant(); } QVariant ResourceAppointmentsItemModel::total( const Appointment *a, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_effortMap.contains( a ) ) { d = m_effortMap[ a ].totalEffort(); } else if ( m_externalEffortMap.contains( a ) ) { d = m_externalEffortMap[ a ].totalEffort(); } return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } case Qt::ToolTipRole: { if ( m_effortMap.contains( a ) ) { return i18n( "Total booking by this task" ); } else if ( m_externalEffortMap.contains( a ) ) { return i18n( "Total booking by the external project" ); } return QVariant(); } case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); case Qt::ForegroundRole: if ( m_externalEffortMap.contains( a ) ) { return QColor( Qt::blue ); } break; } return QVariant(); } QVariant ResourceAppointmentsItemModel::assignment( const Appointment *a, const QDate &date, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_effortMap.contains( a ) ) { if ( date < m_effortMap[ a ].startDate() || date > m_effortMap[ a ].endDate() ) { return QVariant(); } d = m_effortMap[ a ].effortOnDate( date ); return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } else if ( m_externalEffortMap.contains( a ) ) { if ( date < m_externalEffortMap[ a ].startDate() || date > m_externalEffortMap[ a ].endDate() ) { return QVariant(); } d = m_externalEffortMap[ a ].effortOnDate( date ); return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } return QVariant(); } case Qt::EditRole: case Qt::ToolTipRole: { if ( m_effortMap.contains( a ) ) { return i18n( "Booking by this task on %1", QLocale().toString( date, QLocale::ShortFormat ) ); } else if ( m_externalEffortMap.contains( a ) ) { return i18n( "Booking by external project on %1",QLocale().toString( date, QLocale::ShortFormat ) ); } return QVariant(); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); case Qt::ForegroundRole: if ( m_externalEffortMap.contains( a ) ) { return QColor( Qt::blue ); } break; case Qt::BackgroundRole: { Resource *r = parent( a ); if ( r && r->calendar() && r->calendar()->state( date ) != CalendarDay::Working ) { QColor c( 0xf0f0f0 ); return QVariant::fromValue( c ); //return QVariant( Qt::cyan ); } break; } } return QVariant(); } QVariant ResourceAppointmentsItemModel::notUsed( const ResourceGroup *, int role ) const { switch ( role ) { case Qt::DisplayRole: return QString(" "); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::EditRole: case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::data( const QModelIndex &index, int role ) const { if ( m_project == 0 || m_manager == 0 ) { return QVariant(); } QVariant result; if ( index.column() >= columnCount() ) { debugPlan<<"invalid display value column "<node()->node(), role ); break; case 1: result = total( a, role ); break; default: { QDate d = startDate().addDays( index.column()-2 ); result = assignment( a, d, role ); break; } } if ( result.isValid() ) { if ( role == Qt::DisplayRole && result.type() == QVariant::String && result.toString().isEmpty()) { // HACK to show focus in empty cells result = ' '; } return result; } return QVariant(); } a = externalAppointment( index ); if ( a ) { //debugPlan<<"external"<auxcilliaryInfo()<( resource( index ) ); if ( o ) { return o; } o = dynamic_cast( resourcegroup( index ) ); } return o; } Node *ResourceAppointmentsItemModel::node( const QModelIndex &index ) const { Appointment *a = appointment( index ); if ( a == 0 ) { return 0; } return a->node()->node(); } Appointment *ResourceAppointmentsItemModel::appointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } foreach ( Resource *r, m_project->resourceList() ) { foreach ( Appointment *a, r->appointments( id() ) ) { if ( a == index.internalPointer() ) { return a; } } } return 0; } Appointment *ResourceAppointmentsItemModel::externalAppointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } foreach ( Resource *r, m_project->resourceList() ) { foreach ( Appointment *a, r->externalAppointmentList() ) { if ( a == index.internalPointer() ) { return a; } } } return 0; } QModelIndex ResourceAppointmentsItemModel::createAppointmentIndex( int row, int col, void *ptr ) const { return createIndex( row, col, ptr ); } QModelIndex ResourceAppointmentsItemModel::createExternalAppointmentIndex( int row, int col, void *ptr ) const { if ( m_project == 0 || m_manager == 0 ) { return QModelIndex(); } QModelIndex i = createIndex( row, col, ptr ); //debugPlan<resourceList() ) { if ( r == index.internalPointer() ) { return r; } } return 0; } QModelIndex ResourceAppointmentsItemModel::createResourceIndex( int row, int col, void *ptr ) const { return createIndex( row, col, ptr ); } ResourceGroup *ResourceAppointmentsItemModel::resourcegroup( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } foreach ( ResourceGroup *r, m_project->resourceGroups() ) { if ( r == index.internalPointer() ) { return r; } } return 0; } QModelIndex ResourceAppointmentsItemModel::createGroupIndex( int row, int col, void *ptr ) const { return createIndex( row, col, ptr ); } void ResourceAppointmentsItemModel::slotCalendarChanged( Calendar* ) { foreach ( Resource *r, m_project->resourceList() ) { if ( r->calendar( true ) == 0 ) { slotResourceChanged( r ); } } } void ResourceAppointmentsItemModel::slotResourceChanged( Resource *res ) { ResourceGroup *g = res->parentGroup(); if ( g ) { int row = g->indexOf( res ); emit dataChanged( createResourceIndex( row, 0, res ), createResourceIndex( row, columnCount() - 1, res ) ); return; } } void ResourceAppointmentsItemModel::slotResourceGroupChanged( ResourceGroup *res ) { Project *p = res->project(); if ( p ) { int row = p->resourceGroups().indexOf( res ); emit dataChanged( createGroupIndex( row, 0, res ), createGroupIndex( row, columnCount() - 1, res ) ); } } //------------------------------------------------------- class Q_DECL_HIDDEN ResourceAppointmentsRowModel::Private { public: Private( Private *par=0, void *p=0, KPlato::ObjectType t=OT_None ) : parent( par ), ptr( p ), type( t ), internalCached( false ), externalCached( false ), intervalRow( -1 ) {} ~Private() { qDeleteAll( intervals ); } QVariant data( int column, long id = -1, int role = Qt::DisplayRole ) const; Private *parent; void *ptr; KPlato::ObjectType type; bool internalCached; bool externalCached; Private *intervalAt( int row ) const; // used by interval AppointmentInterval interval; protected: QVariant groupData( int column, int role ) const; QVariant resourceData( int column, long id, int role ) const; QVariant appointmentData( int column, int role ) const; QVariant externalData( int column, int role ) const; QVariant intervalData( int column, int role ) const; private: // used by resource Appointment internal; Appointment external; // used by appointment int intervalRow; mutable QMap intervals; }; QVariant ResourceAppointmentsRowModel::Private::data( int column, long id, int role ) const { if ( role == Role::ObjectType ) { return (int)type; } switch ( type ) { case OT_ResourceGroup: return groupData( column, role ); case OT_Resource: return resourceData( column, id, role ); case OT_Appointment: return appointmentData( column, role ); case OT_External: return externalData( column, role ); case OT_Interval: return intervalData( column, role ); default: break; } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::groupData( int column, int role ) const { ResourceGroup *g = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return g->name(); case ResourceAppointmentsRowModel::Type: return g->typeToString( true ); case ResourceAppointmentsRowModel::StartTime: return " "; case ResourceAppointmentsRowModel::EndTime: return " "; case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Role::Maximum ) { return g->units(); //TODO: Maximum Load } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::resourceData( int column, long id, int role ) const { KPlato::Resource *r = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return r->name(); case ResourceAppointmentsRowModel::Type: return r->typeToString( true ); case ResourceAppointmentsRowModel::StartTime: return " "; case ResourceAppointmentsRowModel::EndTime: return " "; case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Role::Maximum ) { return r->units(); //TODO: Maximum Load } else if ( role == Role::InternalAppointments ) { if ( ! internalCached ) { Resource *r = static_cast( ptr ); const_cast( this )->internal.clear(); foreach ( Appointment *a, r->appointments( id ) ) { const_cast( this )->internal += *a; } const_cast( this )->internalCached = true; } return QVariant::fromValue( (void*)(&internal) ); } else if ( role == Role::ExternalAppointments ) { if ( ! externalCached ) { Resource *r = static_cast( ptr ); const_cast( this )->external.clear(); foreach ( Appointment *a, r->externalAppointmentList() ) { Appointment e; e.setIntervals( a->intervals( r->startTime( id ), r->endTime( id ) ) ); const_cast( this )->external += e; } const_cast( this )->externalCached = true; } return QVariant::fromValue( (void*)(&external) ); } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::appointmentData( int column, int role ) const { KPlato::Appointment *a = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return a->node()->node()->name(); case ResourceAppointmentsRowModel::Type: return a->node()->node()->typeToString( true ); case ResourceAppointmentsRowModel::StartTime: return QLocale().toString( a->startTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::EndTime: return QLocale().toString( a->endTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Qt::ToolTipRole ) { Node *n = a->node()->node(); return xi18nc( "@info:tooltip", "%1: %2%3: %4", n->wbsCode(), n->name(), QLocale().toString( a->startTime(), QLocale::ShortFormat ), KFormat().formatDuration( ( a->endTime() - a->startTime() ).milliseconds() ) ); } else if ( role == Role::Maximum ) { return a->resource()->resource()->units(); //TODO: Maximum Load } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::externalData( int column, int role ) const { KPlato::Appointment *a = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return a->auxcilliaryInfo(); case ResourceAppointmentsRowModel::Type: return i18n( "Project" ); case ResourceAppointmentsRowModel::StartTime: return QLocale().toString( a->startTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::EndTime: return QLocale().toString( a->endTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Qt::ForegroundRole ) { return QColor( Qt::blue ); } else if ( role == Role::Maximum ) { KPlato::Resource *r = static_cast( parent->ptr ); return r->units(); //TODO: Maximum Load } return QVariant(); } ResourceAppointmentsRowModel::Private *ResourceAppointmentsRowModel::Private::intervalAt( int row ) const { Q_ASSERT( type == OT_Appointment || type == OT_External ); Private *p = intervals.value( row ); if ( p ) { return p; } Appointment *a = static_cast( ptr ); p = new Private( const_cast( this ), 0, OT_Interval ); p->intervalRow = row; p->interval = a->intervalAt( row ); intervals.insert( row, p ); return p; } QVariant ResourceAppointmentsRowModel::Private::intervalData( int column, int role ) const { if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return QVariant(); case ResourceAppointmentsRowModel::Type: return i18n( "Interval" ); case ResourceAppointmentsRowModel::StartTime: return QLocale().toString( interval.startTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::EndTime: return QLocale().toString( interval.endTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::Load: return interval.load(); } } else if ( role == Qt::ToolTipRole ) { Appointment *a = static_cast( parent->ptr ); if (a && a->node() && a->node()->node()) { Node *n = a->node()->node(); return xi18nc( "@info:tooltip", "%1: %2%3: %4Assigned: %5Available: %6", n->wbsCode(), n->name(), QLocale().toString( a->startTime(), QLocale::ShortFormat ), KFormat().formatDuration( ( a->endTime() - a->startTime() ).milliseconds() ), interval.load(), a->resource()->resource()->units() ); } } else if ( role == Role::Maximum ) { return parent->appointmentData( column, role ); } return QVariant(); } int ResourceAppointmentsRowModel::sortRole( int column ) const { switch ( column ) { case ResourceAppointmentsRowModel::StartTime: case ResourceAppointmentsRowModel::EndTime: return Qt::EditRole; default: break; } return Qt::DisplayRole; } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug dbg, KPlato::ObjectType t) { switch(t){ case KPlato::OT_None: dbg << "None"; break; case KPlato::OT_ResourceGroup: dbg << "Group"; break; case KPlato::OT_Resource: dbg << "Resource"; break; case KPlato::OT_Appointment: dbg << "Appointment"; break; case KPlato::OT_External: dbg << "External"; break; case KPlato::OT_Interval: dbg << "Interval"; break; default: dbg << "Unknown"; } return dbg; } QDebug operator<<( QDebug dbg, const ResourceAppointmentsRowModel::Private& s ) { dbg <<&s; return dbg; } QDebug operator<<( QDebug dbg, const ResourceAppointmentsRowModel::Private* s ) { if ( s == 0 ) { dbg<<"ResourceAppointmentsRowModel::Private[ ("<<(void*)s<<") ]"; } else { dbg << "ResourceAppointmentsRowModel::Private[ ("<<(void*)s<<") Type="<type<<" parent="; switch( s->type ) { case KPlato::OT_ResourceGroup: dbg<(s->ptr)->project()<(s->ptr)->project()->name(); dbg<<" ptr="<(s->ptr)<(s->ptr)->name(); break; case KPlato::OT_Resource: dbg<(s->parent->ptr)<(s->parent->ptr)->name(); dbg<<" ptr="<(s->ptr)<(s->ptr)->name(); break; case KPlato::OT_Appointment: case KPlato::OT_External: dbg<(s->parent->ptr)<(s->parent->ptr)->name(); dbg<<" ptr="<(s->ptr); break; case KPlato::OT_Interval: dbg<(s->parent->ptr)<<" ptr="<(s->ptr); break; default: dbg<parent<<" ptr="<ptr; break; } dbg<<" ]"; } return dbg; } #endif ResourceAppointmentsRowModel::ResourceAppointmentsRowModel( QObject *parent ) : ItemModelBase( parent ), m_schedule( 0 ) { } ResourceAppointmentsRowModel::~ResourceAppointmentsRowModel() { qDeleteAll( m_datamap ); } void ResourceAppointmentsRowModel::setProject( Project *project ) { beginResetModel(); //debugPlan<resourceList() ) { - disconnect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - disconnect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - disconnect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); + disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); + disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); + disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); + disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); } } m_project = project; if ( m_project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); + connect(m_project, &Project::aboutToBeDeleted, this, &ResourceAppointmentsRowModel::projectDeleted); - connect( m_project, SIGNAL(resourceGroupToBeAdded(KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAppointmentsRowModel::slotResourceGroupToBeInserted ); - connect( m_project, SIGNAL(resourceGroupToBeRemoved(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAppointmentsRowModel::slotResourceGroupToBeRemoved ); - connect( m_project, SIGNAL(resourceToBeAdded(KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceToBeAdded, this, &ResourceAppointmentsRowModel::slotResourceToBeInserted ); - connect( m_project, SIGNAL(resourceToBeRemoved(KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(KPlato::Resource*)) ); + connect( m_project, &Project::resourceToBeRemoved, this, &ResourceAppointmentsRowModel::slotResourceToBeRemoved ); - connect( m_project, SIGNAL(resourceGroupAdded(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupAdded, this, &ResourceAppointmentsRowModel::slotResourceGroupInserted ); - connect( m_project, SIGNAL(resourceGroupRemoved(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupRemoved, this, &ResourceAppointmentsRowModel::slotResourceGroupRemoved ); - connect( m_project, SIGNAL(resourceAdded(KPlato::Resource*)), this, SLOT(slotResourceInserted(KPlato::Resource*)) ); + connect( m_project, &Project::resourceAdded, this, &ResourceAppointmentsRowModel::slotResourceInserted ); - connect( m_project, SIGNAL(resourceRemoved(KPlato::Resource*)), this, SLOT(slotResourceRemoved(KPlato::Resource*)) ); + connect( m_project, &Project::resourceRemoved, this, &ResourceAppointmentsRowModel::slotResourceRemoved ); - connect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); + connect( m_project, &Project::projectCalculated, this, &ResourceAppointmentsRowModel::slotProjectCalculated ); foreach ( Resource *r, m_project->resourceList() ) { - connect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - connect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - connect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); + connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); + connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); + connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); + connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); } } endResetModel(); } void ResourceAppointmentsRowModel::setScheduleManager( ScheduleManager *sm ) { debugPlan<<"ResourceAppointmentsRowModel::setScheduleManager:"<expected() != m_schedule ) { beginResetModel(); m_manager = sm; m_schedule = sm ? sm->expected() : 0; qDeleteAll( m_datamap ); m_datamap.clear(); endResetModel(); } } long ResourceAppointmentsRowModel::id() const { return m_manager ? m_manager->scheduleId() : -1; } const QMetaEnum ResourceAppointmentsRowModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } int ResourceAppointmentsRowModel::columnCount( const QModelIndex & /*parent */) const { return columnMap().keyCount(); } int ResourceAppointmentsRowModel::rowCount( const QModelIndex & parent ) const { if ( m_project == 0 ) { return 0; } if ( ! parent.isValid() ) { return m_project->numResourceGroups(); } if ( ResourceGroup *g = resourcegroup( parent ) ) { return g->numResources(); } if ( m_manager == 0 ) { return 0; } if ( Resource *r = resource( parent ) ) { return r->numAppointments( id() ) + r->numExternalAppointments(); // number of tasks there are appointments with + external projects } if ( Appointment *a = appointment( parent ) ) { return a->count(); // number of appointment intervals } return 0; } QVariant ResourceAppointmentsRowModel::data( const QModelIndex &index, int role ) const { //debugPlan<(index.internalPointer() )->data( index.column(), id(), role ); } QVariant ResourceAppointmentsRowModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Vertical ) { return QVariant(); } if ( role == Qt::DisplayRole ) { switch ( section ) { case Name: return i18n( "Name" ); case Type: return i18n( "Type" ); case StartTime: return i18n( "Start Time" ); case EndTime: return i18n( "End Time" ); case Load: return xi18nc( "@title:column noun", "Load" ); } } if ( role == Qt::TextAlignmentRole ) { switch ( section ) { case Name: case Type: case StartTime: case EndTime: return (int)(Qt::AlignLeft|Qt::AlignVCenter); case Load: return (int)(Qt::AlignRight|Qt::AlignVCenter); } } return ItemModelBase::headerData( section, orientation, role ); } QModelIndex ResourceAppointmentsRowModel::parent( const QModelIndex &idx ) const { if ( !idx.isValid() || m_project == 0 ) { warnPlan<<"No data "<indexOf( pg ); p = const_cast( this )->createGroupIndex( row, 0, m_project ); //debugPlan<<"Parent:"<parentGroup()->name(); Q_ASSERT( p.isValid() ); return p; } if ( Resource *pr = parentResource( idx ) ) { // Appointment, parent is Resource int row = pr->parentGroup()->indexOf( pr ); p = const_cast( this )->createResourceIndex( row, 0, pr->parentGroup() ); //debugPlan<<"Parent:"<parentGroup()->name(); Q_ASSERT( p.isValid() ); return p; } if ( Appointment *a = parentAppointment( idx ) ) { // AppointmentInterval, parent is Appointment Private *pi = static_cast( idx.internalPointer() ); if ( pi->parent->type == OT_Appointment ) { Q_ASSERT( a->resource()->id() == id() ); if ( a->resource() && a->resource()->resource() ) { Resource *r = a->resource()->resource(); int row = r->indexOf( a, id() ); Q_ASSERT( row >= 0 ); p = const_cast( this )->createAppointmentIndex( row, 0, r ); //debugPlan<<"Parent:"<name(); Q_ASSERT( p.isValid() ); } } else if ( pi->parent->type == OT_External ) { Resource *r = static_cast( pi->parent->parent->ptr ); int row = r->externalAppointmentList().indexOf( a ); Q_ASSERT( row >= 0 ); row += r->numAppointments( id() ); p = const_cast( this )->createAppointmentIndex( row, 0, r ); } return p; } return QModelIndex(); } QModelIndex ResourceAppointmentsRowModel::index( ResourceGroup *g ) const { if ( m_project == 0 || g == 0 ) { return QModelIndex(); } return const_cast( this )->createGroupIndex( m_project->indexOf( g ), 0, m_project ); } QModelIndex ResourceAppointmentsRowModel::index( Resource *r ) const { if ( m_project == 0 || r == 0 ) { return QModelIndex(); } return const_cast( this )->createResourceIndex( r->parentGroup()->indexOf( r ), 0, r->parentGroup() ); } QModelIndex ResourceAppointmentsRowModel::index( Appointment *a ) const { if ( m_project == 0 || m_manager == 0 || a == 0 || a->resource()->resource() ) { return QModelIndex(); } Resource *r = a->resource()->resource(); return const_cast( this )->createAppointmentIndex( r->indexOf( a, id() ), 0, r ); } QModelIndex ResourceAppointmentsRowModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || row < 0 || column < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { //debugPlan<<"Group: "<resourceGroupAt( row ); return const_cast( this )->createGroupIndex( row, column, m_project ); } return QModelIndex(); } if ( ResourceGroup *g = resourcegroup( parent ) ) { if ( row < g->numResources() ) { //debugPlan<<"Resource: "<resourceAt( row )<( parent.internalPointer() ); return const_cast( this )->createResourceIndex( row, column, g ); } return QModelIndex(); } if ( m_manager == 0 ) { return QModelIndex(); } if ( Resource *r = resource( parent ) ) { int num = r->numAppointments( id() ) + r->numExternalAppointments(); if ( row < num ) { //debugPlan<<"Appointment: "<appointmentAt( row, m_manager->scheduleId() )<( parent.internalPointer() ); return const_cast( this )->createAppointmentIndex( row, column, r ); } return QModelIndex(); } if ( Appointment *a = appointment( parent ) ) { int num = a->count(); if ( row < num ) { //debugPlan<<"Appointment interval at: "<( parent.internalPointer() ); return const_cast( this )->createIntervalIndex( row, column, a ); } return QModelIndex(); } return QModelIndex(); } QModelIndex ResourceAppointmentsRowModel::createGroupIndex( int row, int column, Project *project ) { ResourceGroup *group = project->resourceGroupAt( row ); Private *p = m_datamap.value( (void*)group ); if ( p == 0 ) { p = new Private( 0, group, OT_ResourceGroup ); m_datamap.insert( group, p ); } QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } QModelIndex ResourceAppointmentsRowModel::createResourceIndex( int row, int column, ResourceGroup *g ) { Resource *res = g->resourceAt( row ); Private *p = m_datamap.value( (void*)res ); if ( p == 0 ) { Private *pg = m_datamap.value( g ); Q_ASSERT( pg ); p = new Private( pg, res, OT_Resource ); m_datamap.insert( res, p ); } QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } QModelIndex ResourceAppointmentsRowModel::createAppointmentIndex( int row, int column, Resource *r ) { Private *p = 0; KPlato::ObjectType type; Appointment *a = 0; if ( row < r->numAppointments( id() ) ) { a = r->appointmentAt( row, id() ); type = OT_Appointment; } else { a = r->externalAppointmentList().value( row - r->numAppointments( id() ) ); type = OT_External; } Q_ASSERT( a ); p = m_datamap.value( (void*)a ); if ( p == 0 ) { Private *pr = m_datamap.value( r ); Q_ASSERT( pr ); p = new Private( pr, a, type ); m_datamap.insert( a, p ); } QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } QModelIndex ResourceAppointmentsRowModel::createIntervalIndex( int row, int column, Appointment *a ) { AppointmentInterval i = a->intervalAt( row ); Private *pr = m_datamap.value( a ); Q_ASSERT( pr ); Private *p = pr->intervalAt( row ); Q_ASSERT( p ); QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } void ResourceAppointmentsRowModel::slotResourceToBeInserted( const ResourceGroup *group, int row ) { debugPlan<name()<( group ) ); beginInsertRows( i, row, row ); } void ResourceAppointmentsRowModel::slotResourceInserted( const Resource *r ) { debugPlan<name(); endInsertRows(); - connect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - connect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - connect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); + connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); + connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); + connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); + connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); } void ResourceAppointmentsRowModel::slotResourceToBeRemoved( const Resource *r ) { debugPlan<name(); int row = r->parentGroup()->indexOf( r ); beginRemoveRows( index( r->parentGroup() ), row, row ); - disconnect( r, SIGNAL(externalAppointmentToBeAdded(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeInserted(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentAdded(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentInserted(KPlato::Resource*,KPlato::Appointment*)) ); - disconnect( r, SIGNAL(externalAppointmentToBeRemoved(KPlato::Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(KPlato::Resource*,int)) ); - disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); - disconnect( r, SIGNAL(externalAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)), this, SLOT(slotAppointmentChanged(KPlato::Resource*,KPlato::Appointment*)) ); + disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); + disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); + disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); + disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); + disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); Private *p = 0; foreach ( Appointment *a, r->appointments( id() ) ) { // remove appointment p = m_datamap.value( a ); if ( p ) { m_datamap.remove( a ); delete p; } } foreach ( Appointment *a, r->externalAppointmentList() ) { // remove appointment p = m_datamap.value( a ); if ( p ) { m_datamap.remove( a ); delete p; } } // remove resource p = m_datamap.value( (void*)r ); if ( p ) { m_datamap.remove( const_cast( r ) ); delete p; } } void ResourceAppointmentsRowModel::slotResourceRemoved( const Resource *resource ) { Q_UNUSED(resource); //debugPlan<name(); endRemoveRows(); } void ResourceAppointmentsRowModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row ) { Q_UNUSED(group); beginInsertRows( QModelIndex(), row, row ); } void ResourceAppointmentsRowModel::slotResourceGroupInserted( const ResourceGroup*/*group*/ ) { endInsertRows(); } void ResourceAppointmentsRowModel::slotResourceGroupToBeRemoved( const ResourceGroup *group ) { //debugPlan<name()<indexOf( const_cast( group ) ); beginRemoveRows( QModelIndex(), row, row ); Private *p = m_datamap.value( const_cast( group ) ); if ( p ) { m_datamap.remove( const_cast( group ) ); delete p; } } void ResourceAppointmentsRowModel::slotResourceGroupRemoved( const ResourceGroup *group ) { Q_UNUSED(group); //debugPlan<name(); endRemoveRows(); } void ResourceAppointmentsRowModel::slotAppointmentToBeInserted( Resource *r, int row ) { Q_UNUSED(r); Q_UNUSED(row); // external appointments only, (Internal handled in slotProjectCalculated) } void ResourceAppointmentsRowModel::slotAppointmentInserted( Resource *r, Appointment *a ) { Q_UNUSED(a); beginResetModel(); // external appointments only, (Internal handled in slotProjectCalculated) Private *p = m_datamap.value( r ); if ( p ) { p->externalCached = false; } endResetModel(); } void ResourceAppointmentsRowModel::slotAppointmentToBeRemoved( Resource *r, int row ) { Q_UNUSED(row); // external appointments only, (Internal handled in slotProjectCalculated) Private *p = m_datamap.value( r ); if ( p ) { p->externalCached = false; } } void ResourceAppointmentsRowModel::slotAppointmentRemoved() { // external appointments only, (Internal handled in slotProjectCalculated) beginResetModel(); endResetModel(); } void ResourceAppointmentsRowModel::slotAppointmentChanged( Resource *r, Appointment *a ) { Q_UNUSED(r); Q_UNUSED(a); // external appointments only, (Internal handled in slotProjectCalculated) // will not happen atm } void ResourceAppointmentsRowModel::slotProjectCalculated( ScheduleManager *sm ) { if ( sm == m_manager ) { setScheduleManager( sm ); } } ResourceGroup *ResourceAppointmentsRowModel::parentGroup( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *ch = static_cast( index.internalPointer() ); if ( ch && ch->type == OT_Resource ) { return static_cast( ch->parent->ptr ); } return 0; } ResourceGroup *ResourceAppointmentsRowModel::resourcegroup( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && p->type == OT_ResourceGroup ) { return static_cast( p->ptr ); } return 0; } Resource *ResourceAppointmentsRowModel::parentResource( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *ch = static_cast( index.internalPointer() ); if ( ch && ( ch->type == OT_Appointment || ch->type == OT_External ) ) { return static_cast( ch->parent->ptr ); } return 0; } Resource *ResourceAppointmentsRowModel::resource( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && p->type == OT_Resource ) { return static_cast( p->ptr ); } return 0; } Appointment *ResourceAppointmentsRowModel::parentAppointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } Private *ch = static_cast( index.internalPointer() ); if ( ch && ch->type == OT_Interval ) { return static_cast( ch->parent->ptr ); } return 0; } Appointment *ResourceAppointmentsRowModel::appointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 || ! index.isValid() ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && ( p->type == OT_Appointment || p->type == OT_External ) ) { return static_cast( p->ptr ); } return 0; } AppointmentInterval *ResourceAppointmentsRowModel::interval( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && p->type == OT_Interval ) { return &( p->interval ); } return 0; } Node *ResourceAppointmentsRowModel::node( const QModelIndex &idx ) const { Appointment *a = appointment( idx ); return ( a && a->node() ? a->node()->node() : 0 ); } //--------------------------------------------- ResourceAppointmentsGanttModel::ResourceAppointmentsGanttModel( QObject *parent ) : ResourceAppointmentsRowModel( parent ) { } ResourceAppointmentsGanttModel::~ResourceAppointmentsGanttModel() { } QVariant ResourceAppointmentsGanttModel::data( const ResourceGroup *g, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeSummary; case KGantt::StartTimeRole: return g->startTime( id() ); case KGantt::EndTimeRole: return g->endTime( id() ); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const Resource *r, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeSummary; case KGantt::StartTimeRole: return r->startTime( id() ); case KGantt::EndTimeRole: return r->endTime( id() ); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const Appointment *a, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeMulti; case KGantt::StartTimeRole: return a->startTime(); case KGantt::EndTimeRole: return a->endTime(); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const AppointmentInterval *a, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeTask; case KGantt::StartTimeRole: return a->startTime(); case KGantt::EndTimeRole: return a->endTime(); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const QModelIndex &index, int role ) const { //debugPlan< Copyright (C) 2011, 2012 Dag Andersen 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. */ #include "kptresourcemodel.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptdebug.h" #include #include #include #include #include #include #include #ifdef PLAN_KCONTACTS_FOUND #include #include #endif namespace KPlato { //-------------------------------------- ResourceModel::ResourceModel( QObject *parent ) : QObject( parent ), m_project( 0 ) { } ResourceModel::~ResourceModel() { } const QMetaEnum ResourceModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } void ResourceModel::setProject( Project *project ) { m_project = project; } int ResourceModel::propertyCount() const { return columnMap().keyCount(); } QVariant ResourceModel::name( const Resource *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::ToolTipRole: if (res->isShared()) { return xi18nc("@info:tooltip", "%1 is a Shared resource and can thus be shared with other projects", res->name()); } if ( res->autoAllocate() ) { return xi18nc( "@info:tooltip", "%1:This resource will be automatically allocated to new tasks", res->name() ); } return res->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::DecorationRole: if ( res->isBaselined() ) { return koIcon("view-time-schedule-baselined"); } break; case Qt::CheckStateRole: return res->autoAllocate() ? Qt::Checked : Qt::Unchecked; default: break; } return QVariant(); } QVariant ResourceModel::name( const ResourceGroup *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::ToolTipRole: if (!res->isShared()) { return res->name(); } return xi18nc("@info:tooltip", "%1 is a Shared resource group and can thus be shared with other projects", res->name()); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::scope( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return res->isShared() ? i18n("Shared") : i18n("Local"); case Qt::ToolTipRole: if (!res->isShared()) { return xi18nc("@info:tooltip", "%1 is a Local resource and can only be used in this project", res->name()); } return xi18nc("@info:tooltip", "%1 is a Shared resource and can thus be shared with other projects", res->name()); case Qt::EditRole: return res->isShared() ? "Shared" : "Local"; case Role::EnumList: return QStringList() << i18n("Local") << i18n("Shared"); case Role::EnumListValue: return res->isShared() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::scope( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return res->isShared() ? i18n("Shared") : i18n("Local"); case Qt::ToolTipRole: if (!res->isShared()) { return xi18nc("@info:tooltip", "%1 is a Local resource group and can only be used in this project", res->name()); } return xi18nc("@info:tooltip", "%1 is a Shared resource group and can thus be shared with other projects", res->name()); case Qt::EditRole: return res->isShared() ? "Shared" : "Local"; case Role::EnumList: return QStringList() << i18n("Local") << i18n("Shared"); case Role::EnumListValue: return res->isShared() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::type( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return res->typeToString( true ); case Qt::EditRole: return res->typeToString( false ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::type( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return res->typeToString( true ); case Qt::EditRole: return res->typeToString( false ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::initials( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->initials(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::email( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->email(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::calendar( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( res->type() == Resource::Type_Team ) { return " "; } QString s = i18n( "None" ); Calendar *cal = res->calendar( true ); // don't check for default calendar if ( cal ) { s = cal->name(); } else if ( res->type() == Resource::Type_Work ) { // Do we get a default calendar cal = res->calendar(); if ( cal ) { s = i18nc( "Default (calendar name)", "Default (%1)", cal->name() ); } } return s; } case Qt::ToolTipRole: { if ( res->type() == Resource::Type_Team ) { return xi18nc( "@info:tooltip", "A team resource does not have a calendar" ); } QString s = xi18nc( "@info:tooltip", "No calendar" ); Calendar *cal = res->calendar( true ); // don't check for default calendar if ( cal ) { s = cal->name(); } else if ( res->type() == Resource::Type_Work ) { // Do we get a default calendar cal = res->calendar(); if ( cal ) { s = xi18nc( "@info:tooltip 1=calendar name", "Using default calendar: %1", cal->name() ); } } return s; } case Role::EnumList: { Calendar *cal = m_project->defaultCalendar(); QString s = i18n( "None" ); if ( cal && res->type() == Resource::Type_Work ) { s = i18nc( "Default (calendar name)", "Default (%1)", cal->name() ); } return QStringList() << s << m_project->calendarNames(); } case Qt::EditRole: case Role::EnumListValue: { Calendar *cal = res->calendar( true ); // don't check for default calendar return cal == 0 ? 0 : m_project->calendarNames().indexOf( cal->name() ) + 1; } case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::units( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return res->units(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::availableFrom( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( res->availableFrom(), QLocale::ShortFormat ); case Qt::EditRole: return res->availableFrom(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: { if ( res->availableFrom().isValid() ) { return xi18nc( "infor:tooltip", "Available from: %1", QLocale().toString( res->availableFrom(), QLocale::LongFormat ) ); } return xi18nc( "infor:tooltip", "Available from project target start time: %1", QLocale().toString( m_project->constraintStartTime(), QLocale::LongFormat ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::availableUntil( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( res->availableUntil(), QLocale::ShortFormat ); case Qt::EditRole: return res->availableUntil(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: { if ( res->availableUntil().isValid() ) { return xi18nc( "infor:tooltip", "Available until: %1", QLocale().toString( res->availableUntil(), QLocale::LongFormat ) ); } return xi18nc( "infor:tooltip", "Available from project target finish time: %1", QLocale().toString( m_project->constraintEndTime(), QLocale::LongFormat ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::normalRate( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( res->normalRate() ); case Qt::EditRole: return res->normalRate(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: return i18n( "Cost per hour, normal time: %1", m_project->locale()->formatMoney( res->normalRate() ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::overtimeRate( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( res->overtimeRate() ); case Qt::EditRole: return res->overtimeRate(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: return i18n( "Cost per hour, overtime: %1", m_project->locale()->formatMoney( res->overtimeRate() ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::account( const Resource *resource, int role ) const { switch ( role ) { case Qt::DisplayRole: { Account *a = resource->account(); return a == 0 ? i18n( "None" ) : a->name(); } case Qt::ToolTipRole: { Account *a = resource->account(); return i18n( "Account: %1", (a == 0 ? i18n( "None" ) : a->name() ) ); } case Role::EnumListValue: case Qt::EditRole: { Account *a = resource->account(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::data( const Resource *resource, int property, int role ) const { if ( role == Role::ObjectType ) { return OT_Resource; } QVariant result; if ( resource == 0 ) { return result; } switch ( property ) { case ResourceName: result = name( resource, role ); break; case ResourceScope: result = scope( resource, role ); break; case ResourceType: result = type( resource, role ); break; case ResourceInitials: result = initials( resource, role ); break; case ResourceEmail: result = email( resource, role ); break; case ResourceCalendar: result = calendar( resource, role ); break; case ResourceLimit: result = units( resource, role ); break; case ResourceAvailableFrom: result = availableFrom( resource, role ); break; case ResourceAvailableUntil: result = availableUntil( resource, role ); break; case ResourceNormalRate: result = normalRate( resource, role ); break; case ResourceOvertimeRate: result = overtimeRate( resource, role ); break; case ResourceAccount: result = account( resource, role ); break; default: debugPlan<<"data: invalid display value: property="<name()<<","<(group); beginInsertRows( index( group ), row, row ); } void ResourceItemModel::slotResourceInserted( const Resource *resource ) { //debugPlan<name(); Q_ASSERT( resource->parentGroup() == m_group ); #ifdef NDEBUG Q_UNUSED(resource) #endif endInsertRows(); m_group = 0; emit layoutChanged(); //HACK to make the right view react! Bug in qt? } void ResourceItemModel::slotResourceToBeRemoved( const Resource *resource ) { //debugPlan<name(); Q_ASSERT( m_resource == 0 ); #ifdef NDEBUG Q_UNUSED(resource) #endif m_resource = const_cast(resource); int row = index( resource ).row(); beginRemoveRows( index( resource->parentGroup() ), row, row ); } void ResourceItemModel::slotResourceRemoved( const Resource *resource ) { //debugPlan<name(); Q_ASSERT( resource == m_resource ); #ifdef NDEBUG Q_UNUSED(resource) #endif endRemoveRows(); m_resource = 0; } void ResourceItemModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row ) { //debugPlan<name(); Q_ASSERT( m_group == 0 ); m_group = const_cast(group); beginInsertRows( QModelIndex(), row, row ); } void ResourceItemModel::slotResourceGroupInserted( const ResourceGroup *group ) { //debugPlan<name(); Q_ASSERT( group == m_group ); #ifdef NDEBUG Q_UNUSED(group) #endif endInsertRows(); m_group = 0; } void ResourceItemModel::slotResourceGroupToBeRemoved( const ResourceGroup *group ) { //debugPlan<name(); Q_ASSERT( m_group == 0 ); m_group = const_cast(group); int row = index( group ).row(); beginRemoveRows( QModelIndex(), row, row ); } void ResourceItemModel::slotResourceGroupRemoved( const ResourceGroup *group ) { //debugPlan<name(); Q_ASSERT( group == m_group ); #ifdef NDEBUG Q_UNUSED(group) #endif endRemoveRows(); m_group = 0; } -void ResourceItemModel::slotLayoutChanged() -{ - emit layoutAboutToBeChanged(); - emit layoutChanged(); -} - void ResourceItemModel::setProject( Project *project ) { beginResetModel(); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); - disconnect( m_project, SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotResourceChanged(KPlato::Resource*)) ); - disconnect( m_project, SIGNAL(resourceGroupChanged(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupChanged(KPlato::ResourceGroup*)) ); + disconnect(m_project, &Project::aboutToBeDeleted, this, &ResourceItemModel::projectDeleted); + disconnect( m_project, &Project::localeChanged, this, &ResourceItemModel::slotLayoutChanged ); + disconnect( m_project, &Project::resourceChanged, this, &ResourceItemModel::slotResourceChanged ); + disconnect( m_project, &Project::resourceGroupChanged, this, &ResourceItemModel::slotResourceGroupChanged ); - disconnect( m_project, SIGNAL(resourceGroupToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const KPlato::ResourceGroup*,int)) ); + disconnect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceItemModel::slotResourceGroupToBeInserted ); - disconnect( m_project, SIGNAL(resourceGroupToBeRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceItemModel::slotResourceGroupToBeRemoved ); - disconnect( m_project, SIGNAL(resourceToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const KPlato::ResourceGroup*,int)) ); + disconnect( m_project, &Project::resourceToBeAdded, this, &ResourceItemModel::slotResourceToBeInserted ); - disconnect( m_project, SIGNAL(resourceToBeRemoved(const KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(const KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceToBeRemoved, this, &ResourceItemModel::slotResourceToBeRemoved ); - disconnect( m_project, SIGNAL(resourceGroupAdded(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupAdded, this, &ResourceItemModel::slotResourceGroupInserted ); - disconnect( m_project, SIGNAL(resourceGroupRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const KPlato::ResourceGroup*)) ); + disconnect( m_project, &Project::resourceGroupRemoved, this, &ResourceItemModel::slotResourceGroupRemoved ); - disconnect( m_project, SIGNAL(resourceAdded(const KPlato::Resource*)), this, SLOT(slotResourceInserted(const KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceAdded, this, &ResourceItemModel::slotResourceInserted ); - disconnect( m_project, SIGNAL(resourceRemoved(const KPlato::Resource*)), this, SLOT(slotResourceRemoved(const KPlato::Resource*)) ); + disconnect( m_project, &Project::resourceRemoved, this, &ResourceItemModel::slotResourceRemoved ); - disconnect( m_project, SIGNAL(defaultCalendarChanged(KPlato::Calendar*)), this, SLOT(slotCalendarChanged(KPlato::Calendar*)) ); + disconnect( m_project, &Project::defaultCalendarChanged, this, &ResourceItemModel::slotCalendarChanged ); } m_project = project; if ( m_project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); - connect( m_project, SIGNAL(resourceChanged(KPlato::Resource*)), this, SLOT(slotResourceChanged(KPlato::Resource*)) ); - connect( m_project, SIGNAL(resourceGroupChanged(KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupChanged(KPlato::ResourceGroup*)) ); + connect(m_project, &Project::aboutToBeDeleted, this, &ResourceItemModel::projectDeleted); + connect( m_project, &Project::localeChanged, this, &ResourceItemModel::slotLayoutChanged ); + connect( m_project, &Project::resourceChanged, this, &ResourceItemModel::slotResourceChanged ); + connect( m_project, &Project::resourceGroupChanged, this, &ResourceItemModel::slotResourceGroupChanged ); - connect( m_project, SIGNAL(resourceGroupToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceItemModel::slotResourceGroupToBeInserted ); - connect( m_project, SIGNAL(resourceGroupToBeRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceItemModel::slotResourceGroupToBeRemoved ); - connect( m_project, SIGNAL(resourceToBeAdded(const KPlato::ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const KPlato::ResourceGroup*,int)) ); + connect( m_project, &Project::resourceToBeAdded, this, &ResourceItemModel::slotResourceToBeInserted ); - connect( m_project, SIGNAL(resourceToBeRemoved(const KPlato::Resource*)), this, SLOT(slotResourceToBeRemoved(const KPlato::Resource*)) ); + connect( m_project, &Project::resourceToBeRemoved, this, &ResourceItemModel::slotResourceToBeRemoved ); - connect( m_project, SIGNAL(resourceGroupAdded(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupAdded, this, &ResourceItemModel::slotResourceGroupInserted ); - connect( m_project, SIGNAL(resourceGroupRemoved(const KPlato::ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const KPlato::ResourceGroup*)) ); + connect( m_project, &Project::resourceGroupRemoved, this, &ResourceItemModel::slotResourceGroupRemoved ); - connect( m_project, SIGNAL(resourceAdded(const KPlato::Resource*)), this, SLOT(slotResourceInserted(const KPlato::Resource*)) ); + connect( m_project, &Project::resourceAdded, this, &ResourceItemModel::slotResourceInserted ); - connect( m_project, SIGNAL(resourceRemoved(const KPlato::Resource*)), this, SLOT(slotResourceRemoved(const KPlato::Resource*)) ); + connect( m_project, &Project::resourceRemoved, this, &ResourceItemModel::slotResourceRemoved ); - connect( m_project, SIGNAL(defaultCalendarChanged(KPlato::Calendar*)), this, SLOT(slotCalendarChanged(KPlato::Calendar*)) ); + connect( m_project, &Project::defaultCalendarChanged, this, &ResourceItemModel::slotCalendarChanged ); } m_model.setProject( m_project ); endResetModel(); } Qt::ItemFlags ResourceItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); if ( !m_readWrite ) { //debugPlan<<"read only"<( object ( index ) ); if ( r != 0 ) { flags |= Qt::ItemIsDragEnabled; if (r->isShared()) { flags &= ~Qt::ItemIsEditable; if (index.column() == ResourceModel::ResourceName) { flags |= Qt::ItemIsUserCheckable; } return flags; } switch ( index.column() ) { case ResourceModel::ResourceName: flags |= Qt::ItemIsEditable | Qt::ItemIsUserCheckable; break; case ResourceModel::ResourceScope: flags &= ~Qt::ItemIsEditable; break; case ResourceModel::ResourceType: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; case ResourceModel::ResourceAccount: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; case ResourceModel::ResourceNormalRate: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; case ResourceModel::ResourceOvertimeRate: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; default: flags |= Qt::ItemIsEditable; } //debugPlan<<"resource"<( object( index ) ); if ( g ) { if (g->isShared()) { flags &= ~Qt::ItemIsEditable; return flags; } flags |= Qt::ItemIsDropEnabled; switch ( index.column() ) { case ResourceModel::ResourceName: flags |= Qt::ItemIsEditable; break; case ResourceModel::ResourceType: flags |= Qt::ItemIsEditable; break; default: flags &= ~Qt::ItemIsEditable; } //debugPlan<<"group"<parentGroup() ) { // only resources have parent int row = m_project->indexOf( r->parentGroup() ); return createIndex( row, 0, r->parentGroup() ); } return QModelIndex(); } QModelIndex ResourceItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || column < 0 || column >= columnCount() || row < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { return createIndex( row, column, m_project->resourceGroupAt( row ) ); } return QModelIndex(); } ResourceGroup *g = group( parent ); if ( g ) { if ( row < g->numResources() ) { return createIndex( row, column, g->resourceAt( row ) ); } return QModelIndex(); } return QModelIndex(); } QModelIndex ResourceItemModel::index( const Resource *resource, int column ) const { if ( m_project == 0 || resource == 0 ) { return QModelIndex(); } Resource *r = const_cast(resource); int row = -1; ResourceGroup *par = r->parentGroup(); if ( par ) { row = par->indexOf( r ); return createIndex( row, column, r ); } return QModelIndex(); } QModelIndex ResourceItemModel::index( const ResourceGroup *group, int column ) const { if ( m_project == 0 || group == 0 ) { return QModelIndex(); } ResourceGroup *g = const_cast(group); int row = m_project->indexOf( g ); return createIndex( row, column, g ); } int ResourceItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_model.propertyCount(); } int ResourceItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 ) { return 0; } if ( ! parent.isValid() ) { return m_project->numResourceGroups(); } ResourceGroup *g = group( parent ); if ( g ) { return g->numResources(); } return 0; } QVariant ResourceItemModel::name( const ResourceGroup *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ResourceItemModel::setName( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->name() ) { return false; } emit executeCommand( new ModifyResourceNameCmd( res, value.toString(), kundo2_i18n( "Modify resource name" ) ) ); return true; case Qt::CheckStateRole: emit executeCommand( new ModifyResourceAutoAllocateCmd( res, value.toBool(), kundo2_i18n( "Modify resource auto allocate" ) ) ); return true; } return false; } bool ResourceItemModel::setName( ResourceGroup *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->name() ) { return false; } emit executeCommand( new ModifyResourceGroupNameCmd( res, value.toString(), kundo2_i18n( "Modify resourcegroup name" ) ) ); return true; } return false; } QVariant ResourceItemModel::type( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return res->typeToString( true ); case Qt::EditRole: return res->typeToString( false ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ResourceItemModel::setType( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Resource::Type v; QStringList lst = res->typeToStringList( false ); if ( lst.contains( value.toString() ) ) { v = static_cast( lst.indexOf( value.toString() ) ); } else { v = static_cast( value.toInt() ); } if ( v == res->type() ) { return false; } emit executeCommand( new ModifyResourceTypeCmd( res, v, kundo2_i18n( "Modify resource type" ) ) ); return true; } } return false; } bool ResourceItemModel::setType( ResourceGroup *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { ResourceGroup::Type v; QStringList lst = res->typeToStringList( false ); if ( lst.contains( value.toString() ) ) { v = static_cast( lst.indexOf( value.toString() ) ); } else { v = static_cast( value.toInt() ); } if ( v == res->type() ) { return false; } emit executeCommand( new ModifyResourceGroupTypeCmd( res, v, kundo2_i18n( "Modify resourcegroup type" ) ) ); return true; } } return false; } bool ResourceItemModel::setInitials( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->initials() ) { return false; } emit executeCommand( new ModifyResourceInitialsCmd( res, value.toString(), kundo2_i18n( "Modify resource initials" ) ) ); return true; } return false; } bool ResourceItemModel::setEmail( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->email() ) { return false; } emit executeCommand( new ModifyResourceEmailCmd( res, value.toString(), kundo2_i18n( "Modify resource email" ) ) ); return true; } return false; } bool ResourceItemModel::setCalendar( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Calendar *c = 0; if ( value.toInt() > 0 ) { QStringList lst = m_model.calendar( res, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { c = m_project->calendarByName( lst.at( value.toInt() ) ); } } if ( c == res->calendar( true ) ) { return false; } emit executeCommand( new ModifyResourceCalendarCmd( res, c, kundo2_i18n( "Modify resource calendar" ) ) ); return true; } } return false; } bool ResourceItemModel::setUnits( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toInt() == res->units() ) { return false; } emit executeCommand( new ModifyResourceUnitsCmd( res, value.toInt(), kundo2_i18n( "Modify resource available units" ) ) ); return true; } return false; } bool ResourceItemModel::setAvailableFrom( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDateTime() == res->availableFrom() ) { return false; } emit executeCommand( new ModifyResourceAvailableFromCmd( res, value.toDateTime(), kundo2_i18n( "Modify resource available from" ) ) ); return true; } return false; } bool ResourceItemModel::setAvailableUntil( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDateTime() == res->availableUntil() ) { return false; } emit executeCommand( new ModifyResourceAvailableUntilCmd( res, value.toDateTime(), kundo2_i18n( "Modify resource available until" ) ) ); return true; } return false; } bool ResourceItemModel::setNormalRate( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDouble() == res->normalRate() ) { return false; } emit executeCommand( new ModifyResourceNormalRateCmd( res, value.toDouble(), kundo2_i18n( "Modify resource normal rate" ) ) ); return true; } return false; } bool ResourceItemModel::setOvertimeRate( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDouble() == res->overtimeRate() ) { return false; } emit executeCommand( new ModifyResourceOvertimeRateCmd( res, value.toDouble(), kundo2_i18n( "Modify resource overtime rate" ) ) ); return true; } return false; } bool ResourceItemModel::setAccount( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Account *a = 0; if ( value.type() == QVariant::Int ) { QStringList lst = m_model.account( res, Role::EnumList ).toStringList(); if ( value.toInt() >= lst.count() ) { return false; } a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); } else if ( value.type() == QVariant::String ) { a = m_project->accounts().findAccount( value.toString() ); } Account *old = res->account(); if ( old != a ) { emit executeCommand( new ResourceModifyAccountCmd( *res, old, a, kundo2_i18n( "Modify resource account" ) ) ); return true; } } default: break; } return false; } QVariant ResourceItemModel::notUsed( const ResourceGroup *, int role ) const { switch ( role ) { case Qt::DisplayRole: return QString(" "); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::EditRole: case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceItemModel::data( const QModelIndex &index, int role ) const { QVariant result; QObject *obj = object( index ); if ( obj == 0 ) { return QVariant(); } if ( role == Qt::TextAlignmentRole ) { // use same alignment as in header (headers always horizontal) return headerData( index.column(), Qt::Horizontal, role ); } Resource *r = qobject_cast( obj ); if ( r ) { result = m_model.data( r, index.column(), role ); } else { ResourceGroup *g = qobject_cast( obj ); if ( g ) { result = m_model.data( g, index.column(), role ); } } return result; } bool ResourceItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } if (role != Qt::EditRole && role != Qt::CheckStateRole) { return false; } if ((flags( index ) & (Qt::ItemIsEditable | Qt::ItemIsUserCheckable)) == 0) { return false; } QObject *obj = object( index ); Resource *r = qobject_cast( obj ); if ( r ) { switch (index.column()) { case ResourceModel::ResourceName: return setName( r, value, role ); case ResourceModel::ResourceScope: return false; // Not editable case ResourceModel::ResourceType: return setType( r, value, role ); case ResourceModel::ResourceInitials: return setInitials( r, value, role ); case ResourceModel::ResourceEmail: return setEmail( r, value, role ); case ResourceModel::ResourceCalendar: return setCalendar( r, value, role ); case ResourceModel::ResourceLimit: return setUnits( r, value, role ); case ResourceModel::ResourceAvailableFrom: return setAvailableFrom( r, value, role ); case ResourceModel::ResourceAvailableUntil: return setAvailableUntil( r, value, role ); case ResourceModel::ResourceNormalRate: return setNormalRate( r, value, role ); case ResourceModel::ResourceOvertimeRate: return setOvertimeRate( r, value, role ); case ResourceModel::ResourceAccount: return setAccount( r, value, role ); default: qWarning("data: invalid display value column %d", index.column()); return false; } } else { ResourceGroup *g = qobject_cast( obj ); if ( g ) { switch (index.column()) { case ResourceModel::ResourceName: return setName( g, value, role ); case ResourceModel::ResourceScope: return false; // Not editable case ResourceModel::ResourceType: return setType( g, value, role ); default: qWarning("data: invalid display value column %d", index.column()); return false; } } } return false; } QVariant ResourceItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole || role == Qt::TextAlignmentRole ) { return m_model.headerData( section, role ); } } if ( role == Qt::ToolTipRole ) { return m_model.headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QAbstractItemDelegate *ResourceItemModel::createDelegate( int col, QWidget *parent ) const { switch ( col ) { case ResourceModel::ResourceType: return new EnumDelegate( parent ); case ResourceModel::ResourceCalendar: return new EnumDelegate( parent ); case ResourceModel::ResourceAvailableFrom: return new DateTimeCalendarDelegate( parent ); case ResourceModel::ResourceAvailableUntil: return new DateTimeCalendarDelegate( parent ); case ResourceModel::ResourceAccount: return new EnumDelegate( parent ); default: break; } return 0; } QObject *ResourceItemModel::object( const QModelIndex &index ) const { QObject *o = 0; if ( index.isValid() ) { Q_ASSERT( m_project ); //debugPlan<<(void*)index.internalPointer()<resourceGroups()<resourceList(); Q_ASSERT(m_project->resourceGroups().contains(static_cast(index.internalPointer())) || m_project->resourceList().contains(static_cast(index.internalPointer()))); o = static_cast( index.internalPointer() ); Q_ASSERT( o ); } return o; } ResourceGroup *ResourceItemModel::group( const QModelIndex &index ) const { return qobject_cast( object( index ) ); } Resource *ResourceItemModel::resource( const QModelIndex &index ) const { return qobject_cast( object( index ) ); } void ResourceItemModel::slotCalendarChanged( Calendar* ) { foreach ( Resource *r, m_project->resourceList() ) { if ( r->calendar( true ) == 0 ) { slotResourceChanged( r ); } } } void ResourceItemModel::slotResourceChanged( Resource *res ) { ResourceGroup *g = res->parentGroup(); if ( g ) { int row = g->indexOf( res ); emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) ); return; } } void ResourceItemModel::slotResourceGroupChanged( ResourceGroup *res ) { Project *p = res->project(); if ( p ) { int row = p->resourceGroups().indexOf( res ); emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) ); } } Qt::DropActions ResourceItemModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } bool ResourceItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ) { if ( data->hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) { QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); int i = 0; foreach ( Resource *r, resourceList( stream ) ) { if (r->isShared()) { return false; } } } //debugPlan<( object( index ) ); // Allow only on group default: break; } return false; } QStringList ResourceItemModel::mimeTypes() const { return QStringList() #ifdef PLAN_KDEPIMLIBS_FOUND << "text/x-vcard" << "text/directory" << "text/uri-list" #endif << "application/x-vnd.kde.plan.resourceitemmodel.internal"; } void ResourceItemModel::slotDataArrived( KIO::Job *job, const QByteArray &data ) { if ( m_dropDataMap.contains( job ) ) { m_dropDataMap[ job ].data += data; } } void ResourceItemModel::slotJobFinished( KJob *job ) { if ( job->error() || ! m_dropDataMap.contains( job ) ) { debugPlan<<(job->error() ? "Job error":"Error: no such job"); } else if ( QMimeDatabase().mimeTypeForData( m_dropDataMap[ job ].data ).inherits(QStringLiteral("text/x-vcard") ) ) { ResourceGroup *g = 0; if ( m_dropDataMap[ job ].parent.isValid() ) { g = qobject_cast( object( m_dropDataMap[ job ].parent ) ); } else { g = qobject_cast( object( index( m_dropDataMap[ job ].row, m_dropDataMap[ job ].column, m_dropDataMap[ job ].parent ) ) ); } if ( g == 0 ) { debugPlan<<"No group"<findResource( uid ) ) { r->setId( uid ); } r->setName( lst[a].formattedName() ); r->setEmail( lst[a].preferredEmail() ); m->addCommand( new AddResourceCmd( group, r ) ); } if ( m->isEmpty() ) { delete m; return false; } emit executeCommand( m ); return true; #else Q_UNUSED(group); Q_UNUSED(data); return false; #endif } bool ResourceItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ) { debugPlan< 0) { return false; } ResourceGroup *g = 0; if ( parent.isValid() ) { g = qobject_cast( object( parent ) ); } else { g = qobject_cast( object( index( row, column, parent ) ) ); } if ( g == 0 ) { debugPlan<<"No group"<formats()<name(); if ( data->hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) { debugPlan<data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); int i = 0; foreach ( Resource *r, resourceList( stream ) ) { if ( r->parentGroup() == g ) { continue; } if ( m == 0 ) m = new MacroCommand( KUndo2MagicString() ); m->addCommand( new MoveResourceCmd( g, r ) ); ++i; } if ( m ) { KUndo2MagicString msg = kundo2_i18np( "Move resource", "Move %1 resources", i ); MacroCommand *c = new MacroCommand( msg ); c->addCommand( m ); emit executeCommand( c ); } return true; } if ( action == Qt::CopyAction ) { MacroCommand *m = 0; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); int i = 0; foreach ( Resource *r, resourceList( stream ) ) { Resource *nr = new Resource( r ); if ( m == 0 ) m = new MacroCommand( KUndo2MagicString() ); m->addCommand( new AddResourceCmd( g, nr ) ); ++i; } if ( m ) { KUndo2MagicString msg = kundo2_i18np( "Copy resource", "Copy %1 resources", i ); MacroCommand *c = new MacroCommand( msg ); c->addCommand( m ); emit executeCommand( c ); } return true; } return true; } if ( data->hasFormat( "text/x-vcard" ) || data->hasFormat( "text/directory" ) ) { if ( action != Qt::CopyAction ) { return false; } QString f = data->hasFormat( "text/x-vcard" ) ? "text/x-vcard" : "text/directory"; return createResources( g, data->data( f ) ); } if ( data->hasFormat( "text/uri-list" ) ) { const QList urls = data->urls(); if ( urls.isEmpty() ) { return false; } bool result = false; foreach ( const QUrl &url, urls ) { if ( url.scheme() != "akonadi" ) { debugPlan<setSide( KIO::StatJob::SourceSide ); const bool isUrlReadable = statJob->exec(); if (! isUrlReadable ) { debugPlan<start(); result = true; } return result; } return false; } QList ResourceItemModel::resourceList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Resource *r = m_project->findResource( id ); if ( r ) { lst << r; } } debugPlan< rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<( object( index ) ); if ( r ) { rows << index.row(); stream << r->id(); } else if ( ::qobject_cast( object( index ) ) ) { rows.clear(); break; } } } if ( rows.isEmpty() ) { delete m; return 0; } m->setData("application/x-vnd.kde.plan.resourceitemmodel.internal", encodedData); return m; } QModelIndex ResourceItemModel::insertGroup( ResourceGroup *g ) { //debugPlan; emit executeCommand( new AddResourceGroupCmd( m_project, g, kundo2_i18n( "Add resource group" ) ) ); int row = m_project->resourceGroups().indexOf( g ); if ( row != -1 ) { return createIndex( row, 0, g ); } return QModelIndex(); } QModelIndex ResourceItemModel::insertResource( ResourceGroup *g, Resource *r, Resource * /*after*/ ) { //debugPlan; emit executeCommand( new AddResourceCmd( g, r, kundo2_i18n( "Add resource" ) ) ); int row = g->indexOf( r ); if ( row != -1 ) { return createIndex( row, 0, r ); } return QModelIndex(); } int ResourceItemModel::sortRole( int column ) const { switch ( column ) { case ResourceModel::ResourceAvailableFrom: case ResourceModel::ResourceAvailableUntil: return Qt::EditRole; default: break; } return Qt::DisplayRole; } //------------------- ResourceItemSFModel::ResourceItemSFModel( QObject *parent ) : QSortFilterProxyModel( parent ) { setDynamicSortFilter( true ); setSourceModel( new ResourceItemModel( this ) ); } void ResourceItemSFModel::setProject( Project *project ) { static_cast( sourceModel() )->setProject( project ); } Resource *ResourceItemSFModel::resource( const QModelIndex &idx ) const { return static_cast( sourceModel() )->resource( mapToSource( idx ) ); } QModelIndex ResourceItemSFModel::index( Resource *r ) const { return mapFromSource( static_cast( sourceModel() )->index( r ) ); } Qt::ItemFlags ResourceItemSFModel::flags( const QModelIndex & index ) const { Qt::ItemFlags f = QSortFilterProxyModel::flags( index ); if ( index.isValid() && ! parent( index ).isValid() ) { // group, not selectable f &= ~Qt::ItemIsSelectable; } return f; } void ResourceItemSFModel::addFilteredResource( const Resource *r ) { if ( ! m_filteredResources.contains( r ) ) { m_filteredResources << r; } } bool ResourceItemSFModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const { //TODO make this general filter ResourceItemModel *m = static_cast( sourceModel() ); if ( m->index( source_row, ResourceModel::ResourceType, source_parent ).data( Role::EnumListValue ).toInt() == ResourceGroup::Type_Work ) { return false; } QModelIndex idx = m->index( source_row, 0, source_parent ); return ! m_filteredResources.contains( m->resource( idx ) ); } //----------------------- AllocatedResourceItemModel::AllocatedResourceItemModel( QObject *parent ) : QSortFilterProxyModel( parent ), m_task( 0 ) { setDynamicSortFilter( true ); setSourceModel( new ResourceItemModel( this ) ); } int AllocatedResourceItemModel::columnCount( const QModelIndex &idx ) const { Q_UNUSED(idx); return 2; } Project *AllocatedResourceItemModel::project() const { return static_cast( sourceModel() )->project(); } void AllocatedResourceItemModel::setProject( Project *project ) { debugPlan<project()<<"="<project(); if ( p ) { - disconnect(p, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*))); + disconnect(p, &Project::nodeChanged, this, &AllocatedResourceItemModel::slotNodeChanged); } static_cast( sourceModel() )->setProject( project ); if ( project ) { - connect(project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*))); + connect(project, &Project::nodeChanged, this, &AllocatedResourceItemModel::slotNodeChanged); } debugPlan<rowCount(); } void AllocatedResourceItemModel::reset() { beginResetModel(); endResetModel(); emit expandAll(); emit resizeColumnToContents( 0 ); } void AllocatedResourceItemModel::slotNodeChanged( Node *n ) { debugPlan<<(n==m_task)<name(); if ( n != m_task ) { return; } reset(); } Task *AllocatedResourceItemModel::task() const { return m_task; } void AllocatedResourceItemModel::setTask( Task *task ) { debugPlan<name():""); m_task = task; reset(); debugPlan<rowCount(); } QObject* AllocatedResourceItemModel::object(const QModelIndex& idx) const { return static_cast( sourceModel() )->object( mapToSource( idx ) ); } Resource *AllocatedResourceItemModel::resource( const QModelIndex &idx ) const { return qobject_cast( object( idx ) ); } QModelIndex AllocatedResourceItemModel::index( Resource *r ) const { return mapFromSource( static_cast( sourceModel() )->index( r ) ); } Qt::ItemFlags AllocatedResourceItemModel::flags( const QModelIndex & index ) const { Qt::ItemFlags f = QSortFilterProxyModel::flags( index ); f &= ~Qt::ItemIsUserCheckable; return f; } QVariant AllocatedResourceItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if ( section == 1 ) { if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { return xi18nc( "@title:column", "Allocation" ); } return QVariant(); } return QSortFilterProxyModel::headerData( section, orientation, role ); } QVariant AllocatedResourceItemModel::allocation( const Resource *res, int role ) const { ResourceRequest *rr = m_task->requests().find( res ); ResourceGroupRequest *gr = m_task->requests().find( res->parentGroup() ); if ( rr == 0 || gr == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: { case Qt::EditRole: // xgettext: no-c-format return i18nc( "%", "%1%",rr->units() ); } case Qt::ToolTipRole: { if ( rr->units() == 0 ) { return xi18nc( "@info:tooltip", "Not allocated" ); } return xi18nc( "@info:tooltip", "%1 allocated out of %2 available", gr->count(), res->parentGroup()->numResources() ); } default: break; } return QVariant(); } QVariant AllocatedResourceItemModel::allocation( const ResourceGroup *res, int role ) const { ResourceGroupRequest *gr = m_task->requests().find( res ); if ( gr == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return QString( "%1 (%2)" ).arg( gr->units() ).arg( gr->count() ); case Qt::ToolTipRole: { QString s1 = i18ncp( "@info:tooltip", "%1 resource requested for dynamic allocation", "%1 resources requested for dynamic allocation", gr->units() ); QString s2 = i18ncp( "@info:tooltip", "%1 resource allocated", "%1 resources allocated", gr->count() ); return xi18nc( "@info:tooltip", "%1%2", s1, s2 ); } case Qt::WhatsThisRole: { return xi18nc( "@info:whatsthis", "Group allocations" "You can allocate a number of resources from a group and let" " the scheduler select from the available resources at the time of scheduling." " These dynamically allocated resources will be in addition to any resource you have allocated specifically." ); } case Role::Minimum: { return 0; } case Role::Maximum: { return res->numResources() - gr->units(); } default: break; } return QVariant(); } QVariant AllocatedResourceItemModel::data(const QModelIndex& idx, int role) const { if ( m_task == 0 || role == Qt::CheckStateRole || role == Qt::DecorationRole ) { return QVariant(); } if ( idx.column() == 1 ) { switch ( role ) { case Qt::TextAlignmentRole: return Qt::AlignLeft; default: { QObject *o = object( idx ); Resource *r = qobject_cast( o ); if ( r ) { return allocation( r, role ); } ResourceGroup *g = qobject_cast( o ); if ( g ) { return allocation( g, role ); } break; } return QVariant(); } } return QSortFilterProxyModel::data( idx, role ); } bool AllocatedResourceItemModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const { if ( m_task == 0 ) { return false; } QModelIndex idx = sourceModel()->index( source_row, 0, source_parent ); if ( ! idx.isValid() ) { return false; } bool result = false; const ResourceRequestCollection &req = m_task->requests(); if ( source_parent.isValid() ) { const Resource *r = static_cast( sourceModel() )->resource( idx ); result = (bool) req.find( r ); } else { const ResourceGroup *g = static_cast( sourceModel() )->group( idx ); ResourceGroupRequest *gr = req.find( g ); result = (bool) gr && ( gr->units() > 0 || gr->count() > 0 ); } debugPlan< 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. */ #ifndef KPTRESOURCEMODEL_H #define KPTRESOURCEMODEL_H #include "planmodels_export.h" #include #include #include class QByteArray; namespace KIO { class Job; } class KJob; namespace KPlato { class Project; class Resource; class ResourceGroup; class Calendar; class Task; class Node; class PLANMODELS_EXPORT ResourceModel : public QObject { Q_OBJECT public: explicit ResourceModel( QObject *parent = 0 ); ~ResourceModel(); enum Properties { ResourceName = 0, ResourceScope, ResourceType, ResourceInitials, ResourceEmail, ResourceCalendar, ResourceLimit, ResourceAvailableFrom, ResourceAvailableUntil, ResourceNormalRate, ResourceOvertimeRate, ResourceAccount }; Q_ENUM(Properties) const QMetaEnum columnMap() const; void setProject( Project *project ); int propertyCount() const; QVariant data( const Resource *resource, int property, int role = Qt::DisplayRole ) const; QVariant data( const ResourceGroup *group, int property, int role = Qt::DisplayRole ) const; static QVariant headerData( int section, int role = Qt::DisplayRole ); QVariant name( const Resource *res, int role ) const; QVariant scope( const Resource *res, int role ) const; QVariant type( const Resource *res, int role ) const; QVariant initials( const Resource *res, int role ) const; QVariant email( const Resource *res, int role ) const; QVariant calendar( const Resource *res, int role ) const; QVariant units( const Resource *res, int role ) const; QVariant availableFrom( const Resource *res, int role ) const; QVariant availableUntil( const Resource *res, int role ) const; QVariant normalRate( const Resource *res, int role ) const; QVariant overtimeRate( const Resource *res, int role ) const; QVariant account( const Resource *res, int role ) const; QVariant name( const ResourceGroup *res, int role ) const; QVariant scope( const ResourceGroup *res, int role ) const; QVariant type( const ResourceGroup *res, int role ) const; private: Project *m_project; }; class PLANMODELS_EXPORT ResourceItemModel : public ItemModelBase { Q_OBJECT public: explicit ResourceItemModel( QObject *parent = 0 ); ~ResourceItemModel(); virtual const QMetaEnum columnMap() const { return m_model.columnMap(); } virtual void setProject( Project *project ); virtual Qt::ItemFlags flags( const QModelIndex & index ) const; virtual QModelIndex parent( const QModelIndex & index ) const; virtual QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const; QModelIndex index( const ResourceGroup *group, int column = 0 ) const; QModelIndex index( const Resource *resource, int column = 0 ) const; virtual int columnCount( const QModelIndex & parent = QModelIndex() ) const; virtual int rowCount( const QModelIndex & parent = QModelIndex() ) const; virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QStringList mimeTypes () const; virtual Qt::DropActions supportedDropActions() const; virtual bool dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ); virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); QMimeData *mimeData( const QModelIndexList & indexes ) const; QAbstractItemDelegate *createDelegate( int col, QWidget *parent ) const; QObject *object( const QModelIndex &index ) const; ResourceGroup *group( const QModelIndex &index ) const; Resource *resource( const QModelIndex &index ) const; QModelIndex insertGroup( ResourceGroup *g ); QModelIndex insertResource( ResourceGroup *g, Resource *r, Resource *after = 0 ); virtual int sortRole( int column ) const; protected Q_SLOTS: void slotResourceChanged(KPlato::Resource*); void slotResourceGroupChanged(KPlato::ResourceGroup *); void slotResourceGroupToBeInserted(const KPlato::ResourceGroup *group, int row); void slotResourceGroupInserted(const KPlato::ResourceGroup *group); void slotResourceGroupToBeRemoved(const KPlato::ResourceGroup *group); void slotResourceGroupRemoved(const KPlato::ResourceGroup *group); void slotResourceToBeInserted(const KPlato::ResourceGroup *group, int row); void slotResourceInserted(const KPlato::Resource *resource); void slotResourceToBeRemoved(const KPlato::Resource *resource); void slotResourceRemoved(const KPlato::Resource *resource); void slotCalendarChanged(KPlato::Calendar* cal); - void slotLayoutChanged(); void slotDataArrived( KIO::Job *job, const QByteArray &data ); void slotJobFinished( KJob *job ); protected: QVariant notUsed( const ResourceGroup *res, int role ) const; QVariant name( const ResourceGroup *res, int role ) const; bool setName( Resource *res, const QVariant &value, int role ); bool setName( ResourceGroup *res, const QVariant &value, int role ); QVariant type( const ResourceGroup *res, int role ) const; bool setType( Resource *res, const QVariant &value, int role ); bool setType( ResourceGroup *res, const QVariant &value, int role ); bool setInitials( Resource *res, const QVariant &value, int role ); bool setEmail( Resource *res, const QVariant &value, int role ); bool setCalendar( Resource *res, const QVariant &value, int role ); bool setUnits( Resource *res, const QVariant &value, int role ); bool setAvailableFrom( Resource *res, const QVariant &value, int role ); bool setAvailableUntil( Resource *res, const QVariant &value, int role ); bool setNormalRate( Resource *res, const QVariant &value, int role ); bool setOvertimeRate( Resource *res, const QVariant &value, int role ); bool setAccount( Resource *res, const QVariant &value, int role ); QList resourceList( QDataStream &stream ); bool createResources( ResourceGroup *group, const QByteArray &data ); private: ResourceGroup *m_group; // Used for sanity checks Resource *m_resource; // Used for sanity checks ResourceModel m_model; struct DropData { Qt::DropAction action; int row; int column; QModelIndex parent; QByteArray data; } m_dropData; QMap m_dropDataMap; }; class PLANMODELS_EXPORT ResourceItemSFModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ResourceItemSFModel(QObject *parent = 0); void setProject( Project *project ); Resource *resource( const QModelIndex &index ) const; using QAbstractProxyModel::index; QModelIndex index( Resource *r ) const; Qt::ItemFlags flags( const QModelIndex & index ) const; void addFilteredResource( const Resource *r ); protected: bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const; QList m_filteredResources; }; class PLANMODELS_EXPORT AllocatedResourceItemModel : public QSortFilterProxyModel { Q_OBJECT public: explicit AllocatedResourceItemModel(QObject *parent = 0); int columnCount( const QModelIndex &idx ) const; Project *project() const; Task *task() const; Resource *resource( const QModelIndex &index ) const; using QAbstractProxyModel::index; QModelIndex index( Resource *r ) const; Qt::ItemFlags flags( const QModelIndex & index ) const; QVariant headerData( int section, Qt::Orientation orientation, int role ) const; QVariant data( const QModelIndex &idx, int role ) const; public Q_SLOTS: void setProject(KPlato::Project *project); void setTask(KPlato::Task *task); Q_SIGNALS: void expandAll(); void resizeColumnToContents( int ); protected Q_SLOTS: void slotNodeChanged(KPlato::Node *n); protected: bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const; void reset(); QObject *object( const QModelIndex &idx ) const; QVariant allocation( const Resource *r, int role ) const; QVariant allocation( const ResourceGroup *g, int role ) const; Task *m_task; }; } //KPlato namespace #endif diff --git a/src/libs/models/kptschedulemodel.cpp b/src/libs/models/kptschedulemodel.cpp index ecafa0bc..1769a91a 100644 --- a/src/libs/models/kptschedulemodel.cpp +++ b/src/libs/models/kptschedulemodel.cpp @@ -1,1264 +1,1264 @@ /* 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. */ #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 { //-------------------------------------- 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, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); + disconnect(m_project, &Project::aboutToBeDeleted, this, &ScheduleItemModel::projectDeleted); - disconnect(m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotManagerChanged(KPlato::ScheduleManager*))); + disconnect(m_project, &Project::scheduleManagerChanged, this, &ScheduleItemModel::slotManagerChanged); - disconnect(m_project, SIGNAL(scheduleManagerToBeAdded(const KPlato::ScheduleManager*,int)), this, SLOT(slotScheduleManagerToBeInserted(const KPlato::ScheduleManager*,int))); + disconnect(m_project, &Project::scheduleManagerToBeAdded, this, &ScheduleItemModel::slotScheduleManagerToBeInserted); - disconnect(m_project, SIGNAL(scheduleManagerToBeRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeRemoved(const KPlato::ScheduleManager*))); + disconnect(m_project, &Project::scheduleManagerToBeRemoved, this, &ScheduleItemModel::slotScheduleManagerToBeRemoved); - disconnect(m_project, SIGNAL(scheduleManagerAdded(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerInserted(const KPlato::ScheduleManager*))); + disconnect(m_project, &Project::scheduleManagerAdded, this, &ScheduleItemModel::slotScheduleManagerInserted); - disconnect(m_project, SIGNAL(scheduleManagerRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerRemoved(const KPlato::ScheduleManager*))); + disconnect(m_project, &Project::scheduleManagerRemoved, this, &ScheduleItemModel::slotScheduleManagerRemoved); - disconnect(m_project, SIGNAL(scheduleManagerToBeMoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeMoved(const KPlato::ScheduleManager*))); + disconnect(m_project, &Project::scheduleManagerToBeMoved, this, &ScheduleItemModel::slotScheduleManagerToBeMoved); - disconnect(m_project, SIGNAL(scheduleManagerMoved(const KPlato::ScheduleManager*,int)), this, SLOT(slotScheduleManagerMoved(const KPlato::ScheduleManager*,int))); + disconnect(m_project, &Project::scheduleManagerMoved, this, &ScheduleItemModel::slotScheduleManagerMoved); - disconnect(m_project, SIGNAL(scheduleChanged(KPlato::MainSchedule*)), this, SLOT(slotScheduleChanged(KPlato::MainSchedule*))); + disconnect(m_project, &Project::scheduleChanged, this, &ScheduleItemModel::slotScheduleChanged); - disconnect(m_project, SIGNAL(scheduleToBeAdded(const KPlato::ScheduleManager*,int)), this, SLOT(slotScheduleToBeInserted(const KPlato::ScheduleManager*,int))); + disconnect(m_project, &Project::scheduleToBeAdded, this, &ScheduleItemModel::slotScheduleToBeInserted); - disconnect(m_project, SIGNAL(scheduleToBeRemoved(const KPlato::MainSchedule*)), this, SLOT(slotScheduleToBeRemoved(const KPlato::MainSchedule*))); + disconnect(m_project, &Project::scheduleToBeRemoved, this, &ScheduleItemModel::slotScheduleToBeRemoved); - disconnect(m_project, SIGNAL(scheduleAdded(const KPlato::MainSchedule*)), this, SLOT(slotScheduleInserted(const KPlato::MainSchedule*))); + disconnect(m_project, &Project::scheduleAdded, this, &ScheduleItemModel::slotScheduleInserted); - disconnect(m_project, SIGNAL(scheduleRemoved(const KPlato::MainSchedule*)), this, SLOT(slotScheduleRemoved(const KPlato::MainSchedule*))); + disconnect(m_project, &Project::scheduleRemoved, this, &ScheduleItemModel::slotScheduleRemoved); } m_project = project; if ( m_project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); + connect(m_project, &Project::aboutToBeDeleted, this, &ScheduleItemModel::projectDeleted); - connect(m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotManagerChanged(KPlato::ScheduleManager*))); + connect(m_project, &Project::scheduleManagerChanged, this, &ScheduleItemModel::slotManagerChanged); - connect(m_project, SIGNAL(scheduleManagerToBeAdded(const KPlato::ScheduleManager*,int)), this, SLOT(slotScheduleManagerToBeInserted(const KPlato::ScheduleManager*,int))); + connect(m_project, &Project::scheduleManagerToBeAdded, this, &ScheduleItemModel::slotScheduleManagerToBeInserted); - connect(m_project, SIGNAL(scheduleManagerToBeRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeRemoved(const KPlato::ScheduleManager*))); + connect(m_project, &Project::scheduleManagerToBeRemoved, this, &ScheduleItemModel::slotScheduleManagerToBeRemoved); - connect(m_project, SIGNAL(scheduleManagerAdded(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerInserted(const KPlato::ScheduleManager*))); + connect(m_project, &Project::scheduleManagerAdded, this, &ScheduleItemModel::slotScheduleManagerInserted); - connect(m_project, SIGNAL(scheduleManagerRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerRemoved(const KPlato::ScheduleManager*))); + connect(m_project, &Project::scheduleManagerRemoved, this, &ScheduleItemModel::slotScheduleManagerRemoved); - connect(m_project, SIGNAL(scheduleManagerToBeMoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeMoved(const KPlato::ScheduleManager*))); + connect(m_project, &Project::scheduleManagerToBeMoved, this, &ScheduleItemModel::slotScheduleManagerToBeMoved); - connect(m_project, SIGNAL(scheduleManagerMoved(const KPlato::ScheduleManager*,int)), this, SLOT(slotScheduleManagerMoved(const KPlato::ScheduleManager*,int))); + connect(m_project, &Project::scheduleManagerMoved, this, &ScheduleItemModel::slotScheduleManagerMoved); - connect(m_project, SIGNAL(scheduleChanged(KPlato::MainSchedule*)), this, SLOT(slotScheduleChanged(KPlato::MainSchedule*))); + connect(m_project, &Project::scheduleChanged, this, &ScheduleItemModel::slotScheduleChanged); - connect(m_project, SIGNAL(scheduleToBeAdded(const KPlato::ScheduleManager*,int)), this, SLOT(slotScheduleToBeInserted(const KPlato::ScheduleManager*,int))); + connect(m_project, &Project::scheduleToBeAdded, this, &ScheduleItemModel::slotScheduleToBeInserted); - connect(m_project, SIGNAL(scheduleToBeRemoved(const KPlato::MainSchedule*)), this, SLOT(slotScheduleToBeRemoved(const KPlato::MainSchedule*))); + connect(m_project, &Project::scheduleToBeRemoved, this, &ScheduleItemModel::slotScheduleToBeRemoved); - connect(m_project, SIGNAL(scheduleAdded(const KPlato::MainSchedule*)), this, SLOT(slotScheduleInserted(const KPlato::MainSchedule*))); + connect(m_project, &Project::scheduleAdded, this, &ScheduleItemModel::slotScheduleInserted); - connect(m_project, SIGNAL(scheduleRemoved(const KPlato::MainSchedule*)), this, SLOT(slotScheduleRemoved(const KPlato::MainSchedule*))); + 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::ScheduleState: 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; } 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: case Qt::ToolTipRole: return sm->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); 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; } 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; } 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 ); } //-------------------------------------- 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, SIGNAL(logInserted(KPlato::MainSchedule*,int,int)), this, SLOT(slotLogInserted(KPlato::MainSchedule*,int,int))); + 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< 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 "kpttaskstatusmodel.h" #include "PlanMacros.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptitemmodelbase.h" #include "kpttaskcompletedelegate.h" #include "kptcommand.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptnodeitemmodel.h" #include "kptdebug.h" #include #include #include namespace KPlato { TaskStatusItemModel::TaskStatusItemModel( QObject *parent ) : ItemModelBase( parent ), m_period( 7 ), m_periodType( UseCurrentDate ), m_weekday( Qt::Friday ) { m_topNames << i18n( "Not Started" ); m_topTips << i18n( "Tasks that should have been started" ); m_top.append(&m_notstarted ); m_topNames << i18n( "Running" ); m_topTips << i18n( "Tasks that are running" ); m_top.append(&m_running ); m_topNames << i18n( "Finished" ); m_topTips << i18n( "Tasks that have finished during this period" ); m_top.append(&m_finished ); m_topNames << i18n( "Next Period" ); m_topTips << i18n( "Tasks that are scheduled to start next period" ); m_top.append(&m_upcoming ); /* connect( this, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset()) ); connect( this, SIGNAL(modelReset()), SLOT(slotReset()) );*/ } TaskStatusItemModel::~TaskStatusItemModel() { } void TaskStatusItemModel::slotAboutToBeReset() { debugPlan; clear(); } void TaskStatusItemModel::slotReset() { debugPlan; refresh(); } void TaskStatusItemModel::slotNodeToBeInserted( Node *, int ) { //debugPlan<name(); clear(); } void TaskStatusItemModel::slotNodeInserted( Node * /*node*/ ) { //debugPlan<getParent->name()<<"-->"<name(); refresh(); } void TaskStatusItemModel::slotNodeToBeRemoved( Node * /*node*/ ) { //debugPlan<name(); clear(); } void TaskStatusItemModel::slotNodeRemoved( Node * /*node*/ ) { //debugPlan<name(); refresh(); } void TaskStatusItemModel::slotNodeToBeMoved(Node *node, int pos, Node *newParent, int newPos) { Q_UNUSED( node ); Q_UNUSED( pos ); Q_UNUSED( newParent ); Q_UNUSED( newPos ); clear(); } void TaskStatusItemModel::slotNodeMoved( Node * /*node*/ ) { //debugPlan<name(); refresh(); } void TaskStatusItemModel::setProject( Project *project ) { beginResetModel(); clear(); if ( m_project ) { - disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); - disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) ); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - disconnect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); - disconnect(m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotNodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int))); + disconnect(m_project, &Project::aboutToBeDeleted, this, &TaskStatusItemModel::projectDeleted); + disconnect(m_project, &Project::localeChanged, this, &TaskStatusItemModel::slotLayoutChanged); + disconnect( m_project, &Project::wbsDefinitionChanged, this, &TaskStatusItemModel::slotWbsDefinitionChanged ); + disconnect( m_project, &Project::nodeChanged, this, &TaskStatusItemModel::slotNodeChanged ); + disconnect( m_project, &Project::nodeToBeAdded, this, &TaskStatusItemModel::slotNodeToBeInserted ); + disconnect( m_project, &Project::nodeToBeRemoved, this, &TaskStatusItemModel::slotNodeToBeRemoved ); + disconnect(m_project, &Project::nodeToBeMoved, this, &TaskStatusItemModel::slotNodeToBeMoved); - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - disconnect(m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*))); + disconnect( m_project, &Project::nodeAdded, this, &TaskStatusItemModel::slotNodeInserted ); + disconnect( m_project, &Project::nodeRemoved, this, &TaskStatusItemModel::slotNodeRemoved ); + disconnect(m_project, &Project::nodeMoved, this, &TaskStatusItemModel::slotNodeMoved); } m_project = project; m_nodemodel.setProject( project ); if ( project ) { - connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); - connect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); - connect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) ); - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - connect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); - connect(m_project, SIGNAL(nodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int)), this, SLOT(slotNodeToBeMoved(KPlato::Node*,int,KPlato::Node*,int))); + connect(m_project, &Project::aboutToBeDeleted, this, &TaskStatusItemModel::projectDeleted); + connect(m_project, &Project::localeChanged, this, &TaskStatusItemModel::slotLayoutChanged); + connect( m_project, &Project::wbsDefinitionChanged, this, &TaskStatusItemModel::slotWbsDefinitionChanged ); + connect( m_project, &Project::nodeChanged, this, &TaskStatusItemModel::slotNodeChanged ); + connect( m_project, &Project::nodeToBeAdded, this, &TaskStatusItemModel::slotNodeToBeInserted ); + connect( m_project, &Project::nodeToBeRemoved, this, &TaskStatusItemModel::slotNodeToBeRemoved ); + connect(m_project, &Project::nodeToBeMoved, this, &TaskStatusItemModel::slotNodeToBeMoved); - connect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - connect(m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*))); + connect( m_project, &Project::nodeAdded, this, &TaskStatusItemModel::slotNodeInserted ); + connect( m_project, &Project::nodeRemoved, this, &TaskStatusItemModel::slotNodeRemoved ); + connect(m_project, &Project::nodeMoved, this, &TaskStatusItemModel::slotNodeMoved); } endResetModel(); } void TaskStatusItemModel::setScheduleManager( ScheduleManager *sm ) { beginResetModel(); if (sm == m_nodemodel.manager()) { return; } clear(); if ( m_nodemodel.manager() ) { } m_nodemodel.setManager( sm ); ItemModelBase::setScheduleManager( sm ); if ( sm ) { } endResetModel(); refresh(); } void TaskStatusItemModel::clear() { foreach ( NodeMap *l, m_top ) { int c = l->count(); if ( c > 0 ) { //FIXME: gives error msg: // Can't select indexes from different model or with different parents QModelIndex i = index( l ); debugPlan<clear(); endRemoveRows(); } } } void TaskStatusItemModel::setNow() { switch ( m_periodType ) { case UseWeekday: { QDate date = QDate::currentDate(); int wd = date.dayOfWeek(); date = date.addDays( m_weekday - wd ); if ( wd < m_weekday ) { date = date.addDays( -7 ); } m_nodemodel.setNow( date ); break; } case UseCurrentDate: m_nodemodel.setNow( QDate::currentDate() ); break; default: m_nodemodel.setNow( QDate::currentDate() ); break; } } void TaskStatusItemModel::refresh() { clear(); if ( m_project == 0 ) { return; } m_id = m_nodemodel.id(); if ( m_id == -1 ) { return; } setNow(); const QDate begin = m_nodemodel.now().addDays( -m_period ); const QDate end = m_nodemodel.now().addDays( m_period ); foreach( Node* n, m_project->allNodes() ) { if ( n->type() != Node::Type_Task && n->type() != Node::Type_Milestone ) { continue; } Task *task = static_cast( n ); const TaskStatus status = taskStatus(task, begin, end); if (status != TaskUnknownStatus) { m_top.at(status)->insert(task->wbsCode(), task); } } foreach ( NodeMap *l, m_top ) { int c = l->count(); if ( c > 0 ) { debugPlan<isScheduled( m_id ) ) { 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 NodeModel::NodeActualStart: flags |= Qt::ItemIsEditable; break; case NodeModel::NodeCompleted: if ( t->state() & Node::State_ReadyToStart ) { flags |= Qt::ItemIsEditable; } break; default: break; } } else if ( ! t->completion().isFinished() ) { // task is running switch ( index.column() ) { case NodeModel::NodeActualFinish: case NodeModel::NodeCompleted: case NodeModel::NodeRemainingEffort: flags |= Qt::ItemIsEditable; break; case NodeModel::NodeActualEffort: if ( t->completion().entrymode() == Completion::EnterEffortPerTask || t->completion().entrymode() == Completion::EnterEffortPerResource ) { flags |= Qt::ItemIsEditable; } break; default: break; } } return flags; } QModelIndex TaskStatusItemModel::parent( const QModelIndex &index ) const { if ( !index.isValid() ) { return QModelIndex(); } //debugPlan<( index.internalPointer() ) ); if ( row != -1 ) { return QModelIndex(); // top level has no parent } Node *n = node( index ); if ( n == 0 ) { return QModelIndex(); } NodeMap *lst = 0; foreach ( NodeMap *l, m_top ) { if (CONTAINS((*l), n)) { lst = l; break; } } if ( lst == 0 ) { return QModelIndex(); } return createIndex( m_top.indexOf( lst ), 0, lst ); } QModelIndex TaskStatusItemModel::index( int row, int column, const QModelIndex &parent ) const { //debugPlan<= columnCount() || row < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row >= m_top.count() ) { return QModelIndex(); } return createIndex(row, column, m_top.value( row ) ); } NodeMap *l = list( parent ); if ( l == 0 ) { return QModelIndex(); } if ( row >= rowCount( parent ) ) { warnPlan<<"Row >= rowCount, Qt4.4 asks, so we need to handle it"< &nodes = l->values(); QModelIndex i = createIndex(row, column, nodes.value(row)); Q_ASSERT( i.internalPointer() != 0 ); return i; } QModelIndex TaskStatusItemModel::index( const Node *node ) const { if ( m_project == 0 || node == 0 ) { return QModelIndex(); } foreach( NodeMap *l, m_top ) { const QList &nodes = l->values(); int row = nodes.indexOf( const_cast( node ) ); if ( row != -1 ) { return createIndex( row, 0, const_cast( node ) ); } } return QModelIndex(); } QModelIndex TaskStatusItemModel::index( const NodeMap *lst ) const { if ( m_project == 0 || lst == 0 ) { return QModelIndex(); } NodeMap *l = const_cast( lst ); int row = m_top.indexOf( l ); if ( row == -1 ) { return QModelIndex(); } return createIndex( row, 0, l ); } QVariant TaskStatusItemModel::name( int row, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return m_topNames.value( row ); case Qt::ToolTipRole: return m_topTips.value( row ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool TaskStatusItemModel::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(); QDateTime dt = QDateTime::currentDateTime(); QDate date = dt.date(); // 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 ) ); } emit executeCommand( m ); // also adds a new entry if necessary if ( c.entrymode() == Completion::EnterCompleted ) { Duration planned = static_cast( node )->plannedEffort( m_nodemodel.id() ); Duration actual = ( planned * value.toInt() ) / 100; debugPlan<execute(); m->addCommand( cmd ); cmd = new ModifyCompletionRemainingEffortCmd( c, date, planned - actual ); 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 TaskStatusItemModel::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 TaskStatusItemModel::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 TaskStatusItemModel::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_i18n( "Modify actual start time" ) ); 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 TaskStatusItemModel::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_i18n( "Modify actual finish time" ) ); if ( ! t->completion().isFinished() ) { m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) ); 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 ) ); } } 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; } QVariant TaskStatusItemModel::data( const QModelIndex &index, int role ) const { QVariant result; if ( ! index.isValid() ) { return result; } if ( role == Qt::TextAlignmentRole ) { return alignment( index.column() ); } Node *n = node( index ); if ( n == 0 ) { switch ( index.column() ) { case NodeModel::NodeName: return name( index.row(), role ); default: break; } return QVariant(); } result = m_nodemodel.data( n, index.column(), role ); if ( role == Qt::DisplayRole ) { switch ( index.column() ) { case NodeModel::NodeActualStart: if ( ! result.isValid() ) { return m_nodemodel.data( n, NodeModel::NodeStatus, role ); } break; } } else if ( role == Qt::EditRole ) { switch ( index.column() ) { case NodeModel::NodeActualStart: case NodeModel::NodeActualFinish: if ( ! result.isValid() ) { return QDateTime::currentDateTime(); } break; } } return result; } bool TaskStatusItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } switch ( index.column() ) { case NodeModel::NodeCompleted: return setCompletion( node( index ), value, role ); case NodeModel::NodeRemainingEffort: return setRemainingEffort( node( index ), value, role ); case NodeModel::NodeActualEffort: return setActualEffort( node( index ), value, role ); case NodeModel::NodeActualStart: return setStartedTime( node( index ), value, role ); case NodeModel::NodeActualFinish: return setFinishedTime( node( index ), value, role ); default: break; } return false; } QVariant TaskStatusItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if (role == Qt::DisplayRole || role == Qt::EditRole) { return m_nodemodel.headerData( section, role ); } else if ( role == Qt::TextAlignmentRole ) { return alignment( section ); } } if ( role == Qt::ToolTipRole ) { return m_nodemodel.headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QVariant TaskStatusItemModel::alignment( int column ) const { return m_nodemodel.headerData( column, Qt::TextAlignmentRole ); } QAbstractItemDelegate *TaskStatusItemModel::createDelegate( int column, QWidget *parent ) const { switch ( column ) { case NodeModel::NodeCompleted: return new TaskCompleteDelegate( parent ); case NodeModel::NodeRemainingEffort: return new DurationSpinBoxDelegate( parent ); case NodeModel::NodeActualEffort: return new DurationSpinBoxDelegate( parent ); default: return 0; } return 0; } int TaskStatusItemModel::columnCount( const QModelIndex & ) const { return m_nodemodel.propertyCount(); } int TaskStatusItemModel::rowCount( const QModelIndex &parent ) const { if ( ! parent.isValid() ) { //debugPlan<<"top="<count()<count(); } //debugPlan<<"node"< rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<id(); } } } m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData); return m; } bool TaskStatusItemModel::dropAllowed( Node *, const QMimeData * ) { return false; } bool TaskStatusItemModel::dropMimeData( const QMimeData *, Qt::DropAction , int , int , const QModelIndex & ) { return false; } NodeMap *TaskStatusItemModel::list( const QModelIndex &index ) const { if ( index.isValid() ) { Q_ASSERT( index.internalPointer() ); if ( m_top.contains( static_cast( index.internalPointer() ) ) ) { return static_cast( index.internalPointer() ); } } return 0; } Node *TaskStatusItemModel::node( const QModelIndex &index ) const { if ( index.isValid() ) { foreach ( NodeMap *l, m_top ) { const QList &nodes = l->values(); int row = nodes.indexOf( static_cast( index.internalPointer() ) ); if ( row != -1 ) { return static_cast( index.internalPointer() ); } } } return 0; } TaskStatusItemModel::TaskStatus TaskStatusItemModel::taskStatus(const Task *task, const QDate &begin, const QDate &end) { TaskStatus result = TaskUnknownStatus; const Completion &completion = task->completion(); if (completion.isFinished()) { if (completion.finishTime().date() > begin) { result = TaskFinished; } } else if (completion.isStarted()) { result = TaskRunning; } else if (task->startTime(m_id).date() < m_nodemodel.now()) { // should have been started result = TaskNotStarted; } else if (task->startTime(m_id).date() <= end) { // start next period result = TaskUpcoming; } return result; } void TaskStatusItemModel::slotNodeChanged( Node *node ) { debugPlan; if (node == 0 || node->type() == Node::Type_Project || (node->type() != Node::Type_Task && node->type() != Node::Type_Milestone)) { return; } Task *task = static_cast(node); const QDate begin = m_nodemodel.now().addDays( -m_period ); const QDate end = m_nodemodel.now().addDays( m_period ); const TaskStatus status = taskStatus(task, begin, end); int row = -1; if (status != TaskUnknownStatus) { // find the row of the task const QString wbs = node->wbsCode(); // TODO: not enough to just check the result of indexOf? wbs not unique? if (m_top.at(status)->value(wbs) == node ) { row = m_top.at(status)->keys().indexOf(wbs); } } if (row >= 0) { // task in old group, just changed values emit dataChanged(createIndex(row, 0, node), createIndex(row, columnCount() - 1, node)); } else { // task is new or changed groups refresh(); } } void TaskStatusItemModel::slotWbsDefinitionChanged() { debugPlan; foreach ( NodeMap *l, m_top ) { for ( int row = 0; row < l->count(); ++row ) { const QList &nodes = l->values(); emit dataChanged( createIndex( row, NodeModel::NodeWBSCode, nodes.value( row ) ), createIndex( row, NodeModel::NodeWBSCode, nodes.value( row ) ) ); } } } -void TaskStatusItemModel::slotLayoutChanged() -{ - //debugPlan<name(); - emit layoutAboutToBeChanged(); - emit layoutChanged(); -} - int TaskStatusItemModel::sortRole( int column ) const { switch ( column ) { case NodeModel::NodeStartTime: case NodeModel::NodeEndTime: case NodeModel::NodeActualStart: case NodeModel::NodeActualFinish: case NodeModel::NodeEarlyStart: case NodeModel::NodeEarlyFinish: case NodeModel::NodeLateStart: case NodeModel::NodeLateFinish: case NodeModel::NodeConstraintStart: case NodeModel::NodeConstraintEnd: return Qt::EditRole; default: break; } return Qt::DisplayRole; } } // namespace KPlato diff --git a/src/libs/models/kpttaskstatusmodel.h b/src/libs/models/kpttaskstatusmodel.h index 8acb9171..70abdc1a 100644 --- a/src/libs/models/kpttaskstatusmodel.h +++ b/src/libs/models/kpttaskstatusmodel.h @@ -1,154 +1,153 @@ /* This file is part of the KDE project Copyright (C) 2007 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. */ #ifndef TASKSTATUSMODEL_H #define TASKSTATUSMODEL_H #include "planmodels_export.h" #include "kptitemmodelbase.h" #include "kptnodeitemmodel.h" namespace KPlato { class Project; class Node; class Task; typedef QMap NodeMap; class PLANMODELS_EXPORT TaskStatusItemModel : public ItemModelBase { Q_OBJECT public: explicit TaskStatusItemModel( QObject *parent = 0 ); ~TaskStatusItemModel(); enum PeriodType { UseCurrentDate, UseWeekday }; int periodType() const { return m_periodType; } void setPeriodType( int type ) { m_periodType = type; } /// Returns a column number/- name map for this model virtual const QMetaEnum columnMap() const { return m_nodemodel.columnMap(); } virtual void setProject( Project *project ); virtual Qt::ItemFlags flags( const QModelIndex & index ) const; virtual QModelIndex parent( const QModelIndex & index ) const; virtual QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const; virtual QModelIndex index( const Node *node ) const; virtual QModelIndex index( const NodeMap *lst ) const; virtual int columnCount( const QModelIndex & parent = QModelIndex() ) const; virtual int rowCount( const QModelIndex & parent = QModelIndex() ) const; virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual bool setData( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QMimeData * mimeData( const QModelIndexList & indexes ) const; virtual QStringList mimeTypes () const; virtual Qt::DropActions supportedDropActions() const; virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ); NodeMap *list( const QModelIndex &index ) const; Node *node( const QModelIndex &index ) const; QAbstractItemDelegate *createDelegate( int column, QWidget *parent ) const; NodeMap nodeList( QDataStream &stream ); using ItemModelBase::dropAllowed; bool dropAllowed( Node *on, const QMimeData *data ); void clear(); void setNow(); void setPeriod( int days ) { m_period = days; } int period() const { return m_period; } void setWeekday( int day ) { m_weekday = day; } int weekday() const { return m_weekday; } /// Return the sortorder to be used for @p column virtual int sortRole( int column ) const; public Q_SLOTS: virtual void setScheduleManager(KPlato::ScheduleManager *sm); virtual void refresh(); protected Q_SLOTS: void slotAboutToBeReset(); void slotReset(); void slotNodeChanged(KPlato::Node* ); void slotNodeToBeInserted(KPlato::Node *node, int row ); void slotNodeInserted(KPlato::Node *node ); void slotNodeToBeRemoved(KPlato::Node *node ); void slotNodeRemoved(KPlato::Node *node ); void slotNodeToBeMoved(KPlato::Node *node, int pos, KPlato::Node *newParent, int newPos ); void slotNodeMoved(KPlato::Node *node ); void slotWbsDefinitionChanged(); - void slotLayoutChanged(); protected: // keep in sync with order in m_top enum TaskStatus { TaskUnknownStatus = -1, TaskNotStarted = 0, TaskRunning = 1, TaskFinished = 2, TaskUpcoming = 3 }; QVariant alignment( int column ) const; QVariant name( int row, int role ) const; TaskStatusItemModel::TaskStatus taskStatus(const Task *task, const QDate &begin, const QDate &end); bool setCompletion( Node *node, const QVariant &value, int role ); bool setRemainingEffort( Node *node, const QVariant &value, int role ); bool setActualEffort( Node *node, const QVariant &value, int role ); bool setStartedTime( Node *node, const QVariant &value, int role ); bool setFinishedTime( Node *node, const QVariant &value, int role ); private: NodeModel m_nodemodel; QStringList m_topNames; QStringList m_topTips; QList m_top; NodeMap m_notstarted; NodeMap m_running; NodeMap m_finished; NodeMap m_upcoming; long m_id; // schedule id int m_period; // days int m_periodType; int m_weekday; }; } //namespace KPlato #endif diff --git a/src/libs/models/kptworkpackagemodel.cpp b/src/libs/models/kptworkpackagemodel.cpp index 25cdc941..9aed4af6 100644 --- a/src/libs/models/kptworkpackagemodel.cpp +++ b/src/libs/models/kptworkpackagemodel.cpp @@ -1,558 +1,558 @@ /* This file is part of the KDE project Copyright (C) 2007, 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. */ #include "kptworkpackagemodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptflatproxymodel.h" #include "kptnodeitemmodel.h" #include "kptnode.h" #include "kpttask.h" #include "kptproject.h" #include "kptschedule.h" #include "kptdebug.h" #include #include #include namespace KPlato { QVariant WorkPackageModel::nodeName( const WorkPackage *wp, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return wp->parentTask() ? wp->parentTask()->name() : ""; case Qt::EditRole: return wp->parentTask() ? wp->parentTask()->name() : ""; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant WorkPackageModel::ownerName( const WorkPackage *wp, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return wp->ownerName(); case Qt::EditRole: return wp->ownerName(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant WorkPackageModel::transmitionStatus( const WorkPackage *wp, int role ) const { switch ( role ) { case Qt::DisplayRole: return wp->transmitionStatusToString( wp->transmitionStatus(), true ); case Qt::EditRole: return wp->transmitionStatus(); case Qt::ToolTipRole: { int sts = wp->transmitionStatus(); if ( sts == WorkPackage::TS_Send ) { return i18n( "Sent to %1 at %2", wp->ownerName(), transmitionTime( wp, Qt::DisplayRole ).toString() ); } if ( sts == WorkPackage::TS_Receive ) { return i18n( "Received from %1 at %2", wp->ownerName(), transmitionTime( wp, Qt::DisplayRole ).toString() ); } return i18n( "Not available" ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant WorkPackageModel::transmitionTime( const WorkPackage *wp, int role ) const { if ( ! wp ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: return QLocale().toString( wp->transmitionTime(), QLocale::ShortFormat ); case Qt::EditRole: return wp->transmitionTime(); case Qt::ToolTipRole: { int sts = wp->transmitionStatus(); QString t = QLocale().toString( wp->transmitionTime(), QLocale::LongFormat ); if ( sts == WorkPackage::TS_Send ) { return i18n( "Work package sent at: %1", t ); } if ( sts == WorkPackage::TS_Receive ) { return i18n( "Work package transmission received at: %1", t ); } return i18n( "Not available" ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant WorkPackageModel::completion( const WorkPackage *wp, int role ) const { switch ( role ) { case Qt::DisplayRole: if ( wp->transmitionStatus() == WorkPackage::TS_Receive ) { return wp->completion().percentFinished(); } break; case Qt::EditRole: if ( wp->transmitionStatus() == WorkPackage::TS_Receive ) { return wp->completion().percentFinished(); } break; case Qt::ToolTipRole: if ( wp->transmitionStatus() == WorkPackage::TS_Receive ) { return i18n( "Task reported %1% completed", wp->completion().percentFinished() ); } break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant WorkPackageModel::data( const WorkPackage *wp, int column, int role ) const { switch ( column ) { case NodeModel::WPOwnerName: case NodeModel::NodeName: return ownerName( wp, role ); case NodeModel::WPTransmitionStatus: case NodeModel::NodeStatus: return transmitionStatus( wp, role ); case NodeModel::NodeCompleted: return completion( wp, role ); case NodeModel::WPTransmitionTime: case NodeModel::NodeActualStart: return transmitionTime( wp, role ); default: break; } return QVariant(); } //----------------------------- bool WPSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { if ( sourceModel()->index( source_row, NodeModel::NodeType, source_parent ).data( Qt::EditRole ).toInt() != Node::Type_Task ) { return false; } if ( sourceModel()->index( source_row, NodeModel::NodeStatus, source_parent ).data( Qt::EditRole ).toInt() & Node::State_NotScheduled ) { return false; } return true; } WorkPackageProxyModel::WorkPackageProxyModel( QObject *parent ) : QAbstractProxyModel( parent ) { m_proxies << new WPSortFilterProxyModel( this ); m_proxies << new FlatProxyModel( this ); m_nodemodel = new NodeItemModel( this ); QAbstractProxyModel *p = this; foreach ( QAbstractProxyModel *m, m_proxies ) { p->setSourceModel( m ); p = m; } p->setSourceModel( m_nodemodel ); } Qt::ItemFlags WorkPackageProxyModel::flags(const QModelIndex &index) const { if ( isWorkPackageIndex( index ) ) { return Qt::ItemIsEnabled; } return QAbstractProxyModel::flags( index ); } void WorkPackageProxyModel::setSourceModel( QAbstractItemModel *model ) { if ( sourceModel() ) { - disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); + disconnect(sourceModel(), &QAbstractItemModel::dataChanged, + this, &WorkPackageProxyModel::sourceDataChanged); /* disconnect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(sourceHeaderDataChanged(Qt::Orientation,int,int)));*/ - disconnect(sourceModel(), SIGNAL(layoutChanged()), - this, SIGNAL(layoutChanged())); - disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged()), - this, SIGNAL(layoutAboutToBeChanged())); - disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); - disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsInserted(QModelIndex,int,int))); - disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); - disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); + disconnect(sourceModel(), &QAbstractItemModel::layoutChanged, + this, &QAbstractItemModel::layoutChanged); + disconnect(sourceModel(), &QAbstractItemModel::layoutAboutToBeChanged, + this, &QAbstractItemModel::layoutAboutToBeChanged); + disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeInserted, + this, &WorkPackageProxyModel::sourceRowsAboutToBeInserted); + disconnect(sourceModel(), &QAbstractItemModel::rowsInserted, + this, &WorkPackageProxyModel::sourceRowsInserted); + disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved, + this, &WorkPackageProxyModel::sourceRowsAboutToBeRemoved); + disconnect(sourceModel(), &QAbstractItemModel::rowsRemoved, + this, &WorkPackageProxyModel::sourceRowsAboutToBeRemoved); /* disconnect(sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(sourceColumnsAboutToBeInserted(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(sourceColumnsInserted(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(sourceColumnsAboutToBeRemoved(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(sourceColumnsRemoved(QModelIndex,int,int))); */ - disconnect(sourceModel(), SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); - disconnect(sourceModel(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); + disconnect(sourceModel(), &QAbstractItemModel::modelAboutToBeReset, this, &WorkPackageProxyModel::sourceModelAboutToBeReset); + disconnect(sourceModel(), &QAbstractItemModel::modelReset, this, &WorkPackageProxyModel::sourceModelReset); - disconnect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); - disconnect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); + disconnect(sourceModel(), &QAbstractItemModel::rowsAboutToBeMoved, + this, &WorkPackageProxyModel::sourceRowsAboutToBeMoved); + disconnect(sourceModel(), &QAbstractItemModel::rowsMoved, + this, &WorkPackageProxyModel::sourceRowsMoved); /* disconnect(sourceModel(), SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); disconnect(sourceModel(), SIGNAL(columnsMoved(QModelIndex&parent,int,int,QModelIndex,int)), this, SLOT(sourceColumnsMoved(QModelIndex&parent,int,int,QModelIndex,int)));*/ } QAbstractProxyModel::setSourceModel( model ); if ( model ) { - connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - this, SLOT(sourceDataChanged(QModelIndex,QModelIndex))); + connect(model, &QAbstractItemModel::dataChanged, + this, &WorkPackageProxyModel::sourceDataChanged); /* connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), this, SLOT(sourceHeaderDataChanged(Qt::Orientation,int,int)));*/ - connect(model, SIGNAL(layoutChanged()), - this, SIGNAL(layoutChanged())); - connect(model, SIGNAL(layoutAboutToBeChanged()), - this, SIGNAL(layoutAboutToBeChanged())); - connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); - connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(sourceRowsInserted(QModelIndex,int,int))); - connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); - connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); + connect(model, &QAbstractItemModel::layoutChanged, + this, &QAbstractItemModel::layoutChanged); + connect(model, &QAbstractItemModel::layoutAboutToBeChanged, + this, &QAbstractItemModel::layoutAboutToBeChanged); + connect(model, &QAbstractItemModel::rowsAboutToBeInserted, + this, &WorkPackageProxyModel::sourceRowsAboutToBeInserted); + connect(model, &QAbstractItemModel::rowsInserted, + this, &WorkPackageProxyModel::sourceRowsInserted); + connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, + this, &WorkPackageProxyModel::sourceRowsAboutToBeRemoved); + connect(model, &QAbstractItemModel::rowsRemoved, + this, &WorkPackageProxyModel::sourceRowsRemoved); /* connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(sourceColumnsAboutToBeInserted(QModelIndex,int,int))); connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(sourceColumnsInserted(QModelIndex,int,int))); connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(sourceColumnsAboutToBeRemoved(QModelIndex,int,int))); connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(sourceColumnsRemoved(QModelIndex,int,int))); */ - connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(sourceModelAboutToBeReset())); - connect(model, SIGNAL(modelReset()), this, SLOT(sourceModelReset())); + connect(model, &QAbstractItemModel::modelAboutToBeReset, this, &WorkPackageProxyModel::sourceModelAboutToBeReset); + connect(model, &QAbstractItemModel::modelReset, this, &WorkPackageProxyModel::sourceModelReset); - connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); - connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))); + connect(model, &QAbstractItemModel::rowsAboutToBeMoved, + this, &WorkPackageProxyModel::sourceRowsAboutToBeMoved); + connect(model, &QAbstractItemModel::rowsMoved, + this, &WorkPackageProxyModel::sourceRowsMoved); /* connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); connect(model, SIGNAL(columnsMoved(QModelIndex&parent,int,int,QModelIndex,int)), this, SLOT(sourceColumnsMoved(QModelIndex&parent,int,int,QModelIndex,int)));*/ } } void WorkPackageProxyModel::sourceDataChanged(const QModelIndex &start, const QModelIndex &end) { emit dataChanged( mapFromSource( start ), mapFromSource( end ) ); } void WorkPackageProxyModel::sourceModelAboutToBeReset() { // debugPlan; beginResetModel(); detachTasks(); } void WorkPackageProxyModel::sourceModelReset() { // debugPlan; attachTasks(); for ( int r = 0; r < rowCount(); ++r ) { debugPlan< 0; } int WorkPackageProxyModel::rowCount( const QModelIndex &parent ) const { int rows = 0; if ( ! parent.isValid() ) { rows = sourceModel()->rowCount(); } else if ( isTaskIndex( parent ) ) { Task *task = taskFromIndex( parent ); rows = task ? task->workPackageLogCount() : 0; } // debugPlan<columnCount(); } QModelIndex WorkPackageProxyModel::mapToSource( const QModelIndex &proxyIndex ) const { if ( ! proxyIndex.isValid() ) { return QModelIndex(); } if ( isWorkPackageIndex( proxyIndex ) ) { // workpackage, not mapped to source model return QModelIndex(); } return sourceModel()->index( proxyIndex.row(), proxyIndex.column() ); } QModelIndex WorkPackageProxyModel::mapFromSource( const QModelIndex &sourceIndex ) const { // index from source model is always a node return createIndex( sourceIndex.row(), sourceIndex.column() ); } QModelIndex WorkPackageProxyModel::parent( const QModelIndex &child ) const { QModelIndex idx; if ( isWorkPackageIndex( child ) ) { // only work packages have parent idx = m_nodemodel->index( static_cast( child.internalPointer() ) ); idx = mapFromBaseModel( idx ); } // debugPlan<workPackageAt( idx.row() ), idx.column(), role ); } } // debugPlan<( idx.internalPointer() ); } else if ( idx.isValid() ) { QVariant obj = data( idx, Role::Object ); task = qobject_cast( obj.value() ); } // debugPlan<index( node ) ); } QModelIndex WorkPackageProxyModel::mapFromBaseModel( const QModelIndex &idx ) const { if ( ! idx.isValid() ) { return QModelIndex(); } QModelIndex in = idx; for ( int i = m_proxies.count() -1; i >= 0; --i ) { in = m_proxies.at( i )->mapFromSource( in ); } return mapFromSource( in ); } void WorkPackageProxyModel::setProject( Project *project ) { debugPlan<setProject( project ); } void WorkPackageProxyModel::setScheduleManager(ScheduleManager *sm) { debugPlan<setScheduleManager( sm ); } NodeItemModel *WorkPackageProxyModel::baseModel() const { return m_nodemodel; } void WorkPackageProxyModel::detachTasks( Task *task ) { if ( task ) { - disconnect(task, SIGNAL(workPackageToBeAdded(KPlato::Node*,int)), this, SLOT(workPackageToBeAdded(KPlato::Node*,int))); - disconnect(task, SIGNAL(workPackageAdded(KPlato::Node*)), this, SLOT(workPackageAdded(KPlato::Node*))); - disconnect(task, SIGNAL(workPackageToBeRemoved(KPlato::Node*,int)), this, SLOT(workPackageToBeRemoved(KPlato::Node*,int))); - disconnect(task, SIGNAL(workPackageRemoved(KPlato::Node*)), this, SLOT(workPackageRemoved(KPlato::Node*))); + disconnect(task, &Task::workPackageToBeAdded, this, &WorkPackageProxyModel::workPackageToBeAdded); + disconnect(task, &Task::workPackageAdded, this, &WorkPackageProxyModel::workPackageAdded); + disconnect(task, &Task::workPackageToBeRemoved, this, &WorkPackageProxyModel::workPackageToBeRemoved); + disconnect(task, &Task::workPackageRemoved, this, &WorkPackageProxyModel::workPackageRemoved); // debugPlan< #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kio/job.h" #include "kio/mkdirjob.h" #include "kio/copyjob.h" #include "kio/deletejob.h" #include "kio/scheduler.h" namespace KIO { class NetAccessPrivate { public: NetAccessPrivate() : m_metaData(0) , bJobOK(true) {} UDSEntry m_entry; QString m_mimetype; QByteArray m_data; QUrl m_url; QMap *m_metaData; /** * Whether the download succeeded or not */ bool bJobOK; }; } // namespace KIO using namespace KIO; /** * List of temporary files */ static QStringList *tmpfiles; static QString *lastErrorMsg = 0; static int lastErrorCode = 0; NetAccess::NetAccess() : d(new NetAccessPrivate) { } NetAccess::~NetAccess() { delete d; } bool NetAccess::download(const QUrl &u, QString &target, QWidget *window) { if (u.isLocalFile()) { // file protocol. We do not need the network target = u.toLocalFile(); const bool readable = QFileInfo(target).isReadable(); if (!readable) { if (!lastErrorMsg) { lastErrorMsg = new QString; } *lastErrorMsg = i18n("File '%1' is not readable", target); lastErrorCode = ERR_COULD_NOT_READ; } return readable; } if (target.isEmpty()) { QTemporaryFile tmpFile; tmpFile.setAutoRemove(false); tmpFile.open(); target = tmpFile.fileName(); if (!tmpfiles) { tmpfiles = new QStringList; } tmpfiles->append(target); } NetAccess kioNet; const QUrl dest = QUrl::fromLocalFile(target); return kioNet.filecopyInternal(u, dest, -1, KIO::Overwrite, window, false /*copy*/); } bool NetAccess::upload(const QString &src, const QUrl &target, QWidget *window) { if (target.isEmpty()) { return false; } // If target is local... well, just copy. This can be useful // when the client code uses a temp file no matter what. // Let's make sure it's not the exact same file though if (target.isLocalFile() && target.toLocalFile() == src) { return true; } NetAccess kioNet; const QUrl srcUrl = QUrl::fromLocalFile(src); return kioNet.filecopyInternal(srcUrl, target, -1, KIO::Overwrite, window, false /*copy*/); } #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::file_copy(const QUrl &src, const QUrl &target, QWidget *window) { NetAccess kioNet; return kioNet.filecopyInternal(src, target, -1, KIO::DefaultFlags, window, false /*copy*/); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::copy(const QUrl &src, const QUrl &target, QWidget *window) { return file_copy(src, target, window); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::dircopy(const QUrl &src, const QUrl &target, QWidget *window) { QList srcList; srcList.append(src); return NetAccess::dircopy(srcList, target, window); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::dircopy(const QList &srcList, const QUrl &target, QWidget *window) { NetAccess kioNet; return kioNet.dircopyInternal(srcList, target, window, false /*copy*/); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::move(const QUrl &src, const QUrl &target, QWidget *window) { QList srcList; srcList.append(src); NetAccess kioNet; return kioNet.dircopyInternal(srcList, target, window, true /*move*/); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::move(const QList &srcList, const QUrl &target, QWidget *window) { NetAccess kioNet; return kioNet.dircopyInternal(srcList, target, window, true /*move*/); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::exists(const QUrl &url, bool source, QWidget *window) { if (url.isLocalFile()) { return QFile::exists(url.toLocalFile()); } NetAccess kioNet; return kioNet.statInternal(url, 0 /*no details*/, source ? SourceSide : DestinationSide, window); } #endif bool NetAccess::exists(const QUrl &url, StatSide side, QWidget *window) { if (url.isLocalFile()) { return QFile::exists(url.toLocalFile()); } NetAccess kioNet; return kioNet.statInternal(url, 0 /*no details*/, side, window); } bool NetAccess::stat(const QUrl &url, KIO::UDSEntry &entry, QWidget *window) { NetAccess kioNet; bool ret = kioNet.statInternal(url, 2 /*all details*/, SourceSide, window); if (ret) { entry = kioNet.d->m_entry; } return ret; } QUrl NetAccess::mostLocalUrl(const QUrl &url, QWidget *window) { if (url.isLocalFile()) { return url; } KIO::UDSEntry entry; if (!stat(url, entry, window)) { return url; } const QString path = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH); if (!path.isEmpty()) { QUrl new_url = QUrl::fromLocalFile(path); return new_url; } return url; } #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::del(const QUrl &url, QWidget *window) { NetAccess kioNet; return kioNet.delInternal(url, window); } #endif #ifndef KDELIBS4SUPPORT_NO_DEPRECATED bool NetAccess::mkdir(const QUrl &url, QWidget *window, int permissions) { NetAccess kioNet; return kioNet.mkdirInternal(url, permissions, window); } #endif QString NetAccess::fish_execute(const QUrl &url, const QString &command, QWidget *window) { NetAccess kioNet; return kioNet.fish_executeInternal(url, command, window); } bool NetAccess::synchronousRun(Job *job, QWidget *window, QByteArray *data, QUrl *finalURL, QMap *metaData) { NetAccess kioNet; // Disable autodeletion until we are back from this event loop (#170963) // We just have to hope people don't mess with setAutoDelete in slots connected to the job, though. const bool wasAutoDelete = job->isAutoDelete(); job->setAutoDelete(false); const bool ok = kioNet.synchronousRunInternal(job, window, data, finalURL, metaData); if (wasAutoDelete) { job->deleteLater(); } return ok; } QString NetAccess::mimetype(const QUrl &url, QWidget *window) { NetAccess kioNet; return kioNet.mimetypeInternal(url, window); } QString NetAccess::lastErrorString() { return lastErrorMsg ? *lastErrorMsg : QString(); } int NetAccess::lastError() { return lastErrorCode; } void NetAccess::removeTempFile(const QString &name) { if (!tmpfiles) { return; } if (tmpfiles->contains(name)) { QFile::remove(name); tmpfiles->removeAll(name); } } bool NetAccess::filecopyInternal(const QUrl &src, const QUrl &target, int permissions, KIO::JobFlags flags, QWidget *window, bool move) { d->bJobOK = true; // success unless further error occurs KIO::Scheduler::checkSlaveOnHold(true); KIO::Job *job = move ? KIO::file_move(src, target, permissions, flags) : KIO::file_copy(src, target, permissions, flags); KJobWidgets::setWindow(job, window); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); enter_loop(); return d->bJobOK; } bool NetAccess::dircopyInternal(const QList &src, const QUrl &target, QWidget *window, bool move) { d->bJobOK = true; // success unless further error occurs KIO::Job *job = move ? KIO::move(src, target) : KIO::copy(src, target); KJobWidgets::setWindow(job, window); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); enter_loop(); return d->bJobOK; } bool NetAccess::statInternal(const QUrl &url, int details, StatSide side, QWidget *window) { d->bJobOK = true; // success unless further error occurs KIO::JobFlags flags = url.isLocalFile() ? KIO::HideProgressInfo : KIO::DefaultFlags; KIO::StatJob *job = KIO::stat(url, flags); KJobWidgets::setWindow(job, window); job->setDetails(details); job->setSide(side == SourceSide ? StatJob::SourceSide : StatJob::DestinationSide); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); enter_loop(); return d->bJobOK; } bool NetAccess::delInternal(const QUrl &url, QWidget *window) { d->bJobOK = true; // success unless further error occurs KIO::Job *job = KIO::del(url); KJobWidgets::setWindow(job, window); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); enter_loop(); return d->bJobOK; } bool NetAccess::mkdirInternal(const QUrl &url, int permissions, QWidget *window) { d->bJobOK = true; // success unless further error occurs KIO::Job *job = KIO::mkdir(url, permissions); KJobWidgets::setWindow(job, window); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); enter_loop(); return d->bJobOK; } QString NetAccess::mimetypeInternal(const QUrl &url, QWidget *window) { d->bJobOK = true; // success unless further error occurs d->m_mimetype = QLatin1String("unknown"); KIO::Job *job = KIO::mimetype(url); KJobWidgets::setWindow(job, window); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); connect(job, SIGNAL(mimetype(KIO::Job*,QString)), this, SLOT(slotMimetype(KIO::Job*,QString))); enter_loop(); return d->m_mimetype; } void NetAccess::slotMimetype(KIO::Job *, const QString &type) { d->m_mimetype = type; } QString NetAccess::fish_executeInternal(const QUrl &url, const QString &command, QWidget *window) { QString target, remoteTempFileName, resultData; QTemporaryFile tmpFile; tmpFile.open(); if (url.scheme() == "fish") { // construct remote temp filename QUrl tempPathUrl = url; remoteTempFileName = tmpFile.fileName(); // We only need the filename. The directory might not exist on the remote side. int pos = remoteTempFileName.lastIndexOf('/'); remoteTempFileName = "/tmp/fishexec_" + remoteTempFileName.mid(pos + 1); tempPathUrl.setPath(remoteTempFileName); d->bJobOK = true; // success unless further error occurs QByteArray packedArgs; QDataStream stream(&packedArgs, QIODevice::WriteOnly); stream << int('X') << tempPathUrl << command; KIO::Job *job = KIO::special(tempPathUrl, packedArgs); KJobWidgets::setWindow(job, window); - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); enter_loop(); // since the KIO::special does not provide feedback we need to download the result if (NetAccess::download(tempPathUrl, target, window)) { QFile resultFile(target); if (resultFile.open(QIODevice::ReadOnly)) { QTextStream ts(&resultFile); // default encoding is Locale resultData = ts.readAll(); resultFile.close(); NetAccess::del(tempPathUrl, window); } } } else { resultData = i18n("ERROR: Unknown protocol '%1'", url.scheme()); } return resultData; } bool NetAccess::synchronousRunInternal(Job *job, QWidget *window, QByteArray *data, QUrl *finalURL, QMap *metaData) { KJobWidgets::setWindow(job, window); d->m_metaData = metaData; if (d->m_metaData) { for (QMap::iterator it = d->m_metaData->begin(); it != d->m_metaData->end(); ++it) { job->addMetaData(it.key(), it.value()); } } if (finalURL) { SimpleJob *sj = qobject_cast(job); if (sj) { d->m_url = sj->url(); } } - connect(job, SIGNAL(result(KJob*)), - this, SLOT(slotResult(KJob*))); + connect(job, &KJob::result, + this, &NetAccess::slotResult); const QMetaObject *meta = job->metaObject(); static const char dataSignal[] = "data(KIO::Job*,QByteArray)"; if (meta->indexOfSignal(dataSignal) != -1) { connect(job, SIGNAL(data(KIO::Job*,QByteArray)), this, SLOT(slotData(KIO::Job*,QByteArray))); } static const char redirSignal[] = "redirection(KIO::Job*,QUrl)"; if (meta->indexOfSignal(redirSignal) != -1) { connect(job, SIGNAL(redirection(KIO::Job*,QUrl)), this, SLOT(slotRedirection(KIO::Job*,QUrl))); } enter_loop(); if (finalURL) { *finalURL = d->m_url; } if (data) { *data = d->m_data; } return d->bJobOK; } void NetAccess::enter_loop() { QEventLoop eventLoop; - connect(this, SIGNAL(leaveModality()), - &eventLoop, SLOT(quit())); + connect(this, &NetAccess::leaveModality, + &eventLoop, &QEventLoop::quit); eventLoop.exec(QEventLoop::ExcludeUserInputEvents); } void NetAccess::slotResult(KJob *job) { lastErrorCode = job->error(); d->bJobOK = !job->error(); if (!d->bJobOK) { if (!lastErrorMsg) { lastErrorMsg = new QString; } *lastErrorMsg = job->errorString(); } KIO::StatJob *statJob = qobject_cast(job); if (statJob) { d->m_entry = statJob->statResult(); } KIO::Job *kioJob = qobject_cast(job); if (kioJob && d->m_metaData) { *d->m_metaData = kioJob->metaData(); } emit leaveModality(); } void NetAccess::slotData(KIO::Job *, const QByteArray &data) { if (data.isEmpty()) { return; } unsigned offset = d->m_data.size(); d->m_data.resize(offset + data.size()); std::memcpy(d->m_data.data() + offset, data.data(), data.size()); } void NetAccess::slotRedirection(KIO::Job *, const QUrl &url) { d->m_url = url; } diff --git a/src/libs/ui/ResourceAllocationView.cpp b/src/libs/ui/ResourceAllocationView.cpp index 5899e3b6..3d9bf5f4 100644 --- a/src/libs/ui/ResourceAllocationView.cpp +++ b/src/libs/ui/ResourceAllocationView.cpp @@ -1,164 +1,164 @@ /* 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. */ #include "ResourceAllocationView.h" #include "kptnode.h" #include "kptresource.h" #include "kptnodeitemmodel.h" #include "kptresourcemodel.h" #include "kptcommand.h" #include #include #include #include #include #include #include namespace KPlato { ResourceAllocationView::ResourceAllocationView(KoDocument *doc, QWidget *parent) : QTreeView(parent) , m_doc(doc) { m_allocateAction = new QAction(i18n("Allocate"), this); - connect(m_allocateAction, SIGNAL(triggered(bool)), this, SLOT(slotAllocate())); + connect(m_allocateAction, &QAction::triggered, this, &ResourceAllocationView::slotAllocate); } QList ResourceAllocationView::selectedResources() const { QList resources; ResourceItemModel *m = qobject_cast(model()); if (m) { foreach(const QModelIndex &idx, selectionModel()->selectedRows()) { Resource *r = m->resource(idx); if (r) { resources << r; } } } return resources; } void ResourceAllocationView::setSelectedTasks(const QItemSelection &selected, const QItemSelection &deselected) { for (QModelIndex &idx : deselected.indexes()) { if (m_tasks.contains(idx)) { m_tasks.removeAt(m_tasks.indexOf(idx)); } } QModelIndexList tasks = selected.indexes(); if (tasks.isEmpty()) { return; } const NodeItemModel *m = qobject_cast(tasks.first().model()); if (!m) { return; } for (const QModelIndex &idx : tasks) { if (idx.column() != NodeModel::NodeAllocation) { continue; } Node *n = m->node(idx); if (n->type() != Node::Type_Task) { continue; } m_tasks << QPersistentModelIndex(idx); } } void ResourceAllocationView::contextMenuEvent(QContextMenuEvent *event) { if (m_tasks.isEmpty()) { return; } if (selectedResources().isEmpty()) { return; } QMenu menu; menu.move(event->globalPos()); menu.addAction(m_allocateAction); menu.exec(); return; } void ResourceAllocationView::slotAllocate() { if (!m_doc) { warnPlan<<"ResourceAllocationView has no document, commands cannot be executed"; return; } QList lst; for (QPersistentModelIndex &idx : m_tasks) { if (idx.isValid()) { lst << idx; } } if (lst.isEmpty()) { return; } QList resources = selectedResources(); if (resources.isEmpty()) { return; } const NodeItemModel *m = qobject_cast(lst.first().model()); MacroCommand *cmd = new MacroCommand(); for (QPersistentModelIndex &idx : lst) { Node *n = m->node(idx); if (!n || n->type() != Node::Type_Task) { continue; } Task *t = static_cast(n); // remove any requests before adding new ones foreach(ResourceGroupRequest *r, t->requests().requests()) { RemoveResourceGroupRequestCmd *c = new RemoveResourceGroupRequestCmd(r); c->execute(); // need to remove everyting before we add anything cmd->addCommand(c); } QHash groups; for (Resource *r : resources) { if (!groups.contains(r->parentGroup())) { groups[r->parentGroup()] = new ResourceGroupRequest(r->parentGroup()); AddResourceGroupRequestCmd *c = new AddResourceGroupRequestCmd(*t, groups[r->parentGroup()]); c->execute(); cmd->addCommand(c); } ResourceRequest *rr = new ResourceRequest(r); rr->setUnits(100); // defaults to 100% AddResourceRequestCmd *c = new AddResourceRequestCmd(groups[r->parentGroup()], rr); c->execute(); cmd->addCommand(c); } } if (cmd->isEmpty()) { delete cmd; } else { MacroCommand *m = new MacroCommand(kundo2_i18n("Modify resource allocations")); m_doc->addCommand(m); m->addCommand(cmd); } } } // namespace KPlato diff --git a/src/libs/ui/TasksEditController.cpp b/src/libs/ui/TasksEditController.cpp index 53fcce7c..b63a44c0 100644 --- a/src/libs/ui/TasksEditController.cpp +++ b/src/libs/ui/TasksEditController.cpp @@ -1,78 +1,78 @@ /* This file is part of the KDE project Copyright (C) 2002 Bo Thorsen bo@sonofthor.dk Copyright (C) 2004 -2010 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 "TasksEditController.h" #include "TasksEditDialog.h" #include "kpttaskcostpanel.h" #include "kpttaskgeneralpanel.h" #include "kptrequestresourcespanel.h" #include "kptdocumentspanel.h" #include "kpttaskdescriptiondialog.h" #include "kptcommand.h" #include "kptnode.h" #include "kpttask.h" #include "kptproject.h" #include #include namespace KPlato { TasksEditController::TasksEditController(Project &project, const QList &tasks, QObject *p) : QObject(p) , m_project(project) , m_tasks(tasks) , m_dlg(0) { } TasksEditController::~TasksEditController() { delete m_dlg; } void TasksEditController::activate() { m_dlg = new TasksEditDialog(m_project, m_tasks); - connect(m_dlg, SIGNAL(finished(int)), this, SLOT(finish(int))); + connect(m_dlg, &QDialog::finished, this, &TasksEditController::finish); m_dlg->show(); m_dlg->raise(); m_dlg->activateWindow(); } void TasksEditController::finish(int result) { if (!m_dlg || sender() != m_dlg) { return; } if (result == QDialog::Accepted) { MacroCommand *m = m_dlg->buildCommand(); if (m) { emit addCommand(m); } } m_dlg->hide(); deleteLater(); } } //KPlato namespace diff --git a/src/libs/ui/kptaccountseditor.cpp b/src/libs/ui/kptaccountseditor.cpp index 63598264..0112bf27 100644 --- a/src/libs/ui/kptaccountseditor.cpp +++ b/src/libs/ui/kptaccountseditor.cpp @@ -1,382 +1,382 @@ /* This file is part of the KDE project Copyright (C) 2007 Dag Andersen Copyright (C) 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. */ #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, SIGNAL(accepted()), this, SLOT(slotOk())); + 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 ) { header()->setContextMenuPolicy( Qt::CustomContextMenu ); setModel( new AccountItemModel( this ) ); setSelectionModel( new QItemSelectionModel( model() ) ); setSelectionMode( QAbstractItemView::SingleSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); setAcceptDrops( false ); setDropIndicatorShown( false ); 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) { setupGui(); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new AccountTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + 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 ); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + 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() { QString name = "accountseditor_edit_list"; actionAddAccount = new QAction(koIcon("document-new"), i18n("Add Account"), this); actionCollection()->addAction("add_account", actionAddAccount ); actionCollection()->setDefaultShortcut(actionAddAccount, Qt::CTRL + Qt::Key_I); - connect( actionAddAccount, SIGNAL(triggered(bool)), SLOT(slotAddAccount()) ); + connect( actionAddAccount, &QAction::triggered, this, &AccountsEditor::slotAddAccount ); addAction( name, actionAddAccount ); actionAddSubAccount = new QAction(koIcon("document-new"), i18n("Add Subaccount"), this); actionCollection()->addAction("add_subaccount", actionAddSubAccount ); actionCollection()->setDefaultShortcut(actionAddSubAccount, Qt::SHIFT + Qt::CTRL + Qt::Key_I); - connect( actionAddSubAccount, SIGNAL(triggered(bool)), SLOT(slotAddSubAccount()) ); + connect( actionAddSubAccount, &QAction::triggered, this, &AccountsEditor::slotAddSubAccount ); addAction( name, actionAddSubAccount ); actionDeleteSelection = new QAction(koIcon("edit-delete"), i18nc("@action", "Delete"), this); actionCollection()->addAction("delete_selection", actionDeleteSelection ); actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete); - connect( actionDeleteSelection, SIGNAL(triggered(bool)), SLOT(slotDeleteSelection()) ); + connect( actionDeleteSelection, &QAction::triggered, this, &AccountsEditor::slotDeleteSelection ); addAction( name, actionDeleteSelection ); 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->show(); dlg->raise(); dlg->activateWindow(); } 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); } } // namespace KPlato diff --git a/src/libs/ui/kptaccountsview.cpp b/src/libs/ui/kptaccountsview.cpp index 04c75049..55004da1 100644 --- a/src/libs/ui/kptaccountsview.cpp +++ b/src/libs/ui/kptaccountsview.cpp @@ -1,337 +1,337 @@ /* This file is part of the KDE project Copyright (C) 2005 - 2006, 2012 Dag Andersen danders@get2net> 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 "kptaccountsview.h" #include "kptaccountsviewconfigdialog.h" #include "kptdatetime.h" #include "kptproject.h" #include "kpteffortcostmap.h" #include "kptaccountsmodel.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include namespace KPlato { AccountsTreeView::AccountsTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { debugPlan<<"---------------"<header(); v->setStretchLastSection( false ); v->setSectionResizeMode( CostBreakdownItemModel::Description, QHeaderView::Stretch ); v->setSectionResizeMode ( CostBreakdownItemModel::Total, QHeaderView::ResizeToContents ); v = m_rightview->header(); v->setSectionResizeMode ( QHeaderView::ResizeToContents ); v->setStretchLastSection( false ); m_leftHidden = QList() << CostBreakdownItemModel::Planned << CostBreakdownItemModel::Actual << -1; slotModelReset(); - connect( m, SIGNAL(modelReset()), SLOT(slotModelReset()) ); + connect( m, &QAbstractItemModel::modelReset, this, &AccountsTreeView::slotModelReset ); Help::add(this, xi18nc("@info:whatsthis", "Cost Breakdown View" "" "Displays aggregated total cost as well as cost distribution over time." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Cost_Breakdown_View"))); } void AccountsTreeView::slotModelReset() { hideColumns( m_leftHidden ); QHeaderView *v = m_leftview->header(); debugPlan<sectionSize(2)<sectionSizeHint(2)<defaultSectionSize()<minimumSectionSize(); CostBreakdownItemModel *m = static_cast(model()); QList cols; for (int c = 0; c < m->propertyCount(); ++c) { cols << c; } hideColumns( m_rightview, cols); } CostBreakdownItemModel *AccountsTreeView::model() const { return static_cast( DoubleTreeViewBase::model() ); } bool AccountsTreeView::cumulative() const { return model()->cumulative(); } void AccountsTreeView::setCumulative( bool on ) { model()->setCumulative( on ); } int AccountsTreeView::periodType() const { return model()->periodType(); } void AccountsTreeView::setPeriodType( int period ) { model()->setPeriodType( period ); } int AccountsTreeView::startMode() const { return model()->startMode(); } void AccountsTreeView::setStartMode( int mode ) { model()->setStartMode( mode ); } int AccountsTreeView::endMode() const { return model()->endMode(); } void AccountsTreeView::setEndMode( int mode ) { model()->setEndMode( mode ); } QDate AccountsTreeView::startDate() const { return model()->startDate(); } void AccountsTreeView::setStartDate( const QDate &date ) { model()->setStartDate( date ); } QDate AccountsTreeView::endDate() const { return model()->endDate(); } void AccountsTreeView::setEndDate( const QDate &date ) { model()->setEndDate( date ); } int AccountsTreeView::showMode() const { return model()->showMode(); } void AccountsTreeView::setShowMode( int show ) { model()->setShowMode( show ); } //------------------------ AccountsView::AccountsView(KoPart *part, Project *project, KoDocument *doc, QWidget *parent ) : ViewBase(part, doc, parent), m_project(project), m_manager( 0 ) { init(); setupGui(); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &AccountsView::slotContextMenuRequested ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } void AccountsView::setZoom( double zoom ) { Q_UNUSED( zoom ); } void AccountsView::init() { QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin(0); m_view = new AccountsTreeView( this ); l->addWidget( m_view ); setProject( m_project ); } void AccountsView::setupGui() { createOptionActions(ViewBase::OptionAll); } void AccountsView::slotContextMenuRequested( const QModelIndex &index, const QPoint &pos ) { debugPlan; m_view->setContextMenuIndex(index); slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); } void AccountsView::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlan; QList lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } void AccountsView::slotOptions() { debugPlan; AccountsviewConfigDialog *dlg = new AccountsviewConfigDialog( this, m_view, this, sender()->objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void AccountsView::setProject( Project *project ) { model()->setProject( project ); m_project = project; } void AccountsView::setScheduleManager( ScheduleManager *sm ) { if (!sm && m_manager) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_view->masterView()->saveExpanded(element); } bool tryexpand = sm && !m_manager; bool expand = sm && m_manager && sm != m_manager; QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } m_manager = sm; model()->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } CostBreakdownItemModel *AccountsView::model() const { return static_cast( m_view->model() ); } #if 0 void AccountsView::print( QPrinter &printer, QPrintDialog &printDialog ) { //debugPlan; uint top, left, bottom, right; printer.margins( &top, &left, &bottom, &right ); //debugPlan<setCumulative( (bool)( context.attribute( "cumulative" ).toInt() ) ); m_view->setPeriodType( context.attribute( "period-type", "0" ).toInt() ); m_view->setStartDate( QDate::fromString( context.attribute( "start-date", "" ), Qt::ISODate ) ); m_view->setStartMode( context.attribute( "start-mode", "0" ).toInt() ); m_view->setEndDate( QDate::fromString( context.attribute( "end-date", "" ), Qt::ISODate ) ); m_view->setEndMode( context.attribute( "end-mode", "0" ).toInt() ); //debugPlan<startMode()<startDate()<endMode()<endDate(); m_view->masterView()->setObjectName("AccountsView"); m_view->loadContext(model()->columnMap(), context); return true; } void AccountsView::saveContext( QDomElement &context ) const { //debugPlan; ViewBase::saveContext( context ); context.setAttribute( "show-mode", QString::number(m_view->showMode()) ); context.setAttribute( "cumulative", QString::number(m_view->cumulative()) ); context.setAttribute( "period-type", QString::number(m_view->periodType()) ); context.setAttribute( "start-mode", QString::number(m_view->startMode()) ); context.setAttribute( "start-date", m_view->startDate().toString( Qt::ISODate ) ); context.setAttribute( "end-mode", QString::number(m_view->endMode()) ); context.setAttribute( "end-date", m_view->endDate().toString( Qt::ISODate ) ); m_view->saveContext(model()->columnMap(), context); } KoPrintJob *AccountsView::createPrintJob() { return m_view->createPrintJob( this ); } } //KPlato namespace diff --git a/src/libs/ui/kptaccountsviewconfigdialog.cpp b/src/libs/ui/kptaccountsviewconfigdialog.cpp index 38d5663c..015b73b5 100644 --- a/src/libs/ui/kptaccountsviewconfigdialog.cpp +++ b/src/libs/ui/kptaccountsviewconfigdialog.cpp @@ -1,157 +1,157 @@ /* This file is part of the KDE project Copyright (C) 2005, 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. */ #include "kptaccountsviewconfigdialog.h" #include "kptaccountsview.h" #include "kptaccountsmodel.h" #include "kptviewbase.h" #include "kptdebug.h" #include "KoPageLayoutWidget.h" #include #include #include #include namespace KPlato { AccountsviewConfigDialog::AccountsviewConfigDialog( ViewBase *view, AccountsTreeView *treeview, QWidget *p, bool selectPrint) : KPageDialog(p), m_view( view ), m_treeview( treeview ) { setWindowTitle( i18n("Settings") ); m_panel = new AccountsviewConfigPanel( this ); switch ( treeview->startMode() ) { case CostBreakdownItemModel::StartMode_Project: m_panel->ui_projectstartBtn->setChecked( true ); m_panel->ui_startdate->setEnabled( false ); break; case CostBreakdownItemModel::StartMode_Date: m_panel->ui_startdateBtn->setChecked( true ); break; } switch ( treeview->endMode() ) { case CostBreakdownItemModel::EndMode_Project: m_panel->ui_projectendBtn->setChecked( true ); m_panel->ui_enddate->setEnabled( false ); break; case CostBreakdownItemModel::EndMode_Date: m_panel->ui_enddateBtn->setChecked( true ); break; case CostBreakdownItemModel::EndMode_CurrentDate: m_panel->ui_currentdateBtn->setChecked( true ); m_panel->ui_enddate->setEnabled( false ); break; } m_panel->ui_startdate->setDate( treeview->startDate() ); m_panel->ui_enddate->setDate( treeview->endDate() ); m_panel->ui_periodBox->setCurrentIndex( treeview->periodType() ); m_panel->ui_cumulative->setChecked( treeview->cumulative() ); m_panel->ui_showBox->setCurrentIndex( treeview->showMode() ); KPageWidgetItem *page = addPage( m_panel, i18n( "General" ) ); page->setHeader( i18n( "View 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() ); page = addPage( tab, i18n( "Printing" ) ); page->setHeader( i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } - connect( this, SIGNAL(accepted()), this, SLOT(slotOk())); + connect( this, &QDialog::accepted, this, &AccountsviewConfigDialog::slotOk); - connect(m_panel, SIGNAL(changed(bool)), SLOT(enableOkButton(bool))); + connect(m_panel, &AccountsviewConfigPanel::changed, this, &AccountsviewConfigDialog::enableOkButton); } void AccountsviewConfigDialog::enableOkButton(bool enabled) { button( QDialogButtonBox::Ok )->setEnabled( enabled ); } void AccountsviewConfigDialog::slotOk() { debugPlan; m_treeview->setPeriodType( m_panel->ui_periodBox->currentIndex() ); m_treeview->setCumulative( m_panel->ui_cumulative->isChecked() ); m_treeview->setShowMode( m_panel->ui_showBox->currentIndex() ); if ( m_panel->ui_startdateBtn->isChecked() ) { m_treeview->setStartDate( m_panel->ui_startdate->date() ); m_treeview->setStartMode( CostBreakdownItemModel::StartMode_Date ); } else { m_treeview->setStartMode( CostBreakdownItemModel::StartMode_Project ); } if ( m_panel->ui_enddateBtn->isChecked() ) { m_treeview->setEndDate( m_panel->ui_enddate->date() ); m_treeview->setEndMode( CostBreakdownItemModel::EndMode_Date ); } else if ( m_panel->ui_currentdateBtn->isChecked() ) { m_treeview->setEndMode( CostBreakdownItemModel::EndMode_CurrentDate ); } else { m_treeview->setEndMode( CostBreakdownItemModel::EndMode_Project ); } m_view->setPageLayout( m_pagelayout->pageLayout() ); m_view->setPrintingOptions( m_headerfooter->options() ); } //---------------------------- AccountsviewConfigPanel::AccountsviewConfigPanel(QWidget *parent) : AccountsviewConfigurePanelBase(parent) { - connect(ui_startdate, SIGNAL(dateChanged(QDate)), SLOT(slotChanged())); - connect(ui_enddate, SIGNAL(dateChanged(QDate)), SLOT(slotChanged())); + connect(ui_startdate, &QDateTimeEdit::dateChanged, this, &AccountsviewConfigPanel::slotChanged); + connect(ui_enddate, &QDateTimeEdit::dateChanged, this, &AccountsviewConfigPanel::slotChanged); connect(ui_periodBox, SIGNAL(activated(int)), SLOT(slotChanged())); - connect(ui_cumulative, SIGNAL(clicked()), SLOT(slotChanged())); + connect(ui_cumulative, &QAbstractButton::clicked, this, &AccountsviewConfigPanel::slotChanged); - connect(ui_projectstartBtn, SIGNAL(clicked()), SLOT(slotChanged())); - connect(ui_startdateBtn, SIGNAL(clicked()), SLOT(slotChanged())); - connect(ui_projectendBtn, SIGNAL(clicked()), SLOT(slotChanged())); - connect(ui_currentdateBtn, SIGNAL(clicked()), SLOT(slotChanged())); - connect(ui_enddateBtn, SIGNAL(clicked()), SLOT(slotChanged())); + connect(ui_projectstartBtn, &QAbstractButton::clicked, this, &AccountsviewConfigPanel::slotChanged); + connect(ui_startdateBtn, &QAbstractButton::clicked, this, &AccountsviewConfigPanel::slotChanged); + connect(ui_projectendBtn, &QAbstractButton::clicked, this, &AccountsviewConfigPanel::slotChanged); + connect(ui_currentdateBtn, &QAbstractButton::clicked, this, &AccountsviewConfigPanel::slotChanged); + connect(ui_enddateBtn, &QAbstractButton::clicked, this, &AccountsviewConfigPanel::slotChanged); connect(ui_showBox, SIGNAL(activated(int)), SLOT(slotChanged())); - connect(ui_startdateBtn, SIGNAL(toggled(bool)), ui_startdate, SLOT(setEnabled(bool))); - connect(ui_enddateBtn, SIGNAL(toggled(bool)), ui_enddate, SLOT(setEnabled(bool))); + connect(ui_startdateBtn, &QAbstractButton::toggled, ui_startdate, &QWidget::setEnabled); + connect(ui_enddateBtn, &QAbstractButton::toggled, ui_enddate, &QWidget::setEnabled); } void AccountsviewConfigPanel::slotChanged() { emit changed(true); } } //KPlato namespace diff --git a/src/libs/ui/kptcalendareditor.cpp b/src/libs/ui/kptcalendareditor.cpp index 07dcc8b8..1fab98cf 100644 --- a/src/libs/ui/kptcalendareditor.cpp +++ b/src/libs/ui/kptcalendareditor.cpp @@ -1,872 +1,872 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2012 Dag Andersen * 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. */ #include "kptcalendareditor.h" #include "kcalendar/kdatepicker.h" #include "kcalendar/kdatetable.h" //#include "kptcalendarpanel.h" #include "kptcommand.h" #include "kptcalendarmodel.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptdatetime.h" #include "kptintervaledit.h" #include "kptitemviewsettup.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { //-------------------- CalendarTreeView::CalendarTreeView( QWidget *parent ) : TreeViewBase( parent ) { header()->setContextMenuPolicy( Qt::CustomContextMenu ); setModel( new CalendarItemModel() ); setSelectionBehavior( QAbstractItemView::SelectRows ); setSelectionMode( QAbstractItemView::SingleSelection ); setSelectionModel( new QItemSelectionModel( model() ) ); setItemDelegateForColumn( CalendarItemModel::Scope, new EnumDelegate( this ) ); setItemDelegateForColumn( CalendarItemModel::TimeZone, new EnumDelegate( this ) ); // timezone #ifdef HAVE_KHOLIDAYS setItemDelegateForColumn( CalendarItemModel::HolidayRegion, new EnumDelegate( this ) ); #endif connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) ); } void CalendarTreeView::slotHeaderContextMenuRequested( const QPoint &pos ) { emit contextMenuRequested(QModelIndex(), mapToGlobal(pos)); } void CalendarTreeView::contextMenuEvent ( QContextMenuEvent *event ) { emit contextMenuRequested( indexAt(event->pos()), event->globalPos() ); } void CalendarTreeView::focusInEvent ( QFocusEvent *event ) { //debugPlan; TreeViewBase::focusInEvent( event ); emit focusChanged(); } void CalendarTreeView::focusOutEvent ( QFocusEvent * event ) { //debugPlan; TreeViewBase::focusInEvent( event ); emit focusChanged(); } void CalendarTreeView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel ) { //debugPlan<selectedIndexes() ) { debugPlan<selectedIndexes() ); } void CalendarTreeView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) { //debugPlan; TreeViewBase::currentChanged( current, previous ); // possible bug in qt: in QAbstractItemView::SingleSelection you can select multiple items/rows selectionModel()->select( current, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); emit currentChanged( current ); } Calendar *CalendarTreeView::currentCalendar() const { return model()->calendar( currentIndex() ); } Calendar *CalendarTreeView::selectedCalendar() const { QModelIndexList lst = selectionModel()->selectedRows(); if ( lst.count() == 1 ) { return model()->calendar( lst.first() ); } return 0; } QList CalendarTreeView::selectedCalendars() const { QList lst; foreach ( const QModelIndex &i, selectionModel()->selectedRows() ) { Calendar *a = model()->calendar( i ); if ( a ) { lst << a; } } return lst; } void CalendarTreeView::dragMoveEvent(QDragMoveEvent *event) { if (dragDropMode() == InternalMove && (event->source() != this || !(event->possibleActions() & Qt::MoveAction))) { return; } TreeViewBase::dragMoveEvent( event ); if ( ! event->isAccepted() ) { return; } // QTreeView thinks it's ok to drop, but it might not be... event->ignore(); QModelIndex index = indexAt( event->pos() ); if ( ! index.isValid() ) { if ( model()->dropAllowed( 0, event->mimeData() ) ) { event->accept(); } return; } Calendar *c = model()->calendar( index ); if ( c == 0 ) { errorPlan<<"no calendar to drop on!"; return; // hmmm } switch ( dropIndicatorPosition() ) { case AboveItem: case BelowItem: // c == sibling // if siblings parent is me or child of me: illegal if ( model()->dropAllowed( c->parentCal(), event->mimeData() ) ) { event->accept(); } break; case OnItem: // c == new parent if ( model()->dropAllowed( c, event->mimeData() ) ) { event->accept(); } break; default: break; } } //-------------------- CalendarDayView::CalendarDayView( QWidget *parent ) : QTableView( parent ), m_readwrite( false ) { setTabKeyNavigation( false ); setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ); horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch ); m_model = new CalendarDayItemModel( this ); setModel(m_model); verticalHeader()->hide(); actionSetWork = new QAction( i18n( "Work..." ), this ); - connect( actionSetWork, SIGNAL(triggered(bool)), SLOT(slotSetWork()) ); + connect( actionSetWork, &QAction::triggered, this, &CalendarDayView::slotSetWork ); actionSetVacation = new QAction( i18n( "Non-working" ), this ); - connect( actionSetVacation, SIGNAL(triggered(bool)), SLOT(slotSetVacation()) ); + connect( actionSetVacation, &QAction::triggered, this, &CalendarDayView::slotSetVacation ); actionSetUndefined = new QAction( i18n( "Undefined" ), this ); - connect( actionSetUndefined, SIGNAL(triggered(bool)), SLOT(slotSetUndefined()) ); + connect( actionSetUndefined, &QAction::triggered, this, &CalendarDayView::slotSetUndefined ); } QSize CalendarDayView::sizeHint() const { QSize s = QTableView::sizeHint(); s.setHeight( horizontalHeader()->height() + rowHeight( 0 ) + frameWidth() * 2 ); return s; } void CalendarDayView::slotSetWork() { debugPlan; if ( receivers( SIGNAL(executeCommand(KUndo2Command*)) ) == 0 ) { return; } Calendar *cal = model()->calendar(); if ( cal == 0 ) { return; } QModelIndexList lst = selectionModel()->selectedIndexes(); if ( lst.isEmpty() ) { lst << currentIndex(); } if ( lst.isEmpty() ) { return; } QList days; foreach ( const QModelIndex &i, lst ) { CalendarDay *day = model()->day( i ); if ( day == 0 ) { continue; } days << day; } IntervalEditDialog *dlg = new IntervalEditDialog( cal, days, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotIntervalEditDialogFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void CalendarDayView::slotIntervalEditDialogFinished( int result ) { IntervalEditDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == QDialog::Accepted ) { MacroCommand *cmd = dlg->buildCommand(); if ( cmd ) { emit executeCommand( cmd ); } } dlg->deleteLater(); } void CalendarDayView::slotSetVacation() { debugPlan; if ( receivers( SIGNAL(executeCommand(KUndo2Command*)) ) == 0 ) { return; } QModelIndexList lst = selectionModel()->selectedIndexes(); if ( lst.isEmpty() ) { lst << currentIndex(); } if ( lst.isEmpty() ) { return; } bool mod = false; MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify Weekday State" ) ); foreach ( const QModelIndex &i, lst ) { CalendarDay *day = model()->day( i ); if ( day == 0 || day->state() == CalendarDay::NonWorking ) { continue; } mod = true; m->addCommand( new CalendarModifyStateCmd( model()->calendar(), day, CalendarDay::NonWorking ) ); } if ( mod ) { emit executeCommand( m ); } else { delete m; } } void CalendarDayView::slotSetUndefined() { debugPlan; if ( receivers( SIGNAL(executeCommand(KUndo2Command*)) ) == 0 ) { return; } QModelIndexList lst = selectionModel()->selectedIndexes(); if ( lst.isEmpty() ) { lst << currentIndex(); } if ( lst.isEmpty() ) { return; } bool mod = false; MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify Weekday State" ) ); foreach ( const QModelIndex &i, lst ) { CalendarDay *day = model()->day( i ); if ( day == 0 || day->state() == CalendarDay::Undefined ) { continue; } mod = true; m->addCommand( new CalendarModifyStateCmd( model()->calendar(), day, CalendarDay::Undefined ) ); } if ( mod ) { emit executeCommand( m ); } else { delete m; } } void CalendarDayView::setCurrentCalendar( Calendar *calendar ) { model()->setCalendar( calendar ); } void CalendarDayView::contextMenuEvent ( QContextMenuEvent *event ) { //debugPlan; if ( !isReadWrite() || !model()->calendar() || model()->calendar()->isShared() ) { return; } QMenu menu; menu.addAction( actionSetWork ); menu.addAction( actionSetVacation ); menu.addAction( actionSetUndefined ); menu.exec( event->globalPos(), actionSetWork ); //emit contextMenuRequested( indexAt(event->pos()), event->globalPos() ); } void CalendarDayView::focusInEvent ( QFocusEvent *event ) { //debugPlan; QTableView::focusInEvent( event ); emit focusChanged(); } void CalendarDayView::focusOutEvent ( QFocusEvent * event ) { //debugPlan; QTableView::focusInEvent( event ); emit focusChanged(); } void CalendarDayView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel ) { //debugPlan<selectedIndexes() ) { debugPlan<selectedIndexes() ); } void CalendarDayView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) { //debugPlan; QTableView::currentChanged( current, previous ); // selectionModel()->select( current, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); emit currentChanged( current ); } CalendarDay *CalendarDayView::selectedDay() const { QModelIndexList lst = selectionModel()->selectedIndexes(); if ( lst.count() == 1 ) { return model()->day( lst.first() ); } return 0; } //----------------------------------- CalendarEditor::CalendarEditor(KoPart *part, KoDocument *doc, QWidget *parent ) : ViewBase(part, doc, parent ), m_model( new DateTableDataModel( this ) ) { Help::add(this, xi18nc( "@info:whatsthis", "Work & Vacation Editor" "" "A calendar defines availability for resources or tasks of type Duration. " "A calendar can be specific to a resource or task, or shared by multiple resources or tasks. " "A day can be of type Undefined, Non-working day or Working day. " "A working day has one or more work intervals defined. " "" "A calendar can have sub calendars. If a day is undefined in a calendar, the parent calendar is checked. " "An Undefined day defaults to Non-working if used by a resource, or available all day if used by a task." "" "A calendar can be defined as the Default calendar. " "The default calendar is used by a working resource, when the resources calendar is not explicitly set." "More..." "", Help::page("Manual/Work_and_Vacation_Editor"))); setupGui(); QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); QSplitter *sp = new QSplitter( this ); l->addWidget( sp ); m_calendarview = new CalendarTreeView( sp ); - connect(this, SIGNAL(expandAll()), m_calendarview, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_calendarview, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_calendarview, &TreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_calendarview, &TreeViewBase::slotCollapse); QFrame *f = new QFrame( sp ); l = new QVBoxLayout( f ); l->setMargin( 0 ); m_dayview = new CalendarDayView( f ); l->addWidget( m_dayview ); sp = new QSplitter( f ); l->addWidget( sp ); m_datePicker = new KDatePicker( sp ); m_datePicker->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); m_datePicker->dateTable()->setWeekNumbersEnabled( true ); m_datePicker->dateTable()->setGridEnabled( true ); m_datePicker->dateTable()->setSelectionMode( KDateTable::ExtendedSelection ); m_datePicker->dateTable()->setDateDelegate( new DateTableDateDelegate( m_datePicker->dateTable() ) ); m_datePicker->dateTable()->setModel( m_model ); m_datePicker->dateTable()->setPopupMenuEnabled( true ); m_calendarview->setDragDropMode( QAbstractItemView::InternalMove ); m_calendarview->setDropIndicatorShown( true ); m_calendarview->setDragEnabled ( true ); m_calendarview->setAcceptDrops( true ); m_calendarview->setAcceptDropsOnView( true ); connect( m_datePicker->dateTable(), SIGNAL(aboutToShowContextMenu(QMenu*,QDate)), SLOT(slotContextMenuDate(QMenu*,QDate)) ); connect( m_datePicker->dateTable(), SIGNAL(aboutToShowContextMenu(QMenu*,QList)), SLOT(slotContextMenuDate(QMenu*,QList)) ); /* const QDate date(2007,7,19); const QColor fgColor(Qt::darkGray); KDateTable::BackgroundMode bgMode = KDateTable::CircleMode; const QColor bgColor( Qt::lightGray); m_datePicker->dateTable()->setCustomDatePainting( date, fgColor, bgMode, bgColor );*/ m_calendarview->setEditTriggers( m_calendarview->editTriggers() | QAbstractItemView::EditKeyPressed ); m_dayview->setEditTriggers( m_dayview->editTriggers() | QAbstractItemView::EditKeyPressed ); m_calendarview->setDragDropMode( QAbstractItemView::InternalMove ); m_calendarview->setDropIndicatorShown ( true ); m_calendarview->setDragEnabled ( true ); m_calendarview->setAcceptDrops( true ); - connect( m_calendarview->model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); - connect( m_dayview->model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); - connect( m_dayview, SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( m_calendarview->model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); + connect( m_dayview->model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); + connect( m_dayview, &CalendarDayView::executeCommand, doc, &KoDocument::addCommand ); connect( m_calendarview, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentCalendarChanged(QModelIndex)) ); - connect( m_calendarview, SIGNAL(sigSelectionChanged(QModelIndexList)), this, SLOT(slotCalendarSelectionChanged(QModelIndexList)) ); + connect( m_calendarview, &CalendarTreeView::sigSelectionChanged, this, &CalendarEditor::slotCalendarSelectionChanged ); connect( m_calendarview, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuCalendar(QModelIndex,QPoint)) ); connect( m_dayview, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentDayChanged(QModelIndex)) ); - connect( m_dayview, SIGNAL(sigSelectionChanged(QModelIndexList)), this, SLOT(slotDaySelectionChanged(QModelIndexList)) ); - connect( m_dayview, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuDay(QModelIndex,QPoint)) ); + connect( m_dayview, &CalendarDayView::sigSelectionChanged, this, &CalendarEditor::slotDaySelectionChanged ); + connect( m_dayview, &CalendarDayView::contextMenuRequested, this, &CalendarEditor::slotContextMenuDay ); - connect( m_dayview->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(slotEnableActions()) ); + connect( m_dayview->model(), &QAbstractItemModel::dataChanged, this, &CalendarEditor::slotEnableActions ); - connect( m_calendarview, SIGNAL(focusChanged()), this, SLOT(slotEnableActions()) ); - connect( m_dayview, SIGNAL(focusChanged()), this, SLOT(slotEnableActions()) ); + connect( m_calendarview, &CalendarTreeView::focusChanged, this, &CalendarEditor::slotEnableActions ); + connect( m_dayview, &CalendarDayView::focusChanged, this, &CalendarEditor::slotEnableActions ); } void CalendarEditor::draw( Project &project ) { m_calendarview->setProject( &project ); m_dayview->setProject( &project ); } void CalendarEditor::draw() { } void CalendarEditor::setGuiActive( bool activate ) { //debugPlan<currentIndex().isValid() ) { m_calendarview->selectionModel()->setCurrentIndex(m_calendarview->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } //slotSelectionChanged( m_calendarview->selectionModel()->selectedRows() ); } } void CalendarEditor::slotContextMenuDate( QMenu *menu, const QList &dates ) { if ( ! isReadWrite() ) { return; } if (!currentCalendar() || currentCalendar()->isShared()) { return; } if ( dates.isEmpty() ) { m_currentMenuDateList << m_datePicker->date(); } else { m_currentMenuDateList = dates; } menu->addAction( actionSetWork ); menu->addAction( actionSetVacation ); menu->addAction( actionSetUndefined ); } void CalendarEditor::slotContextMenuDate( QMenu *menu, const QDate &date ) { debugPlan<isShared()) { return; } m_currentMenuDateList << date; menu->addAction( actionSetWork ); menu->addAction( actionSetVacation ); menu->addAction( actionSetUndefined ); } void CalendarEditor::slotContextMenuCalendar( const QModelIndex &index, const QPoint& pos ) { if (!index.isValid()) { slotHeaderContextMenuRequested(pos); return; } if ( ! isReadWrite() || !currentCalendar() ) { return; } //debugPlan<model()->calendar( index ); if ( a ) { name = "calendareditor_calendar_popup"; } }*/ //debugPlan<setContextMenuIndex(index); if ( name.isEmpty() ) { slotHeaderContextMenuRequested(pos); m_calendarview->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_calendarview->setContextMenuIndex(QModelIndex()); } void CalendarEditor::slotContextMenuDay( const QModelIndex &index, const QPoint& pos ) { if ( ! isReadWrite() ) { return; } debugPlan<model()->day( index ) ) { name = "calendareditor_day_popup"; } } debugPlan<loadContext(m_calendarview->model()->columnMap(), context); } void CalendarEditor::saveContext( QDomElement &context ) const { m_calendarview->saveContext(m_calendarview->model()->columnMap(), context); } Calendar *CalendarEditor::currentCalendar() const { return m_calendarview->currentCalendar(); } void CalendarEditor::slotCurrentCalendarChanged( const QModelIndex & ) { //debugPlan<setCurrentCalendar( currentCalendar() ); if ( m_model ) { m_model->setCalendar( currentCalendar() ); } } void CalendarEditor::slotCalendarSelectionChanged( const QModelIndexList& /*list */) { //debugPlan< lst = m_calendarview->selectedCalendars(); bool one = lst.count() == 1; bool more = lst.count() > 1; actionAddCalendar ->setEnabled( on && !more ); actionAddSubCalendar ->setEnabled( on && one ); actionDeleteSelection->setEnabled( on && ( one || more ) ); } void CalendarEditor::setupGui() { KActionCollection *coll = actionCollection(); QString name = "calendareditor_calendar_list"; actionAddCalendar = new QAction(koIcon("resource-calendar-insert"), i18n("Add Calendar"), this); coll->addAction("add_calendar", actionAddCalendar ); coll->setDefaultShortcut(actionAddCalendar, Qt::CTRL + Qt::Key_I); - connect( actionAddCalendar , SIGNAL(triggered(bool)), SLOT(slotAddCalendar()) ); + connect( actionAddCalendar , &QAction::triggered, this, &CalendarEditor::slotAddCalendar ); actionAddSubCalendar = new QAction(koIcon("resource-calendar-child-insert"), i18n("Add Subcalendar"), this); coll->addAction("add_subcalendar", actionAddSubCalendar ); coll->setDefaultShortcut(actionAddSubCalendar, Qt::SHIFT + Qt::CTRL + Qt::Key_I); - connect( actionAddSubCalendar , SIGNAL(triggered(bool)), SLOT(slotAddSubCalendar()) ); + connect( actionAddSubCalendar , &QAction::triggered, this, &CalendarEditor::slotAddSubCalendar ); actionDeleteSelection = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this); coll->addAction("delete_calendar_selection", actionDeleteSelection ); coll->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete); - connect( actionDeleteSelection, SIGNAL(triggered(bool)), SLOT(slotDeleteCalendar()) ); + connect( actionDeleteSelection, &QAction::triggered, this, &CalendarEditor::slotDeleteCalendar ); addAction( name, actionAddCalendar ); addAction( name, actionAddSubCalendar ); addAction( name, actionDeleteSelection ); actionSetWork = new QAction( i18n( "Work..." ), this ); - connect( actionSetWork, SIGNAL(triggered(bool)), SLOT(slotSetWork()) ); + connect( actionSetWork, &QAction::triggered, this, &CalendarEditor::slotSetWork ); actionSetVacation = new QAction( i18n( "Non-working" ), this ); - connect( actionSetVacation, SIGNAL(triggered(bool)), SLOT(slotSetVacation()) ); + connect( actionSetVacation, &QAction::triggered, this, &CalendarEditor::slotSetVacation ); actionSetUndefined = new QAction( i18n( "Undefined" ), this ); - connect( actionSetUndefined, SIGNAL(triggered(bool)), SLOT(slotSetUndefined()) ); + connect( actionSetUndefined, &QAction::triggered, this, &CalendarEditor::slotSetUndefined ); createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig); } void CalendarEditor::slotOptions() { ItemViewSettupDialog *dlg = new ItemViewSettupDialog( this, m_calendarview, false, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void CalendarEditor::updateReadWrite( bool readwrite ) { m_calendarview->setReadWrite( readwrite ); m_dayview->setReadWrite( readwrite ); ViewBase::updateReadWrite( readwrite ); } void CalendarEditor::slotAddCalendar () { //debugPlan; // get parent through sibling Calendar *cal = m_calendarview->selectedCalendar(); Calendar *parent = cal ? cal->parentCal() : 0; int pos = parent ? parent->indexOf( cal ) : project()->indexOf( cal ); if ( pos >= 0 ) { ++pos; // after selected calendar } insertCalendar ( new Calendar(), parent, pos ); } void CalendarEditor::slotAddSubCalendar () { //debugPlan; insertCalendar ( new Calendar (), m_calendarview->selectedCalendar () ); } void CalendarEditor::insertCalendar ( Calendar *calendar, Calendar *parent, int pos ) { m_calendarview->closePersistentEditor( m_calendarview->selectionModel()->currentIndex() ); QModelIndex i = m_calendarview->model()->insertCalendar ( calendar, pos, parent ); if ( i.isValid() ) { QModelIndex p = m_calendarview->model()->parent( i ); //if (parent) debugPlan<<" parent="<name()<<":"<setExpanded( p, true ); m_calendarview->setCurrentIndex( i ); m_calendarview->edit( i ); } } void CalendarEditor::slotDeleteCalendar() { //debugPlan; m_calendarview->model()->removeCalendar( m_calendarview->selectedCalendar() ); } void CalendarEditor::slotAddInterval () { //debugPlan; /* CalendarDay *parent = m_dayview->selectedDay (); if ( parent == 0 ) { TimeInterval *ti = m_dayview->selectedInterval(); if ( ti == 0 ) { return; } parent = m_dayview->model()->parentDay( ti ); if ( parent == 0 ) { return; } } QModelIndex i = m_dayview->model()->insertInterval( new TimeInterval(), parent ); if ( i.isValid() ) { QModelIndex p = m_dayview->model()->index( parent ); m_dayview->setExpanded( p, true ); m_dayview->setCurrentIndex( i ); m_dayview->edit( i ); }*/ } void CalendarEditor::slotDeleteDaySelection() { //debugPlan; /* TimeInterval *ti = m_dayview->selectedInterval(); if ( ti != 0 ) { m_dayview->model()->removeInterval( ti ); return; } CalendarDay *day = m_dayview->selectedDay(); if ( day != 0 ) { m_dayview->model()->removeDay( day ); }*/ } void CalendarEditor::slotAddDay () { //debugPlan; /* Calendar *c = currentCalendar(); if ( c == 0 ) { return; } QDate date = QDate::currentDate(); while ( c->day( date ) ) { date = date.addDays( 1 ); } QModelIndex i = m_dayview->model()->insertDay( new CalendarDay(date, CalendarDay::NonWorking ) ); if ( i.isValid() ) { QModelIndex p = m_dayview->model()->parent( i ); m_dayview->setExpanded( p, true ); m_dayview->setCurrentIndex( i ); m_dayview->edit( i ); }*/ } void CalendarEditor::slotSetWork() { debugPlan<show(); dlg->raise(); dlg->activateWindow(); m_currentMenuDateList.clear(); } void CalendarEditor::slotIntervalEditDialogFinished( int result ) { IntervalEditDialog *dlg = qobject_cast( sender() ); if ( dlg == 0 ) { return; } if ( result == QDialog::Accepted ) { MacroCommand *cmd = dlg->buildCommand(); if ( cmd ) { part()->addCommand( cmd ); } } dlg->deleteLater(); } void CalendarEditor::slotSetVacation() { debugPlan<findDay( date ); if ( day == 0 ) { mod = true; day = new CalendarDay( date, CalendarDay::NonWorking ); m->addCommand( new CalendarAddDayCmd( currentCalendar(), day ) ); if ( m_currentMenuDateList.count() == 1 ) { m->setText( kundo2_i18n( "%1: Set to Non-Working", date.toString() ) ); } } else if ( day->state() != CalendarDay::NonWorking ) { mod = true; m->addCommand( new CalendarModifyStateCmd( currentCalendar(), day, CalendarDay::NonWorking ) ); if ( m_currentMenuDateList.count() == 1 ) { m->setText( kundo2_i18n( "%1: Set to Non-Working", date.toString() ) ); } } } if ( mod ) { part()->addCommand( m ); } else { delete m; } m_currentMenuDateList.clear(); } void CalendarEditor::slotSetUndefined() { debugPlan; if ( m_currentMenuDateList.isEmpty() || currentCalendar() == 0 ) { return; } bool mod = false; MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify Calendar" ) ); foreach ( const QDate &date, m_currentMenuDateList ) { CalendarDay *day = currentCalendar()->findDay( date ); if ( day && day->state() != CalendarDay::Undefined ) { mod = true; m->addCommand( new CalendarRemoveDayCmd( currentCalendar(), day ) ); if ( m_currentMenuDateList.count() == 1 ) { m->setText( kundo2_i18n( "Set %1 to Undefined", date.toString() ) ); } } } if ( mod ) { part()->addCommand( m ); } else { delete m; } m_currentMenuDateList.clear(); } } // namespace KPlato diff --git a/src/libs/ui/kptdependencyeditor.cpp b/src/libs/ui/kptdependencyeditor.cpp index 9b729396..cd2db426 100644 --- a/src/libs/ui/kptdependencyeditor.cpp +++ b/src/libs/ui/kptdependencyeditor.cpp @@ -1,2448 +1,2448 @@ /* This file is part of the KDE project Copyright (C) 2007 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; 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 "kptdependencyeditor.h" #include "PlanMacros.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptitemmodelbase.h" #include "kptcommand.h" #include "kptproject.h" #include "kptrelation.h" #include "kptschedule.h" #include "kptdebug.h" #include "config.h" #include "Help.h" #include "KoPageLayoutWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ConnectCursor Qt::DragLinkCursor namespace KPlato { void plan_paintFocusSelectedItem( QPainter *painter, const QStyleOptionGraphicsItem *option ) { if ( option->state & ( QStyle::State_Selected | QStyle::State_HasFocus ) ) { painter->save(); if (option->state & QStyle::State_Selected) { debugPlanDepEditor<<"selected"; QPalette::ColorGroup cg = option->state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (cg == QPalette::Normal && !(option->state & QStyle::State_Active)) cg = QPalette::Inactive; QLinearGradient g( 0.0, option->rect.top(), 0.0, option->rect.bottom() ); QColor col = option->palette.brush(cg, QPalette::Highlight).color(); g.setColorAt( 0.0, col.lighter( 125 ) ); g.setColorAt( 1.0, col.lighter( 60 ) ); painter->setPen( Qt::NoPen ); painter->setBrush( QBrush( g ) ); painter->drawRect( option->exposedRect ); } if ( option->state & QStyle::State_HasFocus ) { debugPlanDepEditor<<"has focus"; QPalette::ColorGroup cg = option->state & QStyle::State_Enabled ? QPalette::Active : QPalette::Disabled; if (cg == QPalette::Active && !(option->state & QStyle::State_Active)) cg = QPalette::Inactive; QPen p( Qt::DotLine ); p.setWidthF( 2. ); if ( option->state & QStyle::State_Selected ) { p.setColor( option->palette.color( cg, QPalette::Shadow ) ); debugPlanDepEditor<<"focus: selected"<palette.color( cg, QPalette::Highlight ) ); debugPlanDepEditor<<"focus: not selected"<setPen( p ); painter->setBrush( Qt::NoBrush ); painter->drawRect( option->exposedRect ); } painter->restore(); } } //---------------------- DependecyViewPrintingDialog::DependecyViewPrintingDialog( ViewBase *parent, DependencyView *view ) : PrintingDialog( parent ), m_depview( view ) { debugPlanDepEditor< DependecyViewPrintingDialog::createOptionWidgets() const { QList lst; lst << createPageLayoutWidget(); lst += PrintingDialog::createOptionWidgets(); return lst; } void DependecyViewPrintingDialog::printPage( int page, QPainter &painter ) { painter.save(); QRect hRect = headerRect(); QRect fRect = footerRect(); QRect pageRect = printer().pageRect(); pageRect.moveTo( 0, 0 ); debugPlanDepEditor<project()) ); int gap = 8; int pageHeight = pageRect.height(); if ( hRect.isValid() ) { pageHeight -= ( hRect.height() + gap ); } if ( fRect.isValid() ) { pageHeight -= ( fRect.height() + gap ); } painter.translate( 0, hRect.height() + gap ); QRect r( 0, 0, pageRect.width(), pageHeight ); m_depview->itemScene()->render( &painter, r ); painter.restore(); } DependencyLinkItemBase::DependencyLinkItemBase( QGraphicsItem *parent ) : QGraphicsPathItem( parent ), m_editable( false ), predItem( 0 ), succItem( 0 ), relation( 0 ), m_arrow( new QGraphicsPathItem( this ) ) { } DependencyLinkItemBase::DependencyLinkItemBase( DependencyNodeItem *predecessor, DependencyNodeItem *successor, Relation *rel, QGraphicsItem *parent ) : QGraphicsPathItem( parent ), m_editable( false ), predItem( predecessor ), succItem( successor ), relation( rel ), m_arrow( new QGraphicsPathItem( this ) ) { } DependencyLinkItemBase::~DependencyLinkItemBase() { } DependencyScene *DependencyLinkItemBase::itemScene() const { return static_cast( scene() ); } void DependencyLinkItemBase::createPath( const QPointF &sp, int starttype, const QPointF &ep, int endtype ) { //if ( predItem && succItem ) debugPlanDepEditor<text()<<" ->"<text()<<" visible="<horizontalGap(); bool up = sp.y() > ep.y(); bool right = sp.x() < ep.x(); bool same = sp.x() == ep.x(); QPainterPath link( sp ); qreal x = sp.x(); qreal y = sp.y(); if ( right && starttype == DependencyNodeItem::Finish) { x = ep.x(); x += endtype == DependencyNodeItem::Start ? - hgap/2 - 6 : hgap/2 - 6; link.lineTo( x, y ); x += 6; QPointF cp( x, y ); y += up ? -6 : +6; link.quadTo( cp, QPointF( x, y ) ); y = up ? ep.y() + 6 : ep.y() - 6; link.lineTo( x, y ); y = ep.y(); cp = QPointF( x, y ); x += endtype == DependencyNodeItem::Start ? 6 : -6; link.quadTo( cp, QPointF( x, y ) ); } else if ( right && starttype == DependencyNodeItem::Start ) { x = sp.x() - hgap/2 + 6; link.lineTo( x, y ); x -= 6; QPointF cp( x, y ); y += up ? -6 : +6; link.quadTo( cp, QPointF( x, y ) ); y = up ? ep.y() + 6 : ep.y() - 6; link.lineTo( x, y ); y = ep.y(); cp = QPointF( x, y ); x += endtype == DependencyNodeItem::Start ? 6 : -6; link.quadTo( cp, QPointF( x, y ) ); } else if ( same ) { x = ep.x(); x += endtype == DependencyNodeItem::Start ? - hgap/2 + 6 : hgap/2 - 6; link.lineTo( x, y ); x += endtype == DependencyNodeItem::Start ? -6 : +6; QPointF cp( x, y ); y += up ? -6 : 6; link.quadTo( cp, QPointF( x, y ) ); y = up ? ep.y() + 6 : ep.y() - 6; link.lineTo( x, y ); y = ep.y(); cp = QPointF( x, y ); if ( endtype == DependencyNodeItem::Start ) { x += 6; } else { x -= 6; } link.quadTo( cp, QPointF( x, y ) ); } else { x = ep.x(); x += endtype == DependencyNodeItem::Start ? - hgap/2 + 6 : hgap/2 + 6; link.lineTo( x, y ); x -= 6; QPointF cp( x, y ); y += up ? -6 : 6; link.quadTo( cp, QPointF( x, y ) ); y = up ? ep.y() + 6 : ep.y() - 6; link.lineTo( x, y ); y = ep.y(); cp = QPointF( x, y ); x += endtype == DependencyNodeItem::Start ? 6 : -6; link.quadTo( cp, QPointF( x, y ) ); } link.lineTo( ep ); setPath( link ); QPainterPath arrow; x = endtype == DependencyNodeItem::Start ? -6 : 6; arrow.moveTo( ep ); arrow.lineTo( ep.x() + x, ep.y() - 3 ); arrow.lineTo( ep.x() + x, ep.y() + 3 ); arrow.lineTo( ep ); m_arrow->setPath( arrow ); m_arrow->show(); } //-------------------------------- DependencyLinkItem::DependencyLinkItem( DependencyNodeItem *predecessor, DependencyNodeItem *successor, Relation *rel, QGraphicsItem *parent ) : DependencyLinkItemBase( predecessor, successor, rel, parent ) { setZValue( 100.0 ); setAcceptHoverEvents( true ); //debugPlanDepEditor<text()<<"("<column()<<") -"<text(); predItem->addChildRelation( this ); succItem->addParentRelation( this ); succItem->setColumn(); m_arrow->setBrush( Qt::black ); m_pen = pen(); } DependencyLinkItem::~DependencyLinkItem() { if ( predItem ) { predItem->takeChildRelation( this ); } if ( succItem ) { succItem->takeParentRelation( this ); } } int DependencyLinkItem::newChildColumn() const { int col = predItem->column(); if ( relation->type() == Relation::FinishStart ) { ++col; } //debugPlanDepEditor<<"new col="<isVisible() && succItem->isVisible() ); } void DependencyLinkItem::createPath() { setVisible( predItem->isVisible() && succItem->isVisible() ); if ( ! isVisible() ) { //debugPlanDepEditor<<"Visible="<node()->name()<<" -"<node()->name(); return; } QPointF sp = startPoint(); QPointF ep = endPoint(); int stype = 0, etype = 0; switch ( relation->type() ) { case Relation::StartStart: stype = DependencyNodeItem::Start; etype = DependencyNodeItem::Start; break; case Relation::FinishStart: stype = DependencyNodeItem::Finish; etype = DependencyNodeItem::Start; break; case Relation::FinishFinish: stype = DependencyNodeItem::Finish; etype = DependencyNodeItem::Finish; break; default: break; } DependencyLinkItemBase::createPath( sp, stype, ep, etype ); } QPointF DependencyLinkItem::startPoint() const { if ( relation->type() == Relation::StartStart ) { return predItem->connectorPoint( DependencyNodeItem::Start ); } return predItem->connectorPoint( DependencyNodeItem::Finish ); } QPointF DependencyLinkItem::endPoint() const { if ( relation->type() == Relation::FinishFinish ) { return succItem->connectorPoint( DependencyNodeItem::Finish ); } return succItem->connectorPoint( DependencyNodeItem::Start ); } void DependencyLinkItem::hoverEnterEvent( QGraphicsSceneHoverEvent * /*event*/ ) { setZValue( zValue() + 1 ); setPen( QPen( Qt::black, 2 ) ); m_arrow->setPen( pen() ); update(); } void DependencyLinkItem::hoverLeaveEvent( QGraphicsSceneHoverEvent * /*event*/ ) { resetHooverIndication(); } void DependencyLinkItem::resetHooverIndication() { setZValue( zValue() - 1 ); setPen( m_pen ); m_arrow->setPen( m_pen ); update(); } void DependencyLinkItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { //debugPlanDepEditor; QGraphicsItem::GraphicsItemFlags f = flags(); if ( isEditable() && itemScene()->connectionMode() ) { itemScene()->clearConnection(); setFlags( f & ~QGraphicsItem::ItemIsSelectable ); } QGraphicsPathItem::mousePressEvent( event ); if ( f != flags() ) { setFlags( f ); } } //-------------------- DependencyCreatorItem::DependencyCreatorItem( QGraphicsItem *parent ) : DependencyLinkItemBase( parent ), predConnector( 0 ), succConnector( 0 ), m_editable( false ) { setZValue( 1000.0 ); clear(); setPen( QPen( Qt::blue, 2 ) ); m_arrow->setBrush( Qt::blue ); m_arrow->setPen( QPen( Qt::blue, 2 ) ); } void DependencyCreatorItem::clear() { hide(); if ( predConnector && predConnector->parentItem() ) { static_cast( predConnector->parentItem() )->setConnectorHoverMode( true ); } else if ( succConnector && succConnector->parentItem() ) { static_cast( succConnector->parentItem() )->setConnectorHoverMode( true ); } predConnector = 0; succConnector = 0; setPath( QPainterPath() ); m_arrow->setPath( QPainterPath() ); } void DependencyCreatorItem::setPredConnector( DependencyConnectorItem *item ) { predConnector = item; //static_cast( item->parentItem() )->setConnectorHoverMode( false ); } void DependencyCreatorItem::setSuccConnector( DependencyConnectorItem *item ) { succConnector = item; } void DependencyCreatorItem::createPath() { if ( predConnector == 0 ) { return; } if ( succConnector == 0 ) { return; } QPointF sp = predConnector->connectorPoint(); QPointF ep = succConnector->connectorPoint(); DependencyLinkItemBase::createPath( sp, predConnector->ctype(), ep, succConnector->ctype() ); } void DependencyCreatorItem::createPath( const QPointF &ep ) { m_arrow->hide(); if ( succConnector ) { return createPath(); } if ( predConnector == 0 ) { return; } QPointF sp = predConnector->connectorPoint(); QPainterPath link( sp ); link.lineTo( ep ); setPath( link ); } QPointF DependencyCreatorItem::startPoint() const { return predConnector == 0 ? QPointF() : predConnector->connectorPoint(); } QPointF DependencyCreatorItem::endPoint() const { return succConnector == 0 ? QPointF() : succConnector->connectorPoint(); } //-------------------- DependencyConnectorItem::DependencyConnectorItem( DependencyNodeItem::ConnectorType type, DependencyNodeItem *parent ) : QGraphicsRectItem( parent ), m_ctype( type ), m_editable( false ) { setCursor( ConnectCursor); setAcceptHoverEvents( true ); setZValue( 500.0 ); setFlag( QGraphicsItem::ItemIsFocusable ); } DependencyScene *DependencyConnectorItem::itemScene() const { return static_cast( scene() ); } DependencyNodeItem *DependencyConnectorItem::nodeItem() const { return static_cast( parentItem() ); } Node *DependencyConnectorItem::node() const { return static_cast( parentItem() )->node(); } QPointF DependencyConnectorItem::connectorPoint() const { QRectF r = rect(); return QPointF( r.x()+r.width(), r.y() + r.height()/2 ); } void DependencyConnectorItem::hoverEnterEvent( QGraphicsSceneHoverEvent * /*event*/ ) { itemScene()->connectorEntered( this, true ); } void DependencyConnectorItem::hoverLeaveEvent( QGraphicsSceneHoverEvent * /*event*/ ) { itemScene()->connectorEntered( this, false ); } void DependencyConnectorItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if ( ! isEditable() ) { event->ignore(); return; } if (event->button() == Qt::LeftButton ) { m_mousePressPos = event->pos(); } else { event->ignore(); } } void DependencyConnectorItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { m_mousePressPos = QPointF(); if (event->button() != Qt::LeftButton ) { event->ignore(); return; } if ( rect().contains( event->scenePos() ) ) { // user clicked on this item bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0; if (multiSelect) { itemScene()->multiConnectorClicked( this ); } else { itemScene()->singleConnectorClicked( this ); } return; } QGraphicsItem *item = 0; foreach ( QGraphicsItem *i, itemScene()->items( event->scenePos() ) ) { if ( i->type() == DependencyConnectorItem::Type ) { item = i; break; } } if ( item == 0 || item == itemScene()->fromItem() ) { itemScene()->setFromItem( 0 ); return; } itemScene()->singleConnectorClicked( static_cast( item ) ); } void DependencyConnectorItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (event->buttons() == Qt::LeftButton ) { if ( ! m_mousePressPos.isNull() ) { itemScene()->setFromItem( this ); m_mousePressPos = QPointF(); } QGraphicsItem *item = 0; foreach ( QGraphicsItem *i, itemScene()->items( event->scenePos() ) ) { if ( i->type() == DependencyConnectorItem::Type ) { item = i; break; } } if ( item != this ) { itemScene()->connectorEntered( this, false ); } if ( item != 0 ) { itemScene()->connectorEntered( static_cast( item ), true ); } } else { event->ignore(); } } void DependencyConnectorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget */*widget*/) { //debugPlanDepEditor; QStyleOptionGraphicsItem opt( *option ); opt.exposedRect = rect(); if ( itemScene()->fromItem() == this ) { opt.state |= QStyle::State_Selected; } if ( itemScene()->focusItem() == this ) { opt.state |= QStyle::State_HasFocus; } plan_paintFocusSelectedItem( painter, &opt ); QRectF r = rect(); if ( ctype() == DependencyNodeItem::Start ) { r.setRect( r.right() - (r.width()/2.0) + 1.0, r.y() + ( r.height() * 0.33 ), r.width() / 2.0, r.height() * 0.33 ); } else { r.setRect( r.right() - (r.width()/2.0) - 1.0, r.y() + ( r.height() * 0.33 ), r.width() / 2.0, r.height() * 0.33 ); } painter->fillRect( r, Qt::black ); } QList DependencyConnectorItem::predecessorItems() const { return nodeItem()->predecessorItems( m_ctype ); } QList DependencyConnectorItem::successorItems() const { return nodeItem()->successorItems( m_ctype ); } //-------------------- DependencyNodeItem::DependencyNodeItem( Node *node, DependencyNodeItem *parent ) : QGraphicsRectItem( parent ), m_node( node ), m_parent( 0 ), m_editable( false ) { setAcceptHoverEvents( true ); setZValue( 400.0 ); setParentItem( parent ); m_start = new DependencyConnectorItem( DependencyNodeItem::Start, this ); m_finish = new DependencyConnectorItem( DependencyNodeItem::Finish, this ); m_text = new QGraphicsTextItem( this ); m_textFont = m_text->font(); m_textFont.setPointSize( 10 ); m_text->setFont( m_textFont ); setText(); setFlags( QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable ); // do not attach this item to the scene as it gives continuous paint events when a node item is selected m_symbol = new DependencyNodeSymbolItem(); m_symbol->setZValue( zValue() + 10.0 ); setSymbol(); m_treeIndicator = new QGraphicsPathItem( this ); m_treeIndicator->setPen( QPen( Qt::gray ) ); } DependencyNodeItem::~DependencyNodeItem() { qDeleteAll( m_childrelations ); qDeleteAll( m_parentrelations ); //qDeleteAll( m_children ); delete m_symbol; } void DependencyNodeItem::setText() { m_text->setPlainText( m_node == 0 ? QString() : QString( "%1 %2").arg( m_node->wbsCode() ).arg(m_node->name() ) ); } DependencyScene *DependencyNodeItem::itemScene() const { return static_cast( scene() ); } void DependencyNodeItem::setSymbol() { m_symbol->setSymbol( m_node->type(), itemScene()->symbolRect() ); } QPointF DependencyNodeItem::connectorPoint( DependencyNodeItem::ConnectorType type ) const { QRectF r; if ( type == Start ) { return m_start->connectorPoint(); } return m_finish->connectorPoint(); } void DependencyNodeItem::setConnectorHoverMode( bool mode ) { m_start->setAcceptHoverEvents( mode ); m_finish->setAcceptHoverEvents( mode ); } void DependencyNodeItem::setParentItem( DependencyNodeItem *parent ) { if ( m_parent ) { m_parent->takeChild( this ); } m_parent = parent; if ( m_parent ) { m_parent->addChild( this ); } } void DependencyNodeItem::setExpanded( bool mode ) { foreach ( DependencyNodeItem *ch, m_children ) { itemScene()->setItemVisible( ch, mode ); ch->setExpanded( mode ); } } void DependencyNodeItem::setItemVisible( bool show ) { setVisible( show ); //debugPlanDepEditor<name(); foreach ( DependencyLinkItem *i, m_parentrelations ) { i->setItemVisible( show ); } foreach ( DependencyLinkItem *i, m_childrelations ) { i->setItemVisible( show ); } } DependencyNodeItem *DependencyNodeItem::takeChild( DependencyNodeItem *ch ) { int i = m_children.indexOf( ch ); if ( i == -1 ) { return 0; } return m_children.takeAt( i ); } void DependencyNodeItem::setRectangle( const QRectF &rect ) { //debugPlanDepEditor<( scene() )->connectorWidth(); m_start->setRect( rect.x() + connection, rect.y(), -connection, rect.height() ); m_finish->setRect( rect.right() - connection, rect.y(), connection, rect.height() ); m_text->setPos( m_finish->rect().right() + 2.0, itemScene()->gridY( row() ) ); m_symbol->setPos( rect.topLeft() + QPointF( connection, 0 ) + QPointF( 2.0, 2.0 ) ); } void DependencyNodeItem::moveToY( qreal y ) { QRectF r = rect(); r. moveTop( y ); setRectangle( r ); //debugPlanDepEditor<createPath(); } foreach ( DependencyLinkItem *i, m_childrelations ) { i->createPath(); } DependencyNodeItem *par = this; while ( par->parentItem() ) { par = par->parentItem(); } par->setTreeIndicator( true ); } void DependencyNodeItem::setRow( int row ) { moveToY( itemScene()->itemY( row ) ); } int DependencyNodeItem::row() const { return itemScene()->row( rect().y() ); } void DependencyNodeItem::moveToX( qreal x ) { QRectF r = rect(); r. moveLeft( x ); setRectangle( r ); //debugPlanDepEditor<toPlainText()<<" to="<createPath(); } foreach ( DependencyLinkItem *i, m_childrelations ) { i->createPath(); } DependencyNodeItem *par = this; while ( par->parentItem() ) { par = par->parentItem(); } par->setTreeIndicator( true ); } void DependencyNodeItem::setColumn() { int col = m_parent == 0 ? 0 : m_parent->column() + 1; //debugPlanDepEditor<newChildColumn() ); } if ( col != column() ) { setColumn( col ); foreach ( DependencyLinkItem *i, m_childrelations ) { i->succItem->setColumn(); } //debugPlanDepEditor<setColumn(); } } } void DependencyNodeItem::setColumn( int col ) { moveToX( itemScene()->itemX( col ) ); } int DependencyNodeItem::column() const { return itemScene()->column( rect().x() ); } DependencyLinkItem *DependencyNodeItem::takeParentRelation( DependencyLinkItem *r ) { int i = m_parentrelations.indexOf( r ); if ( i == -1 ) { return 0; } DependencyLinkItem *dep = m_parentrelations.takeAt( i ); setColumn(); return dep; } DependencyLinkItem *DependencyNodeItem::takeChildRelation( DependencyLinkItem *r ) { int i = m_childrelations.indexOf( r ); if ( i == -1 ) { return 0; } return m_childrelations.takeAt( i ); } void DependencyNodeItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { debugPlanDepEditor; QGraphicsItem::GraphicsItemFlags f = flags(); if ( itemScene()->connectionMode() ) { itemScene()->clearConnection(); setFlags( f & ~QGraphicsItem::ItemIsSelectable ); } QGraphicsRectItem::mousePressEvent( event ); if ( f != flags() ) { setFlags( f ); } } void DependencyNodeItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * ) { //debugPlanDepEditor; QLinearGradient g( 0.0, rect().top(), 0.0, rect().bottom() ); g.setColorAt( 0.0, option->palette.color( QPalette::Midlight ) ); g.setColorAt( 1.0, option->palette.color( QPalette::Dark ) ); QBrush b( g ); painter->setBrush( b ); painter->setPen( QPen( Qt::NoPen ) ); painter->drawRect( rect() ); QStyleOptionGraphicsItem opt( *option ); opt.exposedRect = rect().adjusted( -m_start->rect().width(), 0.0, -m_finish->rect().width(), 0.0 ); if ( this == itemScene()->focusItem() ) { opt.state |= QStyle::State_HasFocus; } plan_paintFocusSelectedItem( painter, &opt ); // paint the symbol m_symbol->paint( itemScene()->project(), painter, &opt ); } DependencyConnectorItem *DependencyNodeItem::connectorItem( ConnectorType ctype ) const { switch ( ctype ) { case Start: return m_start; case Finish: return m_finish; default: break; } return 0; } QList DependencyNodeItem::predecessorItems( ConnectorType ctype ) const { QList lst; foreach ( DependencyLinkItem *i, m_parentrelations ) { if ( ctype == Start && ( i->relation->type() == Relation::StartStart || i->relation->type() == Relation::FinishStart ) ) { lst << i; } if ( ctype == Finish && i->relation->type() == Relation::FinishFinish ) { lst << i; } } return lst; } QList DependencyNodeItem::successorItems( ConnectorType ctype ) const { QList lst; foreach ( DependencyLinkItem *i, m_childrelations ) { if ( ctype == Start && i->relation->type() == Relation::StartStart ) { lst << i; } if ( ctype == Finish && ( i->relation->type() == Relation::FinishFinish || i->relation->type() == Relation::FinishStart ) ) { lst << i; } } return lst; } qreal DependencyNodeItem::treeIndicatorX() const { return rect().x() + 18.0; } void DependencyNodeItem::setTreeIndicator( bool on ) { paintTreeIndicator( on ); foreach ( DependencyNodeItem *i, m_children ) { if ( i->isVisible() ) { i->setTreeIndicator( on ); } } } void DependencyNodeItem::paintTreeIndicator( bool on ) { if ( ! on ) { m_treeIndicator->hide(); return; } QPainterPath p; qreal y1 = itemScene()->gridY( row() ); qreal y2 = itemScene()->gridY( row() + 1 ); for ( DependencyNodeItem *par = m_parent; par; par = par->parentItem() ) { qreal x = par->treeIndicatorX(); p.moveTo( x, y1 ); if ( par == m_parent ) { p.lineTo( x, (y1 + y2) / 2.0 ); p.lineTo( x + 6, (y1 + y2) / 2.0 ); if ( m_node->siblingAfter() ) { p.moveTo( x, (y1 + y2) / 2.0 ); p.lineTo( x, y2 ); } } else { const QList &children = par->children(); if ( children.last()->rect().y() > rect().y() ) { p.lineTo( x, (y1 + y2) / 2.0 ); p.lineTo( x, y2 ); } } } if ( ! m_children.isEmpty() ) { qreal x = treeIndicatorX(); qreal y = rect().bottom(); p.moveTo( x, y ); p.lineTo( x, itemScene()->gridY( row() + 1 ) ); } if ( p.isEmpty() ) { m_treeIndicator->hide(); } else { m_treeIndicator->setPath( p ); m_treeIndicator->show(); } //debugPlanDepEditor<setBrush( p->config().summaryTaskDefaultColor() ); break; case Node::Type_Task: painter->setBrush( p->config().taskNormalColor() ); break; case Node::Type_Milestone: painter->setBrush( p->config().milestoneNormalColor() ); break; default: painter->setBrush( m_delegate.defaultBrush( m_itemtype ) ); break; } } else { painter->setBrush( m_delegate.defaultBrush( m_itemtype ) ); } painter->setPen( Qt::NoPen ); painter->translate( option->exposedRect.x() + 2.0, option->exposedRect.y() + 2.0 ); painter->drawPath( path() ); } //-------------------- DependencyScene::DependencyScene( QWidget *parent ) : QGraphicsScene( parent ), m_model( 0 ), m_readwrite( false ) { setSceneRect( QRectF() ); m_connectionitem = new DependencyCreatorItem(); addItem( m_connectionitem ); //debugPlanDepEditor; m_connectionitem->hide(); } DependencyScene::~DependencyScene() { //debugPlanDepEditor<<" DELETED"; clearScene(); } void DependencyScene::setFromItem( DependencyConnectorItem *item ) { DependencyConnectorItem *old = fromItem(); m_connectionitem->clear(); if ( old && old->parentItem() ) { old->parentItem()->update(); } if ( item ) { foreach ( QGraphicsItem *i, items() ) { if ( i != m_connectionitem && i->type() != DependencyConnectorItem::Type ) { i->setAcceptHoverEvents( false ); if ( i->type() == DependencyLinkItem::Type ) { static_cast( i )->resetHooverIndication(); } } } item->setCursor( ConnectCursor ); m_connectionitem->setPredConnector( item ); m_connectionitem->show(); } else { foreach ( QGraphicsItem *i, items() ) { if ( i != m_connectionitem && i->type() != DependencyConnectorItem::Type ) i->setAcceptHoverEvents( true ); } } if ( item && item->parentItem() ) { item->parentItem()->update(); } } bool DependencyScene::connectionIsValid( DependencyConnectorItem *pred, DependencyConnectorItem *succ ) { if ( pred->ctype() == DependencyNodeItem::Start && succ->ctype() == DependencyNodeItem::Finish ) { return false; } Node *par = static_cast( pred->parentItem() )->node(); Node *ch = static_cast( succ->parentItem() )->node(); return m_project->linkExists( par, ch ) || m_project->legalToLink( par, ch ); } void DependencyScene::connectorEntered( DependencyConnectorItem *item, bool entered ) { //debugPlanDepEditor<setCursor( ConnectCursor ); if ( ! entered ) { // when we leave a connector we don't have a successor m_connectionitem->setSuccConnector( 0 ); return; } if ( m_connectionitem->predConnector == item ) { // when inside the predecessor, clicking is allowed (deselects connector) item->setCursor( ConnectCursor ); return; } if ( ! m_connectionitem->isVisible() ) { // we are not in connection mode return; } if ( m_connectionitem->predConnector == 0 ) { // nothing we can do if we don't have a predecessor (shouldn't happen) return; } if ( item->parentItem() == m_connectionitem->predConnector->parentItem() ) { // not allowed to connect to the same node item->setCursor( Qt::ForbiddenCursor ); return; } if ( ! ( connectionIsValid( m_connectionitem->predConnector, item ) ) ) { // invalid connection (circular dependency, connecting to parent node, etc) item->setCursor( Qt::ForbiddenCursor ); return; } m_connectionitem->setSuccConnector( item ); m_connectionitem->createPath(); } void DependencyScene::drawBackground ( QPainter *painter, const QRectF &rect ) { QGraphicsScene::drawBackground( painter, rect ); QStyleOptionViewItem opt; QBrush br( opt.palette.brush( QPalette::AlternateBase ) ); int first = row( rect.y() ); int last = row( rect.bottom() ); for ( int r = first; r <= last; ++r ) { if ( r % 2 == 1 ) { qreal oy = gridY( r ); QRectF rct( rect.x(), oy, rect.width(), gridHeight() ); painter->fillRect( rct, br ); //debugPlanDepEditor< DependencyScene::itemList( int type ) const { QList lst; foreach ( QGraphicsItem *i, items() ) { if ( i->type() == type ) { lst << i; } } return lst; } void DependencyScene::clearScene() { m_connectionitem->clear(); QList its, deps; foreach ( QGraphicsItem *i, items() ) { if ( i->type() == DependencyNodeItem::Type && i->parentItem() == 0 ) { its << i; } else if ( i->type() == DependencyLinkItem::Type ) { deps << i; } } qDeleteAll( deps ); qDeleteAll( its ); removeItem( m_connectionitem ); qDeleteAll( items() ); setSceneRect( QRectF() ); addItem( m_connectionitem ); //debugPlanDepEditor; } QList DependencyScene::removeChildItems( DependencyNodeItem *item ) { QList lst; foreach ( DependencyNodeItem *i, item->children() ) { m_allItems.removeAt( m_allItems.indexOf( i ) ); lst << i; lst += removeChildItems( i ); } return lst; } void DependencyScene::moveItem( DependencyNodeItem *item, const QList &lst ) { //debugPlanDepEditor<text(); int idx = m_allItems.indexOf( item ); int ndx = lst.indexOf( item->node() ); Q_ASSERT( idx != -1 && ndx != -1 ); Node *oldParent = item->parentItem() == 0 ? 0 : item->parentItem()->node(); Node *newParent = item->node()->parentNode(); if ( newParent == m_project ) { newParent = 0; } else debugPlanDepEditor<name()<level(); if ( idx != ndx || oldParent != newParent ) { // If I have children, these must be moved too. QList items = removeChildItems( item ); m_allItems.removeAt( idx ); m_allItems.insert( ndx, item ); item->setParentItem( m_allItems.value( lst.indexOf( newParent ) ) ); item->setColumn(); //debugPlanDepEditor<text()<<":"<"<column()<setColumn(); //debugPlanDepEditor<text()<<": ->"<column()<flatNodeList() ); // might have been moved } m_hiddenItems.clear(); m_visibleItems.clear(); int viewrow = 0; for ( int i = 0; i < m_allItems.count(); ++i ) { DependencyNodeItem *itm = m_allItems[ i ]; if ( itm->isVisible() ) { m_visibleItems.insert( i, itm ); //debugPlanDepEditor<text()<<":"<setRow( viewrow ); ++viewrow; } else { m_hiddenItems.insert( i, itm ); } } } DependencyNodeItem *DependencyScene::findPrevItem( Node *node ) const { if ( node->numChildren() == 0 ) { return findItem( node ); } return findPrevItem( node->childNodeIterator().last() ); } DependencyNodeItem *DependencyScene::itemBefore( DependencyNodeItem *parent, Node *node ) const { Node *sib = node->siblingBefore(); DependencyNodeItem *bef = parent; if ( sib ) { bef = findPrevItem( sib ); } return bef; } DependencyNodeItem *DependencyScene::createItem( Node *node ) { DependencyNodeItem *parent = findItem( node->parentNode() ); DependencyNodeItem *after = itemBefore( parent, node ); int i = m_allItems.count()-1; if ( after ) { i = m_allItems.indexOf( after ); //debugPlanDepEditor<<"after="<node()->name()<<" pos="<scene() != this ) { addItem( item ); } item->setEditable( m_readwrite ); item->startConnector()->setEditable( m_readwrite ); item->finishConnector()->setEditable( m_readwrite ); //debugPlanDepEditor<text()<column() + 1; } item->setRectangle( QRectF( itemX( col ), itemY(), itemWidth(), itemHeight() ) ); m_allItems.insert( i+1, item ); setItemVisible( item, true ); return item; } DependencyLinkItem *DependencyScene::findItem( const Relation* rel ) const { foreach ( QGraphicsItem *i, itemList( DependencyLinkItem::Type ) ) { if ( static_cast( i )->relation == rel ) { return static_cast( i ); } } return 0; } DependencyLinkItem *DependencyScene::findItem( const DependencyConnectorItem *c1, const DependencyConnectorItem *c2, bool exact ) const { DependencyNodeItem *n1 = c1->nodeItem(); DependencyNodeItem *n2 = c2->nodeItem(); foreach ( QGraphicsItem *i, itemList( DependencyLinkItem::Type ) ) { DependencyLinkItem *link = static_cast( i ); if ( link->predItem == n1 && link->succItem == n2 ) { switch ( link->relation->type() ) { case Relation::StartStart: if ( c1->ctype() == DependencyNodeItem::Start && c2->ctype() == DependencyNodeItem::Start ) { return link; } break; case Relation::FinishStart: if ( c1->ctype() == DependencyNodeItem::Finish && c2->ctype() == DependencyNodeItem::Start ) { return link; } break; case Relation::FinishFinish: if ( c1->ctype() == DependencyNodeItem::Finish && c2->ctype() == DependencyNodeItem::Finish ) { return link; } break; default: break; } return 0; } if ( link->predItem == n2 && link->succItem == n1 ) { if ( exact ) { return 0; } switch ( link->relation->type() ) { case Relation::StartStart: if ( c2->ctype() == DependencyNodeItem::Start && c1->ctype() == DependencyNodeItem::Start ) { return link; } break; case Relation::FinishStart: if ( c2->ctype() == DependencyNodeItem::Finish && c1->ctype() == DependencyNodeItem::Start ) { return link; } break; case Relation::FinishFinish: if ( c2->ctype() == DependencyNodeItem::Finish && c1->ctype() == DependencyNodeItem::Finish ) { return link; } break; default: break; } return 0; } } return 0; } DependencyNodeItem *DependencyScene::findItem( const Node *node ) const { foreach ( QGraphicsItem *i, itemList( DependencyNodeItem::Type ) ) { if ( static_cast( i )->node() == node ) { return static_cast( i ); } } return 0; } void DependencyScene::createLinks() { foreach ( DependencyNodeItem *i, m_allItems ) { createLinks( i ); } } void DependencyScene::createLinks( DependencyNodeItem *item ) { foreach ( Relation *rel, item->node()->dependChildNodes() ) { createLink( item, rel ); } } void DependencyScene::createLink( DependencyNodeItem *parent, Relation *rel ) { DependencyNodeItem *child = findItem( rel->child() ); if ( parent == 0 || child == 0 ) { return; } DependencyLinkItem *dep = new DependencyLinkItem( parent, child, rel ); dep->setEditable( m_readwrite ); addItem( dep ); //debugPlanDepEditor; dep->createPath(); } void DependencyScene::mouseMoveEvent( QGraphicsSceneMouseEvent *mouseEvent ) { if ( m_connectionitem->isVisible() ) { int x = qMin( qMax( sceneRect().left() + 2, mouseEvent->scenePos().x() ), sceneRect().right() - 4 ); int y = qMin( qMax( sceneRect().top() + 2, mouseEvent->scenePos().y() ), sceneRect().bottom() - 4 ); m_connectionitem->createPath( QPoint( x, y ) ); } QGraphicsScene::mouseMoveEvent( mouseEvent ); //debugPlanDepEditor<scenePos()<<","<isAccepted(); } void DependencyScene::keyPressEvent( QKeyEvent *keyEvent ) { //debugPlanDepEditor<update(); } emit focusItemChanged( focusItem() ); return; } switch ( keyEvent->key() ) { case Qt::Key_Left: { if ( fitem->type() == DependencyNodeItem::Type ) { DependencyConnectorItem *item = static_cast( fitem )->startConnector(); if ( item ) { setFocusItem( item ); } } else if ( fitem->type() == DependencyConnectorItem::Type ) { DependencyConnectorItem *citem = static_cast( fitem ); if ( citem->ctype() == DependencyNodeItem::Start ) { //Goto prev nodes finishConnector DependencyNodeItem *nitem = static_cast( citem->parentItem() ); DependencyNodeItem *item = nodeItem( nitem->row() - 1 ); if ( item ) { setFocusItem( item->finishConnector() ); } } else { // Goto node item (parent) setFocusItem( citem->parentItem() ); } } break; } case Qt::Key_Right: { if ( fitem->type() == DependencyNodeItem::Type ) { DependencyConnectorItem *item = static_cast( fitem )->finishConnector(); if ( item ) { setFocusItem( item ); } } else if ( fitem->type() == DependencyConnectorItem::Type ) { DependencyConnectorItem *citem = static_cast( fitem ); if ( citem->ctype() == DependencyNodeItem::Finish ) { //Goto prev nodes startConnector DependencyNodeItem *nitem = static_cast( citem->parentItem() ); DependencyNodeItem *item = nodeItem( nitem->row() + 1 ); if ( item ) { setFocusItem( item->startConnector() ); } } else { // Goto node item (parent) setFocusItem( citem->parentItem() ); } } break; } case Qt::Key_Up: { if ( fitem->type() == DependencyNodeItem::Type ) { DependencyNodeItem *item = nodeItem( static_cast( fitem )->row() - 1 ); if ( item ) { setFocusItem( item ); } } else if ( fitem->type() == DependencyConnectorItem::Type ) { DependencyConnectorItem *citem = static_cast( fitem ); DependencyNodeItem *nitem = static_cast( citem->parentItem() ); if ( citem->ctype() == DependencyNodeItem::Finish ) { DependencyNodeItem *item = nodeItem( nitem->row() - 1 ); if ( item ) { setFocusItem( item->finishConnector() ); } } else { DependencyNodeItem *item = nodeItem( static_cast( fitem )->row() - 1 ); if ( item ) { setFocusItem( item->startConnector() ); } } } break; } case Qt::Key_Down: { if ( fitem->type() == DependencyNodeItem::Type ) { DependencyNodeItem *item = nodeItem( static_cast( fitem )->row() + 1 ); if ( item ) { setFocusItem( item ); } } else if ( fitem->type() == DependencyConnectorItem::Type ) { DependencyConnectorItem *citem = static_cast( fitem ); DependencyNodeItem *nitem = static_cast( citem->parentItem() ); if ( citem->ctype() == DependencyNodeItem::Finish ) { DependencyNodeItem *item = nodeItem( nitem->row() + 1 ); if ( item ) { setFocusItem( item->finishConnector() ); } } else { DependencyNodeItem *item = nodeItem( static_cast( fitem )->row() + 1 ); if ( item ) { setFocusItem( item->startConnector() ); } } } break; } case Qt::Key_Space: case Qt::Key_Select: { if ( fitem->type() == DependencyConnectorItem::Type ) { singleConnectorClicked( static_cast( fitem ) ); } else if ( fitem->type() == DependencyNodeItem::Type ) { singleConnectorClicked( 0 ); foreach ( QGraphicsItem *i, selectedItems() ) { i->setSelected( false ); } fitem->setSelected( true ); } return; } default: QGraphicsScene::keyPressEvent( keyEvent ); } if ( fitem ) { fitem->parentItem() ? fitem->parentItem()->update() : fitem->update(); } if ( focusItem() ) { focusItem()->parentItem() ? focusItem()->parentItem()->update() : focusItem()->update(); } if ( fitem != focusItem() ) { emit focusItemChanged( focusItem() ); } } DependencyNodeItem *DependencyScene::nodeItem( int row ) const { if ( row < 0 || m_visibleItems.isEmpty() ) { return 0; } foreach ( DependencyNodeItem *i, m_visibleItems ) { if ( i->row() == row ) { return i; } } return 0; } void DependencyScene::singleConnectorClicked( DependencyConnectorItem *item ) { //debugPlanDepEditor; clearSelection(); QList lst; if ( item == 0 || item == fromItem() ) { setFromItem( 0 ); m_clickedItems = lst; } else if ( fromItem() == 0 ) { setFromItem( item ); } else if ( connectionIsValid( fromItem(), item ) ) { emit connectItems( fromItem(), item ); setFromItem( 0 ); } else { setFromItem( 0 ); } emit connectorClicked( item ); } void DependencyScene::multiConnectorClicked( DependencyConnectorItem *item ) { //debugPlanDepEditor; singleConnectorClicked( item ); } void DependencyScene::clearConnection() { setFromItem( 0 ); m_clickedItems.clear(); } void DependencyScene::mousePressEvent( QGraphicsSceneMouseEvent *mouseEvent ) { //debugPlanDepEditor; QGraphicsScene::mousePressEvent( mouseEvent ); if ( ! mouseEvent->isAccepted() ) { clearConnection(); } } void DependencyScene::mouseDoubleClickEvent ( QGraphicsSceneMouseEvent *event ) { //debugPlanDepEditor<pos()<scenePos()<screenPos(); QGraphicsScene::mouseDoubleClickEvent( event ); emit itemDoubleClicked( itemAt( event->scenePos(), QTransform() ) ); } void DependencyScene::contextMenuEvent ( QGraphicsSceneContextMenuEvent *event ) { if ( event->reason() == QGraphicsSceneContextMenuEvent::Mouse ) { debugPlanDepEditor<<"Mouse:"<scenePos(), QTransform())<pos()<scenePos()<screenPos(); emit contextMenuRequested( itemAt( event->scenePos(), QTransform() ), event->screenPos() ); return; } if ( focusItem() ) { if ( focusItem()->type() == DependencyConnectorItem::Type ) { DependencyConnectorItem *to = static_cast( focusItem() ); DependencyConnectorItem *from = fromItem(); debugPlanDepEditor<<"DependencyConnectorItem:"<type() == DependencyConnectorItem::Type ) { static_cast( i )->setEditable( on ); } else if ( i->type() == DependencyLinkItem::Type ) { static_cast( i )->setEditable( on ); } } } //-------------------- DependencyView::DependencyView( QWidget *parent ) : QGraphicsView( parent ), m_project( 0 ), m_dirty( false ), m_active( false ) { setItemScene( new DependencyScene( this ) ); setAlignment( Qt::AlignLeft | Qt::AlignTop ); - connect( scene(), SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) ); + connect( scene(), &QGraphicsScene::selectionChanged, this, &DependencyView::slotSelectionChanged ); connect( scene(), SIGNAL(connectItems(DependencyConnectorItem*,DependencyConnectorItem*)), this, SIGNAL(makeConnection(DependencyConnectorItem*,DependencyConnectorItem*)) ); connect( scene(), SIGNAL(contextMenuRequested(QGraphicsItem*)), this, SLOT(slotContextMenuRequested(QGraphicsItem*)) ); connect( scene(), SIGNAL(dependencyContextMenuRequested(DependencyLinkItem*,DependencyConnectorItem*)), this, SLOT(slotDependencyContextMenuRequested(DependencyLinkItem*,DependencyConnectorItem*)) ); connect( scene(), SIGNAL(contextMenuRequested(QGraphicsItem*,QPoint)), this, SIGNAL(contextMenuRequested(QGraphicsItem*,QPoint)) ); connect( itemScene(), SIGNAL(focusItemChanged(QGraphicsItem*)), this, SLOT(slotFocusItemChanged(QGraphicsItem*)) ); m_autoScrollTimer.start( 100 ); - connect( &m_autoScrollTimer, SIGNAL(timeout()), SLOT(slotAutoScroll()) ); + connect( &m_autoScrollTimer, &QTimer::timeout, this, &DependencyView::slotAutoScroll ); } void DependencyView::slotContextMenuRequested( QGraphicsItem *item ) { if ( item ) { debugPlanDepEditor<boundingRect()<<(item->mapToScene( item->pos() ).toPoint())<<(mapToGlobal( item->mapToParent( item->pos() ).toPoint())); emit contextMenuRequested( item, mapToGlobal( item->mapToScene( item->boundingRect().topRight() ).toPoint() ) ); } } void DependencyView::slotDependencyContextMenuRequested( DependencyLinkItem *item, DependencyConnectorItem */*connector */) { if ( item ) { debugPlanDepEditor<boundingRect()<<(item->mapToScene( item->pos() ).toPoint())<<(mapToGlobal( item->mapToParent( item->pos() ).toPoint())); emit contextMenuRequested( item, mapToGlobal( item->mapToScene( item->boundingRect().topRight() ).toPoint() ) ); } } void DependencyView::slotConnectorClicked( DependencyConnectorItem *item ) { if ( itemScene()->fromItem() == 0 ) { itemScene()->setFromItem( item ); } else { //debugPlanDepEditor<<"emit makeConnection:"<( item->parentItem() )->text(); emit makeConnection( itemScene()->fromItem(), item ); } } void DependencyView::slotSelectionChanged() { //HACK because of tt bug 160653 - QTimer::singleShot(0, this, SLOT(slotSelectedItems())); + QTimer::singleShot(0, this, &DependencyView::slotSelectedItems); } void DependencyView::slotSelectedItems() { emit selectionChanged( itemScene()->selectedItems() ); } void DependencyView::slotFocusItemChanged( QGraphicsItem *item ) { ensureVisible( item, 10, 10 ); } void DependencyView::setItemScene( DependencyScene *scene ) { setScene( scene ); scene->setProject( m_project ); //slotResizeScene( m_treeview->viewport()->size() ); if ( m_project ) { createItems(); } } void DependencyView::setActive( bool activate ) { m_active = activate; if ( m_active && m_dirty ) { createItems(); } } void DependencyView::setProject( Project *project ) { if ( m_project ) { - disconnect( m_project, SIGNAL(relationAdded(KPlato::Relation*)), this, SLOT(slotRelationAdded(KPlato::Relation*)) ); - disconnect( m_project, SIGNAL(relationRemoved(KPlato::Relation*)), this, SLOT(slotRelationRemoved(KPlato::Relation*)) ); - disconnect( m_project, SIGNAL(relationModified(KPlato::Relation*)), this, SLOT(slotRelationModified(KPlato::Relation*)) ); + disconnect( m_project, &Project::relationAdded, this, &DependencyView::slotRelationAdded ); + disconnect( m_project, &Project::relationRemoved, this, &DependencyView::slotRelationRemoved ); + disconnect( m_project, &Project::relationModified, this, &DependencyView::slotRelationModified ); - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeAdded(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*)) ); + disconnect( m_project, &Project::nodeAdded, this, &DependencyView::slotNodeAdded ); + disconnect( m_project, &Project::nodeRemoved, this, &DependencyView::slotNodeRemoved ); + disconnect( m_project, &Project::nodeChanged, this, &DependencyView::slotNodeChanged ); + disconnect( m_project, &Project::nodeMoved, this, &DependencyView::slotNodeMoved ); if ( itemScene() ) { itemScene()->clearScene(); } } m_project = project; if ( project ) { - connect( m_project, SIGNAL(relationAdded(KPlato::Relation*)), this, SLOT(slotRelationAdded(KPlato::Relation*)) ); - connect( m_project, SIGNAL(relationRemoved(KPlato::Relation*)), this, SLOT(slotRelationRemoved(KPlato::Relation*)) ); - connect( m_project, SIGNAL(relationModified(KPlato::Relation*)), this, SLOT(slotRelationModified(KPlato::Relation*)) ); + connect( m_project, &Project::relationAdded, this, &DependencyView::slotRelationAdded ); + connect( m_project, &Project::relationRemoved, this, &DependencyView::slotRelationRemoved ); + connect( m_project, &Project::relationModified, this, &DependencyView::slotRelationModified ); - connect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeAdded(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*)) ); + connect( m_project, &Project::nodeAdded, this, &DependencyView::slotNodeAdded ); + connect( m_project, &Project::nodeRemoved, this, &DependencyView::slotNodeRemoved ); + connect( m_project, &Project::nodeChanged, this, &DependencyView::slotNodeChanged ); + connect( m_project, &Project::nodeMoved, this, &DependencyView::slotNodeMoved ); - connect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsCodeChanged()) ); + connect( m_project, &Project::wbsDefinitionChanged, this, &DependencyView::slotWbsCodeChanged ); if ( itemScene() ) { itemScene()->setProject( project ); if ( m_active ) { createItems(); } else { m_dirty = true; } } } } DependencyLinkItem *DependencyView::findItem( const Relation* rel ) const { return itemScene()->findItem( rel ); } DependencyNodeItem *DependencyView::findItem( const Node *node ) const { return itemScene()->findItem( node ); } void DependencyView::slotRelationAdded( Relation* rel ) { if ( m_dirty ) { return; } DependencyLinkItem *item = findItem( rel ); if ( item == 0 ) { DependencyNodeItem *p = findItem( rel->parent() ); DependencyNodeItem *c = findItem( rel->child() ); DependencyLinkItem *r = new DependencyLinkItem( p, c, rel ); scene()->addItem( r ); //debugPlanDepEditor; r->createPath(); r->setVisible( c->isVisible() && p->isVisible() ); } else debugPlanDepEditor<<"Relation already exists!"; } void DependencyView::slotRelationRemoved( Relation* rel ) { if ( m_dirty ) { return; } DependencyLinkItem *item = findItem( rel ); if ( item ) { scene()->removeItem( item ); delete item; } else debugPlanDepEditor<<"Relation does not exist!"; } void DependencyView::slotRelationModified( Relation* rel ) { //debugPlanDepEditor; if ( m_dirty ) { return; } slotRelationRemoved( rel ); slotRelationAdded( rel ); } void DependencyView::slotNodeAdded( Node *node ) { //debugPlanDepEditor; if ( m_dirty ) { return; } DependencyNodeItem *item = findItem( node ); if ( item == 0 ) { item = createItem( node ); } else { //debugPlanDepEditor<name(); itemScene()->setItemVisible( item, true ); } ensureVisible( item ); slotWbsCodeChanged(); } void DependencyView::slotNodeRemoved( Node *node ) { if ( m_dirty ) { return; } DependencyNodeItem *item = findItem( node ); if ( item ) { //debugPlanDepEditor<name(); itemScene()->setItemVisible( item, false ); } else debugPlanDepEditor<<"Node does not exist!"; slotWbsCodeChanged(); } void DependencyView::slotNodeChanged( Node *node ) { if ( m_dirty ) { return; } DependencyNodeItem *item = findItem( node ); if ( item && item->isVisible() ) { item->setText(); item->setSymbol(); } else debugPlanDepEditor<<"Node does not exist!"; } void DependencyView::slotWbsCodeChanged() { if ( m_dirty ) { return; } foreach( DependencyNodeItem *i, itemScene()->nodeItems() ) { if ( i->isVisible() ) { i->setText(); } } } void DependencyView::slotNodeMoved( Node *node ) { if ( m_dirty ) { return; } slotNodeRemoved( node ); slotNodeAdded( node ); } void DependencyView::setItemExpanded( int , bool ) { } void DependencyView::createItems() { itemScene()->clearScene(); m_dirty = false; if ( m_project == 0 ) { return; } scene()->addLine( 0.0, 0.0, 1.0, 0.0 ); createItems( m_project ); createLinks(); } DependencyNodeItem *DependencyView::createItem( Node *node ) { return itemScene()->createItem( node ); } void DependencyView::createItems( Node *node ) { if ( node != m_project ) { //debugPlanDepEditor<name()<<" ("<numChildren()<<")"; DependencyNodeItem *i = createItem( node ); if ( i == 0 ) { return; } } foreach ( Node *n, node->childNodeIterator() ) { createItems( n ); } } void DependencyView::createLinks() { //debugPlanDepEditor; itemScene()->createLinks(); } void DependencyView::keyPressEvent(QKeyEvent *event) { if ( event->modifiers() & Qt::ControlModifier ) { switch ( event->key() ) { case Qt::Key_Plus: return scale( 1.1, 1.1 ); case Qt::Key_Minus: return scale( 0.9, 0.9 ); default: break; } } QGraphicsView::keyPressEvent(event); } void DependencyView::mouseMoveEvent( QMouseEvent *mouseEvent ) { m_cursorPos = mouseEvent->pos(); if ( itemScene()->connectionMode() && itemScene()->mouseGrabberItem() ) { QPointF spos = mapToScene( m_cursorPos ); Qt::CursorShape c = Qt::ArrowCursor; foreach ( QGraphicsItem *i, itemScene()->items( spos ) ) { if ( i->type() == DependencyConnectorItem::Type ) { if ( i == itemScene()->fromItem() ) { c = ConnectCursor; } else { if ( itemScene()->connectionIsValid( itemScene()->fromItem(), static_cast( i ) ) ) { c = ConnectCursor; } else { c = Qt::ForbiddenCursor; } } } } if ( viewport()->cursor().shape() != c ) { viewport()->setCursor( c ); } } QGraphicsView::mouseMoveEvent( mouseEvent ); //debugPlanDepEditor<scenePos()<<","<isAccepted(); } void DependencyView::slotAutoScroll() { if ( itemScene()->connectionMode() ) { ensureVisible( QRectF( mapToScene( m_cursorPos ), QSizeF( 1, 1 ) ), 2, 2 ); } } //----------------------------------- DependencyeditorConfigDialog::DependencyeditorConfigDialog( ViewBase *view, QWidget *p, bool selectPrint) : KPageDialog(p), m_view( view ) { 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, SIGNAL(accepted()), this, SLOT(slotOk())); + connect( this, &QDialog::accepted, this, &DependencyeditorConfigDialog::slotOk); } void DependencyeditorConfigDialog::slotOk() { debugPlan; m_view->setPageLayout( m_pagelayout->pageLayout() ); m_view->setPrintingOptions( m_headerfooter->options() ); } //-------------------- DependencyEditor::DependencyEditor(KoPart *part, KoDocument *doc, QWidget *parent ) : ViewBase(part, doc, parent), m_currentnode( 0 ), m_manager( 0 ) { setupGui(); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new DependencyView( this ); l->addWidget( m_view ); - connect( m_view, SIGNAL(makeConnection(DependencyConnectorItem*,DependencyConnectorItem*)), this, SLOT(slotCreateRelation(DependencyConnectorItem*,DependencyConnectorItem*)) ); + connect( m_view, &DependencyView::makeConnection, this, &DependencyEditor::slotCreateRelation ); connect( m_view, SIGNAL(selectionChanged(QList)), this, SLOT(slotSelectionChanged(QList)) ); - connect( m_view->itemScene(), SIGNAL(itemDoubleClicked(QGraphicsItem*)), this, SLOT(slotItemDoubleClicked(QGraphicsItem*)) ); + connect( m_view->itemScene(), &DependencyScene::itemDoubleClicked, this, &DependencyEditor::slotItemDoubleClicked ); - connect( m_view, SIGNAL(contextMenuRequested(QGraphicsItem*,QPoint)), this, SLOT(slotContextMenuRequested(QGraphicsItem*,QPoint)) ); + connect( m_view, &DependencyView::contextMenuRequested, this, &DependencyEditor::slotContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Task Dependency Editor" "" "Edit dependencies between tasks." "Dependencies can be added by dragging a connection area (start or finish)" " from one task to a connection area of a different task." " You can edit or delete a dependency using the context menu." "" "This view supports printing using the context menu." "More..." "", Help::page("Manual/Task_Dependency_Editor_(Graphical)"))); } void DependencyEditor::updateReadWrite( bool on ) { m_view->itemScene()->setReadWrite( on ); ViewBase::updateReadWrite( on ); } void DependencyEditor::slotItemDoubleClicked( QGraphicsItem *item ) { //debugPlanDepEditor; if ( ! isReadWrite() ) { return; } if ( item && item->type() == DependencyLinkItem::Type ) { emit modifyRelation( static_cast( item )->relation ); return; } if ( item && item->type() == DependencyNodeItem::Type ) { emit editNode( static_cast( item )->node() ); return; } if ( item && item->type() == DependencyNodeSymbolItem::Type ) { emit editNode( static_cast( item->parentItem() )->node() ); return; } } void DependencyEditor::slotCreateRelation( DependencyConnectorItem *pred, DependencyConnectorItem *succ ) { //debugPlanDepEditor; if ( ! isReadWrite() ) { return; } Node *par = pred->node(); Node *ch = succ->node(); Relation::Type type = Relation::FinishStart; if ( pred->ctype() == DependencyNodeItem::Start ) { if ( succ->ctype() == DependencyNodeItem::Start ) { type = Relation::StartStart; } } else { if ( succ->ctype() == DependencyNodeItem::Start ) { type = Relation::FinishStart; } else { type = Relation::FinishFinish; } } Relation *rel = ch->findRelation( par ); if ( rel == 0 ) { //debugPlanDepEditor<<"New:"<name()<<" ->"<name()<<","<type() != type ) { //debugPlanDepEditor<<"Mod:"<name()<<" ->"<name()<<","<setProject( &project ); } void DependencyEditor::draw() { } void DependencyEditor::setGuiActive( bool activate ) { //debugPlanDepEditor<setActive( activate ); /* if ( activate && !m_view->selectionModel()->currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); }*/ } void DependencyEditor::slotCurrentChanged( const QModelIndex &, const QModelIndex & ) { //debugPlanDepEditor<& ) { //debugPlanDepEditor< DependencyEditor::selectedNodes() const { QList lst; foreach ( QGraphicsItem *i, m_view->itemScene()->selectedItems() ) { if ( i->type() == DependencyNodeItem::Type ) { lst << static_cast( i )->node(); } } return lst; } Node *DependencyEditor::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *DependencyEditor::currentNode() const { return m_currentnode; /* Node * n = 0; QGraphicsItem *i = m_view->itemScene()->focusItem(); if ( i && i->type() == DependencyNodeItem::Type ) { n = static_cast( i )->node(); } if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n;*/ } Relation *DependencyEditor::currentRelation() const { return m_currentrelation; } void DependencyEditor::setScheduleManager( ScheduleManager *sm ) { m_manager = sm; } void DependencyEditor::slotContextMenuRequested( QGraphicsItem *item, const QPoint& pos ) { //debugPlanDepEditor<type() == DependencyNodeSymbolItem::Type ) { item = item->parentItem(); } if ( item ) { if ( item->type() == DependencyNodeItem::Type ) { m_currentnode = static_cast( item )->node(); if ( m_currentnode == 0 ) { //debugPlanDepEditor<<"No node"; return; } bool scheduled = m_manager != 0 && m_currentnode->isScheduled( m_manager->scheduleId() ); switch ( m_currentnode->type() ) { case Node::Type_Task: name = scheduled ? "task_popup" : "task_edit_popup"; break; case Node::Type_Milestone: name = scheduled ? "taskeditor_milestone_popup" : "task_edit_popup"; break; case Node::Type_Summarytask: name = "summarytask_popup"; break; default: break; } //debugPlanDepEditor<name()<<" :"<type() == DependencyLinkItem::Type ) { m_currentrelation = static_cast( item )->relation; if ( m_currentrelation ) { name = "relation_popup"; } } else if ( item->type() == DependencyConnectorItem::Type ) { DependencyConnectorItem *c = static_cast( item ); QList items; QList actions; QMenu menu; foreach ( DependencyLinkItem *i, c->predecessorItems() ) { items << i; actions << menu.addAction(koIcon("document-properties"), i->predItem->text()); } menu.addSeparator(); foreach ( DependencyLinkItem *i, c->successorItems() ) { items << i; actions << menu.addAction(koIcon("document-properties"), i->succItem->text()); } if ( ! actions.isEmpty() ) { QAction *action = menu.exec( pos ); if ( action && actions.contains( action ) ) { emit modifyRelation( items[ actions.indexOf( action ) ]->relation ); return; } } } } //debugPlanDepEditor< lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } m_currentnode = 0; m_currentrelation = 0; } void DependencyEditor::slotEnableActions() { updateActionsEnabled( true ); } void DependencyEditor::updateActionsEnabled( bool on ) { if ( ! on || ! isReadWrite() ) { //FIXME: read-write is not set properly menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); return; } int selCount = selectedNodeCount(); if ( selCount == 0 ) { menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); return; } Node *n = selectedNode(); if ( n && n->type() != Node::Type_Task && n->type() != Node::Type_Milestone && n->type() != Node::Type_Summarytask ) { n = 0; } if ( selCount == 1 && n == 0 ) { // only project selected menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( true ); actionAddSubtask->setEnabled( true ); actionAddSubMilestone->setEnabled( true ); actionDeleteTask->setEnabled( false ); return; } bool baselined = false; Project *p = m_view->project(); if ( p && p->isBaselined() ) { foreach ( Node *n, selectedNodes() ) { if ( n->isBaselined() ) { baselined = true; break; } } } if ( selCount == 1 ) { menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionAddSubtask->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionAddSubMilestone->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionDeleteTask->setEnabled( ! baselined ); return; } // selCount > 1 menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( ! baselined ); } void DependencyEditor::setupGui() { KActionCollection *coll = actionCollection(); QString name = "taskeditor_add_list"; menuAddTask = new KActionMenu(koIcon("view-task-add"), i18n("Add Task"), this); coll->addAction("add_task", menuAddTask ); - connect( menuAddTask, SIGNAL(triggered(bool)), SLOT(slotAddTask()) ); + connect( menuAddTask, &QAction::triggered, this, &DependencyEditor::slotAddTask ); addAction( name, menuAddTask ); actionAddTask = new QAction( i18n("Add Task..."), this); actionAddTask->setShortcut( Qt::CTRL + Qt::Key_I ); - connect( actionAddTask, SIGNAL(triggered(bool)), SLOT(slotAddTask()) ); + connect( actionAddTask, &QAction::triggered, this, &DependencyEditor::slotAddTask ); menuAddTask->addAction( actionAddTask ); actionAddMilestone = new QAction( i18n("Add Milestone..."), this ); actionAddMilestone->setShortcut( Qt::CTRL + Qt::ALT + Qt::Key_I ); - connect( actionAddMilestone, SIGNAL(triggered(bool)), SLOT(slotAddMilestone()) ); + connect( actionAddMilestone, &QAction::triggered, this, &DependencyEditor::slotAddMilestone ); menuAddTask->addAction( actionAddMilestone ); menuAddSubTask = new KActionMenu(koIcon("view-task-child-add"), i18n("Add Sub-Task"), this); coll->addAction("add_subtask", menuAddTask ); - connect( menuAddSubTask, SIGNAL(triggered(bool)), SLOT(slotAddSubtask()) ); + connect( menuAddSubTask, &QAction::triggered, this, &DependencyEditor::slotAddSubtask ); addAction( name, menuAddSubTask ); actionAddSubtask = new QAction( i18n("Add Sub-Task..."), this ); actionAddSubtask->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_I ); - connect( actionAddSubtask, SIGNAL(triggered(bool)), SLOT(slotAddSubtask()) ); + connect( actionAddSubtask, &QAction::triggered, this, &DependencyEditor::slotAddSubtask ); menuAddSubTask->addAction( actionAddSubtask ); actionAddSubMilestone = new QAction( i18n("Add Sub-Milestone..."), this ); actionAddSubMilestone->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_I ); - connect( actionAddSubMilestone, SIGNAL(triggered(bool)), SLOT(slotAddSubMilestone()) ); + connect( actionAddSubMilestone, &QAction::triggered, this, &DependencyEditor::slotAddSubMilestone ); menuAddSubTask->addAction( actionAddSubMilestone ); actionDeleteTask = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this); coll->addAction("delete_task", actionDeleteTask ); coll->setDefaultShortcut(actionDeleteTask, Qt::Key_Delete); - connect( actionDeleteTask, SIGNAL(triggered(bool)), SLOT(slotDeleteTask()) ); + connect( actionDeleteTask, &QAction::triggered, this, &DependencyEditor::slotDeleteTask ); addAction( name, actionDeleteTask ); createOptionActions(ViewBase::OptionPrint | ViewBase::OptionPrintPreview | ViewBase::OptionPrintPdf | ViewBase::OptionPrintConfig); } void DependencyEditor::slotOptions() { debugPlan; DependencyeditorConfigDialog *dlg = new DependencyeditorConfigDialog( this, this, sender()->objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void DependencyEditor::slotAddTask() { //debugPlanDepEditor; m_currentnode = selectedNode(); emit addTask(); m_currentnode = 0; } void DependencyEditor::slotAddMilestone() { //debugPlanDepEditor; m_currentnode = selectedNode(); // sibling emit addMilestone(); m_currentnode = 0; } void DependencyEditor::slotAddSubtask() { //debugPlanDepEditor; m_currentnode = selectedNode(); if ( m_currentnode == 0 ) { return; } emit addSubtask(); m_currentnode = 0; } void DependencyEditor::slotAddSubMilestone() { debugPlanDepEditor; m_currentnode = selectedNode(); if ( m_currentnode == 0 ) { return; } emit addSubMilestone(); m_currentnode = 0; } void DependencyEditor::edit( const QModelIndex &i ) { if ( i.isValid() ) { /* QModelIndex p = m_view->itemModel()->parent( i ); m_view->treeView()->setExpanded( p, true ); m_view->treeView()->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->treeView()->edit( i );*/ } } void DependencyEditor::slotDeleteTask() { //debugPlanDepEditor; QList lst = selectedNodes(); while ( true ) { // remove children of selected tasks, as parents delete their children Node *ch = 0; foreach ( Node *n1, lst ) { foreach ( Node *n2, lst ) { if ( n2->isChildOf( n1 ) ) { ch = n2; break; } } if ( ch != 0 ) { break; } } if ( ch == 0 ) { break; } lst.removeAt( lst.indexOf( ch ) ); } foreach ( Node* n, lst ) { debugPlanDepEditor<name(); } emit deleteTaskList( lst ); } KoPrintJob *DependencyEditor::createPrintJob() { DependecyViewPrintingDialog *dia = new DependecyViewPrintingDialog( this, m_view ); dia->printer().setCreator( QString( "Plan %1" ).arg( PLAN_VERSION_STRING ) ); // dia->printer().setFullPage(true); // ignore printer margins return dia; } } // namespace KPlato diff --git a/src/libs/ui/kptdocumentseditor.cpp b/src/libs/ui/kptdocumentseditor.cpp index 05057fe0..1b860618 100644 --- a/src/libs/ui/kptdocumentseditor.cpp +++ b/src/libs/ui/kptdocumentseditor.cpp @@ -1,301 +1,301 @@ /* This file is part of the KDE project Copyright (C) 2007, 2012 Dag Andersen danders@get2net> 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 "kptdocumentseditor.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptdocuments.h" #include "kptdatetime.h" #include "kptitemviewsettup.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include namespace KPlato { //-------------------- DocumentTreeView::DocumentTreeView( QWidget *parent ) : TreeViewBase( parent ) { // header()->setContextMenuPolicy( Qt::CustomContextMenu ); setStretchLastSection( true ); DocumentItemModel *m = new DocumentItemModel(); setModel( m ); setRootIsDecorated ( false ); setSelectionBehavior( QAbstractItemView::SelectRows ); setSelectionMode( QAbstractItemView::SingleSelection ); createItemDelegates( m ); setAcceptDrops( true ); setDropIndicatorShown( true ); - connect( selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged(QItemSelection)) ); + connect( selectionModel(), &QItemSelectionModel::selectionChanged, this, &DocumentTreeView::slotSelectionChanged ); setColumnHidden( DocumentModel::Property_Status, true ); // not used atm } Document *DocumentTreeView::currentDocument() const { return model()->document( selectionModel()->currentIndex() ); } QModelIndexList DocumentTreeView::selectedRows() const { return selectionModel()->selectedRows(); } void DocumentTreeView::slotSelectionChanged( const QItemSelection &selected ) { emit selectionChanged( selected.indexes() ); } QList DocumentTreeView::selectedDocuments() const { QList lst; foreach ( const QModelIndex &i, selectionModel()->selectedRows() ) { Document *doc = model()->document( i ); if ( doc ) { lst << doc; } } return lst; } //----------------------------------- DocumentsEditor::DocumentsEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { setupGui(); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new DocumentTreeView( this ); l->addWidget( m_view ); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); + connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); // clazy:exclude=old-style-connect - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); // clazy:exclude=old-style-connect - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &TreeViewBase::contextMenuRequested, this, &DocumentsEditor::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); // clazy:exclude=old-style-connect } void DocumentsEditor::updateReadWrite( bool readwrite ) { debugPlan<"<setReadWrite( readwrite ); updateActionsEnabled( readwrite ); } void DocumentsEditor::draw( Documents &docs ) { m_view->setDocuments( &docs ); } void DocumentsEditor::draw() { } void DocumentsEditor::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void DocumentsEditor::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { //debugPlan<model()->document( index ); if ( obj ) { name = "documentseditor_popup"; } } m_view->setContextMenuIndex(index); emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } void DocumentsEditor::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlan; QList lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } Document *DocumentsEditor::currentDocument() const { return m_view->currentDocument(); } void DocumentsEditor::slotCurrentChanged( const QModelIndex & ) { //debugPlan< lst = m_view->selectedDocuments(); if ( lst.isEmpty() || lst.count() > 1 ) { actionEditDocument->setEnabled( false ); actionViewDocument->setEnabled( false ); return; } Document *doc = lst.first(); actionViewDocument->setEnabled( on ); actionEditDocument->setEnabled( on && doc->type() == Document::Type_Product && isReadWrite() ); } void DocumentsEditor::setupGui() { QString name = "documentseditor_edit_list"; actionEditDocument = new QAction(koIcon("document-properties"), i18n("Edit..."), this); actionCollection()->addAction("edit_documents", actionEditDocument ); // actionCollection()->setDefaultShortcut(actionEditDocument, Qt::CTRL + Qt::SHIFT + Qt::Key_I); - connect( actionEditDocument, SIGNAL(triggered(bool)), SLOT(slotEditDocument()) ); + connect( actionEditDocument, &QAction::triggered, this, &DocumentsEditor::slotEditDocument ); addAction( name, actionEditDocument ); actionViewDocument = new QAction(koIcon("document-preview"), xi18nc("@action View a document", "View..."), this); actionCollection()->addAction("view_documents", actionViewDocument ); // actionCollection()->setDefaultShortcut(actionViewDocument, Qt::CTRL + Qt::SHIFT + Qt::Key_I); - connect( actionViewDocument, SIGNAL(triggered(bool)), SLOT(slotViewDocument()) ); + connect( actionViewDocument, &QAction::triggered, this, &DocumentsEditor::slotViewDocument ); addAction( name, actionViewDocument ); /* actionDeleteSelection = new QAction(koIcon("edit-delete"), i18n("Delete"), this); actionCollection()->addAction("delete_selection", actionDeleteSelection ); actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete); connect( actionDeleteSelection, SIGNAL(triggered(bool)), SLOT(slotDeleteSelection()) ); addAction( name, actionDeleteSelection );*/ // Add the context menu actions for the view options createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig); } void DocumentsEditor::slotOptions() { debugPlan; ItemViewSettupDialog dlg( this, m_view/*->masterView()*/ ); dlg.exec(); } void DocumentsEditor::slotEditDocument() { QList dl = m_view->selectedDocuments(); if ( dl.isEmpty() ) { return; } debugPlan< dl = m_view->selectedDocuments(); if ( dl.isEmpty() ) { return; } debugPlan< dl = m_view->selectedDocuments(); Document *after = 0; if ( dl.count() > 0 ) { after = dl.last(); } Document *doc = new Document(); QModelIndex i = m_view->model()->insertDocument( doc, after ); if ( i.isValid() ) { m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); } } void DocumentsEditor::slotDeleteSelection() { QList lst = m_view->selectedDocuments(); //debugPlan<loadContext( m_view->model()->columnMap(), context ); } void DocumentsEditor::saveContext( QDomElement &context ) const { m_view->saveContext( m_view->model()->columnMap(), context ); } } // namespace KPlato diff --git a/src/libs/ui/kptdocumentspanel.cpp b/src/libs/ui/kptdocumentspanel.cpp index 40b4c722..c9e21c83 100644 --- a/src/libs/ui/kptdocumentspanel.cpp +++ b/src/libs/ui/kptdocumentspanel.cpp @@ -1,237 +1,237 @@ /* This file is part of the KDE project Copyright (C) 2007, 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. */ #include "kptdocumentspanel.h" #include "kptdocumentseditor.h" #include "kptdocumentmodel.h" #include "kptnode.h" #include "kptcommand.h" #include "kptdebug.h" #include #include #include #include #include #include #include namespace KPlato { DocumentsPanel::DocumentsPanel( Node &node, QWidget *parent ) : QWidget( parent ), m_node( node ), m_docs( node.documents() ) { widget.setupUi( this ); QVBoxLayout *l = new QVBoxLayout( widget.itemViewHolder ); m_view = new DocumentTreeView( widget.itemViewHolder ); l->setMargin(0); l->addWidget( m_view ); m_view->setDocuments( &m_docs ); m_view->setReadWrite( true ); currentChanged( QModelIndex() ); foreach ( Document *doc, m_docs.documents() ) { m_orgurl.insert( doc, doc->url() ); } - connect( widget.pbAdd, SIGNAL(clicked()), SLOT(slotAddUrl()) ); - connect( widget.pbChange, SIGNAL(clicked()), SLOT(slotChangeUrl()) ); - connect( widget.pbRemove, SIGNAL(clicked()), SLOT(slotRemoveUrl()) ); - connect( widget.pbView, SIGNAL(clicked()), SLOT(slotViewUrl()) ); + connect( widget.pbAdd, &QAbstractButton::clicked, this, &DocumentsPanel::slotAddUrl ); + connect( widget.pbChange, &QAbstractButton::clicked, this, &DocumentsPanel::slotChangeUrl ); + connect( widget.pbRemove, &QAbstractButton::clicked, this, &DocumentsPanel::slotRemoveUrl ); + connect( widget.pbView, &QAbstractButton::clicked, this, &DocumentsPanel::slotViewUrl ); - connect( m_view->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(dataChanged(QModelIndex)) ); + connect( m_view->model(), &QAbstractItemModel::dataChanged, this, &DocumentsPanel::dataChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), SLOT(slotSelectionChanged(QModelIndexList)) ); // clazy:exclude=old-style-connect } DocumentItemModel *DocumentsPanel::model() const { return m_view->model(); } void DocumentsPanel::dataChanged( const QModelIndex &index ) { Document *doc = m_docs.value( index.row() ); if ( doc == 0 ) { return; } m_state.insert( doc, (State)( m_state[ doc ] | Modified ) ); emit changed(); debugPlan<selectedRows(); debugPlan<setEnabled( list.count() == 1 ); widget.pbRemove->setEnabled( ! list.isEmpty() ); widget.pbView->setEnabled( false ); //TODO } void DocumentsPanel::currentChanged( const QModelIndex &index ) { widget.pbChange->setEnabled( index.isValid() ); widget.pbRemove->setEnabled( index.isValid() ); widget.pbView->setEnabled( false ); //TODO } Document *DocumentsPanel::selectedDocument() const { QList lst = m_view->selectedDocuments(); return lst.isEmpty() ? 0 : lst.first(); } void DocumentsPanel::slotAddUrl() { QPointer dlg = new KUrlRequesterDialog( QUrl(), QString(), this ); dlg->setWindowTitle( xi18nc( "@title:window", "Attach Document" ) ); if ( dlg->exec() == QDialog::Accepted && dlg ) { if ( m_docs.findDocument( dlg->selectedUrl() ) ) { warnPlan<<"Document (url) already exists: "<selectedUrl(); KMessageBox::sorry( this, xi18nc( "@info", "Document is already attached:
%1", dlg->selectedUrl().toDisplayString() ), xi18nc( "@title:window", "Cannot Attach Document" ) ); } else { Document *doc = new Document( dlg->selectedUrl() ); //DocumentAddCmd *cmd = new DocumentAddCmd( m_docs, doc, kundo2_i18n( "Add document" ) ); //m_cmds.push( cmd ); m_docs.addDocument( doc ); m_state.insert( doc, Added ); model()->setDocuments( &m_docs ); // refresh emit changed(); } } delete dlg; } void DocumentsPanel::slotChangeUrl() { Document *doc = selectedDocument(); if ( doc == 0 ) { return slotAddUrl(); } KUrlRequesterDialog *dlg = new KUrlRequesterDialog( doc->url(), QString(), this ); dlg->setWindowTitle( xi18nc( "@title:window", "Modify Url" ) ); if ( dlg->exec() == QDialog::Accepted ) { if ( doc->url() != dlg->selectedUrl() ) { if ( m_docs.findDocument( dlg->selectedUrl() ) ) { warnPlan<<"Document url already exists"; KMessageBox::sorry( this, i18n( "Document url already exists: %1", dlg->selectedUrl().toDisplayString() ), i18n( "Cannot Modify Url" ) ); } else { debugPlan<<"Modify url: "<url()<<" : "<selectedUrl(); doc->setUrl( dlg->selectedUrl() ); m_state.insert( doc, (State)( m_state[ doc ] | Modified ) ); model()->setDocuments( &m_docs ); emit changed(); debugPlan<<"State: "<url()<<" : "< lst = m_view->selectedDocuments(); bool mod = false; foreach ( Document *doc, lst ) { if ( doc == 0 ) { continue; } m_docs.takeDocument( doc ); if ( m_state.contains( doc ) && m_state[ doc ] & Added ) { m_state.remove( doc ); } else { m_state.insert( doc, Removed ); } mod = true; } if ( mod ) { model()->setDocuments( &m_docs ); // refresh emit changed(); } } void DocumentsPanel::slotViewUrl() { } MacroCommand *DocumentsPanel::buildCommand() { if ( m_docs == m_node.documents() ) { debugPlan<<"No changes to save"; return 0; } Documents &docs = m_node.documents(); Document *d = 0; KUndo2MagicString txt = kundo2_i18n( "Modify documents" ); MacroCommand *m = 0; QMap::const_iterator i = m_state.constBegin(); for ( ; i != m_state.constEnd(); ++i) { debugPlan<addCommand( new DocumentRemoveCmd( m_node.documents(), d, kundo2_i18n( "Remove document" ) ) ); } else if ( ( i.value() & Added ) == 0 && i.value() & Modified ) { d = docs.findDocument( m_orgurl[ i.key() ] ); Q_ASSERT( d ); // do plain modifications before additions debugPlan<<"modify document "<url() != d->url() ) { if ( m == 0 ) m = new MacroCommand( txt ); m->addCommand( new DocumentModifyUrlCmd( d, i.key()->url(), kundo2_i18n( "Modify document url" ) ) ); } if ( i.key()->type() != d->type() ) { if ( m == 0 ) m = new MacroCommand( txt ); m->addCommand( new DocumentModifyTypeCmd( d, i.key()->type(), kundo2_i18n( "Modify document type" ) ) ); } if ( i.key()->status() != d->status() ) { if ( m == 0 ) m = new MacroCommand( txt ); m->addCommand( new DocumentModifyStatusCmd( d, i.key()->status(), kundo2_i18n( "Modify document status" ) ) ); } if ( i.key()->sendAs() != d->sendAs() ) { if ( m == 0 ) m = new MacroCommand( txt ); m->addCommand( new DocumentModifySendAsCmd( d, i.key()->sendAs(), kundo2_i18n( "Modify document send control" ) ) ); } if ( i.key()->name() != d->name() ) { if ( m == 0 ) m = new MacroCommand( txt ); m->addCommand( new DocumentModifyNameCmd( d, i.key()->name()/*, kundo2_i18n( "Modify document name" )*/ ) ); } } else if ( i.value() & Added ) { if ( m == 0 ) m = new MacroCommand( txt ); debugPlan<addCommand( new DocumentAddCmd( docs, d, kundo2_i18n( "Add document" ) ) ); } } return m; } } //namespace KPlato diff --git a/src/libs/ui/kptganttview.cpp b/src/libs/ui/kptganttview.cpp index 09c45ef4..a4fbc4c1 100644 --- a/src/libs/ui/kptganttview.cpp +++ b/src/libs/ui/kptganttview.cpp @@ -1,1460 +1,1460 @@ /* This file is part of the KDE project Copyright (C) 2002 - 2007, 2012 Dag Andersen Copyright (C) 2006 Raphael Langerhorst 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. */ #include "kptganttview.h" #include "kptnodeitemmodel.h" #include "kptappointment.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptrelation.h" #include "kptschedule.h" #include "kptviewbase.h" #include "kptitemviewsettup.h" #include "kptduration.h" #include "kptdatetime.h" #include "kptresourceappointmentsmodel.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 #include #include #include #include /// The main namespace namespace KPlato { class GanttItemDelegate; //------------------------------------------------- GanttChartDisplayOptionsPanel::GanttChartDisplayOptionsPanel( GanttItemDelegate *delegate, QWidget *parent ) : QWidget( parent ), m_delegate( delegate ) { setupUi( this ); setValues( *delegate ); - connect( ui_showTaskName, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showResourceNames, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showDependencies, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showPositiveFloat, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showNegativeFloat, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showCriticalPath, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showCriticalTasks, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showCompletion, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showSchedulingError, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_showTimeConstraint, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); + connect( ui_showTaskName, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showResourceNames, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showDependencies, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showPositiveFloat, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showNegativeFloat, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showCriticalPath, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showCriticalTasks, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showCompletion, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showSchedulingError, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); + connect( ui_showTimeConstraint, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); } void GanttChartDisplayOptionsPanel::slotOk() { m_delegate->showTaskName = ui_showTaskName->checkState() == Qt::Checked; m_delegate->showResources = ui_showResourceNames->checkState() == Qt::Checked; m_delegate->showTaskLinks = ui_showDependencies->checkState() == Qt::Checked; m_delegate->showPositiveFloat = ui_showPositiveFloat->checkState() == Qt::Checked; m_delegate->showNegativeFloat = ui_showNegativeFloat->checkState() == Qt::Checked; m_delegate->showCriticalPath = ui_showCriticalPath->checkState() == Qt::Checked; m_delegate->showCriticalTasks = ui_showCriticalTasks->checkState() == Qt::Checked; m_delegate->showProgress = ui_showCompletion->checkState() == Qt::Checked; m_delegate->showSchedulingError = ui_showSchedulingError->checkState() == Qt::Checked; m_delegate->showTimeConstraint = ui_showTimeConstraint->checkState() == Qt::Checked; } void GanttChartDisplayOptionsPanel::setValues( const GanttItemDelegate &del ) { ui_showTaskName->setCheckState( del.showTaskName ? Qt::Checked : Qt::Unchecked ); ui_showResourceNames->setCheckState( del.showResources ? Qt::Checked : Qt::Unchecked ); ui_showDependencies->setCheckState( del.showTaskLinks ? Qt::Checked : Qt::Unchecked ); ui_showPositiveFloat->setCheckState( del.showPositiveFloat ? Qt::Checked : Qt::Unchecked ); ui_showNegativeFloat->setCheckState( del.showNegativeFloat ? Qt::Checked : Qt::Unchecked ); ui_showCriticalPath->setCheckState( del.showCriticalPath ? Qt::Checked : Qt::Unchecked ); ui_showCriticalTasks->setCheckState( del.showCriticalTasks ? Qt::Checked : Qt::Unchecked ); ui_showCompletion->setCheckState( del.showProgress ? Qt::Checked : Qt::Unchecked ); ui_showSchedulingError->setCheckState( del.showSchedulingError ? Qt::Checked : Qt::Unchecked ); ui_showTimeConstraint->setCheckState( del.showTimeConstraint ? Qt::Checked : Qt::Unchecked ); } void GanttChartDisplayOptionsPanel::setDefault() { GanttItemDelegate del; setValues( del ); } //---- GanttViewSettingsDialog::GanttViewSettingsDialog( GanttViewBase *gantt, GanttItemDelegate *delegate, ViewBase *view, bool selectPrint ) : ItemViewSettupDialog( view, gantt->treeView(), true, view ), m_gantt( gantt ) { GanttChartDisplayOptionsPanel *panel = new GanttChartDisplayOptionsPanel( delegate ); /*KPageWidgetItem *page = */insertWidget( 1, panel, i18n( "Chart" ), i18n( "Gantt Chart Settings" ) ); QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_printingoptions = new GanttPrintingOptionsWidget( this ); m_printingoptions->setOptions( gantt->printingOptions() ); tab->addTab( m_printingoptions, m_printingoptions->windowTitle() ); KPageWidgetItem *page = insertWidget( 2, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); - connect( this, SIGNAL(accepted()), panel, SLOT(slotOk()) ); - connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(setDefault()) ); + connect( this, &QDialog::accepted, panel, &GanttChartDisplayOptionsPanel::slotOk ); + connect( button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, panel, &GanttChartDisplayOptionsPanel::setDefault ); } void GanttViewSettingsDialog::slotOk() { debugPlan; m_gantt->setPrintingOptions( m_printingoptions->options()); ItemViewSettupDialog::slotOk(); } //------------------------- GanttPrintingOptions::GanttPrintingOptions() : printRowLabels( true ), singlePage( true ) { } bool GanttPrintingOptions::loadContext( const KoXmlElement &settings ) { KoXmlElement e = settings.namedItem( "print-options" ).toElement(); if ( ! e.isNull() ) { printRowLabels = (bool)( e.attribute( "print-rowlabels", "0" ).toInt() ); singlePage = (bool)( e.attribute( "print-singlepage", "0" ).toInt() ); } debugPlan <<"..........."<treeView()->header()->height(); // same header hight m_sceneRect = gantt->graphicsView()->sceneRect(); m_horPages = 1; qreal c = m_sceneRect.width() - printer().pageRect().width(); while ( c > 0 ) { ++m_horPages; c -= printer().pageRect().width(); } m_vertPages = 1; c = m_sceneRect.height() - printer().pageRect().height() - m_headerHeight; while ( c > 0 ) { ++m_vertPages; c -= printer().pageRect().height(); } debugPlan< pages; if ( printer().fromPage() > 0 ) { pages << printer().fromPage(); if ( ! m_gantt->m_printOptions.singlePage ) { int last = printer().toPage(); for ( int i = pages.first() + 1; i <= last; ++i ) { pages << i; } if (m_vertPages > 1) { m_image = QImage(m_sceneRect.width(), m_sceneRect.height() + m_headerHeight, QImage::Format_ARGB32); m_image.fill(Qt::white); QPainter p(&m_image); m_gantt->print(&p, m_image.rect(), m_gantt->m_printOptions.printRowLabels, true); } } } setPageRange( pages ); PrintingDialog::startPrinting( removePolicy ); } QList GanttPrintingDialog::createOptionWidgets() const { //debugPlan; GanttPrintingOptionsWidget *w = new GanttPrintingOptionsWidget(); w->setPrintRowLabels( m_gantt->m_printOptions.printRowLabels ); - connect(w->ui_printRowLabels, SIGNAL(toggled(bool)), SLOT(slotPrintRowLabelsToogled(bool))); + connect(w->ui_printRowLabels, &QAbstractButton::toggled, this, &GanttPrintingDialog::slotPrintRowLabelsToogled); w->setSinglePage( m_gantt->m_printOptions.singlePage ); - connect(w->ui_singlePage, SIGNAL(toggled(bool)), SLOT(slotSinglePageToogled(bool))); + connect(w->ui_singlePage, &QAbstractButton::toggled, this, &GanttPrintingDialog::slotSinglePageToogled); const_cast( this )->m_options = w; return QList() << createPageLayoutWidget() << m_options; } void GanttPrintingDialog::slotPrintRowLabelsToogled( bool on ) { m_gantt->m_printOptions.printRowLabels = on; } void GanttPrintingDialog::slotSinglePageToogled( bool on ) { m_gantt->m_printOptions.singlePage = on; printer().setFromTo( documentFirstPage(), documentLastPage() ); } int GanttPrintingDialog::documentLastPage() const { //debugPlan<m_printOptions.singlePage<m_printOptions.singlePage ? documentFirstPage() : m_horPages * m_vertPages; } void GanttPrintingDialog::printPage( int page, QPainter &painter ) { debugPlan<<"page:"<m_printOptions.singlePage; int vert = singlePage ? 0 : p / m_horPages; int hor = singlePage ? 0 : p % m_horPages; // painter.setClipRect( pageRect.adjusted( -1.0, -1.0, 1.0, 1.0 ) ); if (singlePage) { // single page: use KGantt m_gantt->print( &painter, m_sceneRect.left(), m_sceneRect.right(), pageRect, m_gantt->m_printOptions.printRowLabels, true ); } else if (m_vertPages == 1) { // single vertical page: use KGantt qreal hh = vert == 0 ? m_headerHeight : 0; qreal ho = vert > 0 ? m_headerHeight : 0; QRectF sourceRect = QRectF( m_sceneRect.x() + ( pageRect.width() * hor ), m_sceneRect.y() + ( ( pageRect.height() * vert ) - ho ), pageRect.width(), pageRect.height() - hh ); debugPlan<print( &painter, sourceRect.left(), sourceRect.right(), pageRect, hor == 0 && m_gantt->m_printOptions.printRowLabels, true ); } else { // print on multiple vertical pages: use pixmap // QT5TODO Make KGantt able to print multiple pages vertically QRectF sourceRect = m_image.rect(); qreal hh = vert == 0 ? m_headerHeight : 0; qreal ho = vert > 0 ? m_headerHeight : 0; sourceRect = QRectF( sourceRect.x() + ( pageRect.width() * hor ), sourceRect.y() + ( ( pageRect.height() * vert ) - ho ), pageRect.width(), pageRect.height() - hh ); debugPlan<setContextMenuPolicy( Qt::CustomContextMenu ); connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) ); } //------------------------------------------- GanttZoomWidget::GanttZoomWidget( QWidget *parent ) : QSlider( parent ), m_hide( true ), m_grid( 0 ) { setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); setGeometry( 0, 0, 200, minimumSizeHint().height() ); setContextMenuPolicy( Qt::PreventContextMenu ); setOrientation( Qt::Horizontal ); setPageStep( 5 ); setMaximum( 125 ); - connect(this, SIGNAL(valueChanged(int)), SLOT(sliderValueChanged(int))); + connect(this, &QAbstractSlider::valueChanged, this, &GanttZoomWidget::sliderValueChanged); } void GanttZoomWidget::setEnableHideOnLeave( bool hide ) { m_hide = hide; } void GanttZoomWidget::setGrid( KGantt::DateTimeGrid *grid ) { m_grid = grid; if ( grid ) { int pos = -1; // daywidth always >= 0.1 for ( qreal dw = grid->dayWidth(); dw >= 0.1 && pos < maximum(); ++pos ) { dw *= 1.0 / 1.1; } blockSignals( true ); setValue( pos ); blockSignals( false ); } } void GanttZoomWidget::leaveEvent( QEvent *e ) { if ( m_hide ) { setVisible( false ); } QSlider::leaveEvent( e ); } void GanttZoomWidget::sliderValueChanged( int value ) { //debugPlan<setDayWidth( v ); } } //------------------------------------------- GanttViewBase::GanttViewBase( QWidget *parent ) : KGantt::View( parent ) { KGantt::DateTimeGrid *g = static_cast( grid() ); g->setUserDefinedUpperScale( new KGantt::DateTimeScaleFormatter(KGantt::DateTimeScaleFormatter::Month, QString::fromLatin1("yyyy-MMMM"))); g->setUserDefinedLowerScale( new KGantt::DateTimeScaleFormatter(KGantt::DateTimeScaleFormatter::Day, QString::fromLatin1("ddd"))); QLocale locale; g->setWeekStart( locale.firstDayOfWeek() ); const QList weekdays = locale.weekdays(); QSet fd; for ( int i = Qt::Monday; i <= Qt::Sunday; ++i ) { if (!weekdays.contains(static_cast(i))) { fd << static_cast( i ); } } g->setFreeDays( fd ); m_zoomwidget = new GanttZoomWidget( graphicsView() ); m_zoomwidget->setGrid( g ); m_zoomwidget->setEnableHideOnLeave( true ); m_zoomwidget->hide(); m_zoomwidget->move( 6, 6 ); graphicsView()->installEventFilter(this); graphicsView()->setMouseTracking(true); } GanttViewBase::~GanttViewBase() { // HACK: avoid crash due to access of graphicsview scrollbar after death // KGantt tries to sync leftview scrollbar with graphicsview scrollbar // and seems sometimes graphicsview has already been deleted. // Note: this will be fixed in next KGantt release leftView()->verticalScrollBar()->disconnect(); } GanttTreeView *GanttViewBase::treeView() const { GanttTreeView *tv = qobject_cast(const_cast(leftView())); Q_ASSERT(tv); return tv; } bool GanttViewBase::eventFilter(QObject *obj, QEvent *event) { if (obj != graphicsView()) { return false; } if (event->type() == QEvent::HoverMove) { QHoverEvent *e = static_cast( event ); if (e->pos().y() > 7 && e->pos().y() < m_zoomwidget->height() + 5 && e->pos().x() > 7 && e->pos().x() < m_zoomwidget->width() + 5 ) { if ( !m_zoomwidget->isVisible()) { m_zoomwidget->show(); m_zoomwidget->setFocus(); } return true; } } return false; } bool GanttViewBase::loadContext( const KoXmlElement &settings ) { KGantt::DateTimeGrid *g = static_cast( grid() ); g->setScale( static_cast( settings.attribute( "chart-scale", "0" ).toInt() ) ); g->setDayWidth( settings.attribute( "chart-daywidth", "30" ).toDouble() ); return true; } void GanttViewBase::saveContext( QDomElement &settings ) const { KGantt::DateTimeGrid *g = static_cast( grid() ); settings.setAttribute( "chart-scale", QString::number(g->scale()) ); settings.setAttribute( "chart-daywidth", QString::number(g->dayWidth()) ); } //------------------------------------------- NodeGanttViewBase::NodeGanttViewBase( QWidget *parent ) : GanttViewBase( parent ), m_project( 0 ), m_ganttdelegate( new GanttItemDelegate( this ) ) { debugPlan<<"------------------- create NodeGanttViewBase -----------------------"; graphicsView()->setItemDelegate( m_ganttdelegate ); GanttTreeView *tv = new GanttTreeView( this ); tv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); tv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); tv->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); // needed since qt 4.2 setLeftView( tv ); m_rowController = new KGantt::TreeViewRowController( tv, ganttProxyModel() ); setRowController( m_rowController ); tv->header()->setStretchLastSection( true ); NodeSortFilterProxyModel *m = new NodeSortFilterProxyModel( &m_defaultModel, this ); KGantt::View::setModel( m ); } NodeGanttViewBase::~NodeGanttViewBase() { delete m_rowController; } NodeSortFilterProxyModel *NodeGanttViewBase::sfModel() const { return static_cast( KGantt::View::model() ); } void NodeGanttViewBase::setItemModel( ItemModelBase *model ) { sfModel()->setSourceModel( model ); } ItemModelBase *NodeGanttViewBase::model() const { return sfModel()->itemModel(); } void NodeGanttViewBase::setProject( Project *project ) { model()->setProject( project ); m_project = project; } bool NodeGanttViewBase::loadContext( const KoXmlElement &settings ) { treeView()->loadContext( model()->columnMap(), settings ); KoXmlElement e = settings.namedItem( "ganttchart" ).toElement(); if ( ! e.isNull() ) { m_ganttdelegate->showTaskLinks = (bool)( e.attribute( "show-dependencies", "0" ).toInt() ); m_ganttdelegate->showTaskName = (bool)( e.attribute( "show-taskname", "0" ).toInt() ); m_ganttdelegate->showResources = (bool)( e.attribute( "show-resourcenames", "0" ).toInt() ); m_ganttdelegate->showProgress = (bool)( e.attribute( "show-completion", "0" ).toInt() ); m_ganttdelegate->showCriticalPath = (bool)( e.attribute( "show-criticalpath", "0" ).toInt() ); m_ganttdelegate->showCriticalTasks = (bool)( e.attribute( "show-criticaltasks", "0" ).toInt() ); m_ganttdelegate->showPositiveFloat = (bool)( e.attribute( "show-positivefloat", "0" ).toInt() ); m_ganttdelegate->showSchedulingError = (bool)( e.attribute( "show-schedulingerror", "0" ).toInt() ); m_ganttdelegate->showTimeConstraint = (bool)( e.attribute( "show-timeconstraint", "0" ).toInt() ); m_ganttdelegate->showNegativeFloat = (bool)( e.attribute( "show-negativefloat", "0" ).toInt() ); GanttViewBase::loadContext( e ); m_printOptions.loadContext( e ); } return true; } void NodeGanttViewBase::saveContext( QDomElement &settings ) const { debugPlan; treeView()->saveContext( model()->columnMap(), settings ); QDomElement e = settings.ownerDocument().createElement( "ganttchart" ); settings.appendChild( e ); e.setAttribute( "show-dependencies", QString::number(m_ganttdelegate->showTaskLinks) ); e.setAttribute( "show-taskname", QString::number(m_ganttdelegate->showTaskName) ); e.setAttribute( "show-resourcenames", QString::number(m_ganttdelegate->showResources) ); e.setAttribute( "show-completion", QString::number(m_ganttdelegate->showProgress) ); e.setAttribute( "show-criticalpath", QString::number(m_ganttdelegate->showCriticalPath) ); e.setAttribute( "show-criticaltasks",QString::number(m_ganttdelegate->showCriticalTasks) ); e.setAttribute( "show-positivefloat", QString::number(m_ganttdelegate->showPositiveFloat) ); e.setAttribute( "show-schedulingerror", QString::number(m_ganttdelegate->showSchedulingError) ); e.setAttribute( "show-timeconstraint", QString::number(m_ganttdelegate->showTimeConstraint) ); e.setAttribute( "show-negativefloat", QString::number(m_ganttdelegate->showNegativeFloat) ); GanttViewBase::saveContext( e ); m_printOptions.saveContext( e ); } //------------------------------------------- MyKGanttView::MyKGanttView( QWidget *parent ) : NodeGanttViewBase( parent ), m_manager( 0 ) { debugPlan<<"------------------- create MyKGanttView -----------------------"; GanttItemModel *gm = new GanttItemModel( this ); setItemModel( gm ); treeView()->createItemDelegates( gm ); QList show; show << NodeModel::NodeName << NodeModel::NodeCompleted << NodeModel::NodeStartTime << NodeModel::NodeEndTime; treeView()->setDefaultColumns( show ); for ( int i = 0; i < model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { treeView()->hideColumn( i ); } } setConstraintModel( new KGantt::ConstraintModel( this ) ); KGantt::ProxyModel *m = static_cast( ganttProxyModel() ); m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); // To provide correct format m->setRole( KGantt::StartTimeRole, Qt::EditRole ); // To provide correct format m->setRole( KGantt::EndTimeRole, Qt::EditRole ); // To provide correct format m->removeColumn( Qt::DisplayRole ); m->setColumn( KGantt::ItemTypeRole, NodeModel::NodeType ); m->setColumn( KGantt::StartTimeRole, NodeModel::NodeStartTime ); m->setColumn( KGantt::EndTimeRole, NodeModel::NodeEndTime ); m->setColumn( KGantt::TaskCompletionRole, NodeModel::NodeCompleted ); KGantt::DateTimeGrid *g = static_cast( grid() ); g->setDayWidth( 30 ); // TODO: extend QLocale/KGantt to support formats for hourly time display // see bug #349030 // removed custom code here - connect( model(), SIGNAL(nodeInserted(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); + connect( model(), &NodeItemModel::nodeInserted, this, &MyKGanttView::slotNodeInserted ); } GanttItemModel *MyKGanttView::model() const { return static_cast( NodeGanttViewBase::model() ); } void MyKGanttView::setProject( Project *proj ) { clearDependencies(); if ( project() ) { - disconnect( project(), SIGNAL(relationToBeModified(Relation*)), this, SLOT(removeDependency(Relation*))); - disconnect( project(), SIGNAL(relationModified(Relation*)), this, SLOT(addDependency(Relation*))); - disconnect( project(), SIGNAL(relationAdded(Relation*)), this, SLOT(addDependency(Relation*)) ); - disconnect( project(), SIGNAL(relationToBeRemoved(Relation*)), this, SLOT(removeDependency(Relation*)) ); - disconnect( project(), SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); + disconnect( project(), &Project::relationToBeModified, this, &MyKGanttView::removeDependency); + disconnect( project(), &Project::relationModified, this, &MyKGanttView::addDependency); + disconnect( project(), &Project::relationAdded, this, &MyKGanttView::addDependency ); + disconnect( project(), &Project::relationToBeRemoved, this, &MyKGanttView::removeDependency ); + disconnect( project(), &Project::projectCalculated, this, &MyKGanttView::slotProjectCalculated ); } NodeGanttViewBase::setProject( proj ); if ( proj ) { - connect( project(), SIGNAL(relationToBeModified(Relation*)), this, SLOT(removeDependency(Relation*))); - connect( project(), SIGNAL(relationModified(Relation*)), this, SLOT(addDependency(Relation*))); - connect( proj, SIGNAL(relationAdded(Relation*)), this, SLOT(addDependency(Relation*)) ); - connect( proj, SIGNAL(relationToBeRemoved(Relation*)), this, SLOT(removeDependency(Relation*)) ); - connect( proj, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); + connect( project(), &Project::relationToBeModified, this, &MyKGanttView::removeDependency); + connect( project(), &Project::relationModified, this, &MyKGanttView::addDependency); + connect( proj, &Project::relationAdded, this, &MyKGanttView::addDependency ); + connect( proj, &Project::relationToBeRemoved, this, &MyKGanttView::removeDependency ); + connect( proj, &Project::projectCalculated, this, &MyKGanttView::slotProjectCalculated ); } createDependencies(); } void MyKGanttView::slotProjectCalculated( ScheduleManager *sm ) { if ( m_manager == sm ) { setScheduleManager( sm ); } } void MyKGanttView::setScheduleManager( ScheduleManager *sm ) { clearDependencies(); m_manager = sm; KGantt::DateTimeGrid *g = static_cast( grid() ); if ( sm && project() ) { QDateTime start = project()->startTime( sm->scheduleId() ); if ( g->startDateTime() != start ) { g->setStartDateTime( start ); } } if ( ! g->startDateTime().isValid() ) { g->setStartDateTime( QDateTime::currentDateTime() ); } model()->setScheduleManager( sm ); createDependencies(); } void MyKGanttView::slotNodeInserted( Node *node ) { foreach( Relation *r, node->dependChildNodes() ) { addDependency( r ); } foreach( Relation *r, node->dependParentNodes() ) { addDependency( r ); } } void MyKGanttView::addDependency( Relation *rel ) { QModelIndex par = sfModel()->mapFromSource( model()->index( rel->parent() ) ); QModelIndex ch = sfModel()->mapFromSource( model()->index( rel->child() ) ); // debugPlan<<"addDependency() "<( rel->type() )/*NOTE!!*/ ); if ( ! constraintModel()->hasConstraint( con ) ) { constraintModel()->addConstraint( con ); } } } void MyKGanttView::removeDependency( Relation *rel ) { QModelIndex par = sfModel()->mapFromSource( model()->index( rel->parent() ) ); QModelIndex ch = sfModel()->mapFromSource( model()->index( rel->child() ) ); KGantt::Constraint con( par, ch, KGantt::Constraint::TypeSoft, static_cast( rel->type() )/*NOTE!!*/ ); constraintModel()->removeConstraint( con ); } void MyKGanttView::clearDependencies() { constraintModel()->clear(); // Remove old deps from view // NOTE: This should be handled by KGantt graphicsView()->updateScene(); } void MyKGanttView::createDependencies() { clearDependencies(); if ( project() == 0 || m_manager == 0 ) { return; } foreach ( Node* n, project()->allNodes() ) { foreach ( Relation *r, n->dependChildNodes() ) { addDependency( r ); } } } //------------------------------------------ GanttView::GanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite) : ViewBase(part, doc, parent), m_readWrite( readWrite ), m_project( 0 ) { debugPlan <<" ---------------- KPlato: Creating GanttView ----------------"; QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); m_splitter = new QSplitter( this ); l->addWidget( m_splitter ); m_splitter->setOrientation( Qt::Vertical ); m_gantt = new MyKGanttView( m_splitter ); - connect(this, SIGNAL(expandAll()), m_gantt->treeView(), SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_gantt->treeView(), SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_gantt->treeView(), &TreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_gantt->treeView(), &TreeViewBase::slotCollapse); setupGui(); updateReadWrite( readWrite ); //connect( m_gantt->constraintModel(), SIGNAL(constraintAdded(Constraint)), this, SLOT(update()) ); debugPlan <constraintModel(); - connect( m_gantt->treeView(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_gantt->treeView(), &TreeViewBase::contextMenuRequested, this, &GanttView::slotContextMenuRequested ); - connect( m_gantt->treeView(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_gantt->treeView(), &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Gantt View" "" "Displays scheduled tasks in a Gantt diagram." " The chart area can be zoomed in and out with a slider" " positioned in the upper left corner of the time scale." " You need to hoover over it with the mouse for it to show." "" "This view supports configuration and printing using the context menu of the tree view." "More..." "", Help::page("Manual/Task_Gantt_View"))); } KoPrintJob *GanttView::createPrintJob() { return new GanttPrintingDialog( this, m_gantt ); } void GanttView::setZoom( double ) { //debugPlan <<"setting gantt zoom:" << zoom; //m_gantt->setZoomFactor(zoom,true); NO!!! setZoomFactor() is something else } void GanttView::setupGui() { // create context menu actions actionShowProject = new KToggleAction( i18n( "Show Project" ), this ); // FIXME: Dependencies depend on these methods being called in the correct order - connect(actionShowProject, SIGNAL(triggered(bool)), m_gantt, SLOT(clearDependencies())); - connect(actionShowProject, SIGNAL(triggered(bool)), m_gantt->model(), SLOT(setShowProject(bool))); - connect(actionShowProject, SIGNAL(triggered(bool)), m_gantt, SLOT(createDependencies())); + connect(actionShowProject, &QAction::triggered, m_gantt, &MyKGanttView::clearDependencies); + connect(actionShowProject, &QAction::triggered, m_gantt->model(), &NodeItemModel::setShowProject); + connect(actionShowProject, &QAction::triggered, m_gantt, &MyKGanttView::createDependencies); addContextAction( actionShowProject ); createOptionActions(ViewBase::OptionAll); } void GanttView::slotOptions() { debugPlan; GanttViewSettingsDialog *dlg = new GanttViewSettingsDialog( m_gantt, m_gantt->delegate(), this, sender()->objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void GanttView::slotOptionsFinished( int result ) { GanttViewSettingsDialog *dlg = qobject_cast( sender() ); if ( dlg && result == QDialog::Accepted ) { m_gantt->graphicsView()->updateScene(); } ViewBase::slotOptionsFinished( result ); } void GanttView::clear() { // m_gantt->clear(); } void GanttView::setShowResources( bool on ) { m_gantt->delegate()->showResources = on; } void GanttView::setShowTaskName( bool on ) { m_gantt->delegate()->showTaskName = on; } void GanttView::setShowProgress( bool on ) { m_gantt->delegate()->showProgress = on; } void GanttView::setShowPositiveFloat( bool on ) { m_gantt->delegate()->showPositiveFloat = on; } void GanttView::setShowCriticalTasks( bool on ) { m_gantt->delegate()->showCriticalTasks = on; } void GanttView::setShowCriticalPath( bool on ) { m_gantt->delegate()->showCriticalPath = on; } void GanttView::setShowNoInformation( bool on ) { m_gantt->delegate()->showNoInformation = on; } void GanttView::setShowAppointments( bool on ) { m_gantt->delegate()->showAppointments = on; } void GanttView::setShowTaskLinks( bool on ) { m_gantt->delegate()->showTaskLinks = on; } void GanttView::setProject( Project *project ) { m_gantt->setProject( project ); } void GanttView::setScheduleManager( ScheduleManager *sm ) { if (!sm && scheduleManager()) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_gantt->treeView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); bool expand = sm && scheduleManager() && sm != scheduleManager(); QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_gantt->treeView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_gantt->setScheduleManager( sm ); if (expand) { m_gantt->treeView()->doExpand(doc); } else if (tryexpand) { m_gantt->treeView()->doExpand(m_domdoc); } } void GanttView::draw( Project &project ) { setProject( &project ); } void GanttView::drawChanges( Project &project ) { if ( m_project != &project ) { setProject( &project ); } } Node *GanttView::currentNode() const { QModelIndex idx = m_gantt->treeView()->selectionModel()->currentIndex(); return m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); } void GanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint &pos ) { debugPlan; QString name; Node *node = m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node"; m_gantt->treeView()->setContextMenuIndex(idx); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); debugPlan<<"No menu"; return; } emit requestPopupMenu( name, pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); } bool GanttView::loadContext( const KoXmlElement &settings ) { debugPlan; ViewBase::loadContext( settings ); bool show = (bool)(settings.attribute( "show-project", "0" ).toInt() ); actionShowProject->setChecked( show ); m_gantt->model()->setShowProject( show ); // why is this not called by the action? return m_gantt->loadContext( settings ); } void GanttView::saveContext( QDomElement &settings ) const { debugPlan; ViewBase::saveContext( settings ); settings.setAttribute( "show-project", QString::number(actionShowProject->isChecked()) ); m_gantt->saveContext( settings ); } void GanttView::updateReadWrite( bool on ) { // TODO: KGanttView needs read/write mode m_readWrite = on; } //---- MilestoneGanttViewSettingsDialog::MilestoneGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint ) : ItemViewSettupDialog( view, gantt->treeView(), true, view ), m_gantt( gantt ) { QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_printingoptions = new GanttPrintingOptionsWidget( this ); m_printingoptions->setOptions( gantt->printingOptions() ); tab->addTab( m_printingoptions, m_printingoptions->windowTitle() ); KPageWidgetItem *page = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); } void MilestoneGanttViewSettingsDialog::slotOk() { debugPlan; m_gantt->setPrintingOptions( m_printingoptions->options()); ItemViewSettupDialog::slotOk(); } //------------------------ MilestoneKGanttView::MilestoneKGanttView( QWidget *parent ) : NodeGanttViewBase( parent ), m_manager( 0 ) { debugPlan<<"------------------- create MilestoneKGanttView -----------------------"; MilestoneItemModel *mm = new MilestoneItemModel( this ); setItemModel( mm ); treeView()->createItemDelegates( mm ); sfModel()->setFilterRole ( Qt::EditRole ); sfModel()->setFilterFixedString( QString::number( Node::Type_Milestone ) ); sfModel()->setFilterKeyColumn( NodeModel::NodeType ); QList show; show << NodeModel::NodeWBSCode << NodeModel::NodeName << NodeModel::NodeStartTime; treeView()->setDefaultColumns( show ); for ( int i = 0; i < model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { treeView()->hideColumn( i ); } } treeView()->header()->moveSection(NodeModel::NodeWBSCode, show.indexOf(NodeModel::NodeWBSCode)); treeView()->setRootIsDecorated ( false ); KGantt::ProxyModel *m = static_cast( ganttProxyModel() ); m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); // To provide correct format m->setRole( KGantt::StartTimeRole, Qt::EditRole ); // To provide correct format m->setRole( KGantt::EndTimeRole, Qt::EditRole ); // To provide correct format m->removeColumn( Qt::DisplayRole ); m->setColumn( KGantt::ItemTypeRole, NodeModel::NodeType ); m->setColumn( KGantt::StartTimeRole, NodeModel::NodeStartTime ); m->setColumn( KGantt::EndTimeRole, NodeModel::NodeEndTime ); m->setColumn( KGantt::TaskCompletionRole, NodeModel::NodeCompleted ); KGantt::DateTimeGrid *g = static_cast( grid() ); g->setDayWidth( 30 ); // TODO: extend QLocale/KGantt to support formats for hourly time display // see bug #349030 // removed custom code here // TODO: add to context treeView()->sortByColumn(NodeModel::NodeWBSCode, Qt::AscendingOrder); treeView()->setSortingEnabled(true); Help::add(this, xi18nc("@info:whatsthis", "Milestone Gantt View" "" "Displays scheduled milestones in a Gantt diagram." " The chart area can be zoomed in and out with a slider" " positioned in the upper left corner of the time scale." " You need to hoover over it with the mouse for it to show." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Milestone_Gantt_View"))); } MilestoneItemModel *MilestoneKGanttView::model() const { return static_cast( NodeGanttViewBase::model() ); } void MilestoneKGanttView::setProject( Project *proj ) { if ( project() ) { - disconnect( project(), SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); + disconnect( project(), &Project::projectCalculated, this, &MilestoneKGanttView::slotProjectCalculated ); } NodeGanttViewBase::setProject( proj ); if ( proj ) { - connect( proj, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); + connect( proj, &Project::projectCalculated, this, &MilestoneKGanttView::slotProjectCalculated ); } } void MilestoneKGanttView::slotProjectCalculated( ScheduleManager *sm ) { if ( m_manager == sm ) { setScheduleManager( sm ); } } void MilestoneKGanttView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<setScheduleManager( 0 ); m_manager = sm; KGantt::DateTimeGrid *g = static_cast( grid() ); if ( sm && m_project ) { QDateTime start; foreach ( const Node *n, model()->mileStones() ) { QDateTime nt = n->startTime( sm->scheduleId() ); if ( ! nt.isValid() ) { continue; } if ( ! start.isValid() || start > nt ) { start = nt; debugPlan<name()<startTime( sm->scheduleId() ); } if ( g->startDateTime() != start ) { g->setStartDateTime( start ); } } if ( ! g->startDateTime().isValid() ) { g->setStartDateTime( QDateTime::currentDateTime() ); } model()->setScheduleManager( sm ); } //------------------------------------------ MilestoneGanttView::MilestoneGanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite) : ViewBase(part, doc, parent), m_readWrite( readWrite ), m_project( 0 ) { debugPlan <<" ---------------- Plan: Creating Milesone GanttView ----------------"; QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); m_splitter = new QSplitter( this ); l->addWidget( m_splitter ); m_splitter->setOrientation( Qt::Vertical ); setupGui(); m_gantt = new MilestoneKGanttView( m_splitter ); m_showTaskName = false; // FIXME m_showProgress = false; //FIXME m_showPositiveFloat = false; //FIXME m_showCriticalTasks = false; //FIXME m_showNoInformation = false; //FIXME updateReadWrite( readWrite ); - connect( m_gantt->treeView(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_gantt->treeView(), &TreeViewBase::contextMenuRequested, this, &MilestoneGanttView::slotContextMenuRequested ); - connect( m_gantt->treeView(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_gantt->treeView(), &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); } void MilestoneGanttView::setZoom( double ) { //debugPlan <<"setting gantt zoom:" << zoom; //m_gantt->setZoomFactor(zoom,true); NO!!! setZoomFactor() is something else } void MilestoneGanttView::show() { } void MilestoneGanttView::clear() { } void MilestoneGanttView::setProject( Project *project ) { m_gantt->setProject( project ); } void MilestoneGanttView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<setScheduleManager( sm ); } void MilestoneGanttView::draw( Project &project ) { setProject( &project ); } void MilestoneGanttView::drawChanges( Project &project ) { if ( m_project != &project ) { setProject( &project ); } } Node *MilestoneGanttView::currentNode() const { QModelIndex idx = m_gantt->treeView()->selectionModel()->currentIndex(); return m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); } void MilestoneGanttView::setupGui() { createOptionActions(ViewBase::OptionAll); } void MilestoneGanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint &pos ) { debugPlan; QString name; Node *node = m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node"; m_gantt->treeView()->setContextMenuIndex(idx); if ( name.isEmpty() ) { debugPlan<<"No menu"; slotHeaderContextMenuRequested( pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); } void MilestoneGanttView::slotOptions() { debugPlan; MilestoneGanttViewSettingsDialog *dlg = new MilestoneGanttViewSettingsDialog( m_gantt, this, sender()->objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool MilestoneGanttView::loadContext( const KoXmlElement &settings ) { debugPlan; ViewBase::loadContext( settings ); return m_gantt->loadContext( settings ); } void MilestoneGanttView::saveContext( QDomElement &settings ) const { debugPlan; ViewBase::saveContext( settings ); return m_gantt->saveContext( settings ); } void MilestoneGanttView::updateReadWrite( bool on ) { m_readWrite = on; } KoPrintJob *MilestoneGanttView::createPrintJob() { return new GanttPrintingDialog( this, m_gantt ); } //-------------------- ResourceAppointmentsGanttViewSettingsDialog::ResourceAppointmentsGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint ) : ItemViewSettupDialog( view, gantt->treeView(), true, view ) , m_gantt(gantt) { QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_printingoptions = new GanttPrintingOptionsWidget( this ); m_printingoptions->setOptions( gantt->printingOptions() ); tab->addTab( m_printingoptions, m_printingoptions->windowTitle() ); KPageWidgetItem *page = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); } void ResourceAppointmentsGanttViewSettingsDialog::slotOk() { debugPlan; m_gantt->setPrintingOptions( m_printingoptions->options()); ItemViewSettupDialog::slotOk(); } //------------------------------------------ ResourceAppointmentsGanttView::ResourceAppointmentsGanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite) : ViewBase(part, doc, parent), m_project( 0 ), m_model( new ResourceAppointmentsGanttModel( this ) ) { debugPlan <<" ---------------- KPlato: Creating ResourceAppointmentsGanttView ----------------"; m_gantt = new GanttViewBase( this ); m_gantt->graphicsView()->setItemDelegate( new ResourceGanttItemDelegate( m_gantt ) ); GanttTreeView *tv = new GanttTreeView( m_gantt ); tv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); tv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); tv->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); // needed since qt 4.2 m_gantt->setLeftView( tv ); - connect(this, SIGNAL(expandAll()), tv, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), tv, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, tv, &TreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, tv, &TreeViewBase::slotCollapse); m_rowController = new KGantt::TreeViewRowController( tv, m_gantt->ganttProxyModel() ); m_gantt->setRowController( m_rowController ); tv->header()->setStretchLastSection( true ); tv->setTreePosition(-1); KGantt::ProxyModel *m = static_cast( m_gantt->ganttProxyModel() ); m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); m->setRole( KGantt::StartTimeRole, KGantt::StartTimeRole ); m->setRole( KGantt::EndTimeRole, KGantt::EndTimeRole ); m->setRole( KGantt::TaskCompletionRole, KGantt::TaskCompletionRole ); m_gantt->setModel( m_model ); QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); l->addWidget( m_gantt ); setupGui(); updateReadWrite( readWrite ); connect( m_gantt->leftView(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_gantt->leftView(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); Help::add(this, xi18nc("@info:whatsthis", "Resource Assignments (Gantt)" "" "Displays the scheduled resource - task assignments in a Gantt diagram." " The chart area can be zoomed in and out with a slider" " positioned in the upper left corner of the time scale." " You need to hoover over it with the mouse for it to show." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Resource_Assignment_Gantt_View"))); } ResourceAppointmentsGanttView::~ResourceAppointmentsGanttView() { delete m_rowController; } void ResourceAppointmentsGanttView::setZoom( double ) { //debugPlan <<"setting gantt zoom:" << zoom; //m_gantt->setZoomFactor(zoom,true); NO!!! setZoomFactor() is something else } Project *ResourceAppointmentsGanttView::project() const { return m_model->project(); } void ResourceAppointmentsGanttView::setProject( Project *project ) { m_model->setProject( project ); } void ResourceAppointmentsGanttView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); bool expand = sm && scheduleManager() && sm != scheduleManager(); QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); treeView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_model->setScheduleManager( sm ); if (expand) { treeView()->doExpand(doc); } else if (tryexpand) { treeView()->doExpand(m_domdoc); } } void ResourceAppointmentsGanttView::setupGui() { createOptionActions(ViewBase::OptionAll); } Node *ResourceAppointmentsGanttView::currentNode() const { QModelIndex idx = treeView()->selectionModel()->currentIndex(); return m_model->node( idx ); } void ResourceAppointmentsGanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint &pos ) { debugPlan<node( idx ); if ( n ) { name = "taskview_popup"; } } m_gantt->treeView()->setContextMenuIndex(idx); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); } void ResourceAppointmentsGanttView::slotOptions() { debugPlan; ItemViewSettupDialog *dlg = new ResourceAppointmentsGanttViewSettingsDialog(m_gantt, this, sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool ResourceAppointmentsGanttView::loadContext( const KoXmlElement &settings ) { debugPlan; ViewBase::loadContext( settings ); m_gantt->loadContext( settings ); return treeView()->loadContext( m_model->columnMap(), settings ); } void ResourceAppointmentsGanttView::saveContext( QDomElement &settings ) const { debugPlan; ViewBase::saveContext( settings ); m_gantt->saveContext( settings ); treeView()->saveContext( m_model->columnMap(), settings ); } void ResourceAppointmentsGanttView::updateReadWrite( bool on ) { m_readWrite = on; } KoPrintJob *ResourceAppointmentsGanttView::createPrintJob() { return new GanttPrintingDialog( this, m_gantt ); } } //KPlato namespace #include "moc_kptganttview.cpp" diff --git a/src/libs/ui/kpthtmlview.cpp b/src/libs/ui/kpthtmlview.cpp index 67474581..d58accdb 100644 --- a/src/libs/ui/kpthtmlview.cpp +++ b/src/libs/ui/kpthtmlview.cpp @@ -1,99 +1,99 @@ /* 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. */ #include "kpthtmlview.h" #include #include #include #include #include "kptdebug.h" namespace KPlato { //----------------------------------- HtmlView::HtmlView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { m_htmlPart = new KHTMLPart( this ); m_htmlPart->view()->setFrameStyle( QFrame::StyledPanel ); m_htmlPart->view()->setFrameShadow( QFrame::Sunken ); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); l->addWidget( m_htmlPart->view() ); m_htmlPart->show(); setupGui(); KParts::BrowserExtension *ext = m_htmlPart->browserExtension(); if ( ext ) { - connect( ext, SIGNAL(openUrlRequest(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)), SLOT(slotOpenUrlRequest(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)) ); + connect( ext, &KParts::BrowserExtension::openUrlRequest, this, &HtmlView::slotOpenUrlRequest ); } } void HtmlView::slotOpenUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &/*arguments*/, const KParts::BrowserArguments &/*browserArguments*/) { emit openUrlRequest( this, url ); } bool HtmlView::openHtml( const QUrl &url ) { return m_htmlPart->openUrl( url ); } void HtmlView::updateReadWrite( bool /*readwrite */) { } void HtmlView::setGuiActive( bool activate ) { debugPlan<createPrintJob( this ); } } // namespace KPlato diff --git a/src/libs/ui/kptintervaledit.cpp b/src/libs/ui/kptintervaledit.cpp index ef6a16ca..c1f82aef 100644 --- a/src/libs/ui/kptintervaledit.cpp +++ b/src/libs/ui/kptintervaledit.cpp @@ -1,280 +1,280 @@ /* This file is part of the KDE project Copyright (C) 2004 - 2010 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 "kptintervaledit.h" #include "intervalitem.h" #include "kptcommand.h" #include "kptproject.h" #include #include #include #include namespace KPlato { IntervalEdit::IntervalEdit( CalendarDay *day, QWidget *parent) : IntervalEditImpl(parent) { //debugPlan; if ( day ) { const QList &intervals = day->timeIntervals(); setIntervals( intervals ); if ( ! intervals.isEmpty() ) { startTime->setTime( intervals.last()->endTime() ); qreal l = ( intervals.last()->endTime().msecsTo( QTime().addMSecs( -1 ) ) + 1 ) / (1000.0*60.0*60.0); length->setValue( qMin( l, (qreal) 8.0 ) ); } } enableButtons(); startTime->setFocus(); } //-------------------------------------------- IntervalEditImpl::IntervalEditImpl(QWidget *parent) : IntervalEditBase(parent) { intervalList->setColumnCount( 2 ); QStringList lst; lst << i18nc( "Interval start time", "Start" ) << i18nc( "Interval length", "Length" ); intervalList->setHeaderLabels( lst ); intervalList->setRootIsDecorated( false ); intervalList->setSortingEnabled( true ); intervalList->sortByColumn( 0, Qt::AscendingOrder ); bAddInterval->setIcon(koIcon("list-add")); bRemoveInterval->setIcon(koIcon("list-remove")); bClear->setIcon(koIcon("edit-clear-list")); - connect(bClear, SIGNAL(clicked()), SLOT(slotClearClicked())); - connect(bAddInterval, SIGNAL(clicked()), SLOT(slotAddIntervalClicked())); - connect(bRemoveInterval, SIGNAL(clicked()), SLOT(slotRemoveIntervalClicked())); - connect(intervalList, SIGNAL(itemSelectionChanged()), SLOT(slotIntervalSelectionChanged())); + connect(bClear, &QAbstractButton::clicked, this, &IntervalEditImpl::slotClearClicked); + connect(bAddInterval, &QAbstractButton::clicked, this, &IntervalEditImpl::slotAddIntervalClicked); + connect(bRemoveInterval, &QAbstractButton::clicked, this, &IntervalEditImpl::slotRemoveIntervalClicked); + connect(intervalList, &QTreeWidget::itemSelectionChanged, this, &IntervalEditImpl::slotIntervalSelectionChanged); - connect( startTime, SIGNAL(timeChanged(QTime)), SLOT(enableButtons()) ); + connect( startTime, &QDateTimeEdit::timeChanged, this, &IntervalEditImpl::enableButtons ); connect( length, SIGNAL(valueChanged(double)), SLOT(enableButtons()) ); } void IntervalEditImpl::slotClearClicked() { bool c = intervalList->topLevelItemCount() > 0; intervalList->clear(); enableButtons(); if (c) emit changed(); } void IntervalEditImpl::slotAddIntervalClicked() { new IntervalItem(intervalList, startTime->time(), (int)(length->value() * 1000. * 60. *60.) ); enableButtons(); emit changed(); } void IntervalEditImpl::slotRemoveIntervalClicked() { IntervalItem *item = static_cast( intervalList->currentItem() ); if ( item == 0) { return; } intervalList->takeTopLevelItem( intervalList->indexOfTopLevelItem( item ) ); delete item; enableButtons(); emit changed(); } void IntervalEditImpl::slotIntervalSelectionChanged() { QList lst = intervalList->selectedItems(); if (lst.count() == 0) return; IntervalItem *ii = static_cast(lst[0]); startTime->setTime(ii->interval().first); length->setValue((double)(ii->interval().second) / (1000.*60.*60.)); enableButtons(); } QList IntervalEditImpl::intervals() const { QList l; int cnt = intervalList->topLevelItemCount(); for (int i=0; i < cnt; ++i) { IntervalItem *item = static_cast(intervalList->topLevelItem(i)); l.append(new TimeInterval(item->interval().first, item->interval().second)); } return l; } void IntervalEditImpl::setIntervals(const QList &intervals) { intervalList->clear(); foreach (TimeInterval *i, intervals) { new IntervalItem(intervalList, i->first, i->second); } enableButtons(); } void IntervalEditImpl::enableButtons() { bClear->setEnabled( ! intervals().isEmpty() ); bRemoveInterval->setEnabled( intervalList->currentItem() ); if ( length->value() == 0.0 ) { bAddInterval->setEnabled( false ); return; } if ( QTime( 0, 0, 0 ).secsTo( startTime->time() ) + (int)(length->value() * 60. * 60.) > 24 * 60 * 60 ) { bAddInterval->setEnabled( false ); return; } TimeInterval ti( startTime->time(), (int)(length->value() * 1000. * 60. *60.) ); foreach (TimeInterval *i, intervals()) { if ( i->intersects( ti ) ) { bAddInterval->setEnabled( false ); return; } } bAddInterval->setEnabled( true ); } //------------------------------------------------------------- IntervalEditDialog::IntervalEditDialog( Calendar *calendar, const QList &days, QWidget *parent) : KoDialog( parent ), m_calendar( calendar ), m_days( days ) { //debugPlan; setCaption( i18n("Edit Work Intervals") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); //debugPlan<<&p; m_panel = new IntervalEdit( days.value( 0 ), this ); setMainWidget( m_panel ); enableButtonOk( false ); - connect( m_panel, SIGNAL(changed()), SLOT(slotChanged()) ); - connect( calendar->project(), SIGNAL(calendarRemoved(const Calendar*)), SLOT(slotCalendarRemoved(const Calendar*)) ); + connect( m_panel, &IntervalEditImpl::changed, this, &IntervalEditDialog::slotChanged ); + connect( calendar->project(), &Project::calendarRemoved, this, &IntervalEditDialog::slotCalendarRemoved ); } IntervalEditDialog::IntervalEditDialog( Calendar *calendar, const QList &dates, QWidget *parent) : KoDialog( parent ), m_calendar( calendar ), m_dates( dates ) { //debugPlan; setCaption( i18n("Edit Work Intervals") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); //debugPlan<<&p; foreach ( const QDate &d, dates ) { CalendarDay *day = calendar->findDay( d ); if ( day ) { m_days << day; } } m_panel = new IntervalEdit( m_days.value( 0 ), this ); setMainWidget( m_panel ); enableButtonOk( false ); - connect( m_panel, SIGNAL(changed()), SLOT(slotChanged()) ); - connect( calendar->project(), SIGNAL(calendarRemoved(const Calendar*)), SLOT(slotCalendarRemoved(const Calendar*)) ); + connect( m_panel, &IntervalEditImpl::changed, this, &IntervalEditDialog::slotChanged ); + connect( calendar->project(), &Project::calendarRemoved, this, &IntervalEditDialog::slotCalendarRemoved ); } void IntervalEditDialog::slotCalendarRemoved( const Calendar *cal ) { if ( m_calendar == cal ) { reject(); } } void IntervalEditDialog::slotChanged() { enableButtonOk( true ); } MacroCommand *IntervalEditDialog::buildCommand() { MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Modify Work Interval" ) ); foreach ( const QDate &d, m_dates ) { // these are dates, weekdays don't have date CalendarDay *day = m_calendar->findDay( d ); if ( day == 0 ) { // create a new day day = new CalendarDay( d ); cmd->addCommand( new CalendarAddDayCmd( m_calendar, day ) ); } MacroCommand *c = buildCommand( m_calendar, day ); if ( c ) { cmd->addCommand( c ); } } if ( m_dates.isEmpty() ) { // weekdays foreach ( CalendarDay *day, m_days ) { MacroCommand *c = buildCommand( m_calendar, day ); if ( c ) { cmd->addCommand( c ); } } } if ( cmd->isEmpty() ) { delete cmd; return 0; } return cmd; } MacroCommand *IntervalEditDialog::buildCommand( Calendar *calendar, CalendarDay *day ) { //debugPlan; const QList lst = m_panel->intervals(); if ( lst == day->timeIntervals() ) { return 0; } MacroCommand *cmd = 0; // Set to Undefined. This will also clear any intervals CalendarModifyStateCmd *c = new CalendarModifyStateCmd( calendar, day, CalendarDay::Undefined ); if (cmd == 0) cmd = new MacroCommand(KUndo2MagicString()); cmd->addCommand(c); //debugPlan<<"Set Undefined"; foreach ( TimeInterval *i, lst ) { CalendarAddTimeIntervalCmd *c = new CalendarAddTimeIntervalCmd( calendar, day, i ); if (cmd == 0) cmd = new MacroCommand(KUndo2MagicString()); cmd->addCommand(c); } if ( ! lst.isEmpty() ) { CalendarModifyStateCmd *c = new CalendarModifyStateCmd( calendar, day, CalendarDay::Working ); if (cmd == 0) cmd = new MacroCommand(KUndo2MagicString()); cmd->addCommand(c); } if (cmd) { cmd->setText( kundo2_i18n( "Modify Work Interval" ) ); } return cmd; } } //KPlato namespace diff --git a/src/libs/ui/kptitemviewsettup.cpp b/src/libs/ui/kptitemviewsettup.cpp index 7c97a070..c19efcca 100644 --- a/src/libs/ui/kptitemviewsettup.cpp +++ b/src/libs/ui/kptitemviewsettup.cpp @@ -1,290 +1,290 @@ /* This file is part of the KDE project Copyright (C) 2007, 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. */ #include "kptitemviewsettup.h" #include "kptitemmodelbase.h" #include "kptviewbase.h" #include "kptdebug.h" #include "KoPageLayoutWidget.h" #include #include namespace KPlato { ItemViewSettup::Item::Item( int column, const QString &text ) : QListWidgetItem( text ), m_column( column ) { } int ItemViewSettup::Item::column() const { return m_column; } bool ItemViewSettup::Item::operator<( const QListWidgetItem & other ) const { return m_column < static_cast( other ).column(); } //-------------------------- ItemViewSettup::ItemViewSettup( TreeViewBase *view, bool includeColumn0, QWidget *parent ) : QWidget( parent ), m_view( view ), m_includeColumn0( includeColumn0 ) { setupUi( this ); stretchLastSection->setChecked( view->header()->stretchLastSection() ); QAbstractItemModel *model = view->model(); QMap map; int c = includeColumn0 ? 0 : 1; debugPlan<columnCount(); ++c ) { Item *item = new Item( c, model->headerData( c, Qt::Horizontal ).toString() ); item->setToolTip( model->headerData( c, Qt::Horizontal, Qt::ToolTipRole ).toString() ); if ( view->isColumnHidden( c ) ) { selector->availableListWidget()->addItem( item ); } else { map.insert( view->section( c ), item ); } } foreach( Item *i, map ) { selector->selectedListWidget()->addItem( i ); } - connect( stretchLastSection, SIGNAL(stateChanged(int)), this, SLOT(slotChanged()) ); + connect( stretchLastSection, &QCheckBox::stateChanged, this, &ItemViewSettup::slotChanged ); - connect( selector, SIGNAL(added(QListWidgetItem*)), this, SLOT(slotChanged()) ); - connect( selector, SIGNAL(removed(QListWidgetItem*)), this, SLOT(slotChanged()) ); - connect( selector, SIGNAL(movedUp(QListWidgetItem*)), this, SLOT(slotChanged()) ); - connect( selector, SIGNAL(movedDown(QListWidgetItem*)), this, SLOT(slotChanged()) ); + connect( selector, &KActionSelector::added, this, &ItemViewSettup::slotChanged ); + connect( selector, &KActionSelector::removed, this, &ItemViewSettup::slotChanged ); + connect( selector, &KActionSelector::movedUp, this, &ItemViewSettup::slotChanged ); + connect( selector, &KActionSelector::movedDown, this, &ItemViewSettup::slotChanged ); } void ItemViewSettup::slotChanged() { emit enableButtonOk( true ); } void ItemViewSettup::slotOk() { debugPlan; QListWidget *lst = selector->availableListWidget(); for ( int r = 0; r < lst->count(); ++r ) { int c = static_cast( lst->item( r ) )->column(); m_view->hideColumn( c ); } lst = selector->selectedListWidget(); for ( int r = 0; r < lst->count(); ++r ) { int c = static_cast( lst->item( r ) )->column(); m_view->mapToSection( c, r ); m_view->showColumn( c ); } m_view->setStretchLastSection( stretchLastSection->isChecked() ); } void ItemViewSettup::setDefault() { debugPlan; selector->availableListWidget()->clear(); selector->selectedListWidget()->clear(); QAbstractItemModel *model = m_view->model(); int c = m_includeColumn0 ? 0 : 1; QList def = m_view->defaultColumns(); for ( ; c < model->columnCount(); ++c ) { if ( ! def.contains( c ) ) { Item *item = new Item( c, model->headerData( c, Qt::Horizontal ).toString() ); item->setToolTip( model->headerData( c, Qt::Horizontal, Qt::ToolTipRole ).toString() ); selector->availableListWidget()->addItem( item ); } } foreach ( int i, def ) { Item *item = new Item( i, model->headerData( i, Qt::Horizontal ).toString() ); item->setToolTip( model->headerData( i, Qt::Horizontal, Qt::ToolTipRole ).toString() ); selector->selectedListWidget()->addItem( item ); } } //--------------------------- ItemViewSettupDialog::ItemViewSettupDialog( ViewBase *view, TreeViewBase *treeview, bool includeColumn0, QWidget *parent ) : KPageDialog( parent ), m_view( view ), m_treeview( treeview ), m_pagelayout( 0 ), m_headerfooter( 0 ) { setWindowTitle( i18n("View Settings") ); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); button(QDialogButtonBox::Ok)->setDefault(true); button( QDialogButtonBox::RestoreDefaults )->setEnabled( ! treeview->defaultColumns().isEmpty() ); m_panel = new ItemViewSettup( treeview, includeColumn0 ); KPageWidgetItem *page = new KPageWidgetItem( m_panel, i18n( "Tree View" ) ); page->setHeader( i18n( "Tree View Column Configuration" ) ); addPage( page ); m_pageList.append( page ); - connect(this, SIGNAL(accepted()), this, SLOT(slotOk())); - connect(this, SIGNAL(accepted()), m_panel, SLOT(slotOk())); - connect(button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), m_panel, SLOT(setDefault())); + connect(this, &QDialog::accepted, this, &ItemViewSettupDialog::slotOk); + connect(this, &QDialog::accepted, m_panel, &ItemViewSettup::slotOk); + connect(button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, m_panel, &ItemViewSettup::setDefault); } void ItemViewSettupDialog::slotOk() { debugPlan<setPageLayout( m_pagelayout->pageLayout() ); } if ( m_headerfooter ) { m_view->setPrintingOptions( m_headerfooter->options() ); } } KPageWidgetItem *ItemViewSettupDialog::insertWidget( int index, QWidget *widget, const QString &name, const QString &header ) { KPageWidgetItem *before = m_pageList.value( index ); KPageWidgetItem *page = new KPageWidgetItem( widget, name ); page->setHeader( header ); if ( before ) { insertPage( before, page ); m_pageList.insert( index, page ); } else { addPage( page ); m_pageList.append( page ); } return page; } void ItemViewSettupDialog::addPrintingOptions(bool setAsCurrent) { if ( ! m_view ) { return; } QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( m_view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_headerfooter = ViewBase::createHeaderFooterWidget( m_view ); tab->addTab( m_headerfooter, m_headerfooter->windowTitle() ); KPageWidgetItem *itm = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (setAsCurrent) { setCurrentPage(itm); } } //------------------------------- SplitItemViewSettupDialog::SplitItemViewSettupDialog( ViewBase *view, DoubleTreeViewBase *treeview, QWidget *parent ) : KPageDialog( parent ), m_view( view ), m_treeview( treeview ), m_pagelayout( 0 ), m_headerfooter( 0 ) { setWindowTitle( i18n("View Settings") ); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); button(QDialogButtonBox::Ok)->setDefault(true); bool nodef = treeview->masterView()->defaultColumns().isEmpty() || treeview->slaveView()->defaultColumns().isEmpty(); button( QDialogButtonBox::Ok )->setEnabled( ! nodef ); m_page1 = new ItemViewSettup( treeview->masterView(), true ); KPageWidgetItem *page = new KPageWidgetItem( m_page1, i18n( "Main View" ) ); page->setHeader( i18n( "Main View Column Configuration" ) ); addPage( page ); m_pageList.append( page ); m_page2 = new ItemViewSettup( treeview->slaveView(), true ); page = new KPageWidgetItem( m_page2, i18n( "Auxiliary View" ) ); page->setHeader( i18n( "Auxiliary View Column Configuration" ) ); addPage( page ); m_pageList.append( page ); //connect( m_page1, SIGNAL(enableButtonOk(bool)), this, SLOT(enableButtonOk(bool)) ); //connect( m_page2, SIGNAL(enableButtonOk(bool)), this, SLOT(enableButtonOk(bool)) ); - connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); - connect( this, SIGNAL(accepted()), m_page1, SLOT(slotOk()) ); - connect( this, SIGNAL(accepted()), m_page2, SLOT(slotOk()) ); - connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), m_page1, SLOT(setDefault()) ); - connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), m_page2, SLOT(setDefault()) ); + connect( this, &QDialog::accepted, this, &SplitItemViewSettupDialog::slotOk ); + connect( this, &QDialog::accepted, m_page1, &ItemViewSettup::slotOk ); + connect( this, &QDialog::accepted, m_page2, &ItemViewSettup::slotOk ); + connect( button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, m_page1, &ItemViewSettup::setDefault ); + connect( button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, m_page2, &ItemViewSettup::setDefault ); } void SplitItemViewSettupDialog::slotOk() { debugPlan; if ( ! m_view ) { return; } m_view->setPageLayout( m_pagelayout->pageLayout() ); m_view->setPrintingOptions( m_headerfooter->options() ); } KPageWidgetItem *SplitItemViewSettupDialog::insertWidget( int index, QWidget *widget, const QString &name, const QString &header ) { KPageWidgetItem *before = m_pageList.value( index ); KPageWidgetItem *page = new KPageWidgetItem( widget, name ); page->setHeader( header ); if ( before ) { insertPage( before, page ); m_pageList.insert( index, page ); } else { addPage( page ); m_pageList.append( page ); } return page; } void SplitItemViewSettupDialog::addPrintingOptions(bool setAsCurrent) { if ( ! m_view ) { return; } QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( m_view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_pagelayout->setPageLayout( m_view->pageLayout() ); m_headerfooter = ViewBase::createHeaderFooterWidget( m_view ); tab->addTab( m_headerfooter, m_headerfooter->windowTitle() ); m_headerfooter->setOptions( m_view->printingOptions() ); KPageWidgetItem *itm = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (setAsCurrent) { setCurrentPage(itm); } } } //namespace KPlato diff --git a/src/libs/ui/kptlocaleconfigmoneydialog.cpp b/src/libs/ui/kptlocaleconfigmoneydialog.cpp index e01568d8..3881e696 100644 --- a/src/libs/ui/kptlocaleconfigmoneydialog.cpp +++ b/src/libs/ui/kptlocaleconfigmoneydialog.cpp @@ -1,63 +1,63 @@ /* This file is part of the KDE project Copyright (C) 2009 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 "kptlocaleconfigmoneydialog.h" #include "locale/localemon.h" #include "kptcommand.h" #include "kptlocale.h" namespace KPlato { LocaleConfigMoneyDialog::LocaleConfigMoneyDialog( Locale *locale, QWidget *p) : KoDialog( p) { setCaption( i18n("Currency Settings") ); setButtons( Ok|Cancel ); showButtonSeparator( true ); m_panel = new LocaleConfigMoney( locale, this); setMainWidget(m_panel); enableButtonOk(false); - connect(m_panel, SIGNAL(localeChanged()), SLOT(slotChanged())); + connect(m_panel, &LocaleConfigMoney::localeChanged, this, &LocaleConfigMoneyDialog::slotChanged); } void LocaleConfigMoneyDialog::slotChanged() { enableButtonOk(true); } KUndo2Command *LocaleConfigMoneyDialog::buildCommand( Project &project ) { MacroCommand *m = new ModifyProjectLocaleCmd( project, kundo2_i18n( "Modify currency settings" ) ); MacroCommand *cmd = m_panel->buildCommand(); if (cmd) { m->addCommand(cmd); } if ( m->isEmpty() ) { delete m; return 0; } return m; } } //KPlato namespace diff --git a/src/libs/ui/kptmainprojectdialog.cpp b/src/libs/ui/kptmainprojectdialog.cpp index f534b8e7..5841a978 100644 --- a/src/libs/ui/kptmainprojectdialog.cpp +++ b/src/libs/ui/kptmainprojectdialog.cpp @@ -1,91 +1,91 @@ /* This file is part of the KDE project Copyright (C) 2003 - 2007 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 "kptmainprojectdialog.h" #include "kptproject.h" #include "kptmainprojectpanel.h" #include "kptcommand.h" #include namespace KPlato { MainProjectDialog::MainProjectDialog(Project &p, QWidget *parent, bool edit) : KoDialog( parent), project(p) { setWindowTitle( i18n("Project Settings") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); panel = new MainProjectPanel(project, this); panel->projectsLoadBtn->setVisible(edit); panel->projectsClearBtn->setVisible(edit); setMainWidget(panel); enableButtonOk(false); resize( QSize(500, 410).expandedTo(minimumSizeHint())); - connect(this, SIGNAL(rejected()), SLOT(slotRejected())); - connect(this, SIGNAL(accepted()), SLOT(slotOk())); - connect(panel, SIGNAL(obligatedFieldsFilled(bool)), SLOT(enableButtonOk(bool))); + connect(this, &QDialog::rejected, this, &MainProjectDialog::slotRejected); + connect(this, &QDialog::accepted, this, &MainProjectDialog::slotOk); + connect(panel, &MainProjectPanel::obligatedFieldsFilled, this, &KoDialog::enableButtonOk); - connect(panel, SIGNAL(loadResourceAssignments(QUrl)), this, SIGNAL(loadResourceAssignments(QUrl))); - connect(panel, SIGNAL(clearResourceAssignments()), this, SIGNAL(clearResourceAssignments())); + connect(panel, &MainProjectPanel::loadResourceAssignments, this, &MainProjectDialog::loadResourceAssignments); + connect(panel, &MainProjectPanel::clearResourceAssignments, this, &MainProjectDialog::clearResourceAssignments); } void MainProjectDialog::slotRejected() { emit dialogFinished(QDialog::Rejected); } void MainProjectDialog::slotOk() { if (!panel->ok()) { return; } if (panel->loadSharedResources()) { QString file = panel->resourcesFile->text(); if (file.startsWith('/')) { file.prepend("file:/"); } QString place = panel->projectsPlace->text(); if (panel->projectsType->currentIndex() == 0 /*dir*/ && !place.isEmpty() && !place.endsWith('/')) { place.append('/'); } QUrl url(place); emit sigLoadSharedResources(file, url, panel->projectsLoadAtStartup->isChecked()); } emit dialogFinished(QDialog::Accepted); } MacroCommand *MainProjectDialog::buildCommand() { MacroCommand *m = 0; KUndo2MagicString c = kundo2_i18n("Modify main project"); MacroCommand *cmd = panel->buildCommand(); if (cmd) { if (!m) m = new MacroCommand(c); m->addCommand(cmd); } return m; } } //KPlato namespace diff --git a/src/libs/ui/kptmainprojectpanel.cpp b/src/libs/ui/kptmainprojectpanel.cpp index 5c7a57ea..5aa23c94 100644 --- a/src/libs/ui/kptmainprojectpanel.cpp +++ b/src/libs/ui/kptmainprojectpanel.cpp @@ -1,309 +1,309 @@ /* This file is part of the KDE project Copyright (C) 2004-2007, 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. */ #include "kptmainprojectpanel.h" #include "kptdebug.h" #include #ifdef PLAN_KDEPIMLIBS_FOUND #include #include #include #endif #include "kptproject.h" #include "kptcommand.h" #include "kptschedule.h" #include "kpttaskdescriptiondialog.h" #include namespace KPlato { MainProjectPanel::MainProjectPanel(Project &p, QWidget *parent) : QWidget(parent), project(p) { setupUi(this); #ifndef PLAN_KDEPIMLIBS_FOUND chooseLeader->hide(); #endif // FIXME // [Bug 311940] New: Plan crashes when typing a text in the filter textbox before the textbook is fully loaded when selecting a contact from the adressbook chooseLeader->hide(); QString s = i18n( "The Work Breakdown Structure introduces numbering for all tasks in the project, according to the task structure.\nThe WBS code is auto-generated.\nYou can define the WBS code pattern using the Define WBS Pattern command in the Tools menu." ); wbslabel->setWhatsThis( s ); wbs->setWhatsThis( s ); namefield->setText(project.name()); leaderfield->setText(project.leader()); // useSharedResources->setEnabled(!project.isSharedResourcesLoaded()); useSharedResources->setChecked(project.useSharedResources()); resourcesFile->setText(project.sharedResourcesFile()); projectsPlace->setText(project.sharedProjectsUrl().toDisplayString()); qInfo()<widget(1) ); m_description->namefield->hide(); m_description->namelabel->hide(); wbs->setText(project.wbsCode()); if ( wbs->text().isEmpty() ) { wbslabel->hide(); wbs->hide(); } DateTime st = project.constraintStartTime(); DateTime et = project.constraintEndTime(); startDate->setDate(st.date()); startTime->setTime( QTime( st.time().hour(), st.time().minute(), 0 ) ); endDate->setDate(et.date()); endTime->setTime( QTime( et.time().hour(), et.time().minute(), 0 ) ); enableDateTime(); namefield->setFocus(); useSharedResources->setToolTip(xi18nc("@info:tooltip", "Enables sharing resources with other projects")); useSharedResources->setWhatsThis(xi18nc("@info:whatsthis", "Shared resources" "Resources can be shared between projects" " to avoid overbooking resources across projects." " Shared resources must be defined in a separate file," " and you must have at least read access to it." " The projects that share the resources must also be" " accessible by you." )); s = xi18nc("@info:tooltip", "File where shared resources are defined"); resourcesLabel->setToolTip(s); resourcesType->setToolTip(s); resourcesFile->setToolTip(s); s = xi18nc("@info:tooltip", "Directory where all the projects that share resources can be found"); projectsLabel->setToolTip(s); projectsType->setToolTip(s); projectsPlace->setToolTip(s); projectsLoadAtStartup->setChecked(project.loadProjectsAtStartup()); projectsLoadAtStartup->setToolTip(xi18nc("@info:tooltip", "Load shared resource assignments at startup")); projectsLoadBtn->setToolTip(xi18nc("@info:tooltip", "Load (or re-load) shared resource assignments")); projectsClearBtn->setToolTip(xi18nc("@info:tooltip", "Clear shared resource assignments")); // signals and slots connections - connect( m_description, SIGNAL(textChanged(bool)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( endDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( endTime, SIGNAL(timeChanged(QTime)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( startDate, SIGNAL(dateChanged(QDate)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( startTime, SIGNAL(timeChanged(QTime)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( namefield, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( leaderfield, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( useSharedResources, SIGNAL(toggled(bool)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( resourcesFile, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect( projectsPlace, SIGNAL(textChanged(QString)), this, SLOT(slotCheckAllFieldsFilled()) ); - connect(projectsLoadAtStartup, SIGNAL(toggled(bool)), this, SLOT(slotCheckAllFieldsFilled())); - connect( chooseLeader, SIGNAL(clicked()), this, SLOT(slotChooseLeader()) ); - - connect(resourcesBrowseBtn, SIGNAL(clicked()), this, SLOT(openResourcesFile())); - connect(projectsBrowseBtn, SIGNAL(clicked()), this, SLOT(openProjectsPlace())); - - connect(projectsLoadBtn, SIGNAL(clicked()), this, SLOT(loadProjects())); - connect(projectsClearBtn, SIGNAL(clicked()), this, SLOT(clearProjects())); + connect( m_description, &TaskDescriptionPanelImpl::textChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( endDate, &QDateTimeEdit::dateChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( endTime, &QDateTimeEdit::timeChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( startDate, &QDateTimeEdit::dateChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( startTime, &QDateTimeEdit::timeChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( namefield, &QLineEdit::textChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( leaderfield, &QLineEdit::textChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( useSharedResources, &QGroupBox::toggled, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( resourcesFile, &QLineEdit::textChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect( projectsPlace, &QLineEdit::textChanged, this, &MainProjectPanel::slotCheckAllFieldsFilled ); + connect(projectsLoadAtStartup, &QAbstractButton::toggled, this, &MainProjectPanel::slotCheckAllFieldsFilled); + connect( chooseLeader, &QAbstractButton::clicked, this, &MainProjectPanel::slotChooseLeader ); + + connect(resourcesBrowseBtn, &QAbstractButton::clicked, this, &MainProjectPanel::openResourcesFile); + connect(projectsBrowseBtn, &QAbstractButton::clicked, this, &MainProjectPanel::openProjectsPlace); + + connect(projectsLoadBtn, &QAbstractButton::clicked, this, &MainProjectPanel::loadProjects); + connect(projectsClearBtn, &QAbstractButton::clicked, this, &MainProjectPanel::clearProjects); } bool MainProjectPanel::ok() { if (useSharedResources->isChecked() && resourcesFile->text().isEmpty()) { return false; } return true; } MacroCommand *MainProjectPanel::buildCommand() { MacroCommand *m = 0; KUndo2MagicString c = kundo2_i18n("Modify main project"); if (project.name() != namefield->text()) { if (!m) m = new MacroCommand(c); m->addCommand(new NodeModifyNameCmd(project, namefield->text())); } if (project.leader() != leaderfield->text()) { if (!m) m = new MacroCommand(c); m->addCommand(new NodeModifyLeaderCmd(project, leaderfield->text())); } if (startDateTime() != project.constraintStartTime()) { if (!m) m = new MacroCommand(c); m->addCommand(new ProjectModifyStartTimeCmd(project, startDateTime())); } if (endDateTime() != project.constraintEndTime()) { if (!m) m = new MacroCommand(c); m->addCommand(new ProjectModifyEndTimeCmd(project, endDateTime())); } if (project.useSharedResources() != useSharedResources->isChecked()) { if (!m) m = new MacroCommand(c); m->addCommand(new UseSharedResourcesCmd(&project, useSharedResources->isChecked())); } if (project.sharedResourcesFile() != resourcesFile->text()) { if (!m) m = new MacroCommand(c); m->addCommand(new SharedResourcesFileCmd( &project, resourcesFile->text())); } QString place = projectsPlace->text(); if (projectsType->currentIndex() == 0 /*dir*/ && !place.isEmpty() && !place.endsWith('/')) { place.append('/'); } QUrl sharedProjectsUrl(place); if (project.sharedProjectsUrl() != sharedProjectsUrl) { if (!m) m = new MacroCommand(c); m->addCommand(new SharedProjectsUrlCmd( &project, sharedProjectsUrl)); } if (project.loadProjectsAtStartup() != projectsLoadAtStartup->isChecked()) { if (!m) m = new MacroCommand(c); m->addCommand(new LoadProjectsAtStartupCmd( &project, projectsLoadAtStartup->isChecked())); } MacroCommand *cmd = m_description->buildCommand(); if ( cmd ) { if (!m) m = new MacroCommand(c); m->addCommand( cmd ); } return m; } void MainProjectPanel::slotCheckAllFieldsFilled() { emit changed(); bool state = !namefield->text().isEmpty(); if (state && useSharedResources->isChecked()) { state = !resourcesFile->text().isEmpty(); if (state && projectsLoadAtStartup->isChecked()) { state = !projectsPlace->text().isEmpty(); } } emit obligatedFieldsFilled(state); } void MainProjectPanel::slotChooseLeader() { #ifdef PLAN_KDEPIMLIBS_FOUND QPointer dlg = new Akonadi::EmailAddressSelectionDialog( this ); if ( dlg->exec() && dlg ) { QStringList names; const Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); foreach ( const Akonadi::EmailAddressSelection &selection, selections ) { QString s = selection.name(); if ( ! selection.email().isEmpty() ) { if ( ! selection.name().isEmpty() ) { s += " <"; } s += selection.email(); if ( ! selection.name().isEmpty() ) { s += '>'; } if ( ! s.isEmpty() ) { names << s; } } } if ( ! names.isEmpty() ) { leaderfield->setText( names.join( ", " ) ); } } #endif } void MainProjectPanel::slotStartDateClicked() { enableDateTime(); } void MainProjectPanel::slotEndDateClicked() { enableDateTime(); } void MainProjectPanel::enableDateTime() { debugPlan; startTime->setEnabled(true); startDate->setEnabled(true); endTime->setEnabled(true); endDate->setEnabled(true); } QDateTime MainProjectPanel::startDateTime() { return QDateTime(startDate->date(), startTime->time(), Qt::LocalTime); } QDateTime MainProjectPanel::endDateTime() { return QDateTime(endDate->date(), endTime->time(), Qt::LocalTime); } void MainProjectPanel::openResourcesFile() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Resources"), "", tr("Resources file (*.plan)")); resourcesFile->setText(fileName); } void MainProjectPanel::openProjectsPlace() { if (projectsType->currentIndex() == 0 /*Directory*/) { qInfo()<setText(dirName); return; } if (projectsType->currentIndex() == 1 /*File*/) { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Projects"), "", tr("Projects file (*)")); projectsPlace->setText(fileName); return; } Q_ASSERT(false); // Unimplemented projects type } bool MainProjectPanel::loadSharedResources() const { return useSharedResources->isChecked(); } void MainProjectPanel::loadProjects() { QString place = projectsPlace->text(); if (projectsType->currentIndex() == 0 /*dir*/ && !place.isEmpty() && !place.endsWith('/')) { place.append('/'); } QUrl url(place); emit loadResourceAssignments(url); } void MainProjectPanel::clearProjects() { emit clearResourceAssignments(); } } //KPlato namespace diff --git a/src/libs/ui/kptmilestoneprogressdialog.cpp b/src/libs/ui/kptmilestoneprogressdialog.cpp index 234f11b5..d970ee64 100644 --- a/src/libs/ui/kptmilestoneprogressdialog.cpp +++ b/src/libs/ui/kptmilestoneprogressdialog.cpp @@ -1,71 +1,71 @@ /* This file is part of the KDE project Copyright (C) 2005 - 2007 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 "kptmilestoneprogressdialog.h" #include "kptmilestoneprogresspanel.h" #include "kptnode.h" #include "kptproject.h" #include namespace KPlato { class MacroCommand; MilestoneProgressDialog::MilestoneProgressDialog(Task &task, QWidget *p) : KoDialog(p), m_node( &task ) { setCaption( i18n("Milestone Progress") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); m_panel = new MilestoneProgressPanel(task, this); setMainWidget(m_panel); enableButtonOk(false); - connect(m_panel, SIGNAL(changed()), SLOT(slotChanged())); + connect(m_panel, &MilestoneProgressPanelImpl::changed, this, &MilestoneProgressDialog::slotChanged); Project *proj = static_cast( task.projectNode() ); if ( proj ) { - connect(proj, SIGNAL(nodeRemoved(KPlato::Node*)), SLOT(slotNodeRemoved(KPlato::Node*))); + connect(proj, &Project::nodeRemoved, this, &MilestoneProgressDialog::slotNodeRemoved); } } void MilestoneProgressDialog::slotNodeRemoved( Node *node ) { if ( m_node == node ) { reject(); } } void MilestoneProgressDialog::slotChanged() { enableButtonOk(true); } MacroCommand *MilestoneProgressDialog::buildCommand() { return m_panel->buildCommand(); } } //KPlato namespace diff --git a/src/libs/ui/kptmilestoneprogresspanel.cpp b/src/libs/ui/kptmilestoneprogresspanel.cpp index 9ced9d45..6a6b7b90 100644 --- a/src/libs/ui/kptmilestoneprogresspanel.cpp +++ b/src/libs/ui/kptmilestoneprogresspanel.cpp @@ -1,111 +1,111 @@ /* This file is part of the KDE project Copyright (C) 2005-2007, 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. */ #include "kptmilestoneprogresspanel.h" #include #include #include #include "kpttask.h" #include "kptcommand.h" #include "kptdebug.h" namespace KPlato { MilestoneProgressPanel::MilestoneProgressPanel(Task &task, QWidget *parent, const char *name) : MilestoneProgressPanelImpl(parent, name), m_task(task), m_completion( task.completion() ) { debugPlan; finished->setChecked(m_completion.isFinished()); finishTime->setDateTime(m_completion.finishTime()); enableWidgets(); finished->setFocus(); } MacroCommand *MilestoneProgressPanel::buildCommand() { MacroCommand *cmd = 0; KUndo2MagicString c = kundo2_i18n("Modify milestone completion"); if ( m_completion.isFinished() != finished->isChecked() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionStartedCmd( m_completion, finished->isChecked()) ); cmd->addCommand( new ModifyCompletionFinishedCmd( m_completion, finished->isChecked()) ); } if ( m_completion.finishTime() != finishTime->dateTime() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionStartTimeCmd( m_completion, finishTime->dateTime() ) ); cmd->addCommand( new ModifyCompletionFinishTimeCmd( m_completion, finishTime->dateTime() ) ); } if ( finished->isChecked() && finishTime->dateTime().isValid() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionPercentFinishedCmd( m_completion, finishTime->dateTime().date(), 100 ) ); } else { Completion::EntryList::ConstIterator entriesIt = m_completion.entries().constBegin(); const Completion::EntryList::ConstIterator entriesEnd = m_completion.entries().constEnd(); for (; entriesIt != entriesEnd; ++entriesIt) { const QDate &date = entriesIt.key(); if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new RemoveCompletionEntryCmd( m_completion, date ) ); } } return cmd; } //------------------------------------- MilestoneProgressPanelImpl::MilestoneProgressPanelImpl(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); setupUi(this); - connect(finished, SIGNAL(toggled(bool)), SLOT(slotFinishedChanged(bool))); - connect(finished, SIGNAL(toggled(bool)), SLOT(slotChanged())); + connect(finished, &QAbstractButton::toggled, this, &MilestoneProgressPanelImpl::slotFinishedChanged); + connect(finished, &QAbstractButton::toggled, this, &MilestoneProgressPanelImpl::slotChanged); - connect(finishTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); + connect(finishTime, &QDateTimeEdit::dateTimeChanged, this, &MilestoneProgressPanelImpl::slotChanged); } void MilestoneProgressPanelImpl::slotChanged() { emit changed(); } void MilestoneProgressPanelImpl::slotFinishedChanged(bool state) { if (state) { finishTime->setDateTime(QDateTime::currentDateTime()); } enableWidgets(); } void MilestoneProgressPanelImpl::enableWidgets() { finished->setEnabled(true); finishTime->setEnabled(finished->isChecked()); } } //KPlato namespace diff --git a/src/libs/ui/kptperteditor.cpp b/src/libs/ui/kptperteditor.cpp index 718ce3a6..e6e54ab5 100644 --- a/src/libs/ui/kptperteditor.cpp +++ b/src/libs/ui/kptperteditor.cpp @@ -1,439 +1,439 @@ /* This file is part of the KDE project Copyright (C) 2007 Florian Piquemal Copyright (C) 2007 Alexis Ménard Copyright (C) 2007, 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. */ #include "kptperteditor.h" #include "kptproject.h" #include "kptrelationeditor.h" #include "kptdebug.h" #include #include #include #include namespace KPlato { //----------------------------------- PertEditor::PertEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent), m_project( 0 ) { debugPlan <<" ---------------- KPlato: Creating PertEditor ----------------"; widget.setupUi(this); m_tasktree = widget.taskList; m_tasktree->setSelectionMode( QAbstractItemView::SingleSelection ); m_availableList = widget.available; m_availableList->setSelectionMode( QAbstractItemView::SingleSelection ); m_requiredList = widget.required; m_requiredList->hideColumn( 1 ); // child node name m_requiredList->setEditTriggers( QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed ); - connect( m_requiredList->model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( m_requiredList->model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); updateReadWrite( doc->isReadWrite() ); widget.addBtn->setIcon(koIcon("arrow-right")); widget.removeBtn->setIcon(koIcon("arrow-left")); slotAvailableChanged( 0 ); slotRequiredChanged( QModelIndex() ); - connect( m_tasktree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotCurrentTaskChanged(QTreeWidgetItem*,QTreeWidgetItem*)) ); - connect( m_availableList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotAvailableChanged(QTreeWidgetItem*)) ); - connect( m_requiredList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(slotRequiredChanged(QModelIndex)) ); + connect( m_tasktree, &QTreeWidget::currentItemChanged, this, &PertEditor::slotCurrentTaskChanged ); + connect( m_availableList, &QTreeWidget::currentItemChanged, this, &PertEditor::slotAvailableChanged ); + connect( m_requiredList->selectionModel(), &QItemSelectionModel::currentChanged, this, &PertEditor::slotRequiredChanged ); - connect( widget.addBtn, SIGNAL(clicked()), this, SLOT(slotAddClicked()) ); - connect( widget.removeBtn, SIGNAL(clicked()), this, SLOT(slotRemoveClicked()) ); + connect( widget.addBtn, &QAbstractButton::clicked, this, &PertEditor::slotAddClicked ); + connect( widget.removeBtn, &QAbstractButton::clicked, this, &PertEditor::slotRemoveClicked ); - connect( this, SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( this, &PertEditor::executeCommand, doc, &KoDocument::addCommand ); // TODO: need to use TreeViewBase here // connect(this, SIGNAL(expandAll()), m_tasktree, SLOT(slotExpand())); // connect(this, SIGNAL(collapseAll()), m_tasktree, SLOT(slotCollapse())); } void PertEditor::slotCurrentTaskChanged( QTreeWidgetItem *curr, QTreeWidgetItem *prev ) { //debugPlan<clear(); loadRequiredTasksList( 0 ); } else if ( prev == 0 ) { dispAvailableTasks(); } else { updateAvailableTasks(); loadRequiredTasksList( itemToNode( curr ) ); } slotAvailableChanged( m_availableList->currentItem() ); } void PertEditor::slotAvailableChanged( QTreeWidgetItem *item ) { //debugPlan<<(item?item->text(0):"nil")<<(item?item->data( 0, EnabledRole ).toBool():false); if ( item == 0 || item == m_availableList->currentItem() ) { widget.addBtn->setEnabled( item != 0 && item->data( 0, EnabledRole ).toBool() ); } } void PertEditor::slotRequiredChanged( const QModelIndex &item ) { //debugPlan<setEnabled( item.isValid() ); } void PertEditor::slotAddClicked() { if ( ! isReadWrite() ) { return; } QTreeWidgetItem *item = m_availableList->currentItem(); //debugPlan<currentItem(); if ( selectedTask == 0 ) { return; } Node *par = itemToNode( currentItem ); Node *child = itemToNode( selectedTask ); if ( par == 0 || child == 0 || ! m_project->legalToLink( par, child ) ) { return; } Relation *rel = new Relation ( par, child ); AddRelationCmd *addCmd = new AddRelationCmd( *m_project, rel, kundo2_noi18n(currentItem->text( 0 )) ); emit executeCommand( addCmd ); } void PertEditor::slotRemoveClicked() { if ( ! isReadWrite() ) { return; } Node *n = 0; Relation *r = m_requiredList->currentRelation(); if ( r ) { n = r->parent(); } removeTaskFromRequiredList(); setAvailableItemEnabled( n ); } void PertEditor::removeTaskFromRequiredList() { //debugPlan; Relation *r = m_requiredList->currentRelation(); if ( r == 0 ) { return; } // remove the relation emit executeCommand( new DeleteRelationCmd( *m_project, r, kundo2_i18n( "Remove task dependency" ) ) ); } void PertEditor::setProject( Project *project ) { if ( m_project ) { - disconnect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeAdded(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - disconnect( m_project, SIGNAL(relationAdded(KPlato::Relation*)), this, SLOT(slotRelationAdded(KPlato::Relation*)) ); - disconnect( m_project, SIGNAL(relationRemoved(KPlato::Relation*)), this, SLOT(slotRelationRemoved(KPlato::Relation*)) ); + disconnect( m_project, &Project::nodeAdded, this, &PertEditor::slotNodeAdded ); + disconnect( m_project, &Project::nodeToBeRemoved, this, &PertEditor::slotNodeRemoved ); + disconnect( m_project, &Project::nodeMoved, this, &PertEditor::slotNodeMoved ); + disconnect( m_project, &Project::nodeChanged, this, &PertEditor::slotNodeChanged ); + disconnect( m_project, &Project::relationAdded, this, &PertEditor::slotRelationAdded ); + disconnect( m_project, &Project::relationRemoved, this, &PertEditor::slotRelationRemoved ); } m_project = project; if ( m_project ) { - connect( m_project, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeAdded(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeMoved(KPlato::Node*)), this, SLOT(slotNodeMoved(KPlato::Node*)) ); - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - connect( m_project, SIGNAL(relationAdded(KPlato::Relation*)), this, SLOT(slotRelationAdded(KPlato::Relation*)) ); - connect( m_project, SIGNAL(relationRemoved(KPlato::Relation*)), this, SLOT(slotRelationRemoved(KPlato::Relation*)) ); + connect( m_project, &Project::nodeAdded, this, &PertEditor::slotNodeAdded ); + connect( m_project, &Project::nodeToBeRemoved, this, &PertEditor::slotNodeRemoved ); + connect( m_project, &Project::nodeMoved, this, &PertEditor::slotNodeMoved ); + connect( m_project, &Project::nodeChanged, this, &PertEditor::slotNodeChanged ); + connect( m_project, &Project::relationAdded, this, &PertEditor::slotRelationAdded ); + connect( m_project, &Project::relationRemoved, this, &PertEditor::slotRelationRemoved ); } m_requiredList->setProject( project ); draw(); } void PertEditor::slotRelationAdded( Relation *rel ) { debugPlan<child() == itemToNode( m_tasktree->currentItem() ) ) { QTreeWidgetItem *item = findNodeItem( rel->parent(), m_availableList->invisibleRootItem() ); updateAvailableTasks( item ); } } void PertEditor::slotRelationRemoved( Relation *rel ) { debugPlan<child() == itemToNode( m_tasktree->currentItem() ) ) { QTreeWidgetItem *item = findNodeItem( rel->parent(), m_availableList->invisibleRootItem() ); updateAvailableTasks( item ); } } void PertEditor::slotNodeAdded( Node *node ) { debugPlan<name()<childNodeIterator(); Node *parent = node->parentNode(); int index = parent->indexOf( node ); QTreeWidgetItem *pitem = findNodeItem( parent, m_tasktree->invisibleRootItem() ); if ( pitem == 0 ) { pitem = m_tasktree->invisibleRootItem(); } QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText( 0, node->name() ); item->setData( 0, NodeRole, node->id() ); pitem->insertChild( index, item ); pitem = findNodeItem( parent, m_availableList->invisibleRootItem() ); if ( pitem == 0 ) { pitem = m_availableList->invisibleRootItem(); } item = new QTreeWidgetItem(); item->setText( 0, node->name() ); item->setData( 0, NodeRole, node->id() ); item->setData( 0, EnabledRole, true ); pitem->insertChild( index, item ); setAvailableItemEnabled( item ); } void PertEditor::slotNodeRemoved( Node *node ) { //debugPlan; QTreeWidgetItem *item = findNodeItem( node, m_tasktree->invisibleRootItem() ); if ( item ) { QTreeWidgetItem *parent = item->parent(); if ( parent == 0 ) { parent = m_tasktree->invisibleRootItem(); } Q_ASSERT( parent ); parent->removeChild( item ); delete item; } item = findNodeItem( node, m_availableList->invisibleRootItem() ); if ( item ) { QTreeWidgetItem *parent = item->parent(); if ( parent == 0 ) { parent = m_availableList->invisibleRootItem(); } Q_ASSERT( parent ); parent->removeChild( item ); delete item; } } void PertEditor::slotNodeMoved( Node */*node */) { //debugPlan; draw(); } void PertEditor::slotNodeChanged( Node *node ) { QTreeWidgetItem *item = findNodeItem( node, m_tasktree->invisibleRootItem() ); if ( item ) { item->setText( 0, node->name() ); } item = findNodeItem( node, m_availableList->invisibleRootItem() ); if ( item ) { item->setText( 0, node->name() ); } } void PertEditor::draw( Project &project) { setProject( &project ); draw(); } void PertEditor::draw() { m_tasktree->clear(); if ( m_project == 0 ) { return; } drawSubTasksName( m_tasktree->invisibleRootItem(), m_project ); } void PertEditor::drawSubTasksName( QTreeWidgetItem *parent, Node * currentNode) { foreach(Node * currentChild, currentNode->childNodeIterator()){ QTreeWidgetItem * item = new QTreeWidgetItem( parent ); item->setText( 0, currentChild->name()); item->setData( 0, NodeRole, currentChild->id() ); //debugPlan<<"Added task"<name()<<"parent"<parent(); drawSubTasksName( item, currentChild); } } void PertEditor::updateReadWrite( bool rw ) { m_requiredList->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } QTreeWidgetItem *PertEditor::findNodeItem( Node *node, QTreeWidgetItem *item ) { if ( node->id() == item->data( 0, NodeRole ).toString() ) { return item; } for ( int i = 0; i < item->childCount(); ++i ) { QTreeWidgetItem *itm = findNodeItem( node, item->child( i ) ); if ( itm != 0 ) { return itm; } } return 0; } void PertEditor::dispAvailableTasks( Relation */*rel*/ ){ dispAvailableTasks(); } void PertEditor::dispAvailableTasks( Node *parent, Node *selectedTask ) { QTreeWidgetItem *pitem = findNodeItem( parent, m_availableList->invisibleRootItem() ); if ( pitem == 0 ) { pitem = m_availableList->invisibleRootItem(); } foreach(Node * currentNode, parent->childNodeIterator() ) { //debugPlan<name()<<"level="<level(); QTreeWidgetItem *item = new QTreeWidgetItem( QStringList()<name() ); item->setData( 0, NodeRole, currentNode->id() ); pitem->addChild(item); // Checks it isn't the same as the selected task in the m_tasktree setAvailableItemEnabled( item ); dispAvailableTasks( currentNode, selectedTask ); } } void PertEditor::dispAvailableTasks() { m_availableList->clear(); if ( m_project == 0 ) { return; } Node *selectedTask = itemToNode( m_tasktree->currentItem() ); loadRequiredTasksList(selectedTask); dispAvailableTasks( m_project, selectedTask ); } void PertEditor::updateAvailableTasks( QTreeWidgetItem *item ) { //debugPlan<invisibleRootItem(); } else { setAvailableItemEnabled( item ); } for ( int i=0; i < item->childCount(); ++i ) { updateAvailableTasks( item->child( i ) ); } } void PertEditor::setAvailableItemEnabled( QTreeWidgetItem *item ) { //debugPlan<currentItem() ); if ( selected == 0 || ! m_project->legalToLink( node, selected ) ) { //debugPlan<<"Disable:"<name(); item->setData( 0, EnabledRole, false ); QFont f = item->font( 0 ); f.setItalic( true ); item->setFont( 0, f ); } else { //debugPlan<<"Enable:"<name(); item->setData( 0, EnabledRole, true ); QFont f = item->font( 0 ); f.setItalic( false ); item->setFont( 0, f ); } slotAvailableChanged( item ); } void PertEditor::setAvailableItemEnabled( Node *node ) { //debugPlan<name(); setAvailableItemEnabled( nodeToItem( node, m_availableList->invisibleRootItem() ) ); } QTreeWidgetItem *PertEditor::nodeToItem( Node *node, QTreeWidgetItem *item ) { if ( itemToNode( item ) == node ) { return item; } for ( int i=0; i < item->childCount(); ++i ) { QTreeWidgetItem *itm = nodeToItem( node, item->child( i ) ); if ( itm ) { return itm; } } return 0; } Node * PertEditor::itemToNode( QTreeWidgetItem *item ) { if ( m_project == 0 || item == 0 ) { return 0; } return m_project->findNode( item->data( 0, NodeRole ).toString() ); } void PertEditor::loadRequiredTasksList(Node * taskNode) { slotRequiredChanged( QModelIndex() ); m_requiredList->setNode( taskNode ); } void PertEditor::slotUpdate() { draw(); } } // namespace KPlato diff --git a/src/libs/ui/kptpertresult.cpp b/src/libs/ui/kptpertresult.cpp index 8d9a3d21..b3a7122d 100644 --- a/src/libs/ui/kptpertresult.cpp +++ b/src/libs/ui/kptpertresult.cpp @@ -1,599 +1,599 @@ /* This file is part of the KDE project Copyright (C) 2007 Florian Piquemal Copyright (C) 2007 Alexis Ménard Copyright (C) 2007, 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. */ #include "kptpertresult.h" #include "kptproject.h" #include "kpttask.h" #include "kptnode.h" #include "kptschedule.h" #include "kptitemviewsettup.h" #include "kptdebug.h" #include #include #include #include #include #include namespace KPlato { class Project; class Node; class Task; static const double dist[][2] = { {0.00, 0.5000}, {0.02, 0.5080}, {0.04, 0.5160}, {0.06, 0.5239}, {0.08, 0.5319}, {0.10, 0.5398}, {0.12, 0.5478}, {0.14, 0.5557}, {0.16, 0.5636}, {0.18, 0.5714}, {0.20, 0.5793}, {0.22, 0.5871}, {0.24, 0.5948}, {0.26, 0.6026}, {0.28, 0.6103}, {0.30, 0.6179}, {0.32, 0.6255}, {0.34, 0.6331}, {0.36, 0.6406}, {0.38, 0.6480}, {0.40, 0.6554}, {0.42, 0.6628}, {0.44, 0.6700}, {0.46, 0.6772}, {0.48, 0.6844}, {0.50, 0.6915}, {0.52, 0.6985}, {0.54, 0.7054}, {0.56, 0.7123}, {0.58, 0.7190}, {0.60, 0.7257}, {0.62, 0.7324}, {0.64, 0.7389}, {0.66, 0.7454}, {0.68, 0.7517}, {0.70, 0.7580}, {0.72, 0.7642}, {0.74, 0.7704}, {0.76, 0.7764}, {0.78, 0.7823}, {0.80, 0.7881}, {0.82, 0.7939}, {0.84, 0.7995}, {0.86, 0.8051}, {0.88, 0.8106}, {0.90, 0.8159}, {0.92, 0.8212}, {0.94, 0.8264}, {0.96, 0.8315}, {0.98, 0.8365}, {1.00, 0.8413}, {1.02, 0.8461}, {1.04, 0.8508}, {1.06, 0.8554}, {1.08, 0.8599}, {1.10, 0.8643}, {1.12, 0.8686}, {1.14, 0.8729}, {1.16, 0.8770}, {1.18, 0.8810}, {1.20, 0.8849}, {1.22, 0.8888}, {1.24, 0.8925}, {1.26, 0.8962}, {1.28, 0.8997}, {1.30, 0.9032}, {1.32, 0.9066}, {1.34, 0.9099}, {1.36, 0.9131}, {1.38, 0.9162}, {1.40, 0.9192}, {1.42, 0.9222}, {1.44, 0.9251}, {1.46, 0.9279}, {1.48, 0.9306}, {1.50, 0.9332}, {1.52, 0.9357}, {1.54, 0.9382}, {1.56, 0.9406}, {1.58, 0.9429}, {1.60, 0.9452}, {1.62, 0.9474}, {1.64, 0.9495}, {1.66, 0.9515}, {1.68, 0.9535}, {1.70, 0.9554}, {1.72, 0.9573}, {1.74, 0.9591}, {1.76, 0.9608}, {1.78, 0.9625}, {1.80, 0.9641}, {1.82, 0.9656}, {1.84, 0.9671}, {1.86, 0.9686}, {1.88, 0.9699}, {1.90, 0.9713}, {1.92, 0.9726}, {1.94, 0.9738}, {1.96, 0.9750}, {1.98, 0.9761}, {2.00, 0.9772}, {2.02, 0.9783}, {2.34, 0.9793}, {2.36, 0.9803}, {2.38, 0.9812}, {2.10, 0.9821}, {2.12, 0.9830}, {2.34, 0.9838}, {2.36, 0.9846}, {2.38, 0.9854}, {2.20, 0.9861}, {2.22, 0.9868}, {2.34, 0.9875}, {2.36, 0.9881}, {2.38, 0.9887}, {2.30, 0.9893}, {2.32, 0.9898}, {2.34, 0.9904}, {2.36, 0.9909}, {2.38, 0.9913}, {2.40, 0.9918}, {2.42, 0.9922}, {2.44, 0.9927}, {2.46, 0.9931}, {2.48, 0.9934}, {2.50, 0.9938}, {2.52, 0.9941}, {2.54, 0.9945}, {2.56, 0.9948}, {2.58, 0.9951}, {2.60, 0.9953}, {2.62, 0.9956}, {2.64, 0.9959}, {2.66, 0.9961}, {2.68, 0.9963}, {2.70, 0.9965}, {2.72, 0.9967}, {2.74, 0.9969}, {2.76, 0.9971}, {2.78, 0.9973}, {2.80, 0.9974}, {2.82, 0.9976}, {2.84, 0.9977}, {2.86, 0.9979}, {2.88, 0.9980}, {2.90, 0.9981}, {2.92, 0.9982}, {2.94, 0.9984}, {2.96, 0.9985}, {2.98, 0.9986}, {3.00, 0.9987} }; //----------------------------------- PertResult::PertResult(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent ), m_node( 0 ), m_project( 0 ), current_schedule( 0 ) { debugPlan << " ---------------- KPlato: Creating PertResult ----------------"; widget.setupUi(this); PertResultItemModel *m = new PertResultItemModel( widget.treeWidgetTaskResult ); widget.treeWidgetTaskResult->setModel( m ); widget.treeWidgetTaskResult->setStretchLastSection( false ); widget.treeWidgetTaskResult->setSelectionMode( QAbstractItemView::ExtendedSelection ); setupGui(); QList lst1; lst1 << 1 << -1; // only display column 0 (NodeName) in left view QList show; show << NodeModel::NodeEarlyStart << NodeModel::NodeEarlyFinish << NodeModel::NodeLateStart << NodeModel::NodeLateFinish << NodeModel::NodePositiveFloat << NodeModel::NodeFreeFloat << NodeModel::NodeNegativeFloat << NodeModel::NodeStartFloat << NodeModel::NodeFinishFloat; QList lst2; for ( int i = 0; i < m->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } widget.treeWidgetTaskResult->hideColumns( lst1, lst2 ); widget.treeWidgetTaskResult->masterView()->setDefaultColumns( QList() << 0 ); widget.treeWidgetTaskResult->slaveView()->setDefaultColumns( show ); - connect( widget.treeWidgetTaskResult, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( widget.treeWidgetTaskResult, &DoubleTreeViewBase::contextMenuRequested, this, &PertResult::slotContextMenuRequested ); connect( widget.treeWidgetTaskResult, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); - connect(this, SIGNAL(expandAll()), widget.treeWidgetTaskResult, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), widget.treeWidgetTaskResult, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, widget.treeWidgetTaskResult, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, widget.treeWidgetTaskResult, &DoubleTreeViewBase::slotCollapse); } void PertResult::draw( Project &project) { setProject( &project ); //draw(); } void PertResult::draw() { debugPlan<setText( i18n( "None" ) ); widget.totalFloat->clear(); if ( m_project && model()->manager() && model()->manager()->isScheduled() ) { long id = model()->manager()->scheduleId(); if ( id == -1 ) { return; } widget.scheduleName->setText( model()->manager()->name() ); Duration f; foreach ( Node *n, m_project->allNodes() ) { if ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) { f += static_cast( n )->positiveFloat( id ); } } widget.totalFloat->setText( QLocale().toString( f.toDouble( Duration::Unit_h ), 'f', 2 ) ); } } void PertResult::setupGui() { // Add the context menu actions for the view options - connect(widget.treeWidgetTaskResult->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(widget.treeWidgetTaskResult->actionSplitView(), &QAction::triggered, this, &PertResult::slotSplitView); addContextAction( widget.treeWidgetTaskResult->actionSplitView() ); createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig); } void PertResult::slotSplitView() { debugPlan; widget.treeWidgetTaskResult->setViewSplitMode( ! widget.treeWidgetTaskResult->isViewSplit() ); emit optionsModified(); } Node *PertResult::currentNode() const { return model()->node( widget.treeWidgetTaskResult->selectionModel()->currentIndex() ); } void PertResult::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { debugPlan<node( index ); if ( node == 0 ) { slotHeaderContextMenuRequested( pos ); return; } debugPlan<name()<<" :"<type() ) { case Node::Type_Task: name = "task_popup"; break; case Node::Type_Milestone: name = "taskeditor_milestone_popup"; break; case Node::Type_Summarytask: name = "summarytask_popup"; break; case Node::Type_Project: break; default: name = "node_popup"; break; } if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); return; } debugPlan< lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } void PertResult::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, widget.treeWidgetTaskResult, this ); // Note: printing needs fixes in SplitterView/ScheduleHandlerView //dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void PertResult::slotUpdate(){ draw(); } void PertResult::slotScheduleSelectionChanged( ScheduleManager *sm ) { current_schedule = sm; model()->setManager( sm ); draw(); } void PertResult::slotProjectCalculated(KPlato::ScheduleManager *sm) { if ( sm && sm == model()->manager() ) { //draw(); slotScheduleSelectionChanged( sm ); } } void PertResult::slotScheduleManagerToBeRemoved( const ScheduleManager *sm ) { if ( sm == model()->manager() ) { current_schedule = 0; model()->setManager( 0 ); } } void PertResult::slotScheduleManagerChanged( ScheduleManager *sm ) { if ( current_schedule && current_schedule == sm ) { slotScheduleSelectionChanged( sm ); } } void PertResult::setProject( Project *project ) { if ( m_project ) { - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotUpdate()) ); - disconnect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); - disconnect( m_project, SIGNAL(scheduleManagerToBeRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeRemoved(const KPlato::ScheduleManager*)) ); - disconnect( m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerChanged(KPlato::ScheduleManager*)) ); + disconnect( m_project, &Project::nodeChanged, this, &PertResult::slotUpdate ); + disconnect( m_project, &Project::projectCalculated, this, &PertResult::slotProjectCalculated ); + disconnect( m_project, &Project::scheduleManagerToBeRemoved, this, &PertResult::slotScheduleManagerToBeRemoved ); + disconnect( m_project, &Project::scheduleManagerChanged, this, &PertResult::slotScheduleManagerChanged ); } m_project = project; model()->setProject( m_project ); if ( m_project ) { - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotUpdate()) ); - connect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); - connect( m_project, SIGNAL(scheduleManagerToBeRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeRemoved(const KPlato::ScheduleManager*)) ); - connect( m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerChanged(KPlato::ScheduleManager*)) ); + connect( m_project, &Project::nodeChanged, this, &PertResult::slotUpdate ); + connect( m_project, &Project::projectCalculated, this, &PertResult::slotProjectCalculated ); + connect( m_project, &Project::scheduleManagerToBeRemoved, this, &PertResult::slotScheduleManagerToBeRemoved ); + connect( m_project, &Project::scheduleManagerChanged, this, &PertResult::slotScheduleManagerChanged ); } draw(); } bool PertResult::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); return widget.treeWidgetTaskResult->loadContext( model()->columnMap(), context ); } void PertResult::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); widget.treeWidgetTaskResult->saveContext( model()->columnMap(), context ); } KoPrintJob *PertResult::createPrintJob() { return widget.treeWidgetTaskResult->createPrintJob( this ); } //-------------------- PertCpmView::PertCpmView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent), m_project( 0 ), current_schedule( 0 ), block( false ) { debugPlan << " ---------------- KPlato: Creating PertCpmView ----------------"; widget.setupUi(this); widget.cpmTable->setSelectionMode( QAbstractItemView::ExtendedSelection ); widget.probabilityFrame->setVisible( false ); widget.cpmTable->setStretchLastSection ( false ); CriticalPathItemModel *m = new CriticalPathItemModel( widget.cpmTable ); widget.cpmTable->setModel( m ); setupGui(); QList lst1; lst1 << 1 << -1; // only display first column (NodeName) in left view widget.cpmTable->masterView()->setDefaultColumns( QList() << 0 ); QList show; show << NodeModel::NodeDuration << NodeModel::NodeVarianceDuration << NodeModel::NodeOptimisticDuration << NodeModel::NodePessimisticDuration << NodeModel::NodeEstimate << NodeModel::NodeExpected << NodeModel::NodeVarianceEstimate << NodeModel::NodeOptimistic << NodeModel::NodePessimistic; QList lst2; for ( int i = 0; i < m->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } widget.cpmTable->hideColumns( lst1, lst2 ); for ( int s = 0; s < show.count(); ++s ) { widget.cpmTable->slaveView()->mapToSection( show[s], s ); } widget.cpmTable->slaveView()->setDefaultColumns( show ); - connect( widget.cpmTable, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( widget.cpmTable, &DoubleTreeViewBase::contextMenuRequested, this, &PertCpmView::slotContextMenuRequested ); connect( widget.cpmTable, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); - connect( widget.finishTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotFinishTimeChanged(QDateTime)) ); + connect( widget.finishTime, &QDateTimeEdit::dateTimeChanged, this, &PertCpmView::slotFinishTimeChanged ); connect( widget.probability, SIGNAL(valueChanged(int)), SLOT(slotProbabilityChanged(int)) ); } void PertCpmView::setupGui() { // Add the context menu actions for the view options - connect(widget.cpmTable->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(widget.cpmTable->actionSplitView(), &QAction::triggered, this, &PertCpmView::slotSplitView); addContextAction( widget.cpmTable->actionSplitView() ); createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig); } void PertCpmView::slotSplitView() { debugPlan; widget.cpmTable->setViewSplitMode( ! widget.cpmTable->isViewSplit() ); emit optionsModified(); } Node *PertCpmView::currentNode() const { return model()->node( widget.cpmTable->selectionModel()->currentIndex() ); } void PertCpmView::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { debugPlan<node( index ); if ( node == 0 ) { slotHeaderContextMenuRequested( pos ); return; } debugPlan<name()<<" :"<type() ) { case Node::Type_Task: name = "task_popup"; break; case Node::Type_Milestone: name = "taskeditor_milestone_popup"; break; case Node::Type_Summarytask: name = "summarytask_popup"; break; case Node::Type_Project: break; default: name = "node_popup"; break; } if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); return; } debugPlan< lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } void PertCpmView::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, widget.cpmTable, this ); // Note: printing needs fixes in SplitterView/ScheduleHandlerView //dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void PertCpmView::slotScheduleSelectionChanged( ScheduleManager *sm ) { bool enbl = sm && sm->isScheduled() && sm->usePert(); debugPlan<isScheduled():false)<<(sm?sm->usePert():false)<setVisible( enbl ); current_schedule = sm; model()->setManager( sm ); draw(); } void PertCpmView::slotProjectCalculated( ScheduleManager *sm ) { if ( sm && sm == model()->manager() ) { slotScheduleSelectionChanged( sm ); } } void PertCpmView::slotScheduleManagerChanged( ScheduleManager *sm ) { if ( current_schedule == sm ) { slotScheduleSelectionChanged( sm ); } } void PertCpmView::slotScheduleManagerToBeRemoved( const ScheduleManager *sm ) { if ( sm == current_schedule ) { current_schedule = 0; model()->setManager( 0 ); widget.probabilityFrame->setVisible( false ); } } void PertCpmView::setProject( Project *project ) { if ( m_project ) { - disconnect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotUpdate()) ); - disconnect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); - disconnect( m_project, SIGNAL(scheduleManagerToBeRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeRemoved(const KPlato::ScheduleManager*)) ); - disconnect( m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerChanged(KPlato::ScheduleManager*)) ); + disconnect( m_project, &Project::nodeChanged, this, &PertCpmView::slotUpdate ); + disconnect( m_project, &Project::projectCalculated, this, &PertCpmView::slotProjectCalculated ); + disconnect( m_project, &Project::scheduleManagerToBeRemoved, this, &PertCpmView::slotScheduleManagerToBeRemoved ); + disconnect( m_project, &Project::scheduleManagerChanged, this, &PertCpmView::slotScheduleManagerChanged ); } m_project = project; model()->setProject( m_project ); if ( m_project ) { - connect( m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotUpdate()) ); - connect( m_project, SIGNAL(projectCalculated(KPlato::ScheduleManager*)), this, SLOT(slotProjectCalculated(KPlato::ScheduleManager*)) ); - connect( m_project, SIGNAL(scheduleManagerToBeRemoved(const KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerToBeRemoved(const KPlato::ScheduleManager*)) ); - connect( m_project, SIGNAL(scheduleManagerChanged(KPlato::ScheduleManager*)), this, SLOT(slotScheduleManagerChanged(KPlato::ScheduleManager*)) ); + connect( m_project, &Project::nodeChanged, this, &PertCpmView::slotUpdate ); + connect( m_project, &Project::projectCalculated, this, &PertCpmView::slotProjectCalculated ); + connect( m_project, &Project::scheduleManagerToBeRemoved, this, &PertCpmView::slotScheduleManagerToBeRemoved ); + connect( m_project, &Project::scheduleManagerChanged, this, &PertCpmView::slotScheduleManagerChanged ); } draw(); } void PertCpmView::draw( Project &project ) { setProject( &project ); // draw() } void PertCpmView::draw() { widget.scheduleName->setText( i18n( "None" ) ); bool enbl = m_project && current_schedule && current_schedule->isScheduled() && current_schedule->usePert(); widget.probabilityFrame->setVisible( enbl ); if ( m_project && current_schedule && current_schedule->isScheduled() ) { long id = current_schedule->scheduleId(); if ( id == -1 ) { return; } widget.scheduleName->setText( current_schedule->name() ); widget.finishTime->setDateTime( m_project->endTime( id ) ); bool ro = model()->variance( Qt::EditRole ).toDouble() == 0.0; if ( ro ) { widget.probability->setValue( 50 ); } widget.finishTime->setReadOnly( ro ); widget.probability->setEnabled( ! ro ); } } void PertCpmView::slotFinishTimeChanged( const QDateTime &dt ) { debugPlan<variance( Qt::EditRole ).toDouble(); double dev = sqrt( var ); DateTime et = m_project->endTime( current_schedule->scheduleId() ); DateTime t = DateTime( dt ); double d = ( et - t ).toDouble(); d = t < et ? -d : d; double z = d / dev; double v = probability( z ); widget.probability->setValue( (int)( v * 100 ) ); //debugPlan<variance( Qt::EditRole ).toDouble(); double dev = sqrt( var ); DateTime et = m_project->endTime( current_schedule->scheduleId() ); double p = valueZ( value ); DateTime t = et + Duration( qint64( p * dev ) ); widget.finishTime->setDateTime( t ); //debugPlan<setDateTime( ct ); btnCurrent->setChecked( true ); dateTimeEdit->setEnabled( false ); - connect( btnFrom, SIGNAL(toggled(bool)), dateTimeEdit, SLOT(setEnabled(bool)) ); + connect( btnFrom, &QAbstractButton::toggled, dateTimeEdit, &QWidget::setEnabled ); } ////////////////// ResourceDialog //////////////////////// RecalculateDialog::RecalculateDialog( QWidget *parent ) : KoDialog(parent) { setCaption( i18n("Re-calculate Schedule") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); dia = new RecalculateDialogImpl(this); setMainWidget(dia); } QDateTime RecalculateDialog::dateTime() const { return dia->btnFrom->isChecked() ? dia->dateTimeEdit->dateTime() : QDateTime::currentDateTime(); } } //KPlato namespace diff --git a/src/libs/ui/kptrelationdialog.cpp b/src/libs/ui/kptrelationdialog.cpp index 7562fb30..a6942f69 100644 --- a/src/libs/ui/kptrelationdialog.cpp +++ b/src/libs/ui/kptrelationdialog.cpp @@ -1,195 +1,195 @@ /* This file is part of the KDE project Copyright (C) 2003 - 2010 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 "kptrelationdialog.h" #include "kptrelation.h" #include "kptnode.h" #include "kptproject.h" #include "kptcommand.h" #include namespace KPlato { RelationPanel::RelationPanel(QWidget *parent) : QWidget(parent) { setupUi(this); lagLabel->setText( xi18nc( "@label:spinbox Time lag", "Lag:" ) ); QString tt = xi18nc( "@info:tooltip", "Lag is the time the dependent task is delayed" ); lagLabel->setToolTip( tt ); lag->setToolTip( tt ); } AddRelationDialog::AddRelationDialog(Project &project, Relation *rel, QWidget *p, const QString& caption, ButtonCodes buttons) : KoDialog(p), m_project( project ), m_relation( rel ), m_deleterelation( true ) { setCaption( caption ); setButtons( buttons ); setDefaultButton( Ok ); showButtonSeparator( true ); if ( caption.isEmpty() ) { setCaption( xi18nc( "@title:window", "Add Dependency" ) ); } m_relation = rel; m_panel = new RelationPanel(this); setMainWidget(m_panel); m_panel->activateWindow(); m_panel->fromName->setText(rel->parent()->name()); m_panel->toName->setText(rel->child()->name()); if (rel->type() == Relation::FinishStart) { m_panel->bFinishStart->setChecked(true); } else if (rel->type() == Relation::FinishFinish) { m_panel->bFinishFinish->setChecked(true); } else if (rel->type() == Relation::StartStart) { m_panel->bStartStart->setChecked(true); } m_panel->lag->setUnit( Duration::Unit_h ); m_panel->lag->setValue(rel->lag().toDouble( Duration::Unit_h ) ); //FIXME store user input m_panel->relationType->setFocus(); enableButtonOk(true); //connect(m_panel->relationType, SIGNAL(clicked(int)), SLOT(typeClicked(int))); - connect(m_panel->bFinishStart, SIGNAL(toggled(bool)), SLOT(slotFinishStartToggled(bool))); - connect(m_panel->bFinishFinish, SIGNAL(toggled(bool)), SLOT(slotFinishFinishToggled(bool))); - connect(m_panel->bStartStart, SIGNAL(toggled(bool)), SLOT(slotStartStartToggled(bool))); + connect(m_panel->bFinishStart, &QAbstractButton::toggled, this, &AddRelationDialog::slotFinishStartToggled); + connect(m_panel->bFinishFinish, &QAbstractButton::toggled, this, &AddRelationDialog::slotFinishFinishToggled); + connect(m_panel->bStartStart, &QAbstractButton::toggled, this, &AddRelationDialog::slotStartStartToggled); connect(m_panel->lag, SIGNAL(valueChanged(double)), SLOT(lagChanged())); - connect(&project, SIGNAL(nodeRemoved(KPlato::Node*)), SLOT(slotNodeRemoved(KPlato::Node*))); + connect(&project, &Project::nodeRemoved, this, &AddRelationDialog::slotNodeRemoved); } AddRelationDialog::~AddRelationDialog() { if ( m_deleterelation ) { delete m_relation; //in case of cancel } } void AddRelationDialog::slotNodeRemoved( Node *node ) { if ( m_relation->parent() == node || m_relation->child() == node ) { reject(); } } MacroCommand *AddRelationDialog::buildCommand() { MacroCommand *c = new MacroCommand( kundo2_i18n("Add task dependency") ); c->addCommand( new AddRelationCmd(m_project, m_relation ) ); m_deleterelation = false; // don't delete return c; } void AddRelationDialog::slotOk() { accept(); } void AddRelationDialog::slotFinishStartToggled(bool ch) { //debugPlan<type() != Relation::FinishStart) enableButtonOk(true); } void AddRelationDialog::slotFinishFinishToggled(bool ch) { //debugPlan<type() != Relation::FinishFinish) enableButtonOk(true); } void AddRelationDialog::slotStartStartToggled(bool ch) { //debugPlan<type() != Relation::StartStart) enableButtonOk(true); } void AddRelationDialog::lagChanged() { enableButtonOk(true); } void AddRelationDialog::typeClicked(int id) { if (id != m_relation->type()) enableButtonOk(true); } int AddRelationDialog::selectedRelationType() const { if (m_panel->bStartStart->isChecked()) return Relation::StartStart; else if (m_panel->bFinishFinish->isChecked()) return Relation::FinishFinish; return Relation::FinishStart; } ////////////////// ModifyRelationDialog::ModifyRelationDialog(Project &project, Relation *rel, QWidget *p) : AddRelationDialog(project, rel, p, xi18nc( "@title:window", "Edit Dependency"), Ok|Cancel|User1) { m_deleterelation = false; setButtonText( KoDialog::User1, xi18nc( "@action:button", "Delete") ); m_deleted = false; enableButtonOk(false); - connect(this, SIGNAL(user1Clicked()), SLOT(slotUser1())); + connect(this, &KoDialog::user1Clicked, this, &ModifyRelationDialog::slotUser1); - connect(&project, SIGNAL(relationRemoved(KPlato::Relation*)), SLOT(slotRelationRemoved(KPlato::Relation*))); + connect(&project, &Project::relationRemoved, this, &ModifyRelationDialog::slotRelationRemoved); } void ModifyRelationDialog::slotRelationRemoved( Relation *relation ) { if ( m_relation == relation ) { reject(); } } // Delete void ModifyRelationDialog::slotUser1() { m_deleted = true; accept(); } MacroCommand *ModifyRelationDialog::buildCommand() { MacroCommand *cmd=0; if ( m_deleted ) { cmd = new MacroCommand( kundo2_i18n( "Delete task dependency" ) ); cmd ->addCommand( new DeleteRelationCmd( m_project, m_relation ) ); return cmd; } KUndo2MagicString s = kundo2_i18n( "Modify task dependency" ); if (selectedRelationType() != m_relation->type()) { if (cmd == 0) cmd = new MacroCommand( s ); cmd->addCommand(new ModifyRelationTypeCmd(m_relation, (Relation::Type)(selectedRelationType()))); //debugPlan<relationType->selectedId(); } Duration d(m_panel->lag->value(), m_panel->lag->unit()); if (m_relation->lag() != d) { if (cmd == 0) cmd = new MacroCommand( s ); cmd->addCommand(new ModifyRelationLagCmd(m_relation, d)); } return cmd; } } //KPlato namespace diff --git a/src/libs/ui/kptrelationeditor.cpp b/src/libs/ui/kptrelationeditor.cpp index 3a89f78c..dff04397 100644 --- a/src/libs/ui/kptrelationeditor.cpp +++ b/src/libs/ui/kptrelationeditor.cpp @@ -1,224 +1,224 @@ /* This file is part of the KDE project Copyright (C) 2007 - 2010, 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. */ #include "kptrelationeditor.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptproject.h" #include "kptitemviewsettup.h" #include "kptdebug.h" #include #include #include #include #include #include #include namespace KPlato { //-------------------- RelationTreeView::RelationTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { setViewSplitMode( false ); RelationItemModel *m = new RelationItemModel( this ); setModel( m ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); setArrowKeyNavigation( true ); setRootIsDecorated ( false ); createItemDelegates( m ); //HACK to simulate SingleSelection *and* get indication of current item - connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &RelationTreeView::slotCurrentChanged ); } void RelationTreeView::slotCurrentChanged(const QModelIndex &curr, const QModelIndex& ) { selectionModel()->select( curr, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); } //----------------------------------- RelationEditor::RelationEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { debugPlan<<"----------------- Create RelationEditor ----------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new RelationTreeView( this ); l->addWidget( m_view ); //debugPlan<actionSplitView(); setupGui(); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &RelationEditor::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &RelationEditor::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &RelationEditor::slotContextMenuRequested ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); - connect(model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*))); + connect(model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand); } void RelationEditor::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); } void RelationEditor::draw( Project &project ) { m_view->setProject( &project ); } void RelationEditor::draw() { } void RelationEditor::setGuiActive( bool /*activate */) { } void RelationEditor::slotCurrentChanged( const QModelIndex &/*curr*/, const QModelIndex & ) { //debugPlan<currentRelation(); } void RelationEditor::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { Relation *rel = m_view->model()->relation( index ); if ( rel == 0 ) { slotHeaderContextMenuRequested( pos ); return; } QString name = "relation_popup"; emit requestPopupMenu( name, pos ); } void RelationEditor::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlan; QList lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } void RelationEditor::slotEnableActions() { updateActionsEnabled( true ); } void RelationEditor::updateActionsEnabled( bool /*on */) { } void RelationEditor::setupGui() { // Add the context menu actions for the view options - connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &RelationEditor::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig); } void RelationEditor::slotSplitView() { //debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); } void RelationEditor::slotOptions() { debugPlan; bool col0 = false; TreeViewBase *v = m_view->slaveView(); if ( v->isHidden() ) { v = m_view->masterView(); col0 = true; } ItemViewSettupDialog *dlg = new ItemViewSettupDialog( this, v, col0, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void RelationEditor::slotAddRelation() { debugPlan; } void RelationEditor::edit( const QModelIndex &i ) { if ( i.isValid() ) { // QModelIndex p = m_view->model()->parent( i ); // m_view->setExpanded( p ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); } } void RelationEditor::slotDeleteRelation( Relation *r) { emit deleteRelation( r ); } bool RelationEditor::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); return m_view->loadContext( m_view->model()->columnMap(), context ); } void RelationEditor::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); m_view->saveContext( m_view->model()->columnMap(), context ); } KoPrintJob *RelationEditor::createPrintJob() { return m_view->createPrintJob( this ); } } // namespace KPlato diff --git a/src/libs/ui/kptrequestresourcespanel.cpp b/src/libs/ui/kptrequestresourcespanel.cpp index 38631462..088c5230 100644 --- a/src/libs/ui/kptrequestresourcespanel.cpp +++ b/src/libs/ui/kptrequestresourcespanel.cpp @@ -1,177 +1,177 @@ /* This file is part of the KDE project Copyright (C) 2003 - 2009 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 "kptrequestresourcespanel.h" #include "kpttask.h" #include "kptproject.h" #include "kptresource.h" #include "kptcalendar.h" #include "kptresourceallocationeditor.h" #include #include #include namespace KPlato { RequestResourcesPanel::RequestResourcesPanel(QWidget *parent, Project &project, Task &task, bool) : QWidget(parent) { QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin(0); m_view = new ResourceAllocationTreeView( this ); m_view->setViewSplitMode( false ); m_view->masterView()->header()->moveSection( ResourceAllocationModel::RequestType, m_view->masterView()->header()->count() - 1 ); m_view->setReadWrite( true ); l->addWidget( m_view ); m_view->setProject( &project ); m_view->setTask( &task ); m_view->slotExpand(); m_view->masterView()->header()->resizeSections( QHeaderView::ResizeToContents ); - connect( m_view, SIGNAL(dataChanged()), SIGNAL(changed()) ); + connect( m_view, &ResourceAllocationTreeView::dataChanged, this, &RequestResourcesPanel::changed ); } bool RequestResourcesPanel::ok() { return true; } MacroCommand *RequestResourcesPanel::buildCommand() { Task *task = m_view->task(); if ( task == 0 ) { return 0; } MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Modify resource allocations" ) ); const QHash &rmap = m_view->resourceCache(); // First remove all that should be removed for( QHash::const_iterator rit = rmap.constBegin(); rit != rmap.constEnd(); ++rit ) { if ( rit.value()->units() == 0 ) { ResourceRequest *rr = task->requests().find( rit.key() ); if ( rr ) { cmd->addCommand( new RemoveResourceRequestCmd( rr->parent(), rr ) ); } } } QHash groups; // Add/modify const QHash &gmap = m_view->groupCache(); for( QHash::const_iterator git = gmap.constBegin(); git != gmap.constEnd(); ++git ) { ResourceGroupRequest *gr = task->requests().find( git.key() ); if ( gr == 0 ) { if ( git.value()->units() > 0 ) { gr = new ResourceGroupRequest( const_cast( git.key() ), git.value()->units() ); cmd->addCommand( new AddResourceGroupRequestCmd( *task, gr ) ); groups[ git.key() ] = gr; } // else nothing } else { cmd->addCommand( new ModifyResourceGroupRequestUnitsCmd( gr, gr->units(), git.value()->units() ) ); } } for( QHash::const_iterator rit = rmap.constBegin(); rit != rmap.constEnd(); ++rit ) { Resource *resource = const_cast( rit.key() ); ResourceGroup *group = resource->parentGroup(); if ( rit.value()->units() > 0 ) { ResourceRequest *rr = task->requests().find( resource ); if ( rr == 0 ) { ResourceGroupRequest *gr = task->requests().find( group ); if ( gr == 0 ) { if ( groups.contains( group ) ) { gr = groups[ group ]; } else { gr = new ResourceGroupRequest( group, 0 ); groups[ group ] = gr; cmd->addCommand( new AddResourceGroupRequestCmd( *task, gr ) ); } } ResourceRequest *rr = new ResourceRequest( resource, rit.value()->units() ); rr->setRequiredResources( rit.value()->requiredResources() ); cmd->addCommand( new AddResourceRequestCmd( gr, rr ) ); } else { if ( rit.value()->units() != rr->units() ) { cmd->addCommand( new ModifyResourceRequestUnitsCmd( rr, rr->units(), rit.value()->units() ) ); } if ( rit.value()->requiredResources() != rr->requiredResources() ) { cmd->addCommand( new ModifyResourceRequestRequiredCmd( rr, rit.value()->requiredResources() ) ); } } } } if ( cmd->isEmpty() ) { delete cmd; cmd = 0; } return cmd; } MacroCommand *RequestResourcesPanel::buildCommand(Task *task) { if ( task == 0 ) { return 0; } MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Modify resource allocations" ) ); const QHash &rmap = m_view->resourceCache(); // First remove all foreach(ResourceGroupRequest *g, task->requests().requests()) { cmd->addCommand(new RemoveResourceGroupRequestCmd(g)); } QHash groups; // Add possible requests to groups const QHash &gmap = m_view->groupCache(); for( QHash::const_iterator git = gmap.constBegin(); git != gmap.constEnd(); ++git ) { if (git.value()->units() > 0) { ResourceGroupRequest *gr = new ResourceGroupRequest(const_cast(git.key() ), git.value()->units()); cmd->addCommand(new AddResourceGroupRequestCmd(*task, gr)); groups[git.key()] = gr; } } // Add possible requests to resources for( QHash::const_iterator rit = rmap.constBegin(); rit != rmap.constEnd(); ++rit ) { Resource *resource = const_cast(rit.key()); ResourceGroup *group = resource->parentGroup(); if ( rit.value()->units() > 0 ) { ResourceGroupRequest *gr = groups.value(group); // Check if there is already a request to the group if (gr == 0) { gr = new ResourceGroupRequest(group, 0); cmd->addCommand(new AddResourceGroupRequestCmd(*task, gr)); groups[group] = gr; } ResourceRequest *rr = new ResourceRequest(resource, rit.value()->units()); rr->setRequiredResources(rit.value()->requiredResources()); cmd->addCommand( new AddResourceRequestCmd(gr, rr)); } } if (cmd->isEmpty()) { delete cmd; cmd = 0; } return cmd; } } //KPlato namespace diff --git a/src/libs/ui/kptresourceallocationeditor.cpp b/src/libs/ui/kptresourceallocationeditor.cpp index dd4f4db5..235f306c 100644 --- a/src/libs/ui/kptresourceallocationeditor.cpp +++ b/src/libs/ui/kptresourceallocationeditor.cpp @@ -1,218 +1,218 @@ /* This file is part of the KDE project Copyright (C) 2009, 2010, 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. */ #include "kptresourceallocationeditor.h" #include "kptresourcemodel.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptitemviewsettup.h" #include "kptdebug.h" #include #include #include #include namespace KPlato { ResourceAllocationTreeView::ResourceAllocationTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { // header()->setContextMenuPolicy( Qt::CustomContextMenu ); ResourceAllocationItemModel *m = new ResourceAllocationItemModel( this ); setModel( m ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); createItemDelegates( m ); - connect( m, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SIGNAL(dataChanged()) ); + connect( m, &QAbstractItemModel::dataChanged, this, &ResourceAllocationTreeView::dataChanged ); } QObject *ResourceAllocationTreeView::currentObject() const { return model()->object( selectionModel()->currentIndex() ); } //----------------------------------- ResourceAllocationEditor::ResourceAllocationEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new ResourceAllocationTreeView( this ); l->addWidget( m_view ); setupGui(); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); QList lst1; lst1 << 1 << -1; QList lst2; lst2 << 0; m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << 0 ); QList show; for ( int c = 1; c < model()->columnCount(); ++c ) { show << c; } m_view->slaveView()->setDefaultColumns( show ); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &ResourceAllocationEditor::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &ResourceAllocationEditor::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &ResourceAllocationEditor::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); } void ResourceAllocationEditor::updateReadWrite( bool readwrite ) { m_view->setReadWrite( readwrite ); } void ResourceAllocationEditor::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void ResourceAllocationEditor::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { //debugPlan<model()->object( index ); ResourceGroup *g = qobject_cast( obj ); if ( g ) { //name = "resourceeditor_group_popup"; } else { Resource *r = qobject_cast( obj ); if ( r ) { //name = "resourceeditor_resource_popup"; } } } if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); return; } emit requestPopupMenu( name, pos ); } Resource *ResourceAllocationEditor::currentResource() const { return qobject_cast( m_view->currentObject() ); } ResourceGroup *ResourceAllocationEditor::currentResourceGroup() const { return qobject_cast( m_view->currentObject() ); } void ResourceAllocationEditor::slotCurrentChanged( const QModelIndex & ) { //debugPlan<actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &ResourceAllocationEditor::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionAll); } void ResourceAllocationEditor::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void ResourceAllocationEditor::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool ResourceAllocationEditor::loadContext( const KoXmlElement &context ) { debugPlan<loadContext( model()->columnMap(), context ); } void ResourceAllocationEditor::saveContext( QDomElement &context ) const { debugPlan<saveContext( model()->columnMap(), context ); } KoPrintJob *ResourceAllocationEditor::createPrintJob() { return m_view->createPrintJob( this ); } } // namespace KPlato diff --git a/src/libs/ui/kptresourceappointmentsview.cpp b/src/libs/ui/kptresourceappointmentsview.cpp index 203396b6..a6160a37 100644 --- a/src/libs/ui/kptresourceappointmentsview.cpp +++ b/src/libs/ui/kptresourceappointmentsview.cpp @@ -1,428 +1,428 @@ /* This file is part of the KDE project Copyright (C) 2005 - 2010, 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. */ #include "kptresourceappointmentsview.h" #include "kptappointment.h" #include "kptcommand.h" #include "kpteffortcostmap.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptitemviewsettup.h" #include "kptviewbase.h" #include "Help.h" #include "kptdebug.h" #include "KoPageLayoutWidget.h" #include #include #include #include #include #include namespace KPlato { //-------------------- ResourceAppointmentsDisplayOptionsPanel::ResourceAppointmentsDisplayOptionsPanel( ResourceAppointmentsItemModel *model, QWidget *parent ) : QWidget( parent ), m_model( model ) { setupUi( this ); setValues( *model ); - connect( ui_internalAppointments, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( ui_externalAppointments, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); + connect( ui_internalAppointments, &QCheckBox::stateChanged, this, &ResourceAppointmentsDisplayOptionsPanel::changed ); + connect( ui_externalAppointments, &QCheckBox::stateChanged, this, &ResourceAppointmentsDisplayOptionsPanel::changed ); } void ResourceAppointmentsDisplayOptionsPanel::slotOk() { m_model->setShowInternalAppointments( ui_internalAppointments->checkState() == Qt::Checked ); m_model->setShowExternalAppointments( ui_externalAppointments->checkState() == Qt::Checked ); } void ResourceAppointmentsDisplayOptionsPanel::setValues( const ResourceAppointmentsItemModel &m ) { ui_internalAppointments->setCheckState( m.showInternalAppointments() ? Qt::Checked : Qt::Unchecked ); ui_externalAppointments->setCheckState( m.showExternalAppointments() ? Qt::Checked : Qt::Unchecked ); } void ResourceAppointmentsDisplayOptionsPanel::setDefault() { ResourceAppointmentsItemModel m; setValues( m ); } //---- ResourceAppointmentsSettingsDialog::ResourceAppointmentsSettingsDialog( ViewBase *view, ResourceAppointmentsItemModel *model, QWidget *parent, bool selectPrint ) : KPageDialog( parent ), m_view( view ) { ResourceAppointmentsDisplayOptionsPanel *panel = new ResourceAppointmentsDisplayOptionsPanel( model ); KPageWidgetItem *page = addPage( panel, i18n( "General" ) ); page->setHeader( i18n( "Resource Assignments View 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() ); page = addPage( tab, i18n( "Printing" ) ); page->setHeader( i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } - connect( this, SIGNAL(accepted()), this, SLOT(slotOk())); - connect( this, SIGNAL(accepted()), panel, SLOT(slotOk())); + connect( this, &QDialog::accepted, this, &ResourceAppointmentsSettingsDialog::slotOk); + connect( this, &QDialog::accepted, panel, &ResourceAppointmentsDisplayOptionsPanel::slotOk); //TODO: there was no default button configured, should there? // connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(setDefault())); } void ResourceAppointmentsSettingsDialog::slotOk() { m_view->setPageLayout( m_pagelayout->pageLayout() ); m_view->setPrintingOptions( m_headerfooter->options() ); } //--------------------------------------- ResourceAppointmentsTreeView::ResourceAppointmentsTreeView( QWidget *parent ) : DoubleTreeViewBase( true, parent ) { // header()->setContextMenuPolicy( Qt::CustomContextMenu ); m_rightview->setStretchLastSection( false ); ResourceAppointmentsItemModel *m = new ResourceAppointmentsItemModel( this ); setModel( m ); setSelectionMode( QAbstractItemView::ExtendedSelection ); QList lst1; lst1 << 2 << -1; QList lst2; lst2 << 0 << 1; hideColumns( lst1, lst2 ); m_leftview->resizeColumnToContents ( 1 ); - connect( m, SIGNAL(modelReset()), SLOT(slotRefreshed()) ); + connect( m, &QAbstractItemModel::modelReset, this, &ResourceAppointmentsTreeView::slotRefreshed ); m_rightview->setObjectName( "ResourceAppointments" ); } bool ResourceAppointmentsTreeView::loadContext( const KoXmlElement &context ) { debugPlan; KoXmlElement e = context.namedItem( "common" ).toElement(); if ( ! e.isNull() ) { model()->setShowInternalAppointments( (bool)( e.attribute( "show-internal-appointments", "0" ).toInt() ) ); model()->setShowExternalAppointments( (bool)( e.attribute( "show-external-appointments", "0" ).toInt() ) ); } DoubleTreeViewBase::loadContext(QMetaEnum(), context); return true; } void ResourceAppointmentsTreeView::saveContext( QDomElement &settings ) const { debugPlan; QDomElement e = settings.ownerDocument().createElement( "common" ); settings.appendChild( e ); e.setAttribute( "show-internal-appointments", QString::number(model()->showInternalAppointments()) ); e.setAttribute( "show-external-appointments", QString::number(model()->showExternalAppointments()) ); DoubleTreeViewBase::saveContext(QMetaEnum(), settings); } void ResourceAppointmentsTreeView::slotRefreshed() { //debugPlan<columnCount()<<", "<header()->count()<<", "<header()->count()<<", "<header()->hiddenSectionCount()<<", "<header()->hiddenSectionCount(); ResourceAppointmentsItemModel *m = model(); setModel( 0 ); setModel( m ); setSelectionMode( QAbstractItemView::ExtendedSelection ); QList lst1; lst1 << 2 << -1; QList lst2; lst2 << 0 << 1; hideColumns( lst1, lst2 ); } QModelIndex ResourceAppointmentsTreeView::currentIndex() const { return selectionModel()->currentIndex(); } //----------------------------------- ResourceAppointmentsView::ResourceAppointmentsView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { debugPlan<<"------------------- ResourceAppointmentsView -----------------------"; setupGui(); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new ResourceAppointmentsTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); l->addWidget( m_view ); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &ResourceAppointmentsView::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &ResourceAppointmentsView::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &ResourceAppointmentsView::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Resource Assignments View" "" "Displays the scheduled resource - task assignments." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Resource_Assignment_Gantt_View"))); } void ResourceAppointmentsView::draw( Project &project ) { setProject( &project ); } void ResourceAppointmentsView::setProject( Project *project ) { m_view->setProject( project ); } void ResourceAppointmentsView::setScheduleManager( ScheduleManager *sm ) { if (!sm && scheduleManager()) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_view->masterView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); bool expand = sm && scheduleManager() && sm != scheduleManager(); QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_view->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } void ResourceAppointmentsView::draw() { } void ResourceAppointmentsView::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void ResourceAppointmentsView::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { debugPlan<model()->node( index ); if ( n ) { name = "taskview_popup"; } } m_view->setContextMenuIndex(index); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } Node *ResourceAppointmentsView::currentNode() const { return m_view->model()->node( m_view->currentIndex() ); } Resource *ResourceAppointmentsView::currentResource() const { //return qobject_cast( m_view->currentObject() ); return 0; } ResourceGroup *ResourceAppointmentsView::currentResourceGroup() const { //return qobject_cast( m_view->currentObject() ); return 0; } void ResourceAppointmentsView::slotCurrentChanged( const QModelIndex & ) { //debugPlan<project(); QList groupList = m_view->selectedGroups(); bool nogroup = groupList.isEmpty(); bool group = groupList.count() == 1; QList resourceList = m_view->selectedResources(); bool noresource = resourceList.isEmpty(); bool resource = resourceList.count() == 1; bool any = !nogroup || !noresource; actionAddResource->setEnabled( o && ( (group && noresource) || (resource && nogroup) ) ); actionAddGroup->setEnabled( o ); actionDeleteSelection->setEnabled( o && any );*/ } void ResourceAppointmentsView::setupGui() { // Add the context menu actions for the view options createOptionActions(ViewBase::OptionAll); } void ResourceAppointmentsView::slotOptions() { debugPlan; ResourceAppointmentsSettingsDialog *dlg = new ResourceAppointmentsSettingsDialog( this, m_view->model(), this, sender()->objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void ResourceAppointmentsView::slotAddResource() { //debugPlan; /* QList gl = m_view->selectedGroups(); if ( gl.count() > 1 ) { return; } ResourceGroup *g = 0; if ( !gl.isEmpty() ) { g = gl.first(); } else { QList rl = m_view->selectedResources(); if ( rl.count() != 1 ) { return; } g = rl.first()->parentGroup(); } if ( g == 0 ) { return; } Resource *r = new Resource(); QModelIndex i = m_view->model()->insertResource( g, r ); if ( i.isValid() ) { m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); } */ } void ResourceAppointmentsView::slotAddGroup() { //debugPlan; /* ResourceGroup *g = new ResourceGroup(); QModelIndex i = m_view->model()->insertGroup( g ); if ( i.isValid() ) { m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); }*/ } void ResourceAppointmentsView::slotDeleteSelection() { /* QObjectList lst = m_view->selectedObjects(); //debugPlan<loadContext( context ); } void ResourceAppointmentsView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); m_view->saveContext( context ); } KoPrintJob *ResourceAppointmentsView::createPrintJob() { return m_view->createPrintJob( this ); } } // namespace KPlato diff --git a/src/libs/ui/kptresourceassignmentview.cpp b/src/libs/ui/kptresourceassignmentview.cpp index bda5c235..c64a778f 100644 --- a/src/libs/ui/kptresourceassignmentview.cpp +++ b/src/libs/ui/kptresourceassignmentview.cpp @@ -1,410 +1,410 @@ /* This file is part of the KDE project Copyright (C) 2006 - 2007 Frederic BECQUIER 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; 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 "kptresourceassignmentview.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptrelation.h" #include "kptdebug.h" #include #include #include #include #include namespace KPlato { ResourcesList::ResourcesList( QWidget * parent ) : QTreeWidget( parent ) { setContextMenuPolicy( Qt::CustomContextMenu ); //connect( this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(slotContextMenuRequested(QPoint)) ); } void ResourceAssignmentView::slotRequestPopupMenu( const QPoint &p ) { debugPlan << p; emit requestPopupMenu( "resourceassigment_popup", QCursor::pos() ); } void ResourceAssignmentView::draw( Project &project ) { m_project = &project; m_resList->clear(); foreach ( ResourceGroup * gr, project.resourceGroups() ) { QTreeWidgetItem * item = new QTreeWidgetItem( m_resList ); item->setText( 0, gr->name() ); drawResourcesName( item, gr ); debugPlan <<"GROUP FOUND"; } } /*This function is called for the left panel*/ void ResourceAssignmentView::drawResourcesName( QTreeWidgetItem *parent, ResourceGroup *group ) { /*for each resource*/ foreach ( Resource * res, group->resources() ) { QTreeWidgetItem * item = new QTreeWidgetItem( parent ); /*Determine the name and the type of the resource*/ switch ( res->type() ) { case Resource::Type_Work: item->setText( 0, res->name() ); item->setText( 1, i18n( "Work" ) ); break; case Resource::Type_Material: item->setText( 0, res->name() ); item->setText( 1, i18n( "Material" ) ); break; default: break; } } } /*Constructor*/ ResourceAssignmentView::ResourceAssignmentView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent), m_project( 0 ) { debugPlan <<" ---------------- KPlato: Creating ResourceAssignmentView ----------------"; widget.setupUi(this); /* QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); m_splitter = new QSplitter( this ); l->addWidget( m_splitter ); m_splitter->setOrientation( Qt::Horizontal ); m_resList = new ResourcesList( m_splitter ); QStringList sl; sl << i18n( "Name" ) << i18n( "Type" ); m_resList->setHeaderLabels( sl ); m_taskList = new ResourcesList( m_splitter ); m_tasktreeroot = new QTreeWidgetItem ( m_taskList ); QStringList sl2; sl2 << i18n( "Task" ); << i18n( "Completed" ); m_taskList->setHeaderLabels( sl2 );*/ /* m_resList = widget.assign( m_resList ); m_taskList = widget.assign( m_taskList ); m_tasktreeroot = widget.assign( m_tasktreeroot );*/ m_selectedItem = 0; m_splitter = widget.m_splitter; m_resList = (ResourcesList *)widget.m_resList; m_taskList = (ResourcesList *)widget.m_taskList; m_part = doc; m_tasktreeroot = new QTreeWidgetItem ( m_taskList ); connect( m_resList, SIGNAL(itemSelectionChanged()), SLOT(resSelectionChanged()) ); - connect( m_taskList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotRequestPopupMenu(QPoint)) ); + connect( m_taskList, &QWidget::customContextMenuRequested, this, &ResourceAssignmentView::slotRequestPopupMenu ); } /*Store the selected item*/ void ResourceAssignmentView::resSelectionChanged() { QTreeWidgetItem * item = 0; QList selList = m_resList->selectedItems(); if ( !selList.isEmpty() ) item = selList.first(); resSelectionChanged( item ); } /*Update tasks attributed to the selected item*/ void ResourceAssignmentView::resSelectionChanged( QTreeWidgetItem *item ) { QTreeWidgetItem * resItem = item; if ( resItem ) { m_selectedItem = resItem; updateTasks(); return ; } m_selectedItem = 0; // updateTasks(); that method uses m_selectedItem, so this will always crash... CID 3206 } /**/ void ResourceAssignmentView::updateTasks() { Q_ASSERT(m_selectedItem); /*Find Selected Item*/ Resource* ItemRes = 0; ResourceGroup* ItemGrp = 0; QString name = m_selectedItem->text(0); QString type = m_selectedItem->text(1); if(!type.isEmpty()){ debugPlan <<"Item Selected:" << name <<" / Type:" << type; } else{ debugPlan <<"Group Selected:" << name; } m_taskList->clear(); if ( m_project == 0 ) { return; } /*Find tasks attributed to the selected item*/ /*The selected item is a resource*/ if(!type.isEmpty()) { foreach ( ResourceGroup * gr, m_project->resourceGroups() ) { foreach ( Resource * res, gr->resources() ) { if (name == res->name()) { ItemRes = res; debugPlan <<"Selected Resource found"; } else { debugPlan <<"Not found"; } } } drawTasksAttributedToAResource(ItemRes,m_tasktreeroot); } else /*The selected item is a group*/ { foreach ( ResourceGroup * gr, m_project->resourceGroups() ) { if (name == gr->name()) { ItemGrp = gr; debugPlan <<"[void KPlato::ResourceAssignmentView::updateTasks()] Selected Group founded"; } else { debugPlan <<"[void KPlato::ResourceAssignmentView::updateTasks()] Group Not founded"; } } drawTasksAttributedToAGroup(ItemGrp,m_tasktreeroot); } } void ResourceAssignmentView::drawTasksAttributedToAResource (Resource *res, QTreeWidgetItem */*parent*/) { QString taskName; Task *currentTask; /*Differents state regrouping tasks*/ QTreeWidgetItem *notStarted; QTreeWidgetItem *started; QTreeWidgetItem *finished; QString advance ; /*Task node*/ QTreeWidgetItem * item; /*Put the name of the resource on the node*/ /*Case: the resource has no task attributed*/ if((res->requests()).isEmpty()) { QTreeWidgetItem * item = new QTreeWidgetItem( m_taskList ); item->setText( 0, i18n( "No task attributed" ) ); } else /*Case: the resource has tasks attributed*/ { /*Creation of 3 categories of task*/ notStarted = new QTreeWidgetItem( m_taskList ); started = new QTreeWidgetItem( m_taskList ); finished = new QTreeWidgetItem( m_taskList ); /*Set names of categories*/ notStarted->setText( 0, i18n( "Not Started" ) ); started->setText( 0, i18n( "Started" ) ); finished->setText( 0, i18n( "Finished" ) ); /*For each task attributed to the current resource*/ foreach ( ResourceRequest * rr , res->requests() ){ /*get name*/ currentTask = (rr->parent())->task(); taskName = currentTask->name(); /*get status*/ /*State: started*/ if ((((rr->parent())->task())->completion().isStarted()) && !(((rr->parent())->task())->completion().isFinished())) { debugPlan <<"[void KPlato::ResourceAssignmentView::drawTasksAttributedToAResource()] task started"; /*adding to the tree*/ item = new QTreeWidgetItem( started ); item->setText( 0, taskName ); /*Determine the task's advance*/ int percent = ((rr->parent())->task())->completion().percentFinished(); //debugPlan <<"[void KPlato::ResourceAssignmentView::drawTasksAttributedToAResource()]" << percent <<""; advance.setNum(percent); advance += '%'; item->setText( 1, advance ); } /*State: Finished*/ else if (((rr->parent())->task())->completion().isFinished()) { /*adding to the tree*/ debugPlan <<"[void KPlato::ResourceAssignmentView::drawTasksAttributedToAResource()] task finished"; item = new QTreeWidgetItem( finished ); item->setText( 0, taskName ); } /*State not started*/ else { /*adding to the tree*/ debugPlan <<"[void KPlato::ResourceAssignmentView::drawTasksAttributedToAResource()] task not started"; item = new QTreeWidgetItem( notStarted ); item->setText( 0, taskName ); } } } } void ResourceAssignmentView::drawTasksAttributedToAGroup (ResourceGroup *group, QTreeWidgetItem *parent) { QString taskName; Task *currentTask; bool alreadyStored; /*Task node*/ QTreeWidgetItem * item; /*Differents state regrouping tasks*/ QTreeWidgetItem *notStarted; QTreeWidgetItem *started; QTreeWidgetItem *finished; QString advance ; if((group->resources()).isEmpty()) { QTreeWidgetItem * groupnode = new QTreeWidgetItem( parent ); groupnode->setText( 0, i18n( "No resource attributed" ) ); } else { /*Creation of 3 categories of task*/ notStarted = new QTreeWidgetItem( m_taskList ); started = new QTreeWidgetItem( m_taskList ); finished = new QTreeWidgetItem( m_taskList ); /*Set names of categories*/ notStarted->setText( 0, i18n( "Not Started" ) ); started->setText( 0, i18n( "Started" ) ); finished->setText( 0, i18n( "Finished" ) ); foreach ( Resource * res, group->resources() ) { foreach ( ResourceRequest * rr , res->requests() ) { /*get name*/ currentTask = (rr->parent())->task(); taskName = currentTask->name(); alreadyStored = false; /*store tasks in the tree*/ if ((((rr->parent())->task())->completion().isStarted()) && !(((rr->parent())->task())->completion().isFinished())) { for (int i = 0; i < started->childCount();i++) { if (started->child(i)->text(0) == taskName) { alreadyStored = true ;} } if ( !alreadyStored ) { item = new QTreeWidgetItem( started ); item->setText( 0, taskName ); /*Determine the task's advance*/ int percent = ((rr->parent())->task())->completion().percentFinished(); advance.setNum(percent); advance += '%'; item->setText( 1, advance ); } } else if (((rr->parent())->task())->completion().isFinished()) { for (int i = 0; i < finished->childCount();i++) { if (finished->child(i)->text(0) == taskName) { alreadyStored = true ;} } if ( !alreadyStored ) { item = new QTreeWidgetItem( finished ); item->setText( 0, taskName ); } } else { for (int i = 0; i < notStarted->childCount();i++) { if (notStarted->child(i)->text(0) == taskName) { alreadyStored = true ;} } if ( !alreadyStored ) { item = new QTreeWidgetItem( notStarted ); item->setText( 0, taskName ); } } } } } } void ResourceAssignmentView::setGuiActive( bool activate ) { debugPlan< 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 "kptresourcedialog.h" #include "kptlocale.h" #include "kptcommand.h" #include "kptproject.h" #include "kptresource.h" #include "kptcalendar.h" #include "kptresourcemodel.h" #include "kptdebug.h" #include #include #include #include #ifdef PLAN_KDEPIMLIBS_FOUND #include #include #include #endif namespace KPlato { ResourceDialogImpl::ResourceDialogImpl( const Project &project, Resource &resource, bool baselined, QWidget *parent ) : QWidget(parent), m_project( project ), m_resource( resource ) { setupUi(this); #ifndef PLAN_KDEPIMLIBS_FOUND chooseBtn->hide(); #endif // FIXME // [Bug 311940] New: Plan crashes when typing a text in the filter textbox before the textbook is fully loaded when selecting a contact from the adressbook chooseBtn->hide(); QSortFilterProxyModel *pr = new QSortFilterProxyModel( ui_teamView ); QStandardItemModel *m = new QStandardItemModel( ui_teamView ); pr->setSourceModel( new QStandardItemModel( ui_teamView ) ); ui_teamView->setModel( m ); m->setHorizontalHeaderLabels( QStringList() << xi18nc( "title:column", "Select team members" ) << xi18nc( "title:column", "Group" ) ); foreach ( Resource *r, m_project.resourceList() ) { if ( r->type() != Resource::Type_Work || r->id() == m_resource.id() ) { continue; } QList items; QStandardItem *item = new QStandardItem( r->name() ); item->setCheckable( true ); item->setCheckState( m_resource.teamMemberIds().contains( r->id() ) ? Qt::Checked : Qt::Unchecked ); items << item; item = new QStandardItem( r->parentGroup()->name() ); items << item; // Add id so we can find the resource item = new QStandardItem( r->id() ); items << item; m->appendRow( items ); } if ( baselined ) { type->setEnabled( false ); rateEdit->setEnabled( false ); overtimeEdit->setEnabled( false ); account->setEnabled( false ); } // hide resource identity (last column) ui_teamView->setColumnHidden( m->columnCount() - 1, true ); ui_teamView->resizeColumnToContents( 0 ); ui_teamView->sortByColumn( 0, Qt::AscendingOrder ); slotTypeChanged( resource.type() ); - connect( m, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(slotTeamChanged(QModelIndex))); + connect( m, &QAbstractItemModel::dataChanged, this, &ResourceDialogImpl::slotTeamChanged); connect(group, SIGNAL(activated(int)), SLOT(slotChanged())); connect(type, SIGNAL(activated(int)), SLOT(slotTypeChanged(int))); connect(units, SIGNAL(valueChanged(int)), SLOT(slotChanged())); - connect(nameEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged())); - connect(initialsEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged())); - connect(emailEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged())); + connect(nameEdit, &QLineEdit::textChanged, this, &ResourceDialogImpl::slotChanged); + connect(initialsEdit, &QLineEdit::textChanged, this, &ResourceDialogImpl::slotChanged); + connect(emailEdit, &QLineEdit::textChanged, this, &ResourceDialogImpl::slotChanged); connect(calendarList, SIGNAL(activated(int)), SLOT(slotChanged())); - connect(rateEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged())); - connect(overtimeEdit, SIGNAL(textChanged(QString)), SLOT(slotChanged())); + connect(rateEdit, &QLineEdit::textChanged, this, &ResourceDialogImpl::slotChanged); + connect(overtimeEdit, &QLineEdit::textChanged, this, &ResourceDialogImpl::slotChanged); - connect(chooseBtn, SIGNAL(clicked()), SLOT(slotChooseResource())); + connect(chooseBtn, &QAbstractButton::clicked, this, &ResourceDialogImpl::slotChooseResource); - connect(availableFrom, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); - connect(availableUntil, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); - connect(availableFrom, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotAvailableFromChanged(QDateTime))); - connect(availableUntil, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotAvailableUntilChanged(QDateTime))); + connect(availableFrom, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotChanged); + connect(availableUntil, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotChanged); + connect(availableFrom, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotAvailableFromChanged); + connect(availableUntil, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotAvailableUntilChanged); - connect(ui_rbfrom, SIGNAL(toggled(bool)), SLOT(slotChanged())); - connect(ui_rbuntil, SIGNAL(toggled(bool)), SLOT(slotChanged())); + connect(ui_rbfrom, &QAbstractButton::toggled, this, &ResourceDialogImpl::slotChanged); + connect(ui_rbuntil, &QAbstractButton::toggled, this, &ResourceDialogImpl::slotChanged); - connect(ui_rbfrom, SIGNAL(toggled(bool)), availableFrom, SLOT(setEnabled(bool))); - connect(ui_rbuntil, SIGNAL(toggled(bool)), availableUntil, SLOT(setEnabled(bool))); + connect(ui_rbfrom, &QAbstractButton::toggled, availableFrom, &QWidget::setEnabled); + connect(ui_rbuntil, &QAbstractButton::toggled, availableUntil, &QWidget::setEnabled); - connect( useRequired, SIGNAL(stateChanged(int)), SLOT(slotUseRequiredChanged(int)) ); + connect( useRequired, &QCheckBox::stateChanged, this, &ResourceDialogImpl::slotUseRequiredChanged ); connect(account, SIGNAL(activated(int)), SLOT(slotChanged())); } void ResourceDialogImpl::slotTeamChanged( const QModelIndex &index ) { if ( ! index.isValid() ) { return; } bool checked = (bool)(index.data( Qt::CheckStateRole ).toInt()); int idCol = index.model()->columnCount() - 1; QString id = index.model()->index( index.row(), idCol ).data().toString(); if ( checked ) { if ( ! m_resource.teamMemberIds().contains( id ) ) { m_resource.addTeamMemberId( id ); } } else { m_resource.removeTeamMemberId( id ); } emit changed(); } void ResourceDialogImpl::slotTypeChanged( int index ) { switch ( index ) { case Resource::Type_Work: ui_stackedWidget->setCurrentIndex( 0 ); useRequired->setEnabled( true ); slotUseRequiredChanged( useRequired->checkState() ); break; case Resource::Type_Material: ui_stackedWidget->setCurrentIndex( 0 ); useRequired->setEnabled( false ); slotUseRequiredChanged( false ); break; case Resource::Type_Team: ui_stackedWidget->setCurrentIndex( 1 ); break; } emit changed(); } void ResourceDialogImpl::slotChanged() { emit changed(); } void ResourceDialogImpl::setCurrentIndexes( const QModelIndexList &lst ) { m_currentIndexes.clear(); foreach ( const QModelIndex &idx, lst ) { m_currentIndexes << QPersistentModelIndex( idx ); } useRequired->setCheckState( m_currentIndexes.isEmpty() ? Qt::Unchecked : Qt::Checked ); if ( useRequired->isChecked() ) { required->setCurrentIndexes( m_currentIndexes ); } required->setEnabled( useRequired->isChecked() ); } void ResourceDialogImpl::slotUseRequiredChanged( int state ) { required->setEnabled( state ); if ( state ) { required->setCurrentIndexes( m_currentIndexes ); } else { m_currentIndexes = required->currentIndexes(); required->setCurrentIndexes( QList() ); } slotChanged(); } void ResourceDialogImpl::slotAvailableFromChanged(const QDateTime&) { if (availableUntil->dateTime() < availableFrom->dateTime()) { - disconnect(availableUntil, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(slotAvailableUntilChanged(QDateTime))); + disconnect(availableUntil, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotAvailableUntilChanged); //debugPlan<<"From:"<dateTime().toString()<<" until="<dateTime().toString(); availableUntil->setDateTime(availableFrom->dateTime()); - connect(availableUntil, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotAvailableUntilChanged(QDateTime))); + connect(availableUntil, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotAvailableUntilChanged); } } void ResourceDialogImpl::slotAvailableUntilChanged(const QDateTime&) { if (availableFrom->dateTime() > availableUntil->dateTime()) { - disconnect(availableFrom, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(slotAvailableFromChanged(QDateTime))); + disconnect(availableFrom, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotAvailableFromChanged); //debugPlan<<"Until:"<dateTime().toString()<<" from="<dateTime().toString(); availableFrom->setDateTime(availableUntil->dateTime()); - connect(availableFrom, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotAvailableFromChanged(QDateTime))); + connect(availableFrom, &QDateTimeEdit::dateTimeChanged, this, &ResourceDialogImpl::slotAvailableFromChanged); } } void ResourceDialogImpl::slotCalculationNeeded(const QString&) { emit calculate(); emit changed(); } void ResourceDialogImpl::slotChooseResource() { #ifdef PLAN_KDEPIMLIBS_FOUND QPointer dlg = new Akonadi::EmailAddressSelectionDialog( this ); if ( dlg->exec() && dlg ) { QStringList s; const Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); if ( ! selections.isEmpty() ) { const Akonadi::EmailAddressSelection s = selections.first(); nameEdit->setText( s.name() ); emailEdit->setText( s.email() ); const QStringList l = s.name().split(' '); QString in; QStringList::ConstIterator it = l.begin(); for (/*int i = 0*/; it != l.end(); ++it) { in += (*it)[0]; } initialsEdit->setText(in); } } #endif } ////////////////// ResourceDialog //////////////////////// ResourceDialog::ResourceDialog(Project &project, Resource *resource, QWidget *parent, const char *name) : KoDialog(parent), m_project( project ), m_original(resource), m_resource(resource), m_calculationNeeded(false) { setObjectName(name); setCaption( i18n("Resource Settings") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); dia = new ResourceDialogImpl(project, m_resource, resource->isBaselined(), this); setMainWidget(dia); KoDialog::enableButtonOk(false); if ( resource->parentGroup() == 0 ) { //HACK to handle calls from ResourcesPanel dia->groupLabel->hide(); dia->group->hide(); } else { foreach ( ResourceGroup *g, project.resourceGroups() ) { m_groups.insert( g->name(), g ); } dia->group->addItems( m_groups.keys() ); dia->group->setCurrentIndex( m_groups.values().indexOf( resource->parentGroup() ) ); // clazy:exclude=container-anti-pattern } dia->nameEdit->setText(resource->name()); dia->initialsEdit->setText(resource->initials()); dia->emailEdit->setText(resource->email()); dia->type->setCurrentIndex((int)resource->type()); // NOTE: must match enum dia->units->setValue(resource->units()); DateTime dt = resource->availableFrom(); if ( dt.isValid() ) { dia->ui_rbfrom->click(); } else { dia->ui_rbfromunlimited->click(); } dia->availableFrom->setDateTime( dt.isValid() ? dt : QDateTime( QDate::currentDate(), QTime( 0, 0, 0 ), Qt::LocalTime ) ); dia->availableFrom->setEnabled( dt.isValid() ); dt = resource->availableUntil(); if ( dt.isValid() ) { dia->ui_rbuntil->click(); } else { dia->ui_rbuntilunlimited->click(); } dia->availableUntil->setDateTime( dt.isValid() ? dt : QDateTime( QDate::currentDate().addYears( 2 ), QTime( 0, 0, 0 ), Qt::LocalTime ) ); dia->availableUntil->setEnabled( dt.isValid() ); dia->rateEdit->setText(project.locale()->formatMoney(resource->normalRate())); dia->overtimeEdit->setText(project.locale()->formatMoney(resource->overtimeRate())); int cal = 0; dia->calendarList->addItem(i18n("None")); m_calendars.insert(0, 0); QList list = project.allCalendars(); int i=1; foreach (Calendar *c, list) { dia->calendarList->insertItem(i, c->name()); m_calendars.insert(i, c); if (c == resource->calendar(true)) { cal = i; } ++i; } dia->calendarList->setCurrentIndex(cal); ResourceItemSFModel *m = new ResourceItemSFModel( this ); m->setProject( &project ); dia->required->setModel( m ); dia->required->view()->expandAll(); QItemSelectionModel *sm = dia->required->view()->selectionModel(); foreach ( Resource *r, resource->requiredResources() ) { sm->select( m->index( r ), QItemSelectionModel::Select | QItemSelectionModel::Rows ); } dia->setCurrentIndexes( sm->selectedRows() ); QStringList lst; lst << i18n( "None" ) << m_project.accounts().costElements(); dia->account->addItems( lst ); if ( resource->account() ) { dia->account->setCurrentIndex( lst.indexOf( resource->account()->name() ) ); } connect(dia, SIGNAL(changed()), SLOT(enableButtonOk())); - connect(dia, SIGNAL(calculate()), SLOT(slotCalculationNeeded())); + connect(dia, &ResourceDialogImpl::calculate, this, &ResourceDialog::slotCalculationNeeded); connect(dia->calendarList, SIGNAL(activated(int)), SLOT(slotCalendarChanged(int))); connect(dia->required, SIGNAL(changed()), SLOT(enableButtonOk())); connect(dia->account, SIGNAL(currentIndexChanged(QString)), SLOT(slotAccountChanged(QString))); - connect(&project, SIGNAL(resourceRemoved(const Resource*)), this, SLOT(slotResourceRemoved(const Resource*))); + connect(&project, &Project::resourceRemoved, this, &ResourceDialog::slotResourceRemoved); } void ResourceDialog::slotResourceRemoved( const Resource *resource ) { if ( m_original == resource ) { reject(); } } void ResourceDialog::enableButtonOk() { KoDialog::enableButtonOk(true); } void ResourceDialog::slotCalculationNeeded() { m_calculationNeeded = true; } void ResourceDialog::slotButtonClicked(int button) { if (button == KoDialog::Ok) { slotOk(); } else { KoDialog::slotButtonClicked(button); } } void ResourceDialog::slotOk() { if ( ! m_groups.isEmpty() ) { //HACK to handle calls from ResourcesPanel m_resource.setParentGroup( m_groups.value( dia->group->currentText() ) ); } m_resource.setName(dia->nameEdit->text()); m_resource.setInitials(dia->initialsEdit->text()); m_resource.setEmail(dia->emailEdit->text()); m_resource.setType((Resource::Type)(dia->type->currentIndex())); m_resource.setUnits(dia->units->value()); m_resource.setNormalRate(m_project.locale()->readMoney(dia->rateEdit->text())); m_resource.setOvertimeRate(m_project.locale()->readMoney(dia->overtimeEdit->text())); m_resource.setCalendar(m_calendars[dia->calendarList->currentIndex()]); m_resource.setAvailableFrom( dia->ui_rbfrom->isChecked() ? dia->availableFrom->dateTime() : QDateTime() ); m_resource.setAvailableUntil( dia->ui_rbuntil->isChecked() ? dia->availableUntil->dateTime() : QDateTime() ); ResourceItemSFModel *m = static_cast( dia->required->model() ); QStringList lst; foreach ( const QModelIndex &i, dia->required->currentIndexes() ) { Resource *r = m->resource( i ); if ( r ) lst << r->id(); } m_resource.setRequiredIds( lst ); accept(); } void ResourceDialog::slotCalendarChanged(int /*cal*/) { } void ResourceDialog::slotAccountChanged( const QString &name ) { m_resource.setAccount( m_project.accounts().findAccount( name ) ); } MacroCommand *ResourceDialog::buildCommand() { return buildCommand(m_original, m_resource); } // static MacroCommand *ResourceDialog::buildCommand(Resource *original, Resource &resource) { MacroCommand *m=0; KUndo2MagicString n = kundo2_i18n("Modify Resource"); if (resource.parentGroup() != 0 && resource.parentGroup() != original->parentGroup()) { if (!m) m = new MacroCommand(n); m->addCommand(new MoveResourceCmd(resource.parentGroup(), original)); } if (resource.name() != original->name()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceNameCmd(original, resource.name())); } if (resource.initials() != original->initials()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceInitialsCmd(original, resource.initials())); } if (resource.email() != original->email()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceEmailCmd(original, resource.email())); } if (resource.type() != original->type()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceTypeCmd(original, resource.type())); } if (resource.units() != original->units()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceUnitsCmd(original, resource.units())); } if (resource.availableFrom() != original->availableFrom()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceAvailableFromCmd(original, resource.availableFrom())); } if (resource.availableUntil() != original->availableUntil()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceAvailableUntilCmd(original, resource.availableUntil())); } if (resource.normalRate() != original->normalRate()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceNormalRateCmd(original, resource.normalRate())); } if (resource.overtimeRate() != original->overtimeRate()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceOvertimeRateCmd(original, resource.overtimeRate())); } if (resource.calendar(true) != original->calendar(true)) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyResourceCalendarCmd(original, resource.calendar(true))); } if (resource.requiredIds() != original->requiredIds()) { if (!m) m = new MacroCommand(n); m->addCommand(new ModifyRequiredResourcesCmd(original, resource.requiredIds())); } if (resource.account() != original->account()) { if (!m) m = new MacroCommand(n); m->addCommand(new ResourceModifyAccountCmd(*original, original->account(), resource.account())); } if ( resource.type() == Resource::Type_Team ) { //debugPlan<teamMembers()<teamMemberIds().contains( id ) ) { if (!m) m = new MacroCommand(n); m->addCommand( new AddResourceTeamCmd( original, id ) ); } } foreach ( const QString &id, original->teamMemberIds() ) { if ( ! resource.teamMemberIds().contains( id ) ) { if (!m) m = new MacroCommand(n); m->addCommand( new RemoveResourceTeamCmd( original, id ) ); } } } return m; } } //KPlato namespace diff --git a/src/libs/ui/kptresourceeditor.cpp b/src/libs/ui/kptresourceeditor.cpp index ebb48e7a..a4cb56dc 100644 --- a/src/libs/ui/kptresourceeditor.cpp +++ b/src/libs/ui/kptresourceeditor.cpp @@ -1,408 +1,408 @@ /* This file is part of the KDE project Copyright (C) 2006 - 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. */ #include "kptresourceeditor.h" #include "kptresourcemodel.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptitemviewsettup.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include namespace KPlato { ResourceTreeView::ResourceTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { // header()->setContextMenuPolicy( Qt::CustomContextMenu ); setStretchLastSection( false ); ResourceItemModel *m = new ResourceItemModel( this ); setModel( m ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); createItemDelegates( m ); - connect( this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), SLOT(slotDropAllowed(QModelIndex,int,QDragMoveEvent*)) ); + connect( this, &DoubleTreeViewBase::dropAllowed, this, &ResourceTreeView::slotDropAllowed ); } void ResourceTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { event->ignore(); if ( model()->dropAllowed( index, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); } } QObject *ResourceTreeView::currentObject() const { return model()->object( selectionModel()->currentIndex() ); } QList ResourceTreeView::selectedObjects() const { QList lst; foreach (const QModelIndex &i, selectionModel()->selectedRows() ) { lst << static_cast( i.internalPointer() ); } return lst; } QList ResourceTreeView::selectedGroups() const { QList gl; foreach ( QObject *o, selectedObjects() ) { ResourceGroup* g = qobject_cast( o ); if ( g ) { gl << g; } } return gl; } QList ResourceTreeView::selectedResources() const { QList rl; foreach ( QObject *o, selectedObjects() ) { Resource* r = qobject_cast( o ); if ( r ) { rl << r; } } return rl; } //----------------------------------- ResourceEditor::ResourceEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { Help::add(this, xi18nc("@info:whatsthis", "Resource Editor" "" "Resources are organized in a Resource Breakdown Structure. " "Resources can be of type Work or Material. " "When assigned to a task, a resource of type Work can affect the duration of the task, while a resource of type Material does not. " "A resource must refer to a Calendar defined in the Work and Vacation Editor." "More..." "", Help::page("Manual/Resource_Editor"))); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new ResourceTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); l->addWidget( m_view ); setupGui(); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::DragDrop ); m_view->setDropIndicatorShown( true ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( true ); // m_view->setAcceptDropsOnView( true ); QList lst1; lst1 << 1 << -1; QList lst2; lst2 << 0; m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << 0 ); QList show; for ( int c = 1; c < model()->columnCount(); ++c ) { show << c; } m_view->slaveView()->setDefaultColumns( show ); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &ResourceEditor::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &ResourceEditor::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &ResourceEditor::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); } void ResourceEditor::updateReadWrite( bool readwrite ) { m_view->setReadWrite( readwrite ); } void ResourceEditor::setProject( Project *project ) { debugPlan<setProject( project ); ViewBase::setProject( project ); } void ResourceEditor::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void ResourceEditor::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { //debugPlan<model()->object( index ); ResourceGroup *g = qobject_cast( obj ); if ( g ) { //name = "resourceeditor_group_popup"; } else { Resource *r = qobject_cast( obj ); if ( r && !r->isShared() ) { name = "resourceeditor_resource_popup"; } } } m_view->setContextMenuIndex(index); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } Resource *ResourceEditor::currentResource() const { return qobject_cast( m_view->currentObject() ); } ResourceGroup *ResourceEditor::currentResourceGroup() const { return qobject_cast( m_view->currentObject() ); } void ResourceEditor::slotCurrentChanged( const QModelIndex & ) { //debugPlan<project(); QList groupList = m_view->selectedGroups(); bool nogroup = groupList.isEmpty(); bool group = groupList.count() == 1; QList resourceList = m_view->selectedResources(); bool noresource = resourceList.isEmpty(); bool resource = resourceList.count() == 1; bool any = !nogroup || !noresource; actionAddResource->setEnabled( o && ( (group && noresource) || (resource && nogroup) ) ); actionAddGroup->setEnabled( o ); if ( o && any ) { foreach ( ResourceGroup *g, groupList ) { if ( g->isBaselined() ) { o = false; break; } } } if ( o && any ) { foreach ( Resource *r, resourceList ) { if ( r->isBaselined() ) { o = false; break; } } } actionDeleteSelection->setEnabled( o && any ); } void ResourceEditor::setupGui() { QString name = "resourceeditor_edit_list"; actionAddGroup = new QAction(koIcon("resource-group-new"), i18n("Add Resource Group"), this); actionCollection()->addAction("add_group", actionAddGroup ); actionCollection()->setDefaultShortcut(actionAddGroup, Qt::CTRL + Qt::Key_I); - connect( actionAddGroup, SIGNAL(triggered(bool)), SLOT(slotAddGroup()) ); + connect( actionAddGroup, &QAction::triggered, this, &ResourceEditor::slotAddGroup ); addAction( name, actionAddGroup ); actionAddResource = new QAction(koIcon("list-add-user"), i18n("Add Resource"), this); actionCollection()->addAction("add_resource", actionAddResource ); actionCollection()->setDefaultShortcut(actionAddResource, Qt::CTRL + Qt::SHIFT + Qt::Key_I); - connect( actionAddResource, SIGNAL(triggered(bool)), SLOT(slotAddResource()) ); + connect( actionAddResource, &QAction::triggered, this, &ResourceEditor::slotAddResource ); addAction( name, actionAddResource ); actionDeleteSelection = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this); actionCollection()->addAction("delete_selection", actionDeleteSelection ); actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete); - connect( actionDeleteSelection, SIGNAL(triggered(bool)), SLOT(slotDeleteSelection()) ); + connect( actionDeleteSelection, &QAction::triggered, this, &ResourceEditor::slotDeleteSelection ); addAction( name, actionDeleteSelection ); // Add the context menu actions for the view options - connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &ResourceEditor::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionAll); } void ResourceEditor::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void ResourceEditor::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void ResourceEditor::slotAddResource() { //debugPlan; QList gl = m_view->selectedGroups(); if ( gl.count() > 1 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); ResourceGroup *g = 0; if ( !gl.isEmpty() ) { g = gl.first(); } else { QList rl = m_view->selectedResources(); if ( rl.count() != 1 ) { return; } g = rl.first()->parentGroup(); } if ( g == 0 ) { return; } Resource *r = new Resource(); if ( g->type() == ResourceGroup::Type_Material ) { r->setType( Resource::Type_Material ); } QModelIndex i = m_view->model()->insertResource( g, r ); if ( i.isValid() ) { m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); } } void ResourceEditor::slotAddGroup() { //debugPlan; m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); ResourceGroup *g = new ResourceGroup(); QModelIndex i = m_view->model()->insertGroup( g ); if ( i.isValid() ) { m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->edit( i ); } } void ResourceEditor::slotDeleteSelection() { QObjectList lst = m_view->selectedObjects(); //debugPlan<selectionModel()->currentIndex(); if ( i.isValid() ) { m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } } bool ResourceEditor::loadContext( const KoXmlElement &context ) { debugPlan<loadContext( model()->columnMap(), context ); } void ResourceEditor::saveContext( QDomElement &context ) const { debugPlan<saveContext( model()->columnMap(), context ); } KoPrintJob *ResourceEditor::createPrintJob() { return m_view->createPrintJob( this ); } } // namespace KPlato diff --git a/src/libs/ui/kptscheduleeditor.cpp b/src/libs/ui/kptscheduleeditor.cpp index 48906a13..773ae873 100644 --- a/src/libs/ui/kptscheduleeditor.cpp +++ b/src/libs/ui/kptscheduleeditor.cpp @@ -1,856 +1,856 @@ /* This file is part of the KDE project Copyright (C) 2006-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. */ #include "kptscheduleeditor.h" #include "kptcommand.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptschedule.h" #include "kptdatetime.h" #include "kptpertresult.h" #include "kptitemviewsettup.h" #include "kptrecalculatedialog.h" #include "Help.h" #include "kptdebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { ScheduleTreeView::ScheduleTreeView( QWidget *parent ) : TreeViewBase( parent ) { header()->setStretchLastSection ( false ); ScheduleItemModel *m = new ScheduleItemModel( this ); setModel( m ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::SingleSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); setTreePosition(-1); // always visual index 0 createItemDelegates( m ); } void ScheduleTreeView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel ) { //debugPlan<selectedIndexes() ) { Q_UNUSED(i); //debugPlan<selectedIndexes() ); } void ScheduleTreeView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) { //debugPlan<select( current, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); } ScheduleManager *ScheduleTreeView::manager( const QModelIndex &idx ) const { return model()->manager( idx ); } ScheduleManager *ScheduleTreeView::currentManager() const { return model()->manager( currentIndex() ); } QModelIndexList ScheduleTreeView::selectedRows() const { QModelIndexList lst = selectionModel()->selectedRows(); debugPlan<manager( lst.first() ); } return sm; } //----------------------------------- ScheduleEditor::ScheduleEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { setupGui(); slotEnableActions(); QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_schedulingRange = new SchedulingRange(doc, this); l->addWidget( m_schedulingRange ); m_view = new ScheduleTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + 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 ); QList show; show << ScheduleModel::ScheduleName << ScheduleModel::ScheduleState << ScheduleModel::ScheduleDirection << ScheduleModel::ScheduleOverbooking << ScheduleModel::ScheduleDistribution << ScheduleModel::SchedulePlannedStart << ScheduleModel::SchedulePlannedFinish << ScheduleModel::ScheduleScheduler << ScheduleModel::ScheduleGranularity ; QList lst; for ( int c = 0; c < model()->columnCount(); ++c ) { if ( ! show.contains( c ) ) { lst << c; } } m_view->setColumnsHidden( lst ); m_view->setDefaultColumns( show ); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + 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( model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateActionsEnabled(QModelIndex)) ); + connect( model(), &QAbstractItemModel::dataChanged, this, &ScheduleEditor::updateActionsEnabled ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &TreeViewBase::contextMenuRequested, this, &ScheduleEditor::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Schedule Editor" "" "The Schedule Editor is used to create, edit, calculate and delete schedules. " "A schedule can have sub-schedules. A sub-schedule can use the projects progress data" " in order to reschedule only tasks that are not yet finished." " Rescheduling will then use e.g. actual start and remaining effort for the tasks." "More..." "", Help::page("Manual/Schedule_Editor"))); } void ScheduleEditor::draw( Project &project ) { m_view->setProject( &project ); m_schedulingRange->setProject(&project); } void ScheduleEditor::draw() { } void ScheduleEditor::setGuiActive( bool activate ) { //debugPlan<currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void ScheduleEditor::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { debugPlan<setContextMenuIndex(index); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); return; } debugPlan<setContextMenuIndex(QModelIndex()); } void ScheduleEditor::slotCurrentChanged( const QModelIndex & ) { //debugPlan<selectedRows(); // gets column 0 in each row (should be 1 or 0 rows) if ( lst.count() == 1 ) { ScheduleManager *sm = m_view->model()->manager( lst.first() ); emit scheduleSelectionChanged( sm ); } else { emit scheduleSelectionChanged( 0 ); } slotEnableActions(); } void ScheduleEditor::updateActionsEnabled( const QModelIndex &index ) { debugPlan<setEnabled( false ); actionAddSubSchedule->setEnabled( false ); actionDeleteSelection->setEnabled( false ); actionCalculateSchedule->setEnabled( false ); actionBaselineSchedule->setEnabled( false ); actionMoveLeft->setEnabled( false ); return; } QModelIndexList lst = m_view->selectedRows(); if ( lst.isEmpty() ) { actionAddSchedule->setEnabled( true ); actionAddSubSchedule->setEnabled( false ); actionDeleteSelection->setEnabled( false ); actionCalculateSchedule->setEnabled( false ); actionBaselineSchedule->setEnabled( false ); actionMoveLeft->setEnabled( false ); return; } if ( lst.count() > 1 ) { actionAddSchedule->setEnabled( false ); actionAddSubSchedule->setEnabled( false ); actionDeleteSelection->setEnabled( false ); actionCalculateSchedule->setEnabled( false ); actionBaselineSchedule->setEnabled( false ); actionMoveLeft->setEnabled( false ); return; } // one and only one manager selected ScheduleManager *sm = m_view->manager( lst.first() ); Q_ASSERT( sm ); actionAddSchedule->setEnabled( true ); actionAddSubSchedule->setEnabled( sm->isScheduled() ); actionDeleteSelection->setEnabled( ! ( sm->isBaselined() || sm->isChildBaselined() ) ); actionCalculateSchedule->setEnabled( ! sm->scheduling() && sm->childCount() == 0 && ! ( sm->isBaselined() || sm->isChildBaselined() ) ); const char *const actionBaselineScheduleIconName = sm->isBaselined() ? koIconNameCStr("view-time-schedule-baselined-remove") : koIconNameCStr("view-time-schedule-baselined-add"); actionBaselineSchedule->setIcon(QIcon::fromTheme(QLatin1String(actionBaselineScheduleIconName))); // enable if scheduled and no one else is baselined bool en = sm->isScheduled() && ( sm->isBaselined() || ! m_view->project()->isBaselined() ); actionBaselineSchedule->setEnabled( en ); actionMoveLeft->setEnabled( sm->parentManager() ); } void ScheduleEditor::setupGui() { QString name = "scheduleeditor_edit_list"; actionAddSchedule = new QAction(koIcon("view-time-schedule-insert"), i18n("Add Schedule"), this); actionCollection()->setDefaultShortcut(actionAddSchedule, Qt::CTRL + Qt::Key_I); actionCollection()->addAction("add_schedule", actionAddSchedule ); - connect( actionAddSchedule, SIGNAL(triggered(bool)), SLOT(slotAddSchedule()) ); + connect( actionAddSchedule, &QAction::triggered, this, &ScheduleEditor::slotAddSchedule ); addAction( name, actionAddSchedule ); actionAddSubSchedule = new QAction(koIcon("view-time-schedule-child-insert"), i18n("Add Sub-schedule"), this); actionCollection()->setDefaultShortcut(actionAddSubSchedule, Qt::CTRL + Qt::SHIFT + Qt::Key_I); actionCollection()->addAction("add_subschedule", actionAddSubSchedule ); - connect( actionAddSubSchedule, SIGNAL(triggered(bool)), SLOT(slotAddSubSchedule()) ); + connect( actionAddSubSchedule, &QAction::triggered, this, &ScheduleEditor::slotAddSubSchedule ); addAction( name, actionAddSubSchedule ); actionDeleteSelection = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this ); actionCollection()->setDefaultShortcut(actionDeleteSelection, Qt::Key_Delete); actionCollection()->addAction("schedule_delete_selection", actionDeleteSelection ); - connect( actionDeleteSelection, SIGNAL(triggered(bool)), SLOT(slotDeleteSelection()) ); + connect( actionDeleteSelection, &QAction::triggered, this, &ScheduleEditor::slotDeleteSelection ); addAction( name, actionDeleteSelection ); actionCalculateSchedule = new QAction(koIcon("view-time-schedule-calculus"), i18n("Calculate"), this); // actionCollection()->setDefaultShortcut(actionCalculateSchedule, Qt::CTRL + Qt::Key_C); actionCollection()->addAction("calculate_schedule", actionCalculateSchedule ); - connect( actionCalculateSchedule, SIGNAL(triggered(bool)), SLOT(slotCalculateSchedule()) ); + connect( actionCalculateSchedule, &QAction::triggered, this, &ScheduleEditor::slotCalculateSchedule ); addAction( name, actionCalculateSchedule ); actionBaselineSchedule = new QAction(koIcon("view-time-schedule-baselined-add"), i18n("Baseline"), this); // actionCollection()->setDefaultShortcut(actionBaselineSchedule, Qt::CTRL + Qt::Key_B); actionCollection()->addAction("schedule_baseline", actionBaselineSchedule ); - connect( actionBaselineSchedule, SIGNAL(triggered(bool)), SLOT(slotBaselineSchedule()) ); + connect( actionBaselineSchedule, &QAction::triggered, this, &ScheduleEditor::slotBaselineSchedule ); addAction( name, actionBaselineSchedule ); actionMoveLeft = new QAction(koIcon("go-first"), xi18nc("@action", "Detach"), this); actionCollection()->addAction("schedule_move_left", actionMoveLeft ); - connect( actionMoveLeft, SIGNAL(triggered(bool)), SLOT(slotMoveLeft()) ); + connect( actionMoveLeft, &QAction::triggered, this, &ScheduleEditor::slotMoveLeft ); addAction( name, actionMoveLeft ); // Add the context menu actions for the view options createOptionActions(ViewBase::OptionExpand | ViewBase::OptionCollapse | ViewBase::OptionViewConfig); } void ScheduleEditor::updateReadWrite( bool readwrite ) { debugPlan<setReadWrite( readwrite ); slotEnableActions(); } void ScheduleEditor::slotOptions() { debugPlan; ItemViewSettupDialog *dlg = new ItemViewSettupDialog( this, m_view, true, this ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void ScheduleEditor::slotCalculateSchedule() { //debugPlan; ScheduleManager *sm = m_view->selectedManager(); if ( sm == 0 ) { return; } if ( sm->parentManager() ) { RecalculateDialog dlg; if ( dlg.exec() == QDialog::Rejected ) { return; } sm->setRecalculate( true ); sm->setRecalculateFrom( DateTime( dlg.dateTime() ) ); } emit calculateSchedule( m_view->project(), sm ); } void ScheduleEditor::slotAddSchedule() { //debugPlan; int idx = -1; ScheduleManager *sm = m_view->selectedManager(); if ( sm ) { idx = sm->parentManager() ? sm->parentManager()->indexOf( sm ) : m_view->project()->indexOf( sm ); if ( idx >= 0 ) { ++idx; } } if ( sm && sm->parentManager() ) { sm = sm->parentManager(); ScheduleManager *m = m_view->project()->createScheduleManager( sm->name() + QString(".%1").arg( sm->children().count() + 1 ) ); part()->addCommand( new AddScheduleManagerCmd( sm, m, idx, kundo2_i18n( "Create sub-schedule" ) ) ); QModelIndex idx = model()->index( m ); if ( idx.isValid() ) { m_view->setFocus(); m_view->scrollTo( idx ); m_view->selectionModel()->select( idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::NoUpdate ); } } else { Project *p = m_view->project(); ScheduleManager *m = p->createScheduleManager(); AddScheduleManagerCmd *cmd = new AddScheduleManagerCmd( *p, m, idx, kundo2_i18n( "Add schedule %1", m->name() ) ); part() ->addCommand( cmd ); QModelIndex idx = model()->index( m ); if ( idx.isValid() ) { m_view->setFocus(); m_view->scrollTo( idx ); m_view->selectionModel()->select( idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::NoUpdate ); } } } void ScheduleEditor::slotAddSubSchedule() { //debugPlan; ScheduleManager *sm = m_view->selectedManager(); if ( sm ) { int row = sm->parentManager() ? sm->parentManager()->indexOf( sm ) : m_view->project()->indexOf( sm ); if ( row >= 0 ) { ++row; } ScheduleManager *m = m_view->project()->createScheduleManager( sm->name() + QString(".%1").arg( sm->children().count() + 1 ) ); part()->addCommand( new AddScheduleManagerCmd( sm, m, row, kundo2_i18n( "Create sub-schedule" ) ) ); m_view->expand( model()->index( sm ) ); QModelIndex idx = model()->index( m ); if ( idx.isValid() ) { m_view->selectionModel()->select( idx, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::NoUpdate ); } } else { slotAddSchedule(); } } void ScheduleEditor::slotBaselineSchedule() { //debugPlan; ScheduleManager *sm = m_view->selectedManager(); if ( sm ) { emit baselineSchedule( m_view->project(), sm ); } } void ScheduleEditor::slotDeleteSelection() { //debugPlan; ScheduleManager *sm = m_view->selectedManager(); if ( sm ) { emit deleteScheduleManager( m_view->project(), sm ); } } void ScheduleEditor::slotMoveLeft() { ScheduleManager *sm = m_view->selectedManager(); if ( sm ) { int index = -1; for ( ScheduleManager *m = sm; m != 0; m = m->parentManager() ) { if ( m->parentManager() == 0 ) { index = m->project().indexOf( m ) + 1; } } debugPlan<name()<loadContext( model()->columnMap(), context ); } void ScheduleEditor::saveContext( QDomElement &context ) const { m_view->saveContext( model()->columnMap(), context ); } KoPrintJob *ScheduleEditor::createPrintJob() { return m_view->createPrintJob( this ); } //----------------------------------------- ScheduleLogTreeView::ScheduleLogTreeView( QWidget *parent ) : QTreeView( parent ) { header()->setStretchLastSection ( true ); header()->setContextMenuPolicy( Qt::CustomContextMenu ); m_model = new QSortFilterProxyModel( this ); m_model->setFilterRole( Qt::UserRole+1 ); m_model->setFilterKeyColumn ( 2 ); // severity m_model->setFilterWildcard( "[^0]" ); // Filter out Debug m_model->setSourceModel( new ScheduleLogItemModel( this ) ); setModel( m_model ); setRootIsDecorated( false ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); setAlternatingRowColors( true ); - connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint)) ); + connect( header(), &QWidget::customContextMenuRequested, this, &ScheduleLogTreeView::headerContextMenuRequested ); actionShowDebug = new KToggleAction( xi18nc( "@action", "Show Debug Information" ), this ); - connect( actionShowDebug, SIGNAL(toggled(bool)), SLOT(slotShowDebug(bool))); + connect( actionShowDebug, &QAction::toggled, this, &ScheduleLogTreeView::slotShowDebug); } void ScheduleLogTreeView::setFilterWildcard( const QString &filter ) { m_model->setFilterWildcard( filter ); } QRegExp ScheduleLogTreeView::filterRegExp() const { return m_model->filterRegExp(); } void ScheduleLogTreeView::slotShowDebug( bool on ) { on ? setFilterWildcard( QString() ) : setFilterWildcard("[^0]" ); } void ScheduleLogTreeView::contextMenuEvent ( QContextMenuEvent *e ) { debugPlan<pos())<<" at"<pos(); emit contextMenuRequested( indexAt( e->pos() ), e->globalPos() ); } void ScheduleLogTreeView::headerContextMenuRequested( const QPoint &pos ) { //debugPlan<logicalIndexAt(pos)<<" at"<addAction( actionShowDebug ); m->exec( mapToGlobal( pos ) ); delete m; } void ScheduleLogTreeView::selectionChanged( const QItemSelection &sel, const QItemSelection &desel ) { //debugPlan<selectedIndexes() ) { Q_UNUSED(i); //debugPlan<selectedIndexes() ); } void ScheduleLogTreeView::currentChanged( const QModelIndex & current, const QModelIndex & previous ) { //debugPlan<select( current, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); } void ScheduleLogTreeView::slotEditCopy() { QStringList lst; // int row = 0; QString s; QHeaderView *h = header(); foreach( const QModelIndex &i, selectionModel()->selectedRows() ) { QString s; for ( int section = 0; section < h->count(); ++section ) { QModelIndex idx = model()->index( i.row(), h->logicalIndex( section ) ); if ( ! idx.isValid() || isColumnHidden( idx.column() ) ) { continue; } if ( ! s.isEmpty() ) { s += ' '; } s = QString( "%1%2" ).arg( s ).arg( idx.data().toString(), -10 ); } if ( ! s.isEmpty() ) { lst << s; } } if ( ! lst.isEmpty() ) { QApplication::clipboard()->setText( lst.join( "\n" ) ); } } //----------------------------------- ScheduleLogView::ScheduleLogView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent ) { setupGui(); slotEnableActions( 0 ); QVBoxLayout * l = new QVBoxLayout( this ); m_view = new ScheduleLogTreeView( this ); l->addWidget( m_view ); // m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); connect( m_view, SIGNAL(currentChanged(QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); - connect( baseModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(updateActionsEnabled(QModelIndex)) ); + connect( baseModel(), &QAbstractItemModel::dataChanged, this, &ScheduleLogView::updateActionsEnabled ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &ScheduleLogTreeView::contextMenuRequested, this, &ScheduleLogView::slotContextMenuRequested ); } void ScheduleLogView::setProject( Project *project ) { m_view->setProject( project ); } void ScheduleLogView::draw( Project &project ) { setProject( &project ); } void ScheduleLogView::setGuiActive( bool activate ) { //debugPlan<currentIndex().isValid() ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); }*/ } void ScheduleLogView::slotEdit() { QString id = sender()->property( "p_identity" ).toString(); if ( id.isEmpty() ) { emit editNode( project() ); return; } Node *n = project()->findNode( id ); if ( n ) { emit editNode( n ); return; } Resource *r = project()->findResource( id ); if ( r ) { emit editResource( r ); return; } warnPlan<<"No object"; } void ScheduleLogView::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { if ( ! isReadWrite() || ! index.isValid() ) { return; } QMenu *m = new QMenu( this ); QString id = index.data( ScheduleLogItemModel::IdentityRole ).toString(); if ( id.isEmpty() ) { return; } QAction *a = new QAction(koIcon("document-edit"), i18n( "Edit..." ), m); a->setProperty( "p_identity", id ); m->addAction( a ); - connect(a, SIGNAL(triggered(bool)), SLOT(slotEdit())); + connect(a, &QAction::triggered, this, &ScheduleLogView::slotEdit); m->addSeparator(); m->exec( pos ); delete m; } void ScheduleLogView::slotScheduleSelectionChanged( ScheduleManager *sm ) { baseModel()->setManager( sm ); } void ScheduleLogView::slotCurrentChanged( const QModelIndex & ) { //debugPlan<setReadWrite( readwrite ); //slotEnableActions( m_view->currentManager() ); } void ScheduleLogView::slotOptions() { debugPlan; } void ScheduleLogView::slotEditCopy() { m_view->slotEditCopy(); } bool ScheduleLogView::loadContext( const KoXmlElement &/*context */) { debugPlan; return true;//m_view->loadContext( model()->columnMap(), context ); } void ScheduleLogView::saveContext( QDomElement &/*context */) const { //m_view->saveContext( model()->columnMap(), context ); } //--------------------------- ScheduleHandlerView::ScheduleHandlerView(KoPart *part, KoDocument *doc, QWidget *parent ) : SplitterView(part, doc, parent) { debugPlan<<"---------------- Create ScheduleHandlerView ------------------"; m_scheduleEditor = new ScheduleEditor(part, doc, this ); m_scheduleEditor->setObjectName( "ScheduleEditor" ); addView( m_scheduleEditor ); QTabWidget *tab = addTabWidget(); PertResult *p = new PertResult(part, doc, tab); p->setObjectName( "PertResult" ); addView( p, tab, i18n( "Result" ) ); - connect( m_scheduleEditor, SIGNAL(scheduleSelectionChanged(KPlato::ScheduleManager*)), p, SLOT(slotScheduleSelectionChanged(KPlato::ScheduleManager*)) ); + connect( m_scheduleEditor, &ScheduleEditor::scheduleSelectionChanged, p, &PertResult::slotScheduleSelectionChanged ); PertCpmView *c = new PertCpmView(part, doc, tab); c->setObjectName( "PertCpmView" ); addView( c, tab, i18n( "Critical Path" ) ); - connect( m_scheduleEditor, SIGNAL(scheduleSelectionChanged(KPlato::ScheduleManager*)), c, SLOT(slotScheduleSelectionChanged(KPlato::ScheduleManager*)) ); + connect( m_scheduleEditor, &ScheduleEditor::scheduleSelectionChanged, c, &PertCpmView::slotScheduleSelectionChanged ); ScheduleLogView *v = new ScheduleLogView(part, doc, tab); v->setObjectName( "ScheduleLogView" ); addView( v, tab, i18n( "Scheduling Log" ) ); connect( m_scheduleEditor, SIGNAL(scheduleSelectionChanged(KPlato::ScheduleManager*)), v, SLOT(slotScheduleSelectionChanged(KPlato::ScheduleManager*)) ); - connect(v, SIGNAL(editNode(KPlato::Node*)), SIGNAL(editNode(KPlato::Node*))); - connect(v, SIGNAL(editResource(KPlato::Resource*)), SIGNAL(editResource(KPlato::Resource*))); + connect(v, &ScheduleLogView::editNode, this, &ScheduleHandlerView::editNode); + connect(v, &ScheduleLogView::editResource, this, &ScheduleHandlerView::editResource); } void ScheduleHandlerView::currentTabChanged( int ) { } ViewBase *ScheduleHandlerView::hitView( const QPoint &/*glpos */) { //debugPlan<"<() ) { v->setGuiActive( active ); } m_activeview = active ? this : 0; emit guiActivated( this, active ); } void ScheduleHandlerView::slotGuiActivated( ViewBase *, bool ) { } QStringList ScheduleHandlerView::actionListNames() const { QStringList lst; foreach ( ViewBase *v, findChildren() ) { lst += v->actionListNames(); } return lst; } QList ScheduleHandlerView::actionList( const QString &name ) const { //debugPlan< lst; foreach ( ViewBase *v, findChildren() ) { lst += v->actionList( name ); } return lst; } SchedulingRange::SchedulingRange(KoDocument *doc, QWidget *parent) : QWidget(parent) , m_doc(doc) , m_project(0) { setupUi(this); - connect(targetStartTime, SIGNAL(editingFinished()), this, SLOT(slotStartChanged())); - connect(targetEndTime, SIGNAL(editingFinished()), this, SLOT(slotEndChanged())); + connect(targetStartTime, &QAbstractSpinBox::editingFinished, this, &SchedulingRange::slotStartChanged); + connect(targetEndTime, &QAbstractSpinBox::editingFinished, this, &SchedulingRange::slotEndChanged); } void SchedulingRange::setProject(Project *project) { if (m_project) { - disconnect(m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotProjectChanged(KPlato::Node*))); + disconnect(m_project, &Project::nodeChanged, this, &SchedulingRange::slotProjectChanged); } m_project = project; if (m_project) { - connect(m_project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotProjectChanged(KPlato::Node*))); + connect(m_project, &Project::nodeChanged, this, &SchedulingRange::slotProjectChanged); slotProjectChanged(m_project); } } void SchedulingRange::slotProjectChanged(Node *node) { if (node != m_project) { return; } if (targetStartTime->dateTime() != m_project->constraintStartTime()) { targetStartTime->setDateTime(m_project->constraintStartTime()); } if (targetEndTime->dateTime() != m_project->constraintEndTime()) { targetEndTime->setDateTime(m_project->constraintEndTime()); } } void SchedulingRange::slotStartChanged() { if (!m_project || !m_doc) { return; } if (targetStartTime->dateTime() == m_project->constraintStartTime()) { return; } ProjectModifyStartTimeCmd *cmd = new ProjectModifyStartTimeCmd(*m_project, targetStartTime->dateTime(), kundo2_i18n("Modify project target start time")); m_doc->addCommand(cmd); } void SchedulingRange::slotEndChanged() { if (!m_project || !m_doc) { return; } if (targetEndTime->dateTime() == m_project->constraintEndTime()) { return; } ProjectModifyEndTimeCmd *cmd = new ProjectModifyEndTimeCmd(*m_project, targetEndTime->dateTime(), kundo2_i18n("Modify project target end time")); m_doc->addCommand(cmd); } } // namespace KPlato diff --git a/src/libs/ui/kptsplitterview.cpp b/src/libs/ui/kptsplitterview.cpp index 5dc3c879..31c18753 100644 --- a/src/libs/ui/kptsplitterview.cpp +++ b/src/libs/ui/kptsplitterview.cpp @@ -1,340 +1,340 @@ /* This file is part of the KDE project Copyright (C) 2007. 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. */ #include "kptsplitterview.h" #include "KoDocument.h" #include #include #include #include #include "kptdebug.h" namespace KPlato { SplitterView::SplitterView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent), m_activeview( 0 ) { QVBoxLayout *b = new QVBoxLayout( this ); b->setContentsMargins( 0, 0, 0, 0 ); m_splitter = new QSplitter( this ); m_splitter->setOrientation( Qt::Vertical ); b->addWidget( m_splitter ); } QTabWidget *SplitterView::addTabWidget( ) { QTabWidget *w = new QTabWidget( m_splitter ); m_splitter->addWidget( w ); - connect( w, SIGNAL(currentChanged(int)), SLOT(currentTabChanged(int)) ); + connect( w, &QTabWidget::currentChanged, this, &SplitterView::currentTabChanged ); return w; } void SplitterView::currentTabChanged( int ) { ViewBase *v = qobject_cast( qobject_cast( sender() )->currentWidget() ); if ( v && v != m_activeview ) { if ( m_activeview ) { m_activeview->setGuiActive( false ); } v->setGuiActive( true ); } } void SplitterView::addView( ViewBase *view ) { m_splitter->addWidget( view ); - connect( view, SIGNAL(guiActivated(ViewBase*,bool)), this, SLOT(slotGuiActivated(ViewBase*,bool)) ); - connect( view, SIGNAL(requestPopupMenu(QString,QPoint)), SIGNAL(requestPopupMenu(QString,QPoint)) ); - connect(view, SIGNAL(optionsModified()), SIGNAL(optionsModified())); + connect( view, &ViewBase::guiActivated, this, &SplitterView::slotGuiActivated ); + connect( view, &ViewBase::requestPopupMenu, this, &ViewBase::requestPopupMenu ); + connect(view, &ViewBase::optionsModified, this, &ViewBase::optionsModified); } void SplitterView::addView( ViewBase *view, QTabWidget *tab, const QString &label ) { tab->addTab( view, label ); - connect( view, SIGNAL(guiActivated(ViewBase*,bool)), this, SLOT(slotGuiActivated(ViewBase*,bool)) ); - connect( view, SIGNAL(requestPopupMenu(QString,QPoint)), SIGNAL(requestPopupMenu(QString,QPoint)) ); - connect(view, SIGNAL(optionsModified()), SIGNAL(optionsModified())); + connect( view, &ViewBase::guiActivated, this, &SplitterView::slotGuiActivated ); + connect( view, &ViewBase::requestPopupMenu, this, &ViewBase::requestPopupMenu ); + connect(view, &ViewBase::optionsModified, this, &ViewBase::optionsModified); } // reimp void SplitterView::setGuiActive( bool active ) // virtual slot { debugPlan<setGuiActive( active ); } else { emit guiActivated( this, active ); } } void SplitterView::slotGuiActivated( ViewBase *v, bool active ) { debugPlan< "<count(); ++i ) { ViewBase *w = dynamic_cast( m_splitter->widget( i ) ); if ( w && w->frameGeometry().contains( pos ) ) { debugPlan<frameGeometry(); return w; } QTabWidget *tw = dynamic_cast( m_splitter->widget( i ) ); if (tw && tw->frameGeometry().contains( pos ) ) { w = dynamic_cast( tw->currentWidget() ); if ( w ) { debugPlan<frameGeometry(); return w; } } } return const_cast( this ); } void SplitterView::setProject( Project *project ) { foreach ( ViewBase *v, findChildren() ) { v->setProject( project ); } ViewBase::setProject( project ); } void SplitterView::setScheduleManager( ScheduleManager *sm ) { foreach ( ViewBase *v, findChildren() ) { v->setScheduleManager( sm ); } ViewBase::setScheduleManager( sm ); } void SplitterView::draw() { for ( int i = 0; i < m_splitter->count(); ++i ) { ViewBase *v = dynamic_cast( m_splitter->widget( i ) ); if ( v ) { v->draw(); } else { QTabWidget *tw = dynamic_cast( m_splitter->widget( i ) ); if (tw ) { for ( int j = 0; j < tw->count(); ++j ) { v = dynamic_cast( tw->widget( j ) ); if ( v ) { v->draw(); } } } } } } void SplitterView::draw( Project &project ) { for ( int i = 0; i < m_splitter->count(); ++i ) { ViewBase *v = dynamic_cast( m_splitter->widget( i ) ); if ( v ) { v->draw( project ); } else { QTabWidget *tw = dynamic_cast( m_splitter->widget( i ) ); if (tw ) { for ( int j = 0; j < tw->count(); ++j ) { v = dynamic_cast( tw->widget( j ) ); if ( v ) { v->draw( project ); } } } } } } void SplitterView::updateReadWrite( bool mode ) { for ( int i = 0; i < m_splitter->count(); ++i ) { ViewBase *v = dynamic_cast( m_splitter->widget( i ) ); if ( v ) { v->updateReadWrite( mode ); } else { QTabWidget *tw = dynamic_cast( m_splitter->widget( i ) ); if (tw ) { for ( int j = 0; j < tw->count(); ++j ) { v = dynamic_cast( tw->widget( j ) ); if ( v ) { v->updateReadWrite( mode ); } } } } } } ViewBase *SplitterView::focusView() const { QList lst = findChildren(); debugPlan<isActive() ) { debugPlan<actionListNames(); } return lst; } QList SplitterView::actionList( const QString &name ) const { QList lst = ViewActionLists::actionList( name ); if ( lst.isEmpty() ) { ViewBase *view = focusView(); if ( view && view != this ) { lst = view->actionList( name ); } } return lst; } QList SplitterView::contextActionList() const { ViewBase *view = focusView(); debugPlan<contextActionList(); } return QList(); } Node* SplitterView::currentNode() const { ViewBase *view = focusView(); if ( view ) { return view->currentNode(); } return 0; } Resource* SplitterView::currentResource() const { ViewBase *view = focusView(); if ( view ) { return view->currentResource(); } return 0; } ResourceGroup* SplitterView::currentResourceGroup() const { ViewBase *view = focusView(); if ( view ) { return view->currentResourceGroup(); } return 0; } Calendar* SplitterView::currentCalendar() const { ViewBase *view = focusView(); if ( view ) { return view->currentCalendar(); } return 0; } Relation *SplitterView::currentRelation() const { ViewBase *view = focusView(); if ( view ) { return view->currentRelation(); } return 0; } bool SplitterView::loadContext( const KoXmlElement &context ) { KoXmlElement e = context.namedItem( "views" ).toElement(); if ( e.isNull() ) { return true; } #ifndef KOXML_USE_QDOM foreach ( const QString &s, e.attributeNames() ) { ViewBase *v = findChildren( s ).value( 0 ); if ( v == 0 ) { continue; } KoXmlElement e1 = e.namedItem( s ).toElement(); if ( e1.isNull() ) { continue; } v->loadContext( e1 ); } #endif return true; } void SplitterView::saveContext( QDomElement &context ) const { QList lst = findChildren(); if ( lst.isEmpty() ) { return; } QDomElement e = context.ownerDocument().createElement( "views" ); context.appendChild( e ); foreach ( ViewBase *v, lst ) { e.setAttribute( v->objectName(), "" ); } foreach ( ViewBase *v, lst ) { QDomElement e1 = e.ownerDocument().createElement( v->objectName() ); e.appendChild( e1 ); v->saveContext( e1 ); } } void SplitterView::slotEditCopy() { ViewBase *v = focusView(); if ( v ) { v->slotEditCopy(); } } } // namespace KPlato diff --git a/src/libs/ui/kptstandardworktimedialog.cpp b/src/libs/ui/kptstandardworktimedialog.cpp index ba5c7ab9..ff8c0033 100644 --- a/src/libs/ui/kptstandardworktimedialog.cpp +++ b/src/libs/ui/kptstandardworktimedialog.cpp @@ -1,199 +1,199 @@ /* This file is part of the KDE project Copyright (C) 2004 - 2007, 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. */ #include "kptstandardworktimedialog.h" #include "kptduration.h" #include "kptproject.h" #include "kptcalendar.h" #include "kptcommand.h" #include "kptdebug.h" #include #include namespace KPlato { class WeekdayListItem : public QTreeWidgetItem { public: WeekdayListItem(Calendar *cal, int wd, QTreeWidget *parent, const QString& name, QTreeWidgetItem *after) : QTreeWidgetItem(parent, after), original(cal->weekday(wd)), calendar(cal), weekday(wd) { setText(0, name); day = new CalendarDay(original); if (day->state() == CalendarDay::NonWorking) { setHours(); } else { setText(1, QLocale().toString(day->duration().toDouble(Duration::Unit_h), 'f', 2)); } } ~WeekdayListItem() { delete day; } void setHours() { setText(1, "-"); day->clearIntervals(); } void setIntervals(QList intervals) { day->setIntervals(intervals); setText(1, QLocale().toString(day->duration().toDouble(Duration::Unit_h), 'f', 2)); } void setState(int st) { day->setState(st+1); } MacroCommand *save() { MacroCommand *cmd=0; if (*original != *day) { cmd = new MacroCommand(); cmd->addCommand( new CalendarModifyWeekdayCmd(calendar, weekday, day) ); day = 0; } return cmd; } CalendarDay *day; CalendarDay *original; Calendar *calendar; int weekday; }; StandardWorktimeDialog::StandardWorktimeDialog(Project &p, QWidget *parent) : KoDialog(parent), project(p) { setCaption( i18n("Estimate Conversions") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); //debugPlan<<&p; m_original = p.standardWorktime(); dia = new StandardWorktimeDialogImpl(m_original, this); setMainWidget(dia); enableButtonOk(false); - connect(dia, SIGNAL(obligatedFieldsFilled(bool)), SLOT(enableButtonOk(bool))); - connect(dia, SIGNAL(enableButtonOk(bool)), SLOT(enableButtonOk(bool))); - connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); + connect(dia, &StandardWorktimeDialogImpl::obligatedFieldsFilled, this, &KoDialog::enableButtonOk); + connect(dia, &StandardWorktimeDialogImpl::enableButtonOk, this, &KoDialog::enableButtonOk); + connect(this,&KoDialog::okClicked,this,&StandardWorktimeDialog::slotOk); } MacroCommand *StandardWorktimeDialog::buildCommand() { //debugPlan; KUndo2MagicString n = kundo2_i18n("Modify Estimate Conversions"); MacroCommand *cmd = 0; if (m_original->year() != dia->inYear()) { if (cmd == 0) cmd = new MacroCommand(n); cmd->addCommand(new ModifyStandardWorktimeYearCmd(m_original, m_original->year(), dia->inYear())); } if (m_original->month() != dia->inMonth()) { if (cmd == 0) cmd = new MacroCommand(n); cmd->addCommand(new ModifyStandardWorktimeMonthCmd(m_original, m_original->month(), dia->inMonth())); } if (m_original->week() != dia->inWeek()) { if (cmd == 0) cmd = new MacroCommand(n); cmd->addCommand(new ModifyStandardWorktimeWeekCmd(m_original, m_original->week(), dia->inWeek())); } if (m_original->day() != dia->inDay()) { if (cmd == 0) cmd = new MacroCommand(n); cmd->addCommand(new ModifyStandardWorktimeDayCmd(m_original, m_original->day(), dia->inDay())); } return cmd; } void StandardWorktimeDialog::slotOk() { accept(); } StandardWorktimeDialogImpl::StandardWorktimeDialogImpl(StandardWorktime *std, QWidget *parent) : QWidget(parent), m_std(std) { setupUi(this); if (!std) { m_std = new StandardWorktime(); } m_year = m_std->year(); m_month = m_std->month(); m_week = m_std->week(); m_day = m_std->day(); debugPlan<<"y="< namespace KPlato { SummaryTaskDialog::SummaryTaskDialog(Task &task, QWidget *p) : KoDialog(p), m_node( &task ) { setCaption( i18n("Summary Task Settings") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); m_generalTab = new SummaryTaskGeneralPanel(task, this); setMainWidget(m_generalTab); enableButtonOk(false); - connect(m_generalTab, SIGNAL(obligatedFieldsFilled(bool)), SLOT(enableButtonOk(bool))); + connect(m_generalTab, &SummaryTaskGeneralPanel::obligatedFieldsFilled, this, &KoDialog::enableButtonOk); Project *proj = static_cast( task.projectNode() ); if ( proj ) { - connect(proj, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotTaskRemoved(KPlato::Node*))); + connect(proj, &Project::nodeRemoved, this, &SummaryTaskDialog::slotTaskRemoved); } } void SummaryTaskDialog::slotTaskRemoved( Node *node ) { if ( node == m_node ) { reject(); } } MacroCommand *SummaryTaskDialog::buildCommand() { MacroCommand *m = new MacroCommand(kundo2_i18n("Modify Summary Task")); bool modified = false; MacroCommand *cmd = m_generalTab->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } if (!modified) { delete m; return 0; } return m; } void SummaryTaskDialog::slotButtonClicked(int button) { if (button == KoDialog::Ok) { if (!m_generalTab->ok()) return; accept(); } else { KoDialog::slotButtonClicked(button); } } } //KPlato namespace diff --git a/src/libs/ui/kptsummarytaskgeneralpanel.cpp b/src/libs/ui/kptsummarytaskgeneralpanel.cpp index 1a2af873..c75320cc 100644 --- a/src/libs/ui/kptsummarytaskgeneralpanel.cpp +++ b/src/libs/ui/kptsummarytaskgeneralpanel.cpp @@ -1,149 +1,149 @@ /* This file is part of the KDE project Copyright (C) 2004 - 2007, 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. */ #include "kptsummarytaskgeneralpanel.h" #include "kptsummarytaskdialog.h" #include "kpttask.h" #include "kptcommand.h" #include "kpttaskdescriptiondialog.h" #include #ifdef PLAN_KDEPIMLIBS_FOUND #include #include #include #endif namespace KPlato { SummaryTaskGeneralPanel::SummaryTaskGeneralPanel(Task &task, QWidget *p, const char *n) : QWidget(p), m_task(task) { setObjectName(n); setupUi(this); #ifndef PLAN_KDEPIMLIBS_FOUND chooseLeader->hide(); #endif // FIXME // [Bug 311940] New: Plan crashes when typing a text in the filter textbox before the textbook is fully loaded when selecting a contact from the adressbook chooseLeader->hide(); m_description = new TaskDescriptionPanel( task, this ); m_description->namefield->hide(); m_description->namelabel->hide(); layout()->addWidget( m_description ); QString s = i18n( "The Work Breakdown Structure introduces numbering for all tasks in the project, according to the task structure.\nThe WBS code is auto-generated.\nYou can define the WBS code pattern using the Define WBS Pattern command in the Tools menu." ); wbslabel->setWhatsThis( s ); wbsfield->setWhatsThis( s ); setStartValues(task); - connect(namefield, SIGNAL(textChanged(QString)), SLOT(slotObligatedFieldsFilled())); - connect(leaderfield, SIGNAL(textChanged(QString)), SLOT(slotObligatedFieldsFilled())); - connect(m_description, SIGNAL(textChanged(bool)), SLOT(slotObligatedFieldsFilled())); + connect(namefield, &QLineEdit::textChanged, this, &SummaryTaskGeneralPanel::slotObligatedFieldsFilled); + connect(leaderfield, &QLineEdit::textChanged, this, &SummaryTaskGeneralPanel::slotObligatedFieldsFilled); + connect(m_description, &TaskDescriptionPanelImpl::textChanged, this, &SummaryTaskGeneralPanel::slotObligatedFieldsFilled); - connect(chooseLeader, SIGNAL(clicked()), SLOT(slotChooseResponsible())); + connect(chooseLeader, &QAbstractButton::clicked, this, &SummaryTaskGeneralPanel::slotChooseResponsible); } void SummaryTaskGeneralPanel::setStartValues(Task &task) { namefield->setText(task.name()); leaderfield->setText(task.leader()); m_description->descriptionfield->setTextOrHtml(task.description()); wbsfield->setText(task.wbsCode()); namefield->setFocus(); } void SummaryTaskGeneralPanel::slotObligatedFieldsFilled() { emit obligatedFieldsFilled(true); // never block save } MacroCommand *SummaryTaskGeneralPanel::buildCommand() { MacroCommand *cmd = new MacroCommand(kundo2_i18n("Modify task")); bool modified = false; if (!namefield->isHidden() && m_task.name() != namefield->text()) { cmd->addCommand(new NodeModifyNameCmd(m_task, namefield->text())); modified = true; } if (!leaderfield->isHidden() && m_task.leader() != leaderfield->text()) { cmd->addCommand(new NodeModifyLeaderCmd(m_task, leaderfield->text())); modified = true; } /* if (!descriptionfield->isHidden() && m_task.description() != descriptionfield->text()) { cmd->addCommand(new NodeModifyDescriptionCmd(m_task, descriptionfield->text())); modified = true; }*/ MacroCommand *m = m_description->buildCommand(); if ( m ) { cmd->addCommand( m ); modified = true; } if (!modified) { delete cmd; return 0; } return cmd; } bool SummaryTaskGeneralPanel::ok() { return true; } void SummaryTaskGeneralPanel::slotChooseResponsible() { #ifdef PLAN_KDEPIMLIBS_FOUND QPointer dlg = new Akonadi::EmailAddressSelectionDialog( this ); if ( dlg->exec() && dlg ) { QStringList names; const Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); foreach ( const Akonadi::EmailAddressSelection &selection, selections ) { QString s = selection.name(); if ( ! selection.email().isEmpty() ) { if ( ! selection.name().isEmpty() ) { s += " <"; } s += selection.email(); if ( ! selection.name().isEmpty() ) { s += '>'; } if ( ! s.isEmpty() ) { names << s; } } } if ( ! names.isEmpty() ) { leaderfield->setText( names.join( ", " ) ); } } #endif } } //KPlato namespace diff --git a/src/libs/ui/kpttaskcostpanel.cpp b/src/libs/ui/kpttaskcostpanel.cpp index 75e36daa..48c60cb0 100644 --- a/src/libs/ui/kpttaskcostpanel.cpp +++ b/src/libs/ui/kpttaskcostpanel.cpp @@ -1,172 +1,172 @@ /* This file is part of the KDE project Copyright (C) 2005-2007 Dag Andersen Copyright (C) 20011 Dag Andersen 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 Cost Public License for more details. You should have received a copy of the GNU Library Cost 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 "kpttaskcostpanel.h" #include "kptaccount.h" #include "kpttask.h" #include "kptcommand.h" #include "kptproject.h" #include "kptlocale.h" namespace KPlato { TaskCostPanel::TaskCostPanel(Task &task, Accounts &accounts, QWidget *p, const char *n) : TaskCostPanelImpl(p, n), m_task(task), m_accounts(accounts) { const Project *project = qobject_cast( task.projectNode() ); if ( project ) { m_locale = project->locale(); m_localeIsOwn = false; } else { m_locale = new Locale(); m_localeIsOwn = true; } m_accountList << i18n("None"); m_accountList += accounts.costElements(); if ( task.isBaselined( BASELINESCHEDULE ) ) { runningGroup->setEnabled( false ); startupGroup->setEnabled( false ); shutdownGroup->setEnabled( false ); } setStartValues(task); } TaskCostPanel::~TaskCostPanel() { if (m_localeIsOwn) { delete m_locale; } } void TaskCostPanel::setStartValues(Task &task) { runningAccount->addItems(m_accountList); m_oldrunning = m_accounts.findRunningAccount(task); if (m_oldrunning) { setCurrentItem(runningAccount, m_oldrunning->name()); } startupCost->setText(m_locale->formatMoney(task.startupCost())); startupAccount->addItems(m_accountList); m_oldstartup = m_accounts.findStartupAccount(task); if (m_oldstartup) { setCurrentItem(startupAccount, m_oldstartup->name()); } shutdownCost->setText(m_locale->formatMoney(task.shutdownCost())); shutdownAccount->addItems(m_accountList); m_oldshutdown = m_accounts.findShutdownAccount(task); if (m_oldshutdown) { setCurrentItem(shutdownAccount, m_oldshutdown->name()); } } void TaskCostPanel::setCurrentItem(QComboBox *box, const QString& name) { box->setCurrentIndex(0); for (int i = 0; i < box->count(); ++i) { if (name == box->itemText(i)) { box->setCurrentIndex(i); break; } } } MacroCommand *TaskCostPanel::buildCommand() { MacroCommand *cmd = new MacroCommand(kundo2_i18n("Modify Task Cost")); bool modified = false; if ((m_oldrunning == 0 && runningAccount->currentIndex() != 0) || (m_oldrunning && m_oldrunning->name() != runningAccount->currentText())) { cmd->addCommand(new NodeModifyRunningAccountCmd(m_task, m_oldrunning, m_accounts.findAccount(runningAccount->currentText()))); modified = true; } if ((m_oldstartup == 0 && startupAccount->currentIndex() != 0) || (m_oldstartup && m_oldstartup->name() != startupAccount->currentText())) { cmd->addCommand(new NodeModifyStartupAccountCmd(m_task, m_oldstartup, m_accounts.findAccount(startupAccount->currentText()))); modified = true; } if ((m_oldshutdown == 0 && shutdownAccount->currentIndex() != 0) || (m_oldshutdown && m_oldshutdown->name() != shutdownAccount->currentText())) { cmd->addCommand(new NodeModifyShutdownAccountCmd(m_task, m_oldshutdown, m_accounts.findAccount(shutdownAccount->currentText()))); modified = true; } double money = m_locale->readMoney(startupCost->text()); if (money != m_task.startupCost()) { cmd->addCommand(new NodeModifyStartupCostCmd(m_task, money)); modified = true; } money = m_locale->readMoney(shutdownCost->text()); if (money != m_task.shutdownCost()) { cmd->addCommand(new NodeModifyShutdownCostCmd(m_task, money)); modified = true; } if (!modified) { delete cmd; return 0; } return cmd; } bool TaskCostPanel::ok() { if (runningAccount->currentIndex() == 0 || m_accounts.findAccount(runningAccount->currentText()) == 0) { //message return false; } if (startupAccount->currentIndex() == 0 || m_accounts.findAccount(startupAccount->currentText()) == 0) { //message return false; } if (shutdownAccount->currentIndex() == 0 || m_accounts.findAccount(shutdownAccount->currentText()) == 0) { //message return false; } return true; } TaskCostPanelImpl::TaskCostPanelImpl(QWidget *p, const char *n) : QWidget(p) { setObjectName(n); setupUi(this); connect(runningAccount, SIGNAL(activated(int)), SLOT(slotChanged())); connect(startupAccount, SIGNAL(activated(int)), SLOT(slotChanged())); connect(shutdownAccount, SIGNAL(activated(int)), SLOT(slotChanged())); - connect(startupCost, SIGNAL(textChanged(QString)), SLOT(slotChanged())); - connect(shutdownCost, SIGNAL(textChanged(QString)), SLOT(slotChanged())); + connect(startupCost, &QLineEdit::textChanged, this, &TaskCostPanelImpl::slotChanged); + connect(shutdownCost, &QLineEdit::textChanged, this, &TaskCostPanelImpl::slotChanged); } void TaskCostPanelImpl::slotChanged() { emit changed(); } } //KPlato namespace diff --git a/src/libs/ui/kpttaskdescriptiondialog.cpp b/src/libs/ui/kpttaskdescriptiondialog.cpp index bb3e030a..99ef5831 100644 --- a/src/libs/ui/kpttaskdescriptiondialog.cpp +++ b/src/libs/ui/kpttaskdescriptiondialog.cpp @@ -1,171 +1,171 @@ /* This file is part of the KDE project Copyright (C) 2009 Dag Andersen #include #include namespace KPlato { TaskDescriptionPanel::TaskDescriptionPanel(Node &node, QWidget *p, bool readOnly ) : TaskDescriptionPanelImpl( node, p ) { initDescription( readOnly ); setStartValues( node ); descriptionfield->setFocus(); } void TaskDescriptionPanel::setStartValues( Node &node ) { namefield->setText(node.name()); descriptionfield->setTextOrHtml( node.description() ); } MacroCommand *TaskDescriptionPanel::buildCommand() { KUndo2MagicString s = kundo2_i18n("Modify task description"); if ( m_node.type() == Node::Type_Milestone ) { s = kundo2_i18n("Modify milestone description"); } else if ( m_node.type() == Node::Type_Summarytask ) { s = kundo2_i18n("Modify summary task description"); } else if ( m_node.type() == Node::Type_Project ) { s = kundo2_i18n("Modify project description"); } MacroCommand *cmd = new MacroCommand(s); bool modified = false; if ( m_node.description() != descriptionfield->textOrHtml() ) { cmd->addCommand(new NodeModifyDescriptionCmd(m_node, descriptionfield->textOrHtml())); modified = true; } if (!modified) { delete cmd; return 0; } return cmd; } bool TaskDescriptionPanel::ok() { return true; } void TaskDescriptionPanel::initDescription( bool readOnly ) { toolbar->setVisible( ! readOnly ); toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly ); KActionCollection *collection = new KActionCollection( this ); //krazy:exclude=tipsandthis descriptionfield->setRichTextSupport( KRichTextWidget::SupportBold | KRichTextWidget::SupportItalic | KRichTextWidget::SupportUnderline | KRichTextWidget::SupportStrikeOut | KRichTextWidget::SupportChangeListStyle | KRichTextWidget::SupportAlignment | KRichTextWidget::SupportFormatPainting ); collection->addActions(descriptionfield->createActions()); toolbar->addAction( collection->action( "format_text_bold" ) ); toolbar->addAction( collection->action( "format_text_italic" ) ); toolbar->addAction( collection->action( "format_text_underline" ) ); toolbar->addAction( collection->action( "format_text_strikeout" ) ); toolbar->addSeparator(); toolbar->addAction( collection->action( "format_list_style" ) ); toolbar->addSeparator(); toolbar->addAction( collection->action( "format_align_left" ) ); toolbar->addAction( collection->action( "format_align_center" ) ); toolbar->addAction( collection->action( "format_align_right" ) ); toolbar->addAction( collection->action( "format_align_justify" ) ); toolbar->addSeparator(); // toolbar->addAction( collection->action( "format_painter" ) ); descriptionfield->append( "" ); descriptionfield->setReadOnly( readOnly ); descriptionfield->setOverwriteMode( false ); descriptionfield->setLineWrapMode( KTextEdit::WidgetWidth ); descriptionfield->setTabChangesFocus( true ); } //----------------------------- TaskDescriptionPanelImpl::TaskDescriptionPanelImpl( Node &node, QWidget *p ) : QWidget(p), m_node(node) { setupUi(this); - connect( descriptionfield, SIGNAL(textChanged()), SLOT(slotChanged()) ); + connect( descriptionfield, &QTextEdit::textChanged, this, &TaskDescriptionPanelImpl::slotChanged ); } void TaskDescriptionPanelImpl::slotChanged() { emit textChanged( descriptionfield->textOrHtml() != m_node.description() ); } //----------------------------- TaskDescriptionDialog::TaskDescriptionDialog( Task &task, QWidget *p, bool readOnly ) : KoDialog(p) { setCaption( i18n( "Task Description" ) ); if ( readOnly ) { setButtons( Close ); } else { setButtons( Ok|Cancel ); setDefaultButton( Ok ); } showButtonSeparator( true ); m_descriptionTab = new TaskDescriptionPanel( task, this, readOnly ); setMainWidget(m_descriptionTab); enableButtonOk(false); - connect( m_descriptionTab, SIGNAL(textChanged(bool)), this, SLOT(enableButtonOk(bool)) ); + connect( m_descriptionTab, &TaskDescriptionPanelImpl::textChanged, this, &KoDialog::enableButtonOk ); } MacroCommand *TaskDescriptionDialog::buildCommand() { return m_descriptionTab->buildCommand(); } void TaskDescriptionDialog::slotButtonClicked( int button ) { if (button == KoDialog::Ok) { if ( ! m_descriptionTab->ok() ) { return; } accept(); } else { KoDialog::slotButtonClicked( button ); } } } //KPlato namespace diff --git a/src/libs/ui/kpttaskdialog.cpp b/src/libs/ui/kpttaskdialog.cpp index 43bdbcd7..7f043d58 100644 --- a/src/libs/ui/kpttaskdialog.cpp +++ b/src/libs/ui/kpttaskdialog.cpp @@ -1,226 +1,226 @@ /* This file is part of the KDE project Copyright (C) 2002 Bo Thorsen bo@sonofthor.dk Copyright (C) 2004 -2010 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 "kpttaskdialog.h" #include "kpttaskcostpanel.h" #include "kpttaskgeneralpanel.h" #include "kptrequestresourcespanel.h" #include "kptdocumentspanel.h" #include "kpttaskdescriptiondialog.h" #include "kptcommand.h" #include "kptnode.h" #include "kpttask.h" #include "kptproject.h" #include #include namespace KPlato { TaskDialog::TaskDialog( Project &project, Task &task, Accounts &accounts, QWidget *p) : KPageDialog(p), m_project( project ), m_node( &task ) { setWindowTitle( i18n("Task Settings") ); setFaceType( KPageDialog::Tabbed ); KoVBox *page; // Create all the tabs. page = new KoVBox(); addPage(page, i18n("&General")); m_generalTab = new TaskGeneralPanel(project, task, page); page = new KoVBox(); addPage(page, i18n("&Resources")); m_resourcesTab = new RequestResourcesPanel(page, project, task); page = new KoVBox(); addPage(page, i18n("&Documents")); m_documentsTab = new DocumentsPanel( task, page ); page = new KoVBox(); addPage(page, i18n("&Cost")); m_costTab = new TaskCostPanel(task, accounts, page); page = new KoVBox(); addPage(page, i18n("D&escription")); m_descriptionTab = new TaskDescriptionPanel(task, page); m_descriptionTab->namefield->hide(); m_descriptionTab->namelabel->hide(); setButtonOkEnabled(false); - connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), SLOT(slotCurrentChanged(KPageWidgetItem*,KPageWidgetItem*))); + connect(this, &KPageDialog::currentPageChanged, this, &TaskDialog::slotCurrentChanged); - connect(m_generalTab, SIGNAL(obligatedFieldsFilled(bool)), this, SLOT(setButtonOkEnabled(bool))); - connect(m_resourcesTab, SIGNAL(changed()), m_generalTab, SLOT(checkAllFieldsFilled())); - connect(m_documentsTab, SIGNAL(changed()), m_generalTab, SLOT(checkAllFieldsFilled())); - connect(m_costTab, SIGNAL(changed()), m_generalTab, SLOT(checkAllFieldsFilled())); - connect(m_descriptionTab, SIGNAL(textChanged(bool)), m_generalTab, SLOT(checkAllFieldsFilled())); + connect(m_generalTab, &TaskGeneralPanelImpl::obligatedFieldsFilled, this, &TaskDialog::setButtonOkEnabled); + connect(m_resourcesTab, &RequestResourcesPanel::changed, m_generalTab, &TaskGeneralPanelImpl::checkAllFieldsFilled); + connect(m_documentsTab, &DocumentsPanel::changed, m_generalTab, &TaskGeneralPanelImpl::checkAllFieldsFilled); + connect(m_costTab, &TaskCostPanelImpl::changed, m_generalTab, &TaskGeneralPanelImpl::checkAllFieldsFilled); + connect(m_descriptionTab, &TaskDescriptionPanelImpl::textChanged, m_generalTab, &TaskGeneralPanelImpl::checkAllFieldsFilled); - connect(&project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotTaskRemoved(KPlato::Node*))); + connect(&project, &Project::nodeRemoved, this, &TaskDialog::slotTaskRemoved); } void TaskDialog::setButtonOkEnabled(bool enabled) { buttonBox()->button(QDialogButtonBox::Ok)->setEnabled(enabled); } void TaskDialog::slotCurrentChanged( KPageWidgetItem *current, KPageWidgetItem */*prev*/ ) { //debugPlan<widget()<parent(); // HACK: KPageDialog grabs focus when a tab is clicked. // KRichTextWidget still flashes the caret so the user thinks it has the focus. // For now, just give the KRichTextWidget focus. if ( current->widget() == m_descriptionTab->parent() ) { m_descriptionTab->descriptionfield->setFocus(); } } void TaskDialog::slotTaskRemoved( Node *node ) { if ( node == m_node ) { reject(); } } MacroCommand *TaskDialog::buildCommand() { MacroCommand *m = new MacroCommand(kundo2_i18n("Modify task")); bool modified = false; MacroCommand *cmd = m_generalTab->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } cmd = m_resourcesTab->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } cmd = m_documentsTab->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } cmd = m_costTab->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } cmd = m_descriptionTab->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } if (!modified) { delete m; return 0; } return m; } void TaskDialog::accept() { if (!m_generalTab->ok()) return; if (!m_resourcesTab->ok()) return; if (!m_descriptionTab->ok()) return; KPageDialog::accept(); } //--------------------------- TaskAddDialog::TaskAddDialog(Project &project, Task &task, Node *currentNode, Accounts &accounts, QWidget *p) : TaskDialog(project, task, accounts, p) { m_currentnode = currentNode; // do not know wbs code yet m_generalTab->hideWbs(); - connect(&project, SIGNAL(nodeRemoved(KPlato::Node*)), SLOT(slotNodeRemoved(KPlato::Node*))); + connect(&project, &Project::nodeRemoved, this, &TaskAddDialog::slotNodeRemoved); } TaskAddDialog::~TaskAddDialog() { delete m_node; // in case of cancel } void TaskAddDialog::slotNodeRemoved( Node *node ) { if ( m_currentnode == node ) { reject(); } } MacroCommand *TaskAddDialog::buildCommand() { MacroCommand *c = new MacroCommand( kundo2_i18n( "Add task" ) ); c->addCommand( new TaskAddCmd( &m_project, m_node, m_currentnode ) ); MacroCommand *m = TaskDialog::buildCommand(); if ( m ) { c->addCommand( m ); } m_node = 0; // don't delete task return c; } //--------------------------- SubTaskAddDialog::SubTaskAddDialog(Project &project, Task &task, Node *currentNode, Accounts &accounts, QWidget *p) : TaskDialog(project, task, accounts, p) { m_currentnode = currentNode; // do not know wbs code yet m_generalTab->hideWbs(); - connect(&project, SIGNAL(nodeRemoved(KPlato::Node*)), SLOT(slotNodeRemoved(KPlato::Node*))); + connect(&project, &Project::nodeRemoved, this, &SubTaskAddDialog::slotNodeRemoved); } SubTaskAddDialog::~SubTaskAddDialog() { delete m_node; // in case of cancel } void SubTaskAddDialog::slotNodeRemoved( Node *node ) { if ( m_currentnode == node ) { reject(); } } MacroCommand *SubTaskAddDialog::buildCommand() { KUndo2MagicString s = kundo2_i18n( "Add sub-task" ); if ( m_currentnode == 0 ) { s = kundo2_i18n( "Add task" ); // it will be added to project } MacroCommand *c = new MacroCommand( s ); c->addCommand( new SubtaskAddCmd( &m_project, m_node, m_currentnode ) ); MacroCommand *m = TaskDialog::buildCommand(); if ( m ) { c->addCommand( m ); } m_node = 0; // don't delete task return c; } } //KPlato namespace diff --git a/src/libs/ui/kpttaskeditor.cpp b/src/libs/ui/kpttaskeditor.cpp index e4cd98b9..6d43a3d8 100644 --- a/src/libs/ui/kpttaskeditor.cpp +++ b/src/libs/ui/kpttaskeditor.cpp @@ -1,1711 +1,1711 @@ /* This file is part of the KDE project Copyright (C) 2006 - 2010, 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. */ #include "kpttaskeditor.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptnodeitemmodel.h" #include "kptcommand.h" #include "kptproject.h" #include "kptitemviewsettup.h" #include "kptworkpackagesenddialog.h" #include "kptworkpackagesendpanel.h" #include "kptdatetime.h" #include "kptdebug.h" #include "kptresourcemodel.h" #include "kptresourceallocationmodel.h" #include "ResourceAllocationView.h" #include "kpttaskdialog.h" #include "TasksEditController.h" #include "Help.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { //-------------------- TaskEditorItemModel::TaskEditorItemModel( QObject *parent ) : NodeItemModel( parent ) { } Qt::ItemFlags TaskEditorItemModel::flags( const QModelIndex &index ) const { if ( index.column() == NodeModel::NodeType ) { if ( ! m_readWrite || isColumnReadOnly( index.column() ) ) { return QAbstractItemModel::flags( index ); } Node *n = node( index ); bool baselined = n ? n->isBaselined() : false; if ( n && ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) { return QAbstractItemModel::flags( index ) | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; } return QAbstractItemModel::flags( index ) | Qt::ItemIsDropEnabled; } return NodeItemModel::flags( index ); } QVariant TaskEditorItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal && section == NodeModel::NodeType ) { if ( role == Qt::ToolTipRole ) { return xi18nc( "@info:tooltip", "The type of task or the estimate type of the task" ); } else if ( role == Qt::WhatsThisRole ) { return xi18nc( "@info:whatsthis", "

Indicates the type of task or the estimate type of the task.

" "The type can be set to Milestone, Effort or Duration." "If the type is Summary or Project the type is not editable."); } } return NodeItemModel::headerData(section, orientation, role); } QVariant TaskEditorItemModel::data( const QModelIndex &index, int role ) const { if ( role == Qt::TextAlignmentRole ) { return NodeItemModel::data( index, role ); } Node *n = node( index ); if ( n != 0 && index.column() == NodeModel::NodeType ) { return type( n, role ); } return NodeItemModel::data( index, role ); } bool TaskEditorItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { Node *n = node( index ); if ( n != 0 && role == Qt::EditRole && index.column() == NodeModel::NodeType ) { return setType( n, value, role ); } return NodeItemModel::setData( index, value, role ); } QVariant TaskEditorItemModel::type( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( node->type() == Node::Type_Task ) { return node->estimate()->typeToString( true ); } return node->typeToString( true ); } case Qt::EditRole: return node->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: { if ( node->type() == Node::Type_Task ) { return xi18nc( "@info:tooltip", "Task with estimate type: %1", node->estimate()->typeToString( true ) ); } return xi18nc( "@info:tooltip", "Task type: %1", node->typeToString( true ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Role::EnumListValue: { if ( node->type() == Node::Type_Milestone ) { return 0; } if ( node->type() == Node::Type_Task ) { return node->estimate()->type() + 1; } return -1; } case Role::EnumList: { QStringList lst; lst << Node::typeToString( Node::Type_Milestone, true ); lst += Estimate::typeToStringList( true ); return lst; } } return QVariant(); } bool TaskEditorItemModel::setType( Node *node, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { if ( node->type() == Node::Type_Summarytask ) { return false; } int v = value.toInt(); switch ( v ) { case 0: { // Milestone NamedCommand *cmd = 0; if ( node->constraint() == Node::FixedInterval ) { cmd = new NodeModifyConstraintEndTimeCmd( *node, node->constraintStartTime(), kundo2_i18n( "Set type to Milestone" ) ); } else { cmd = new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), 0.0, kundo2_i18n( "Set type to Milestone" ) ); } emit executeCommand( cmd ); return true; } default: { // Estimate --v; MacroCommand *m = new MacroCommand( kundo2_i18n( "Set type to %1", Estimate::typeToString( (Estimate::Type)v, true ) ) ); m->addCommand( new ModifyEstimateTypeCmd( *node, node->estimate()->type(), v ) ); if ( node->type() == Node::Type_Milestone ) { if ( node->constraint() == Node::FixedInterval ) { m->addCommand( new NodeModifyConstraintEndTimeCmd( *node, node->constraintStartTime().addDays( 1 ) ) ); } else { m->addCommand( new ModifyEstimateUnitCmd( *node, node->estimate()->unit(), Duration::Unit_d ) ); m->addCommand( new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), 1.0 ) ); } } emit executeCommand( m ); return true; } } break; } default: break; } return false; } //-------------------- TaskEditorTreeView::TaskEditorTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { TaskEditorItemModel *m = new TaskEditorItemModel( this ); setModel( m ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); createItemDelegates( m ); setItemDelegateForColumn( NodeModel::NodeType, new EnumDelegate( this ) ); - connect( this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), SLOT(slotDropAllowed(QModelIndex,int,QDragMoveEvent*)) ); + connect( this, &DoubleTreeViewBase::dropAllowed, this, &TaskEditorTreeView::slotDropAllowed ); } NodeItemModel *TaskEditorTreeView::baseModel() const { NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { return static_cast( pr->sourceModel() ); } return static_cast( model() ); } void TaskEditorTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { QModelIndex idx = index; NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { idx = pr->mapToSource( index ); } event->ignore(); if ( baseModel()->dropAllowed( idx, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); } } //-------------------- NodeTreeView::NodeTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { NodeItemModel *m = new NodeItemModel( this ); setModel( m ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setSelectionBehavior( QAbstractItemView::SelectRows ); createItemDelegates( m ); - connect( this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), SLOT(slotDropAllowed(QModelIndex,int,QDragMoveEvent*)) ); + connect( this, &DoubleTreeViewBase::dropAllowed, this, &NodeTreeView::slotDropAllowed ); } NodeItemModel *NodeTreeView::baseModel() const { NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { return static_cast( pr->sourceModel() ); } return static_cast( model() ); } void NodeTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { QModelIndex idx = index; NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { idx = pr->mapToSource( index ); } event->ignore(); if ( baseModel()->dropAllowed( idx, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); } } //----------------------------------- TaskEditor::TaskEditor(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent ) { debugPlan<<"----------------- Create TaskEditor ----------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new TaskEditorTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); l->addWidget( m_view ); debugPlan<actionSplitView(); setupGui(); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::DragDrop ); m_view->setDropIndicatorShown( true ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( true ); m_view->setAcceptDropsOnView( true ); QList lst1; lst1 << 1 << -1; // only display column 0 (NodeName) in left view QList show; show << NodeModel::NodeResponsible << NodeModel::NodeAllocation << NodeModel::NodeType << NodeModel::NodeEstimateCalendar << NodeModel::NodeEstimate << NodeModel::NodeOptimisticRatio << NodeModel::NodePessimisticRatio << NodeModel::NodeRisk << NodeModel::NodeConstraint << NodeModel::NodeConstraintStart << NodeModel::NodeConstraintEnd << NodeModel::NodeRunningAccount << NodeModel::NodeStartupAccount << NodeModel::NodeStartupCost << NodeModel::NodeShutdownAccount << NodeModel::NodeShutdownCost << NodeModel::NodeDescription; QList lst2; for ( int i = 0; i < model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } for ( int i = 0; i < show.count(); ++i ) { int sec = m_view->slaveView()->header()->visualIndex( show[ i ] ); //debugPlan<<"move section:"<slaveView()->header()->moveSection( sec, i ); } } m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << NodeModel::NodeName ); m_view->slaveView()->setDefaultColumns( show ); connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &TaskEditor::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &TaskEditor::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint,QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &TaskEditor::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); - connect(baseModel(), SIGNAL(projectShownChanged(bool)), SLOT(slotProjectShown(bool))); - connect(model(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(slotEnableActions())); + connect(baseModel(), &NodeItemModel::projectShownChanged, this, &TaskEditor::slotProjectShown); + connect(model(), &QAbstractItemModel::rowsMoved, this, &TaskEditor::slotEnableActions); Help::add(this, xi18nc("@info:whatsthis", "Task Editor" "" "The Task Editor is used to create, edit, and delete tasks. " "Tasks are organized into a Work Breakdown Structure (WBS) to any depth." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Task_Editor"))); } void TaskEditor::slotProjectShown( bool on ) { debugPlan<rowCount() > 0 ) { idx = proxyModel()->index( 0, 0 ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows ); } } else if ( baseModel() && baseModel()->rowCount() > 0 ) { idx = baseModel()->index( 0, 0 ); m_view->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows ); } if ( on && idx.isValid() ) { m_view->masterView()->expand( idx ); } slotEnableActions(); } void TaskEditor::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } void TaskEditor::setProject( Project *project ) { debugPlan<setProject( project ); ViewBase::setProject( project ); } void TaskEditor::createDockers() { // Add dockers DockWidget *ds = 0; { ds = new DockWidget( this, "Allocations", xi18nc( "@title resource allocations", "Allocations" ) ); QTreeView *x = new QTreeView( ds ); AllocatedResourceItemModel *m1 = new AllocatedResourceItemModel( x ); x->setModel( m1 ); m1->setProject( project() ); // x->setHeaderHidden( true ); x->setSelectionBehavior( QAbstractItemView::SelectRows ); x->setSelectionMode( QAbstractItemView::ExtendedSelection ); x->expandAll(); x->resizeColumnToContents( 0 ); x->setDragDropMode( QAbstractItemView::DragOnly ); x->setDragEnabled ( true ); ds->setWidget( x ); - connect(this, SIGNAL(projectChanged(KPlato::Project*)), m1, SLOT(setProject(KPlato::Project*))); - connect(this, SIGNAL(taskSelected(KPlato::Task*)), m1, SLOT(setTask(KPlato::Task*))); - connect(m1, SIGNAL(expandAll()), x, SLOT(expandAll())); - connect(m1, SIGNAL(resizeColumnToContents(int)), x, SLOT(resizeColumnToContents(int))); + connect(this, &ViewBase::projectChanged, m1, &AllocatedResourceItemModel::setProject); + connect(this, &TaskEditor::taskSelected, m1, &AllocatedResourceItemModel::setTask); + connect(m1, &AllocatedResourceItemModel::expandAll, x, &QTreeView::expandAll); + connect(m1, &AllocatedResourceItemModel::resizeColumnToContents, x, &QTreeView::resizeColumnToContents); addDocker( ds ); } { ds = new DockWidget( this, "Resources", xi18nc( "@title", "Resources" ) ); ds->setToolTip( xi18nc( "@info:tooltip", "Drag resources into the Task Editor" " and drop into the allocations- or responsible column" ) ); ResourceAllocationView *e = new ResourceAllocationView(part(), ds ); ResourceItemModel *m = new ResourceItemModel( e ); e->setModel( m ); m->setProject( project() ); m->setReadWrite( isReadWrite() ); QList show; show << ResourceModel::ResourceName; for ( int i = m->columnCount() - 1; i >= 0; --i ) { e->setColumnHidden( i, ! show.contains( i ) ); } e->setHeaderHidden( true ); e->setSelectionBehavior( QAbstractItemView::SelectRows ); e->setSelectionMode( QAbstractItemView::ExtendedSelection ); e->expandAll(); e->resizeColumnToContents( ResourceModel::ResourceName ); e->setDragDropMode( QAbstractItemView::DragOnly ); e->setDragEnabled ( true ); ds->setWidget( e ); - connect(m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), e, SLOT(setSelectedTasks(QItemSelection,QItemSelection))); + connect(m_view->selectionModel(), &QItemSelectionModel::selectionChanged, e, &ResourceAllocationView::setSelectedTasks); connect(this, SIGNAL(projectChanged(KPlato::Project*)), m, SLOT(setProject(KPlato::Project*))); - connect(this, SIGNAL(readWriteChanged(bool)), m, SLOT(setReadWrite(bool))); - connect(m, SIGNAL(executeCommand(KUndo2Command*)), part(), SLOT(addCommand(KUndo2Command*))); + connect(this, &ViewBase::readWriteChanged, m, &ItemModelBase::setReadWrite); + connect(m, &ItemModelBase::executeCommand, part(), &KoDocument::addCommand); addDocker( ds ); } { ds = new DockWidget( this, "Taskmodules", xi18nc( "@title", "Task Modules" ) ); ds->setToolTip( xi18nc( "@info:tooltip", "Drag a task module into the Task Editor to add it to the project" ) ); ds->setLocation( Qt::LeftDockWidgetArea ); ds->setShown(false); // hide by default QTreeView *e = new QTreeView( ds ); QSortFilterProxyModel *sf = new QSortFilterProxyModel(e); TaskModuleModel *m = new TaskModuleModel(sf); sf->setSourceModel(m); e->setModel(sf); e->sortByColumn(0, Qt::AscendingOrder); e->setSortingEnabled(true); e->setHeaderHidden( true ); e->setRootIsDecorated( false ); e->setSelectionBehavior( QAbstractItemView::SelectRows ); e->setSelectionMode( QAbstractItemView::SingleSelection ); // e->resizeColumnToContents( 0 ); e->setDragDropMode( QAbstractItemView::DragDrop ); e->setAcceptDrops( true ); e->setDragEnabled ( true ); ds->setWidget( e ); - connect(e, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(taskModuleDoubleClicked(QModelIndex))); - connect(this, SIGNAL(loadTaskModules(QStringList)), m, SLOT(loadTaskModules(QStringList))); - connect(m, SIGNAL(saveTaskModule(QUrl,Project*)), this, SIGNAL(saveTaskModule(QUrl,Project*))); - connect(m, SIGNAL(removeTaskModule(QUrl)), this, SIGNAL(removeTaskModule(QUrl))); + connect(e, &QAbstractItemView::doubleClicked, this, &TaskEditor::taskModuleDoubleClicked); + connect(this, &TaskEditor::loadTaskModules, m, &TaskModuleModel::loadTaskModules); + connect(m, &TaskModuleModel::saveTaskModule, this, &TaskEditor::saveTaskModule); + connect(m, &TaskModuleModel::removeTaskModule, this, &TaskEditor::removeTaskModule); addDocker( ds ); } } void TaskEditor::taskModuleDoubleClicked(QModelIndex idx) { QUrl url = idx.data(Qt::UserRole).toUrl(); if (url.isValid()) { emit openDocument(url); } } void TaskEditor::setTaskModules(const QStringList& files) { emit loadTaskModules( files ); } void TaskEditor::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() && m_view->model()->rowCount() > 0 ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void TaskEditor::slotCurrentChanged( const QModelIndex &curr, const QModelIndex & ) { debugPlan<( selectedNode() ) ); } QModelIndexList TaskEditor::selectedRows() const { #if 0 // Qt bug? return m_view->selectionModel()->selectedRows(); #else QModelIndexList lst; foreach ( QModelIndex i, m_view->selectionModel()->selectedIndexes() ) { if ( i.column() == 0 ) { lst << i; } } return lst; #endif } int TaskEditor::selectedRowCount() const { return selectedRows().count(); } QList TaskEditor::selectedNodes() const { QList lst; foreach ( const QModelIndex &i, selectedRows() ) { Node * n = m_view->baseModel()->node( i ); if ( n != 0 && n->type() != Node::Type_Project ) { lst.append( n ); } } return lst; } Node *TaskEditor::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *TaskEditor::currentNode() const { Node * n = m_view->baseModel()->node( m_view->selectionModel()->currentIndex() ); if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n; } void TaskEditor::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos, const QModelIndexList &rows ) { QString name; if (rows.count() > 1) { debugPlan< summarytasks; QList tasks; QList milestones; for (const QModelIndex &idx : rows) { Node *node = m_view->baseModel()->node( idx ); if (node) { switch ( node->type() ) { case Node::Type_Task: tasks << static_cast(node); break; case Node::Type_Milestone: milestones << static_cast(node); break; case Node::Type_Summarytask: summarytasks << static_cast(node); break; default: break; } } } if (!tasks.isEmpty()) { editTasks(tasks, pos); return; } return; } Node *node = m_view->baseModel()->node( index ); if ( node == 0 ) { return; } debugPlan<name()<<" :"<type() ) { case Node::Type_Project: name = "task_edit_popup"; break; case Node::Type_Task: name = node->isScheduled( baseModel()->id() ) ? "task_popup" : "task_edit_popup"; break; case Node::Type_Milestone: name = node->isScheduled( baseModel()->id() ) ? "taskeditor_milestone_popup" : "task_edit_popup"; break; case Node::Type_Summarytask: name = "summarytask_popup"; break; default: name = "node_popup"; break; } m_view->setContextMenuIndex(index); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); return; } debugPlan<setContextMenuIndex(QModelIndex()); } void TaskEditor::editTasks(const QList &tasks, const QPoint &pos) { QList lst; QAction tasksEdit(i18n( "Edit..."), nullptr); if (!tasks.isEmpty()) { TasksEditController *ted = new TasksEditController(*project(), tasks, this); - connect(&tasksEdit, SIGNAL(triggered(bool)), ted, SLOT(activate())); - connect(ted, SIGNAL(addCommand(KUndo2Command*)), koDocument(), SLOT(addCommand(KUndo2Command*))); + connect(&tasksEdit, &QAction::triggered, ted, &TasksEditController::activate); + connect(ted, &TasksEditController::addCommand, koDocument(), &KoDocument::addCommand); lst << &tasksEdit; } lst += contextActionList(); if (!lst.isEmpty()) { QMenu::exec( lst, pos, lst.first() ); } } void TaskEditor::setScheduleManager( ScheduleManager *sm ) { if (!sm && scheduleManager()) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_view->masterView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); QDomDocument doc; bool expand = sm && scheduleManager(); if (expand) { m_view->masterView()->setObjectName("TaskEditor"); QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_view->baseModel()->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } void TaskEditor::slotEnableActions() { updateActionsEnabled( isReadWrite() ); } void TaskEditor::updateActionsEnabled( bool on ) { // debugPlan<setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); return; } int selCount = selectedRowCount(); if ( selCount == 0 ) { if ( currentNode() ) { // there are tasks but none is selected menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); } else { // we need to be able to add the first task menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); } return; } Node *n = selectedNode(); // 0 if not a single task, summarytask or milestone if ( selCount == 1 && n == 0 ) { // only project selected menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( true ); actionAddSubtask->setEnabled( true ); actionAddSubMilestone->setEnabled( true ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); return; } if ( selCount == 1 && n != currentNode() ) { // multi selection in progress menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( false ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); return; } bool baselined = false; Project *p = m_view->project(); if ( p && p->isBaselined() ) { foreach ( Node *n, selectedNodes() ) { if ( n->isBaselined() ) { baselined = true; break; } } } if ( selCount == 1 ) { menuAddTask->setEnabled( true ); actionAddTask->setEnabled( true ); actionAddMilestone->setEnabled( true ); menuAddSubTask->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionAddSubtask->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionAddSubMilestone->setEnabled( ! baselined || n->type() == Node::Type_Summarytask ); actionDeleteTask->setEnabled( ! baselined ); Node *s = n->siblingBefore(); actionMoveTaskUp->setEnabled( s ); actionMoveTaskDown->setEnabled( n->siblingAfter() ); s = n->siblingBefore(); actionIndentTask->setEnabled( ! baselined && s && ! s->isBaselined() ); actionUnindentTask->setEnabled( ! baselined && n->level() > 1 ); return; } // selCount > 1 menuAddTask->setEnabled( false ); actionAddTask->setEnabled( false ); actionAddMilestone->setEnabled( false ); menuAddSubTask->setEnabled( false ); actionAddSubtask->setEnabled( false ); actionAddSubMilestone->setEnabled( false ); actionDeleteTask->setEnabled( ! baselined ); actionMoveTaskUp->setEnabled( false ); actionMoveTaskDown->setEnabled( false ); actionIndentTask->setEnabled( false ); actionUnindentTask->setEnabled( false ); } void TaskEditor::setupGui() { QString name = "taskeditor_add_list"; menuAddTask = new KActionMenu(koIcon("view-task-add"), i18n("Add Task"), this); actionCollection()->addAction("add_task", menuAddTask ); - connect( menuAddTask, SIGNAL(triggered(bool)), SLOT(slotAddTask()) ); + connect( menuAddTask, &QAction::triggered, this, &TaskEditor::slotAddTask ); addAction( name, menuAddTask ); actionAddTask = new QAction( i18n( "Add Task" ), this); actionAddTask->setShortcut( Qt::CTRL + Qt::Key_I ); - connect( actionAddTask, SIGNAL(triggered(bool)), SLOT(slotAddTask()) ); + connect( actionAddTask, &QAction::triggered, this, &TaskEditor::slotAddTask ); menuAddTask->addAction( actionAddTask ); actionAddMilestone = new QAction( i18n( "Add Milestone" ), this ); actionAddMilestone->setShortcut( Qt::CTRL + Qt::ALT + Qt::Key_I ); - connect( actionAddMilestone, SIGNAL(triggered(bool)), SLOT(slotAddMilestone()) ); + connect( actionAddMilestone, &QAction::triggered, this, &TaskEditor::slotAddMilestone ); menuAddTask->addAction( actionAddMilestone ); menuAddSubTask = new KActionMenu(koIcon("view-task-child-add"), i18n("Add Sub-Task"), this); actionCollection()->addAction("add_subtask", menuAddTask ); - connect( menuAddSubTask, SIGNAL(triggered(bool)), SLOT(slotAddSubtask()) ); + connect( menuAddSubTask, &QAction::triggered, this, &TaskEditor::slotAddSubtask ); addAction( name, menuAddSubTask ); actionAddSubtask = new QAction( i18n( "Add Sub-Task" ), this ); actionAddSubtask->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_I ); - connect( actionAddSubtask, SIGNAL(triggered(bool)), SLOT(slotAddSubtask()) ); + connect( actionAddSubtask, &QAction::triggered, this, &TaskEditor::slotAddSubtask ); menuAddSubTask->addAction( actionAddSubtask ); actionAddSubMilestone = new QAction( i18n( "Add Sub-Milestone" ), this ); actionAddSubMilestone->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::ALT + Qt::Key_I ); - connect( actionAddSubMilestone, SIGNAL(triggered(bool)), SLOT(slotAddSubMilestone()) ); + connect( actionAddSubMilestone, &QAction::triggered, this, &TaskEditor::slotAddSubMilestone ); menuAddSubTask->addAction( actionAddSubMilestone ); actionDeleteTask = new QAction(koIcon("edit-delete"), xi18nc("@action", "Delete"), this); actionCollection()->setDefaultShortcut( actionDeleteTask, Qt::Key_Delete ); actionCollection()->addAction("delete_task", actionDeleteTask ); - connect( actionDeleteTask, SIGNAL(triggered(bool)), SLOT(slotDeleteTask()) ); + connect( actionDeleteTask, &QAction::triggered, this, &TaskEditor::slotDeleteTask ); addAction( name, actionDeleteTask ); name = "taskeditor_move_list"; actionIndentTask = new QAction(koIcon("format-indent-more"), i18n("Indent Task"), this); actionCollection()->addAction("indent_task", actionIndentTask ); - connect(actionIndentTask, SIGNAL(triggered(bool)), SLOT(slotIndentTask())); + connect(actionIndentTask, &QAction::triggered, this, &TaskEditor::slotIndentTask); addAction( name, actionIndentTask ); actionUnindentTask = new QAction(koIcon("format-indent-less"), i18n("Unindent Task"), this); actionCollection()->addAction("unindent_task", actionUnindentTask ); - connect(actionUnindentTask, SIGNAL(triggered(bool)), SLOT(slotUnindentTask())); + connect(actionUnindentTask, &QAction::triggered, this, &TaskEditor::slotUnindentTask); addAction( name, actionUnindentTask ); actionMoveTaskUp = new QAction(koIcon("arrow-up"), i18n("Move Up"), this); actionCollection()->addAction("move_task_up", actionMoveTaskUp ); - connect(actionMoveTaskUp, SIGNAL(triggered(bool)), SLOT(slotMoveTaskUp())); + connect(actionMoveTaskUp, &QAction::triggered, this, &TaskEditor::slotMoveTaskUp); addAction( name, actionMoveTaskUp ); actionMoveTaskDown = new QAction(koIcon("arrow-down"), i18n("Move Down"), this); actionCollection()->addAction("move_task_down", actionMoveTaskDown ); - connect(actionMoveTaskDown, SIGNAL(triggered(bool)), SLOT(slotMoveTaskDown())); + connect(actionMoveTaskDown, &QAction::triggered, this, &TaskEditor::slotMoveTaskDown); addAction( name, actionMoveTaskDown ); // Add the context menu actions for the view options actionShowProject = new KToggleAction( i18n( "Show Project" ), this ); - connect(actionShowProject, SIGNAL(triggered(bool)), baseModel(), SLOT(setShowProject(bool))); + connect(actionShowProject, &QAction::triggered, baseModel(), &NodeItemModel::setShowProject); addContextAction( actionShowProject ); - connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &TaskEditor::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionAll); createDockers(); } void TaskEditor::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskEditor::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } void TaskEditor::slotAddTask() { debugPlan; if ( selectedRowCount() == 0 || ( selectedRowCount() == 1 && selectedNode() == 0 ) ) { m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); QModelIndex idx = m_view->baseModel()->insertSubtask( t, m_view->project() ); Q_ASSERT( idx.isValid() ); edit( idx ); return; } Node *sib = selectedNode(); if ( sib == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); QModelIndex idx = m_view->baseModel()->insertTask( t, sib ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::slotAddMilestone() { debugPlan; if ( selectedRowCount() == 0 || ( selectedRowCount() == 1 && selectedNode() == 0 ) ) { // None selected or only project selected: insert under main project m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask(); t->estimate()->clear(); QModelIndex idx = m_view->baseModel()->insertSubtask( t, m_view->project() ); Q_ASSERT( idx.isValid() ); edit( idx ); return; } Node *sib = selectedNode(); // sibling if ( sib == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask(); t->estimate()->clear(); QModelIndex idx = m_view->baseModel()->insertTask( t, sib ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::slotAddSubMilestone() { debugPlan; Node *parent = selectedNode(); if ( parent == 0 && selectedRowCount() == 1 ) { // project selected parent = m_view->project(); } if ( parent == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); t->estimate()->clear(); QModelIndex idx = m_view->baseModel()->insertSubtask( t, parent ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::slotAddSubtask() { debugPlan; Node *parent = selectedNode(); if ( parent == 0 && selectedRowCount() == 1 ) { // project selected parent = m_view->project(); } if ( parent == 0 ) { return; } m_view->closePersistentEditor( m_view->selectionModel()->currentIndex() ); Task *t = m_view->project()->createTask( m_view->project()->taskDefaults() ); QModelIndex idx = m_view->baseModel()->insertSubtask( t, parent ); Q_ASSERT( idx.isValid() ); edit( idx ); } void TaskEditor::edit( const QModelIndex &i ) { if ( i.isValid() ) { m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->setParentsExpanded( i, true ); // in case treeview does not have focus m_view->edit( i ); } } void TaskEditor::slotDeleteTask() { //debugPlan; QList lst = selectedNodes(); while ( true ) { // remove children of selected tasks, as parents delete their children Node *ch = 0; foreach ( Node *n1, lst ) { foreach ( Node *n2, lst ) { if ( n2->isChildOf( n1 ) ) { ch = n2; break; } } if ( ch != 0 ) { break; } } if ( ch == 0 ) { break; } lst.removeAt( lst.indexOf( ch ) ); } //foreach ( Node* n, lst ) { debugPlan<name(); } emit deleteTaskList( lst ); QModelIndex i = m_view->selectionModel()->currentIndex(); if ( i.isValid() ) { m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } void TaskEditor::slotIndentTask() { debugPlan; Node *n = selectedNode(); if ( n ) { emit indentTask(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); m_view->setParentsExpanded( i, true ); } } void TaskEditor::slotUnindentTask() { debugPlan; Node *n = selectedNode(); if ( n ) { emit unindentTask(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } void TaskEditor::slotMoveTaskUp() { debugPlan; Node *n = selectedNode(); if ( n ) { emit moveTaskUp(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } void TaskEditor::slotMoveTaskDown() { debugPlan; Node *n = selectedNode(); if ( n ) { emit moveTaskDown(); QModelIndex i = baseModel()->index( n ); m_view->selectionModel()->select( i, QItemSelectionModel::Rows | QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect ); m_view->selectionModel()->setCurrentIndex( i, QItemSelectionModel::NoUpdate ); } } bool TaskEditor::loadContext( const KoXmlElement &context ) { ViewBase::loadContext( context ); bool show = (bool)(context.attribute( "show-project", "0" ).toInt() ); actionShowProject->setChecked( show ); baseModel()->setShowProject( show ); // why is this not called by the action? bool res = m_view->loadContext( baseModel()->columnMap(), context ); return res; } void TaskEditor::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); context.setAttribute( "show-project", QString::number(baseModel()->projectShown()) ); m_view->saveContext( baseModel()->columnMap(), context ); } KoPrintJob *TaskEditor::createPrintJob() { return m_view->createPrintJob( this ); } //----------------------------------- TaskView::TaskView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new NodeTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); NodeSortFilterProxyModel *p = new NodeSortFilterProxyModel( m_view->baseModel(), m_view ); m_view->setModel( p ); l->addWidget( m_view ); setupGui(); //m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::InternalMove ); m_view->setDropIndicatorShown( false ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( false ); m_view->setAcceptDropsOnView( false ); QList readonly; readonly << NodeModel::NodeName << NodeModel::NodeResponsible << NodeModel::NodeAllocation << NodeModel::NodeEstimateType << NodeModel::NodeEstimateCalendar << NodeModel::NodeEstimate << NodeModel::NodeOptimisticRatio << NodeModel::NodePessimisticRatio << NodeModel::NodeRisk << NodeModel::NodeConstraint << NodeModel::NodeConstraintStart << NodeModel::NodeConstraintEnd << NodeModel::NodeRunningAccount << NodeModel::NodeStartupAccount << NodeModel::NodeStartupCost << NodeModel::NodeShutdownAccount << NodeModel::NodeShutdownCost << NodeModel::NodeDescription; foreach ( int c, readonly ) { m_view->baseModel()->setReadOnly( c, true ); } QList lst1; lst1 << 1 << -1; QList show; show << NodeModel::NodeStatus << NodeModel::NodeCompleted << NodeModel::NodeResponsible << NodeModel::NodeAssignments << NodeModel::NodePerformanceIndex << NodeModel::NodeBCWS << NodeModel::NodeBCWP << NodeModel::NodeACWP << NodeModel::NodeDescription; for ( int s = 0; s < show.count(); ++s ) { m_view->slaveView()->mapToSection( show[s], s ); } QList lst2; for ( int i = 0; i < m_view->model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << 0 ); m_view->slaveView()->setDefaultColumns( show ); - connect( m_view->baseModel(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( m_view->baseModel(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &TaskView::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &TaskView::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &TaskView::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Task Execution View" "" "The view is used to edit and inspect task progress during project execution." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Task_Execution_View"))); } void TaskView::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } void TaskView::draw( Project &project ) { m_view->setProject( &project ); } void TaskView::draw() { } void TaskView::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() && m_view->model()->rowCount() > 0 ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void TaskView::slotCurrentChanged( const QModelIndex &curr, const QModelIndex & ) { debugPlan<selectionModel(); return sm->selectedRows().count(); } QList TaskView::selectedNodes() const { QList lst; QItemSelectionModel* sm = m_view->selectionModel(); if ( sm == 0 ) { return lst; } foreach ( const QModelIndex &i, sm->selectedRows() ) { Node * n = m_view->baseModel()->node( proxyModel()->mapToSource( i ) ); if ( n != 0 && n->type() != Node::Type_Project ) { lst.append( n ); } } return lst; } Node *TaskView::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *TaskView::currentNode() const { Node * n = m_view->baseModel()->node( proxyModel()->mapToSource( m_view->selectionModel()->currentIndex() ) ); if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n; } void TaskView::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { QString name; Node *node = m_view->baseModel()->node( proxyModel()->mapToSource( index ) ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node: "<setContextMenuIndex(index); emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } void TaskView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<masterView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); QDomDocument doc; bool expand = sm && scheduleManager() && sm != scheduleManager(); if (expand) { m_view->masterView()->setObjectName("TaskEditor"); QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_view->baseModel()->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } void TaskView::slotEnableActions() { updateActionsEnabled( true ); } void TaskView::updateActionsEnabled( bool /*on*/ ) { } void TaskView::setupGui() { // KActionCollection *coll = actionCollection(); // Add the context menu actions for the view options actionShowProject = new KToggleAction( i18n( "Show Project" ), this ); - connect(actionShowProject, SIGNAL(triggered(bool)), baseModel(), SLOT(setShowProject(bool))); + connect(actionShowProject, &QAction::triggered, baseModel(), &NodeItemModel::setShowProject); addContextAction( actionShowProject ); - connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &TaskView::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionAll); } void TaskView::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskView::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool TaskView::loadContext( const KoXmlElement &context ) { ViewBase::loadContext( context ); bool show = (bool)(context.attribute( "show-project", "0" ).toInt() ); actionShowProject->setChecked( show ); baseModel()->setShowProject( show ); // why is this not called by the action? return m_view->loadContext( m_view->baseModel()->columnMap(), context ); } void TaskView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); context.setAttribute( "show-project", QString::number(baseModel()->projectShown()) ); m_view->saveContext( m_view->baseModel()->columnMap(), context ); } KoPrintJob *TaskView::createPrintJob() { return m_view->createPrintJob( this ); } //--------------------------------- WorkPackageTreeView::WorkPackageTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { debugPlan<<"----------"<baseModel(); } void WorkPackageTreeView::slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ) { Q_UNUSED(index); Q_UNUSED(dropIndicatorPosition); Q_UNUSED(event); /* QModelIndex idx = index; NodeSortFilterProxyModel *pr = proxyModel(); if ( pr ) { idx = pr->mapToSource( index ); } event->ignore(); if ( baseModel()->dropAllowed( idx, dropIndicatorPosition, event->mimeData() ) ) { event->accept(); }*/ } //-------------------------------- TaskWorkPackageView::TaskWorkPackageView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent ), m_cmd( 0 ) { QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new WorkPackageTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); l->addWidget( m_view ); setupGui(); //m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); m_view->setDragDropMode( QAbstractItemView::InternalMove ); m_view->setDropIndicatorShown( false ); m_view->setDragEnabled ( true ); m_view->setAcceptDrops( false ); m_view->setAcceptDropsOnView( false ); QList readonly; readonly << NodeModel::NodeName << NodeModel::NodeResponsible << NodeModel::NodeAllocation << NodeModel::NodeEstimateType << NodeModel::NodeEstimateCalendar << NodeModel::NodeEstimate << NodeModel::NodeOptimisticRatio << NodeModel::NodePessimisticRatio << NodeModel::NodeRisk << NodeModel::NodeConstraint << NodeModel::NodeConstraintStart << NodeModel::NodeConstraintEnd << NodeModel::NodeRunningAccount << NodeModel::NodeStartupAccount << NodeModel::NodeStartupCost << NodeModel::NodeShutdownAccount << NodeModel::NodeShutdownCost << NodeModel::NodeDescription; foreach ( int c, readonly ) { m_view->baseModel()->setReadOnly( c, true ); } QList lst1; lst1 << 1 << -1; QList show; show << NodeModel::NodeStatus << NodeModel::NodeCompleted << NodeModel::NodeResponsible << NodeModel::NodeAssignments << NodeModel::NodeDescription; for ( int s = 0; s < show.count(); ++s ) { m_view->slaveView()->mapToSection( show[s], s ); } QList lst2; for ( int i = 0; i < m_view->model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } m_view->hideColumns( lst1, lst2 ); m_view->masterView()->setDefaultColumns( QList() << 0 ); m_view->slaveView()->setDefaultColumns( show ); - connect( m_view->baseModel(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( m_view->baseModel(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); - connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( m_view, &DoubleTreeViewBase::currentChanged, this, &TaskWorkPackageView::slotCurrentChanged ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &DoubleTreeViewBase::selectionChanged, this, &TaskWorkPackageView::slotSelectionChanged ); - connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); + connect( m_view, &DoubleTreeViewBase::contextMenuRequested, this, &TaskWorkPackageView::slotContextMenuRequested ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); } Project *TaskWorkPackageView::project() const { return m_view->project(); } void TaskWorkPackageView::setProject( Project *project ) { m_view->setProject( project ); } WorkPackageProxyModel *TaskWorkPackageView::proxyModel() const { return m_view->proxyModel(); } void TaskWorkPackageView::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); ViewBase::updateReadWrite( rw ); } void TaskWorkPackageView::setGuiActive( bool activate ) { debugPlan<selectionModel()->currentIndex().isValid() && m_view->model()->rowCount() > 0 ) { m_view->selectionModel()->setCurrentIndex(m_view->model()->index( 0, 0 ), QItemSelectionModel::NoUpdate); } } void TaskWorkPackageView::slotRefreshView() { emit checkForWorkPackages(); } void TaskWorkPackageView::slotCurrentChanged( const QModelIndex &curr, const QModelIndex & ) { debugPlan<selectionModel(); return sm->selectedRows().count(); } QList TaskWorkPackageView::selectedNodes() const { QList lst; QItemSelectionModel* sm = m_view->selectionModel(); if ( sm == 0 ) { return lst; } foreach ( const QModelIndex &i, sm->selectedRows() ) { Node * n = proxyModel()->taskFromIndex( i ); if ( n != 0 && n->type() != Node::Type_Project ) { lst.append( n ); } } return lst; } Node *TaskWorkPackageView::selectedNode() const { QList lst = selectedNodes(); if ( lst.count() != 1 ) { return 0; } return lst.first(); } Node *TaskWorkPackageView::currentNode() const { Node * n = proxyModel()->taskFromIndex( m_view->selectionModel()->currentIndex() ); if ( n == 0 || n->type() == Node::Type_Project ) { return 0; } return n; } void TaskWorkPackageView::slotContextMenuRequested( const QModelIndex& index, const QPoint& pos ) { QString name; Node *node = proxyModel()->taskFromIndex( index ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "workpackage_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node: "<setContextMenuIndex(index); emit requestPopupMenu( name, pos ); m_view->setContextMenuIndex(QModelIndex()); } void TaskWorkPackageView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<baseModel()->setScheduleManager( sm ); } void TaskWorkPackageView::slotEnableActions() { updateActionsEnabled( true ); } void TaskWorkPackageView::updateActionsEnabled( bool on ) { bool o = ! selectedNodes().isEmpty(); actionMailWorkpackage->setEnabled( o && on ); } void TaskWorkPackageView::setupGui() { // KActionCollection *coll = actionCollection(); QString name = "workpackage_list"; actionMailWorkpackage = new QAction(koIcon("mail-send"), i18n("Send..."), this); actionCollection()->setDefaultShortcut( actionMailWorkpackage, Qt::CTRL + Qt::Key_M ); actionCollection()->addAction("send_workpackage", actionMailWorkpackage ); - connect( actionMailWorkpackage, SIGNAL(triggered(bool)), SLOT(slotMailWorkpackage()) ); + connect( actionMailWorkpackage, &QAction::triggered, this, &TaskWorkPackageView::slotMailWorkpackage ); addAction( name, actionMailWorkpackage ); // Add the context menu actions for the view options - connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &TaskWorkPackageView::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionAll); } void TaskWorkPackageView::slotMailWorkpackage() { QList lst = selectedNodes(); if ( ! lst.isEmpty() ) { // TODO find a better way to log to avoid undo/redo m_cmd = new MacroCommand( kundo2_i18n( "Log Send Workpackage" ) ); QPointer dlg = new WorkPackageSendDialog( lst, scheduleManager(), this ); - connect ( dlg->panel(), SIGNAL(sendWorkpackages(QList,Resource*)), this, SIGNAL(mailWorkpackages(QList,Resource*)) ); + connect ( dlg->panel(), &WorkPackageSendPanel::sendWorkpackages, this, &TaskWorkPackageView::mailWorkpackages ); - connect ( dlg->panel(), SIGNAL(sendWorkpackages(QList,Resource*)), this, SLOT(slotWorkPackageSent(QList,Resource*)) ); + connect ( dlg->panel(), &WorkPackageSendPanel::sendWorkpackages, this, &TaskWorkPackageView::slotWorkPackageSent ); dlg->exec(); delete dlg; if ( ! m_cmd->isEmpty() ) { part()->addCommand( m_cmd ); m_cmd = 0; } delete m_cmd; m_cmd = 0; } } void TaskWorkPackageView::slotWorkPackageSent( const QList &nodes, Resource *resource ) { foreach ( Node *n, nodes ) { WorkPackage *wp = new WorkPackage( static_cast( n )->workPackage() ); wp->setOwnerName( resource->name() ); wp->setOwnerId( resource->id() ); wp->setTransmitionTime( DateTime::currentDateTime() ); wp->setTransmitionStatus( WorkPackage::TS_Send ); m_cmd->addCommand( new WorkPackageAddCmd( static_cast( n->projectNode() ), n, wp ) ); } } void TaskWorkPackageView::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskWorkPackageView::slotOptions() { debugPlan; SplitItemViewSettupDialog *dlg = new SplitItemViewSettupDialog( this, m_view, this ); dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool TaskWorkPackageView::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); return m_view->loadContext( m_view->baseModel()->columnMap(), context ); } void TaskWorkPackageView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); m_view->saveContext( m_view->baseModel()->columnMap(), context ); } KoPrintJob *TaskWorkPackageView::createPrintJob() { return m_view->createPrintJob( this ); } } // namespace KPlato diff --git a/src/libs/ui/kpttaskgeneralpanel.cpp b/src/libs/ui/kpttaskgeneralpanel.cpp index b3c2974e..db920146 100644 --- a/src/libs/ui/kpttaskgeneralpanel.cpp +++ b/src/libs/ui/kpttaskgeneralpanel.cpp @@ -1,577 +1,577 @@ /* This file is part of the KDE project Copyright (C) 2004 - 2007, 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. */ #include "kpttaskgeneralpanel.h" #include "kpttaskdialog.h" #include "kpttask.h" #include "kptcommand.h" #include "kptduration.h" #include "kptdurationspinbox.h" #include "kptcalendar.h" #include "kptdatetime.h" #include "kptproject.h" #include #ifdef PLAN_KDEPIMLIBS_FOUND #include #include #include #endif #include #include namespace KPlato { TaskGeneralPanel::TaskGeneralPanel(Project &project, Task &task, QWidget *p, const char *n) : TaskGeneralPanelImpl(p, n), m_task(task), m_project( project ) { useTime = true; setStartValues( task ); QString s = i18n( "The Work Breakdown Structure introduces numbering for all tasks in the project, according to the task structure.\nThe WBS code is auto-generated.\nYou can define the WBS code pattern using the Define WBS Pattern command in the Tools menu." ); wbslabel->setWhatsThis( s ); wbsfield->setWhatsThis( s ); if ( task.isBaselined( BASELINESCHEDULE ) ) { schedulingGroup->setEnabled( false ); } } void TaskGeneralPanel::setStartValues( Task &task ) { m_estimate = m_duration = task.estimate()->expectedValue(); namefield->setText(task.name()); leaderfield->setText(task.leader()); wbsfield->setText(task.wbsCode()); int cal = 0; m_calendars.clear(); calendarCombo->addItem(i18n("None")); m_calendars.insert(0, 0); QList list = m_project.allCalendars(); int i=1; foreach (Calendar *c, list) { calendarCombo->insertItem(i, c->name()); m_calendars.insert(i, c); if (c == task.estimate()->calendar()) { cal = i; } ++i; } calendarCombo->setCurrentIndex(cal); estimate->setMinimumUnit( (Duration::Unit)(m_project.config().minimumDurationUnit()) ); estimate->setMaximumUnit( (Duration::Unit)(m_project.config().maximumDurationUnit()) ); estimate->setUnit( task.estimate()->unit() ); setEstimateType(task.estimate()->type()); if (task.estimate()->type() == Estimate::Type_Effort && task.estimate()->expectedEstimate() == 0.0) { setEstimateType(2 /*Milestone*/); } setSchedulingType(task.constraint()); if (task.constraintStartTime().isValid()) { setStartDateTime(task.constraintStartTime()); } else { QDate date = QDate::currentDate(); setStartDateTime(QDateTime(date, QTime(), Qt::LocalTime)); } if (task.constraintEndTime().isValid()) { setEndDateTime(task.constraintEndTime()); } else { setEndDateTime(QDateTime(startDate().addDays(1), QTime(), Qt::LocalTime)); } //debugPlan<<"Estimate:"<expected().toString(); setEstimate(task.estimate()->expectedEstimate()); setOptimistic(task.estimate()->optimisticRatio()); setPessimistic(task.estimate()->pessimisticRatio()); setRisktype(task.estimate()->risktype()); namefield->setFocus(); } MacroCommand *TaskGeneralPanel::buildCommand() { MacroCommand *cmd = new MacroCommand(kundo2_i18n("Modify Task")); bool modified = false; if (!namefield->isHidden() && m_task.name() != namefield->text()) { cmd->addCommand(new NodeModifyNameCmd(m_task, namefield->text())); modified = true; } if (!leaderfield->isHidden() && m_task.leader() != leaderfield->text()) { cmd->addCommand(new NodeModifyLeaderCmd(m_task, leaderfield->text())); modified = true; } Node::ConstraintType c = (Node::ConstraintType)schedulingType(); if (c != m_task.constraint()) { cmd->addCommand(new NodeModifyConstraintCmd(m_task, c)); modified = true; } if (startDateTime() != m_task.constraintStartTime() && (c == Node::FixedInterval || c == Node::StartNotEarlier || c == Node::MustStartOn)) { cmd->addCommand(new NodeModifyConstraintStartTimeCmd(m_task, startDateTime())); modified = true; } if (endDateTime() != m_task.constraintEndTime() && (c == Node::FinishNotLater || c == Node::FixedInterval || c == Node::MustFinishOn)) { cmd->addCommand(new NodeModifyConstraintEndTimeCmd(m_task, endDateTime())); modified = true; } int et = estimationType(); if (et == 2 /*Milestome*/) { et = 0; /*Effort*/ } if (et != m_task.estimate()->type()) { cmd->addCommand(new ModifyEstimateTypeCmd(m_task, m_task.estimate()->type(), et)); modified = true; } bool unitchanged = estimate->unit() != m_task.estimate()->unit(); if ( unitchanged ) { cmd->addCommand( new ModifyEstimateUnitCmd( m_task, m_task.estimate()->unit(), estimate->unit() ) ); modified = true; } bool expchanged = estimationValue() != m_task.estimate()->expectedEstimate(); if ( expchanged ) { cmd->addCommand(new ModifyEstimateCmd(m_task, m_task.estimate()->expectedEstimate(), estimationValue())); modified = true; } int x = optimistic(); if ( x != m_task.estimate()->optimisticRatio() || expchanged || unitchanged ) { cmd->addCommand(new EstimateModifyOptimisticRatioCmd(m_task, m_task.estimate()->optimisticRatio(), x)); modified = true; } x = pessimistic(); if ( x != m_task.estimate()->pessimisticRatio() || expchanged || unitchanged ) { cmd->addCommand(new EstimateModifyPessimisticRatioCmd(m_task, m_task.estimate()->pessimisticRatio(), x)); modified = true; } if (m_task.estimate()->risktype() != risktype()) { cmd->addCommand(new EstimateModifyRiskCmd(m_task, m_task.estimate()->risktype(), risktype())); modified = true; } if (m_task.estimate()->calendar() != calendar()) { cmd->addCommand(new ModifyEstimateCalendarCmd(m_task, m_task.estimate()->calendar(), calendar())); modified = true; } if (!modified) { delete cmd; return 0; } return cmd; } bool TaskGeneralPanel::ok() { return true; } void TaskGeneralPanel::estimationTypeChanged(int type) { if (type == 0 /*Effort*/) { estimate->setEnabled(true); calendarCombo->setEnabled(false); } else if ( type == 1 /*Duration*/ ) { calendarCombo->setEnabled(false); if (schedulingType() == 6) { /*Fixed interval*/ estimate->setEnabled(false); } else { estimate->setEnabled(true); calendarCombo->setEnabled(true); } } else if ( type == 2 /* Milestone */ ) { estimate->setValue( 0 ); estimate->setEnabled(false); calendarCombo->setEnabled(false); } TaskGeneralPanelImpl::estimationTypeChanged(type); } void TaskGeneralPanel::scheduleTypeChanged(int value) { if (value == 6 /*Fixed interval*/) { if (estimateType->currentIndex() == 1/*duration*/){ // setEstimateScales(24); estimate->setEnabled(false); //TODO setEstimate( DateTime( endDateTime(), KDateTime::UTC) - DateTime( startDateTime(), KDateTime::UTC ) ); } } else { estimate->setEnabled(true); } TaskGeneralPanelImpl::scheduleTypeChanged(value); } //----------------------------- TaskGeneralPanelImpl::TaskGeneralPanelImpl(QWidget *p, const char *n) : QWidget(p) { setObjectName(n); setupUi(this); #ifndef PLAN_KDEPIMLIBS_FOUND chooseLeader->hide(); #endif // FIXME // [Bug 311940] New: Plan crashes when typing a text in the filter textbox before the textbook is fully loaded when selecting a contact from the adressbook chooseLeader->hide(); - connect(namefield, SIGNAL(textChanged(QString)), SLOT(checkAllFieldsFilled())); - connect(leaderfield, SIGNAL(textChanged(QString)), SLOT(checkAllFieldsFilled())); - connect(chooseLeader, SIGNAL(clicked()), SLOT(changeLeader())); + connect(namefield, &QLineEdit::textChanged, this, &TaskGeneralPanelImpl::checkAllFieldsFilled); + connect(leaderfield, &QLineEdit::textChanged, this, &TaskGeneralPanelImpl::checkAllFieldsFilled); + connect(chooseLeader, &QAbstractButton::clicked, this, &TaskGeneralPanelImpl::changeLeader); connect(estimateType, SIGNAL(activated(int)), SLOT(estimationTypeChanged(int))); connect(scheduleType, SIGNAL(activated(int)), SLOT(scheduleTypeChanged(int))); - connect(scheduleStartDate, SIGNAL(dateChanged(QDate)), SLOT(startDateChanged())); - connect(scheduleStartTime, SIGNAL(timeChanged(QTime)), SLOT(startTimeChanged(QTime))); - connect(scheduleEndDate, SIGNAL(dateChanged(QDate)), SLOT(endDateChanged())); - connect(scheduleEndTime, SIGNAL(timeChanged(QTime)), SLOT(endTimeChanged(QTime))); + connect(scheduleStartDate, &QDateTimeEdit::dateChanged, this, &TaskGeneralPanelImpl::startDateChanged); + connect(scheduleStartTime, &QDateTimeEdit::timeChanged, this, &TaskGeneralPanelImpl::startTimeChanged); + connect(scheduleEndDate, &QDateTimeEdit::dateChanged, this, &TaskGeneralPanelImpl::endDateChanged); + connect(scheduleEndTime, &QDateTimeEdit::timeChanged, this, &TaskGeneralPanelImpl::endTimeChanged); connect(estimate, SIGNAL(valueChanged(double)), SLOT(checkAllFieldsFilled())); connect(optimisticValue, SIGNAL(valueChanged(int)), SLOT(checkAllFieldsFilled())); connect(pessimisticValue, SIGNAL(valueChanged(int)), SLOT(checkAllFieldsFilled())); connect(risk, SIGNAL(activated(int)), SLOT(checkAllFieldsFilled())); connect(calendarCombo, SIGNAL(activated(int)), SLOT(calendarChanged(int))); } void TaskGeneralPanelImpl::setSchedulingType(int type) { enableDateTime(type); scheduleType->setCurrentIndex(type); emit schedulingTypeChanged(type); } int TaskGeneralPanelImpl::schedulingType() const { return scheduleType->currentIndex(); } void TaskGeneralPanelImpl::changeLeader() { #ifdef PLAN_KDEPIMLIBS_FOUND QPointer dlg = new Akonadi::EmailAddressSelectionDialog( this ); if ( dlg->exec() && dlg ) { QStringList names; const Akonadi::EmailAddressSelection::List selections = dlg->selectedAddresses(); foreach ( const Akonadi::EmailAddressSelection &selection, selections ) { QString s = selection.name(); if ( ! selection.email().isEmpty() ) { if ( ! selection.name().isEmpty() ) { s += " <"; } s += selection.email(); if ( ! selection.name().isEmpty() ) { s += '>'; } if ( ! s.isEmpty() ) { names << s; } } } if ( ! names.isEmpty() ) { leaderfield->setText( names.join( ", " ) ); } } #endif } void TaskGeneralPanelImpl::setEstimationType( int type ) { estimateType->setCurrentIndex(type); } int TaskGeneralPanelImpl::estimationType() const { return estimateType->currentIndex(); } void TaskGeneralPanelImpl::setOptimistic( int value ) { optimisticValue->setValue(value); } void TaskGeneralPanelImpl::setPessimistic( int value ) { pessimisticValue->setValue(value); } int TaskGeneralPanelImpl::optimistic() const { return optimisticValue->value(); } int TaskGeneralPanelImpl::pessimistic() { return pessimisticValue->value(); } void TaskGeneralPanelImpl::enableDateTime( int scheduleType ) { scheduleStartTime->setEnabled(false); scheduleEndTime->setEnabled(false); scheduleStartDate->setEnabled(false); scheduleEndDate->setEnabled(false); switch (scheduleType) { case 0: //ASAP case 1: //ALAP break; case 2: //Must start on case 4: // Start not earlier if (useTime) { scheduleStartTime->setEnabled(true); scheduleEndTime->setEnabled(false); } scheduleStartDate->setEnabled(true); scheduleEndDate->setEnabled(false); break; case 3: //Must finish on case 5: // Finish not later if (useTime) { scheduleStartTime->setEnabled(false); scheduleEndTime->setEnabled(true); } scheduleStartDate->setEnabled(false); scheduleEndDate->setEnabled(true); break; case 6: //Fixed interval if (useTime) { scheduleStartTime->setEnabled(true); scheduleEndTime->setEnabled(true); } scheduleStartDate->setEnabled(true); scheduleEndDate->setEnabled(true); break; default: break; } } void TaskGeneralPanelImpl::estimationTypeChanged( int /*type*/ ) { checkAllFieldsFilled(); } void TaskGeneralPanelImpl::calendarChanged( int /*index*/ ) { checkAllFieldsFilled(); } void TaskGeneralPanelImpl::setEstimate( double duration) { estimate->setValue( duration ); } void TaskGeneralPanelImpl::setEstimateType( int type) { estimateType->setCurrentIndex(type); estimationTypeChanged( type ); } void TaskGeneralPanelImpl::checkAllFieldsFilled() { emit changed(); emit obligatedFieldsFilled(true); // do not block save even if name is not filled } double TaskGeneralPanelImpl::estimationValue() { return estimate->value(); } void TaskGeneralPanelImpl::startDateChanged() { if (!scheduleStartDate->isEnabled()) { return; } QDate date = startDate(); if (startDateTime() > endDateTime()) { scheduleEndTime->blockSignals(true); scheduleEndDate->blockSignals(true); setEndDate(date); setEndTime(startTime()); scheduleEndTime->blockSignals(false); scheduleEndDate->blockSignals(false); } if (scheduleType->currentIndex() == 6 /*FixedInterval*/) { estimationTypeChanged(estimateType->currentIndex()); } checkAllFieldsFilled(); } void TaskGeneralPanelImpl::startTimeChanged( const QTime &time ) { if (!scheduleStartTime->isEnabled()) { return; } if (startDateTime() > endDateTime()) { scheduleEndTime->blockSignals(true); setEndTime(time); scheduleEndTime->blockSignals(false); } if (scheduleType->currentIndex() == 6 /*FixedInterval*/) { estimationTypeChanged(estimateType->currentIndex()); } checkAllFieldsFilled(); } void TaskGeneralPanelImpl::endDateChanged() { if (!scheduleEndDate->isEnabled()) { return; } QDate date = endDate(); if (endDateTime() < startDateTime()) { scheduleStartTime->blockSignals(true); scheduleStartDate->blockSignals(true); setStartDate(date); setStartTime(endTime()); scheduleStartTime->blockSignals(false); scheduleStartDate->blockSignals(false); } if (scheduleType->currentIndex() == 6 /*FixedInterval*/) { estimationTypeChanged(estimateType->currentIndex()); } checkAllFieldsFilled(); } void TaskGeneralPanelImpl::endTimeChanged( const QTime &time ) { if (!scheduleEndTime->isEnabled()) { return; } if (endDateTime() < startDateTime()) { scheduleStartTime->blockSignals(true); setStartTime(time); scheduleStartTime->blockSignals(false); } if (scheduleType->currentIndex() == 6 /*FixedInterval*/) { estimationTypeChanged(estimateType->currentIndex()); } checkAllFieldsFilled(); } void TaskGeneralPanelImpl::scheduleTypeChanged( int value ) { estimationTypeChanged(estimateType->currentIndex()); enableDateTime(value); checkAllFieldsFilled(); } QDateTime TaskGeneralPanelImpl::startDateTime() { return QDateTime(startDate(), startTime(), Qt::LocalTime); } QDateTime TaskGeneralPanelImpl::endDateTime() { return QDateTime(endDate(), endTime(), Qt::LocalTime); } void TaskGeneralPanelImpl::setStartTime( const QTime &time ) { scheduleStartTime->setTime( QTime( time.hour(), time.minute(), 0 ) ); } void TaskGeneralPanelImpl::setEndTime( const QTime &time ) { scheduleEndTime->setTime( QTime( time.hour(), time.minute(), 0 ) ); } QTime TaskGeneralPanelImpl::startTime() const { QTime t = scheduleStartTime->time(); t.setHMS( t.hour(), t.minute(), 0 ); return t; } QTime TaskGeneralPanelImpl::endTime() { QTime t = scheduleEndTime->time(); t.setHMS( t.hour(), t.minute(), 0 ); return t; } QDate TaskGeneralPanelImpl::startDate() { return scheduleStartDate->date(); } QDate TaskGeneralPanelImpl::endDate() { return scheduleEndDate->date(); } void TaskGeneralPanelImpl::setStartDateTime( const QDateTime &dt ) { setStartDate(dt.date()); setStartTime(dt.time()); } void TaskGeneralPanelImpl::setEndDateTime( const QDateTime &dt ) { setEndDate(dt.date()); setEndTime(dt.time()); } void TaskGeneralPanelImpl::setStartDate( const QDate &date ) { scheduleStartDate->setDate(date); } void TaskGeneralPanelImpl::setEndDate( const QDate &date ) { scheduleEndDate->setDate(date); } void TaskGeneralPanelImpl::setRisktype( int r ) { risk->setCurrentIndex(r); } int TaskGeneralPanelImpl::risktype() const { return risk->currentIndex(); } Calendar *TaskGeneralPanelImpl::calendar() const { return m_calendars.value( calendarCombo->currentIndex() ); } } //KPlato namespace diff --git a/src/libs/ui/kpttaskprogressdialog.cpp b/src/libs/ui/kpttaskprogressdialog.cpp index ada7e000..2b7ba9f6 100644 --- a/src/libs/ui/kpttaskprogressdialog.cpp +++ b/src/libs/ui/kpttaskprogressdialog.cpp @@ -1,80 +1,80 @@ /* This file is part of the KDE project Copyright (C) 2005-2010 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 "kpttaskprogressdialog.h" #include "kpttaskprogresspanel.h" #include "kptcommand.h" #include "kptproject.h" #include "kpttask.h" #include "kptnode.h" #include namespace KPlato { TaskProgressDialog::TaskProgressDialog(Task &task, ScheduleManager *sm, StandardWorktime *workTime, QWidget *p) : KoDialog( p), m_node( &task ) { setCaption( i18n("Task Progress") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); m_panel = new TaskProgressPanel(task, sm, workTime, this); setMainWidget(m_panel); enableButtonOk(false); - connect(m_panel, SIGNAL(changed()), SLOT(slotChanged())); + connect(m_panel, &TaskProgressPanelImpl::changed, this, &TaskProgressDialog::slotChanged); Project *proj = static_cast( task.projectNode() ); if ( proj ) { - connect(proj, SIGNAL(nodeRemoved(KPlato::Node*)), SLOT(slotNodeRemoved(KPlato::Node*))); + connect(proj, &Project::nodeRemoved, this, &TaskProgressDialog::slotNodeRemoved); } } void TaskProgressDialog::slotNodeRemoved( Node *node ) { if ( m_node == node ) { reject(); } } void TaskProgressDialog::slotChanged() { enableButtonOk(true); } MacroCommand *TaskProgressDialog::buildCommand() { MacroCommand *m = new MacroCommand(kundo2_i18n("Modify Task Progress")); bool modified = false; MacroCommand *cmd = m_panel->buildCommand(); if (cmd) { m->addCommand(cmd); modified = true; } if (!modified) { delete m; return 0; } return m; } } //KPlato namespace diff --git a/src/libs/ui/kpttaskprogresspanel.cpp b/src/libs/ui/kpttaskprogresspanel.cpp index 5931c159..e12cf065 100644 --- a/src/libs/ui/kpttaskprogresspanel.cpp +++ b/src/libs/ui/kpttaskprogresspanel.cpp @@ -1,437 +1,437 @@ /* This file is part of the KDE project Copyright (C) 2004 - 2007, 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. */ #include "kpttaskprogresspanel.h" #include "kptusedefforteditor.h" #include #include #include #include #include "kpttask.h" #include "kptcommand.h" #include "kptcalendar.h" #include "kptresource.h" #include "kptdurationspinbox.h" #include "kptschedule.h" #include "kptproject.h" #include "kptdebug.h" namespace KPlato { //----------------- TaskProgressPanel::TaskProgressPanel( Task &task, ScheduleManager *sm, StandardWorktime *workTime, QWidget *parent ) : TaskProgressPanelImpl( task, parent ) { debugPlan; started->setChecked(m_completion.isStarted()); finished->setChecked(m_completion.isFinished()); startTime->setDateTime(m_completion.startTime()); finishTime->setDateTime(m_completion.finishTime()); finishTime->setMinimumDateTime( qMax( startTime->dateTime(), QDateTime(m_completion.entryDate(), QTime(), Qt::LocalTime) ) ); if (workTime) { debugPlan<<"daylength="<durationDay().hours(); m_dayLength = workTime->durationDay().hours(); setEstimateScales(m_dayLength); } scheduledEffort = task.estimate()->expectedValue(); setYear( QDate::currentDate().year() ); if ( m_completion.usedEffortMap().isEmpty() || m_task.requests().isEmpty() ) { foreach ( ResourceGroupRequest *g, m_task.requests().requests() ) { foreach ( ResourceRequest *r, g->resourceRequests() ) { m_completion.addUsedEffort( r->resource() ); } } } if ( m_completion.isStarted() ) { tabWidget->setCurrentWidget( completionTab ); } enableWidgets(); started->setFocus(); connect( weekNumber, SIGNAL(currentIndexChanged(int)), SLOT(slotWeekNumberChanged(int)) ); - connect( addResource, SIGNAL(clicked()), SLOT(slotAddResource()) ); - connect( addEntryBtn, SIGNAL(clicked()), entryTable, SLOT(addEntry()) ); - connect( removeEntryBtn, SIGNAL(clicked()), entryTable, SLOT(removeEntry()) ); + connect( addResource, &QAbstractButton::clicked, this, &TaskProgressPanel::slotAddResource ); + connect( addEntryBtn, &QAbstractButton::clicked, entryTable, &CompletionEntryEditor::addEntry ); + connect( removeEntryBtn, &QAbstractButton::clicked, entryTable, &CompletionEntryEditor::removeEntry ); entryTable->model()->setManager( sm ); entryTable->model()->setTask( &task ); entryTable->setCompletion( &m_completion ); - connect( entryTable, SIGNAL(rowInserted(QDate)), SLOT(slotEntryAdded(QDate)) ); + connect( entryTable, &CompletionEntryEditor::rowInserted, this, &TaskProgressPanel::slotEntryAdded ); resourceTable->setProject( static_cast( task.projectNode() ) ); resourceTable->setCompletion( &m_completion ); slotWeekNumberChanged( weekNumber->currentIndex() ); addResource->setEnabled( resourceTable->hasFreeResources() ); //resourceTable->resizeColumnsToContents(); - connect(started, SIGNAL(toggled(bool)), SLOT(slotStartedChanged(bool))); - connect(started, SIGNAL(toggled(bool)), SLOT(slotChanged())); - connect(finished, SIGNAL(toggled(bool)), SLOT(slotFinishedChanged(bool))); - connect(finished, SIGNAL(toggled(bool)), SLOT(slotChanged())); + connect(started, &QAbstractButton::toggled, this, &TaskProgressPanelImpl::slotStartedChanged); + connect(started, &QAbstractButton::toggled, this, &TaskProgressPanelImpl::slotChanged); + connect(finished, &QAbstractButton::toggled, this, &TaskProgressPanelImpl::slotFinishedChanged); + connect(finished, &QAbstractButton::toggled, this, &TaskProgressPanelImpl::slotChanged); - connect(startTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); - connect(startTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotStartTimeChanged(QDateTime))); - connect(finishTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); - connect(finishTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotFinishTimeChanged(QDateTime))); + connect(startTime, &QDateTimeEdit::dateTimeChanged, this, &TaskProgressPanelImpl::slotChanged); + connect(startTime, &QDateTimeEdit::dateTimeChanged, this, &TaskProgressPanelImpl::slotStartTimeChanged); + connect(finishTime, &QDateTimeEdit::dateTimeChanged, this, &TaskProgressPanelImpl::slotChanged); + connect(finishTime, &QDateTimeEdit::dateTimeChanged, this, &TaskProgressPanelImpl::slotFinishTimeChanged); } MacroCommand *TaskProgressPanel::buildCommand() { Project *project = dynamic_cast( m_task.projectNode() ); if ( project == 0 ) { return 0; } return buildCommand( *project, m_original, m_completion ); } MacroCommand *TaskProgressPanel::buildCommand( const Project &project, Completion &org, Completion &curr ) { MacroCommand *cmd = 0; KUndo2MagicString c = kundo2_i18n("Modify task completion"); if ( org.entrymode() != curr.entrymode() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionEntrymodeCmd(org, curr.entrymode() ) ); } if ( org.startTime() != curr.startTime() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionStartTimeCmd(org, curr.startTime() ) ); } if ( org.finishTime() != curr.finishTime() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionFinishTimeCmd(org, curr.finishTime() ) ); } if ( org.isStarted() != curr.isStarted() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionStartedCmd(org, curr.isStarted() ) ); } if ( org.isFinished() != curr.isFinished() ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new ModifyCompletionFinishedCmd(org, curr.isFinished() ) ); } QList orgdates = org.entries().keys(); QList currdates = curr.entries().keys(); foreach ( const QDate &d, orgdates ) { if ( currdates.contains( d ) ) { if ( curr.entry( d ) == org.entry( d ) ) { continue; } if ( cmd == 0 ) cmd = new MacroCommand( c ); debugPlan<<"modify entry "<addCommand( new ModifyCompletionEntryCmd(org, d, e ) ); } else { if ( cmd == 0 ) cmd = new MacroCommand( c ); debugPlan<<"remove entry "<addCommand( new RemoveCompletionEntryCmd(org, d ) ); } } foreach ( const QDate &d, currdates ) { if ( ! orgdates.contains( d ) ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); Completion::Entry *e = new Completion::Entry( * ( curr.entry( d ) ) ); debugPlan<<"add entry "<addCommand( new AddCompletionEntryCmd(org, d, e ) ); } } const Completion::ResourceUsedEffortMap &map = curr.usedEffortMap(); Completion::ResourceUsedEffortMap::const_iterator it; for (it = map.constBegin(); it != map.constEnd(); ++it) { Resource *r = project.findResource(it.key()->id()); if ( r == 0 ) { warnPlan<<"Can't find resource:"<id()<name(); continue; } Completion::UsedEffort *ue = map[ r ]; if ( ue == 0 ) { continue; } if ( org.usedEffort( r ) == 0 || *ue != *(org.usedEffort( r )) ) { if ( cmd == 0 ) cmd = new MacroCommand( c ); cmd->addCommand( new AddCompletionUsedEffortCmd( org, r, new Completion::UsedEffort( *ue ) ) ); } } return cmd; } void TaskProgressPanel::setEstimateScales( int day ) { QVariantList lst; lst << QVariant( day ); // remainingEffort->setScales( lst ); // remainingEffort->setFieldScale(0, day); // remainingEffort->setFieldRightscale(0, day); // remainingEffort->setFieldLeftscale(1, day); // actualEffort->setScales( QVariant( lst ) ); /* actualEffort->setFieldScale(0, day); actualEffort->setFieldRightscale(0, day); actualEffort->setFieldLeftscale(1, day);*/ } void TaskProgressPanel::slotWeekNumberChanged( int index ) { debugPlan<setCurrentMonday( date ); } void TaskProgressPanel::slotAddResource() { debugPlan; resourceTable->addResource(); addResource->setEnabled( resourceTable->hasFreeResources() ); } void TaskProgressPanel::slotEntryAdded( const QDate &date ) { debugPlan<setIcon(koIcon("list-add")); removeEntryBtn->setIcon(koIcon("list-remove")); - connect(entryTable, SIGNAL(selectedItemsChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged(QItemSelection)) ); + connect(entryTable, &CompletionEntryEditor::selectedItemsChanged, this, &TaskProgressPanelImpl::slotSelectionChanged ); removeEntryBtn->setEnabled( false ); editmode->setCurrentIndex( m_original.entrymode() - 1 ); connect( editmode, SIGNAL(currentIndexChanged(int)), SLOT(slotEditmodeChanged(int)) ); connect( editmode, SIGNAL(activated(int)), SLOT(slotChanged()) ); - connect(resourceTable, SIGNAL(changed()), SLOT(slotChanged()) ); - connect(resourceTable, SIGNAL(resourceAdded()), SLOT(slotChanged()) ); + connect(resourceTable, &UsedEffortEditor::changed, this, &TaskProgressPanelImpl::slotChanged ); + connect(resourceTable, &UsedEffortEditor::resourceAdded, this, &TaskProgressPanelImpl::slotChanged ); - connect(entryTable, SIGNAL(changed()), SLOT(slotChanged()) ); - connect(entryTable, SIGNAL(rowInserted(QDate)), SLOT(slotChanged()) ); + connect(entryTable, &CompletionEntryEditor::changed, this, &TaskProgressPanelImpl::slotChanged ); + connect(entryTable, &CompletionEntryEditor::rowInserted, this, &TaskProgressPanelImpl::slotChanged ); - connect(entryTable, SIGNAL(changed()), SLOT(slotEntryChanged()) ); - connect(entryTable, SIGNAL(rowInserted(QDate)), SLOT(slotEntryChanged()) ); - connect(entryTable, SIGNAL(rowRemoved(QDate)), SLOT(slotEntryChanged()) ); + connect(entryTable, &CompletionEntryEditor::changed, this, &TaskProgressPanelImpl::slotEntryChanged ); + connect(entryTable, &CompletionEntryEditor::rowInserted, this, &TaskProgressPanelImpl::slotEntryChanged ); + connect(entryTable, &CompletionEntryEditor::rowRemoved, this, &TaskProgressPanelImpl::slotEntryChanged ); - connect( prevWeekBtn, SIGNAL(clicked(bool)), SLOT(slotPrevWeekBtnClicked()) ); - connect( nextWeekBtn, SIGNAL(clicked(bool)), SLOT(slotNextWeekBtnClicked()) ); + connect( prevWeekBtn, &QAbstractButton::clicked, this, &TaskProgressPanelImpl::slotPrevWeekBtnClicked ); + connect( nextWeekBtn, &QAbstractButton::clicked, this, &TaskProgressPanelImpl::slotNextWeekBtnClicked ); connect ( ui_year, SIGNAL(valueChanged(int)), SLOT(slotFillWeekNumbers(int)) ); int y = 0; int wn = QDate::currentDate().weekNumber( &y ); setYear( y ); weekNumber->setCurrentIndex( wn - m_weekOffset ); } void TaskProgressPanelImpl::slotChanged() { emit changed(); } void TaskProgressPanelImpl::slotEditmodeChanged( int idx ) { m_completion.setEntrymode( static_cast( idx + 1 ) ); entryTable->model()->slotDataChanged(); enableWidgets(); } void TaskProgressPanelImpl::slotStartedChanged(bool state) { m_completion.setStarted( state ); if (state) { QTime t = QTime::currentTime(); t.setHMS( t.hour(), t.minute(), 0 ); m_completion.setStartTime( QDateTime(QDate::currentDate(), t, Qt::LocalTime) ); startTime->setDateTime( m_completion.startTime() ); slotCalculateEffort(); } enableWidgets(); } void TaskProgressPanelImpl::setFinished() { QTime t = QTime::currentTime(); t.setHMS( t.hour(), t.minute(), 0 ); finishTime->setDateTime( QDateTime(QDate::currentDate(), t, Qt::LocalTime) ); slotFinishTimeChanged( finishTime->dateTime() ); } void TaskProgressPanelImpl::slotFinishedChanged(bool state) { debugPlan<dateTime(); slotCalculateEffort(); } enableWidgets(); } void TaskProgressPanelImpl::slotFinishTimeChanged( const QDateTime &dt ) { if ( ! m_completion.isFinished() ) { return; } m_completion.setFinishTime( dt ); if ( m_completion.percentFinished() < 100 ) { m_completion.setPercentFinished( dt.date(), 100 ); } entryTable->setCompletion( &m_completion ); // for refresh } void TaskProgressPanelImpl::slotStartTimeChanged( const QDateTime &dt ) { m_completion.setStartTime( dt ); finishTime->setMinimumDateTime( qMax( startTime->dateTime(), QDateTime(m_completion.entryDate(), QTime(), Qt::LocalTime) ) ); } void TaskProgressPanelImpl::slotEntryChanged() { finishTime->setMinimumDateTime( qMax( startTime->dateTime(), QDateTime(m_completion.entryDate(), QTime(), Qt::LocalTime) ) ); } void TaskProgressPanelImpl::enableWidgets() { editmode->setEnabled( !finished->isChecked() ); started->setEnabled(!finished->isChecked()); finished->setEnabled(started->isChecked()); finishTime->setEnabled(finished->isChecked()); startTime->setEnabled(started->isChecked() && !finished->isChecked()); addEntryBtn->setEnabled( started->isChecked() && !finished->isChecked() ); removeEntryBtn->setEnabled( ! entryTable->selectionModel()->selectedIndexes().isEmpty() && started->isChecked() && ! finished->isChecked() ); if ( finished->isChecked() ) { for ( int i = 0; i < entryTable->model()->columnCount(); ++i ) { entryTable->model()->setFlags( i, Qt::NoItemFlags ); } } resourceTable->model()->setReadOnly( ( ! started->isChecked() ) || finished->isChecked() || m_completion.entrymode() != Completion::EnterEffortPerResource ); } void TaskProgressPanelImpl::slotPercentFinishedChanged( int ) { slotCalculateEffort(); } void TaskProgressPanelImpl::slotCalculateEffort() { } void TaskProgressPanelImpl::slotPrevWeekBtnClicked() { debugPlan; int i = weekNumber->currentIndex(); if ( i == 0 ) { debugPlan<value() - 1 ); if ( m_lastIsNextYear ) { decr = 2; } weekNumber->setCurrentIndex( weekNumber->count() - decr ); } else { weekNumber->setCurrentIndex( i - 1 ); } } void TaskProgressPanelImpl::slotNextWeekBtnClicked() { int i = weekNumber->currentIndex(); debugPlan<count(); if ( i == weekNumber->count() - 1 ) { debugPlan<value() + 1 ); if ( m_firstIsPrevYear ) { index = 1; } weekNumber->setCurrentIndex( index ); } else { weekNumber->setCurrentIndex( i + 1 ); } } void TaskProgressPanelImpl::setYear( int year ) { debugPlan; ui_year->setValue( year ); } void TaskProgressPanelImpl::slotFillWeekNumbers( int year ) { debugPlan; weekNumber->clear(); m_year = year; m_weekOffset = 1; int y = 0; QDate date( year, 1, 1 ); int wn = date.weekNumber( &y ); m_firstIsPrevYear = false; debugPlan<addItem( i18nc( "Week number (year)", "Week %1 (%2)", wn, y ) ); m_weekOffset = 0; m_firstIsPrevYear = true; debugPlan<<"Added last week of prev year"; } for ( int i=1; i <= 52; ++i ) { weekNumber->addItem( i18nc( "Week number", "Week %1", i ) ); } date = QDate( year, 12, 31 ); wn = date.weekNumber( &y ); debugPlan<addItem( i18nc( "Week number", "Week %1", wn ) ); } else if ( wn == 1 ) { weekNumber->addItem( i18nc( "Week number (year)", "Week %1 (%2)", wn, y ) ); m_lastIsNextYear = true; } } void TaskProgressPanelImpl::slotSelectionChanged( const QItemSelection &sel ) { removeEntryBtn->setEnabled( ! sel.isEmpty() && started->isChecked() && ! finished->isChecked() ); } } //KPlato namespace diff --git a/src/libs/ui/kpttaskstatusview.cpp b/src/libs/ui/kpttaskstatusview.cpp index dfcb7572..e74e1b6b 100644 --- a/src/libs/ui/kpttaskstatusview.cpp +++ b/src/libs/ui/kpttaskstatusview.cpp @@ -1,1496 +1,1496 @@ /* This file is part of the KDE project Copyright (C) 2007 - 2010, 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. */ #include "kpttaskstatusview.h" #include "kpttaskstatusmodel.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptproject.h" #include "kptschedule.h" #include "kpteffortcostmap.h" #include "Help.h" #include "kptdebug.h" #include #include "KoDocument.h" #include "KoPageLayoutWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KChart; namespace KPlato { TaskStatusTreeView::TaskStatusTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { setContextMenuPolicy( Qt::CustomContextMenu ); TaskStatusItemModel *m = new TaskStatusItemModel( this ); setModel( m ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::ExtendedSelection ); setStretchLastSection( false ); createItemDelegates( m ); QList lst1; lst1 << 1 << -1; // only display column 0 (NodeName) in left view masterView()->setDefaultColumns( QList() << 0 ); QList show; show << NodeModel::NodeCompleted << NodeModel::NodeActualEffort << NodeModel::NodeRemainingEffort << NodeModel::NodePlannedEffort << NodeModel::NodePlannedCost << NodeModel::NodeActualCost << NodeModel::NodeStatus << NodeModel::NodeActualStart << NodeModel::NodeActualFinish << NodeModel::NodeStatusNote; QList lst2; for ( int i = 0; i < m->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } hideColumns( lst1, lst2 ); slaveView()->setDefaultColumns( show ); } int TaskStatusTreeView::weekday() const { return model()->weekday(); } void TaskStatusTreeView::setWeekday( int day ) { model()->setWeekday( day ); refresh(); } int TaskStatusTreeView::defaultPeriodType() const { return TaskStatusItemModel::UseCurrentDate; } int TaskStatusTreeView::periodType() const { return model()->periodType(); } void TaskStatusTreeView::setPeriodType( int type ) { model()->setPeriodType( type ); refresh(); } int TaskStatusTreeView::period() const { return model()->period(); } void TaskStatusTreeView::setPeriod( int days ) { model()->setPeriod( days ); refresh(); } TaskStatusItemModel *TaskStatusTreeView::model() const { return static_cast( DoubleTreeViewBase::model() ); } Project *TaskStatusTreeView::project() const { return model()->project(); } void TaskStatusTreeView::setProject( Project *project ) { model()->setProject( project ); } void TaskStatusTreeView::dragMoveEvent(QDragMoveEvent */*event*/) { /* if (dragDropMode() == InternalMove && (event->source() != this || !(event->possibleActions() & Qt::MoveAction))) return; TreeViewBase::dragMoveEvent( event ); if ( ! event->isAccepted() ) { return; } //QTreeView thinks it's ok to drop event->ignore(); QModelIndex index = indexAt( event->pos() ); if ( ! index.isValid() ) { event->accept(); return; // always ok to drop on main project } Node *dn = model()->node( index ); if ( dn == 0 ) { errorPlan<<"no node to drop on!" return; // hmmm } switch ( dropIndicatorPosition() ) { case AboveItem: case BelowItem: //dn == sibling if ( model()->dropAllowed( dn->parentNode(), event->mimeData() ) ) { event->accept(); } break; case OnItem: //dn == new parent if ( model()->dropAllowed( dn, event->mimeData() ) ) { event->accept(); } break; default: break; }*/ } //----------------------------------- TaskStatusView::TaskStatusView(KoPart *part, KoDocument *doc, QWidget *parent ) : ViewBase(part, doc, parent), m_id( -1 ) { debugPlan<<"-------------------- creating TaskStatusView -------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new TaskStatusTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view, SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view, SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view, &DoubleTreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view, &DoubleTreeViewBase::slotCollapse); l->addWidget( m_view ); setupGui(); - connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); + connect( model(), &ItemModelBase::executeCommand, doc, &KoDocument::addCommand ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &DoubleTreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Task Status View" "" "The Task Status View is used to inspect task progress information. " "The tasks are divided into groups dependent on the task status:" "" "Not Started Tasks that should have been started by now." "Running Tasks that has been started, but not yet finished." "Finished Tasks that where finished in this period." "Next Period Tasks that is scheduled to be started in the next period." "" "The time period is configurable." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Task_Status_View"))); } void TaskStatusView::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); } void TaskStatusView::setScheduleManager( ScheduleManager *sm ) { //debugPlan; if (!sm && scheduleManager()) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_view->masterView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); bool expand = sm && scheduleManager() && sm != scheduleManager(); QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_view->masterView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); static_cast( m_view->model() )->setScheduleManager( sm ); if (expand) { m_view->masterView()->doExpand(doc); } else if (tryexpand) { m_view->masterView()->doExpand(m_domdoc); } } Node *TaskStatusView::currentNode() const { return m_view->model()->node( m_view->selectionModel()->currentIndex() ); } void TaskStatusView::setProject( Project *project ) { m_project = project; m_view->model()->setProject( m_project ); } void TaskStatusView::draw( Project &project ) { setProject( &project ); } void TaskStatusView::setGuiActive( bool activate ) { debugPlan<setContextMenuIndex(index); Node *node = m_view->model()->node( index ); if ( node == 0 ) { slotHeaderContextMenuRequested( pos ); m_view->setContextMenuIndex(QModelIndex()); return; } slotContextMenuRequested( node, pos ); m_view->setContextMenuIndex(QModelIndex()); } void TaskStatusView::slotContextMenuRequested( Node *node, const QPoint& pos ) { debugPlan<name()<<" :"<type() ) { case Node::Type_Task: name = "taskstatus_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } debugPlan<actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &TaskStatusView::slotSplitView); addContextAction( m_view->actionSplitView() ); createOptionActions(ViewBase::OptionAll); } void TaskStatusView::slotSplitView() { debugPlan; m_view->setViewSplitMode( ! m_view->isViewSplit() ); emit optionsModified(); } void TaskStatusView::slotRefreshView() { model()->refresh(); } void TaskStatusView::slotOptions() { debugPlan; TaskStatusViewSettingsDialog *dlg = new TaskStatusViewSettingsDialog( this, m_view, this ); dlg->addPrintingOptions(sender()->objectName() == "print options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool TaskStatusView::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); m_view->setPeriod( context.attribute( "period", QString("%1").arg( m_view->defaultPeriod() ) ).toInt() ); m_view->setPeriodType( context.attribute( "periodtype", QString("%1").arg( m_view->defaultPeriodType() ) ).toInt() ); m_view->setWeekday( context.attribute( "weekday", QString("%1").arg( m_view->defaultWeekday() ) ).toInt() ); return m_view->loadContext( model()->columnMap(), context ); } void TaskStatusView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); context.setAttribute( "period", QString::number(m_view->period()) ); context.setAttribute( "periodtype", QString::number(m_view->periodType()) ); context.setAttribute( "weekday", QString::number(m_view->weekday()) ); m_view->saveContext( model()->columnMap(), context ); } KoPrintJob *TaskStatusView::createPrintJob() { return m_view->createPrintJob( this ); } //------------------------------------------------ TaskStatusViewSettingsPanel::TaskStatusViewSettingsPanel( TaskStatusTreeView *view, QWidget *parent ) : QWidget( parent ), m_view( view ) { setupUi( this ); QStringList lst; QLocale locale; for ( int i = 1; i <= 7; ++i ) { lst << locale.dayName( i, QLocale::ShortFormat ); } weekdays->addItems( lst ); period->setValue( view->period() ); switch ( view->periodType() ) { case TaskStatusItemModel::UseCurrentDate: useCurrentDate->setChecked( true ); break; case TaskStatusItemModel::UseWeekday: useWeekday->setChecked( true ); break; default: break; } weekdays->setCurrentIndex( m_view->weekday() - 1 ); connect( period, SIGNAL(valueChanged(int)), SIGNAL(changed()) ); - connect( useWeekday, SIGNAL(toggled(bool)), SIGNAL(changed()) ); - connect( useCurrentDate, SIGNAL(toggled(bool)), SIGNAL(changed()) ); + connect( useWeekday, &QAbstractButton::toggled, this, &TaskStatusViewSettingsPanel::changed ); + connect( useCurrentDate, &QAbstractButton::toggled, this, &TaskStatusViewSettingsPanel::changed ); connect( weekdays, SIGNAL(currentIndexChanged(int)), SIGNAL(changed()) ); } void TaskStatusViewSettingsPanel::slotOk() { if ( period->value() != m_view->period() ) { m_view->setPeriod( period->value() ); } if ( weekdays->currentIndex() != m_view->weekday() - 1 ) { m_view->setWeekday( weekdays->currentIndex() + 1 ); } if ( useCurrentDate->isChecked() && m_view->periodType() != TaskStatusItemModel::UseCurrentDate ) { m_view->setPeriodType( TaskStatusItemModel::UseCurrentDate ); } else if ( useWeekday->isChecked() && m_view->periodType() != TaskStatusItemModel::UseWeekday ) { m_view->setPeriodType( TaskStatusItemModel::UseWeekday ); } } void TaskStatusViewSettingsPanel::setDefault() { period->setValue( m_view->defaultPeriod() ); switch ( m_view->defaultPeriodType() ) { case TaskStatusItemModel::UseCurrentDate: useCurrentDate->setChecked( true ); break; case TaskStatusItemModel::UseWeekday: useWeekday->setChecked( true ); break; default: break; } weekdays->setCurrentIndex( m_view->defaultWeekday() - 1 ); } TaskStatusViewSettingsDialog::TaskStatusViewSettingsDialog( ViewBase *view, TaskStatusTreeView *treeview, QWidget *parent ) : SplitItemViewSettupDialog( view, treeview, parent ) { TaskStatusViewSettingsPanel *panel = new TaskStatusViewSettingsPanel( treeview ); KPageWidgetItem *page = insertWidget( 0, panel, i18n( "General" ), i18n( "General Settings" ) ); setCurrentPage( page ); //connect( panel, SIGNAL(changed(bool)), this, SLOT(enableButtonOk(bool)) ); - connect( this, SIGNAL(accepted()), panel, SLOT(slotOk()) ); - connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(setDefault()) ); + connect( this, &QDialog::accepted, panel, &TaskStatusViewSettingsPanel::slotOk ); + connect( button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, panel, &TaskStatusViewSettingsPanel::setDefault ); } //----------------------------------- ProjectStatusView::ProjectStatusView(KoPart *part, KoDocument *doc, QWidget *parent ) : ViewBase(part, doc, parent), m_project( 0 ) { debugPlan<<"-------------------- creating ProjectStatusView -------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new PerformanceStatusBase( this ); l->addWidget( m_view ); setupGui(); - connect( m_view, SIGNAL(customContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &QWidget::customContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); Help::add(this, xi18nc("@info:whatsthis", "Project Performance View" "" "Displays performance data aggregated to the project level." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Project_Performance_View"))); } void ProjectStatusView::setScheduleManager( ScheduleManager *sm ) { //debugPlan; m_view->setScheduleManager( sm ); m_view->model()->clearNodes(); if ( m_project ) { m_view->setNodes( QList() << m_project ); } } void ProjectStatusView::setProject( Project *project ) { m_project = project; m_view->model()->clearNodes(); m_view->setProject( project ); } void ProjectStatusView::setGuiActive( bool activate ) { debugPlan<objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool ProjectStatusView::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); return m_view->loadContext( context ); } void ProjectStatusView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); m_view->saveContext( context ); } KoPrintJob *ProjectStatusView::createPrintJob() { return m_view->createPrintJob( this ); } //---------------------- PerformanceStatusPrintingDialog::PerformanceStatusPrintingDialog( ViewBase *view, PerformanceStatusBase *chart, Project *project ) : PrintingDialog( view ), m_chart( chart ), m_project( project ) { } int PerformanceStatusPrintingDialog::documentLastPage() const { return documentFirstPage(); } QList PerformanceStatusPrintingDialog::createOptionWidgets() const { QList lst; lst << createPageLayoutWidget(); lst += PrintingDialog::createOptionWidgets(); return lst; } void PerformanceStatusPrintingDialog::printPage( int page, QPainter &painter ) { //debugPlan<ui_chart->geometry().size(); qreal r = (qreal)s.width() / (qreal)s.height(); if ( rect.height() > rect.width() && r > 0.0 ) { rect.setHeight( rect.width() / r ); } debugPlan<ui_chart->paint( &painter, rect ); painter.restore(); } //----------------------------------- PerformanceStatusBase::PerformanceStatusBase( QWidget *parent ) : QWidget( parent ), m_project( 0 ), m_manager( 0 ) { setupUi( this ); ui_performancetable->setModel( new PerformanceDataCurrentDateModel( this ) ); BackgroundAttributes backgroundAttrs( ui_chart->backgroundAttributes() ); backgroundAttrs.setVisible( true ); backgroundAttrs.setBrush( Qt::white ); ui_chart->setBackgroundAttributes( backgroundAttrs ); m_legend = new Legend( ui_chart ); ui_chart->replaceLegend( m_legend ); m_legend->setObjectName( "Chart legend" ); backgroundAttrs = m_legend->backgroundAttributes(); m_legend->setBackgroundAttributes( backgroundAttrs ); backgroundAttrs.setVisible( true ); backgroundAttrs.setBrush( Qt::white ); m_legend->setPosition( Position::East ); //m_legend->setAlignment( (Qt::Alignment)(Qt::AlignTop | Qt::AlignCenter) ); m_legenddiagram.setModel( &m_chartmodel ); m_legenddiagram.setObjectName( "Legend diagram" ); m_legend->setDiagram( &m_legenddiagram ); // get rid of the default coordinate plane AbstractCoordinatePlane *p = ui_chart->coordinatePlane(); ui_chart->takeCoordinatePlane( p ); delete p; createBarChart(); createLineChart(); setupChart(); #ifdef PLAN_CHART_DEBUG ui_tableView->setModel( &m_chartmodel ); #endif - connect(&m_chartmodel, SIGNAL(modelReset()), SLOT(slotUpdate())); + connect(&m_chartmodel, &QAbstractItemModel::modelReset, this, &PerformanceStatusBase::slotUpdate); setContextMenuPolicy ( Qt::DefaultContextMenu ); } void PerformanceStatusBase::setChartInfo( const PerformanceChartInfo &info ) { if ( info != m_chartinfo ) { m_chartinfo = info; setupChart(); } } void PerformanceStatusBase::refreshChart() { ui_performancetable->resize( QSize() ); // NOTE: Force grid/axis recalculation, couldn't find a better way :( QResizeEvent event( ui_chart->size(), QSize() ); QApplication::sendEvent( ui_chart, &event ); m_legend->forceRebuild(); } void PerformanceStatusBase::createBarChart() { m_barchart.effortplane = new CartesianCoordinatePlane( ui_chart ); m_barchart.effortplane->setObjectName( "Bar chart, Effort" ); m_barchart.costplane = new CartesianCoordinatePlane( ui_chart ); m_barchart.costplane->setObjectName( "Bar chart, Cost" ); BarDiagram *effortdiagram = new BarDiagram( ui_chart, m_barchart.effortplane ); effortdiagram->setObjectName( "Effort diagram" ); m_barchart.dateaxis = new CartesianAxis(); m_barchart.dateaxis->setPosition( CartesianAxis::Bottom ); m_barchart.effortaxis = new CartesianAxis( effortdiagram ); m_barchart.effortaxis->setPosition( CartesianAxis::Right ); effortdiagram->addAxis( m_barchart.effortaxis ); m_barchart.effortplane->addDiagram( effortdiagram ); // Hide cost in effort diagram effortdiagram->setHidden( 0, true ); effortdiagram->setHidden( 1, true ); effortdiagram->setHidden( 2, true ); m_barchart.effortproxy.setZeroColumns( QList() << 0 << 1 << 2 ); m_barchart.effortproxy.setSourceModel( &m_chartmodel ); effortdiagram->setModel( &(m_barchart.effortproxy) ); BarDiagram *costdiagram = new BarDiagram( ui_chart, m_barchart.costplane ); costdiagram->setObjectName( "Cost diagram" ); m_barchart.costaxis = new CartesianAxis( costdiagram ); m_barchart.costaxis->setPosition( CartesianAxis::Left ); costdiagram->addAxis( m_barchart.costaxis ); m_barchart.costplane->addDiagram( costdiagram ); // Hide effort in cost diagram costdiagram->setHidden( 3, true ); costdiagram->setHidden( 4, true ); costdiagram->setHidden( 5, true ); m_barchart.costproxy.setZeroColumns( QList() << 3 << 4 << 5 ); m_barchart.costproxy.setObjectName( "Bar: Cost" ); m_barchart.costproxy.setSourceModel( &m_chartmodel ); costdiagram->setModel( &(m_barchart.costproxy) ); m_barchart.effortdiagram = effortdiagram; m_barchart.costdiagram = costdiagram; m_barchart.piplane = new CartesianCoordinatePlane( ui_chart ); m_barchart.piplane->setObjectName( "Performance Indices" ); BarDiagram *pidiagram = new BarDiagram( ui_chart, m_barchart.piplane ); pidiagram->setObjectName( "PI diagram" ); m_barchart.piaxis = new CartesianAxis( pidiagram ); pidiagram->addAxis( m_barchart.piaxis ); m_barchart.piplane->addDiagram( pidiagram ); m_barchart.piproxy.setSourceModel( &m_chartmodel ); pidiagram->setModel( &( m_barchart.piproxy ) ); } void PerformanceStatusBase::createLineChart() { m_linechart.effortplane = new CartesianCoordinatePlane( ui_chart ); m_linechart.effortplane->setObjectName( "Line chart, Effort" ); m_linechart.effortplane->setRubberBandZoomingEnabled( true ); m_linechart.costplane = new CartesianCoordinatePlane( ui_chart ); m_linechart.costplane->setObjectName( "Line chart, Cost" ); m_linechart.costplane->setRubberBandZoomingEnabled( true ); LineDiagram *effortdiagram = new LineDiagram( ui_chart, m_linechart.effortplane ); effortdiagram->setObjectName( "Effort diagram" ); m_linechart.dateaxis = new CartesianAxis(); m_linechart.dateaxis->setPosition( CartesianAxis::Bottom ); m_linechart.effortaxis = new CartesianAxis( effortdiagram ); m_linechart.effortaxis->setPosition( CartesianAxis::Right ); effortdiagram->addAxis( m_linechart.effortaxis ); m_linechart.effortplane->addDiagram( effortdiagram ); // Hide cost in effort diagram effortdiagram->setHidden( 0, true ); effortdiagram->setHidden( 1, true ); effortdiagram->setHidden( 2, true ); m_linechart.effortproxy.setZeroColumns( QList() << 0 << 1 << 2 ); m_linechart.effortproxy.setObjectName( "Line: Effort" ); m_linechart.effortproxy.setSourceModel( &m_chartmodel ); effortdiagram->setModel( &(m_linechart.effortproxy) ); LineDiagram *costdiagram = new LineDiagram( ui_chart, m_linechart.costplane ); costdiagram->setObjectName( "Cost diagram" ); m_linechart.costaxis = new CartesianAxis( costdiagram ); m_linechart.costaxis->setPosition( CartesianAxis::Left ); costdiagram->addAxis( m_linechart.costaxis ); m_linechart.costplane->addDiagram( costdiagram ); // Hide effort in cost diagram costdiagram->setHidden( 3, true ); costdiagram->setHidden( 4, true ); costdiagram->setHidden( 5, true ); m_linechart.costproxy.setObjectName( "Line: Cost" ); m_linechart.costproxy.setZeroColumns( QList() << 3 << 4 << 5 ); m_linechart.costproxy.setSourceModel( &m_chartmodel ); costdiagram->setModel( &(m_linechart.costproxy) ); m_linechart.effortdiagram = effortdiagram; m_linechart.costdiagram = costdiagram; m_linechart.piplane = new CartesianCoordinatePlane( ui_chart ); m_linechart.piplane->setObjectName( "Performance Indices" ); m_linechart.piplane->setRubberBandZoomingEnabled( true ); LineDiagram *pidiagram = new LineDiagram( ui_chart, m_linechart.piplane ); pidiagram->setObjectName( "PI diagram" ); m_linechart.piaxis = new CartesianAxis( pidiagram ); pidiagram->addAxis( m_linechart.piaxis ); m_linechart.piplane->addDiagram( pidiagram ); m_linechart.piproxy.setSourceModel( &m_chartmodel ); pidiagram->setModel( &( m_linechart.piproxy ) ); } void PerformanceStatusBase::setupChart() { while ( ! ui_chart->coordinatePlanes().isEmpty() ) { const CoordinatePlaneList &planes = ui_chart->coordinatePlanes(); ui_chart->takeCoordinatePlane(planes.last()); } if ( m_chartinfo.showBarChart ) { setupChart( m_barchart ); } else if ( m_chartinfo.showLineChart ) { setupChart( m_linechart ); } else { #ifdef PLAN_CHART_DEBUG ui_stack->setCurrentIndex( 1 ); refreshChart(); return; #else setupChart( m_linechart ); #endif } ui_stack->setCurrentIndex( 0 ); debugPlan<<"Planes:"<coordinatePlanes(); foreach ( AbstractCoordinatePlane *pl, ui_chart->coordinatePlanes() ) { CartesianCoordinatePlane *p = dynamic_cast( pl ); if ( p == 0 ) continue; GridAttributes ga = p->globalGridAttributes(); ga.setGridVisible( p->referenceCoordinatePlane() == 0 ); p->setGlobalGridAttributes( ga ); } m_legend->setDatasetHidden( 0, ! ( m_chartinfo.showBaseValues && m_chartinfo.showCost && m_chartinfo.showBCWSCost ) ); m_legend->setDatasetHidden( 1, ! ( m_chartinfo.showBaseValues && m_chartinfo.showCost && m_chartinfo.showBCWPCost ) ); m_legend->setDatasetHidden( 2, ! ( m_chartinfo.showBaseValues && m_chartinfo.showCost && m_chartinfo.showACWPCost ) ); m_legend->setDatasetHidden( 3, ! ( m_chartinfo.showBaseValues && m_chartinfo.showEffort && m_chartinfo.showBCWSEffort ) ); m_legend->setDatasetHidden( 4, ! ( m_chartinfo.showBaseValues && m_chartinfo.showEffort && m_chartinfo.showBCWPEffort ) ); m_legend->setDatasetHidden( 5, ! ( m_chartinfo.showBaseValues && m_chartinfo.showEffort && m_chartinfo.showACWPEffort ) ); // spi/cpi m_legend->setDatasetHidden( 6, ! ( m_chartinfo.showIndices && m_chartinfo.showSpiCost ) ); m_legend->setDatasetHidden( 7, ! ( m_chartinfo.showIndices && m_chartinfo.showCpiCost ) ); m_legend->setDatasetHidden( 8, ! ( m_chartinfo.showIndices && m_chartinfo.showSpiEffort ) ); m_legend->setDatasetHidden( 9, ! ( m_chartinfo.showIndices && m_chartinfo.showCpiEffort ) ); setEffortValuesVisible( m_chartinfo.effortShown() ); setCostValuesVisible( m_chartinfo.costShown() ); refreshChart(); } void PerformanceStatusBase::setEffortValuesVisible( bool visible ) { ui_performancetable->verticalHeader()->setSectionHidden( 1, ! visible ); ui_performancetable->setMaximumHeight( ui_performancetable->sizeHint().height() ); } void PerformanceStatusBase::setCostValuesVisible( bool visible ) { ui_performancetable->verticalHeader()->setSectionHidden( 0, ! visible ); ui_performancetable->setMaximumHeight( ui_performancetable->sizeHint().height() ); } void PerformanceStatusBase::setupChart( ChartContents &cc ) { QList erc, ezc, crc, czc; // sourcemodel column numbers int effort_start_column = 3; // proxy column number const PerformanceChartInfo &info = m_chartinfo; debugPlan<<"cost="<( cc.effortplane->diagram() )->takeAxis( cc.dateaxis ); static_cast( cc.costplane->diagram() )->takeAxis( cc.dateaxis ); static_cast( cc.piplane->diagram() )->takeAxis( cc.dateaxis ); cc.costplane->setReferenceCoordinatePlane( 0 ); if ( info.showBaseValues ) { if ( info.showEffort ) { // filter cost columns if cost is *not* shown, else hide them and zero out if ( ! info.showCost ) { erc << 0 << 1 << 2; effort_start_column = 0; // no cost, so effort start at 0 } else { ezc << 0 << 1 << 2; cc.effortplane->diagram()->setHidden( 0, true ); cc.effortplane->diagram()->setHidden( 1, true ); cc.effortplane->diagram()->setHidden( 2, true ); } // always disable spi/cpi erc << 6 << 7 << 8 << 9; ezc << 6 << 7 << 8 << 9; // if cost is shown don't return a cost value or else it goes into the effort axis scale calculation //cc.effortproxy.setZeroColumns( info.showCost ? QList() << 0 << 1 << 2 : QList() << 3 << 4 << 5 ); cc.effortaxis->setPosition( info.showCost ? CartesianAxis::Right : CartesianAxis::Left ); ui_chart->addCoordinatePlane( cc.effortplane ); static_cast( cc.effortplane->diagram() )->addAxis( cc.dateaxis ); cc.effortplane->setGridNeedsRecalculate(); } if ( info.showCost ) { // Should never get any effort values in cost diagram czc << 3 << 4 << 5; // remove effort columns from cost if no effort is shown, else hide them if ( ! info.showEffort ) { crc << 3 << 4 << 5; } else { cc.costplane->diagram()->setHidden( 3, true ); cc.costplane->diagram()->setHidden( 4, true ); cc.costplane->diagram()->setHidden( 5, true ); } // always disable spi/cpi erc << 6 << 7 << 8 << 9; ezc << 6 << 7 << 8 << 9; cc.costplane->setReferenceCoordinatePlane( info.showEffort ? cc.effortplane : 0 ); ui_chart->addCoordinatePlane( cc.costplane ); static_cast( cc.costplane->diagram() )->addAxis( cc.dateaxis ); cc.costplane->setGridNeedsRecalculate(); cc.costplane->diagram()->setHidden( 0, ! info.showBCWSCost ); cc.costplane->diagram()->setHidden( 1, ! info.showBCWPCost ); cc.costplane->diagram()->setHidden( 2, ! info.showACWPCost ); } if ( info.showEffort ) { cc.effortplane->diagram()->setHidden( effort_start_column, ! info.showBCWSEffort ); cc.effortplane->diagram()->setHidden( effort_start_column+1, ! info.showBCWPEffort ); cc.effortplane->diagram()->setHidden( effort_start_column+2, ! info.showACWPEffort ); cc.effortaxis->setCachedSizeDirty(); cc.effortproxy.reset(); cc.effortproxy.setZeroColumns( ezc ); cc.effortproxy.setRejectColumns( erc ); } if ( info.showCost ) { cc.costaxis->setCachedSizeDirty(); cc.costproxy.reset(); cc.costproxy.setZeroColumns( czc ); cc.costproxy.setRejectColumns( crc ); } } else if ( info.showIndices ) { cc.piaxis->setPosition( CartesianAxis::Left ); ui_chart->addCoordinatePlane( cc.piplane ); static_cast( cc.piplane->diagram() )->addAxis( cc.dateaxis ); cc.piplane->setGridNeedsRecalculate(); cc.piaxis->setCachedSizeDirty(); cc.piproxy.reset(); QList reject; reject << 0 << 1 << 2 << 3 << 4 << 5; if ( ! info.showSpiCost ) { reject << ChartItemModel::SPICost; } if ( ! info.showCpiCost ) { reject << ChartItemModel::CPICost; } if ( ! info.showSpiEffort ) { reject << ChartItemModel::SPIEffort; } if ( ! info.showCpiEffort ) { reject << ChartItemModel::CPIEffort; } cc.piproxy.setRejectColumns( reject ); } #if 0 debugPlan<<"Effort:"< 0 ) { debugPlan<<"Effort:"<diagram()->isHidden(i)?"hide":"show"); } } debugPlan<<"Cost:"< 0 ) { debugPlan<<"Cost:"<diagram()->isHidden(i)?"hide":"show"); } } foreach( AbstractCoordinatePlane *p, ui_chart->coordinatePlanes() ) { debugPlan<referenceCoordinatePlane(); foreach ( AbstractDiagram *d, p->diagrams() ) { debugPlan<globalPos(); emit customContextMenuRequested( event->globalPos() ); } void PerformanceStatusBase::slotUpdate() { //debugPlan; refreshChart(); } void PerformanceStatusBase::setScheduleManager( ScheduleManager *sm ) { //debugPlan; if (sm == m_manager) { return; } m_manager = sm; m_chartmodel.setScheduleManager( sm ); static_cast( ui_performancetable->model() )->setScheduleManager( sm ); } void PerformanceStatusBase::setProject( Project *project ) { if ( m_project ) { - disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLocaleChanged()) ); + disconnect( m_project, &Project::localeChanged, this, &PerformanceStatusBase::slotLocaleChanged ); } m_project = project; if ( m_project ) { - connect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLocaleChanged()) ); + connect( m_project, &Project::localeChanged, this, &PerformanceStatusBase::slotLocaleChanged ); } m_chartmodel.setProject( project ); static_cast( ui_performancetable->model() )->setProject( project ); slotLocaleChanged(); } void PerformanceStatusBase::slotLocaleChanged() { debugPlan; const QString currencySymbol = m_project->locale()->currencySymbol(); m_linechart.costaxis->setTitleText( i18nc( "Chart axis title 1=currency symbol", "Cost (%1)", currencySymbol ) ); m_linechart.effortaxis->setTitleText( i18nc( "Chart axis title", "Effort (hours)" ) ); m_barchart.costaxis->setTitleText( i18nc( "Chart axis title 1=currency symbol", "Cost (%1)", currencySymbol ) ); m_barchart.effortaxis->setTitleText( i18nc( "Chart axis title", "Effort (hours)" ) ); } bool PerformanceStatusBase::loadContext( const KoXmlElement &context ) { debugPlan; m_chartinfo.showBarChart = context.attribute( "show-bar-chart", "0" ).toInt(); m_chartinfo.showLineChart = context.attribute( "show-line-chart", "1" ).toInt(); m_chartinfo.showTableView = context.attribute( "show-table-view", "0" ).toInt(); m_chartinfo.showBaseValues = context.attribute( "show-base-values", "1" ).toInt(); m_chartinfo.showIndices = context.attribute( "show-indeces", "0" ).toInt(); m_chartinfo.showCost = context.attribute( "show-cost", "1" ).toInt(); m_chartinfo.showBCWSCost = context.attribute( "show-bcws-cost", "1" ).toInt(); m_chartinfo.showBCWPCost = context.attribute( "show-bcwp-cost", "1" ).toInt(); m_chartinfo.showACWPCost = context.attribute( "show-acwp-cost", "1" ).toInt(); m_chartinfo.showEffort = context.attribute( "show-effort", "1" ).toInt(); m_chartinfo.showBCWSEffort = context.attribute( "show-bcws-effort", "1" ).toInt(); m_chartinfo.showBCWPEffort = context.attribute( "show-bcwp-effort", "1" ).toInt(); m_chartinfo.showACWPEffort = context.attribute( "show-acwp-effort", "1" ).toInt(); m_chartinfo.showSpiCost = context.attribute( "show-spi-cost", "1" ).toInt(); m_chartinfo.showCpiCost = context.attribute( "show-cpi-cost", "1" ).toInt(); m_chartinfo.showSpiEffort = context.attribute( "show-spi-effort", "1" ).toInt(); m_chartinfo.showCpiEffort = context.attribute( "show-cpi-effort", "1" ).toInt(); debugPlan<<"Cost:"<project() ); dia->printer().setCreator("Plan"); return dia; } void PerformanceStatusBase::setNodes( const QList &nodes ) { m_chartmodel.setNodes( nodes ); static_cast( ui_performancetable->model() )->setNodes( nodes ); } //----------------------------------- PerformanceStatusTreeView::PerformanceStatusTreeView( QWidget *parent ) : QSplitter( parent ) , m_manager(0) { m_tree = new TreeViewBase( this ); NodeItemModel *m = new NodeItemModel( m_tree ); m_tree->setModel( m ); QList lst1; lst1 << 1 << -1; // only display column 0 (NodeName) in tree view m_tree->setDefaultColumns( QList() << 0 ); m_tree->setColumnsHidden( lst1 ); m_tree->setSelectionMode( QAbstractItemView::ExtendedSelection ); addWidget( m_tree ); m_tree->setTreePosition(-1); m_chart = new PerformanceStatusBase( this ); addWidget( m_chart ); - connect( m_tree->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) ); + connect( m_tree->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PerformanceStatusTreeView::slotSelectionChanged ); - QTimer::singleShot( 0, this, SLOT(resizeSplitters()) ); + QTimer::singleShot( 0, this, &PerformanceStatusTreeView::resizeSplitters ); } void PerformanceStatusTreeView::slotSelectionChanged( const QItemSelection&, const QItemSelection& ) { //debugPlan; QList nodes; foreach ( const QModelIndex &i, m_tree->selectionModel()->selectedIndexes() ) { Node *n = nodeModel()->node( i ); if ( ! nodes.contains( n ) ) { nodes.append( n ); } } m_chart->setNodes( nodes ); } NodeItemModel *PerformanceStatusTreeView::nodeModel() const { return static_cast( m_tree->model() ); } void PerformanceStatusTreeView::setScheduleManager( ScheduleManager *sm ) { if (!sm && m_manager) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); treeView()->saveExpanded(element); } bool tryexpand = sm && !m_manager; bool expand = sm && m_manager && sm != m_manager; QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); treeView()->saveExpanded(element); } m_manager = sm; nodeModel()->setScheduleManager( sm ); m_chart->setScheduleManager( sm ); if (expand) { treeView()->doExpand(doc); } else if (tryexpand) { treeView()->doExpand(m_domdoc); } } Project *PerformanceStatusTreeView::project() const { return nodeModel()->project(); } void PerformanceStatusTreeView::setProject( Project *project ) { nodeModel()->setProject( project ); m_chart->setProject( project ); } bool PerformanceStatusTreeView::loadContext( const KoXmlElement &context ) { debugPlan; bool res = false; res = m_chart->loadContext( context.namedItem( "chart" ).toElement() ); res &= m_tree->loadContext( nodeModel()->columnMap(), context.namedItem( "tree" ).toElement() ); return res; } void PerformanceStatusTreeView::saveContext( QDomElement &context ) const { QDomElement c = context.ownerDocument().createElement( "chart" ); context.appendChild( c ); m_chart->saveContext( c ); QDomElement t = context.ownerDocument().createElement( "tree" ); context.appendChild( t ); m_tree->saveContext( nodeModel()->columnMap(), t ); } KoPrintJob *PerformanceStatusTreeView::createPrintJob( ViewBase *view ) { return m_chart->createPrintJob( view ); } // hackish way to get reasonable initial splitter sizes void PerformanceStatusTreeView::resizeSplitters() { int x1 = sizes().value( 0 ); int x2 = sizes().value( 1 ); if ( x1 == 0 && x2 == 0 ) { // not shown yet, try later - QTimer::singleShot( 100, this, SLOT(resizeSplitters()) ); + QTimer::singleShot( 100, this, &PerformanceStatusTreeView::resizeSplitters ); return; } if ( x1 == 0 || x2 == 0 ) { // one is hidden, do nothing return; } int tot = x1 + x2; x1 = qMax( x1, qMin( ( tot ) / 2, 150 ) ); setSizes( QList() << x1 << ( tot - x1 ) ); } //----------------------------------- PerformanceStatusView::PerformanceStatusView(KoPart *part, KoDocument *doc, QWidget *parent ) : ViewBase(part, doc, parent ) { debugPlan<<"-------------------- creating PerformanceStatusView -------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new PerformanceStatusTreeView( this ); - connect(this, SIGNAL(expandAll()), m_view->treeView(), SLOT(slotExpand())); - connect(this, SIGNAL(collapseAll()), m_view->treeView(), SLOT(slotCollapse())); + connect(this, &ViewBase::expandAll, m_view->treeView(), &TreeViewBase::slotExpand); + connect(this, &ViewBase::collapseAll, m_view->treeView(), &TreeViewBase::slotCollapse); l->addWidget( m_view ); setupGui(); - connect( m_view->treeView(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); - connect( m_view->chartView(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view->treeView(), &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); + connect( m_view->chartView(), &QWidget::customContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); connect( m_view->treeView(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); Help::add(this, xi18nc("@info:whatsthis", "Task Performance View" "" "Displays performance data aggregated to the selected task." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Task_Performance_View"))); } void PerformanceStatusView::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { debugPlan<treeView()->setContextMenuIndex(index); if ( ! index.isValid() ) { slotHeaderContextMenuRequested( pos ); return; } Node *node = m_view->nodeModel()->node( index ); if ( node == 0 ) { slotHeaderContextMenuRequested( pos ); m_view->treeView()->setContextMenuIndex(QModelIndex()); return; } slotContextMenuRequested( node, pos ); m_view->treeView()->setContextMenuIndex(QModelIndex()); } Node *PerformanceStatusView::currentNode() const { return m_view->nodeModel()->node( m_view->treeView()->selectionModel()->currentIndex() ); } void PerformanceStatusView::slotContextMenuRequested( Node *node, const QPoint& pos ) { debugPlan<name()<<" :"<type() ) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } //debugPlan<setScheduleManager( sm ); } void PerformanceStatusView::setProject( Project *project ) { m_view->setProject( project ); } void PerformanceStatusView::setGuiActive( bool activate ) { debugPlan<objectName() == "print options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->show(); dlg->raise(); dlg->activateWindow(); } bool PerformanceStatusView::loadContext( const KoXmlElement &context ) { debugPlan; ViewBase::loadContext( context ); return m_view->loadContext( context ); } void PerformanceStatusView::saveContext( QDomElement &context ) const { ViewBase::saveContext( context ); m_view->saveContext( context ); } KoPrintJob *PerformanceStatusView::createPrintJob() { return m_view->createPrintJob( this ); } //------------------------------------------------ PerformanceStatusViewSettingsPanel::PerformanceStatusViewSettingsPanel( PerformanceStatusBase *view, QWidget *parent ) : QWidget( parent ), m_view( view ) { setupUi( this ); #ifndef PLAN_CHART_DEBUG ui_table->hide(); #endif PerformanceChartInfo info = m_view->chartInfo(); ui_linechart->setChecked( info.showLineChart ); ui_barchart->setChecked( info.showBarChart ); #ifdef PLAN_CHART_DEBUG ui_table->setChecked( info.showTableView ); #endif ui_bcwsCost->setCheckState( info.showBCWSCost ? Qt::Checked : Qt::Unchecked ); ui_bcwpCost->setCheckState( info.showBCWPCost ? Qt::Checked : Qt::Unchecked ); ui_acwpCost->setCheckState( info.showACWPCost ? Qt::Checked : Qt::Unchecked ); ui_cost->setChecked( info.showCost ); ui_bcwsEffort->setCheckState( info.showBCWSEffort ? Qt::Checked : Qt::Unchecked ); ui_bcwpEffort->setCheckState( info.showBCWPEffort ? Qt::Checked : Qt::Unchecked ); ui_acwpEffort->setCheckState( info.showACWPEffort ? Qt::Checked : Qt::Unchecked ); ui_effort->setChecked( info.showEffort ); ui_showbasevalues->setChecked( info.showBaseValues ); ui_showindices->setChecked( info.showIndices ); ui_spicost->setCheckState( info.showSpiCost ? Qt::Checked : Qt::Unchecked ); ui_cpicost->setCheckState( info.showCpiCost ? Qt::Checked : Qt::Unchecked ); ui_spieffort->setCheckState( info.showSpiEffort ? Qt::Checked : Qt::Unchecked ); ui_cpieffort->setCheckState( info.showCpiEffort ? Qt::Checked : Qt::Unchecked ); - connect(ui_showbasevalues, SIGNAL(toggled(bool)), SLOT(switchStackWidget())); - connect(ui_showindices, SIGNAL(toggled(bool)), SLOT(switchStackWidget())); + connect(ui_showbasevalues, &QAbstractButton::toggled, this, &PerformanceStatusViewSettingsPanel::switchStackWidget); + connect(ui_showindices, &QAbstractButton::toggled, this, &PerformanceStatusViewSettingsPanel::switchStackWidget); switchStackWidget(); } void PerformanceStatusViewSettingsPanel::slotOk() { PerformanceChartInfo info; info.showLineChart = ui_linechart->isChecked(); info.showBarChart = ui_barchart->isChecked(); info.showTableView = ui_table->isChecked(); info.showBaseValues = ui_showbasevalues->isChecked(); info.showIndices = ui_showindices->isChecked(); info.showBCWSCost = ui_bcwsCost->checkState() == Qt::Unchecked ? false : true; info.showBCWPCost = ui_bcwpCost->checkState() == Qt::Unchecked ? false : true; info.showACWPCost = ui_acwpCost->checkState() == Qt::Unchecked ? false : true; info.showCost = ui_cost->isChecked(); info.showBCWSEffort = ui_bcwsEffort->checkState() == Qt::Unchecked ? false : true; info.showBCWPEffort = ui_bcwpEffort->checkState() == Qt::Unchecked ? false : true; info.showACWPEffort = ui_acwpEffort->checkState() == Qt::Unchecked ? false : true; info.showEffort = ui_effort->isChecked(); info.showSpiCost = ui_spicost->isChecked(); info.showCpiCost = ui_cpicost->isChecked(); info.showSpiEffort = ui_spieffort->isChecked(); info.showCpiEffort = ui_cpieffort->isChecked(); m_view->setChartInfo( info ); } void PerformanceStatusViewSettingsPanel::setDefault() { ui_linechart->setChecked( true ); ui_bcwsCost->setCheckState( Qt::Checked ); ui_bcwpCost->setCheckState( Qt::Checked ); ui_acwpCost->setCheckState( Qt::Checked ); ui_cost->setChecked( true ); ui_bcwsEffort->setCheckState( Qt::Checked ); ui_bcwpEffort->setCheckState( Qt::Checked ); ui_acwpEffort->setCheckState( Qt::Checked ); ui_effort->setChecked( Qt::Unchecked ); ui_showbasevalues->setChecked( true ); ui_showindices->setChecked( false ); ui_spicost->setCheckState( Qt::Checked ); ui_cpicost->setCheckState( Qt::Checked ); ui_spieffort->setCheckState( Qt::Checked ); ui_cpieffort->setCheckState( Qt::Checked ); } void PerformanceStatusViewSettingsPanel::switchStackWidget() { if ( ui_showbasevalues->isChecked() ) { ui_stackWidget->setCurrentIndex( 0 ); } else if ( ui_showindices->isChecked() ) { ui_stackWidget->setCurrentIndex( 1 ); } //debugPlan<currentIndex(); } //----------------- PerformanceStatusViewSettingsDialog::PerformanceStatusViewSettingsDialog( PerformanceStatusView *view, PerformanceStatusTreeView *treeview, QWidget *parent, bool selectPrint ) : ItemViewSettupDialog( view, treeview->treeView(), true, parent ) { PerformanceStatusViewSettingsPanel *panel = new PerformanceStatusViewSettingsPanel( treeview->chartView(), this ); KPageWidgetItem *page = insertWidget( 0, panel, i18n( "Chart" ), i18n( "Chart Settings" ) ); setCurrentPage( page ); addPrintingOptions(selectPrint); //connect( panel, SIGNAL(changed(bool)), this, SLOT(enableButtonOk(bool)) ); - connect( this, SIGNAL(accepted()), panel, SLOT(slotOk()) ); - connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(setDefault()) ); + connect( this, &QDialog::accepted, panel, &PerformanceStatusViewSettingsPanel::slotOk ); + connect( button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, panel, &PerformanceStatusViewSettingsPanel::setDefault ); } //----------------- ProjectStatusViewSettingsDialog::ProjectStatusViewSettingsDialog( ViewBase *base, PerformanceStatusBase *view, QWidget *parent, bool selectPrint ) : KPageDialog( parent ), m_base( base ) { PerformanceStatusViewSettingsPanel *panel = new PerformanceStatusViewSettingsPanel( view, this ); KPageWidgetItem *page = new KPageWidgetItem( panel, i18n( "Chart" ) ); page->setHeader( i18n( "Chart Settings" ) ); addPage( page ); QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( base ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_headerfooter = ViewBase::createHeaderFooterWidget( base ); m_headerfooter->setOptions( base->printingOptions() ); tab->addTab( m_headerfooter, m_headerfooter->windowTitle() ); page = addPage( tab, i18n( "Printing" ) ); page->setHeader( i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } - connect( this, SIGNAL(accepted()), panel, SLOT(slotOk()) ); + connect( this, &QDialog::accepted, panel, &PerformanceStatusViewSettingsPanel::slotOk ); //TODO: there was no default button configured, should there? // connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(setDefault()) ); - connect( this, SIGNAL(accepted()), this, SLOT(slotOk())); + connect( this, &QDialog::accepted, this, &ProjectStatusViewSettingsDialog::slotOk); } void ProjectStatusViewSettingsDialog::slotOk() { debugPlan; m_base->setPageLayout( m_pagelayout->pageLayout() ); m_base->setPrintingOptions( m_headerfooter->options() ); } } // namespace KPlato diff --git a/src/libs/ui/kptusedefforteditor.cpp b/src/libs/ui/kptusedefforteditor.cpp index d17ba457..6316e7ae 100644 --- a/src/libs/ui/kptusedefforteditor.cpp +++ b/src/libs/ui/kptusedefforteditor.cpp @@ -1,876 +1,876 @@ /* This file is part of the KDE project Copyright (C) 2007, 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. */ #include "kptusedefforteditor.h" #include "kptitemmodelbase.h" #include #include #include #include #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdebug.h" namespace KPlato { UsedEffortItemModel::UsedEffortItemModel ( QWidget *parent ) : QAbstractItemModel( parent ), m_completion( 0 ), m_readonly( false ) { m_headers << i18n( "Resource" ); QLocale locale; for ( int i = 1; i <= 7; ++i ) { m_headers << locale.dayName( i, QLocale::ShortFormat ); } m_headers << i18n( "This Week" ); } Qt::ItemFlags UsedEffortItemModel::flags ( const QModelIndex &index ) const { Qt::ItemFlags flags = QAbstractItemModel::flags( index ); if ( m_readonly || ! index.isValid() || index.column() == 8 ) { return flags; } if ( index.column() == 0 ) { const Resource *r = resource( index ); if ( r ) { if ( m_resourcelist.contains( r ) && ! m_completion->usedEffortMap().contains( r ) ) { return flags | Qt::ItemIsEditable; } } return flags; } return flags | Qt::ItemIsEditable; } QVariant UsedEffortItemModel::data ( const QModelIndex &index, int role ) const { if ( ! index.isValid() ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: { if ( index.column() == 0 ) { const Resource *r = resource( index ); //debugPlan<name(); } break; } Completion::UsedEffort *ue = usedEffort( index ); if ( ue == 0 ) { return QVariant(); } if ( index.column() == 8 ) { // Total //debugPlan<effort( d ); res += e.normalEffort().toDouble( Duration::Unit_h ); } return QLocale().toString(res, 'f', 1 ); } Completion::UsedEffort::ActualEffort e = ue->effort( m_dates.value( index.column() - 1 ) ); double res = e.normalEffort().toDouble( Duration::Unit_h ); return QLocale().toString(res, 'f', 1 ); } case Qt::EditRole: { if ( index.column() == 8 ) { return QVariant(); } if ( index.column() == 0 ) { const Resource *r = resource( index ); //debugPlan<name(); } } else { Completion::UsedEffort *ue = usedEffort( index ); if ( ue == 0 ) { return QVariant(); } Completion::UsedEffort::ActualEffort e = ue->effort( m_dates.value( index.column() - 1 ) ); double res = e.normalEffort().toDouble( Duration::Unit_h ); return QLocale().toString(res, 'f', 1 ); } break; } case Role::EnumList: { if ( index.column() == 0 ) { QStringList lst = m_editlist.keys(); return lst; } break; } case Role::EnumListValue: { if ( index.column() == 0 ) { return m_editlist.values().indexOf( resource( index ) ); // clazy:exclude=container-anti-pattern } break; } default: break; } return QVariant(); } bool UsedEffortItemModel::setData ( const QModelIndex &idx, const QVariant &value, int role ) { debugPlan; switch ( role ) { case Qt::EditRole: { if ( idx.column() == 8 ) { return false; } if ( idx.column() == 0 ) { const Resource *er = resource( idx ); Q_ASSERT( er != 0 ); Q_ASSERT ( m_editlist.count() > value.toInt() ); const Resource *v = m_editlist.values().value( value.toInt() ); // clazy:exclude=container-anti-pattern Q_ASSERT( v != 0 ); int x = m_resourcelist.indexOf( er ); Q_ASSERT( x != -1 ); m_resourcelist.replace( x, v ); m_completion->addUsedEffort( v ); emit dataChanged( createIndex( idx.row(), 1 ), createIndex( idx.row(), columnCount() - 1 ) ); emit rowInserted( createIndex( idx.row(), 0 ) ); return true; } Completion::UsedEffort *ue = usedEffort( idx ); if ( ue == 0 ) { return false; } QDate d = m_dates.value( idx.column() - 1 ); Completion::UsedEffort::ActualEffort e = ue->effort( d ); e.setNormalEffort( Duration( value.toDouble(), Duration::Unit_h ) ); ue->setEffort( d, e ); emit dataChanged( idx, idx ); return true; } default: break; } return false; } bool UsedEffortItemModel::submit() { debugPlan; return QAbstractItemModel::submit(); } void UsedEffortItemModel::revert() { debugPlan; QList lst = m_resourcelist; foreach ( const Resource *r, lst ) { if ( ! m_completion->usedEffortMap().contains( r ) ) { int row = m_resourcelist.indexOf( r ); if ( row != -1 ) { beginRemoveRows( QModelIndex(), row, row ); m_resourcelist.removeAt( row ); endRemoveRows(); } } } } QVariant UsedEffortItemModel::headerData ( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Vertical ) { return QVariant(); } if ( section < 0 || section >= m_headers.count() ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: return m_headers.at( section ); case Qt::ToolTipRole: { if ( section >= 1 && section <= 7 ) { return QLocale().toString(m_dates.at( section - 1 ), QLocale::ShortFormat); } if ( section == 8 ) { return i18n( "Total effort this week" ); } break; } default: break; } return QVariant(); } int UsedEffortItemModel::columnCount(const QModelIndex & parent ) const { int c = 0; if ( m_completion && ! parent.isValid() ) { c = 9; } return c; } int UsedEffortItemModel::rowCount(const QModelIndex & ) const { int rows = 0; if ( m_completion ) { rows = m_resourcelist.count(); } return rows; } QModelIndex UsedEffortItemModel::index ( int row, int column, const QModelIndex &parent ) const { if ( parent.isValid() ) { return QModelIndex(); } return createIndex( row, column ); } void UsedEffortItemModel::setCompletion( Completion *completion ) { beginResetModel(); m_completion = completion; m_resourcelist.clear(); QMap lst; const Completion::ResourceUsedEffortMap &map = completion->usedEffortMap(); Completion::ResourceUsedEffortMap::const_iterator it; for (it = map.constBegin(); it != map.constEnd(); ++it) { lst.insertMulti(it.key()->name(), it.key()); } m_resourcelist = lst.values(); endResetModel(); } const Resource *UsedEffortItemModel::resource(const QModelIndex &index ) const { int row = index.row(); if ( m_completion == 0 || row < 0 || row >= m_resourcelist.count() ) { return 0; } return m_resourcelist.value( row ); } Completion::UsedEffort *UsedEffortItemModel::usedEffort(const QModelIndex &index ) const { const Resource *r = resource( index ); if ( r == 0 ) { return 0; } return m_completion->usedEffort( r ); } void UsedEffortItemModel::setCurrentMonday( const QDate &date ) { beginResetModel(); m_dates.clear(); for ( int i = 0; i < 7; ++i ) { m_dates << date.addDays( i ); } endResetModel(); emit headerDataChanged ( Qt::Horizontal, 1, 7 ); } QModelIndex UsedEffortItemModel::addRow() { if ( m_project == 0 ) { return QModelIndex(); } m_editlist.clear(); m_editlist = freeResources(); if ( m_editlist.isEmpty() ) { return QModelIndex(); } int row = rowCount(); beginInsertRows( QModelIndex(), row, row ); m_resourcelist.append(m_editlist.first()); endInsertRows(); return createIndex(row, 0, const_cast(m_editlist.first())); } QMap UsedEffortItemModel::freeResources() const { QMap map; foreach ( Resource *r, m_project->resourceList() ) { if ( ! m_resourcelist.contains( r ) ) { map.insertMulti( r->name(), r ); } } return map; } //----------- UsedEffortEditor::UsedEffortEditor( QWidget *parent ) : QTableView( parent ) { UsedEffortItemModel *m = new UsedEffortItemModel(this ); setModel( m ); setItemDelegateForColumn ( 0, new EnumDelegate( this ) ); setItemDelegateForColumn ( 1, new DoubleSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 2, new DoubleSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 3, new DoubleSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 4, new DoubleSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 5, new DoubleSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 6, new DoubleSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 7, new DoubleSpinBoxDelegate( this ) ); - connect ( model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SIGNAL(changed()) ); + connect ( model(), &QAbstractItemModel::dataChanged, this, &UsedEffortEditor::changed ); - connect ( m, SIGNAL(rowInserted(QModelIndex)), SIGNAL(resourceAdded()) ); + connect ( m, &UsedEffortItemModel::rowInserted, this, &UsedEffortEditor::resourceAdded ); } bool UsedEffortEditor::hasFreeResources() const { return ! static_cast( model() )->freeResources().isEmpty(); } void UsedEffortEditor::setProject( Project *p ) { static_cast( model() )->setProject( p ); } void UsedEffortEditor::setCompletion( Completion *completion ) { static_cast( model() )->setCompletion( completion ); } void UsedEffortEditor::setCurrentMonday( const QDate &date ) { static_cast( model() )->setCurrentMonday( date ); } void UsedEffortEditor::addResource() { UsedEffortItemModel *m = static_cast( model() ); QModelIndex i = m->addRow(); if ( i.isValid() ) { setCurrentIndex( i ); edit( i ); } } //---------------------------------------- CompletionEntryItemModel::CompletionEntryItemModel ( QObject *parent ) : QAbstractItemModel( parent ), m_node( 0 ), m_project( 0 ), m_manager( 0 ), m_completion( 0 ) { m_headers << i18n( "Date" ) // xgettext: no-c-format << i18n( "% Completed" ) << i18n( "Used Effort" ) << i18n( "Remaining Effort" ) << i18n( "Planned Effort" ); m_flags.insert( Property_Date, Qt::NoItemFlags ); m_flags.insert( Property_Completion, Qt::ItemIsEditable ); m_flags.insert( Property_UsedEffort, Qt::NoItemFlags ); m_flags.insert( Property_RemainingEffort, Qt::ItemIsEditable ); m_flags.insert( Property_PlannedEffort, Qt::NoItemFlags ); } void CompletionEntryItemModel::setTask( Task *t ) { m_node = t; m_project = 0; if ( m_node && m_node->projectNode() ) { m_project = static_cast( m_node->projectNode() ); } } void CompletionEntryItemModel::slotDataChanged() { refresh(); } void CompletionEntryItemModel::setManager( ScheduleManager *sm ) { m_manager = sm; refresh(); } Qt::ItemFlags CompletionEntryItemModel::flags ( const QModelIndex &index ) const { if ( index.isValid() && index.column() < m_flags.count() ) { return QAbstractItemModel::flags( index ) | m_flags[ index.column() ]; } return QAbstractItemModel::flags( index ); } QVariant CompletionEntryItemModel::date ( int row, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return m_datelist.value( row ); default: break; } return QVariant(); } QVariant CompletionEntryItemModel::percentFinished ( int row, int role ) const { Completion::Entry *e = m_completion->entry( date( row ).toDate() ); if ( e == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return e->percentFinished; default: break; } return QVariant(); } QVariant CompletionEntryItemModel::remainingEffort ( int row, int role ) const { Completion::Entry *e = m_completion->entry( date( row ).toDate() ); if ( e == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { return e->remainingEffort.format(); } case Qt::EditRole: return e->remainingEffort.toDouble( Duration::Unit_h ); case Role::DurationScales: { QVariantList lst; // TODO: week if ( m_node && m_project ) { if ( m_node->estimate()->type() == Estimate::Type_Effort ) { lst.append( m_project->standardWorktime()->day() ); } } if ( lst.isEmpty() ) { lst.append( 24.0 ); } lst << 60.0 << 60.0 << 1000.0; return lst; } case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Role::Minimum: return m_project->config().minimumDurationUnit(); case Role::Maximum: return m_project->config().maximumDurationUnit(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CompletionEntryItemModel::actualEffort ( int row, int role ) const { Completion::Entry *e = m_completion->entry( date( row ).toDate() ); if ( e == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { Duration v; if ( m_completion->entrymode() == Completion::EnterEffortPerResource ) { v = m_completion->actualEffortTo( date( row ).toDate() ); } else { v = e->totalPerformed; } //debugPlan<name()<<": "<totalPerformed.toDouble( Duration::Unit_h ); case Role::DurationScales: { QVariantList lst; // TODO: week if ( m_node && m_project ) { if ( m_node->estimate()->type() == Estimate::Type_Effort ) { lst.append( m_project->standardWorktime()->day() ); } } if ( lst.isEmpty() ) { lst.append( 24 ); } lst << 60 << 60 << 1000; return lst; } case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Role::Minimum: return m_project->config().minimumDurationUnit(); case Role::Maximum: return m_project->config().maximumDurationUnit(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CompletionEntryItemModel::plannedEffort ( int /*row*/, int role ) const { if ( m_node == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { Duration v = m_node->plannedEffort( id(), ECCT_EffortWork ); //debugPlan<name()<<": "<estimate()->type() == Estimate::Type_Effort ) { lst.append( m_project->standardWorktime()->day() ); } } if ( lst.isEmpty() ) { lst.append( 24.0 ); } lst << 60.0 << 60.0 << 1000.0; return lst; } case Role::DurationUnit: return static_cast( Duration::Unit_h ); case Role::Minimum: return m_project->config().minimumDurationUnit(); case Role::Maximum: return m_project->config().maximumDurationUnit(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant CompletionEntryItemModel::data ( const QModelIndex &index, int role ) const { if ( ! index.isValid() ) { return QVariant(); } switch ( index.column() ) { case Property_Date: return date( index.row(), role ); case Property_Completion: return percentFinished( index.row(), role ); case Property_UsedEffort: return actualEffort( index.row(), role ); case Property_RemainingEffort: return remainingEffort( index.row(), role ); case Property_PlannedEffort: return plannedEffort( index.row(), role ); default: break; } return QVariant(); } QList CompletionEntryItemModel::scales() const { QList lst; if ( m_node && m_project ) { if ( m_node->estimate()->type() == Estimate::Type_Effort ) { lst = m_project->standardWorktime()->scales(); } } if ( lst.isEmpty() ) { lst = Estimate::defaultScales(); } //debugPlan<entry( date( idx.row() ).toDate() ); if ( e == 0 ) { return false; } e->percentFinished = value.toInt(); if ( m_completion->entrymode() == Completion::EnterCompleted && m_node ) { // calculate used/remaining Duration est = m_node->plannedEffort( id(), ECCT_EffortWork ); e->totalPerformed = est * e->percentFinished / 100; e->remainingEffort = est - e->totalPerformed; } emit dataChanged( idx, createIndex( idx.row(), 3 ) ); return true; } if ( idx.column() == Property_UsedEffort ) { Completion::Entry *e = m_completion->entry( date( idx.row() ).toDate() ); if ( e == 0 ) { return false; } double v( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration d = Estimate::scale( v, unit, scales() ); if ( d == e->totalPerformed ) { return false; } e->totalPerformed = d; emit dataChanged( idx, idx ); return true; } if ( idx.column() == Property_RemainingEffort ) { Completion::Entry *e = m_completion->entry( date( idx.row() ).toDate() ); if ( e == 0 ) { return false; } double v( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration d = Estimate::scale( v, unit, scales() ); if ( d == e->remainingEffort ) { return false; } e->remainingEffort = d; emit dataChanged( idx, idx ); return true; } } default: break; } return false; } bool CompletionEntryItemModel::submit() { debugPlan<= m_headers.count() ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: return m_headers.at( section ); default: break; } return QVariant(); } int CompletionEntryItemModel::columnCount(const QModelIndex & /*parent */) const { return 5; } int CompletionEntryItemModel::rowCount(const QModelIndex &idx ) const { if ( m_completion == 0 || idx.isValid() ) { return 0; } return m_datelist.count(); } QModelIndex CompletionEntryItemModel::index ( int row, int column, const QModelIndex &parent ) const { if ( parent.isValid() ) { return QModelIndex(); } return createIndex( row, column ); } void CompletionEntryItemModel::setCompletion( Completion *completion ) { m_completion = completion; refresh(); } void CompletionEntryItemModel::refresh() { beginResetModel(); m_datelist.clear(); m_flags[ Property_UsedEffort ] = Qt::NoItemFlags; if ( m_completion ) { m_datelist = m_completion->entries().keys(); if ( m_completion->entrymode() == Completion::EnterEffortPerTask ) { m_flags[ Property_UsedEffort ] = Qt::ItemIsEditable; } } debugPlan< 0 && d <= m_datelist.last() ) { d = m_datelist.last().addDays( 1 ); } beginInsertRows( QModelIndex(), row, row ); m_datelist.append( d ); endInsertRows(); return createIndex( row, 0 ); } void CompletionEntryItemModel::removeEntry( const QDate& date ) { removeRow( m_datelist.indexOf( date ) ); } void CompletionEntryItemModel::removeRow( int row ) { debugPlan<= rowCount() ) { return; } QDate date = m_datelist.value( row ); beginRemoveRows( QModelIndex(), row, row ); m_datelist.removeAt( row ); endRemoveRows(); debugPlan<takeEntry( date ); emit rowRemoved( date ); emit changed(); } void CompletionEntryItemModel::addEntry( const QDate& date ) { debugPlan<entries().isEmpty() ) { if ( m_node ) { e->remainingEffort = m_node->plannedEffort( id(), ECCT_EffortWork ); } } else { e->percentFinished = m_completion->percentFinished(); e->totalPerformed = m_completion->actualEffort(); e->remainingEffort = m_completion->remainingEffort(); } m_completion->addEntry( date, e ); refresh(); int i = m_datelist.indexOf( date ); if ( i != -1 ) { emit rowInserted( date ); emit dataChanged( createIndex( i, 1 ), createIndex( i, rowCount() - 1 ) ); } else errorPlan<<"Failed to find added entry: "<hide(); CompletionEntryItemModel *m = new CompletionEntryItemModel(this ); setItemDelegateForColumn ( 1, new ProgressBarDelegate( this ) ); setItemDelegateForColumn ( 2, new DurationSpinBoxDelegate( this ) ); setItemDelegateForColumn ( 3, new DurationSpinBoxDelegate( this ) ); setCompletionModel( m ); } void CompletionEntryEditor::setCompletionModel( CompletionEntryItemModel *m ) { if ( model() ) { - disconnect(model(), SIGNAL(rowInserted(QDate)), this, SIGNAL(rowInserted(QDate))); - disconnect(model(), SIGNAL(rowRemoved(QDate)), this, SIGNAL(rowRemoved(QDate))); - disconnect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SIGNAL(changed())); - disconnect(model(), SIGNAL(changed()), this, SIGNAL(changed())); - disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(selectedItemsChanged(QItemSelection,QItemSelection))); + disconnect(model(), &CompletionEntryItemModel::rowInserted, this, &CompletionEntryEditor::rowInserted); + disconnect(model(), &CompletionEntryItemModel::rowRemoved, this, &CompletionEntryEditor::rowRemoved); + disconnect(model(), &QAbstractItemModel::dataChanged, this, &CompletionEntryEditor::changed); + disconnect(model(), &CompletionEntryItemModel::changed, this, &CompletionEntryEditor::changed); + disconnect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &CompletionEntryEditor::selectedItemsChanged); } setModel( m ); if ( model() ) { - connect(model(), SIGNAL(rowInserted(QDate)), this, SIGNAL(rowInserted(QDate))); - connect(model(), SIGNAL(rowRemoved(QDate)), this, SIGNAL(rowRemoved(QDate))); - connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SIGNAL(changed())); - connect(model(), SIGNAL(changed()), this, SIGNAL(changed())); - connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(selectedItemsChanged(QItemSelection,QItemSelection))); + connect(model(), &CompletionEntryItemModel::rowInserted, this, &CompletionEntryEditor::rowInserted); + connect(model(), &CompletionEntryItemModel::rowRemoved, this, &CompletionEntryEditor::rowRemoved); + connect(model(), &QAbstractItemModel::dataChanged, this, &CompletionEntryEditor::changed); + connect(model(), &CompletionEntryItemModel::changed, this, &CompletionEntryEditor::changed); + connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &CompletionEntryEditor::selectedItemsChanged); } } void CompletionEntryEditor::setCompletion( Completion *completion ) { model()->setCompletion( completion ); } void CompletionEntryEditor::addEntry() { debugPlan<addRow(); if ( i.isValid() ) { model()->setFlags( i.column(), Qt::ItemIsEditable ); setCurrentIndex( i ); emit selectedItemsChanged(QItemSelection(), QItemSelection()); //hmmm, control removeEntryBtn scrollTo( i ); edit( i ); model()->setFlags( i.column(), Qt::NoItemFlags ); } } void CompletionEntryEditor::removeEntry() { //debugPlan; QModelIndexList lst = selectedIndexes(); debugPlan< rows; while ( ! lst.isEmpty() ) { QModelIndex idx = lst.takeFirst(); rows[ idx.row() ] = 0; } QList r = rows.uniqueKeys(); debugPlan<= 0; --i ) { model()->removeRow( r.at( i ) ); } } } //KPlato namespace diff --git a/src/libs/ui/kptviewbase.cpp b/src/libs/ui/kptviewbase.cpp index df43dc4f..99e4f5d3 100644 --- a/src/libs/ui/kptviewbase.cpp +++ b/src/libs/ui/kptviewbase.cpp @@ -1,2524 +1,2524 @@ /* This file is part of the KDE project Copyright (C) 2006 -2010, 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. */ #include "kptviewbase.h" #include "kptitemmodelbase.h" #include "kptproject.h" #include "kptdebug.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KPlato { DockWidget::DockWidget( ViewBase *v, const QString &identity, const QString &title ) : QDockWidget( v ), view( v ), id( identity ), location( Qt::RightDockWidgetArea ), editor( false ), m_shown( true ) { setWindowTitle( title ); setObjectName( v->objectName() + '-' + identity ); toggleViewAction()->setObjectName( objectName() ); - connect(this, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), SLOT(setLocation(Qt::DockWidgetArea))); + connect(this, &QDockWidget::dockLocationChanged, this, &DockWidget::setLocation); } void DockWidget::activate( KoMainWindow *mainWindow ) { - connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(setShown(bool))); + connect(this, &QDockWidget::visibilityChanged, this, &DockWidget::setShown); setVisible( m_shown ); mainWindow->addDockWidget( location, this ); foreach(const KActionCollection *c, KActionCollection::allCollections()) { KActionMenu *a = qobject_cast(c->action("settings_dockers_menu")); if ( a ) { a->addAction( toggleViewAction() ); break; } } } void DockWidget::deactivate( KoMainWindow *mainWindow ) { - disconnect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(setShown(bool))); + disconnect(this, &QDockWidget::visibilityChanged, this, &DockWidget::setShown); mainWindow->removeDockWidget( this ); // activation re-parents to QMainWindow, so re-parent back to view setParent( const_cast( view ) ); foreach(const KActionCollection *c, KActionCollection::allCollections()) { KActionMenu *a = qobject_cast(c->action("settings_dockers_menu")); if ( a ) { a->removeAction( toggleViewAction() ); break; } } } void DockWidget::setShown( bool show ) { m_shown = show; setVisible( show ); } bool KPlato::DockWidget::shown() const { return m_shown; } void DockWidget::setLocation( Qt::DockWidgetArea area ) { location = area; } bool DockWidget::saveXml( QDomElement &context ) const { QDomElement e = context.ownerDocument().createElement( "docker" ); context.appendChild( e ); e.setAttribute( "id", id ); e.setAttribute( "location", QString::number(location) ); e.setAttribute( "floating", QString::number(isFloating()) ); e.setAttribute( "visible", QString::number(m_shown) ); return true; } void DockWidget::loadXml(const KoXmlElement& context) { location = static_cast( context.attribute( "location", "0" ).toInt() ); setFloating( (bool) context.attribute( "floating", "0" ).toInt() ); m_shown = context.attribute( "visible", "1" ).toInt(); } //------------------------ bool PrintingOptions::loadXml( KoXmlElement &element ) { KoXmlElement e; forEachElement( e, element ) { if ( e.tagName() == "header" ) { headerOptions.group = e.attribute( "group", "0" ).toInt(); headerOptions.project = static_cast( e.attribute( "project", "0" ).toInt() ); headerOptions.date = static_cast( e.attribute( "date", "0" ).toInt() ); headerOptions.manager = static_cast( e.attribute( "manager", "0" ).toInt() ); headerOptions.page = static_cast( e.attribute( "page", "0" ).toInt() ); } else if ( e.tagName() == "footer" ) { footerOptions.group = e.attribute( "group", "0" ).toInt(); footerOptions.project = static_cast( e.attribute( "project", "0" ).toInt() ); footerOptions.date = static_cast( e.attribute( "date", "0" ).toInt() ); footerOptions.manager = static_cast( e.attribute( "manager", "0" ).toInt() ); footerOptions.page = static_cast( e.attribute( "page", "0" ).toInt() ); } } return true; } void PrintingOptions::saveXml( QDomElement &element ) const { QDomElement me = element.ownerDocument().createElement( "printing-options" ); element.appendChild( me ); QDomElement h = me.ownerDocument().createElement( "header" ); me.appendChild( h ); h.setAttribute( "group", QString::number(headerOptions.group) ); h.setAttribute( "project", QString::number(headerOptions.project) ); h.setAttribute( "date", QString::number(headerOptions.date) ); h.setAttribute( "manager", QString::number(headerOptions.manager) ); h.setAttribute( "page", QString::number(headerOptions.page) ); QDomElement f = me.ownerDocument().createElement( "footer" ); me.appendChild( f ); f.setAttribute( "group", QString::number(footerOptions.group) ); f.setAttribute( "project", QString::number(footerOptions.project) ); f.setAttribute( "date", QString::number(footerOptions.date) ); f.setAttribute( "manager", QString::number(footerOptions.manager) ); f.setAttribute( "page", QString::number(footerOptions.page) ); } //---------------------- PrintingHeaderFooter::PrintingHeaderFooter( const PrintingOptions &opt, QWidget *parent ) : QWidget( parent ) { setupUi( this ); setWindowTitle( i18n("Header and Footer" )); setOptions( opt ); - connect(ui_header, SIGNAL(toggled(bool)), SLOT(slotChanged())); - connect(ui_headerProject, SIGNAL(stateChanged(int)), SLOT(slotChanged())); - connect(ui_headerPage, SIGNAL(stateChanged(int)), SLOT(slotChanged())); - connect(ui_headerManager, SIGNAL(stateChanged(int)), SLOT(slotChanged())); - connect(ui_headerDate, SIGNAL(stateChanged(int)), SLOT(slotChanged())); + connect(ui_header, &QGroupBox::toggled, this, &PrintingHeaderFooter::slotChanged); + connect(ui_headerProject, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); + connect(ui_headerPage, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); + connect(ui_headerManager, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); + connect(ui_headerDate, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); - connect(ui_footer, SIGNAL(toggled(bool)), SLOT(slotChanged())); - connect(ui_footerProject, SIGNAL(stateChanged(int)), SLOT(slotChanged())); - connect(ui_footerPage, SIGNAL(stateChanged(int)), SLOT(slotChanged())); - connect(ui_footerManager, SIGNAL(stateChanged(int)), SLOT(slotChanged())); - connect(ui_footerDate, SIGNAL(stateChanged(int)), SLOT(slotChanged())); + connect(ui_footer, &QGroupBox::toggled, this, &PrintingHeaderFooter::slotChanged); + connect(ui_footerProject, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); + connect(ui_footerPage, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); + connect(ui_footerManager, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); + connect(ui_footerDate, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged); } PrintingHeaderFooter::~PrintingHeaderFooter() { //debugPlan; } void PrintingHeaderFooter::slotChanged() { debugPlan; emit changed( options() ); } void PrintingHeaderFooter::setOptions( const PrintingOptions &options ) { m_options = options; ui_header->setChecked( m_options.headerOptions.group ); ui_headerProject->setCheckState( m_options.headerOptions.project ); ui_headerDate->setCheckState( m_options.headerOptions.date ); ui_headerManager->setCheckState( m_options.headerOptions.manager ); ui_headerPage->setCheckState( m_options.headerOptions.page ); ui_footer->setChecked( m_options.footerOptions.group ); ui_footerProject->setCheckState( m_options.footerOptions.project ); ui_footerDate->setCheckState( m_options.footerOptions.date ); ui_footerManager->setCheckState( m_options.footerOptions.manager ); ui_footerPage->setCheckState( m_options.footerOptions.page ); } PrintingOptions PrintingHeaderFooter::options() const { //debugPlan; PrintingOptions opt; opt.headerOptions.group = ui_header->isChecked(); opt.headerOptions.project = ui_headerProject->checkState(); opt.headerOptions.date = ui_headerDate->checkState(); opt.headerOptions.manager = ui_headerManager->checkState(); opt.headerOptions.page = ui_headerPage->checkState(); opt.footerOptions.group = ui_footer->isChecked(); opt.footerOptions.project = ui_footerProject->checkState(); opt.footerOptions.date = ui_footerDate->checkState( ); opt.footerOptions.manager = ui_footerManager->checkState(); opt.footerOptions.page = ui_footerPage->checkState(); return opt; } PrintingDialog::PrintingDialog( ViewBase *view ) : KoPrintingDialog( view ), m_view( view ), m_widget( 0 ) { setPrinterPageLayout( view->pageLayout() ); QImage px( 100, 600, QImage::Format_Mono ); int dpm = printer().resolution() * 40; px.setDotsPerMeterX( dpm ); px.setDotsPerMeterY( dpm ); QPainter p( &px ); m_textheight = p.boundingRect( QRectF(), Qt::AlignTop, "Aj" ).height(); debugPlan<<"textheight:"<printingOptions(); } void PrintingDialog::setPrintingOptions( const PrintingOptions &opt ) { debugPlan; m_view->setPrintingOptions( opt ); emit changed( opt ); emit changed(); } void PrintingDialog::setPrinterPageLayout( const KoPageLayout &pagelayout ) { QPrinter &p = printer(); QPrinter::Orientation o; switch ( pagelayout.orientation ) { case KoPageFormat::Portrait: o = QPrinter::Portrait; break; case KoPageFormat::Landscape: o = QPrinter::Landscape; break; default: o = QPrinter::Portrait; break; } p.setOrientation( o ); p.setPaperSize( KoPageFormat::printerPageSize( pagelayout.format ) ); p.setPageMargins( pagelayout.leftMargin, pagelayout.topMargin, pagelayout.rightMargin, pagelayout.bottomMargin, QPrinter::Point ); } void PrintingDialog::startPrinting(RemovePolicy removePolicy ) { setPrinterPageLayout( m_view->pageLayout() ); // FIXME: Something resets printer().paperSize() to A4 ! KoPrintingDialog::startPrinting( removePolicy ); } QWidget *PrintingDialog::createPageLayoutWidget() const { QWidget *w = ViewBase::createPageLayoutWidget( m_view ); KoPageLayoutWidget *pw = w->findChild(); connect(pw, SIGNAL(layoutChanged(KoPageLayout)), m_view, SLOT(setPageLayout(KoPageLayout))); - connect(pw, SIGNAL(layoutChanged(KoPageLayout)), this, SLOT(setPrinterPageLayout(KoPageLayout))); + connect(pw, &KoPageLayoutWidget::layoutChanged, this, &PrintingDialog::setPrinterPageLayout); connect(pw, SIGNAL(layoutChanged(KoPageLayout)), this, SIGNAL(changed())); return w; } QList PrintingDialog::createOptionWidgets() const { //debugPlan; PrintingHeaderFooter *w = new PrintingHeaderFooter( printingOptions() ); - connect(w, SIGNAL(changed(PrintingOptions)), this, SLOT(setPrintingOptions(PrintingOptions))); + connect(w, &PrintingHeaderFooter::changed, this, &PrintingDialog::setPrintingOptions); const_cast( this )->m_widget = w; return QList() << w; } /*QList PrintingDialog::shapesOnPage(int) { return QList(); }*/ void PrintingDialog::drawRect( QPainter &p, const QRect &r, Qt::Edges edges ) { p.save(); QPen pen = p.pen(); pen.setColor(Qt::gray); p.setPen(pen); if (edges & Qt::LeftEdge) { p.drawLine( r.topLeft(), r.bottomLeft() ); } if (edges & Qt::BottomEdge) { p.drawLine( r.bottomLeft(), r.bottomRight() ); } if (edges & Qt::TopEdge) { p.drawLine( r.topRight(), r.bottomRight() ); } if (edges & Qt::RightEdge) { p.drawLine( r.topRight(), r.bottomRight() ); } p.restore(); } QRect PrintingDialog::headerRect() const { PrintingOptions options = m_view->printingOptions(); if ( options.headerOptions.group == false ) { return QRect(); } int height = headerFooterHeight( options.headerOptions ); return QRect( 0, 0, const_cast( this )->printer().pageRect().width(), height ); } QRect PrintingDialog::footerRect() const { PrintingOptions options = m_view->printingOptions(); if ( options.footerOptions.group == false ) { return QRect(); } int height = headerFooterHeight( options.footerOptions ); QRect r = const_cast( this )->printer().pageRect(); return QRect( 0, r.height() - height, r.width(), height ); } int PrintingDialog::headerFooterHeight( const PrintingOptions::Data &options ) const { int height = 0.0; if ( options.page == Qt::Checked || options.project == Qt::Checked || options.manager == Qt::Checked || options.date == Qt::Checked ) { height += m_textheight * 1.5; } if ( options.project == Qt::Checked && options.manager == Qt::Checked && ( options.date == Qt::Checked || options.page == Qt::Checked ) ) { height *= 2.0; } debugPlan< pageRect.left()) { pageRect.setLeft(r.left()); } p.restore(); if ( options.project == Qt::Checked || options.manager == Qt::Checked || options.date == Qt::Checked ) { p.drawLine( rect_1.topRight(), rect_1.bottomRight() ); } } if ( options.date == Qt::Checked ) { p.save(); QFont f = p.font(); f.setPointSize( f.pointSize() * 0.5 ); p.setFont( f ); QRect rct = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, i18n("Date:") ); p.restore(); if ( ( options.project == Qt::Checked && options.manager != Qt::Checked ) || ( options.project != Qt::Checked && options.manager == Qt::Checked ) ) { dateRect = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, date ); dateRect.setHeight( rect_1.height() ); rect_1.setRight( dateRect.left() - 2 ); if (rct.right() > dateRect.right()) { dateRect.setRight(rct.right()); } p.drawLine( rect_1.topRight(), rect_1.bottomRight() ); } else if ( options.project == Qt::Checked && options.manager == Qt::Checked ) { dateRect = p.boundingRect( rect_2, Qt::AlignRight|Qt::AlignTop, date ); dateRect.setHeight( rect_2.height() ); rect_2.setRight( dateRect.left() - 2 ); if (rct.right() > dateRect.right()) { dateRect.setRight(rct.right()); } p.drawLine( rect_2.topRight(), rect_2.bottomRight() ); } else { dateRect = p.boundingRect( rect_2, Qt::AlignLeft|Qt::AlignTop, date ); if (rct.right() > dateRect.right()) { dateRect.setRight(rct.right()); } dateRect.setHeight( rect_2.height() ); rect_2.setRight( dateRect.left() - 2 ); if ( rect_2.left() != rect.left() ) { p.drawLine( rect_2.topRight(), rect_2.bottomRight() ); } } } if ( options.manager == Qt::Checked ) { p.save(); QFont f = p.font(); f.setPointSize( f.pointSize() * 0.5 ); p.setFont( f ); QRect rct = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, i18n("Manager:") ); p.restore(); if ( options.project != Qt::Checked ) { managerRect = p.boundingRect( rect_1, Qt::AlignLeft|Qt::AlignTop, manager ); managerRect.setHeight( rect_1.height() ); if (rct.right() > managerRect.right()) { managerRect.setRight(rct.right()); } } else if ( options.date != Qt::Checked && options.page != Qt::Checked ) { managerRect = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, manager ); managerRect.setHeight( rect_1.height() ); if (rct.right() > managerRect.right()) { managerRect.setRight(rct.right()); } rect_1.setRight( managerRect.left() - 2 ); p.drawLine( rect_1.topRight(), rect_1.bottomRight() ); } else { managerRect = p.boundingRect( rect_2, Qt::AlignLeft|Qt::AlignTop, manager ); managerRect.setHeight( rect_2.height() ); if (rct.right() > managerRect.right()) { managerRect.setRight(rct.right()); } } } if ( options.project == Qt::Checked ) { projectRect = p.boundingRect( rect_1, Qt::AlignLeft|Qt::AlignTop, projectName ); projectRect.setHeight( rect_1.height() ); p.save(); QFont f = p.font(); f.setPointSize( f.pointSize() * 0.5 ); p.setFont( f ); QRect rct = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, i18n("Project:") ); if (rct.right() > projectRect.right()) { projectRect.setRight(rct.right()); } p.restore(); } if ( options.page == Qt::Checked ) { p.drawText( pageRect, Qt::AlignHCenter|Qt::AlignBottom, page ); } if ( options.project == Qt::Checked ) { p.drawText( projectRect.adjusted(3, 0, 3, 0), Qt::AlignLeft|Qt::AlignBottom, projectName ); } if ( options.date == Qt::Checked ) { p.drawText( dateRect, Qt::AlignHCenter|Qt::AlignBottom, date ); } if ( options.manager == Qt::Checked ) { p.drawText( managerRect.adjusted(3, 0, 3, 0), Qt::AlignLeft|Qt::AlignBottom, manager ); } QFont f = p.font(); f.setPointSize( f.pointSize() * 0.5 ); p.setFont( f ); if ( options.page == Qt::Checked ) { p.drawText( pageRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Page:" ) ); } if ( options.project == Qt::Checked ) { p.drawText( projectRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Project:" ) ); } if ( options.date == Qt::Checked ) { p.drawText( dateRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Date:" ) ); } if ( options.manager == Qt::Checked ) { p.drawText( managerRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Manager:" ) ); } p.restore(); } //-------------- ViewBase::ViewBase(KoPart *part, KoDocument *doc, QWidget *parent) : KoView(part, doc, parent), m_readWrite( false ), m_proj( 0 ), m_schedulemanager( 0 ) { } ViewBase::~ViewBase() { if ( koDocument() ) { //HACK to avoid ~View to access koDocument() setDocumentDeleted(); } } void ViewBase::setProject( Project *project ) { m_proj = project; emit projectChanged( project ); } KoDocument *ViewBase::part() const { return koDocument(); } KoPageLayout ViewBase::pageLayout() const { return m_pagelayout; } void ViewBase::setPageLayout( const KoPageLayout &layout ) { m_pagelayout = layout; } bool ViewBase::isActive() const { if ( hasFocus() ) { return true; } foreach ( QWidget *v, findChildren() ) { if ( v->hasFocus() ) { return true; } } return false; } void ViewBase::updateReadWrite( bool readwrite ) { m_readWrite = readwrite; emit readWriteChanged( readwrite ); } void ViewBase::setGuiActive( bool active ) // virtual slot { //debugPlan<setWindowTitle( xi18nc( "@title:tab", "Page Layout" ) ); QHBoxLayout *lay = new QHBoxLayout(widget); KoPageLayoutWidget *w = new KoPageLayoutWidget( widget, view->pageLayout() ); w->showPageSpread( false ); lay->addWidget( w, 1 ); KoPagePreviewWidget *prev = new KoPagePreviewWidget( widget ); prev->setPageLayout( view->pageLayout() ); lay->addWidget( prev, 1 ); - connect (w, SIGNAL(layoutChanged(KoPageLayout)), prev, SLOT(setPageLayout(KoPageLayout))); + connect (w, &KoPageLayoutWidget::layoutChanged, prev, &KoPagePreviewWidget::setPageLayout); return widget; } /*static*/ PrintingHeaderFooter *ViewBase::createHeaderFooterWidget( ViewBase *view ) { PrintingHeaderFooter *widget = new PrintingHeaderFooter( view->printingOptions() ); widget->setWindowTitle( xi18nc( "@title:tab", "Header and Footer" ) ); widget->setOptions( view->printingOptions() ); return widget; } void ViewBase::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlan; QList lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } void ViewBase::createOptionActions(int actions) { QAction *action; action = new QAction(this); action->setSeparator(true); addContextAction(action); if (actions & OptionExpand) { action = new QAction(koIcon("arrow-down"), i18n("Expand All"), this); - connect(action, SIGNAL(triggered(bool)), this, SIGNAL(expandAll())); + connect(action, &QAction::triggered, this, &ViewBase::expandAll); addContextAction(action); } if (actions & OptionExpand) { action = new QAction(koIcon("arrow-up"), i18n("Collapse All"), this); - connect(action, SIGNAL(triggered(bool)), this, SIGNAL(collapseAll())); + connect(action, &QAction::triggered, this, &ViewBase::collapseAll); addContextAction(action); } action = new QAction(this); action->setSeparator(true); addContextAction(action); if (actions & OptionPrint) { action = KStandardAction::create(KStandardAction::Print, mainWindow(), SLOT(slotFilePrint()), this); action->setObjectName("print"); addContextAction(action); } if (actions & OptionPrintPreview) { action = KStandardAction::create(KStandardAction::PrintPreview, mainWindow(), SLOT(slotFilePrintPreview()), this); action->setObjectName("print preview"); addContextAction(action); } if (actions & OptionPrintPdf) { action = new QAction(koIcon("application-pdf"), i18n("Print to PDF..."), this); action->setObjectName("print pdf"); connect(action, SIGNAL(triggered()), mainWindow(), SLOT(exportToPdf())); addContextAction(action); } if (actions & OptionPrintConfig) { action = new QAction(koIcon("configure"), i18n("Print Options..."), this); action->setObjectName("print options"); - connect(action, SIGNAL(triggered(bool)), SLOT(slotOptions())); + connect(action, &QAction::triggered, this, &ViewBase::slotOptions); addContextAction(action); } action = new QAction(this); action->setSeparator(true); addContextAction(action); if (actions & OptionViewConfig) { action = new QAction(koIcon("configure"), i18n("Configure View..."), this); action->setObjectName("configure view"); - connect(action, SIGNAL(triggered(bool)), SLOT(slotOptions())); + connect(action, &QAction::triggered, this, &ViewBase::slotOptions); addContextAction(action); } } void ViewBase::slotOptionsFinished( int result ) { if ( result == QDialog::Accepted ) { emit optionsModified(); } if ( sender() ) { sender()->deleteLater(); } } bool ViewBase::loadContext( const KoXmlElement &context ) { KoXmlElement me; forEachElement( me, context ) { if ( me.tagName() == "page-layout" ) { m_pagelayout.format = KoPageFormat::formatFromString( me.attribute( "format" ) ); m_pagelayout.orientation = me.attribute( "orientation" ) == "landscape" ? KoPageFormat::Landscape : KoPageFormat::Portrait; m_pagelayout.width = me.attribute( "width", "0.0" ).toDouble(); m_pagelayout.height = me.attribute( "height", "0.0" ).toDouble(); m_pagelayout.leftMargin = me.attribute( "left-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble(); m_pagelayout.rightMargin = me.attribute( "right-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble(); m_pagelayout.topMargin = me.attribute( "top-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble(); m_pagelayout.bottomMargin = me.attribute( "bottom-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble(); } else if ( me.tagName() == "printing-options" ) { m_printingOptions.loadXml( me ); } else if ( me.tagName() == "dockers" ) { KoXmlElement e; forEachElement ( e, me ) { DockWidget *ds = findDocker( e.attribute( "id" ) ); if ( ds ) { ds->loadXml( e ); } } } } return true; } void ViewBase::saveContext( QDomElement &context ) const { QDomElement me = context.ownerDocument().createElement( "page-layout" ); context.appendChild( me ); me.setAttribute( "format", KoPageFormat::formatString( m_pagelayout.format ) ); me.setAttribute( "orientation", m_pagelayout.orientation == KoPageFormat::Portrait ? "portrait" : "landscape" ); me.setAttribute( "width", QString::number(m_pagelayout.width) ); me.setAttribute( "height",QString::number(m_pagelayout. height) ); me.setAttribute( "left-margin", QString::number(m_pagelayout.leftMargin) ); me.setAttribute( "right-margin", QString::number(m_pagelayout.rightMargin) ); me.setAttribute( "top-margin", QString::number(m_pagelayout.topMargin) ); me.setAttribute( "bottom-margin",QString::number( m_pagelayout.bottomMargin) ); m_printingOptions.saveXml( context ); if ( ! m_dockers.isEmpty() ) { QDomElement e = context.ownerDocument().createElement( "dockers" ); context.appendChild( e ); foreach ( const DockWidget *ds, m_dockers ) { ds->saveXml( e ); } } } void ViewBase::addDocker( DockWidget *ds ) { //addAction( "view_docker_list", ds->toggleViewAction() ); m_dockers << ds; } QList ViewBase::dockers() const { return m_dockers; } DockWidget* ViewBase::findDocker( const QString &id ) const { foreach ( DockWidget *ds, m_dockers ) { if ( ds->id == id ) { return ds; } } return 0; } //---------------------- TreeViewPrintingDialog::TreeViewPrintingDialog( ViewBase *view, TreeViewBase *treeview, Project *project ) : PrintingDialog( view ), m_tree( treeview ), m_project( project ), m_firstRow( -1 ) { printer().setFromTo( documentFirstPage(), documentLastPage() ); } int TreeViewPrintingDialog::documentLastPage() const { int page = documentFirstPage(); while ( firstRow( page ) != -1 ) { ++page; } if ( page > documentFirstPage() ) { --page; } return page; } int TreeViewPrintingDialog::firstRow( int page ) const { debugPlan<header(); int height = mh->height(); int hHeight = headerRect().height(); int fHeight = footerRect().height(); QRect pageRect = const_cast( this )->printer().pageRect(); int gap = 8; int pageHeight = pageRect.height() - height; if ( hHeight > 0 ) { pageHeight -= ( hHeight + gap ); } if ( fHeight > 0 ) { pageHeight -= ( fHeight + gap ); } int rowsPrPage = pageHeight / height; int rows = m_tree->model()->rowCount(); int row = -1; for ( int i = 0; i < rows; ++i ) { if ( ! m_tree->isRowHidden( i, QModelIndex() ) ) { row = i; break; } } if ( row != -1 ) { QModelIndex idx = m_tree->model()->index( row, 0, QModelIndex() ); row = 0; while ( idx.isValid() ) { if ( row >= rowsPrPage * pageNumber ) { debugPlan<indexBelow( idx ); } if ( ! idx.isValid() ) { row = -1; } } debugPlan<<"Page"< TreeViewPrintingDialog::createOptionWidgets() const { QList lst; lst << createPageLayoutWidget(); lst += PrintingDialog::createOptionWidgets(); return lst; } void TreeViewPrintingDialog::printPage( int page, QPainter &painter ) { m_firstRow = firstRow( page ); QHeaderView *mh = m_tree->header(); int length = mh->length(); int height = mh->height(); QRect hRect = headerRect(); QRect fRect = footerRect(); QRect pageRect = printer().pageRect(); pageRect.moveTo( 0, 0 ); QRect paperRect = printer().paperRect(); QAbstractItemModel *model = m_tree->model(); debugPlan<printingOptions(), page, *(m_project) ); } int gap = 8; int pageHeight = pageRect.height() - height; if ( hRect.isValid() ) { pageHeight -= ( hRect.height() + gap ); } if ( fRect.isValid() ) { pageHeight -= ( fRect.height() + gap ); } int rowsPrPage = pageHeight / height; double sx = pageRect.width() > length ? 1.0 : (double)pageRect.width() / (double)length; double sy = 1.0; painter.scale( sx, sy ); int h = 0; painter.translate( 0, hRect.height() + gap ); h = hRect.height() + gap; painter.setPen(Qt::black); painter.setBrush( Qt::lightGray ); int higestIndex = 0; int rightpos = 0; for ( int i = 0; i < mh->count(); ++i ) { QString text = model->headerData( i, Qt::Horizontal ).toString(); QVariant a = model->headerData( i, Qt::Horizontal, Qt::TextAlignmentRole ); int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter); if ( ! mh->isSectionHidden( i ) ) { QRect r = QRect( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height ).adjusted(0, 0, 0, -painter.pen().width()); if (rightpos < r.right()) { higestIndex = i; rightpos = r.right(); } painter.drawRect( r ); // FIXME There is a bug somewhere, the text somehow overwites the rect outline for the first column! painter.save(); painter.setBrush(QBrush()); painter.drawText( r.adjusted(3, 1, -3, -1), align, text ); painter.drawRect( r ); painter.restore(); } //debugPlan<isSectionHidden( i )<sectionPosition( i ); } if ( m_firstRow == -1 ) { debugPlan<<"No data"; return; } painter.setBrush( QBrush() ); QModelIndex idx = model->index( m_firstRow, 0, QModelIndex() ); int numRows = 0; //debugPlan<count(); ++i ) { if ( mh->isSectionHidden( i ) ) { continue; } Qt::Edges edges = Qt::BottomEdge | Qt::LeftEdge; QModelIndex index = model->index( idx.row(), i, idx.parent() ); QString text = model->data( index ).toString(); QVariant a = model->data( index, Qt::TextAlignmentRole ); int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter); QRect r( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height ); if (higestIndex == i) { edges |= Qt::RightEdge; r.adjust(0, 0, 1, 0); } drawRect( painter, r, edges ); painter.drawText( r.adjusted(3, 1, -3, -1) , align, text ); } ++numRows; idx = m_tree->indexBelow( idx ); } } /** * TreeViewBase is a QTreeView adapted for operation by keyboard only and as components in DoubleTreeViewBase. * Note that keyboard navigation and selection behavior may not be fully compliant with QTreeView. * If you use other settings than QAbstractItemView::ExtendedSelection and QAbstractItemView::SelectRows, * you should have a look at the implementation keyPressEvent() and updateSelection(). */ TreeViewBase::TreeViewBase( QWidget *parent ) : QTreeView( parent ), m_arrowKeyNavigation( true ), m_acceptDropsOnView( false ), m_readWrite( false ) { setDefaultDropAction( Qt::MoveAction ); setItemDelegate( new ItemDelegate( this ) ); setAlternatingRowColors ( true ); header()->setContextMenuPolicy( Qt::CustomContextMenu ); - connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( header(), &QWidget::customContextMenuRequested, this, &TreeViewBase::slotHeaderContextMenuRequested ); } void TreeViewBase::dropEvent( QDropEvent *e ) { debugPlan; QTreeView::dropEvent( e ); } KoPrintJob * TreeViewBase::createPrintJob( ViewBase *parent ) { TreeViewPrintingDialog *dia = new TreeViewPrintingDialog( parent, this, parent->project() ); dia->printer().setCreator( QString( "Plan %1" ).arg( PLAN_VERSION_STRING ) ); // dia->printer().setFullPage(true); // ignore printer margins return dia; } void TreeViewBase::setReadWrite( bool rw ) { m_readWrite = rw; if ( model() ) { model()->setData( QModelIndex(), rw, Role::ReadWrite ); } } void TreeViewBase::createItemDelegates( ItemModelBase *model ) { for ( int c = 0; c < model->columnCount(); ++c ) { QAbstractItemDelegate *delegate = model->createDelegate( c, this ); if ( delegate ) { setItemDelegateForColumn( c, delegate ); } } } void TreeViewBase::slotHeaderContextMenuRequested( const QPoint& pos ) { //debugPlan; emit headerContextMenuRequested( header()->mapToGlobal( pos ) ); } void TreeViewBase::setColumnsHidden( const QList &lst ) { //debugPlan< xlst; foreach ( int c, lst ) { if ( c == -1 ) { // hide rest for ( int i = prev+1; i < model()->columnCount(); ++i ) { if ( ! lst.contains( i ) ) { xlst << i; } } break; } xlst << c; prev = c; } for ( int c = 0; c < model()->columnCount(); ++c ) { setColumnHidden( c, xlst.contains( c ) ); } } QModelIndex TreeViewBase::firstColumn( int row, const QModelIndex &parent ) { int s; for ( s = 0; s < header()->count(); ++s ) { if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) { break; } } if ( s == -1 ) { return QModelIndex(); } return model()->index( row, header()->logicalIndex( s ), parent ); } QModelIndex TreeViewBase::lastColumn( int row, const QModelIndex &parent ) { int s; for ( s = header()->count() - 1; s >= 0; --s ) { if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) { break; } } if ( s == -1 ) { return QModelIndex(); } return model()->index( row, header()->logicalIndex( s ), parent ); } QModelIndex TreeViewBase::nextColumn( const QModelIndex &curr ) { return moveCursor( curr, QAbstractItemView::MoveRight ); } QModelIndex TreeViewBase::previousColumn( const QModelIndex &curr ) { return moveCursor( curr, QAbstractItemView::MoveLeft ); } QModelIndex TreeViewBase::firstEditable( int row, const QModelIndex &parent ) { QModelIndex index = firstColumn( row, parent ); if ( model()->flags( index ) & Qt::ItemIsEditable ) { return index; } return moveToEditable( index, QAbstractItemView::MoveRight ); } QModelIndex TreeViewBase::lastEditable( int row, const QModelIndex &parent ) { QModelIndex index = lastColumn( row, parent ); if ( model()->flags( index ) & Qt::ItemIsEditable ) { return index; } return moveToEditable( index, QAbstractItemView::MoveLeft ); } // Reimplemented to fix qt bug 160083: Doesn't scroll horizontally. void TreeViewBase::scrollTo(const QModelIndex &index, ScrollHint hint) { //debugPlan<width(); int horizontalOffset = header()->offset(); int horizontalPosition = header()->sectionPosition(index.column()); int cellWidth = header()->sectionSize(index.column()); if (hint == PositionAtCenter) { horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2)); } else { if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth) horizontalScrollBar()->setValue(horizontalPosition); else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth) horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth); } } void TreeViewBase::focusInEvent(QFocusEvent *event) { //debugPlan<reason(); QAbstractScrollArea::focusInEvent(event); //NOTE: not QTreeView if ( event->reason() == Qt::MouseFocusReason ) { return; } QModelIndex curr = currentIndex(); if ( ! curr.isValid() || ! isIndexHidden( curr ) ) { return; } QModelIndex idx = curr; for ( int s = 0; s < header()->count(); ++s) { idx = model()->index( curr.row(), header()->logicalIndex( s ), curr.parent() ); if ( ! isIndexHidden( idx ) ) { selectionModel()->setCurrentIndex(idx, QItemSelectionModel::NoUpdate); scrollTo( idx ); break; } } } /*! \reimp */ void TreeViewBase::keyPressEvent(QKeyEvent *event) { //debugPlan<key()<<","<key()) { case Qt::Key_Right: { QModelIndex nxt = moveCursor( MoveRight, Qt::NoModifier ); if ( nxt.isValid() ) { selectionModel()->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate ); } else { emit moveAfterLastColumn( current ); } event->accept(); return; break; } case Qt::Key_Left: { QModelIndex prv = moveCursor( MoveLeft, Qt::NoModifier ); if ( prv.isValid() ) { selectionModel()->setCurrentIndex( prv, QItemSelectionModel::NoUpdate ); } else { emit moveBeforeFirstColumn( current ); } event->accept(); return; break; } case Qt::Key_Down: { QModelIndex i = moveCursor( MoveDown, Qt::NoModifier ); updateSelection( current, i, event ); event->accept(); return; break; } case Qt::Key_Up: { QModelIndex i = moveCursor( MoveUp, Qt::NoModifier ); updateSelection( current, i, event ); event->accept(); return; break; } default: break; } } QTreeView::keyPressEvent(event); } void TreeViewBase::updateSelection( const QModelIndex &oldidx, const QModelIndex &newidx, QKeyEvent *event ) { if ( newidx == oldidx || ! newidx.isValid() ) { return; } if ( !hasFocus() && QApplication::focusWidget() == indexWidget(oldidx) ) { setFocus(); } QItemSelectionModel::SelectionFlags command; // NoUpdate on Key movement and Ctrl Qt::KeyboardModifiers modifiers = static_cast(event)->modifiers(); switch (static_cast(event)->key()) { case Qt::Key_Backtab: modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab Q_FALLTHROUGH(); case Qt::Key_Down: case Qt::Key_Up: case Qt::Key_Left: case Qt::Key_Right: if (modifiers & Qt::ControlModifier) command = QItemSelectionModel::NoUpdate; else if (modifiers & Qt::ShiftModifier) command = QItemSelectionModel::Select | selectionBehaviorFlags(); else command = QItemSelectionModel::ClearAndSelect | selectionBehaviorFlags(); break; default: break; } selectionModel()->setCurrentIndex( newidx, command ); } void TreeViewBase::mousePressEvent(QMouseEvent *event) { // If the mouse is pressed outside any item, the current item should be/remain selected QPoint pos = event->pos(); QModelIndex index = indexAt(pos); debugPlan<pos(); if ( ! index.isValid() ) { index = selectionModel()->currentIndex(); if ( index.isValid() && ! selectionModel()->isSelected( index ) ) { pos = visualRect( index ).center(); QMouseEvent e( event->type(), pos, mapToGlobal( pos ), event->button(), event->buttons(), event->modifiers() ); QTreeView::mousePressEvent( &e ); event->setAccepted( e.isAccepted() ); debugPlan<( sender() ); if ( delegate == 0 ) { warnPlan<<"Not a KPlato::ItemDelegate, try standard treatment"<endEditHint(); // Close editor, do nothing else QTreeView::closeEditor( editor, QAbstractItemDelegate::NoHint ); QModelIndex index; switch ( endHint ) { case Delegate::EditLeftItem: index = moveToEditable( currentIndex(), MoveLeft ); break; case Delegate::EditRightItem: index = moveToEditable( currentIndex(), MoveRight ); break; case Delegate::EditDownItem: index = moveToEditable( currentIndex(), MoveDown ); break; case Delegate::EditUpItem: index = moveToEditable( currentIndex(), MoveUp ); break; default: //debugPlan<<"Standard treatment"<setCurrentIndex(persistent, flags); // currentChanged signal would have already started editing if (!(editTriggers() & QAbstractItemView::CurrentChanged)) { edit(persistent); } } } QModelIndex TreeViewBase::moveToEditable( const QModelIndex &index, CursorAction cursorAction ) { QModelIndex ix = index; do { ix = moveCursor( ix, cursorAction ); } while ( ix.isValid() && ! ( model()->flags( ix ) & Qt::ItemIsEditable ) ); //debugPlan<= model()->columnCount(ix.parent()) ) { //debugPlan<columnCount(ix.parent())<index( ix.row(), col, ix.parent() ); } // else Here we could go to the top return ix; } case MoveUp: { // TODO: span // Fetch the index above current. // This should be the previous non-hidden row, same column as current, // that has a column in current.column() ix = indexAbove( current ); while ( ix.isValid() && col >= model()->columnCount(ix.parent()) ) { ix = indexAbove( ix ); } if ( ix.isValid() ) { ix = model()->index( ix.row(), col, ix.parent() ); } // else Here we could go to the bottom return ix; } case MovePrevious: case MoveLeft: { for ( int s = header()->visualIndex( col ) - 1; s >= 0; --s ) { if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) { ix = model()->index( current.row(), header()->logicalIndex( s ), current.parent() ); break; } } return ix; } case MoveNext: case MoveRight: { for ( int s = header()->visualIndex( col ) + 1; s < header()->count(); ++s ) { if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) { ix = model()->index( current.row(), header()->logicalIndex( s ), current.parent() ); break; } } return ix; } case MovePageUp: case MovePageDown: { ix = QTreeView::moveCursor( cursorAction, modifiers ); // Now we are at the correct row, so move to correct column if ( ix.isValid() ) { ix = model()->index( ix.row(), col, ix.parent() ); } // else Here we could go to the bottom return ix; } case MoveHome: { if ( ( modifiers & Qt::ControlModifier ) == 0 ) { ix = QTreeView::moveCursor( cursorAction, modifiers ); // move to first row } else { //stay at this row ix = current; } for ( int s = 0; s < header()->count(); ++s ) { int logicalIndex = header()->logicalIndex( s ); if ( ! isColumnHidden( logicalIndex ) ) { ix = model()->index( ix.row(), header()->logicalIndex( s ), ix.parent() ); break; } } return ix; } case MoveEnd: { if ( ( modifiers & Qt::ControlModifier ) == 0 ) { ix = QTreeView::moveCursor( cursorAction, modifiers ); // move to last row } else { //stay at this row ix = current; } for ( int s = header()->count() - 1; s >= 0; --s ) { int logicalIndex = header()->logicalIndex( s ); if ( ! isColumnHidden( logicalIndex ) ) { ix = model()->index( ix.row(), logicalIndex, ix.parent() ); break; } } return ix; } default: break; } return ix; } void TreeViewBase::contextMenuEvent ( QContextMenuEvent *event ) { debugPlan<selectedRows(); emit contextMenuRequested( indexAt(event->pos()), event->globalPos(), selectionModel()->selectedRows() ); } void TreeViewBase::slotCurrentChanged( const QModelIndex ¤t, const QModelIndex & ) { if ( current.isValid() ) { scrollTo( current ); } } void TreeViewBase::setModel( QAbstractItemModel *model ) { if ( selectionModel() ) { - disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + disconnect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged ); } QTreeView::setModel( model ); if ( selectionModel() ) { - connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged ); } setReadWrite( m_readWrite ); } void TreeViewBase::setSelectionModel( QItemSelectionModel *model ) { if ( selectionModel() ) { - disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + disconnect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged ); } QTreeView::setSelectionModel( model ); if ( selectionModel() ) { - connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); + connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged ); } } void TreeViewBase::setStretchLastSection( bool mode ) { header()->setStretchLastSection( mode ); } void TreeViewBase::mapToSection( int col, int section ) { header()->moveSection( header()->visualIndex( col ), section ); } int TreeViewBase::section( int col ) const { return header()->visualIndex( col ); } void TreeViewBase::dragMoveEvent(QDragMoveEvent *event) { //debugPlan; if (dragDropMode() == InternalMove && (event->source() != this || !(event->possibleActions() & Qt::MoveAction))) { //debugPlan<<"Internal:"<isAccepted(); return; } QTreeView::dragMoveEvent( event ); if ( dropIndicatorPosition() == QAbstractItemView::OnViewport ) { if ( ! m_acceptDropsOnView ) { event->ignore(); } debugPlan<<"On viewport:"<isAccepted(); } else { QModelIndex index = indexAt( event->pos() ); if ( index.isValid() ) { emit dropAllowed( index, dropIndicatorPosition(), event ); } else { event->ignore(); debugPlan<<"Invalid index:"<isAccepted(); } } if ( event->isAccepted() ) { if ( viewport()->cursor().shape() == Qt::ForbiddenCursor ) { viewport()->unsetCursor(); } } else if ( viewport()->cursor().shape() != Qt::ForbiddenCursor ) { viewport()->setCursor( Qt::ForbiddenCursor ); } debugPlan<isAccepted()<cursor().shape(); } QModelIndex TreeViewBase::firstVisibleIndex( const QModelIndex &idx ) const { int count = model()->columnCount(); for ( int c = 0; c < count; ++c ) { if ( ! isColumnHidden( c ) ) { return model()->index( idx.row(), c, model()->parent( idx ) ); } } return QModelIndex(); } bool TreeViewBase::loadContext( const QMetaEnum &map, const KoXmlElement &element, bool expand ) { //debugPlan<setStretchLastSection( (bool)( element.attribute( "stretch-last-column", "1" ).toInt() ) ); KoXmlElement e = element.namedItem( "columns" ).toElement(); if ( ! e.isNull() ) { if ( ! map.isValid() ) { // try numbers debugPlan<<"invalid map"; for ( int i = model()->columnCount() - 1; i >= 0; --i ) { QString s = e.attribute( QString( "column-%1" ).arg( i ), "" ); if ( s == "hidden" ) { hideColumn( i ); } else if ( s == "shown" ) { showColumn( i ); } else debugPlan<columnCount() - 1; i >= 0; --i ) { QString n = map.key( i ); //debugPlan<count(); ++i ) { if ( e.hasAttribute( s.arg( i ) ) ) { int index = e.attribute( s.arg( i ), "-1" ).toInt(); if ( index >= 0 && index < h->count() ) { header()->moveSection( h->visualIndex( index ), i ); } } } } else { QMap m; // QMap for ( int i = 0; i < h->count(); ++i ) { QString n = e.attribute( s.arg( i ) ); if ( n.isEmpty() ) { continue; } int col = map.keyToValue( n.toUtf8() ); if ( col >= 0 && col < h->count() ) { m.insert( i, col ); } } for ( QMap::const_iterator it = m.constBegin(); it != m.constEnd(); ++it ) { QString n = e.attribute( s.arg( it.key() ) ); int current = h->visualIndex( it.value() ); header()->moveSection( current, it.key() ); } } } if (expand) { loadExpanded(element); } return true; } void TreeViewBase::saveContext( const QMetaEnum &map, QDomElement &element, bool expand ) const { //debugPlan<stretchLastSection()) ); QDomElement e = element.ownerDocument().createElement( "columns" ); element.appendChild( e ); for ( int i = 0; i < model()->columnCount(); ++i ) { bool h = isColumnHidden( i ); if ( ! map.isValid() ) { debugPlan<<"invalid map"; e.setAttribute( QString( "column-%1" ).arg( i ), h ? "hidden" : "shown" ); } else { QString n = map.key( i ); //debugPlan<count(); ++i ) { if ( ! isColumnHidden( h->logicalIndex( i ) ) ) { if ( ! map.isValid() ) { e.setAttribute( QString( "section-%1" ).arg( i ), h->logicalIndex( i ) ); } else { QString n = map.key( h->logicalIndex( i ) ); if ( ! n.isEmpty() ) { e.setAttribute( QString( "section-%1" ).arg( i ), n ); } } } } if (expand) { QDomElement expanded = element.ownerDocument().createElement("expanded"); element.appendChild(expanded); saveExpanded(expanded); } } ItemModelBase *TreeViewBase::itemModel() const { QAbstractItemModel *m = model(); QAbstractProxyModel *p = qobject_cast( m ); while ( p ) { m = p->sourceModel(); p = qobject_cast( m ); } return qobject_cast( m ); } void TreeViewBase::expandRecursive(const QModelIndex &idx, bool xpand) { int rowCount = model()->rowCount(idx); if (rowCount == 0) { return; } xpand ? expand(idx) : collapse(idx); for (int r = 0; r < rowCount; ++r) { QModelIndex i = model()->index(r, 0, idx); Q_ASSERT(i.isValid()); expandRecursive(i, xpand); } } void TreeViewBase::slotExpand() { // NOTE: Do not use this, KGantt does not like it // if (!m_contextMenuIndex.isValid()) { // expandAll(); // return; // } QModelIndex idx = m_contextMenuIndex; if (idx.column() > 0) { idx = idx.model()->index(idx.row(), idx.column(), idx.parent()); } expandRecursive(idx, true); } void TreeViewBase::slotCollapse() { // NOTE: Do not use this, KGantt does not like it // if (!m_contextMenuIndex.isValid()) { // collapseAll(); // return; // } QModelIndex idx = m_contextMenuIndex; if (idx.column() > 0) { idx = idx.model()->index(idx.row(), 0, idx.parent()); } expandRecursive(idx, false); } void TreeViewBase::setContextMenuIndex(const QModelIndex &idx) { m_contextMenuIndex = idx; } void TreeViewBase::loadExpanded(const KoXmlElement &element) { // we get here on loadContext() m_loadContextDoc.clear(); KoXmlElement expanded = element.namedItem("expanded").toElement(); if (expanded.isNull()) { return; } KoXml::asQDomElement(m_loadContextDoc, expanded); // FIXME: // if data is dependent on schedule manger // we cannot do anything until schedulemanger is set, // so we wait a bit and hope everything is ok - QTimer::singleShot(500, this, SLOT(doContextExpanded())); + QTimer::singleShot(500, this, &TreeViewBase::doContextExpanded); } void TreeViewBase::expandRecursivly(QDomElement element, const QModelIndex &parent) { if (element.isNull()) { return; } for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement e = n.toElement(); if (e.tagName() != "item") { continue; } int childRow = e.attribute("row", "-1").toInt(); if (childRow > -1) { QModelIndex idx = model()->index(childRow, 0, parent); if (idx.isValid()) { setExpanded(idx, true); expandRecursivly(e, idx); } } } } void TreeViewBase::doExpand(QDomDocument &doc) { // we get here on setScheduleManager() m_expandDoc = doc; - QTimer::singleShot(0, this, SLOT(doExpanded())); + QTimer::singleShot(0, this, &TreeViewBase::doExpanded); } void TreeViewBase::doContextExpanded() { expandRecursivly(m_loadContextDoc.documentElement()); } void TreeViewBase::doExpanded() { expandRecursivly(m_expandDoc.documentElement()); } void TreeViewBase::saveExpanded(QDomElement &element, const QModelIndex &parent) const { for (int r = 0; r < model()->rowCount(parent); ++r) { QModelIndex idx = model()->index(r, 0, parent); if (isExpanded(idx)) { QDomElement e = element.ownerDocument().createElement("item"); e.setAttribute("row", r); element.appendChild(e); saveExpanded(e, idx); } } } //---------------------- DoubleTreeViewPrintingDialog::DoubleTreeViewPrintingDialog( ViewBase *view, DoubleTreeViewBase *treeview, Project *project ) : PrintingDialog( view ), m_tree( treeview ), m_project( project ), m_firstRow( -1 ) { printer().setFromTo( documentFirstPage(), documentLastPage() ); } int DoubleTreeViewPrintingDialog::documentLastPage() const { debugPlan<pageLayout().format ); int page = documentFirstPage(); while ( firstRow( page ) != -1 ) { ++page; } if ( page > documentFirstPage() ) { --page; } return page; } int DoubleTreeViewPrintingDialog::firstRow( int page ) const { debugPlan<masterView()->header(); QHeaderView *sh = m_tree->slaveView()->header(); int height = mh->height() > sh->height() ? mh->height() : sh->height(); int hHeight = headerRect().height(); int fHeight = footerRect().height(); QRect pageRect = const_cast( this )->printer().pageRect(); int gap = 8; int pageHeight = pageRect.height() - height; if ( hHeight > 0 ) { pageHeight -= ( hHeight + gap ); } if ( fHeight > 0 ) { pageHeight -= ( fHeight + gap ); } int rowsPrPage = pageHeight / height; debugPlan<<"rowsPrPage"< 0 ); int rows = m_tree->model()->rowCount(); int row = -1; for ( int i = 0; i < rows; ++i ) { if ( ! m_tree->masterView()->isRowHidden( i, QModelIndex() ) ) { row = i; break; } } if ( row != -1 ) { QModelIndex idx = m_tree->model()->index( row, 0, QModelIndex() ); row = 0; while ( idx.isValid() ) { if ( row >= rowsPrPage * pageNumber ) { debugPlan<masterView()->indexBelow( idx ); } if ( ! idx.isValid() ) { row = -1; } } debugPlan<<"Page"< DoubleTreeViewPrintingDialog::createOptionWidgets() const { QList lst; lst << createPageLayoutWidget(); lst += PrintingDialog::createOptionWidgets(); return lst; } void DoubleTreeViewPrintingDialog::printPage( int page, QPainter &painter ) { debugPlan<pageLayout() ); qreal t, l, b, r; printer().getPageMargins( &l, &t, &r, &b, QPrinter::Point ); debugPlan<masterView()->header(); QHeaderView *sh = m_tree->slaveView()->header(); int length = mh->length() + sh->length(); int height = mh->height() > sh->height() ? mh->height() : sh->height(); QRect hRect = headerRect(); QRect fRect = footerRect(); QRect pageRect = printer().pageRect(); pageRect.moveTo( 0, 0 ); QRect paperRect = printer().paperRect(); QAbstractItemModel *model = m_tree->model(); Q_ASSERT( model != 0 ); debugPlan< length ? 1.0 : (double)pageRect.width() / (double)length; double sy = 1.0; painter.scale( sx, sy ); int h = 0; painter.translate( 0, hRect.height() + gap ); h = hRect.height() + gap; painter.setPen(Qt::black); painter.setBrush( Qt::lightGray ); int higestIndex = 0; int rightpos = 0; for ( int i = 0; i < mh->count(); ++i ) { QString text = model->headerData( i, Qt::Horizontal ).toString(); QVariant a = model->headerData( i, Qt::Horizontal, Qt::TextAlignmentRole ); int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter); if ( ! mh->isSectionHidden( i ) ) { QRect r = QRect( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height ).adjusted(0, 0, 0, -painter.pen().width()); if (rightpos < r.right()) { higestIndex = i; rightpos = r.right(); } painter.drawRect( r ); // FIXME There is a bug somewhere, the text somehow overwites the rect outline for the first column! painter.save(); painter.setBrush(QBrush()); painter.drawText( r.adjusted(3, 1, -3, -1), align, text ); painter.drawRect( r ); painter.restore(); } if ( ! sh->isSectionHidden( i ) ) { QRect r = QRect( sh->sectionPosition( i ) + mh->length(), 0, sh->sectionSize( i ), height ).adjusted(0, 0, 0, -painter.pen().width()); if (rightpos < r.right()) { higestIndex = i; rightpos = r.right(); } painter.drawRect( r ); painter.drawText( r.adjusted(3, 1, -3, -1), align, text ); } //debugPlan<isSectionHidden( i )<sectionPosition( i ); } if ( m_firstRow == -1 || model->rowCount() == 0 ) { debugPlan<<"No data"; painter.restore(); return; } painter.setBrush( QBrush() ); QModelIndex idx = model->index( 0, 0 ); for ( int r = 0; r < m_firstRow && idx.isValid(); ++r ) { idx = m_tree->masterView()->indexBelow( idx ); } int numRows = 0; //debugPlan<count(); ++i ) { if ( mh->isSectionHidden( i ) && sh->isSectionHidden( i ) ) { continue; } Qt::Edges edges = Qt::BottomEdge | Qt::LeftEdge; QModelIndex index = model->index( idx.row(), i, idx.parent() ); QString text = model->data( index ).toString(); QVariant a = model->data( index, Qt::TextAlignmentRole ); int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter); if ( ! mh->isSectionHidden( i ) ) { QRect r( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height ); if (higestIndex == i) { edges |= Qt::RightEdge; r.adjust(0, 0, 1, 0); } drawRect( painter, r, edges ); painter.drawText( r.adjusted(3, 1, -3, -1) , align, text ); } if ( ! sh->isSectionHidden( i ) ) { QRect r( sh->sectionPosition( i ) + mh->length(), 0, sh->sectionSize( i ), height ); if (higestIndex == i) { edges |= Qt::RightEdge; r.adjust(0, 0, 1, 0); } drawRect( painter, r, edges ); painter.drawText( r.adjusted(3, 1, -3, -1), align, text ); } } ++numRows; idx = m_tree->masterView()->indexBelow( idx ); } painter.restore(); } /** * DoubleTreeViewBase is a QSplitter containing two treeviews. * This makes it possible to keep columns visible in one view when scrolling the other view horizontally. */ DoubleTreeViewBase::DoubleTreeViewBase( bool /*mode*/, QWidget *parent ) : QSplitter( parent ), m_rightview( 0 ), m_selectionmodel( 0 ), m_readWrite( false ), m_mode( false ) { init(); } DoubleTreeViewBase::DoubleTreeViewBase( QWidget *parent ) : QSplitter( parent ), m_rightview( 0 ), m_selectionmodel( 0 ), m_mode( false ) { init(); } DoubleTreeViewBase::~DoubleTreeViewBase() { } KoPrintJob *DoubleTreeViewBase::createPrintJob( ViewBase *parent ) { DoubleTreeViewPrintingDialog *dia = new DoubleTreeViewPrintingDialog( parent, this, parent->project() ); dia->printer().setCreator( QString( "Plan %1" ).arg( PLAN_VERSION_STRING ) ); // dia->printer().setFullPage(true); // ignore printer margins return dia; } void DoubleTreeViewBase::slotExpand() { m_leftview->slotExpand(); } void DoubleTreeViewBase::slotCollapse() { m_leftview->slotCollapse(); } void DoubleTreeViewBase::setParentsExpanded( const QModelIndex &idx, bool expanded ) { //debugPlan<isExpanded( idx )<isExpanded( idx ); QModelIndex p = model()->parent( idx ); QList lst; while ( p.isValid() ) { lst << p; p = model()->parent( p ); } while ( ! lst.isEmpty() ) { p = lst.takeLast(); m_leftview->setExpanded( p, expanded ); m_rightview->setExpanded( m_rightview->firstVisibleIndex( p ), expanded ); //HACK: qt can't handle that column 0 is hidden! //debugPlan<isExpanded( p )<isExpanded( p ); } } void DoubleTreeViewBase::init() { setOrientation( Qt::Horizontal ); setHandleWidth( 3 ); m_leftview = new TreeViewBase(this); m_leftview->setObjectName("Left view"); addWidget( m_leftview ); setStretchFactor( 0, 1 ); m_rightview = new TreeViewBase(this); m_rightview->setObjectName("Right view"); addWidget( m_rightview ); setStretchFactor( 1, 1 ); m_leftview->setTreePosition(-1); // always visual index 0 - connect( m_leftview, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)) ); - connect( m_leftview, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotLeftHeaderContextMenuRequested(QPoint)) ); + connect( m_leftview, &TreeViewBase::contextMenuRequested, this, &DoubleTreeViewBase::contextMenuRequested ); + connect( m_leftview, &TreeViewBase::headerContextMenuRequested, this, &DoubleTreeViewBase::slotLeftHeaderContextMenuRequested ); - connect( m_rightview, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)) ); - connect( m_rightview, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotRightHeaderContextMenuRequested(QPoint)) ); + connect( m_rightview, &TreeViewBase::contextMenuRequested, this, &DoubleTreeViewBase::contextMenuRequested ); + connect( m_rightview, &TreeViewBase::headerContextMenuRequested, this, &DoubleTreeViewBase::slotRightHeaderContextMenuRequested ); - connect( m_leftview->verticalScrollBar(), SIGNAL(valueChanged(int)), m_rightview->verticalScrollBar(), SLOT(setValue(int)) ); + connect( m_leftview->verticalScrollBar(), &QAbstractSlider::valueChanged, m_rightview->verticalScrollBar(), &QAbstractSlider::setValue ); - connect( m_rightview->verticalScrollBar(), SIGNAL(valueChanged(int)), m_leftview->verticalScrollBar(), SLOT(setValue(int)) ); + connect( m_rightview->verticalScrollBar(), &QAbstractSlider::valueChanged, m_leftview->verticalScrollBar(), &QAbstractSlider::setValue ); - connect( m_leftview, SIGNAL(moveAfterLastColumn(QModelIndex)), this, SLOT(slotToRightView(QModelIndex)) ); - connect( m_rightview, SIGNAL(moveBeforeFirstColumn(QModelIndex)), this, SLOT(slotToLeftView(QModelIndex)) ); + connect( m_leftview, &TreeViewBase::moveAfterLastColumn, this, &DoubleTreeViewBase::slotToRightView ); + connect( m_rightview, &TreeViewBase::moveBeforeFirstColumn, this, &DoubleTreeViewBase::slotToLeftView ); - connect( m_leftview, SIGNAL(editAfterLastColumn(QModelIndex)), this, SLOT(slotEditToRightView(QModelIndex)) ); - connect( m_rightview, SIGNAL(editBeforeFirstColumn(QModelIndex)), this, SLOT(slotEditToLeftView(QModelIndex)) ); + connect( m_leftview, &TreeViewBase::editAfterLastColumn, this, &DoubleTreeViewBase::slotEditToRightView ); + connect( m_rightview, &TreeViewBase::editBeforeFirstColumn, this, &DoubleTreeViewBase::slotEditToLeftView ); - connect( m_leftview, SIGNAL(expanded(QModelIndex)), m_rightview, SLOT(expand(QModelIndex)) ); - connect( m_leftview, SIGNAL(collapsed(QModelIndex)), m_rightview, SLOT(collapse(QModelIndex)) ); + connect( m_leftview, &QTreeView::expanded, m_rightview, &QTreeView::expand ); + connect( m_leftview, &QTreeView::collapsed, m_rightview, &QTreeView::collapse ); - connect( m_rightview, SIGNAL(expanded(QModelIndex)), m_leftview, SLOT(expand(QModelIndex)) ); - connect( m_rightview, SIGNAL(collapsed(QModelIndex)), m_leftview, SLOT(collapse(QModelIndex)) ); + connect( m_rightview, &QTreeView::expanded, m_leftview, &QTreeView::expand ); + connect( m_rightview, &QTreeView::collapsed, m_leftview, &QTreeView::collapse ); - connect( m_leftview, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)) ); - connect( m_rightview, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)), this, SIGNAL(dropAllowed(QModelIndex,int,QDragMoveEvent*)) ); + connect( m_leftview, &TreeViewBase::dropAllowed, this, &DoubleTreeViewBase::dropAllowed ); + connect( m_rightview, &TreeViewBase::dropAllowed, this, &DoubleTreeViewBase::dropAllowed ); m_actionSplitView = new QAction(koIcon("view-split-left-right"), QString(), this); setViewSplitMode( true ); - connect( m_leftview->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(slotLeftSortIndicatorChanged(int,Qt::SortOrder)) ); + connect( m_leftview->header(), &QHeaderView::sortIndicatorChanged, this, &DoubleTreeViewBase::slotLeftSortIndicatorChanged ); - connect( m_rightview->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(slotRightSortIndicatorChanged(int,Qt::SortOrder)) ); + connect( m_rightview->header(), &QHeaderView::sortIndicatorChanged, this, &DoubleTreeViewBase::slotRightSortIndicatorChanged ); } void DoubleTreeViewBase::slotLeftSortIndicatorChanged( int logicalIndex, Qt::SortOrder /*order*/ ) { QSortFilterProxyModel *sf = qobject_cast( model() ); if ( sf ) { ItemModelBase *m = m_rightview->itemModel(); if ( m ) { sf->setSortRole( m->sortRole( logicalIndex ) ); } } m_leftview->header()->setSortIndicatorShown( true ); // sorting controlled by left treeview, turn right off m_rightview->header()->setSortIndicatorShown( false ); } void DoubleTreeViewBase::slotRightSortIndicatorChanged( int logicalIndex, Qt::SortOrder /*order*/ ) { QSortFilterProxyModel *sf = qobject_cast( model() ); if ( sf ) { ItemModelBase *m = m_rightview->itemModel(); if ( m ) { sf->setSortRole( m->sortRole( logicalIndex ) ); } } m_rightview->header()->setSortIndicatorShown( true ); // sorting controlled by right treeview, turn left off m_leftview->header()->setSortIndicatorShown( false ); } QList DoubleTreeViewBase::expandColumnList( const QList &lst ) const { QList mlst = lst; if ( ! mlst.isEmpty() ) { int v = 0; if ( mlst.last() == -1 && mlst.count() > 1 ) { v = mlst[ mlst.count() - 2 ] + 1; mlst.removeLast(); } for ( int c = v; c < model()->columnCount(); ++c ) { mlst << c; } } return mlst; } void DoubleTreeViewBase::hideColumns( TreeViewBase *view, const QList &list ) { view->setColumnsHidden( list ); } void DoubleTreeViewBase::hideColumns( const QList &masterList, const QList &slaveList ) { m_leftview->setColumnsHidden( masterList ); m_rightview->setColumnsHidden( slaveList ); if ( m_rightview->isHidden() ) { QList mlst = expandColumnList( masterList ); QList slst = expandColumnList( slaveList ); QList lst; for ( int c = 0; c < model()->columnCount(); ++c ) { // only hide columns hidden in *both* views //debugPlan<= 0) && (slst.indexOf( c ) >= 0) ) { lst << c; } } //debugPlan<setColumnsHidden( lst ); } else { setStretchFactors(); } } void DoubleTreeViewBase::slotToRightView( const QModelIndex &index ) { //debugPlan<firstColumn( index.row(), model()->parent( index ) ); m_rightview->setFocus(); if ( nxt.isValid() ) { m_selectionmodel->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate ); } } void DoubleTreeViewBase::slotToLeftView( const QModelIndex &index ) { //debugPlan<lastColumn( index.row(), model()->parent( index ) ); m_leftview->setFocus(); if ( prv.isValid() ) { m_selectionmodel->setCurrentIndex( prv, QItemSelectionModel::NoUpdate ); } } void DoubleTreeViewBase::slotEditToRightView( const QModelIndex &index ) { //debugPlan<isHidden() ) { return; } m_rightview->setFocus(); QModelIndex nxt = m_rightview->firstEditable( index.row(), model()->parent ( index ) ); if ( nxt.isValid() && ( model()->flags( nxt ) & Qt::ItemIsEditable ) ) { m_selectionmodel->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate ); m_rightview->edit( nxt ); } else { slotToRightView( index ); } } void DoubleTreeViewBase::slotEditToLeftView( const QModelIndex &index ) { //debugPlan<isHidden() ) { return; } m_leftview->setFocus(); QModelIndex nxt = m_leftview->lastEditable( index.row(), model()->parent ( index ) ); if ( nxt.isValid() && ( model()->flags( nxt ) & Qt::ItemIsEditable ) ) { m_selectionmodel->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate ); m_leftview->edit( nxt ); } else { slotToLeftView( index ); } } void DoubleTreeViewBase::setReadWrite( bool rw ) { m_readWrite = rw; m_leftview->setReadWrite( rw ); m_rightview->setReadWrite( rw ); } void DoubleTreeViewBase::closePersistentEditor( const QModelIndex &index ) { m_leftview->closePersistentEditor( index ); m_rightview->closePersistentEditor( index ); } void DoubleTreeViewBase::setModel( QAbstractItemModel *model ) { m_leftview->setModel( model ); m_rightview->setModel( model ); if ( m_selectionmodel ) { - disconnect( m_selectionmodel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) ); + disconnect( m_selectionmodel, &QItemSelectionModel::selectionChanged, this, &DoubleTreeViewBase::slotSelectionChanged ); - disconnect( m_selectionmodel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(currentChanged(QModelIndex,QModelIndex)) ); + disconnect( m_selectionmodel, &QItemSelectionModel::currentChanged, this, &DoubleTreeViewBase::currentChanged ); } m_selectionmodel = m_leftview->selectionModel(); m_rightview->setSelectionModel( m_selectionmodel ); - connect( m_selectionmodel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection)) ); + connect( m_selectionmodel, &QItemSelectionModel::selectionChanged, this, &DoubleTreeViewBase::slotSelectionChanged ); - connect( m_selectionmodel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(currentChanged(QModelIndex,QModelIndex)) ); + connect( m_selectionmodel, &QItemSelectionModel::currentChanged, this, &DoubleTreeViewBase::currentChanged ); setReadWrite( m_readWrite ); } QAbstractItemModel *DoubleTreeViewBase::model() const { return m_leftview->model(); } void DoubleTreeViewBase::slotSelectionChanged( const QItemSelection &sel, const QItemSelection & ) { emit selectionChanged( sel.indexes() ); } void DoubleTreeViewBase::setSelectionModel( QItemSelectionModel *model ) { m_leftview->setSelectionModel( model ); m_rightview->setSelectionModel( model ); } void DoubleTreeViewBase::setSelectionMode( QAbstractItemView::SelectionMode mode ) { m_leftview->setSelectionMode( mode ); m_rightview->setSelectionMode( mode ); } void DoubleTreeViewBase::setSelectionBehavior( QAbstractItemView::SelectionBehavior mode ) { m_leftview->setSelectionBehavior( mode ); m_rightview->setSelectionBehavior( mode ); } void DoubleTreeViewBase::setItemDelegateForColumn( int col, QAbstractItemDelegate * delegate ) { m_leftview->setItemDelegateForColumn( col, delegate ); m_rightview->setItemDelegateForColumn( col, delegate ); } void DoubleTreeViewBase::createItemDelegates( ItemModelBase *model ) { m_leftview->createItemDelegates( model ); m_rightview->createItemDelegates( model ); } void DoubleTreeViewBase::setEditTriggers( QAbstractItemView::EditTriggers mode ) { m_leftview->setEditTriggers( mode ); m_rightview->setEditTriggers( mode ); } QAbstractItemView::EditTriggers DoubleTreeViewBase::editTriggers() const { return m_leftview->editTriggers(); } void DoubleTreeViewBase::setStretchLastSection( bool mode ) { m_rightview->header()->setStretchLastSection( mode ); if ( m_rightview->isHidden() ) { m_leftview->header()->setStretchLastSection( mode ); } } void DoubleTreeViewBase::edit( const QModelIndex &index ) { if ( ! m_leftview->isColumnHidden( index.column() ) ) { m_leftview->edit( index ); } else if ( ! m_rightview->isHidden() && ! m_rightview->isColumnHidden( index.column() ) ) { m_rightview->edit( index ); } } void DoubleTreeViewBase::setDragDropMode( QAbstractItemView::DragDropMode mode ) { m_leftview->setDragDropMode( mode ); m_rightview->setDragDropMode( mode ); } void DoubleTreeViewBase::setDragDropOverwriteMode( bool mode ) { m_leftview->setDragDropOverwriteMode( mode ); m_rightview->setDragDropOverwriteMode( mode ); } void DoubleTreeViewBase::setDropIndicatorShown( bool mode ) { m_leftview->setDropIndicatorShown( mode ); m_rightview->setDropIndicatorShown( mode ); } void DoubleTreeViewBase::setDragEnabled ( bool mode ) { m_leftview->setDragEnabled( mode ); m_rightview->setDragEnabled( mode ); } void DoubleTreeViewBase::setAcceptDrops( bool mode ) { m_leftview->setAcceptDrops( mode ); m_rightview->setAcceptDrops( mode ); } void DoubleTreeViewBase::setAcceptDropsOnView( bool mode ) { m_leftview->setAcceptDropsOnView( mode ); m_rightview->setAcceptDropsOnView( mode ); } void DoubleTreeViewBase::setDefaultDropAction( Qt::DropAction action ) { m_leftview->setDefaultDropAction( action ); m_rightview->setDefaultDropAction( action ); } void DoubleTreeViewBase::slotRightHeaderContextMenuRequested( const QPoint &pos ) { //debugPlan; emit slaveHeaderContextMenuRequested( pos ); emit headerContextMenuRequested( pos ); } void DoubleTreeViewBase::slotLeftHeaderContextMenuRequested( const QPoint &pos ) { //debugPlan; emit masterHeaderContextMenuRequested( pos ); emit headerContextMenuRequested( pos ); } void DoubleTreeViewBase::setStretchFactors() { int lc = m_leftview->header()->count() - m_leftview->header()->hiddenSectionCount(); int rc = m_rightview->header()->count() - m_rightview->header()->hiddenSectionCount(); setStretchFactor( indexOf( m_rightview ), qMax( 1, qMin( 4, rc / qMax( 1, lc ) ) ) ); //debugPlan<loadContext(map, slave, false); } KoXmlElement master = element.namedItem("master").toElement(); if (!master.isNull()) { m_leftview->loadContext(map, master); } return true; } void DoubleTreeViewBase::saveContext( const QMetaEnum &map, QDomElement &element ) const { QDomElement master = element.ownerDocument().createElement( "master" ); element.appendChild(master); m_leftview->saveContext(map, master); QDomElement slave = element.ownerDocument().createElement( "slave" ); element.appendChild(slave); if (m_rightview->isHidden()) { slave.setAttribute("hidden", "true"); } m_rightview->saveContext(map, slave, false); } void DoubleTreeViewBase::setViewSplitMode( bool split ) { if ( split ) { m_actionSplitView->setText( i18n( "Unsplit View" ) ); m_actionSplitView->setIcon(koIcon("view-close")); } else { m_actionSplitView->setText( i18n( "Split View" ) ); m_actionSplitView->setIcon(koIcon("view-split-left-right")); } if ( m_mode == split ) { return; } m_mode = split; if ( split ) { m_leftview->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); m_leftview->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); if ( model() ) { m_rightview->setColumnHidden( 0, true ); m_leftview->resizeColumnToContents( 0 ); for ( int c = 1; c < m_rightview->model()->columnCount(); ++c ) { if ( m_leftview->isColumnHidden( c ) ) { m_rightview->setColumnHidden( c, true ); } else { m_rightview->setColumnHidden( c, false ); m_rightview->mapToSection( c, m_leftview->section( c ) ); m_leftview->setColumnHidden( c, true ); m_rightview->resizeColumnToContents( c ); } } } m_rightview->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn ); m_rightview->show(); } else { m_rightview->hide(); if ( model() ) { int offset = m_rightview->isColumnHidden( 0 ) ? 1 : 0; for ( int c = 0; c < model()->columnCount(); ++c ) { if ( ! m_rightview->isColumnHidden( c ) ) { m_leftview->setColumnHidden( c, false ); m_leftview->mapToSection( c, m_rightview->section( c ) + offset ); m_leftview->resizeColumnToContents( c ); } } } m_leftview->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded ); m_leftview->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded ); } } void DoubleTreeViewBase::setRootIsDecorated ( bool show ) { m_leftview->setRootIsDecorated( show ); m_rightview->setRootIsDecorated( show ); } QModelIndex DoubleTreeViewBase::indexAt( const QPoint &pos ) const { QModelIndex idx = m_leftview->indexAt( pos ); if ( ! idx.isValid() ) { idx = m_rightview->indexAt( pos ); } return idx; } void DoubleTreeViewBase::setContextMenuIndex(const QModelIndex &idx) { m_leftview->setContextMenuIndex(idx); m_rightview->setContextMenuIndex(idx); } } // namespace KPlato diff --git a/src/libs/ui/kptwbsdefinitiondialog.cpp b/src/libs/ui/kptwbsdefinitiondialog.cpp index bba413c5..88210f89 100644 --- a/src/libs/ui/kptwbsdefinitiondialog.cpp +++ b/src/libs/ui/kptwbsdefinitiondialog.cpp @@ -1,58 +1,58 @@ /* This file is part of the KDE project Copyright (C) 2005 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 "kptwbsdefinitiondialog.h" #include "kptwbsdefinitionpanel.h" #include "kptwbsdefinition.h" #include #include namespace KPlato { WBSDefinitionDialog::WBSDefinitionDialog(Project &project, WBSDefinition &def, QWidget *p) : KoDialog(p) { setCaption( i18n("WBS Definition") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); m_panel = new WBSDefinitionPanel(project, def, this); setMainWidget(m_panel); enableButtonOk(false); - connect(m_panel, SIGNAL(changed(bool)), SLOT(enableButtonOk(bool))); - connect(this, SIGNAL(okClicked()), SLOT(slotOk())); + connect(m_panel, &WBSDefinitionPanel::changed, this, &KoDialog::enableButtonOk); + connect(this, &KoDialog::okClicked, this, &WBSDefinitionDialog::slotOk); } KUndo2Command *WBSDefinitionDialog::buildCommand() { return m_panel->buildCommand(); } void WBSDefinitionDialog::slotOk() { if (!m_panel->ok()) return; accept(); } } //KPlato namespace diff --git a/src/libs/ui/kptwbsdefinitionpanel.cpp b/src/libs/ui/kptwbsdefinitionpanel.cpp index 48d9ddd0..ac1e836d 100644 --- a/src/libs/ui/kptwbsdefinitionpanel.cpp +++ b/src/libs/ui/kptwbsdefinitionpanel.cpp @@ -1,225 +1,225 @@ /* This file is part of the KDE project Copyright (C) 2005-2007, 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. */ #include "kptwbsdefinitionpanel.h" #include "kptwbsdefinition.h" #include "kptcommand.h" #include "kptproject.h" #include "kptdebug.h" #include #include #include #include #include namespace KPlato { ComboBoxDelegate::ComboBoxDelegate(QStringList &list, QObject *parent) : QStyledItemDelegate(parent) { debugPlan; setObjectName("ComboBoxDelegate"); m_list = list; } QWidget *ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex &/* index */) const { debugPlan; QComboBox *editor = new KComboBox(parent); editor->installEventFilter(const_cast(this)); return editor; } void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QString value = index.model()->data(index, Qt::DisplayRole).toString(); debugPlan<(editor); comboBox->insertItems(0, m_list); comboBox->setCurrentIndex(comboBox->findText(value)); } void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *comboBox = static_cast(editor); debugPlan<currentText(); model->setData(index, comboBox->currentText()); } void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } //---------------------- WBSDefinitionPanel::WBSDefinitionPanel( Project &project, WBSDefinition &def, QWidget *p, const char *n) : QWidget(p), m_project( project ), m_def(def), selectedRow(-1) { setObjectName(n); setupUi(this); projectCode->setText( m_def.projectCode() ); projectSeparator->setText( m_def.projectSeparator() ); QStringList codeList = m_def.codeList(); debugPlan<setText(m_def.defaultSeparator()); defaultCode->addItems(codeList); defaultCode->setCurrentIndex(m_def.defaultCodeIndex()); defaultCode->setFocus(); levelsTable->setItemDelegateForColumn(0, new ComboBoxDelegate(codeList, this)); levelsGroup->setChecked(m_def.isLevelsDefEnabled()); int i = 0; const QMap &lev = m_def.levelsDef(); levelsTable->setRowCount(lev.count()); QStringList sl; debugPlan<<"Map size="<::const_iterator it; for (it = lev.begin(); it != lev.end(); ++it) { sl << QString("%1").arg(it.key()); QTableWidgetItem *item = new QTableWidgetItem(); item->setData(Qt::DisplayRole, it.value().code); levelsTable->setItem(i, 0, item); item = new QTableWidgetItem(); item->setText(it.value().separator); levelsTable->setItem(i, 1, item); i++; } levelsTable->setVerticalHeaderLabels(sl); //levelsTable->setColumnStretchable(0, true); slotLevelChanged(level->value()); - connect(projectCode, SIGNAL(textChanged(QString)), SLOT(slotChanged())); - connect(projectSeparator, SIGNAL(textChanged(QString)), SLOT(slotChanged())); + connect(projectCode, &QLineEdit::textChanged, this, &WBSDefinitionPanel::slotChanged); + connect(projectSeparator, &QLineEdit::textChanged, this, &WBSDefinitionPanel::slotChanged); connect(defaultCode, SIGNAL(activated(int)), SLOT(slotChanged())); - connect(defaultSeparator, SIGNAL(textChanged(QString)), SLOT(slotChanged())); - connect(levelsGroup, SIGNAL(toggled(bool)), SLOT(slotLevelsGroupToggled(bool))); - connect(levelsTable, SIGNAL(cellChanged(int,int)), SLOT(slotChanged())); - connect(levelsTable, SIGNAL(itemSelectionChanged()), SLOT(slotSelectionChanged())); + connect(defaultSeparator, &QLineEdit::textChanged, this, &WBSDefinitionPanel::slotChanged); + connect(levelsGroup, &QGroupBox::toggled, this, &WBSDefinitionPanel::slotLevelsGroupToggled); + connect(levelsTable, &QTableWidget::cellChanged, this, &WBSDefinitionPanel::slotChanged); + connect(levelsTable, &QTableWidget::itemSelectionChanged, this, &WBSDefinitionPanel::slotSelectionChanged); connect(level, SIGNAL(valueChanged(int)), SLOT(slotLevelChanged(int))); - connect(removeBtn, SIGNAL(clicked(bool)), SLOT(slotRemoveBtnClicked())); - connect(addBtn, SIGNAL(clicked(bool)), SLOT(slotAddBtnClicked())); + connect(removeBtn, &QAbstractButton::clicked, this, &WBSDefinitionPanel::slotRemoveBtnClicked); + connect(addBtn, &QAbstractButton::clicked, this, &WBSDefinitionPanel::slotAddBtnClicked); removeBtn->setEnabled(false); } void WBSDefinitionPanel::setStartValues() { } KUndo2Command *WBSDefinitionPanel::buildCommand() { WBSDefinition def = m_def; def.setProjectCode( projectCode->text() ); def.setProjectSeparator( projectSeparator->text() ); def.setDefaultCode(defaultCode->currentIndex()); def.setDefaultSeparator(defaultSeparator->text()); def.setLevelsDefEnabled(levelsGroup->isChecked()); def.clearLevelsDef(); for (int i = 0; i < levelsTable->rowCount(); ++i) { def.setLevelsDef(levelsTable->verticalHeaderItem(i)->text().toInt(), levelsTable->item(i, 0)->text(), levelsTable->item(i, 1)->text()); } WBSDefinitionModifyCmd *cmd = new WBSDefinitionModifyCmd( m_project, def, kundo2_i18n("Modify WBS Code Definition")); return cmd; } bool WBSDefinitionPanel::ok() { debugPlan; return true; } void WBSDefinitionPanel::slotChanged() { emit changed(true); } void WBSDefinitionPanel::slotSelectionChanged() { QString s; selectedRow = -1; QList items = levelsTable->selectedItems(); if (items.count() == 2 && items[0]->row() == items[1]->row()) { selectedRow = items[0]->row(); s = QString("Row[%1]=selected ").arg(selectedRow); } else { s = "None selected"; } removeBtn->setEnabled(selectedRow != -1); debugPlan<removeRow(selectedRow); removeBtn->setEnabled(false); slotLevelChanged(level->value()); } void WBSDefinitionPanel::slotAddBtnClicked() { debugPlan; int i=levelsTable->rowCount()-1; for (; i >= 0; --i) { debugPlan<<"Checking row["<verticalHeaderItem(i)->text()<<" with"<value(); if (level->value() > levelsTable->verticalHeaderItem(i)->text().toInt()) { break; } } i++; levelsTable->insertRow(i); levelsTable->setVerticalHeaderItem(i, new QTableWidgetItem(QString("%1").arg(level->value()))); QTableWidgetItem *item = new QTableWidgetItem(); item->setData(Qt::DisplayRole, (m_def.codeList().value(m_def.defaultCodeIndex()))); levelsTable->setItem(i, 0, item); item = new QTableWidgetItem(); item->setText(m_def.defaultSeparator()); levelsTable->setItem(i, 1, item); addBtn->setEnabled(false); slotChanged(); debugPlan<<"Added row="< #include #include #include #include #include #include #include #include #include #include #include "kmessagebox_copy.cpp" // themedMessageBoxIcon() namespace KPlato { PackageInfoWidget::PackageInfoWidget( Package *package, QWidget* parent) : QFrame( parent ), m_package( package ) { setFrameStyle( QFrame::Sunken | QFrame::StyledPanel ); QHBoxLayout *l = new QHBoxLayout( this ); l->addSpacing( 20 ); QCheckBox *w = new QCheckBox( this ); w->setText( i18n( "Used Effort" ) ); w->setCheckState( package->settings.usedEffort ? Qt::Checked : Qt::Unchecked ); l->addWidget( w ); - connect(w, SIGNAL(stateChanged(int)), SLOT(slotUsedEffortChanged(int))); + connect(w, &QCheckBox::stateChanged, this, &PackageInfoWidget::slotUsedEffortChanged); w = new QCheckBox( this ); w->setText( i18n( "Task Progress" ) ); w->setCheckState( package->settings.progress ? Qt::Checked : Qt::Unchecked ); l->addWidget( w ); - connect(w, SIGNAL(stateChanged(int)), SLOT(slotProgressChanged(int))); + connect(w, &QCheckBox::stateChanged, this, &PackageInfoWidget::slotProgressChanged); w = new QCheckBox( this ); w->setText( i18n("&Documents") ); w->setCheckState( package->settings.documents ? Qt::Checked : Qt::Unchecked ); l->addWidget( w ); - connect(w, SIGNAL(stateChanged(int)), SLOT(slotDocumentsChanged(int))); + connect(w, &QCheckBox::stateChanged, this, &PackageInfoWidget::slotDocumentsChanged); } void PackageInfoWidget::slotUsedEffortChanged( int s ) { m_package->settings.usedEffort = (bool)s; } void PackageInfoWidget::slotProgressChanged( int s ) { m_package->settings.progress = (bool)s; } void PackageInfoWidget::slotDocumentsChanged( int s ) { m_package->settings.documents = (bool)s; } WorkPackageMergePanel::WorkPackageMergePanel( QWidget *parent ) : QWidget( parent ) { setupUi( this ); } WorkPackageMergeDialog::WorkPackageMergeDialog( const QString &text, const QMap &list, QWidget *parent ) : KoDialog( parent ), m_packages( list.values() ) { panel.ui_text->setText( text ); QIcon icon = themedMessageBoxIcon( QMessageBox::Information ); if ( ! icon.isNull() ) { QStyleOption option; option.initFrom( this ); panel.ui_icon->setPixmap( icon.pixmap( style()->pixelMetric( QStyle::PM_MessageBoxIconSize, &option, this ) ) ); } setButtons( KoDialog::Yes | KoDialog::No ); panel.ui_view->setHeaderHidden( true ); panel.ui_view->setRootIsDecorated( false ); m_delegate = new KExtendableItemDelegate( panel.ui_view ); panel.ui_view->setItemDelegate( m_delegate ); m_model = new QStandardItemModel( panel.ui_view ); foreach( Package *p, m_packages ) { QList items; items << new QStandardItem(); items << new QStandardItem( p->project->childNode( 0 )->name() ); items << new QStandardItem( static_cast( p->project->childNode( 0 ) )->workPackage().ownerName() ); items << new QStandardItem( QLocale().toString(p->timeTag, QLocale::ShortFormat) ); if ( p->toTask ) { items[ CheckColumn ]->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable ); items[ CheckColumn ]->setCheckState( Qt::Checked ); items[ TaskNameColumn ]->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); items[ OwnerNameColumn ]->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); items[DateTimeColumn]->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); items[ DateTimeColumn ]->setTextAlignment( Qt::AlignCenter ); } m_model->appendRow( items ); } // sort on datetime first QSortFilterProxyModel *dtsort = new QSortFilterProxyModel( panel.ui_view ); dtsort->setSourceModel( m_model ); dtsort->sort( DateTimeColumn, Qt::DescendingOrder ); // then on task name QSortFilterProxyModel *tasksort = new QSortFilterProxyModel( panel.ui_view ); tasksort->setSourceModel( dtsort ); tasksort->sort( TaskNameColumn, Qt::AscendingOrder ); panel.ui_view->setModel( tasksort ); for ( int c = 0; c < m_model->columnCount(); ++c ) { panel.ui_view->resizeColumnToContents( c ); } setMainWidget( &panel ); slotChanged(); - connect(panel.ui_view->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(slotChanged())); - connect(panel.ui_view, SIGNAL(activated(QModelIndex)), SLOT(slotActivated(QModelIndex))); + connect(panel.ui_view->model(), &QAbstractItemModel::dataChanged, this, &WorkPackageMergeDialog::slotChanged); + connect(panel.ui_view, &QAbstractItemView::activated, this, &WorkPackageMergeDialog::slotActivated); } WorkPackageMergeDialog::~WorkPackageMergeDialog() { m_delegate->contractAll(); } void WorkPackageMergeDialog::slotActivated( const QModelIndex &idx ) { QModelIndex i = idx; if ( i.column() >= CheckColumn ) { i = i.model()->index( i.row(), TaskNameColumn, i.parent() ); } if ( i.column() != TaskNameColumn ) { return; } if ( m_delegate->isExtended( i ) ) { m_delegate->contractItem( i ); } else { m_delegate->extendItem( new PackageInfoWidget( m_packages.at( idx.row() ) ), i ); } } QList WorkPackageMergeDialog::checkedList() const { QList lst; int count = m_model->rowCount(); for ( int i = 0; i < count; ++i ) { if ( m_model->index( i, 0 ).data( Qt::CheckStateRole ).toInt() == Qt::Checked ) { lst << i; } } return lst; } void WorkPackageMergeDialog::slotChanged() { enableButton( KoDialog::Yes, m_model->rowCount() > 0 ); } } // namespace KPlato diff --git a/src/libs/ui/kptworkpackagesendpanel.cpp b/src/libs/ui/kptworkpackagesendpanel.cpp index 51f5e6aa..6e2e3a63 100644 --- a/src/libs/ui/kptworkpackagesendpanel.cpp +++ b/src/libs/ui/kptworkpackagesendpanel.cpp @@ -1,73 +1,73 @@ /* This file is part of the KDE project Copyright (C) 2007 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 "kptworkpackagesendpanel.h" #include "kpttaskeditor.h" #include "kptproject.h" #include "kpttask.h" #include "kptschedule.h" #include #include #include #include #include namespace KPlato { WorkPackageSendPanel::WorkPackageSendPanel( const QList &tasks, ScheduleManager *sm, QWidget *p ) : QWidget(p) { setupUi( this ); long id = sm ? sm->scheduleId() : NOTSCHEDULED; foreach ( Node *n, tasks ) { Task *t = qobject_cast( n ); if ( t == 0 ) { continue; } foreach ( Resource *r, t->workPackage().fetchResources( id ) ) { m_resMap[ r ] << n; } } QMap >::const_iterator it; for ( it = m_resMap.constBegin(); it != m_resMap.constEnd(); ++it ) { QPushButton *pb = new QPushButton(koIcon("mail-send"), i18n("Send To..."), scrollArea); QLineEdit *le = new QLineEdit( it.key()->name(), scrollArea ); le->setReadOnly( true ); formLayout->addRow( pb, le ); - connect( pb, SIGNAL(clicked(bool)), SLOT(slotSendClicked()) ); + connect( pb, &QAbstractButton::clicked, this, &WorkPackageSendPanel::slotSendClicked ); m_pbMap[ pb ] = it.key(); } } void WorkPackageSendPanel::slotSendClicked() { Resource *r = m_pbMap[ qobject_cast( sender() ) ]; emit sendWorkpackages( m_resMap[ r ], r ); } } //KPlato namespace diff --git a/src/libs/ui/locale/localemon.cpp b/src/libs/ui/locale/localemon.cpp index 10714c8e..b900f4a7 100644 --- a/src/libs/ui/locale/localemon.cpp +++ b/src/libs/ui/locale/localemon.cpp @@ -1,133 +1,133 @@ /* * localemon.cpp * * Copyright (c) 1999-2003 Hans Petter Bieker * Copyright (c) 2009, 2012 Dag Andersen * Copyright (C) 2016 Dag Andersen * * Requires the Qt widget libraries, available at no cost at * http://www.troll.no/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //#include "toplevel.h" #include "localemon.h" #include "kptlocale.h" #include "kptcommand.h" #include "kptdebug.h" #include #include #include #include #include #include namespace KPlato { LocaleConfigMoney::LocaleConfigMoney(Locale *locale, QWidget *parent) : QWidget(parent), m_locale(locale) { setupUi(this); // Money m_labMonCurSym->setObjectName( I18N_NOOP("Currency symbol:") ); m_labMonFraDig->setObjectName( I18N_NOOP("Fract digits:") ); - connect(m_edMonCurSym,SIGNAL(textChanged(QString)),SLOT(slotMonCurSymChanged(QString))); + connect(m_edMonCurSym,&QLineEdit::textChanged,this, &LocaleConfigMoney::slotMonCurSymChanged); connect(m_inMonFraDig,SIGNAL(valueChanged(int)),SLOT(slotMonFraDigChanged(int))); m_inMonFraDig->setRange(0, 10); m_inMonFraDig->setSingleStep(1); slotTranslate(); slotLocaleChanged(); } LocaleConfigMoney::~LocaleConfigMoney() { } void LocaleConfigMoney::slotLocaleChanged() { m_edMonCurSym->setText( m_locale->currencySymbolExplicit()); m_inMonFraDig->setValue(m_locale->monetaryDecimalPlaces()); } void LocaleConfigMoney::slotMonCurSymChanged(const QString &/*t*/) { emit localeChanged(); } void LocaleConfigMoney::slotMonFraDigChanged(int /*value*/) { emit localeChanged(); } void LocaleConfigMoney::slotMonPosPreCurSymChanged() { emit localeChanged(); } void LocaleConfigMoney::slotMonNegPreCurSymChanged() { emit localeChanged(); } void LocaleConfigMoney::slotMonPosMonSignPosChanged(int /*i*/) { emit localeChanged(); } void LocaleConfigMoney::slotMonNegMonSignPosChanged(int /*i*/) { emit localeChanged(); } void LocaleConfigMoney::slotTranslate() { QString str; str = i18n( "Here you can enter your usual currency " "symbol, e.g. $ or €." ); m_labMonCurSym->setWhatsThis( str ); m_edMonCurSym->setWhatsThis( str ); } MacroCommand *LocaleConfigMoney::buildCommand() { MacroCommand *m = new MacroCommand(); if ( m_locale->currencySymbolExplicit() != m_edMonCurSym->text() ) { m->addCommand( new ModifyCurrencySymolCmd( m_locale, m_edMonCurSym->text() ) ); } if (m_locale->monetaryDecimalPlaces() != m_inMonFraDig->value()) { m->addCommand( new ModifyCurrencyFractionalDigitsCmd( m_locale, m_inMonFraDig->value() ) ); } debugPlan<<"buildCommand:"<isEmpty(); if ( m->isEmpty() ) { delete m; return 0; } return m; } } // namespace KPlato diff --git a/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp b/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp index c9c4cbc6..8e18d4df 100644 --- a/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp +++ b/src/libs/ui/reportsgenerator/ReportsGeneratorView.cpp @@ -1,539 +1,539 @@ /* 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. */ #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 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; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; 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); qDebug()<(editor); qDebug()<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); qDebug()<currentText(); qDebug()<<"template file:"<setData(index, nfile); if (files.contains(nfile)) { nfile = files[nfile].url(); } model->setData(index, nfile, FULLPATHROLE); } } else qDebug()<<" No combo box editor!!"; } class FileItemDelegate : public QStyledItemDelegate { public: FileItemDelegate(QObject *parent); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; 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; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; }; 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 ----------------------"; 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); - connect(m_view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotContextMenuRequested(QPoint))); + 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); qDebug()<<"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(), SIGNAL(selectionChanged(QItemSelection&,QItemSelection&)), this, SLOT(slotSelectionChanged())); + 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::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() { // Umpff, adding a specific list name for this view in calligraplan.rc does not work! // But reusing an already existing name works, so... // Not important atm, the whole setup should be refactored anyway. //QString name = "reportsgeneratorview_list"; QString name = "workpackage_list"; 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, SIGNAL(triggered(bool)), SLOT(slotAddReport())); + connect(actionAddReport, &QAction::triggered, this, &ReportsGeneratorView::slotAddReport); addAction(name, actionAddReport); 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, SIGNAL(triggered(bool)), SLOT(slotRemoveReport())); + connect(actionRemoveReport, &QAction::triggered, this, &ReportsGeneratorView::slotRemoveReport); addAction(name, actionRemoveReport); 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, SIGNAL(triggered(bool)), SLOT(slotGenerateReport())); + connect(actionGenerateReport, &QAction::triggered, this, &ReportsGeneratorView::slotGenerateReport); addAction(name, actionGenerateReport); 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; } QMessageBox::information(this, i18n("Report Generation"), i18n("Report file generated: %1", file)); 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, 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); } 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/libs/ui/welcome/WelcomeView.cpp b/src/libs/ui/welcome/WelcomeView.cpp index 0b5c726a..38fbd330 100644 --- a/src/libs/ui/welcome/WelcomeView.cpp +++ b/src/libs/ui/welcome/WelcomeView.cpp @@ -1,321 +1,321 @@ /* 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. */ #include "WelcomeView.h" #include "kptcommand.h" #include "kptdebug.h" #include "Help.h" #include #include #include #include #include #include #include #include #include #include #include #include const QLoggingCategory &PLANWELCOME_LOG() { static const QLoggingCategory category("calligra.plan.welcome"); return category; } #define debugWelcome qCDebug(PLANWELCOME_LOG) #define warnWelcome qCWarning(PLANWELCOME_LOG) #define errorWelcome qCCritical(PLANWELCOME_LOG) namespace KPlato { class RecentFilesModel : public QStringListModel { public: RecentFilesModel(QObject *parent = 0); Qt::ItemFlags flags(const QModelIndex &idx) const; QVariant data(const QModelIndex &idx, int role) const; }; RecentFilesModel::RecentFilesModel(QObject *parent) : QStringListModel(parent) { } Qt::ItemFlags RecentFilesModel::flags(const QModelIndex &idx) const { Qt::ItemFlags f = (QStringListModel::flags(idx) & ~Qt::ItemIsEditable); return f; } QVariant RecentFilesModel::data(const QModelIndex &idx, int role) const { switch(role) { case Qt::DecorationRole: return QIcon::fromTheme(QStringLiteral("document-open")); break; case Qt::FontRole: break; default: break; } return QStringListModel::data(idx, role); } //----------------------------------- WelcomeView::WelcomeView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) , m_projectdialog(0) , m_filedialog(0) { widget.setupUi(this); widget.recentProjects->setBackgroundRole(QPalette::Midlight); Help::add(widget.newProjectBtn, xi18nc("@info:whatsthis", "Create a new project" "" "Creates a new project with default values defined in" " Settings." "Opens the project dialog" " so you can define project specific properties like" " Project Name," " Target Start" " and - End times." "More..." "", Help::page("Manual/Creating_a_Project"))); Help::add(widget.createResourceFileBtn, xi18nc("@info:whatsthis", "Shared resources" "" "Create a shared resources file." "This enables you to only create your resources once," " you just refer to your resources file when you create a new project." "These resources can then be shared between projects" " to avoid overbooking resources across projects." "Shared resources must be defined in a separate file." "More..." "", Help::page("Manual/Managing_Resources"))); Help::add(widget.recentProjects, xi18nc("@info:whatsthis", "Recent Projects" "" "A list of the 10 most recent project files opened." "" "This enables you to quickly open projects you have worked on recently." "")); Help::add(widget.introductionBtn, xi18nc("@info:whatsthis", "Introduction to <application>Plan</application>" "" "These introductory pages gives you hints and tips on what" " you can use Plan for, and how to use it." "")); Help::add(widget.contextHelp, xi18nc("@info:whatsthis", "Context help" "" "Help is available many places using What's This." "It is activated using the menu entry Help->What's this?" " or the keyboard shortcut Shift+F1." "" "In dialogs it is available via the ? in the dialog title bar." "" "If you see More... in the text," " pressing it will display more information from online resources in your browser." "", Help::page("Manual/Context_Help"))); m_model = new RecentFilesModel(this); widget.recentProjects->setModel(m_model); setupGui(); - connect(widget.newProjectBtn, SIGNAL(clicked(bool)), this, SLOT(slotNewProject())); - connect(widget.createResourceFileBtn, SIGNAL(clicked(bool)), this, SLOT(slotCreateResourceFile())); - connect(widget.openProjectBtn, SIGNAL(clicked(bool)), this, SLOT(slotOpenProject())); - connect(widget.introductionBtn, SIGNAL(clicked(bool)), this, SIGNAL(showIntroduction())); + connect(widget.newProjectBtn, &QAbstractButton::clicked, this, &WelcomeView::slotNewProject); + connect(widget.createResourceFileBtn, &QAbstractButton::clicked, this, &WelcomeView::slotCreateResourceFile); + connect(widget.openProjectBtn, &QAbstractButton::clicked, this, &WelcomeView::slotOpenProject); + connect(widget.introductionBtn, &QAbstractButton::clicked, this, &WelcomeView::showIntroduction); - connect(widget.recentProjects->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotRecentFileSelected(QItemSelection))); + connect(widget.recentProjects->selectionModel(), &QItemSelectionModel::selectionChanged, this, &WelcomeView::slotRecentFileSelected); } WelcomeView::~WelcomeView() { debugWelcome; } void WelcomeView::setRecentFiles(const QStringList &files) { QStringList lst; for (const QString &s : files) { lst.prepend(s); } m_model->setStringList(lst); widget.recentProjects->resizeColumnToContents(0); } void WelcomeView::updateReadWrite(bool /*readwrite */) { } void WelcomeView::setGuiActive(bool activate) { debugPlan<show(); m_projectdialog->raise(); m_projectdialog->activateWindow(); } } void WelcomeView::slotProjectEditFinished(int result) { qDebug()<(sender()); if (dia == 0) { return; } if (result == QDialog::Accepted) { MacroCommand *cmd = dia->buildCommand(); if (cmd) { cmd->execute(); delete cmd; koDocument()->setModified(true); } emit projectCreated(); emit selectDefaultView(); emit finished(); } dia->deleteLater(); } void WelcomeView::slotCreateResourceFile() { QString file = QStandardPaths::locate(QStandardPaths::AppDataLocation, "templates/.source/SharedResources.plant"); emit openTemplate(QUrl::fromUserInput(file)); emit finished(); } void WelcomeView::slotOpenProject() { if (m_projectdialog) { qWarning()<mimeFilter(KoFilterManager::Import)); filedialog.setHideNameFilterDetailsOption(); QUrl url = QUrl::fromUserInput(filedialog.filename()); if (!url.isEmpty() && mainWindow()->openDocument(url)) { emit finished(); } } } void WelcomeView::slotOpenFileFinished(int result) { KoFileDialog *dia = qobject_cast(sender()); if (dia == 0) { return; } if (result == QDialog::Accepted) { QUrl url = QUrl::fromUserInput(dia->filename()); if (!url.isEmpty() && mainWindow()->openDocument(url)) { emit finished(); } } dia->deleteLater(); } void WelcomeView::slotLoadSharedResources(const QString &file, const QUrl &projects, bool loadProjectsAtStartup) { QUrl url(file); if (url.scheme().isEmpty()) { url.setScheme("file"); } if (url.isValid()) { emit loadSharedResources(url, loadProjectsAtStartup ? projects :QUrl()); } } } // namespace KPlato diff --git a/src/libs/widgets/KoDockWidgetTitleBar.cpp b/src/libs/widgets/KoDockWidgetTitleBar.cpp index 290d0513..75e8123b 100644 --- a/src/libs/widgets/KoDockWidgetTitleBar.cpp +++ b/src/libs/widgets/KoDockWidgetTitleBar.cpp @@ -1,381 +1,381 @@ /* This file is part of the KDE project Copyright (c) 2007 Marijn Kruisselbrink Copyright (C) 2007 Thomas Zander 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 "KoDockWidgetTitleBar.h" #include "KoDockWidgetTitleBar_p.h" #include "KoDockWidgetTitleBarButton.h" #include #include #include #include #include #include #include #include #include #include static inline bool hasFeature(const QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature) { return (dockwidget->features() & feature) == feature; } static QIcon openIcon(QDockWidget *q) { QIcon icon = q->style()->standardIcon(QStyle::SP_TitleBarShadeButton); return icon.isNull() ? koIcon("arrow-down") : icon; } static QIcon closeIcon(QDockWidget *q) { QIcon icon = q->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton); return icon.isNull() ? koIcon("arrow-right") : icon; } KoDockWidgetTitleBar::KoDockWidgetTitleBar(QDockWidget* dockWidget) : QWidget(dockWidget), d(new Private(this)) { QDockWidget *q = dockWidget; d->floatButton = new KoDockWidgetTitleBarButton(this); d->floatButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, 0, q)); - connect(d->floatButton, SIGNAL(clicked()), SLOT(toggleFloating())); + connect(d->floatButton, SIGNAL(clicked()), SLOT(toggleFloating())); // clazy:exclude=old-style-connect d->floatButton->setVisible(true); d->floatButton->setToolTip(i18nc("@info:tooltip", "Float Docker")); d->floatButton->setStyleSheet("border: 0"); d->closeButton = new KoDockWidgetTitleBarButton(this); d->closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, 0, q)); - connect(d->closeButton, SIGNAL(clicked()), q, SLOT(close())); + connect(d->closeButton, &QAbstractButton::clicked, q, &QWidget::close); d->closeButton->setVisible(true); d->closeButton->setToolTip(i18nc("@info:tooltip", "Close Docker")); d->closeButton->setStyleSheet("border: 0"); // border makes the header busy looking (appears on some OSs) d->collapseButton = new KoDockWidgetTitleBarButton(this); d->collapseButton->setIcon(openIcon(q)); - connect(d->collapseButton, SIGNAL(clicked()), SLOT(toggleCollapsed())); + connect(d->collapseButton, SIGNAL(clicked()), SLOT(toggleCollapsed())); // clazy:exclude=old-style-connect d->collapseButton->setVisible(true); d->collapsable = true; d->collapseButton->setToolTip(i18nc("@info:tooltip", "Collapse Docker")); d->collapseButton->setStyleSheet("border: 0"); d->lockButton = new KoDockWidgetTitleBarButton(this); d->lockButton->setCheckable(true); d->lockButton->setIcon(koIcon("object-unlocked")); - connect(d->lockButton, SIGNAL(toggled(bool)), SLOT(setLocked(bool))); + connect(d->lockButton, &QAbstractButton::toggled, this, &KoDockWidgetTitleBar::setLocked); d->lockButton->setVisible(true); d->lockable = true; d->lockButton->setToolTip(i18nc("@info:tooltip", "Lock Docker")); d->lockButton->setStyleSheet("border: 0"); - connect(dockWidget, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), SLOT(featuresChanged(QDockWidget::DockWidgetFeatures))); - connect(dockWidget, SIGNAL(topLevelChanged(bool)), SLOT(topLevelChanged(bool))); + connect(dockWidget, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)), SLOT(featuresChanged(QDockWidget::DockWidgetFeatures))); // clazy:exclude=old-style-connect + connect(dockWidget, SIGNAL(topLevelChanged(bool)), SLOT(topLevelChanged(bool))); // clazy:exclude=old-style-connect d->featuresChanged(0); } KoDockWidgetTitleBar::~KoDockWidgetTitleBar() { delete d; } QSize KoDockWidgetTitleBar::minimumSizeHint() const { return sizeHint(); } QSize KoDockWidgetTitleBar::sizeHint() const { if (isHidden()) { return QSize(0, 0); } QDockWidget *q = qobject_cast(parentWidget()); int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q); int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q); // get size of buttons... QSize closeSize(0, 0); if (d->closeButton && hasFeature(q, QDockWidget::DockWidgetClosable)) { closeSize = d->closeButton->sizeHint(); } QSize floatSize(0, 0); if (d->floatButton && hasFeature(q, QDockWidget::DockWidgetFloatable)) { floatSize = d->floatButton->sizeHint(); } QSize hideSize(0, 0); if (d->collapseButton && d->collapsable) { hideSize = d->collapseButton->sizeHint(); } QSize lockSize(0, 0); if (d->lockButton && d->lockable) { lockSize = d->lockButton->sizeHint(); } int buttonHeight = qMax(qMax(qMax(closeSize.height(), floatSize.height()), hideSize.height()), lockSize.height()) + 2; int buttonWidth = closeSize.width() + floatSize.width() + hideSize.width() + lockSize.width(); int height = buttonHeight; if (d->textVisibilityMode == FullTextAlwaysVisible) { // get font size QFontMetrics titleFontMetrics = q->fontMetrics(); int fontHeight = titleFontMetrics.lineSpacing() + 2 * mw; height = qMax(height, fontHeight); } /* * Calculate the width of title and add to the total width of the docker window when collapsed. */ const int titleWidth = (d->textVisibilityMode == FullTextAlwaysVisible) ? (q->fontMetrics().width(q->windowTitle()) + 2*mw) : 0; if (d->preCollapsedWidth > 0) { return QSize(d->preCollapsedWidth, height); } else { if (d->textVisibilityMode == FullTextAlwaysVisible) { return QSize(buttonWidth /*+ height*/ + 2*mw + 2*fw + titleWidth, height); } else { if (q->widget()) { return QSize(qMin(q->widget()->sizeHint().width(), buttonWidth), height); } else { return QSize(buttonWidth, height); } } } } void KoDockWidgetTitleBar::paintEvent(QPaintEvent*) { QStylePainter p(this); QDockWidget *q = qobject_cast(parentWidget()); int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q) : 0; int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, 0, q); QStyleOptionDockWidget titleOpt; titleOpt.initFrom(q); QSize collapseButtonSize(0,0); if (d->collapsable) { collapseButtonSize = d->collapseButton->size(); } QSize lockButtonSize(0,0); if (d->lockable) { lockButtonSize = d->lockButton->size(); } titleOpt.rect = QRect(QPoint(fw + mw + collapseButtonSize.width() + lockButtonSize.width(), 0), QSize(geometry().width() - (fw * 2) - mw - collapseButtonSize.width() - lockButtonSize.width(), geometry().height())); titleOpt.title = q->windowTitle(); titleOpt.closable = hasFeature(q, QDockWidget::DockWidgetClosable); titleOpt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable); p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt); } void KoDockWidgetTitleBar::resizeEvent(QResizeEvent*) { QDockWidget *q = qobject_cast(parentWidget()); int fw = q->isFloating() ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q) : 0; QStyleOptionDockWidget opt; opt.initFrom(q); opt.rect = QRect(QPoint(fw, fw), QSize(geometry().width() - (fw * 2), geometry().height() - (fw * 2))); opt.title = q->windowTitle(); opt.closable = hasFeature(q, QDockWidget::DockWidgetClosable); opt.floatable = hasFeature(q, QDockWidget::DockWidgetFloatable); QRect floatRect = q->style()->subElementRect(QStyle::SE_DockWidgetFloatButton, &opt, q); if (!floatRect.isNull()) d->floatButton->setGeometry(floatRect); QRect closeRect = q->style()->subElementRect(QStyle::SE_DockWidgetCloseButton, &opt, q); if (!closeRect.isNull()) d->closeButton->setGeometry(closeRect); int top = fw; if (!floatRect.isNull()) top = floatRect.y(); else if (!closeRect.isNull()) top = closeRect.y(); QSize size = d->collapseButton->size(); if (!closeRect.isNull()) { size = d->closeButton->size(); } else if (!floatRect.isNull()) { size = d->floatButton->size(); } QRect collapseRect = QRect(QPoint(fw, top), size); d->collapseButton->setGeometry(collapseRect); size = d->lockButton->size(); if (!closeRect.isNull()) { size = d->closeButton->size(); } else if (!floatRect.isNull()) { size = d->floatButton->size(); } int offset = 0; if (d->collapsable) { offset = collapseRect.width(); } QRect lockRect = QRect(QPoint(fw + 2 + offset, top), size); d->lockButton->setGeometry(lockRect); if (width() < (closeRect.width() + lockRect.width()) + 50) { d->collapsable = false; d->collapseButton->setVisible(false); d->lockButton->setVisible(false); d->lockable = false; } else { d->collapsable = d->collapsableSet; d->collapseButton->setVisible(d->collapsableSet); d->lockButton->setVisible(true); d->lockable = true; } } void KoDockWidgetTitleBar::setCollapsed(bool collapsed) { QDockWidget *q = qobject_cast(parentWidget()); if (q && q->widget() && q->widget()->isHidden() != collapsed) d->toggleCollapsed(); } void KoDockWidgetTitleBar::setLocked(bool locked) { QDockWidget *q = qobject_cast(parentWidget()); d->locked = locked; d->lockButton->blockSignals(true); d->lockButton->setChecked(locked); d->lockButton->blockSignals(false); //qDebug() << "setlocked" << q << d->locked << locked; if (locked) { d->features = q->features(); q->setFeatures(QDockWidget::NoDockWidgetFeatures); } else { q->setFeatures(d->features); } q->toggleViewAction()->setEnabled(!locked); d->closeButton->setEnabled(!locked); d->floatButton->setEnabled(!locked); d->collapseButton->setEnabled(!locked); d->updateIcons(); q->setProperty("Locked", locked); resizeEvent(0); } void KoDockWidgetTitleBar::setCollapsable(bool collapsable) { d->collapsableSet = collapsable; d->collapsable = collapsable; d->collapseButton->setVisible(collapsable); } void KoDockWidgetTitleBar::setTextVisibilityMode(TextVisibilityMode textVisibilityMode) { d->textVisibilityMode = textVisibilityMode; } void KoDockWidgetTitleBar::updateIcons() { d->updateIcons(); } void KoDockWidgetTitleBar::Private::toggleFloating() { QDockWidget *q = qobject_cast(thePublic->parentWidget()); q->setFloating(!q->isFloating()); } void KoDockWidgetTitleBar::Private::topLevelChanged(bool topLevel) { lockButton->setEnabled(!topLevel); } void KoDockWidgetTitleBar::Private::toggleCollapsed() { QDockWidget *q = qobject_cast(thePublic->parentWidget()); if (q == 0) // there does not *have* to be anything on the dockwidget. return; preCollapsedWidth = q->widget()->isHidden() ? -1 : thePublic->width(); q->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // will be overwritten again next if (q->widget()) { q->widget()->setVisible(q->widget()->isHidden()); collapseButton->setIcon(q->widget()->isHidden() ? closeIcon(q) : openIcon(q)); } } void KoDockWidgetTitleBar::Private::featuresChanged(QDockWidget::DockWidgetFeatures) { QDockWidget *q = qobject_cast(thePublic->parentWidget()); closeButton->setVisible(hasFeature(q, QDockWidget::DockWidgetClosable)); floatButton->setVisible(hasFeature(q, QDockWidget::DockWidgetFloatable)); thePublic->resizeEvent(0); } // QT5TODO: this is not yet triggered by theme changes it seems void KoDockWidgetTitleBar::Private::updateIcons() { QDockWidget *q = qobject_cast(thePublic->parentWidget()); lockButton->setIcon((!locked) ? koIcon("object-unlocked") : koIcon("object-locked")); // this method gets called when switching themes, so update all of the themed icons now floatButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, 0, q)); closeButton->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, 0, q)); if (q->widget()) { collapseButton->setIcon(q->widget()->isHidden() ? closeIcon(q) : openIcon(q)); } thePublic->resizeEvent(0); } //have to include this because of Q_PRIVATE_SLOT #include "moc_KoDockWidgetTitleBar.cpp" diff --git a/src/libs/widgets/KoDocumentInfoDlg.cpp b/src/libs/widgets/KoDocumentInfoDlg.cpp index 55e2c327..16dbf6dd 100644 --- a/src/libs/widgets/KoDocumentInfoDlg.cpp +++ b/src/libs/widgets/KoDocumentInfoDlg.cpp @@ -1,478 +1,478 @@ /* This file is part of the KDE project Copyright (c) 2000 Simon Hausmann 2006 Martin Pfeiffer 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 "KoDocumentInfoDlg.h" #include "ui_koDocumentInfoAboutWidget.h" #include "ui_koDocumentInfoAuthorWidget.h" #include "KoDocumentInfo.h" #include "KoDocumentBase.h" #include "KoGlobal.h" #ifdef QCA2 #include #endif #include "KoPageWidgetItem.h" //#include #include #include #include #include #include #include #include #include #include #include #include // see KoIcon.h #define koSmallIcon(name) (SmallIcon(QStringLiteral(name))) class KoPageWidgetItemAdapter : public KPageWidgetItem { Q_OBJECT public: KoPageWidgetItemAdapter(KoPageWidgetItem *item) : KPageWidgetItem(item->widget(), item->name()) , m_item(item) { setHeader(item->name()); setIcon(QIcon::fromTheme(item->iconName())); } ~KoPageWidgetItemAdapter() { delete m_item; } bool shouldDialogCloseBeVetoed() { return m_item->shouldDialogCloseBeVetoed(); } void apply() { m_item->apply(); } private: KoPageWidgetItem * const m_item; }; class KoDocumentInfoDlg::KoDocumentInfoDlgPrivate { public: KoDocumentInfoDlgPrivate() : toggleEncryption(false), applyToggleEncryption(false), documentSaved(false) {} ~KoDocumentInfoDlgPrivate() {} KoDocumentInfo* info; QList pages; Ui::KoDocumentInfoAboutWidget* aboutUi; Ui::KoDocumentInfoAuthorWidget* authorUi; bool toggleEncryption; bool applyToggleEncryption; bool documentSaved; }; KoDocumentInfoDlg::KoDocumentInfoDlg(QWidget* parent, KoDocumentInfo* docInfo) : KPageDialog(parent) , d(new KoDocumentInfoDlgPrivate) { d->info = docInfo; setWindowTitle(i18n("Document Information")); // setInitialSize(QSize(500, 500)); setFaceType(KPageDialog::List); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); button(QDialogButtonBox::Ok)->setDefault(true); d->aboutUi = new Ui::KoDocumentInfoAboutWidget(); QWidget *infodlg = new QWidget(); d->aboutUi->setupUi(infodlg); #ifdef QCA2 if (!KoEncryptionChecker::isEncryptionSupported()) { #endif d->aboutUi->lblEncryptedDesc->setVisible(false); d->aboutUi->lblEncrypted->setVisible(false); d->aboutUi->pbEncrypt->setVisible(false); d->aboutUi->lblEncryptedPic->setVisible(false); #ifdef QCA2 } #endif d->aboutUi->cbLanguage->addItems(KoGlobal::listOfLanguages()); d->aboutUi->cbLanguage->setCurrentIndex(-1); KPageWidgetItem *page = new KPageWidgetItem(infodlg, i18n("General")); page->setHeader(i18n("General")); // Ugly hack, the mimetype should be a parameter, instead KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent()); if (doc) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(doc->mimeType()); if (mime.isValid()) { page->setIcon(QIcon::fromTheme(mime.iconName())); } } else { // hide all entries not used in pages for KoDocumentInfoPropsPage d->aboutUi->filePathInfoLabel->setVisible(false); d->aboutUi->filePathLabel->setVisible(false); d->aboutUi->filePathSeparatorLine->setVisible(false); d->aboutUi->lblTypeDesc->setVisible(false); d->aboutUi->lblType->setVisible(false); } addPage(page); d->pages.append(page); initAboutTab(); d->authorUi = new Ui::KoDocumentInfoAuthorWidget(); QWidget *authordlg = new QWidget(); d->authorUi->setupUi(authordlg); page = new KPageWidgetItem(authordlg, i18n("Author")); page->setHeader(i18n("Last saved by")); page->setIcon(koIcon("user-identity")); addPage(page); d->pages.append(page); initAuthorTab(); } KoDocumentInfoDlg::~KoDocumentInfoDlg() { delete d->authorUi; delete d->aboutUi; delete d; } void KoDocumentInfoDlg::accept() { // check if any pages veto the close foreach(KPageWidgetItem* item, d->pages) { KoPageWidgetItemAdapter *page = dynamic_cast(item); if (page) { if (page->shouldDialogCloseBeVetoed()) { return; } } } // all fine, go and apply saveAboutData(); foreach(KPageWidgetItem* item, d->pages) { KoPageWidgetItemAdapter *page = dynamic_cast(item); if (page) { page->apply(); } } KPageDialog::accept(); } bool KoDocumentInfoDlg::isDocumentSaved() { return d->documentSaved; } void KoDocumentInfoDlg::initAboutTab() { KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent()); if (doc) { d->aboutUi->filePathLabel->setText(doc->localFilePath()); } d->aboutUi->leTitle->setText(d->info->aboutInfo("title")); d->aboutUi->leSubject->setText(d->info->aboutInfo("subject")); QString language = KoGlobal::languageFromTag(d->info->aboutInfo("language")); d->aboutUi->cbLanguage->setCurrentIndex(d->aboutUi->cbLanguage->findText(language)); d->aboutUi->leKeywords->setToolTip(i18n("Use ';' (Example: Office;KDE;Calligra)")); if (!d->info->aboutInfo("keyword").isEmpty()) d->aboutUi->leKeywords->setText(d->info->aboutInfo("keyword")); d->aboutUi->meComments->setPlainText(d->info->aboutInfo("description")); if (doc && !doc->mimeType().isEmpty()) { QMimeDatabase db; QMimeType docmime = db.mimeTypeForName(doc->mimeType()); if (docmime.isValid()) d->aboutUi->lblType->setText(docmime.comment()); } if (!d->info->aboutInfo("creation-date").isEmpty()) { QDateTime t = QDateTime::fromString(d->info->aboutInfo("creation-date"), Qt::ISODate); QString s = QLocale().toString(t); d->aboutUi->lblCreated->setText(s + ", " + d->info->aboutInfo("initial-creator")); } if (!d->info->aboutInfo("date").isEmpty()) { QDateTime t = QDateTime::fromString(d->info->aboutInfo("date"), Qt::ISODate); QString s = QLocale().toString(t); d->aboutUi->lblModified->setText(s + ", " + d->info->authorInfo("creator")); } d->aboutUi->lblRevision->setText(d->info->aboutInfo("editing-cycles")); if (doc && (doc->supportedSpecialFormats() & KoDocumentBase::SaveEncrypted)) { if (doc->specialOutputFlag() == KoDocumentBase::SaveEncrypted) { if (d->toggleEncryption) { d->aboutUi->lblEncrypted->setText(i18n("This document will be decrypted")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked")); d->aboutUi->pbEncrypt->setText(i18n("Do not decrypt")); } else { d->aboutUi->lblEncrypted->setText(i18n("This document is encrypted")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked")); d->aboutUi->pbEncrypt->setText(i18n("D&ecrypt")); } } else { if (d->toggleEncryption) { d->aboutUi->lblEncrypted->setText(i18n("This document will be encrypted.")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked")); d->aboutUi->pbEncrypt->setText(i18n("Do not encrypt")); } else { d->aboutUi->lblEncrypted->setText(i18n("This document is not encrypted")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked")); d->aboutUi->pbEncrypt->setText(i18n("&Encrypt")); } } } else { d->aboutUi->lblEncrypted->setText(i18n("This document does not support encryption")); d->aboutUi->pbEncrypt->setEnabled( false ); } - connect(d->aboutUi->pbReset, SIGNAL(clicked()), - this, SLOT(slotResetMetaData())); - connect(d->aboutUi->pbEncrypt, SIGNAL(clicked()), - this, SLOT(slotToggleEncryption())); + connect(d->aboutUi->pbReset, &QAbstractButton::clicked, + this, &KoDocumentInfoDlg::slotResetMetaData); + connect(d->aboutUi->pbEncrypt, &QAbstractButton::clicked, + this, &KoDocumentInfoDlg::slotToggleEncryption); } void KoDocumentInfoDlg::initAuthorTab() { d->authorUi->fullName->setText(d->info->authorInfo("creator")); d->authorUi->initials->setText(d->info->authorInfo("initial")); d->authorUi->title->setText(d->info->authorInfo("author-title")); d->authorUi->company->setText(d->info->authorInfo("company")); d->authorUi->email->setText(d->info->authorInfo("email")); d->authorUi->phoneWork->setText(d->info->authorInfo("telephone-work")); d->authorUi->phoneHome->setText(d->info->authorInfo("telephone")); d->authorUi->fax->setText(d->info->authorInfo("fax")); d->authorUi->country->setText(d->info->authorInfo("country")); d->authorUi->postal->setText(d->info->authorInfo("postal-code")); d->authorUi->city->setText(d->info->authorInfo("city")); d->authorUi->street->setText(d->info->authorInfo("street")); d->authorUi->position->setText(d->info->authorInfo("position")); } void KoDocumentInfoDlg::saveAboutData() { d->info->setAboutInfo("keyword", d->aboutUi->leKeywords->text()); d->info->setAboutInfo("title", d->aboutUi->leTitle->text()); d->info->setAboutInfo("subject", d->aboutUi->leSubject->text()); d->info->setAboutInfo("description", d->aboutUi->meComments->toPlainText()); d->info->setAboutInfo("language", KoGlobal::tagOfLanguage(d->aboutUi->cbLanguage->currentText())); d->applyToggleEncryption = d->toggleEncryption; } void KoDocumentInfoDlg::hideEvent( QHideEvent *event ) { Q_UNUSED(event); // Saving encryption implies saving the document, this is done after closing the dialog // TODO: shouldn't this be skipped if cancel is pressed? saveEncryption(); } void KoDocumentInfoDlg::slotResetMetaData() { d->info->resetMetaData(); if (!d->info->aboutInfo("creation-date").isEmpty()) { QDateTime t = QDateTime::fromString(d->info->aboutInfo("creation-date"), Qt::ISODate); QString s = QLocale().toString(t); d->aboutUi->lblCreated->setText(s + ", " + d->info->aboutInfo("initial-creator")); } if (!d->info->aboutInfo("date").isEmpty()) { QDateTime t = QDateTime::fromString(d->info->aboutInfo("date"), Qt::ISODate); QString s = QLocale().toString(t); d->aboutUi->lblModified->setText(s + ", " + d->info->authorInfo("creator")); } d->aboutUi->lblRevision->setText(d->info->aboutInfo("editing-cycles")); } void KoDocumentInfoDlg::slotToggleEncryption() { KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent()); if (!doc) return; d->toggleEncryption = !d->toggleEncryption; if (doc->specialOutputFlag() == KoDocumentBase::SaveEncrypted) { if (d->toggleEncryption) { d->aboutUi->lblEncrypted->setText(i18n("This document will be decrypted")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked")); d->aboutUi->pbEncrypt->setText(i18n("Do not decrypt")); } else { d->aboutUi->lblEncrypted->setText(i18n("This document is encrypted")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked")); d->aboutUi->pbEncrypt->setText(i18n("D&ecrypt")); } } else { if (d->toggleEncryption) { d->aboutUi->lblEncrypted->setText(i18n("This document will be encrypted.")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-locked")); d->aboutUi->pbEncrypt->setText(i18n("Do not encrypt")); } else { d->aboutUi->lblEncrypted->setText(i18n("This document is not encrypted")); d->aboutUi->lblEncryptedPic->setPixmap(koSmallIcon("object-unlocked")); d->aboutUi->pbEncrypt->setText(i18n("&Encrypt")); } } } void KoDocumentInfoDlg::saveEncryption() { if (!d->applyToggleEncryption) return; KoDocumentBase* doc = dynamic_cast< KoDocumentBase* >(d->info->parent()); if (!doc) return; KMainWindow* mainWindow = dynamic_cast< KMainWindow* >(parent()); if (doc->specialOutputFlag() == KoDocumentBase::SaveEncrypted) { // Decrypt if (KMessageBox::warningContinueCancel( this, i18n("Decrypting the document will remove the password protection from it." "

Do you still want to decrypt the file?"), i18n("Confirm Decrypt"), KGuiItem(i18n("Decrypt")), KStandardGuiItem::cancel(), "DecryptConfirmation" ) != KMessageBox::Continue) { return; } bool modified = doc->isModified(); doc->setOutputMimeType(doc->outputMimeType(), doc->specialOutputFlag() & ~KoDocumentBase::SaveEncrypted); if (!mainWindow) { KMessageBox::information( this, i18n("Your document could not be saved automatically." "

To complete the decryption, please save the document."), i18n("Save Document"), "DecryptSaveMessage"); return; } if (modified && KMessageBox::questionYesNo( this, i18n("The document has been changed since it was opened. To complete the decryption the document needs to be saved." "

Do you want to save the document now?"), i18n("Save Document"), KStandardGuiItem::save(), KStandardGuiItem::dontSave(), "DecryptSaveConfirmation" ) != KMessageBox::Yes) { return; } } else { // Encrypt bool modified = doc->isModified(); if (!doc->url().isEmpty() && !(doc->mimeType().startsWith("application/vnd.oasis.opendocument.") && doc->specialOutputFlag() == 0)) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(doc->mimeType()); QString comment = mime.isValid() ? mime.comment() : i18n("%1 (unknown file type)", QString::fromLatin1(doc->mimeType())); if (KMessageBox::warningContinueCancel( this, i18n("The document is currently saved as %1. The document needs to be changed to OASIS OpenDocument to be encrypted." "

Do you want to change the file to OASIS OpenDocument?", QString("%1").arg(comment)), i18n("Change Filetype"), KGuiItem(i18n("Change")), KStandardGuiItem::cancel(), "EncryptChangeFiletypeConfirmation" ) != KMessageBox::Continue) { return; } doc->resetURL(); } doc->setMimeType(doc->nativeOasisMimeType()); doc->setOutputMimeType(doc->nativeOasisMimeType(), KoDocumentBase::SaveEncrypted); if (!mainWindow) { KMessageBox::information( this, i18n("Your document could not be saved automatically." "

To complete the encryption, please save the document."), i18n("Save Document"), "EncryptSaveMessage"); return; } if (modified && KMessageBox::questionYesNo( this, i18n("The document has been changed since it was opened. To complete the encryption the document needs to be saved." "

Do you want to save the document now?"), i18n("Save Document"), KStandardGuiItem::save(), KStandardGuiItem::dontSave(), "EncryptSaveConfirmation" ) != KMessageBox::Yes) { return; } } // Why do the dirty work ourselves? emit saveRequested(); d->toggleEncryption = false; d->applyToggleEncryption = false; // Detects when the user cancelled saving d->documentSaved = !doc->url().isEmpty(); } QList KoDocumentInfoDlg::pages() const { return d->pages; } void KoDocumentInfoDlg::setReadOnly(bool ro) { d->aboutUi->meComments->setReadOnly(ro); Q_FOREACH(KPageWidgetItem* page, d->pages) { Q_FOREACH(QLineEdit* le, page->widget()->findChildren()) { le->setReadOnly(ro); } Q_FOREACH(QPushButton* le, page->widget()->findChildren()) { le->setDisabled(ro); } } } void KoDocumentInfoDlg::addPageItem(KoPageWidgetItem *item) { KPageWidgetItem * page = new KoPageWidgetItemAdapter(item); addPage(page); d->pages.append(page); } #include "KoDocumentInfoDlg.moc" diff --git a/src/libs/widgets/KoPageLayoutDialog.cpp b/src/libs/widgets/KoPageLayoutDialog.cpp index 21a312fe..7aa1bad0 100644 --- a/src/libs/widgets/KoPageLayoutDialog.cpp +++ b/src/libs/widgets/KoPageLayoutDialog.cpp @@ -1,157 +1,157 @@ /* This file is part of the KDE project * Copyright (C) 2007,2010 Thomas Zander * * 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 "KoPageLayoutDialog.h" #include "KoPageLayoutWidget.h" #include "KoPagePreviewWidget.h" #include #include #include #include #include #include class Q_DECL_HIDDEN KoPageLayoutDialog::Private { public: Private() : pageLayoutWidget(0), documentCheckBox(0) {} KoPageLayoutWidget *pageLayoutWidget; QCheckBox *documentCheckBox; }; KoPageLayoutDialog::KoPageLayoutDialog(QWidget *parent, const KoPageLayout &layout) : KPageDialog(parent) , d(new Private) { setWindowTitle(i18n("Page Layout")); setFaceType(KPageDialog::Tabbed); QWidget *widget = new QWidget(this); addPage(widget, i18n("Page")); QHBoxLayout *lay = new QHBoxLayout(widget); d->pageLayoutWidget = new KoPageLayoutWidget(widget, layout); d->pageLayoutWidget->showUnitchooser(false); lay->addWidget(d->pageLayoutWidget,1); KoPagePreviewWidget *prev = new KoPagePreviewWidget(widget); // use not original layout, but "fixed" one (e.g. with 0 values) as now hold by pageLayoutWidget prev->setPageLayout(d->pageLayoutWidget->pageLayout()); lay->addWidget(prev, 1); - connect (d->pageLayoutWidget, SIGNAL(layoutChanged(KoPageLayout)), - prev, SLOT(setPageLayout(KoPageLayout))); - connect (d->pageLayoutWidget, SIGNAL(layoutChanged(KoPageLayout)), - this, SLOT(setPageLayout(KoPageLayout))); - connect (d->pageLayoutWidget, SIGNAL(unitChanged(KoUnit)), - this, SIGNAL(unitChanged(KoUnit))); + connect (d->pageLayoutWidget, &KoPageLayoutWidget::layoutChanged, + prev, &KoPagePreviewWidget::setPageLayout); + connect (d->pageLayoutWidget, &KoPageLayoutWidget::layoutChanged, + this, &KoPageLayoutDialog::setPageLayout); + connect (d->pageLayoutWidget, &KoPageLayoutWidget::unitChanged, + this, &KoPageLayoutDialog::unitChanged); } KoPageLayoutDialog::~KoPageLayoutDialog() { delete d; } KoPageLayout KoPageLayoutDialog::pageLayout() const { return d->pageLayoutWidget->pageLayout(); } void KoPageLayoutDialog::setPageLayout(const KoPageLayout &layout) { d->pageLayoutWidget->setPageLayout(layout); } void KoPageLayoutDialog::accept() { KPageDialog::accept(); deleteLater(); } void KoPageLayoutDialog::reject() { KPageDialog::reject(); deleteLater(); } bool KoPageLayoutDialog::applyToDocument() const { return d->documentCheckBox && d->documentCheckBox->isChecked(); } void KoPageLayoutDialog::showApplyToDocument(bool on) { if (on && d->documentCheckBox == 0) { for (int i = 0; i < children().count(); ++i) { if (QDialogButtonBox *buttonBox = qobject_cast(children()[i])) { d->documentCheckBox = new QCheckBox(i18n("Apply to document"), buttonBox); d->documentCheckBox->setChecked(true); buttonBox->addButton(d->documentCheckBox, QDialogButtonBox::ResetRole); break; } } Q_ASSERT(d->pageLayoutWidget); - connect (d->documentCheckBox, SIGNAL(toggled(bool)), - d->pageLayoutWidget, SLOT(setApplyToDocument(bool))); + connect (d->documentCheckBox, &QAbstractButton::toggled, + d->pageLayoutWidget, &KoPageLayoutWidget::setApplyToDocument); } else if (d->documentCheckBox) { d->documentCheckBox->setVisible(on); } } /* void KoPageLayoutDialog::showTextDirection(bool on) { d->pageLayoutWidget->showTextDirection(on); } KoText::Direction KoPageLayoutDialog::textDirection() const { return d->pageLayoutWidget->textDirection(); } void KoPageLayoutDialog::setTextDirection(KoText::Direction direction) { d->pageLayoutWidget->setTextDirection(direction); } */ void KoPageLayoutDialog::showPageSpread(bool on) { d->pageLayoutWidget->showPageSpread(on); } void KoPageLayoutDialog::setPageSpread(bool pageSpread) { d->pageLayoutWidget->setPageSpread(pageSpread); } void KoPageLayoutDialog::showUnitchooser(bool on) { d->pageLayoutWidget->showUnitchooser(on); } /* void KoPageLayoutDialog::setUnit(const KoUnit &unit) { d->pageLayoutWidget->setUnit(unit); } */ diff --git a/src/libs/widgets/KoPageLayoutDialog.h b/src/libs/widgets/KoPageLayoutDialog.h index 1cd44920..0618e38c 100644 --- a/src/libs/widgets/KoPageLayoutDialog.h +++ b/src/libs/widgets/KoPageLayoutDialog.h @@ -1,66 +1,67 @@ /* This file is part of the KDE project * Copyright (C) 2007 Thomas Zander * * 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. */ #ifndef KO_PAGE_LAYOUT_DIALOG #define KO_PAGE_LAYOUT_DIALOG #include "kowidgets_export.h" //#include +#include #include struct KoPageLayout; /// A dialog to show the settings for one page and apply them afterwards. class KOWIDGETS_EXPORT KoPageLayoutDialog : public KPageDialog { Q_OBJECT public: explicit KoPageLayoutDialog(QWidget *parent, const KoPageLayout &layout); ~KoPageLayoutDialog(); void showTextDirection(bool on); // KoText::Direction textDirection() const; // void setTextDirection(KoText::Direction direction); void showPageSpread(bool on); void setPageSpread(bool pageSpread); KoPageLayout pageLayout() const; bool applyToDocument() const; void showApplyToDocument(bool on); void showUnitchooser(bool on); // void setUnit(const KoUnit &unit); Q_SIGNALS: - //void unitChanged(const KoUnit &unit); + void unitChanged(const KoUnit &unit); public Q_SLOTS: void setPageLayout(const KoPageLayout &layout); protected Q_SLOTS: void accept(); void reject(); private: class Private; Private * const d; }; #endif diff --git a/src/libs/widgets/KoPageLayoutWidget.cpp b/src/libs/widgets/KoPageLayoutWidget.cpp index b67e9848..2d8790c1 100644 --- a/src/libs/widgets/KoPageLayoutWidget.cpp +++ b/src/libs/widgets/KoPageLayoutWidget.cpp @@ -1,350 +1,350 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2010 Thomas Zander * * 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 "KoPageLayoutWidget.h" #include #include #include class Q_DECL_HIDDEN KoPageLayoutWidget::Private { public: Ui::KoPageLayoutWidget widget; KoPageLayout pageLayout; KoUnit unit; QButtonGroup *orientationGroup; bool marginsEnabled; bool allowSignals; }; KoPageLayoutWidget::KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout) : QWidget(parent) , d(new Private) { d->widget.setupUi(this); d->pageLayout = layout; d->marginsEnabled = true; d->allowSignals = true; d->orientationGroup = new QButtonGroup(this); d->orientationGroup->addButton(d->widget.portrait, KoPageFormat::Portrait); d->orientationGroup->addButton(d->widget.landscape, KoPageFormat::Landscape); QButtonGroup *group2 = new QButtonGroup(this); group2->addButton(d->widget.singleSided); group2->addButton(d->widget.facingPages); // the two sets of labels we use might have different lengths; make sure this does not create a 'jumping' ui d->widget.facingPages->setChecked(true); facingPagesChanged(); int width = qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width()); d->widget.singleSided->setChecked(true); facingPagesChanged(); width = qMax(width, qMax(d->widget.leftLabel->width(), d->widget.rightLabel->width())); d->widget.leftLabel->setMinimumSize(QSize(width, 5)); d->widget.units->addItems(KoUnit::listOfUnitNameForUi(KoUnit::HidePixel)); d->widget.sizes->addItems(KoPageFormat::localizedPageFormatNames()); setPageSpread(false); - connect(d->widget.sizes, SIGNAL(currentIndexChanged(int)), this, SLOT(sizeChanged(int))); - connect(d->widget.units, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int))); - connect(group2, SIGNAL(buttonClicked(int)), this, SLOT(facingPagesChanged())); - connect(d->orientationGroup, SIGNAL(buttonClicked(int)), this, SLOT(orientationChanged())); - connect(d->widget.width, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - connect(d->widget.height, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - connect(d->widget.topMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.bottomMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.bindingEdgeMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.pageEdgeMargin, SIGNAL(valueChangedPt(qreal)), this, SLOT(marginsChanged())); - connect(d->widget.width, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); - connect(d->widget.height, SIGNAL(valueChangedPt(qreal)), this, SLOT(optionsChanged())); + connect(d->widget.sizes, static_cast(&QComboBox::currentIndexChanged), this, &KoPageLayoutWidget::sizeChanged); + connect(d->widget.units, static_cast(&QComboBox::currentIndexChanged), this, &KoPageLayoutWidget::slotUnitChanged); + connect(group2, static_cast(&QButtonGroup::buttonClicked), this, &KoPageLayoutWidget::facingPagesChanged); + connect(d->orientationGroup, static_cast(&QButtonGroup::buttonClicked), this, &KoPageLayoutWidget::orientationChanged); + connect(d->widget.width, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged); + connect(d->widget.height, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged); + connect(d->widget.topMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged); + connect(d->widget.bottomMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged); + connect(d->widget.bindingEdgeMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged); + connect(d->widget.pageEdgeMargin, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::marginsChanged); + connect(d->widget.width, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged); + connect(d->widget.height, &KoUnitDoubleSpinBox::valueChangedPt, this, &KoPageLayoutWidget::optionsChanged); setUnit(KoUnit(KoUnit::Millimeter)); setPageLayout(layout); if (layout.format == 0) // make sure we always call this during startup, even if the A3 (index=0) was chosen sizeChanged(layout.format); showTextDirection(false); /* disable advanced page layout features by default */ d->widget.facingPageLabel->setVisible(false); d->widget.facingPages->setVisible(false); d->widget.singleSided->setVisible(false); d->widget.stylesLabel->setVisible(false); d->widget.pageStyle->setVisible(false); } KoPageLayoutWidget::~KoPageLayoutWidget() { delete d; } KoPageLayout KoPageLayoutWidget::pageLayout() const { return d->pageLayout; } void KoPageLayoutWidget::sizeChanged(int row) { if (row < 0) return; if (! d->allowSignals) return; d->allowSignals = false; d->pageLayout.format = static_cast (row); bool custom = d->pageLayout.format == KoPageFormat::CustomSize; d->widget.width->setEnabled( custom ); d->widget.height->setEnabled( custom ); if ( !custom ) { d->pageLayout.width = MM_TO_POINT( KoPageFormat::width( d->pageLayout.format, d->pageLayout.orientation ) ); d->pageLayout.height = MM_TO_POINT( KoPageFormat::height( d->pageLayout.format, d->pageLayout.orientation ) ); if (d->widget.facingPages->isChecked()) // is pagespread d->pageLayout.width *= 2; } d->widget.width->changeValue( d->pageLayout.width ); d->widget.height->changeValue( d->pageLayout.height ); emit layoutChanged(d->pageLayout); d->allowSignals = true; } -void KoPageLayoutWidget::unitChanged(int row) +void KoPageLayoutWidget::slotUnitChanged(int row) { setUnit(KoUnit::fromListForUi(row, KoUnit::HidePixel)); } void KoPageLayoutWidget::setUnit(const KoUnit &unit) { if (d->unit == unit) return; d->unit = unit; d->widget.width->setUnit(unit); d->widget.height->setUnit(unit); d->widget.topMargin->setUnit(unit); d->widget.bottomMargin->setUnit(unit); d->widget.bindingEdgeMargin->setUnit(unit); d->widget.pageEdgeMargin->setUnit(unit); d->widget.units->setCurrentIndex(unit.indexInListForUi(KoUnit::HidePixel)); emit unitChanged(d->unit); } void KoPageLayoutWidget::setPageLayout(const KoPageLayout &layout) { if (! d->allowSignals) return; d->allowSignals = false; d->pageLayout = layout; Q_ASSERT(d->orientationGroup->button( layout.orientation )); d->orientationGroup->button( layout.orientation )->setChecked( true ); if (layout.bindingSide >= 0 && layout.pageEdge >= 0) { d->widget.facingPages->setChecked(true); d->widget.bindingEdgeMargin->changeValue(layout.bindingSide); d->widget.pageEdgeMargin->changeValue(layout.pageEdge); d->pageLayout.leftMargin = -1; d->pageLayout.rightMargin = -1; } else { d->widget.singleSided->setChecked(true); d->widget.bindingEdgeMargin->changeValue(layout.leftMargin); d->widget.pageEdgeMargin->changeValue(layout.rightMargin); d->pageLayout.pageEdge = -1; d->pageLayout.bindingSide = -1; } facingPagesChanged(); d->widget.topMargin->changeValue(layout.topMargin); d->widget.bottomMargin->changeValue(layout.bottomMargin); d->allowSignals = true; d->widget.sizes->setCurrentIndex(layout.format); // calls sizeChanged() } void KoPageLayoutWidget::facingPagesChanged() { if (! d->allowSignals) return; d->allowSignals = false; if (d->widget.singleSided->isChecked()) { d->widget.leftLabel->setText(i18n("Left Edge:")); d->widget.rightLabel->setText(i18n("Right Edge:")); } else { d->widget.leftLabel->setText(i18n("Binding Edge:")); d->widget.rightLabel->setText(i18n("Page Edge:")); } d->allowSignals = true; marginsChanged(); sizeChanged(d->widget.sizes->currentIndex()); } void KoPageLayoutWidget::marginsChanged() { if (! d->allowSignals) return; d->allowSignals = false; d->pageLayout.leftMargin = -1; d->pageLayout.rightMargin = -1; d->pageLayout.bindingSide = -1; d->pageLayout.pageEdge = -1; d->pageLayout.topMargin = d->marginsEnabled?d->widget.topMargin->value():0; d->pageLayout.bottomMargin = d->marginsEnabled?d->widget.bottomMargin->value():0; qreal left = d->marginsEnabled?d->widget.bindingEdgeMargin->value():0; qreal right = d->marginsEnabled?d->widget.pageEdgeMargin->value():0; if (left + right > d->pageLayout.width - 10) { // make sure the actual text area is never smaller than 10 points. qreal diff = d->pageLayout.width - 10 - left - right; left = qMin(d->pageLayout.width - 10, qMax(qreal(0.0), left - diff / qreal(2.0))); right = qMax(qreal(0.0), right - d->pageLayout.width - 10 - left); } if (d->widget.singleSided->isChecked()) { d->pageLayout.leftMargin = left; d->pageLayout.rightMargin = right; } else { d->pageLayout.bindingSide = left; d->pageLayout.pageEdge = right; } // debugWidgets << " " << d->pageLayout.left <<"|"<< d->pageLayout.bindingSide << "," << // d->pageLayout.right << "|"<< d->pageLayout.pageEdge; emit layoutChanged(d->pageLayout); d->allowSignals = true; } void KoPageLayoutWidget::setTextAreaAvailable(bool available) { d->marginsEnabled = available; d->widget.margins->setEnabled(available); marginsChanged(); } void KoPageLayoutWidget::optionsChanged() { if (! d->allowSignals) return; if (d->widget.sizes->currentIndex() == KoPageFormat::CustomSize) { d->pageLayout.width = d->widget.width->value(); d->pageLayout.height = d->widget.height->value(); } else sizeChanged(d->widget.sizes->currentIndex()); marginsChanged(); } void KoPageLayoutWidget::orientationChanged() { if (! d->allowSignals) return; d->allowSignals = false; d->pageLayout.orientation = d->widget.landscape->isChecked() ? KoPageFormat::Landscape : KoPageFormat::Portrait; qreal x = d->widget.height->value(); d->widget.height->changeValue( d->widget.width->value() ); d->widget.width->changeValue( x ); d->allowSignals = true; optionsChanged(); } void KoPageLayoutWidget::showUnitchooser(bool on) { d->widget.units->setVisible(on); d->widget.unitsLabel->setVisible(on); } void KoPageLayoutWidget::showPageSpread(bool on) { d->widget.facingPageLabel->setVisible(on); d->widget.singleSided->setVisible(on); d->widget.facingPages->setVisible(on); } void KoPageLayoutWidget::setPageSpread(bool pageSpread) { if (pageSpread) d->widget.facingPages->setChecked(true); else d->widget.singleSided->setChecked(true); } void KoPageLayoutWidget::setApplyToDocument(bool apply) { if (apply) { d->widget.facingPageLabel->setText(i18n("Facing Pages:")); d->widget.facingPages->setText(i18n("Facing pages")); } else { d->widget.facingPageLabel->setText(i18n("Page Layout:")); d->widget.facingPages->setText(i18n("Page spread")); } } void KoPageLayoutWidget::showTextDirection(bool on) { d->widget.directionLabel->setVisible(on); d->widget.textDirection->setVisible(on); } /* void KoPageLayoutWidget::setTextDirection(KoText::Direction direction ) { int index = 0; switch(direction) { case KoText::LeftRightTopBottom: index = 1; break; case KoText::RightLeftTopBottom: index = 2; break; case KoText::TopBottomRightLeft: // unused for now. case KoText::InheritDirection: case KoText::AutoDirection: index = 0; case KoText::TopBottomLeftRight: ; // unhandled, because it actually doesn't exist in real-world writing systems. // Boustrophedon would be interesting to implement, though } d->widget.textDirection->setCurrentIndex(index); } KoText::Direction KoPageLayoutWidget::textDirection() const { switch(d->widget.textDirection->currentIndex()) { case 1: return KoText::LeftRightTopBottom; case 2: return KoText::RightLeftTopBottom; default: case 0: return KoText::AutoDirection; } } */ void KoPageLayoutWidget::showPageStyles(bool on) { d->widget.stylesLabel->setVisible(on); d->widget.pageStyle->setVisible(on); } void KoPageLayoutWidget::setPageStyles(const QStringList &styles) { d->widget.pageStyle->clear(); d->widget.pageStyle->addItems(styles); } QString KoPageLayoutWidget::currentPageStyle() const { return d->widget.pageStyle->currentText(); } diff --git a/src/libs/widgets/KoPageLayoutWidget.h b/src/libs/widgets/KoPageLayoutWidget.h index 3217036d..3f7d6048 100644 --- a/src/libs/widgets/KoPageLayoutWidget.h +++ b/src/libs/widgets/KoPageLayoutWidget.h @@ -1,75 +1,75 @@ /* This file is part of the KDE project * Copyright (C) 2007, 2010 Thomas Zander * * 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. */ #ifndef KO_PAGE_LAYOUT_WIDGET #define KO_PAGE_LAYOUT_WIDGET #include "kowidgets_export.h" //#include #include #include class KoUnit; /// the widget that shows the size/margins and other page settings. class KOWIDGETS_EXPORT KoPageLayoutWidget : public QWidget { Q_OBJECT public: KoPageLayoutWidget(QWidget *parent, const KoPageLayout &layout); ~KoPageLayoutWidget(); KoPageLayout pageLayout() const; void setUnit(const KoUnit &unit); void showUnitchooser(bool on); void showPageSpread(bool on); void showPageStyles(bool on); void setPageStyles(const QStringList &styles); QString currentPageStyle() const; void setPageSpread(bool pageSpread); void showTextDirection(bool on); // void setTextDirection(KoText::Direction direction); // KoText::Direction textDirection() const; Q_SIGNALS: void layoutChanged(const KoPageLayout &layout); void unitChanged(const KoUnit &unit); public Q_SLOTS: void setPageLayout(const KoPageLayout &layout); void setTextAreaAvailable(bool available); + void setApplyToDocument(bool apply); private Q_SLOTS: void sizeChanged(int row); - void unitChanged(int row); + void slotUnitChanged(int row); void facingPagesChanged(); void optionsChanged(); void marginsChanged(); void orientationChanged(); - void setApplyToDocument(bool apply); private: class Private; Private * const d; }; #endif diff --git a/src/libs/widgetutils/KoFileDialog.cpp b/src/libs/widgetutils/KoFileDialog.cpp index a8fbbff7..dcf11ead 100644 --- a/src/libs/widgetutils/KoFileDialog.cpp +++ b/src/libs/widgetutils/KoFileDialog.cpp @@ -1,525 +1,525 @@ /* This file is part of the KDE project Copyright (C) 2013 - 2014 Yue Liu 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 "KoFileDialog.h" #include #include #include #include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KoFileDialog::Private { public: Private(QWidget *parent_, KoFileDialog::DialogType dialogType_, const QString caption_, const QString defaultDir_, const QString dialogName_) : parent(parent_) , type(dialogType_) , dialogName(dialogName_) , caption(caption_) , defaultDirectory(defaultDir_) , filterList(QStringList()) , defaultFilter(QString()) , useStaticForNative(false) , hideDetails(false) , swapExtensionOrder(false) { // Force the native file dialogs on Windows. Except for KDE, the native file dialogs are only possible // using the static methods. The Qt documentation is wrong here, if it means what it says " By default, // the native file dialog is used unless you use a subclass of QFileDialog that contains the Q_OBJECT // macro." #ifdef Q_OS_WIN useStaticForNative = true; #endif // Non-static KDE file is broken when called with QFileDialog::AcceptSave: // then the directory above defaultdir is opened, and defaultdir is given as the default file name... // // So: in X11, use static methods inside KDE, which give working native dialogs, but non-static outside // KDE, which gives working Qt dialogs. // // Only show the GTK dialog in Gnome, where people deserve it #ifdef HAVE_X11 if (qgetenv("KDE_FULL_SESSION").size() > 0) { useStaticForNative = true; } if (qgetenv("XDG_CURRENT_DESKTOP") == "GNOME") { useStaticForNative = true; QClipboard *cb = QApplication::clipboard(); cb->blockSignals(true); swapExtensionOrder = true; } #endif } ~Private() { if (qgetenv("XDG_CURRENT_DESKTOP") == "GNOME") { useStaticForNative = true; QClipboard *cb = QApplication::clipboard(); cb->blockSignals(false); } } QWidget *parent; KoFileDialog::DialogType type; QString dialogName; QString caption; QString defaultDirectory; QStringList filterList; QString defaultFilter; QScopedPointer fileDialog; QMimeType mimeType; bool useStaticForNative; bool hideDetails; bool swapExtensionOrder; }; KoFileDialog::KoFileDialog(QWidget *parent, KoFileDialog::DialogType type, const QString &dialogName) : d(new Private(parent, type, "", getUsedDir(dialogName), dialogName)) { } KoFileDialog::~KoFileDialog() { delete d; } void KoFileDialog::setCaption(const QString &caption) { d->caption = caption; } void KoFileDialog::setDefaultDir(const QString &defaultDir, bool override) { if (override || d->defaultDirectory.isEmpty()) { QFileInfo f(defaultDir); d->defaultDirectory = f.absoluteFilePath(); } else { QFileInfo df(d->defaultDirectory); if (!df.isFile()) { QFileInfo f(defaultDir); if (df.exists()) { df.setFile(df.filePath(), f.fileName()); d->defaultDirectory = df.absoluteFilePath(); } else { QFileInfo f(defaultDir); d->defaultDirectory = f.absoluteFilePath(); } } } } void KoFileDialog::setOverrideDir(const QString &overrideDir) { d->defaultDirectory = overrideDir; } void KoFileDialog::setImageFilters() { QStringList imageMimeTypes; foreach(const QByteArray &mimeType, QImageReader::supportedMimeTypes()) { imageMimeTypes << QLatin1String(mimeType); } setMimeTypeFilters(imageMimeTypes); } void KoFileDialog::setNameFilter(const QString &filter) { d->filterList.clear(); if (d->type == KoFileDialog::SaveFile) { QStringList mimeList; d->filterList << splitNameFilter(filter, &mimeList); d->defaultFilter = d->filterList.first(); } else { d->filterList << filter; } } void KoFileDialog::setNameFilters(const QStringList &filterList, QString defaultFilter) { d->filterList.clear(); if (d->type == KoFileDialog::SaveFile) { QStringList mimeList; foreach(const QString &filter, filterList) { d->filterList << splitNameFilter(filter, &mimeList); } if (!defaultFilter.isEmpty()) { mimeList.clear(); QStringList defaultFilters = splitNameFilter(defaultFilter, &mimeList); if (defaultFilters.size() > 0) { defaultFilter = defaultFilters.first(); } } } else { d->filterList = filterList; } d->defaultFilter = defaultFilter; } void KoFileDialog::setMimeTypeFilters(const QStringList &filterList, QString defaultFilter) { d->filterList = getFilterStringListFromMime(filterList, true); if (!defaultFilter.isEmpty()) { QStringList defaultFilters = getFilterStringListFromMime(QStringList() << defaultFilter, false); if (defaultFilters.size() > 0) { defaultFilter = defaultFilters.first(); } } d->defaultFilter = defaultFilter; } void KoFileDialog::setHideNameFilterDetailsOption() { d->hideDetails = true; } QStringList KoFileDialog::nameFilters() const { return d->filterList; } QString KoFileDialog::selectedNameFilter() const { if (!d->useStaticForNative) { return d->fileDialog->selectedNameFilter(); } else { return d->defaultFilter; } } QString KoFileDialog::selectedMimeType() const { if (d->mimeType.isValid()) { return d->mimeType.name(); } else { return ""; } } void KoFileDialog::createFileDialog() { qInfo()<type; d->fileDialog.reset(new QFileDialog(d->parent, d->caption, d->defaultDirectory)); if (d->type == SaveFile) { d->fileDialog->setAcceptMode(QFileDialog::AcceptSave); d->fileDialog->setFileMode(QFileDialog::AnyFile); } else { // open / import d->fileDialog->setAcceptMode(QFileDialog::AcceptOpen); if (d->type == ImportDirectory || d->type == OpenDirectory) { d->fileDialog->setFileMode(QFileDialog::Directory); d->fileDialog->setOption(QFileDialog::ShowDirsOnly, true); } else { // open / import file(s) if (d->type == OpenFile || d->type == ImportFile) { d->fileDialog->setFileMode(QFileDialog::ExistingFile); } else { // files d->fileDialog->setFileMode(QFileDialog::ExistingFiles); } } } d->fileDialog->setNameFilters(d->filterList); if (!d->defaultFilter.isEmpty()) { d->fileDialog->selectNameFilter(d->defaultFilter); } if (d->type == ImportDirectory || d->type == ImportFile || d->type == ImportFiles || d->type == SaveFile) { d->fileDialog->setWindowModality(Qt::WindowModal); } if (d->hideDetails) { d->fileDialog->setOption(QFileDialog::HideNameFilterDetails); } - connect(d->fileDialog.data(), SIGNAL(filterSelected(QString)), this, SLOT(filterSelected(QString))); - connect(d->fileDialog.data(), SIGNAL(finished(int)), this, SIGNAL(finished(int))); + connect(d->fileDialog.data(), &QFileDialog::filterSelected, this, &KoFileDialog::filterSelected); + connect(d->fileDialog.data(), &QDialog::finished, this, &KoFileDialog::finished); } QString KoFileDialog::filename() { qInfo()<useStaticForNative; QString url; if (!d->useStaticForNative) { if (!d->fileDialog) { createFileDialog(); } if (d->fileDialog->exec() == QDialog::Accepted) { url = d->fileDialog->selectedFiles().first(); } } else { switch (d->type) { case OpenFile: { url = QFileDialog::getOpenFileName(d->parent, d->caption, d->defaultDirectory, d->filterList.join(";;"), &d->defaultFilter); break; } case OpenDirectory: { url = QFileDialog::getExistingDirectory(d->parent, d->caption, d->defaultDirectory, QFileDialog::ShowDirsOnly); break; } case ImportFile: { url = QFileDialog::getOpenFileName(d->parent, d->caption, d->defaultDirectory, d->filterList.join(";;"), &d->defaultFilter); break; } case ImportDirectory: { url = QFileDialog::getExistingDirectory(d->parent, d->caption, d->defaultDirectory, QFileDialog::ShowDirsOnly); break; } case SaveFile: { url = QFileDialog::getSaveFileName(d->parent, d->caption, d->defaultDirectory, d->filterList.join(";;"), &d->defaultFilter); break; } default: ; } } if (!url.isEmpty()) { if (d->type == SaveFile && QFileInfo(url).suffix().isEmpty()) { int start = d->defaultFilter.lastIndexOf("*.") + 1; int end = d->defaultFilter.lastIndexOf(" )"); int n = end - start; QString extension = d->defaultFilter.mid(start, n); url.append(extension); } QMimeDatabase db; d->mimeType = db.mimeTypeForFile(url); saveUsedDir(url, d->dialogName); } return url; } QStringList KoFileDialog::filenames() { QStringList urls; if (!d->useStaticForNative) { if (!d->fileDialog) { createFileDialog(); } if (d->fileDialog->exec() == QDialog::Accepted) { urls = d->fileDialog->selectedFiles(); } } else { switch (d->type) { case OpenFiles: case ImportFiles: { urls = QFileDialog::getOpenFileNames(d->parent, d->caption, d->defaultDirectory, d->filterList.join(";;"), &d->defaultFilter); break; } default: ; } } if (urls.size() > 0) { saveUsedDir(urls.first(), d->dialogName); } return urls; } void KoFileDialog::filterSelected(const QString &filter) { // "Windows BMP image ( *.bmp )"; int start = filter.lastIndexOf("*.") + 2; int end = filter.lastIndexOf(" )"); int n = end - start; QString extension = filter.mid(start, n); d->defaultFilter = filter; d->fileDialog->setDefaultSuffix(extension); } QStringList KoFileDialog::splitNameFilter(const QString &nameFilter, QStringList *mimeList) { Q_ASSERT(mimeList); QStringList filters; QString description; if (nameFilter.contains("(")) { description = nameFilter.left(nameFilter.indexOf("(") -1).trimmed(); } QStringList entries = nameFilter.mid(nameFilter.indexOf("(") + 1).split(" ",QString::SkipEmptyParts ); foreach(QString entry, entries) { entry = entry.remove("*"); entry = entry.remove(")"); QMimeDatabase db; QMimeType mime = db.mimeTypeForName("bla" + entry); if (mime.name() != "application/octet-stream") { if (!mimeList->contains(mime.name())) { mimeList->append(mime.name()); filters.append(mime.comment() + " ( *" + entry + " )"); } } else { filters.append(entry.remove(".").toUpper() + " " + description + " ( *." + entry + " )"); } } return filters; } const QStringList KoFileDialog::getFilterStringListFromMime(const QStringList &mimeList, bool withAllSupportedEntry) { QStringList mimeSeen; QStringList ret; if (withAllSupportedEntry) { ret << QString(); } for (QStringList::ConstIterator it = mimeList.begin(); it != mimeList.end(); ++it) { QMimeDatabase db; QMimeType mimeType = db.mimeTypeForName(*it); if (!mimeType.isValid()) { continue; } if (!mimeSeen.contains(mimeType.name())) { QString oneFilter; QStringList patterns = mimeType.globPatterns(); QStringList::ConstIterator jt; for (jt = patterns.constBegin(); jt != patterns.constEnd(); ++jt) { if (d->swapExtensionOrder) { oneFilter.prepend(*jt + " "); if (withAllSupportedEntry) { ret[0].prepend(*jt + " "); } } else { oneFilter.append(*jt + " "); if (withAllSupportedEntry) { ret[0].append(*jt + " "); } } } oneFilter = mimeType.comment() + " ( " + oneFilter + ")"; ret << oneFilter; mimeSeen << mimeType.name(); } } if (withAllSupportedEntry) { ret[0] = i18n("All supported formats") + " ( " + ret[0] + (")"); } return ret; } QString KoFileDialog::getUsedDir(const QString &dialogName) { if (dialogName.isEmpty()) return ""; KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString dir = group.readEntry(dialogName); return dir; } void KoFileDialog::saveUsedDir(const QString &fileName, const QString &dialogName) { if (dialogName.isEmpty()) return; QFileInfo fileInfo(fileName); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); group.writeEntry(dialogName, fileInfo.absolutePath()); } void KoFileDialog::setVisible(bool value) { d->fileDialog.data()->setVisible(value); if (value) { d->fileDialog.data()->raise(); d->fileDialog.data()->activateWindow(); } } diff --git a/src/libs/widgetutils/KoProgressUpdater.cpp b/src/libs/widgetutils/KoProgressUpdater.cpp index 5ac7a84b..25e1d25b 100644 --- a/src/libs/widgetutils/KoProgressUpdater.cpp +++ b/src/libs/widgetutils/KoProgressUpdater.cpp @@ -1,234 +1,234 @@ /* This file is part of the KDE project * Copyright (C) 2006-2007 Thomas Zander * Copyright (C) 2009 Boudewijn Rempt * * 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 "KoProgressUpdater.h" #include #include #include #include #include "KoUpdaterPrivate_p.h" #include "KoUpdater.h" #include "KoProgressProxy.h" // 4 updates per second should be enough #define PROGRESSUPDATER_GUITIMERINTERVAL 250 class Q_DECL_HIDDEN KoProgressUpdater::Private { public: Private(KoProgressUpdater *_parent, KoProgressProxy *p, Mode _mode, QTextStream *output_ = 0) : parent(_parent) , progressBar(p) , mode(_mode) , totalWeight(0) , currentProgress(0) , updated(false) , output(output_) , updateGuiTimer(_parent) , canceled(false) { } KoProgressUpdater *parent; KoProgressProxy *progressBar; Mode mode; int totalWeight; int currentProgress; bool updated; // is true whenever the progress needs to be recomputed QTextStream *output; QTimer updateGuiTimer; // fires regularly to update the progress bar widget QList > subtasks; QList > subTaskWrappers; // We delete these QTime referenceTime; static void logEvents(QTextStream& out, KoProgressUpdater::Private *updater, const QTime& startTime, const QString& prefix); bool canceled; }; // NOTE: do not make the KoProgressUpdater object part of the QObject // hierarchy. Do not make KoProgressProxy its parent (note that KoProgressProxy // is not necessarily castable to QObject ). This prevents proper functioning // of progress reporting in multi-threaded environments. KoProgressUpdater::KoProgressUpdater(KoProgressProxy *progressBar, Mode mode, QTextStream *output) : d (new Private(this, progressBar, mode, output)) { Q_ASSERT(d->progressBar); - connect(&d->updateGuiTimer, SIGNAL(timeout()), SLOT(updateUi()), Qt::QueuedConnection); + connect(&d->updateGuiTimer, &QTimer::timeout, this, &KoProgressUpdater::updateUi, Qt::QueuedConnection); } KoProgressUpdater::~KoProgressUpdater() { if (d->output) { Private::logEvents(*d->output, d, referenceTime(), ""); } d->progressBar->setValue(d->progressBar->maximum()); // make sure to stop the timer to avoid accessing // the data we are going to delete right now d->updateGuiTimer.stop(); qDeleteAll(d->subtasks); d->subtasks.clear(); qDeleteAll(d->subTaskWrappers); d->subTaskWrappers.clear(); delete d; } void KoProgressUpdater::setReferenceTime(const QTime &referenceTime) { d->referenceTime = referenceTime; } QTime KoProgressUpdater::referenceTime() const { return d->referenceTime; } void KoProgressUpdater::start(int range, const QString &text) { d->updateGuiTimer.start(PROGRESSUPDATER_GUITIMERINTERVAL); qDeleteAll(d->subtasks); d->subtasks.clear(); qDeleteAll(d->subTaskWrappers); d->subTaskWrappers.clear(); d->progressBar->setRange(0, range-1); d->progressBar->setValue(0); if(!text.isEmpty()) { d->progressBar->setFormat(text); } d->totalWeight = 0; d->canceled = false; } QPointer KoProgressUpdater::startSubtask(int weight, const QString &name) { KoUpdaterPrivate *p = new KoUpdaterPrivate(this, weight, name); d->totalWeight += weight; d->subtasks.append(p); - connect(p, SIGNAL(sigUpdated()), SLOT(update())); + connect(p, &KoUpdaterPrivate::sigUpdated, this, &KoProgressUpdater::update); QPointer updater = new KoUpdater(p); d->subTaskWrappers.append(updater); if (!d->updateGuiTimer.isActive()) { // we maybe need to restart the timer if it was stopped in updateUi() cause // other sub-tasks created before this one finished already. d->updateGuiTimer.start(PROGRESSUPDATER_GUITIMERINTERVAL); } return updater; } void KoProgressUpdater::cancel() { foreach(KoUpdaterPrivate *updater, d->subtasks) { updater->setProgress(100); updater->interrupt(); } d->canceled = true; updateUi(); } void KoProgressUpdater::update() { d->updated = true; if (d->mode == Unthreaded) { qApp->processEvents(); } } void KoProgressUpdater::updateUi() { // This function runs in the app main thread. All the progress // updates arrive at the KoUpdaterPrivate instances through // queued connections, so until we relinquish control to the // event loop, the progress values cannot change, and that // won't happen until we return from this function (which is // triggered by a timer) if (d->updated) { int totalProgress = 0; foreach(QPointer updater, d->subtasks) { if (updater->interrupted()) { d->currentProgress = -1; return; } int progress = updater->progress(); if (progress > 100 || progress < 0) { progress = updater->progress(); } totalProgress += progress *updater->weight(); } d->currentProgress = totalProgress / d->totalWeight; d->updated = false; } if (d->currentProgress == -1) { d->progressBar->setValue( d->progressBar->maximum() ); // should we hide the progressbar after a little while? return; } if (d->currentProgress >= d->progressBar->maximum()) { // we're done d->updateGuiTimer.stop(); // 10 updates/second should be enough? } d->progressBar->setValue(d->currentProgress); } bool KoProgressUpdater::interrupted() const { return d->canceled; } bool KoProgressUpdater::hasOutput() const { return d->output != 0; } void KoProgressUpdater::Private::logEvents(QTextStream& out, KoProgressUpdater::Private *updater, const QTime& startTime, const QString& prefix) { // initial implementation: write out the names of all events foreach (QPointer p, updater->subtasks) { if (!p) continue; foreach (const KoUpdaterPrivate::TimePoint &tp, p->getPoints()) { out << prefix+p->objectName() << '\t' << startTime.msecsTo(tp.time) << '\t' << tp.value << endl; } } } diff --git a/src/libs/widgetutils/KoUpdater.cpp b/src/libs/widgetutils/KoUpdater.cpp index 0eb28374..c3aa4640 100644 --- a/src/libs/widgetutils/KoUpdater.cpp +++ b/src/libs/widgetutils/KoUpdater.cpp @@ -1,101 +1,101 @@ /* This file is part of the KDE project * * Copyright (C) 2006-2007 Thomas Zander * Copyright (C) 2009 Boudewijn Rempt * * 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 "KoUpdater.h" #include "KoUpdaterPrivate_p.h" KoUpdater::KoUpdater(KoUpdaterPrivate *p) : QObject(p), m_progressPercent(0) { d = p; Q_ASSERT(p); Q_ASSERT(!d.isNull()); - connect( this, SIGNAL(sigCancel()), d, SLOT(cancel()) ); - connect( this, SIGNAL(sigProgress(int)), d, SLOT(setProgress(int)) ); - connect( d, SIGNAL(sigInterrupted()), this, SLOT(interrupt()) ); + connect( this, &KoUpdater::sigCancel, d.data(), &KoUpdaterPrivate::cancel ); + connect( this, &KoUpdater::sigProgress, d.data(), &KoUpdaterPrivate::setProgress ); + connect( d.data(), &KoUpdaterPrivate::sigInterrupted, this, &KoUpdater::interrupt ); setRange(0, 100); m_interrupted = false; } void KoUpdater::cancel() { emit sigCancel(); } void KoUpdater::setProgress(int percent) { if (m_progressPercent >= percent) { return; } d->addPoint(percent); m_progressPercent = percent; emit sigProgress( percent ); } int KoUpdater::progress() const { return m_progressPercent; } bool KoUpdater::interrupted() const { return m_interrupted; } int KoUpdater::maximum() const { return 100; } void KoUpdater::setValue( int value ) { if ( value < min ) value = min; if ( value > max ) value = max; // Go from range to percent if (range == 0) return; setProgress( ((100 * value ) / range) + 1 ); } void KoUpdater::setRange( int minimum, int maximum ) { min = minimum - 1; max = maximum; range = max - min; } void KoUpdater::setFormat( const QString & format ) { Q_UNUSED(format); // XXX: Do nothing } void KoUpdater::interrupt() { m_interrupted = true; } diff --git a/src/plugins/schedulers/tj/PlanTJPlugin.cpp b/src/plugins/schedulers/tj/PlanTJPlugin.cpp index bcad5ab6..99d8df20 100644 --- a/src/plugins/schedulers/tj/PlanTJPlugin.cpp +++ b/src/plugins/schedulers/tj/PlanTJPlugin.cpp @@ -1,166 +1,166 @@ /* 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. */ #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" "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, SIGNAL(jobFinished(KPlato::SchedulerThread*)), SLOT(slotFinished(KPlato::SchedulerThread*))); + 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, SIGNAL(maxProgressChanged(int)), sm, SLOT(setMaxProgress(int))); - connect(job, SIGNAL(progressChanged(int)), sm, SLOT(setProgress(int))); + 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, SIGNAL(jobFinished(PlanTJScheduler*)), this, SLOT(slotFinished(PlanTJScheduler*)) ); + 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:"; } 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, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*)), mp, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*))); - disconnect(this, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*)), mp, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*))); + 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/plugins/schedulers/tj/PlanTJScheduler.cpp b/src/plugins/schedulers/tj/PlanTJScheduler.cpp index c093c4b3..8ee472bf 100644 --- a/src/plugins/schedulers/tj/PlanTJScheduler.cpp +++ b/src/plugins/schedulers/tj/PlanTJScheduler.cpp @@ -1,917 +1,917 @@ /* This file is part of the KDE project * Copyright (C) 2009, 2010, 2011, 2012 Dag Andersen * 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. */ #include "PlanTJScheduler.h" #include "kptproject.h" #include "kptschedule.h" #include "kptresource.h" #include "kpttask.h" #include "kptrelation.h" #include "kptduration.h" #include "kptcalendar.h" #include "kptdebug.h" #include "taskjuggler/taskjuggler.h" #include "taskjuggler/Project.h" #include "taskjuggler/Scenario.h" #include "taskjuggler/Resource.h" #include "taskjuggler/Task.h" #include "taskjuggler/Interval.h" #include "taskjuggler/Allocation.h" #include "taskjuggler/Utility.h" #include "taskjuggler/UsageLimits.h" #include "taskjuggler/CoreAttributes.h" #include "taskjuggler/TjMessageHandler.h" #include "taskjuggler/debug.h" #include #include #include #include #include #include #include #include #define PROGRESS_MAX_VALUE 100 PlanTJScheduler::PlanTJScheduler( Project *project, ScheduleManager *sm, ulong granularity, QObject *parent ) : SchedulerThread( project, sm, parent ), result( -1 ), m_schedule( 0 ), m_recalculate( false ), m_usePert( false ), m_backward( false ), m_granularity( granularity ) { TJ::TJMH.reset(); - connect(&TJ::TJMH, SIGNAL(message(int,QString,TJ::CoreAttributes*)), this, SLOT(slotMessage(int,QString,TJ::CoreAttributes*))); + connect(&TJ::TJMH, &TJ::TjMessageHandler::message, this, &PlanTJScheduler::slotMessage); - connect(this, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*)), project, SIGNAL(sigCalculationStarted(KPlato::Project*,KPlato::ScheduleManager*))); + connect(this, &PlanTJScheduler::sigCalculationStarted, project, &KPlato::Project::sigCalculationStarted); emit sigCalculationStarted( project, sm ); - connect( this, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*)), project, SIGNAL(sigCalculationFinished(KPlato::Project*,KPlato::ScheduleManager*)) ); + connect( this, &PlanTJScheduler::sigCalculationFinished, project, &KPlato::Project::sigCalculationFinished ); } PlanTJScheduler::~PlanTJScheduler() { delete m_tjProject; } void PlanTJScheduler::slotMessage( int type, const QString &msg, TJ::CoreAttributes *object ) { // debugPlan<<"PlanTJScheduler::slotMessage:"<getType() == CA_Task && m_taskmap.contains( static_cast( object ) ) ) { log = Schedule::Log( static_cast( m_taskmap[ static_cast( object ) ] ), type, msg ); } else if ( object && object->getType() == CA_Resource && m_resourcemap.contains( static_cast( object ) ) ) { log = Schedule::Log( 0, m_resourcemap[ static_cast( object ) ], type, msg ); } else if ( object && ! object->getName().isEmpty() ) { log = Schedule::Log( static_cast( m_project ), type, QString( "%1: %2" ).arg(object->getName() ).arg( msg ) ); } else { log = Schedule::Log( static_cast( m_project ), type, msg ); } slotAddLog( log ); } void PlanTJScheduler::run() { if ( m_haltScheduling ) { deleteLater(); return; } if ( m_stopScheduling ) { return; } setMaxProgress( PROGRESS_MAX_VALUE ); { // mutex --> m_projectMutex.lock(); m_managerMutex.lock(); m_project = new Project(); loadProject( m_project, m_pdoc ); m_project->setName( "Schedule: " + m_project->name() ); //Debug m_project->stopcalculation = false; m_manager = m_project->scheduleManager( m_mainmanagerId ); Q_CHECK_PTR( m_manager ); Q_ASSERT( m_manager->expected() ); Q_ASSERT( m_manager != m_mainmanager ); Q_ASSERT( m_manager->scheduleId() == m_mainmanager->scheduleId() ); Q_ASSERT( m_manager->expected() != m_mainmanager->expected() ); m_manager->setName( "Schedule: " + m_manager->name() ); //Debug m_schedule = m_manager->expected(); bool x = connect(m_manager, SIGNAL(sigLogAdded(KPlato::Schedule::Log)), this, SLOT(slotAddLog(KPlato::Schedule::Log))); Q_ASSERT( x ); Q_UNUSED( x ); m_project->initiateCalculation( *m_schedule ); m_project->initiateCalculationLists( *m_schedule ); m_usePert = m_manager->usePert(); m_recalculate = m_manager->recalculate(); if ( m_recalculate ) { m_backward = false; } else { m_backward = m_manager->schedulingDirection(); } m_project->setCurrentSchedule( m_manager->expected()->id() ); m_schedule->setPhaseName( 0, xi18nc( "@info/plain" , "Init" ) ); QLocale locale; KFormat format(locale); if ( ! m_backward ) { logDebug( m_project, 0, QString( "Schedule project using TJ Scheduler, starting at %1, granularity %2" ).arg( QDateTime::currentDateTime().toString() ).arg( format.formatDuration( m_granularity ) ), 0 ); if ( m_recalculate ) { logInfo( m_project, 0, xi18nc( "@info/plain" , "Re-calculate project from start time: %1", locale.toString(m_project->constraintStartTime(), QLocale::ShortFormat) ), 0 ); } else { logInfo( m_project, 0, xi18nc( "@info/plain" , "Schedule project from start time: %1", locale.toString(m_project->constraintStartTime(), QLocale::ShortFormat) ), 0 ); } logInfo( m_project, 0, xi18nc( "@info/plain" , "Project target finish time: %1", locale.toString(m_project->constraintEndTime(), QLocale::ShortFormat) ), 0 ); } else { logDebug( m_project, 0, QString( "Schedule project backward using TJ Scheduler, starting at %1, granularity %2" ).arg( locale.toString(QDateTime::currentDateTime(), QLocale::ShortFormat) ).arg( format.formatDuration( m_granularity ) ), 0 ); logInfo( m_project, 0, xi18nc( "@info/plain" , "Schedule project from end time: %1", locale.toString(m_project->constraintEndTime(), QLocale::ShortFormat) ), 0 ); } m_managerMutex.unlock(); m_projectMutex.unlock(); } // <--- mutex setProgress( 2 ); if ( ! kplatoToTJ() ) { result = 1; setProgress( PROGRESS_MAX_VALUE ); return; } setMaxProgress( PROGRESS_MAX_VALUE ); connect(m_tjProject, SIGNAL(updateProgressBar(int,int)), this, SLOT(setProgress(int))); m_schedule->setPhaseName( 1, xi18nc( "@info/plain" , "Schedule" ) ); logInfo( m_project, 0, "Start scheduling", 1 ); bool r = solve(); if ( ! r ) { debugPlan<<"Scheduling failed"; result = 2; logError( m_project, 0, xi18nc( "@info/plain" , "Failed to schedule project" ) ); setProgress( PROGRESS_MAX_VALUE ); return; } if ( m_haltScheduling ) { debugPlan<<"Scheduling halted"; logInfo( m_project, 0, "Scheduling halted" ); deleteLater(); return; } m_schedule->setPhaseName( 2, xi18nc( "@info/plain" , "Update" ) ); logInfo( m_project, 0, "Scheduling finished, update project", 2 ); if ( ! kplatoFromTJ() ) { logError( m_project, 0, "Project update failed" ); } setProgress( PROGRESS_MAX_VALUE ); m_schedule->setPhaseName( 3, xi18nc( "@info/plain" , "Finish" ) ); } bool PlanTJScheduler::check() { DebugCtrl.setDebugMode( 0 ); DebugCtrl.setDebugLevel( 1000 ); return m_tjProject->pass2( true ); } bool PlanTJScheduler::solve() { debugPlan<<"PlanTJScheduler::solve()"; TJ::Scenario *sc = m_tjProject->getScenario( 0 ); if ( ! sc ) { logError( m_project, 0, xi18nc( "@info/plain" , "Failed to find scenario to schedule" ) ); return false; } DebugCtrl.setDebugLevel(0); DebugCtrl.setDebugMode(PSDEBUG+TSDEBUG+RSDEBUG+PADEBUG); return m_tjProject->scheduleScenario( sc ); } bool PlanTJScheduler::kplatoToTJ() { m_tjProject = new TJ::Project(); m_tjProject->setScheduleGranularity( m_granularity / 1000 ); m_tjProject->getScenario( 0 )->setMinSlackRate( 0.0 ); // Do not calculate critical path m_tjProject->setNow( m_project->constraintStartTime().toTime_t() ); m_tjProject->setStart( m_project->constraintStartTime().toTime_t() ); m_tjProject->setEnd( m_project->constraintEndTime().toTime_t() ); m_tjProject->setDailyWorkingHours( m_project->standardWorktime()->day() ); // Set working days for the project, it is used for tasks with a length specification // FIXME: Plan has task specific calendars for this estimate type KPlato::Calendar *cal = m_project->defaultCalendar(); if ( ! cal ) { m_project->calendars().value( 0 ); } if ( cal ) { int days[ 7 ] = { Qt::Sunday, Qt::Monday, Qt::Tuesday, Qt::Wednesday, Qt::Thursday, Qt::Friday, Qt::Saturday }; for ( int i = 0; i < 7; ++i ) { CalendarDay *d = 0; for ( Calendar *c = cal; c; c = c->parentCal() ) { QTime t; t.start(); d = c->weekday( days[ i ] ); Q_ASSERT( d ); if ( d == 0 || d->state() != CalendarDay::Undefined ) { break; } } if ( d && d->state() == CalendarDay::Working ) { QList lst; foreach ( const TimeInterval *ti, d->timeIntervals() ) { TJ::Interval *tji = new TJ::Interval( toTJInterval( ti->startTime(), ti->endTime(),tjGranularity() ) ); lst << tji; } m_tjProject->setWorkingHours( i, lst ); qDeleteAll( lst ); } } } addTasks(); setConstraints(); addDependencies(); addRequests(); addStartEndJob(); if (result != -1) { return false; } return check(); } void PlanTJScheduler::addStartEndJob() { TJ::Task *start = new TJ::Task( m_tjProject, "TJ::StartJob", "TJ::StartJob", 0, QString(), 0); start->setMilestone( true ); if ( ! m_backward ) { start->setSpecifiedStart( 0, m_tjProject->getStart() ); start->setPriority( 999 ); } else { // backwards: insert a new ms before start and make start an ALAP to push all other jobs ALAP TJ::Task *bs = new TJ::Task( m_tjProject, "TJ::StartJob-B", "TJ::StartJob-B", 0, QString(), 0); bs->setMilestone( true ); bs->setSpecifiedStart( 0, m_tjProject->getStart() ); bs->setPriority( 999 ); bs->addPrecedes( start->getId() ); start->addDepends( bs->getId() ); start->setScheduling( TJ::Task::ALAP ); } TJ::Task *end = new TJ::Task( m_tjProject, "TJ::EndJob", "TJ::EndJob", 0, QString(), 0); end->setMilestone( true ); if ( m_backward ) { end->setSpecifiedEnd( 0, m_tjProject->getEnd() - 1 ); end->setScheduling( TJ::Task::ALAP ); } for ( QMap::ConstIterator it = m_taskmap.constBegin(); it != m_taskmap.constEnd(); ++it ) { if ( it.value()->isStartNode() ) { it.key()->addDepends( start->getId() ); // logDebug( m_project, 0, QString( "'%1' depends on: '%2'" ).arg( it.key()->getName() ).arg( start->getName() ) ); if ( start->getScheduling() == TJ::Task::ALAP ) { start->addPrecedes( it.key()->getId() ); // logDebug( m_project, 0, QString( "'%1' precedes: '%2'" ).arg( start->getName() ).arg( it.key()->getName() ) ); } } if ( it.value()->isEndNode() ) { end->addDepends( it.key()->getId() ); if ( it.key()->getScheduling() == TJ::Task::ALAP ) { it.key()->addPrecedes( end->getId() ); } } } } // static int PlanTJScheduler::toTJDayOfWeek( int day ) { return day == 7 ? 0 : day; } // static DateTime PlanTJScheduler::fromTime_t( time_t t, const QTimeZone &tz ) { return DateTime ( QDateTime::fromTime_t( t ).toTimeZone( tz ) ); } time_t PlanTJScheduler::toTJTime_t( const QDateTime &dt, ulong granularity ) { int secs = QTime( 0, 0, 0 ).secsTo( dt.time() ); secs -= secs % granularity; return QDateTime( dt.date(), QTime( 0, 0, 0 ).addSecs( secs ), dt.timeZone() ).toTime_t(); } // static AppointmentInterval PlanTJScheduler::fromTJInterval( const TJ::Interval &tji, const QTimeZone &tz ) { AppointmentInterval a( fromTime_t( tji.getStart(), tz ), fromTime_t( tji.getEnd(), tz ).addSecs( 1 ) ); return a; } // static TJ::Interval PlanTJScheduler::toTJInterval( const QDateTime &start, const QDateTime &end, ulong granularity ) { int secs = QTime( 0, 0, 0 ).secsTo( start.time() ); secs -= secs % granularity; QDateTime s( start.date(), QTime( 0, 0, 0 ).addSecs( secs ), start.timeZone() ); secs = QTime( 0, 0, 0 ).secsTo( end.time() ); secs -= secs % granularity; QDateTime e( end.date(), QTime( 0, 0, 0 ).addSecs( secs ), end.timeZone() ); TJ::Interval ti( s.toTime_t(), e.addSecs( -1 ).toTime_t() ); return ti; } // static TJ::Interval PlanTJScheduler::toTJInterval( const QTime &start, const QTime &end, ulong granularity ) { int secs = QTime( 0, 0, 0 ).secsTo( start ); time_t s = secs - ( secs % granularity ); secs = ( end == QTime( 0, 0, 0 ) ) ? 86399 : QTime( 0, 0, 0 ).secsTo( end ); time_t e = secs - ( secs % granularity ) - 1; TJ::Interval ti( s, e ); return ti; } ulong PlanTJScheduler::tjGranularity() const { return m_tjProject->getScheduleGranularity(); } bool PlanTJScheduler::kplatoFromTJ() { MainSchedule *cs = static_cast( m_project->currentSchedule() ); QDateTime start; QDateTime end; for ( QMap::ConstIterator it = m_taskmap.constBegin(); it != m_taskmap.constEnd(); ++it ) { if ( ! taskFromTJ( it.key(), it.value() ) ) { return false; } if ( ! start.isValid() || it.value()->startTime() < start ) { start = it.value()->startTime(); } if ( ! end.isValid() || it.value()->endTime() > end ) { end = it.value()->endTime(); } } m_project->setStartTime( start.isValid() ? start : m_project->constraintStartTime() ); m_project->setEndTime( end.isValid() ? end : m_project->constraintEndTime() ); adjustSummaryTasks( m_schedule->summaryTasks() ); foreach ( Task *task, m_taskmap ) { calcPertValues( task ); } m_project->calcCriticalPathList( m_schedule ); // calculate positive float foreach ( Task* t, m_taskmap ) { if ( ! t->inCriticalPath() && t->isStartNode() ) { calcPositiveFloat( t ); } } QLocale locale; logInfo( m_project, 0, xi18nc( "@info/plain" , "Project scheduled to start at %1 and finish at %2", locale.toString(m_project->startTime(), QLocale::ShortFormat), locale.toString(m_project->endTime(), QLocale::ShortFormat) ) ); if ( m_manager ) { logDebug( m_project, 0, QString( "Project scheduling finished at %1" ).arg( locale.toString(QDateTime::currentDateTime(), QLocale::ShortFormat) ) ); m_project->finishCalculation( *m_manager ); m_manager->scheduleChanged( cs ); } return true; } bool PlanTJScheduler::taskFromTJ( TJ::Task *job, Task *task ) { if ( m_haltScheduling || m_manager == 0 ) { return true; } Schedule *cs = task->currentSchedule(); Q_ASSERT( cs ); QTimeZone tz = m_project->timeZone(); debugPlan<<"taskFromTJ:"<name()<id()<getStart( 0 ); if ( s < m_tjProject->getStart() || s > m_tjProject->getEnd() ) { m_project->currentSchedule()->setSchedulingError( true ); cs->setSchedulingError( true ); s = m_tjProject->getStart(); } time_t e = job->getEnd( 0 ); if ( job->isMilestone() ) { Q_ASSERT( s = (e + 1)); e = s - 1; } else if ( e <= s || e > m_tjProject->getEnd() ) { m_project->currentSchedule()->setSchedulingError( true ); cs->setSchedulingError( true ); e = s + (8*60*60); } task->setStartTime( fromTime_t( s, tz ) ); task->setEndTime( fromTime_t( e + 1, tz ) ); task->setDuration( task->endTime() - task->startTime() ); debugPlan<startTime()<<"-- "<endTime(); if ( ! task->startTime().isValid() ) { logError( task, 0, xi18nc( "@info/plain", "Invalid start time" ) ); return false; } if ( ! task->endTime().isValid() ) { logError( task, 0, xi18nc( "@info/plain", "Invalid end time" ) ); return false; } if ( m_project->startTime() > task->startTime() ) { m_project->setStartTime( task->startTime() ); } if ( task->endTime() > m_project->endTime() ) { m_project->setEndTime( task->endTime() ); } foreach ( TJ::CoreAttributes *a, job->getBookedResources( 0 ) ) { TJ::Resource *r = static_cast( a ); Resource *res = m_resourcemap[ r ]; const QVector lst = r->getBookedIntervals( 0, job ); foreach ( const TJ::Interval &tji, lst ) { AppointmentInterval ai = fromTJInterval( tji, tz ); double load = res->type() == Resource::Type_Material ? res->units() : ai.load() * r->getEfficiency(); res->addAppointment( cs, ai.startTime(), ai.endTime(), load ); logDebug( task, 0, '\'' + res->name() + "' added appointment: " + ai.startTime().toString( Qt::ISODate ) + " - " + ai.endTime().toString( Qt::ISODate ) ); } } cs->setScheduled( true ); QLocale locale; if ( task->type() == Node::Type_Milestone ) { logInfo( task, 0, xi18nc( "@info/plain" , "Scheduled milestone: %1", locale.toString(task->startTime(), QLocale::ShortFormat) ) ); } else { logInfo( task, 0, xi18nc( "@info/plain" , "Scheduled task: %1 - %2", locale.toString(task->startTime(), QLocale::ShortFormat), locale.toString(task->endTime(), QLocale::ShortFormat) ) ); } return true; } void PlanTJScheduler::adjustSummaryTasks( const QList &nodes ) { foreach ( Node *n, nodes ) { adjustSummaryTasks( n->childNodeIterator() ); if ( n->parentNode()->type() == Node::Type_Summarytask ) { DateTime pt = n->parentNode()->startTime(); DateTime nt = n->startTime(); if ( ! pt.isValid() || pt > nt ) { n->parentNode()->setStartTime( nt ); } pt = n->parentNode()->endTime(); nt = n->endTime(); if ( ! pt.isValid() || pt < nt ) { n->parentNode()->setEndTime( nt ); } } } } Duration PlanTJScheduler::calcPositiveFloat( Task *task ) { if ( task->positiveFloat() != 0 ) { return task->positiveFloat(); } Duration x; if ( task->dependChildNodes().isEmpty() && task->childProxyRelations().isEmpty() ) { x = m_project->endTime() - task->endTime(); } else { foreach ( const Relation *r, task->dependChildNodes() + task->childProxyRelations() ) { if ( ! r->child()->inCriticalPath() ) { Duration f = calcPositiveFloat( static_cast( r->child() ) ); if ( x == 0 || f < x ) { x = f; } } } } Duration totfloat = task->freeFloat() + x; task->setPositiveFloat( totfloat ); return totfloat; } void PlanTJScheduler::calcPertValues( Task *t ) { switch ( t->constraint() ) { case Node::MustStartOn: if ( t->constraintStartTime() != t->startTime() ) { t->setNegativeFloat( t->startTime() - t->constraintStartTime() ); } break; case Node::StartNotEarlier: if ( t->startTime() < t->constraintStartTime() ) { t->setNegativeFloat( t->constraintStartTime() - t->startTime() ); } break; case Node::MustFinishOn: if ( t->constraintEndTime() != t->endTime() ) { t->setNegativeFloat( t->endTime() - t->constraintEndTime() ); } break; case Node::FinishNotLater: if ( t->endTime() > t->constraintEndTime() ) { t->setNegativeFloat( t->endTime() - t->constraintEndTime() ); } break; case Node::FixedInterval: if ( t->constraintStartTime() != t->startTime() ) { t->setNegativeFloat( t->startTime() - t->constraintStartTime() ); } else if ( t->endTime() != t->constraintEndTime() ) { t->setNegativeFloat( t->endTime() - t->constraintEndTime() ); } break; default: break; } if ( t->negativeFloat() != 0 ) { t->currentSchedule()->setConstraintError( true ); m_project->currentSchedule()->setSchedulingError( true ); logError( t, 0, i18nc( "1=type of constraint", "%1: Failed to meet constraint. Negative float=%2", t->constraintToString( true ), t->negativeFloat().toString( Duration::Format_i18nHour ) ) ); } debugPlan<name()<startTime()<endTime(); Duration negativefloat; foreach ( const Relation *r, t->dependParentNodes() + t->parentProxyRelations() ) { if ( r->parent()->endTime() + r->lag() > t->startTime() ) { Duration f = r->parent()->endTime() + r->lag() - t->startTime(); if ( f > negativefloat ) { negativefloat = f; } } } if ( negativefloat > 0 ) { t->currentSchedule()->setSchedulingError( true ); m_project->currentSchedule()->setSchedulingError( true ); logError( t, 0, xi18nc( "@info/plain", "Failed to meet dependency. Negative float=%1", negativefloat.toString( Duration::Format_i18nHour ) ) ); if ( t->negativeFloat() < negativefloat ) { t->setNegativeFloat( negativefloat ); } } Duration freefloat; foreach ( const Relation *r, t->dependChildNodes() + t->childProxyRelations() ) { if ( t->endTime() + r->lag() < r->child()->startTime() ) { Duration f = r->child()->startTime() - r->lag() - t->endTime(); if ( f > 0 && ( freefloat == 0 || freefloat > f ) ) { freefloat = f; } } } t->setFreeFloat( freefloat ); } bool PlanTJScheduler::exists( QList &lst, CalendarDay *day ) { foreach ( CalendarDay *d, lst ) { if ( d->date() == day->date() && day->state() != CalendarDay::Undefined && d->state() != CalendarDay::Undefined ) { return true; } } return false; } TJ::Resource *PlanTJScheduler::addResource( KPlato::Resource *r) { if ( m_resourcemap.values().contains( r ) ) { debugPlan<name()<<"already exist"; return m_resourcemap.key( r ); } TJ::Resource *res = new TJ::Resource( m_tjProject, r->id(), r->name(), 0 ); if ( r->type() == Resource::Type_Material ) { res->setEfficiency( 0.0 ); } else { res->setEfficiency( (double)(r->units()) / 100. ); } Calendar *cal = r->calendar(); Q_ASSERT(cal); DateTime start = qMax( r->availableFrom(), m_project->constraintStartTime() ); DateTime end = m_project->constraintEndTime(); if ( r->availableUntil().isValid() && end > r->availableUntil() ) { end = r->availableUntil(); } AppointmentIntervalList lst = cal->workIntervals( start, end, 1.0 ); // qDebug()<name()< &map = lst.map(); QMultiMap::const_iterator mapend = map.constEnd(); QMultiMap::const_iterator it = map.constBegin(); TJ::Shift *shift = new TJ::Shift( m_tjProject, r->id(), r->name(), 0, QString(), 0 ); for ( ; it != mapend; ++it ) { shift->addWorkingInterval( toTJInterval( it.value().startTime(), it.value().endTime(), m_granularity/1000 ) ); } res->addShift( toTJInterval( start, end, m_granularity/1000 ), shift ); m_resourcemap[res] = r; logDebug( m_project, 0, "Added resource: " + r->name() ); /* QListIterator it = res->getVacationListIterator(); while ( it.hasNext() ) { TJ::Interval *i = it.next(); logDebug( m_project, 0, "Vacation: " + TJ::time2ISO( i->getStart() ) + " - " + TJ::time2ISO( i->getEnd() ) ); }*/ return res; } TJ::Task *PlanTJScheduler::addTask( KPlato::Task *task, TJ::Task *parent ) { /* if ( m_backward && task->isStartNode() ) { Relation *r = new Relation( m_backwardTask, task ); m_project->addRelation( r ); }*/ TJ::Task *t = new TJ::Task(m_tjProject, task->id(), task->name(), parent, QString(), 0); m_taskmap[ t ] = task; // logDebug( m_project, 0, "Added task: " + task->name() ); addWorkingTime( task, t ); return t; } void PlanTJScheduler::addWorkingTime( KPlato::Task *task, TJ::Task *job ) { if ( task->type() != Node::Type_Task || task->estimate()->type() != Estimate::Type_Duration || ! task->estimate()->calendar() ) { return; } int id = 0; Calendar *cal = task->estimate()->calendar(); DateTime start = m_project->constraintStartTime(); DateTime end = m_project->constraintEndTime(); AppointmentIntervalList lst = cal->workIntervals( start, end, 1.0 ); const QMultiMap &map = lst.map(); QMultiMap::const_iterator mapend = map.constEnd(); QMultiMap::const_iterator it = map.constBegin(); TJ::Shift *shift = new TJ::Shift( m_tjProject, task->id() + QString( "-%1" ).arg( ++id ), task->name(), 0, QString(), 0 ); for ( ; it != mapend; ++it ) { shift->addWorkingInterval(toTJInterval(it.value().startTime(), it.value().endTime(), m_granularity/1000)); } job->addShift(toTJInterval(start, end, m_granularity/1000), shift); } void PlanTJScheduler::addTasks() { debugPlan; QList list = m_project->allNodes(); for (int i = 0; i < list.count(); ++i) { Node *n = list.at(i); TJ::Task *parent = 0; switch ( n->type() ) { case Node::Type_Summarytask: m_schedule->insertSummaryTask( n ); break; case Node::Type_Task: case Node::Type_Milestone: switch ( n->constraint() ) { case Node::StartNotEarlier: parent = addStartNotEarlier( n ); break; case Node::FinishNotLater: parent = addFinishNotLater( n ); break; } addTask( static_cast( n ), parent ); break; default: break; } } } void PlanTJScheduler::addDepends( const Relation *rel ) { TJ::Task *child = m_tjProject->getTask( rel->child()->id() ); TJ::TaskDependency *d = child->addDepends( rel->parent()->id() ); d->setGapDuration( 0, rel->lag().seconds() ); } void PlanTJScheduler::addPrecedes( const Relation *rel ) { TJ::Task *parent = m_tjProject->getTask( rel->parent()->id() ); TJ::TaskDependency *d = parent->addPrecedes( rel->child()->id() ); d->setGapDuration( 0, rel->lag().seconds() ); } void PlanTJScheduler::addDependencies( KPlato::Task *task ) { foreach ( Relation *r, task->dependParentNodes() + task->parentProxyRelations() ) { Node *n = r->parent(); if ( n == 0 || n->type() == Node::Type_Summarytask ) { continue; } switch ( r->type() ) { case Relation::FinishStart: break; case Relation::FinishFinish: case Relation::StartStart: warnPlan<<"Dependency type not handled. Using FinishStart."; logWarning( task, 0, xi18nc( "@info/plain" , "Dependency type '%1' not handled. Using FinishStart.", r->typeToString( true ) ) ); break; } switch ( task->constraint() ) { case Node::ASAP: case Node::ALAP: addPrecedes( r ); addDepends( r ); break; case Node::MustStartOn: case Node::StartNotEarlier: addPrecedes( r ); if ( task->constraintStartTime() < m_project->constraintStartTime() ) { addDepends( r ); } break; case Node::MustFinishOn: case Node::FinishNotLater: addDepends( r ); if ( task->constraintEndTime() < m_project->constraintEndTime() ) { addPrecedes( r ); } break; case Node::FixedInterval: break; } } } void PlanTJScheduler::addDependencies() { foreach ( Task *t, m_taskmap ) { addDependencies( t ); } } void PlanTJScheduler::setConstraints() { QMap ::const_iterator it = m_taskmap.constBegin(); for ( ; it != m_taskmap.constEnd(); ++it ) { setConstraint( it.key(), it.value() ); } } void PlanTJScheduler::setConstraint( TJ::Task *job, KPlato::Task *task ) { switch ( task->constraint() ) { case Node::ASAP: if ( ! job->isMilestone() ) { job->setScheduling( m_backward ? TJ::Task::ALAP : TJ::Task::ASAP ); } break; case Node::ALAP: job->setScheduling( TJ::Task::ALAP); break; case Node::MustStartOn: if ( task->constraintStartTime() >= m_project->constraintStartTime() ) { job->setPriority( 600 ); job->setSpecifiedStart( 0, task->constraintStartTime().toTime_t() ); logDebug( task, 0, QString( "MSO: set specified start: %1").arg( TJ::time2ISO( task->constraintStartTime().toTime_t() ) ) ); } else { logWarning( task, 0, xi18nc( "@info/plain", "%1: Invalid start constraint", task->constraintToString( true ) ) ); } break; case Node::StartNotEarlier: { break; } case Node::MustFinishOn: if ( task->constraintEndTime() <= m_project->constraintEndTime() ) { job->setPriority( 600 ); job->setScheduling( TJ::Task::ALAP ); job->setSpecifiedEnd( 0, task->constraintEndTime().toTime_t() - 1 ); logDebug( task, 0, QString( "MFO: set specified end: %1").arg( TJ::time2ISO( task->constraintEndTime().toTime_t() ) ) ); } else { logWarning( task, 0, xi18nc( "@info/plain", "%1: Invalid end constraint", task->constraintToString( true ) ) ); } break; case Node::FinishNotLater: { break; } case Node::FixedInterval: { job->setPriority( 700 ); TJ::Interval i( toTJInterval( task->constraintStartTime(), task->constraintEndTime(), tjGranularity() ) ); job->setSpecifiedPeriod( 0, i ); // estimate not allowed job->setDuration( 0, 0.0 ); job->setLength( 0, 0.0 ); job->setEffort( 0, 0.0 ); logDebug( task, 0, QString( "FI: set specified: %1 - %2 -> %3 - %4 (%5)") .arg( TJ::time2ISO( task->constraintStartTime().toTime_t() ) ) .arg( TJ::time2ISO( task->constraintEndTime().toTime_t() ) ) .arg( TJ::time2ISO( i.getStart() ) ) .arg( TJ::time2ISO( i.getEnd() ) ) .arg( tjGranularity() ) ); break; } default: logWarning( task, 0, xi18nc( "@info/plain", "Unhandled time constraint type" ) ); break; } } TJ::Task *PlanTJScheduler::addStartNotEarlier( Node *task ) { DateTime time = task->constraintStartTime(); if ( task->estimate()->type() == Estimate::Type_Duration && task->estimate()->calendar() != 0 ) { Calendar *cal = task->estimate()->calendar(); if ( cal != m_project->defaultCalendar() && cal != m_project->calendars().value( 0 ) ) { logWarning( task, 0, xi18nc( "@info/plain", "Could not use the correct calendar for calculation of task duration" ) ); } else { time = cal->firstAvailableAfter( time, m_project->constraintEndTime() ); } } TJ::Task *p = new TJ::Task( m_tjProject, QString("%1-sne").arg( m_tjProject->taskCount() + 1 ), task->name() + "-sne", 0, QString(), 0 ); p->setSpecifiedStart( 0, toTJTime_t( time, tjGranularity() ) ); p->setSpecifiedEnd( 0, m_tjProject->getEnd() - 1 ); qDebug()<<"PlanTJScheduler::addStartNotEarlier:"<constraintEndTime(); if ( task->estimate()->type() == Estimate::Type_Duration && task->estimate()->calendar() != 0 ) { Calendar *cal = task->estimate()->calendar(); if ( cal != m_project->defaultCalendar() && cal != m_project->calendars().value( 0 ) ) { logWarning( task, 0, xi18nc( "@info/plain", "Could not use the correct calendar for calculation of task duration" ) ); } else { time = cal->firstAvailableBefore( time, m_project->constraintStartTime() ); } } TJ::Task *p = new TJ::Task( m_tjProject, QString("%1-fnl").arg( m_tjProject->taskCount() + 1 ), task->name() + "-fnl", 0, QString(), 0 ); p->setSpecifiedEnd( 0, toTJTime_t( time, tjGranularity() ) - 1 ); p->setSpecifiedStart( 0, m_tjProject->getStart() ); return p; } void PlanTJScheduler::addRequests() { debugPlan; QMap ::const_iterator it = m_taskmap.constBegin(); for ( ; it != m_taskmap.constEnd(); ++it ) { addRequest( it.key(), it.value() ); } } void PlanTJScheduler::addRequest( TJ::Task *job, Task *task ) { debugPlan; if ( task->type() == Node::Type_Milestone || task->estimate() == 0 || ( m_recalculate && task->completion().isFinished() ) ) { job->setMilestone( true ); job->setDuration( 0, 0.0 ); return; } // Note: FI tasks can never have an estimate set (duration, length or effort) if ( task->constraint() != Node::FixedInterval ) { if ( task->estimate()->type() == Estimate::Type_Duration && task->estimate()->calendar() == 0 ) { job->setDuration( 0, task->estimate()->value( Estimate::Use_Expected, m_usePert ).toDouble( Duration::Unit_d ) ); return; } if ( task->estimate()->type() == Estimate::Type_Duration && task->estimate()->calendar() != 0 ) { job->setLength( 0, task->estimate()->value( Estimate::Use_Expected, m_usePert ).toDouble( Duration::Unit_d ) * 24.0 / m_tjProject->getDailyWorkingHours() ); return; } if ( m_recalculate && task->completion().isStarted() ) { job->setEffort( 0, task->completion().remainingEffort().toDouble( Duration::Unit_d ) ); } else { Estimate *estimate = task->estimate(); double e = estimate->scale( estimate->value( Estimate::Use_Expected, m_usePert ), Duration::Unit_d, estimate->scales() ); job->setEffort( 0, e ); } } if ( task->requests().isEmpty() ) { return; } foreach ( ResourceRequest *rr, task->requests().resourceRequests( true /*resolveTeam*/ ) ) { if (!rr->resource()->calendar()) { result = 1; // stops scheduling logError(task, 0, i18n("No working hours defined for resource: %1",rr->resource()->name())); continue; // may happen if no calendar is set, and no default calendar } TJ::Resource *tjr = addResource( rr->resource() ); TJ::Allocation *a = new TJ::Allocation(); a->setSelectionMode( TJ::Allocation::order ); if ( rr->units() != 100 ) { TJ::UsageLimits *l = new TJ::UsageLimits(); l->setDailyUnits( rr->units() ); a->setLimits( l ); } a->addCandidate( tjr ); job->addAllocation( a ); logDebug( task, 0, "Added resource candidate: " + rr->resource()->name() ); foreach ( Resource *r, rr->requiredResources() ) { TJ::Resource *tr = addResource( r ); a->addRequiredResource( tjr, tr ); logDebug( task, 0, "Added required resource: " + r->name() ); } } } diff --git a/src/workpackage/mainwindow.cpp b/src/workpackage/mainwindow.cpp index a18c60d4..fc86bd14 100644 --- a/src/workpackage/mainwindow.cpp +++ b/src/workpackage/mainwindow.cpp @@ -1,161 +1,161 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 1999 Simon Hausmann Copyright (C) 2000-2005 David Faure Copyright (C) 2005, 2006 Sven Lüppken Copyright (C) 2008 - 2009, 2012 Dag Andersen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "mainwindow.h" #include "part.h" #include "view.h" #include "kptdocuments.h" #include #include #include #include #include #include #include //#include "koshellsettings.h" #include #include #include #include #include #include #include #include #include #include #include "debugarea.h" KPlatoWork_MainWindow::KPlatoWork_MainWindow() : KParts::MainWindow() { debugPlanWork<undoStack(), SLOT(undo()), actionCollection()); a->setEnabled( false ); - connect( m_part->undoStack(), SIGNAL(canUndoChanged(bool)), a, SLOT(setEnabled(bool)) ); + connect( m_part->undoStack(), &KUndo2QStack::canUndoChanged, a, &QAction::setEnabled ); a = KStandardAction::redo(m_part->undoStack(), SLOT(redo()), actionCollection()); a->setEnabled( false ); - connect( m_part->undoStack(), SIGNAL(canRedoChanged(bool)), a, SLOT(setEnabled(bool)) ); + connect( m_part->undoStack(), &KUndo2QStack::canRedoChanged, a, &QAction::setEnabled ); setCentralWidget( m_part->widget() ); setupGUI( KXmlGuiWindow::ToolBar | KXmlGuiWindow::Keys | KXmlGuiWindow::StatusBar | KXmlGuiWindow::Save); createGUI( m_part ); connect( m_part, SIGNAL(captionChanged(QString,bool)), SLOT(setCaption(QString,bool)) ); } KPlatoWork_MainWindow::~KPlatoWork_MainWindow() { debugPlanWork; } void KPlatoWork_MainWindow::setCaption( const QString & ) { KParts::MainWindow::setCaption( QString() ); } void KPlatoWork_MainWindow::setCaption( const QString &, bool modified ) { KParts::MainWindow::setCaption( QString(), modified ); } bool KPlatoWork_MainWindow::openDocument(const QUrl & url) { // TODO: m_part->openUrl will find out about this as well, no? KIO::StatJob* statJob = KIO::stat( url ); statJob->setSide( KIO::StatJob::SourceSide ); const bool isUrlReadable = statJob->exec(); if (! isUrlReadable) { KMessageBox::error(0L, i18n("The file %1 does not exist.", url.url())); // d->recent->removeUrl(url); //remove the file from the recent-opened-file-list // saveRecentFiles(); return false; } return m_part->openUrl( url ); } QString KPlatoWork_MainWindow::configFile() const { //return readConfigFile( QStandardPaths::locate(QStandardPaths::GenericDataLocation "koshell/koshell_shell.rc" ) ); return QString(); // use UI standards only for now } //called from slotFileSave(), slotFileSaveAs(), queryClose(), slotEmailFile() bool KPlatoWork_MainWindow::saveDocument( bool saveas, bool silent ) { debugPlanWork<saveWorkPackages( silent ); } bool KPlatoWork_MainWindow::queryClose() { KPlatoWork::Part *part = rootDocument(); if ( part == 0 ) { return true; } return part->queryClose(); } void KPlatoWork_MainWindow::slotFileClose() { if (queryClose()) { } } void KPlatoWork_MainWindow::slotFileSave() { saveDocument(); } void KPlatoWork_MainWindow::slotFileOpen() { const QUrl file = QFileDialog::getOpenFileUrl( 0, QString(), QUrl(), "*.planwork" ); if ( ! file.isEmpty() ) { openDocument( file ); } } diff --git a/src/workpackage/packagesettings.cpp b/src/workpackage/packagesettings.cpp index e4e62cf2..4004c983 100644 --- a/src/workpackage/packagesettings.cpp +++ b/src/workpackage/packagesettings.cpp @@ -1,98 +1,98 @@ /* This file is part of the KDE project Copyright (C) 2009 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 "packagesettings.h" #include "workpackage.h" #include #include namespace KPlatoWork { PackageSettingsDialog::PackageSettingsDialog(WorkPackage &p, QWidget *parent) : KoDialog(parent) { setCaption( i18n("Work Package Settings") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); //debugPlanWork<<&p; dia = new PackageSettingsPanel(p, this); setMainWidget(dia); enableButtonOk(false); - connect(dia, SIGNAL(changed(bool)), SLOT(enableButtonOk(bool))); + connect(dia, &PackageSettingsPanel::changed, this, &KoDialog::enableButtonOk); } KUndo2Command *PackageSettingsDialog::buildCommand() { //debugPlanWork; return dia->buildCommand(); } PackageSettingsPanel::PackageSettingsPanel(WorkPackage &p, QWidget *parent) : QWidget(parent), m_package( p ) { setupUi(this); setSettings( p.settings() ); - connect( ui_usedEffort, SIGNAL(stateChanged(int)), SLOT(slotChanged()) ); - connect( ui_progress, SIGNAL(stateChanged(int)), SLOT(slotChanged()) ); - connect( ui_documents, SIGNAL(stateChanged(int)), SLOT(slotChanged()) ); + connect( ui_usedEffort, &QCheckBox::stateChanged, this, &PackageSettingsPanel::slotChanged ); + connect( ui_progress, &QCheckBox::stateChanged, this, &PackageSettingsPanel::slotChanged ); + connect( ui_documents, &QCheckBox::stateChanged, this, &PackageSettingsPanel::slotChanged ); } KUndo2Command *PackageSettingsPanel::buildCommand() { //debugPlanWork; WorkPackageSettings s = settings(); if ( s == m_package.settings() ) { return 0; } return new ModifyPackageSettingsCmd( &m_package, s, kundo2_i18n( "Modify package settings" ) ); } void PackageSettingsPanel::slotChanged() { emit changed( settings() != m_package.settings() ); } WorkPackageSettings PackageSettingsPanel::settings() const { WorkPackageSettings s; s.usedEffort = ui_usedEffort->checkState() == Qt::Checked; s.progress = ui_progress->checkState() == Qt::Checked; s.documents = ui_documents->checkState() == Qt::Checked; return s; } void PackageSettingsPanel::setSettings( const WorkPackageSettings &s ) { ui_usedEffort->setCheckState( s.usedEffort ? Qt::Checked : Qt::Unchecked ); ui_progress->setCheckState( s.progress ? Qt::Checked : Qt::Unchecked ); ui_documents->setCheckState( s.documents ? Qt::Checked : Qt::Unchecked ); } } //KPlatoWork namespace diff --git a/src/workpackage/part.cpp b/src/workpackage/part.cpp index 12019249..9dda10de 100644 --- a/src/workpackage/part.cpp +++ b/src/workpackage/part.cpp @@ -1,843 +1,843 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 Torben Weis Copyright (C) 2004 - 2009 Dag Andersen Copyright (C) 2006 Raphael Langerhorst Copyright (C) 2007 Thorsten Zachmann Copyright (C) 2007 - 2009, 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. */ #include "part.h" #include "view.h" #include "factory.h" #include "mainwindow.h" #include "workpackage.h" #include "KPlatoXmlLoader.h" //NB! #include "kptglobal.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptdocuments.h" #include "kptcommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include "debugarea.h" using namespace KPlato; namespace KPlatoWork { //------------------------------- DocumentChild::DocumentChild( WorkPackage *parent) : QObject( parent ), m_doc( 0 ), m_type( Type_Unknown ), m_copy( false ), m_process( 0 ), m_editor( 0 ), m_editormodified( false ), m_filemodified( false ), m_fileSystemWatcher(new QFileSystemWatcher(this)) { } // DocumentChild::DocumentChild( KParts::ReadWritePart *editor, const QUrl &url, const Document *doc, Part *parent) // : KoDocumentChild( parent ), // m_doc( doc ), // m_type( Type_Unknown ), // m_copy( true ), // m_process( 0 ), // m_editor( editor ), // m_editormodified( false ), // m_filemodified( false ) // { // setFileInfo( url ); // if ( dynamic_cast( editor ) ) { // debugPlanWork<<"Creating Calligra doc"; // m_type = Type_Calligra; // connect( static_cast( editor ), SIGNAL(modified(bool)), this, SLOT(setModified(bool)) ); // } else { // debugPlanWork<<"Creating KParts doc"; // m_type = Type_KParts; // slotUpdateModified(); // } // } DocumentChild::~DocumentChild() { debugPlanWork; - disconnect(m_fileSystemWatcher, SIGNAL(fileChanged(QString)), this, SLOT(slotDirty(QString))); + disconnect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &DocumentChild::slotDirty); m_fileSystemWatcher->removePath( filePath() ); if ( m_type == Type_Calligra || m_type == Type_KParts ) { delete m_editor; } } WorkPackage *DocumentChild::parentPackage() const { return static_cast( parent() ); } void DocumentChild::setFileInfo( const QUrl &url ) { m_fileinfo.setFile( url.path() ); //debugPlanWork<addPath( filePath() ); } void DocumentChild::setModified( bool mod ) { debugPlanWork<isModified() != m_editormodified ) ) { setModified( m_editor->isModified() ); } - QTimer::singleShot( 500, this, SLOT(slotUpdateModified()) ); + QTimer::singleShot( 500, this, &DocumentChild::slotUpdateModified ); } bool DocumentChild::setDoc( const Document *doc ) { Q_ASSERT ( m_doc == 0 ); if ( isOpen() ) { KMessageBox::error( 0, i18n( "Document is already open:
%1", doc->url().url() ) ); return false; } m_doc = doc; QUrl url; if ( parentPackage()->newDocuments().contains( doc ) ) { url = parentPackage()->newDocuments().value( doc ); Q_ASSERT( url.isValid() ); parentPackage()->removeNewDocument( doc ); } else if ( doc->sendAs() == Document::SendAs_Copy ) { url = parentPackage()->extractFile( doc ); if ( url.url().isEmpty() ) { KMessageBox::error( 0, i18n( "Could not extract document from storage:
%1", doc->url().url() ) ); return false; } m_copy = true; } else { url = doc->url(); } if ( ! url.isValid() ) { KMessageBox::error( 0, i18n( "Invalid URL:
%1", url.url() ) ); return false; } setFileInfo( url ); return true; } bool DocumentChild::openDoc( const Document *doc, KoStore *store ) { Q_ASSERT ( m_doc == 0 ); if ( isOpen() ) { KMessageBox::error( 0, i18n( "Document is already open:
%1", doc->url().path() ) ); return false; } m_doc = doc; QUrl url; if ( doc->sendAs() == Document::SendAs_Copy ) { url = parentPackage()->extractFile( doc, store ); if ( url.url().isEmpty() ) { KMessageBox::error( 0, i18n( "Could not extract document from storage:
%1", doc->url().path() ) ); return false; } m_copy = true; } else { url = doc->url(); } if ( ! url.isValid() ) { KMessageBox::error( 0, i18n( "Invalid URL:
%1", url.url() ) ); return false; } setFileInfo( url ); return true; } bool DocumentChild::editDoc() { Q_ASSERT( m_doc != 0 ); debugPlanWork<<"file:"< %1", m_doc->url().path() ) ); return false; } if ( ! m_fileinfo.exists() ) { KMessageBox::error( 0, i18n( "File does not exist:
%1", fileName() ) ); return false; } QUrl filename = QUrl::fromLocalFile( filePath() ); const QMimeType mimetype = QMimeDatabase().mimeTypeForUrl( filename ); KService::Ptr service = KMimeTypeTrader::self()->preferredService( mimetype.name() ); bool editing = startProcess( service, filename ); if ( editing ) { m_type = Type_Other; // FIXME: try to be more specific } return editing; } bool DocumentChild::startProcess( KService::Ptr service, const QUrl &url ) { QStringList args; QList files; if ( url.isValid() ) { files << url; } if ( service ) { KIO::DesktopExecParser parser(*service, files); parser.setUrlsAreTempFiles(false); args = parser.resultingArguments(); } else { QList list; QPointer dlg = new KOpenWithDialog( list, i18n("Edit with:"), QString(), 0 ); if ( dlg->exec() == QDialog::Accepted && dlg ){ args << dlg->text(); } if ( args.isEmpty() ) { debugPlanWork<<"No executable selected"; return false; } args << url.url(); delete dlg; } debugPlanWork<setProgram( args ); connect( m_process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(slotEditFinished(int,QProcess::ExitStatus)) ); connect( m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(slotEditError(QProcess::ProcessError)) ); m_process->start(); //debugPlanWork<pid()<program(); return true; } bool DocumentChild::isModified() const { return m_editormodified; } bool DocumentChild::isFileModified() const { return m_filemodified; } void DocumentChild::slotEditFinished( int /*par*/, QProcess::ExitStatus ) { //debugPlanWork<deleteLater(); m_process = 0; } else debugPlanWork<<"Error="<removePath( filePath() ); bool ok = false; bool wasmod = m_filemodified; if ( m_type == Type_Calligra || m_type == Type_KParts ) { if ( m_editor->isModified() ) { ok = m_editor->save(); // hmmmm } else { ok = true; } } else if ( m_type == Type_Other ) { if ( isOpen() ) { warnPlanWork<<"External editor open"; } ok = true; } else { errorPlanWork<<"Unknown document type"; } if ( ok ) { debugPlanWork<<"Add to store:"<addLocalFile( filePath(), fileName() ); m_filemodified = false; if ( wasmod != m_filemodified ) { emit fileModified( m_filemodified ); } } m_fileSystemWatcher->addPath( filePath() ); return ok; } //------------------------------------ Part::Part( QWidget *parentWidget, QObject *parent, const QVariantList & /*args*/ ) : KParts::ReadWritePart( parent ), m_xmlLoader(), m_modified( false ), m_loadingFromProjectStore( false ), m_undostack( new KUndo2QStack( this ) ) { debugPlanWork; setComponentData( *Factory::aboutData() ); if ( isReadWrite() ) { setXMLFile( "calligraplanwork.rc" ); } else { setXMLFile( "calligraplanwork_readonly.rc" ); } View *v = new View( this, parentWidget, actionCollection() ); setWidget( v ); - connect( v, SIGNAL(viewDocument(KPlato::Document*)), SLOT(viewWorkpackageDocument(KPlato::Document*)) ); + connect( v, &View::viewDocument, this, &Part::viewWorkpackageDocument ); loadWorkPackages(); - connect( m_undostack, SIGNAL(cleanChanged(bool)), SLOT(setDocumentClean(bool)) ); + connect( m_undostack, &KUndo2QStack::cleanChanged, this, &Part::setDocumentClean ); } Part::~Part() { debugPlanWork; // m_config.save(); qDeleteAll( m_packageMap ); } void Part::addCommand( KUndo2Command *cmd ) { if ( cmd ) { m_undostack->push( cmd ); } } bool Part::setWorkPackage( WorkPackage *wp, KoStore *store ) { //debugPlanWork; QString id = wp->id(); if ( m_packageMap.contains( id ) ) { if ( KMessageBox::warningYesNo( 0, i18n("

The work package already exists in the projects store.

" "

Project: %1
Task: %2

" "

Do you want to update the existing package with data from the new?

", wp->project()->name(), wp->node()->name()) ) == KMessageBox::No ) { delete wp; return false; } m_packageMap[ id ]->merge( this, wp, store ); delete wp; return true; } wp->setFilePath( m_loadingFromProjectStore ? wp->fileName( this ) : localFilePath() ); m_packageMap[ id ] = wp; if ( ! m_loadingFromProjectStore ) { wp->saveToProjects( this ); } connect( wp->project(), SIGNAL(projectChanged()), wp, SLOT(projectChanged()) ); connect ( wp, SIGNAL(modified(bool)), this, SLOT(setModified(bool)) ); emit workPackageAdded( wp, indexOf( wp ) ); - connect(wp, SIGNAL(saveWorkPackage(KPlatoWork::WorkPackage*)), SLOT(saveWorkPackage(KPlatoWork::WorkPackage*))); + connect(wp, &WorkPackage::saveWorkPackage, this, &Part::saveWorkPackage); return true; } void Part::removeWorkPackage( Node *node, MacroCommand *m ) { //debugPlanWork<name(); WorkPackage *wp = findWorkPackage( node ); if ( wp == 0 ) { KMessageBox::error( 0, i18n("Remove failed. Cannot find work package") ); return; } PackageRemoveCmd *cmd = new PackageRemoveCmd( this, wp, kundo2_i18n( "Remove work package" ) ); if ( m ) { m->addCommand( cmd ); } else { addCommand( cmd ); } } void Part::removeWorkPackages( const QList &nodes ) { //debugPlanWork<name(); MacroCommand *m = new MacroCommand( kundo2_i18np( "Remove work package", "Remove work packages", nodes.count() ) ); foreach ( Node *n, nodes ) { removeWorkPackage( n, m ); } if ( m->isEmpty() ) { delete m; } else { addCommand( m ); } } void Part::removeWorkPackage( WorkPackage *wp ) { //debugPlanWork; int row = indexOf( wp ); if (row >= 0) { const QList &lst = m_packageMap.keys(); const QString &key = lst.value(row); m_packageMap.remove(key); emit workPackageRemoved(wp, row); } } void Part::addWorkPackage( WorkPackage *wp ) { //debugPlanWork; QString id = wp->id(); Q_ASSERT( ! m_packageMap.contains( id ) ); m_packageMap[ id ] = wp; emit workPackageAdded( wp, indexOf( wp ) ); } bool Part::loadWorkPackages() { m_loadingFromProjectStore = true; const QStringList lst = KoResourcePaths::findAllResources( "projects", "*.planwork", KoResourcePaths::Recursive | KoResourcePaths::NoDuplicates ); //debugPlanWork<%1" , file ) ); } } m_loadingFromProjectStore = false; return true; } bool Part::loadNativeFormatFromStore(const QString& file) { debugPlanWork<bad()) { KMessageBox::error( 0, i18n("Not a valid work package file:
%1", file) ); delete store; QApplication::restoreOverrideCursor(); return false; } const bool success = loadNativeFormatFromStoreInternal(store); delete store; return success; } bool Part::loadNativeFormatFromStoreInternal(KoStore * store) { if (store->hasFile("root")) { KoXmlDocument doc; bool ok = loadAndParse(store, "root", doc); if (ok) { ok = loadXML(doc, store); } if (!ok) { QApplication::restoreOverrideCursor(); return false; } } else { errorPlanWork << "ERROR: No maindoc.xml" << endl; KMessageBox::error( 0, i18n("Invalid document. The document does not contain 'maindoc.xml'.") ); QApplication::restoreOverrideCursor(); return false; } // if (store->hasFile("documentinfo.xml")) { // KoXmlDocument doc; // if (oldLoadAndParse(store, "documentinfo.xml", doc)) { // d->m_docInfo->load(doc); // } // } else { // //debugPlanWork <<"cannot open document info"; // delete d->m_docInfo; // d->m_docInfo = new KoDocumentInfo(this); // } bool res = completeLoading(store); QApplication::restoreOverrideCursor(); return res; } bool Part::loadAndParse(KoStore* store, const QString& filename, KoXmlDocument& doc) { //debugPlanWork <<"Trying to open" << filename; if (!store->open(filename)) { warnPlanWork << "Entry " << filename << " not found!"; KMessageBox::error( 0, i18n("Failed to open file: %1", filename) ); return false; } // Error variables for QDomDocument::setContent QString errorMsg; int errorLine, errorColumn; bool ok = doc.setContent(store->device(), &errorMsg, &errorLine, &errorColumn); store->close(); if (!ok) { errorPlanWork << "Parsing error in " << filename << "! Aborting!" << endl << " In line: " << errorLine << ", column: " << errorColumn << endl << " Error message: " << errorMsg; KMessageBox::error( 0, i18n("Parsing error in file '%1' at line %2, column %3
Error message: %4", filename , errorLine, errorColumn , QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0) ) ); return false; } return true; } bool Part::loadXML( const KoXmlDocument &document, KoStore* store ) { debugPlanWork; QString value; KoXmlElement plan = document.documentElement(); // Check if this is the right app value = plan.attribute( "mime", QString() ); if ( value.isEmpty() ) { errorPlanWork << "No mime type specified!" << endl; KMessageBox::error( 0, i18n( "Invalid document. No mimetype specified." ) ); return false; } else if ( value == "application/x-vnd.kde.kplato.work" ) { return loadKPlatoXML( document, store ); } else if ( value != "application/x-vnd.kde.plan.work" ) { errorPlanWork << "Unknown mime type " << value; KMessageBox::error( 0, i18n( "Invalid document. Expected mimetype application/x-vnd.kde.plan.work, got %1", value ) ); return false; } QString syntaxVersion = plan.attribute( "version", PLANWORK_FILE_SYNTAX_VERSION ); m_xmlLoader.setWorkVersion( syntaxVersion ); if ( syntaxVersion > PLANWORK_FILE_SYNTAX_VERSION ) { KMessageBox::ButtonCode ret = KMessageBox::warningContinueCancel( 0, i18n( "This document is a newer version than supported by PlanWork (syntax version: %1)
" "Opening it in this version of PlanWork will lose some information.", syntaxVersion ), i18n( "File-Format Mismatch" ), KGuiItem( i18n( "Continue" ) ) ); if ( ret == KMessageBox::Cancel ) { return false; } } m_xmlLoader.setVersion( plan.attribute( "plan-version", PLAN_FILE_SYNTAX_VERSION ) ); m_xmlLoader.startLoad(); WorkPackage *wp = new WorkPackage( m_loadingFromProjectStore ); wp->loadXML( plan, m_xmlLoader ); m_xmlLoader.stopLoad(); if ( ! setWorkPackage( wp, store ) ) { // rejected, so nothing changed... return true; } emit changed(); return true; } bool Part::loadKPlatoXML( const KoXmlDocument &document, KoStore* ) { debugPlanWork; QString value; KoXmlElement plan = document.documentElement(); // Check if this is the right app value = plan.attribute( "mime", QString() ); if ( value.isEmpty() ) { errorPlanWork << "No mime type specified!" << endl; KMessageBox::error( 0, i18n( "Invalid document. No mimetype specified." ) ); return false; } else if ( value != "application/x-vnd.kde.kplato.work" ) { errorPlanWork << "Unknown mime type " << value; KMessageBox::error( 0, i18n( "Invalid document. Expected mimetype application/x-vnd.kde.kplato.work, got %1", value ) ); return false; } QString syntaxVersion = plan.attribute( "version", KPLATOWORK_MAX_FILE_SYNTAX_VERSION ); m_xmlLoader.setWorkVersion( syntaxVersion ); if ( syntaxVersion > KPLATOWORK_MAX_FILE_SYNTAX_VERSION ) { KMessageBox::ButtonCode ret = KMessageBox::warningContinueCancel( 0, i18n( "This document is a newer version than supported by PlanWork (syntax version: %1)
" "Opening it in this version of PlanWork will lose some information.", syntaxVersion ), i18n( "File-Format Mismatch" ), KGuiItem( i18n( "Continue" ) ) ); if ( ret == KMessageBox::Cancel ) { return false; } } m_xmlLoader.setMimetype( value ); m_xmlLoader.setVersion( plan.attribute( "kplato-version", KPLATO_MAX_FILE_SYNTAX_VERSION ) ); m_xmlLoader.startLoad(); WorkPackage *wp = new WorkPackage( m_loadingFromProjectStore ); wp->loadKPlatoXML( plan, m_xmlLoader ); m_xmlLoader.stopLoad(); if ( ! setWorkPackage( wp ) ) { // rejected, so nothing changed... return true; } emit changed(); return true; } bool Part::completeLoading( KoStore * ) { return true; } QUrl Part::extractFile( const Document *doc ) { WorkPackage *wp = findWorkPackage( doc ); return wp == 0 ? QUrl() : wp->extractFile( doc ); } int Part::docType( const Document *doc ) const { DocumentChild *ch = findChild( doc ); if ( ch == 0 ) { return DocumentChild::Type_Unknown; } return ch->type(); } DocumentChild *Part::findChild( const Document *doc ) const { foreach ( const WorkPackage *wp, m_packageMap ) { DocumentChild *c = wp->findChild( doc ); if ( c ) { return c; } } return 0; } WorkPackage *Part::findWorkPackage( const Document *doc ) const { foreach ( const WorkPackage *wp, m_packageMap ) { if ( wp->contains( doc ) ) { return const_cast( wp ); } } return 0; } WorkPackage *Part::findWorkPackage( const DocumentChild *child ) const { foreach ( const WorkPackage *wp, m_packageMap ) { if ( wp->contains( child ) ) { return const_cast( wp ); } } return 0; } WorkPackage *Part::findWorkPackage( const Node *node ) const { return m_packageMap.value( node->projectNode()->id() + node->id() ); } bool Part::editWorkpackageDocument( const Document *doc ) { //debugPlanWork<url(); // start in any suitable application return editOtherDocument( doc ); } bool Part::editOtherDocument( const Document *doc ) { Q_ASSERT( doc != 0 ); //debugPlanWork<url(); WorkPackage *wp = findWorkPackage( doc ); if ( wp == 0 ) { KMessageBox::error( 0, i18n( "Edit failed. Cannot find a work package." ) ); return false; } return wp->addChild( this, doc ); } void Part::viewWorkpackageDocument( Document *doc ) { debugPlanWork<sendAs() == Document::SendAs_Copy ) { filename = extractFile( doc ); } else { filename = doc->url(); } // open for view viewDocument( filename ); } bool Part::removeDocument( Document *doc ) { if ( doc == 0 ) { return false; } WorkPackage *wp = findWorkPackage( doc ); if ( wp == 0 ) { return false; } return wp->removeDocument( this, doc ); } bool Part::viewDocument( const QUrl &filename ) { debugPlanWork<<"url:"<isModified() ) { saveWorkPackage( wp ); } } m_undostack->setClean(); } void Part::saveWorkPackage( WorkPackage *wp ) { wp->saveToProjects( this ); } bool Part::saveWorkPackages( bool silent ) { debugPlanWork<saveToProjects( this ); } m_undostack->setClean(); return true; } bool Part::completeSaving( KoStore */*store*/ ) { return true; } QDomDocument Part::saveXML() { debugPlanWork; return QDomDocument(); } bool Part::queryClose() { debugPlanWork; QList modifiedList; foreach ( WorkPackage *wp, m_packageMap ) { switch ( wp->queryClose( this ) ) { case KMessageBox::No: modifiedList << wp; break; case KMessageBox::Cancel: debugPlanWork<<"Cancel"; return false; } } // closeEvent calls queryClose so modified must be reset or else wps are queried all over again foreach ( WorkPackage *wp, modifiedList ) { wp->setModified( false ); } setModified( false ); return true; } bool Part::openFile() { debugPlanWork< 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 "taskcompletiondialog.h" #include "workpackage.h" #include "kptusedefforteditor.h" #include "kptcommand.h" #include "kptitemmodelbase.h" #include "kptaccountsmodel.h" // FIXME hack to get at i18n'ed header text #include #include #include #include "debugarea.h" using namespace KPlato; namespace KPlatoWork { TaskCompletionDialog::TaskCompletionDialog(WorkPackage &p, ScheduleManager *sm, QWidget *parent) : KoDialog(parent) { setCaption( i18n("Task Progress") ); setButtons( Ok|Cancel ); setDefaultButton( Ok ); showButtonSeparator( true ); m_panel = new TaskCompletionPanel( p, sm, this); setMainWidget(m_panel); enableButtonOk(false); - connect(m_panel, SIGNAL(changed(bool)), SLOT(slotChanged(bool))); + connect(m_panel, &TaskCompletionPanel::changed, this, &TaskCompletionDialog::slotChanged); } void TaskCompletionDialog::slotChanged( bool ) { enableButtonOk( true ); } KUndo2Command *TaskCompletionDialog::buildCommand() { //debugPlanWork; return m_panel->buildCommand(); } TaskCompletionPanel::TaskCompletionPanel(WorkPackage &p, ScheduleManager *sm, QWidget *parent) : QWidget(parent), m_package( &p ) { //debugPlanWork; setupUi(this); addEntryBtn->setIcon(koIcon("list-add")); removeEntryBtn->setIcon(koIcon("list-remove")); CompletionEntryItemModel *m = new CompletionEntryItemModel( this ); entryTable->setItemDelegateForColumn ( 1, new ProgressBarDelegate( this ) ); entryTable->setItemDelegateForColumn ( 2, new DurationSpinBoxDelegate( this ) ); entryTable->setItemDelegateForColumn ( 3, new DurationSpinBoxDelegate( this ) ); entryTable->setCompletionModel( m ); Task *task = qobject_cast( p.node() ); m_completion = task->completion(); started->setChecked(m_completion.isStarted()); finished->setChecked(m_completion.isFinished()); startTime->setDateTime(m_completion.startTime()); finishTime->setDateTime(m_completion.finishTime()); finishTime->setMinimumDateTime( qMax( startTime->dateTime(), QDateTime(m_completion.entryDate(), QTime(), Qt::LocalTime) ) ); scheduledEffort = p.node()->estimate()->expectedValue(); if ( m_completion.usedEffortMap().isEmpty() || task->requests().isEmpty() ) { foreach ( ResourceGroupRequest *g, task->requests().requests() ) { foreach ( ResourceRequest *r, g->resourceRequests() ) { m_completion.addUsedEffort( r->resource() ); } } } enableWidgets(); started->setFocus(); m->setManager( sm ); m->setTask( task ); Resource *r = p.project()->findResource( task->workPackage().ownerId() ); m->setSource( r, task ); entryTable->horizontalHeader()->swapSections( CompletionEntryItemModel::Property_PlannedEffort, CompletionEntryItemModel::Property_ActualAccumulated ); //FIXME when string freeze is lifted Duration pr = task->plannedEffort( r ); Duration tr = task->plannedEffort(); if ( pr == tr ) { ui_plannedFrame->hide(); } else { ui_plannedLabel->setText( m->headerData( CompletionEntryItemModel::Property_PlannedEffort, Qt::Horizontal ).toString() ); ui_labelResource->setText( r->name() ); ui_plannedResource->setText( pr.format() ); ui_labelTask->setText( Node::typeToString( Node::Type_Task, true ) ); ui_plannedTask->setText( tr.format() ); } if ( m->rowCount() > 0 ) { QModelIndex idx = m->index( m->rowCount() -1, 0 ); entryTable->scrollTo( idx ); } - connect( addEntryBtn, SIGNAL(clicked()), this, SLOT(slotAddEntry()) ); - connect( removeEntryBtn, SIGNAL(clicked()), entryTable, SLOT(removeEntry()) ); + connect( addEntryBtn, &QAbstractButton::clicked, this, &TaskCompletionPanel::slotAddEntry ); + connect( removeEntryBtn, &QAbstractButton::clicked, entryTable, &KPlato::CompletionEntryEditor::removeEntry ); - connect( entryTable, SIGNAL(rowInserted(QDate)), SLOT(slotEntryAdded(QDate)) ); - connect(entryTable, SIGNAL(changed()), SLOT(slotChanged()) ); - connect(entryTable, SIGNAL(changed()), SLOT(slotEntryChanged()) ); - connect(entryTable, SIGNAL(rowInserted(QDate)), SLOT(slotChanged()) ); - connect(entryTable, SIGNAL(rowInserted(QDate)), SLOT(slotEntryChanged()) ); - connect(entryTable, SIGNAL(rowRemoved(QDate)), SLOT(slotEntryChanged()) ); - connect(entryTable, SIGNAL(selectedItemsChanged(QItemSelection,QItemSelection)), SLOT(slotSelectionChanged(QItemSelection)) ); + connect( entryTable, &KPlato::CompletionEntryEditor::rowInserted, this, &TaskCompletionPanel::slotEntryAdded ); + connect(entryTable, &KPlato::CompletionEntryEditor::changed, this, &TaskCompletionPanel::slotChanged ); + connect(entryTable, &KPlato::CompletionEntryEditor::changed, this, &TaskCompletionPanel::slotEntryChanged ); + connect(entryTable, &KPlato::CompletionEntryEditor::rowInserted, this, &TaskCompletionPanel::slotChanged ); + connect(entryTable, &KPlato::CompletionEntryEditor::rowInserted, this, &TaskCompletionPanel::slotEntryChanged ); + connect(entryTable, &KPlato::CompletionEntryEditor::rowRemoved, this, &TaskCompletionPanel::slotEntryChanged ); + connect(entryTable, &KPlato::CompletionEntryEditor::selectedItemsChanged, this, &TaskCompletionPanel::slotSelectionChanged ); - connect(started, SIGNAL(toggled(bool)), SLOT(slotStartedChanged(bool))); - connect(started, SIGNAL(toggled(bool)), SLOT(slotChanged())); - connect(finished, SIGNAL(toggled(bool)), SLOT(slotFinishedChanged(bool))); - connect(finished, SIGNAL(toggled(bool)), SLOT(slotChanged())); + connect(started, &QAbstractButton::toggled, this, &TaskCompletionPanel::slotStartedChanged); + connect(started, &QAbstractButton::toggled, this, &TaskCompletionPanel::slotChanged); + connect(finished, &QAbstractButton::toggled, this, &TaskCompletionPanel::slotFinishedChanged); + connect(finished, &QAbstractButton::toggled, this, &TaskCompletionPanel::slotChanged); - connect(startTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); - connect(startTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotStartTimeChanged(QDateTime))); - connect(finishTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotChanged())); - connect(finishTime, SIGNAL(dateTimeChanged(QDateTime)), SLOT(slotFinishTimeChanged(QDateTime))); + connect(startTime, &QDateTimeEdit::dateTimeChanged, this, &TaskCompletionPanel::slotChanged); + connect(startTime, &QDateTimeEdit::dateTimeChanged, this, &TaskCompletionPanel::slotStartTimeChanged); + connect(finishTime, &QDateTimeEdit::dateTimeChanged, this, &TaskCompletionPanel::slotChanged); + connect(finishTime, &QDateTimeEdit::dateTimeChanged, this, &TaskCompletionPanel::slotFinishTimeChanged); removeEntryBtn->setEnabled( false ); } QSize TaskCompletionPanel::sizeHint() const { return QWidget::sizeHint().expandedTo( QSize( 610, 0 ) ); } KUndo2Command *TaskCompletionPanel::buildCommand() { MacroCommand *cmd = new MacroCommand( kundo2_i18n("Modify task completion") ); Completion &org = m_package->task()->completion(); if ( org.entrymode() != m_completion.entrymode() ) { cmd->addCommand( new ModifyCompletionEntrymodeCmd(org, m_completion.entrymode() ) ); } if ( org.isStarted() != m_completion.isStarted() ) { cmd->addCommand( new ModifyCompletionStartedCmd(org, m_completion.isStarted() ) ); } if ( org.isFinished() != m_completion.isFinished() ) { cmd->addCommand( new ModifyCompletionFinishedCmd(org, m_completion.isFinished() ) ); } if ( org.startTime() != m_completion.startTime() ) { cmd->addCommand( new ModifyCompletionStartTimeCmd(org, m_completion.startTime() ) ); } if ( org.finishTime() != m_completion.finishTime() ) { cmd->addCommand( new ModifyCompletionFinishTimeCmd(org, m_completion.finishTime() ) ); } QList orgdates = org.entries().keys(); QList m_completiondates = m_completion.entries().keys(); foreach ( const QDate &d, orgdates ) { if ( m_completiondates.contains( d ) ) { if ( m_completion.entry( d ) == org.entry( d ) ) { continue; } Completion::Entry *e = new Completion::Entry( *( m_completion.entry( d ) ) ); cmd->addCommand( new ModifyCompletionEntryCmd(org, d, e ) ); } else { cmd->addCommand( new RemoveCompletionEntryCmd(org, d ) ); } } foreach ( const QDate &d, m_completiondates ) { if ( ! orgdates.contains( d ) ) { Completion::Entry *e = new Completion::Entry( * ( m_completion.entry( d ) ) ); cmd->addCommand( new AddCompletionEntryCmd(org, d, e ) ); } } if ( cmd->isEmpty() ) { delete cmd; return 0; } return cmd; } void TaskCompletionPanel::slotChanged() { emit changed( true ); //FIXME } void TaskCompletionPanel::slotStartedChanged(bool state) { m_completion.setStarted( state ); if (state) { m_completion.setStartTime( QDateTime::currentDateTime() ); startTime->setDateTime( m_completion.startTime() ); slotCalculateEffort(); } enableWidgets(); } void TaskCompletionPanel::setFinished() { finishTime->setDateTime( QDateTime::currentDateTime() ); slotFinishTimeChanged( finishTime->dateTime() ); } void TaskCompletionPanel::slotFinishedChanged(bool state) { debugPlanWork<node()->plannedEffort() ); m_completion.addEntry( m_completion.finishTime().date(), e ); entryTable->setCompletion( &m_completion ); debugPlanWork<<"Entry added:"<model()->rowCount() - 1; QModelIndex idx = entryTable->model()->index( row, CompletionEntryItemModel::Property_Completion ); entryTable->model()->setData( idx, 100 ); } } enableWidgets(); } void TaskCompletionPanel::slotFinishTimeChanged( const QDateTime &dt ) { m_completion.setFinishTime( dt ); } void TaskCompletionPanel::slotStartTimeChanged( const QDateTime &dt ) { m_completion.setStartTime( dt ); finishTime->setMinimumDateTime( qMax( startTime->dateTime(), QDateTime(m_completion.entryDate(), QTime(), Qt::LocalTime) ) ); } void TaskCompletionPanel::slotAddEntry() { CompletionEntryItemModel *m = static_cast( entryTable->model() ); int col = KPlato::CompletionEntryItemModel::Property_UsedEffort; entryTable->addEntry(); m_completion.setEntrymode( Completion::EnterEffortPerTask ); m->setFlags( col, Qt::ItemIsEditable ); } void TaskCompletionPanel::slotEntryChanged() { finishTime->setMinimumDateTime( qMax( startTime->dateTime(), QDateTime(m_completion.entryDate(), QTime(), Qt::LocalTime) ) ); if ( ! finished->isChecked() && ! m_completion.isFinished() && m_completion.percentFinished() == 100 ) { finished->setChecked( true ); } } void TaskCompletionPanel::enableWidgets() { started->setEnabled(!finished->isChecked()); finished->setEnabled(started->isChecked()); finishTime->setEnabled(finished->isChecked()); startTime->setEnabled(started->isChecked() && !finished->isChecked()); } void TaskCompletionPanel::slotPercentFinishedChanged( int ) { slotCalculateEffort(); } void TaskCompletionPanel::slotCalculateEffort() { } void TaskCompletionPanel::slotEntryAdded( const QDate& date ) { debugPlanWork<setEnabled( !sel.isEmpty() ); } void TaskCompletionPanel::slotEditmodeChanged( int index ) { Q_UNUSED( index ); } //------------------- CompletionEntryItemModel::CompletionEntryItemModel( QObject *parent ) : KPlato::CompletionEntryItemModel( parent ), m_calculate( false ), m_resource( 0 ), m_task( 0 ) { // FIXME after string freeze is lifted CostBreakdownItemModel m; m_headers << m.headerData( 2, Qt::Horizontal ).toString(); } void CompletionEntryItemModel::setSource( Resource *resource, Task *task ) { m_resource = resource; m_task = task; setCompletion( &(task->completion()) ); } int CompletionEntryItemModel::columnCount( const QModelIndex& ) const { return 6; } QVariant CompletionEntryItemModel::actualEffort ( int row, int role ) const { Completion::Entry *e = m_completion->entry( date( row ).toDate() ); if ( e == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: { Duration v = e->totalPerformed; if ( row > 0 ) { v -= m_completion->entry( date( row - 1 ).toDate() )->totalPerformed; } //debugPlanWork<name()<<": "<totalPerformed; if ( row > 0 ) { v -= m_completion->entry( date( row - 1 ).toDate() )->totalPerformed; } //debugPlanWork<name()<<": "<( Duration::Unit_h ); case Role::Minimum: return static_cast( Duration::Unit_h ); case Role::Maximum: return static_cast( Duration::Unit_h ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); default: break; } return QVariant(); } QVariant CompletionEntryItemModel::data( const QModelIndex &idx, int role ) const { if ( idx.column() == Property_PlannedEffort && m_resource ) { switch ( role ) { case Qt::DisplayRole: { Duration v = m_task->plannedEffortTo( m_resource, date( idx.row() ).toDate() ); return v.format(); } default: return QVariant(); } } else if ( idx.column() == Property_ActualAccumulated ) { switch ( role ) { case Qt::DisplayRole: { Duration v; Completion::Entry *e = m_completion->entry( date( idx.row() ).toDate() ); if ( e ) { v = e->totalPerformed; } return v.format(); } default: return QVariant(); } } return KPlato::CompletionEntryItemModel::data( idx, role ); } bool CompletionEntryItemModel::setData( const QModelIndex &idx, const QVariant &value, int role ) { //debugPlanWork; switch ( role ) { case Qt::EditRole: { if ( idx.column() == Property_Date ) { QDate od = date( idx.row() ).toDate(); removeEntry( od ); addEntry( value.toDate() ); // emit dataChanged( idx, idx ); m_calculate = true; return true; } if ( idx.column() == Property_Completion ) { Completion::Entry *e = m_completion->entry( date( idx.row() ).toDate() ); if ( e == 0 ) { return false; } e->percentFinished = value.toInt(); if ( m_calculate && m_node && idx.row() == rowCount() - 1 ) { // calculate used/remaining Duration est = m_node->plannedEffort( id(), ECCT_EffortWork ); e->totalPerformed = est * e->percentFinished / 100; e->remainingEffort = est - e->totalPerformed; } else if ( e->percentFinished == 100 && e->remainingEffort != 0 ) { e->remainingEffort = Duration::zeroDuration; } emit dataChanged( idx, createIndex( idx.row(), 3 ) ); return true; } if ( idx.column() == Property_ActualEffort ) { Completion::Entry *e = m_completion->entry( date( idx.row() ).toDate() ); if ( e == 0 ) { return false; } m_calculate = false; Duration prev; if ( idx.row() > 0 ) { Completion::Entry *pe = m_completion->entry( date( idx.row() - 1 ).toDate() ); if ( pe ) { prev = pe->totalPerformed; } } double v( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration d = Estimate::scale( v, unit, scales() ); if ( d + prev == e->totalPerformed ) { return false; } e->totalPerformed = d + prev; emit dataChanged( idx, idx ); return true; } if ( idx.column() == Property_RemainigEffort ) { Completion::Entry *e = m_completion->entry( date( idx.row() ).toDate() ); if ( e == 0 ) { return false; } m_calculate = false; double v( value.toList()[0].toDouble() ); Duration::Unit unit = static_cast( value.toList()[1].toInt() ); Duration d = Estimate::scale( v, unit, scales() ); if ( d == e->remainingEffort ) { return false; } e->remainingEffort = d; debugPlanWork<remainingEffort.format(); emit dataChanged( idx, idx ); return true; } break; } default: break; } return false; } } //KPlatoWork namespace diff --git a/src/workpackage/taskworkpackagemodel.cpp b/src/workpackage/taskworkpackagemodel.cpp index ec76383d..0c12a982 100644 --- a/src/workpackage/taskworkpackagemodel.cpp +++ b/src/workpackage/taskworkpackagemodel.cpp @@ -1,709 +1,709 @@ /* 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. */ #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 "debugarea.h" using namespace KPlato; namespace KPlatoWork { TaskWorkPackageModel::TaskWorkPackageModel( Part *part, QObject *parent ) : ItemModelBase( parent ), m_part( part ) { - connect( part, SIGNAL(workPackageAdded(KPlato::WorkPackage*,int)), this, SLOT(addWorkPackage(KPlato::WorkPackage*,int)) ); - connect( part, SIGNAL(workPackageRemoved(KPlato::WorkPackage*,int)), this, SLOT(removeWorkPackage(KPlato::WorkPackage*,int)) ); + 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 ) { beginInsertRows( QModelIndex(), row, row ); Project *project = package->project(); endInsertRows(); if ( project ) { - connect( project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - connect( project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - connect( project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); + 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, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - connect( project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); + connect( project, &KPlato::Project::nodeAdded, this, &TaskWorkPackageModel::slotNodeInserted ); + connect( project, &KPlato::Project::nodeRemoved, this, &TaskWorkPackageModel::slotNodeRemoved ); - connect(project, SIGNAL(documentAdded(KPlato::Node*,KPlato::Document*,int)), this, SLOT(slotDocumentAdded(KPlato::Node*,KPlato::Document*,int))); - connect(project, SIGNAL(documentRemoved(KPlato::Node*,KPlato::Document*,int)), this, SLOT(slotDocumentRemoved(KPlato::Node*,KPlato::Document*,int))); - connect(project, SIGNAL(documentChanged(KPlato::Node*,KPlato::Document*,int)), this, SLOT(slotDocumentChanged(KPlato::Node*,KPlato::Document*,int))); + 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 ) { beginRemoveRows( QModelIndex(), row, row ); Project *project = package->project(); debugPlanWork<project(); if ( project ) { - disconnect( project, SIGNAL(nodeChanged(KPlato::Node*)), this, SLOT(slotNodeChanged(KPlato::Node*)) ); - disconnect( project, SIGNAL(nodeToBeAdded(KPlato::Node*,int)), this, SLOT(slotNodeToBeInserted(KPlato::Node*,int)) ); - disconnect( project, SIGNAL(nodeToBeRemoved(KPlato::Node*)), this, SLOT(slotNodeToBeRemoved(KPlato::Node*)) ); + 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, SIGNAL(nodeAdded(KPlato::Node*)), this, SLOT(slotNodeInserted(KPlato::Node*)) ); - disconnect( project, SIGNAL(nodeRemoved(KPlato::Node*)), this, SLOT(slotNodeRemoved(KPlato::Node*)) ); + disconnect( project, &KPlato::Project::nodeAdded, this, &TaskWorkPackageModel::slotNodeInserted ); + disconnect( project, &KPlato::Project::nodeRemoved, this, &TaskWorkPackageModel::slotNodeRemoved ); - disconnect(project, SIGNAL(documentAdded(KPlato::Node*,KPlato::Document*,int)), this, SLOT(slotDocumentAdded(KPlato::Node*,KPlato::Document*,int))); - disconnect(project, SIGNAL(documentRemoved(KPlato::Node*,KPlato::Document*,int)), this, SLOT(slotDocumentRemoved(KPlato::Node*,KPlato::Document*,int))); - disconnect(project, SIGNAL(documentChanged(KPlato::Node*,KPlato::Document*,int)), this, SLOT(slotDocumentChanged(KPlato::Node*,KPlato::Document*,int))); + 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_part->workPackageCount(); // == no of nodes (1 node pr wp) } Node *n = nodeForIndex( parent ); if ( n ) { //debugPlanWork<documents().count(); return n->documents().count(); } //debugPlanWork<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: return doc->typeToString( doc->type(), true ); 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" ); // After scheduling case NodeStartTime: return i18n( "Planned Start" ); case NodeEndTime: return i18n( "Planned Finish" ); case NodeAssignments: return i18n( "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" ); 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_part->indexOf( p ), 0, p ); } WorkPackage *TaskWorkPackageModel::workPackage( int index ) const { return m_part->workPackage( 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; } WorkPackage *TaskWorkPackageModel::ptrToWorkPackage( const QModelIndex &idx ) const { return qobject_cast( static_cast( idx.internalPointer() ) ); } Node *TaskWorkPackageModel::ptrToNode( const QModelIndex &idx ) const { return qobject_cast( static_cast( idx.internalPointer() ) ); } bool TaskWorkPackageModel::isNode( const QModelIndex &idx ) const { // a node index: ptr is WorkPackage* return qobject_cast( static_cast( idx.internalPointer() ) ) != 0; } bool TaskWorkPackageModel::isDocument( const QModelIndex &idx ) const { // a document index: ptr is Node* return qobject_cast( static_cast( idx.internalPointer() ) ) != 0; } } //namespace KPlato diff --git a/src/workpackage/taskworkpackageview.cpp b/src/workpackage/taskworkpackageview.cpp index 491a9281..5a1e1490 100644 --- a/src/workpackage/taskworkpackageview.cpp +++ b/src/workpackage/taskworkpackageview.cpp @@ -1,930 +1,930 @@ /* This file is part of the KDE project Copyright (C) 2007 - 2009, 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. */ #include "taskworkpackageview.h" #include "taskworkpackagemodel.h" #include "workpackage.h" #include "part.h" #include "kptglobal.h" #include "kptcommand.h" #include "kptproject.h" #include "kptschedule.h" #include "kpteffortcostmap.h" #include "kptitemviewsettup.h" #include "calligraplanworksettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "debugarea.h" using namespace KPlato; namespace KPlatoWork { TaskWorkPackageTreeView::TaskWorkPackageTreeView( Part *part, QWidget *parent ) : DoubleTreeViewBase( parent ) { setContextMenuPolicy( Qt::CustomContextMenu ); masterView()->header()->setSortIndicatorShown( true ); masterView()->header()->setSectionsClickable( true ); slaveView()->header()->setSortIndicatorShown( true ); slaveView()->header()->setSectionsClickable( true ); QSortFilterProxyModel *sf = new QSortFilterProxyModel( this ); TaskWorkPackageModel *m = new TaskWorkPackageModel( part, sf ); sf->setSourceModel( m ); setModel( sf ); //setSelectionBehavior( QAbstractItemView::SelectItems ); setSelectionMode( QAbstractItemView::SingleSelection ); setStretchLastSection( false ); createItemDelegates( m ); QList lst1; lst1 << 2 << -1; // display column 0 and 1 (NodeName and NodeType ) in left view masterView()->setDefaultColumns( QList() << 0 << 1 ); QList show; show << TaskWorkPackageModel::NodeCompleted << TaskWorkPackageModel::NodeActualEffort << TaskWorkPackageModel::NodeRemainingEffort << TaskWorkPackageModel::NodePlannedEffort << TaskWorkPackageModel::NodeStartTime << TaskWorkPackageModel::NodeActualStart << TaskWorkPackageModel::NodeEndTime << TaskWorkPackageModel::NodeActualFinish << TaskWorkPackageModel::ProjectName << TaskWorkPackageModel::ProjectManager; QList lst2; for ( int i = 0; i < m->columnCount(); ++i ) { if ( ! show.contains( i ) ) { lst2 << i; } } hideColumns( lst1, lst2 ); slaveView()->setDefaultColumns( show ); masterView()->setFocus(); debugPlanWork<taskWorkPackageView(); masterView()->header()->setSectionsClickable( true ); slaveView()->header()->setSortIndicatorShown( true ); - connect(masterView()->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(setSortOrder(int,Qt::SortOrder))); - connect(slaveView()->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(setSortOrder(int,Qt::SortOrder))); + connect(masterView()->header(), &QHeaderView::sortIndicatorChanged, this, &TaskWorkPackageTreeView::setSortOrder); + connect(slaveView()->header(), &QHeaderView::sortIndicatorChanged, this, &TaskWorkPackageTreeView::setSortOrder); masterView()->header()->setSortIndicator( TaskWorkPackageModel::NodeType, Qt::AscendingOrder ); - connect(masterView()->header(), SIGNAL(sectionMoved(int,int,int)), SIGNAL(sectionsMoved())); - connect(slaveView()->header(), SIGNAL(sectionMoved(int,int,int)), SIGNAL(sectionsMoved())); + connect(masterView()->header(), &QHeaderView::sectionMoved, this, &TaskWorkPackageTreeView::sectionsMoved); + connect(slaveView()->header(), &QHeaderView::sectionMoved, this, &TaskWorkPackageTreeView::sectionsMoved); } void TaskWorkPackageTreeView::setSortOrder( int col, Qt::SortOrder order ) { model()->sort( col, order ); } TaskWorkPackageModel *TaskWorkPackageTreeView::itemModel() const { return static_cast( static_cast( model() )->sourceModel() ); } Project *TaskWorkPackageTreeView::project() const { return itemModel()->project(); } Document *TaskWorkPackageTreeView::currentDocument() const { QSortFilterProxyModel *sf = qobject_cast( model() ); Q_ASSERT( sf ); if ( sf == 0 ) { return 0; } return itemModel()->documentForIndex( sf->mapToSource( selectionModel()->currentIndex() ) ); } Node *TaskWorkPackageTreeView::currentNode() const { QSortFilterProxyModel *sf = qobject_cast( model() ); Q_ASSERT( sf ); if ( sf == 0 ) { return 0; } return itemModel()->nodeForIndex( sf->mapToSource( selectionModel()->currentIndex() ) ); } QList TaskWorkPackageTreeView::selectedNodes() const { QList lst; QSortFilterProxyModel *sf = qobject_cast( model() ); Q_ASSERT( sf ); if ( sf == 0 ) { return lst; } foreach( const QModelIndex &idx, selectionModel()->selectedIndexes() ) { QModelIndex i = sf->mapToSource( idx ); Q_ASSERT( i.isValid() && i.model() == itemModel() ); Node *n = itemModel()->nodeForIndex( i ); if ( n && ! lst.contains( n ) ) { lst << n; } } return lst; } void TaskWorkPackageTreeView::setProject( Project *project ) { itemModel()->setProject( project ); } void TaskWorkPackageTreeView::slotActivated( const QModelIndex &index ) { debugPlanWork<source() != this || !(event->possibleActions() & Qt::MoveAction))) return; TreeViewBase::dragMoveEvent( event ); if ( ! event->isAccepted() ) { return; } //QTreeView thinks it's ok to drop event->ignore(); QModelIndex index = indexAt( event->pos() ); if ( ! index.isValid() ) { event->accept(); return; // always ok to drop on main project } Node *dn = model()->node( index ); if ( dn == 0 ) { errorPlanWork<<"no node to drop on!" return; // hmmm } switch ( dropIndicatorPosition() ) { case AboveItem: case BelowItem: //dn == sibling if ( model()->dropAllowed( dn->parentNode(), event->mimeData() ) ) { event->accept(); } break; case OnItem: //dn == new parent if ( model()->dropAllowed( dn, event->mimeData() ) ) { event->accept(); } break; default: break; }*/ } //----------------------------------- AbstractView::AbstractView( Part *part, QWidget *parent ) : QWidget( parent ), m_part( part ) { } void AbstractView::updateReadWrite( bool /*rw*/ ) { } QList AbstractView::selectedNodes() const { return QList(); } Node *AbstractView::currentNode() const { return 0; } Document *AbstractView::currentDocument() const { return 0; } void AbstractView::slotHeaderContextMenuRequested( const QPoint &pos ) { debugPlanWork; QList lst = contextActionList(); if ( ! lst.isEmpty() ) { QMenu::exec( lst, pos, lst.first() ); } } void AbstractView::slotContextMenuRequested( const QModelIndex &/*index*/, const QPoint& pos ) { return slotHeaderContextMenuRequested( pos ); } void AbstractView::slotContextMenuRequested( Node *node, const QPoint& pos ) { debugPlanWork<name()<<" :"<type() ) { case Node::Type_Task: name = "taskstatus_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } debugPlanWork<url()<<" :"<type() ) { case Document::Type_Product: name = "editdocument_popup"; break; default: name = "viewdocument_popup"; break; } debugPlanWork<setMargin( 0 ); m_view = new TaskWorkPackageTreeView( part, this ); l->addWidget( m_view ); setupGui(); - connect( itemModel(), SIGNAL(executeCommand(KUndo2Command*)), part, SLOT(addCommand(KUndo2Command*)) ); + connect( itemModel(), &KPlato::ItemModelBase::executeCommand, part, &Part::addCommand ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); + connect( m_view, &KPlato::DoubleTreeViewBase::headerContextMenuRequested, this, &TaskWorkPackageView::slotHeaderContextMenuRequested ); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), SLOT(slotSelectionChanged(QModelIndexList)) ); + connect( m_view, &KPlato::DoubleTreeViewBase::selectionChanged, this, &TaskWorkPackageView::slotSelectionChanged ); loadContext(); - connect(m_view, SIGNAL(sectionsMoved()), SLOT(sectionsMoved())); + connect(m_view, &TaskWorkPackageTreeView::sectionsMoved, this, &TaskWorkPackageView::sectionsMoved); } void TaskWorkPackageView::updateReadWrite( bool rw ) { m_view->setReadWrite( rw ); } void TaskWorkPackageView::slotSelectionChanged( const QModelIndexList &/*lst*/ ) { emit selectionChanged(); } QList TaskWorkPackageView::selectedNodes() const { return m_view->selectedNodes(); } Node *TaskWorkPackageView::currentNode() const { return m_view->currentNode(); } Document *TaskWorkPackageView::currentDocument() const { return m_view->currentDocument(); } void TaskWorkPackageView::slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ) { debugPlanWork<( m_view->model() ); Q_ASSERT( sf ); if ( sf == 0 ) { return; } QModelIndex idx = sf->mapToSource( index ); if ( ! idx.isValid() ) { slotHeaderContextMenuRequested( pos ); return; } Node *node = itemModel()->nodeForIndex( idx ); if ( node ) { return slotContextMenuRequested( node, pos ); } Document *doc = itemModel()->documentForIndex( idx ); if ( doc ) { return slotContextMenuRequested( doc, pos ); } return slotHeaderContextMenuRequested( pos ); } void TaskWorkPackageView::setupGui() { // Add the context menu actions for the view options - connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); + connect(m_view->actionSplitView(), &QAction::triggered, this, &TaskWorkPackageView::slotSplitView); addContextAction( m_view->actionSplitView() ); actionOptions = new QAction(koIcon("configure"), i18n("Configure View..."), this); - connect(actionOptions, SIGNAL(triggered(bool)), SLOT(slotOptions())); + connect(actionOptions, &QAction::triggered, this, &TaskWorkPackageView::slotOptions); addContextAction( actionOptions ); } void TaskWorkPackageView::slotSplitView() { debugPlanWork; m_view->setViewSplitMode( ! m_view->isViewSplit() ); saveContext(); } void TaskWorkPackageView::slotOptions() { debugPlanWork; QPointer dlg = new SplitItemViewSettupDialog( 0, m_view, this ); dlg->exec(); delete dlg; saveContext(); } bool TaskWorkPackageView::loadContext() { KoXmlDocument doc; doc.setContent( PlanWorkSettings::self()->taskWorkPackageView() ); KoXmlElement context = doc.namedItem( "TaskWorkPackageViewSettings" ).toElement(); if ( context.isNull() ) { debugPlanWork<<"No settings"; return false; } return m_view->loadContext( itemModel()->columnMap(), context ); } void TaskWorkPackageView::saveContext() { QDomDocument doc ( "TaskWorkPackageView" ); QDomElement context = doc.createElement( "TaskWorkPackageViewSettings" ); doc.appendChild( context ); m_view->saveContext( itemModel()->columnMap(), context ); PlanWorkSettings::self()->setTaskWorkPackageView( doc.toString() ); PlanWorkSettings::self()->save(); debugPlanWork<( idx.data( KGantt::ItemTypeRole ).toInt() ); QString txt = itemText( idx, typ ); QRectF itemRect = opt.itemRect; // painter->save(); // painter->setPen( Qt::blue ); // painter->drawRect( opt.boundingRect.adjusted( -1., -1., 1., 1. ) ); // painter->setPen( Qt::red ); // painter->drawRect( itemRect ); // painter->restore(); QRectF textRect = itemRect; if ( ! txt.isEmpty() ) { int tw = opt.fontMetrics.width( txt ) + static_cast( itemRect.height()/1.5 ); switch( opt.displayPosition ) { case KGantt::StyleOptionGanttItem::Left: textRect.adjust( -tw, 0.0, 0.0, 0.0 ); break; case KGantt::StyleOptionGanttItem::Right: textRect.adjust( 0.0, 0.0, tw, 0.0 ); break; default: break; } } painter->save(); QPen pen = defaultPen( typ ); if ( opt.state & QStyle::State_Selected ) pen.setWidth( 2*pen.width() ); painter->setPen( pen ); qreal pw = painter->pen().width()/2.; switch( typ ) { case KGantt::TypeTask: if ( itemRect.isValid() ) { pw-=1; QRectF r = itemRect; r.translate( 0., r.height()/6. ); r.setHeight( 2.*r.height()/3. ); painter->save(); painter->setBrushOrigin( itemRect.topLeft() ); painter->translate( 0.5, 0.5 ); bool normal = true; if ( showStatus ) { int state = data( idx, TaskWorkPackageModel::NodeStatus, Qt::EditRole ).toInt(); if ( state & Node::State_NotScheduled ) { painter->setBrush( m_brushes[ Brush_NotScheduled ] ); normal = false; } else if ( state & Node::State_Finished ) { painter->setBrush( m_brushes[ Brush_Finished ] ); normal = false; } else if ( state & Node::State_Started ) { if ( state & Node::State_Late ) { painter->setBrush( m_brushes[ Brush_Late ] ); normal = false; } } else { // scheduled, not started, not finished if ( state & Node::State_Late ) { painter->setBrush( m_brushes[ Brush_Late ] ); normal = false; } else if ( state & Node::State_NotReadyToStart ) { painter->setBrush( m_brushes[ Brush_NotReadyToStart ] ); normal = false; } else if ( state & Node::State_ReadyToStart ) { painter->setBrush( m_brushes[ Brush_ReadyToStart ] ); normal = false; } } } else if ( showCriticalTasks ) { bool critical = data( idx, NodeModel::NodeCritical, Qt::DisplayRole ).toBool(); if ( ! critical && showCriticalPath ) { critical = data( idx, NodeModel::NodeCriticalPath, Qt::DisplayRole ).toBool(); } if ( critical ) { QVariant br = data( idx, NodeModel::NodeCritical, Role::Foreground ); painter->setBrush( br.isValid() ? br.value() : m_criticalBrush ); normal = false; } } if ( normal ) { painter->setBrush( m_brushes[ Brush_Normal ] ); } painter->drawRect( r ); if ( showProgress ) { bool ok; qreal completion = idx.model()->data( idx, KGantt::TaskCompletionRole ).toDouble( &ok ); if ( ok ) { qreal h = r.height(); QRectF cr( r.x(), r.y()+h/4. + 1, r.width()*completion/100., h/2. - 2 ); painter->fillRect( cr, painter->pen().brush() ); } } painter->restore(); // only Left/Center/Right used const Qt::Alignment ta = (opt.displayPosition == KGantt::StyleOptionGanttItem::Left) ? Qt::AlignLeft : (opt.displayPosition == KGantt::StyleOptionGanttItem::Right) ? Qt::AlignRight : /* KGantt::StyleOptionGanttItem::Center*/ Qt::AlignCenter; painter->drawText( textRect, ta, txt ); } break; default: break; } painter->restore(); } QString GanttItemDelegate::toolTip( const QModelIndex &idx ) const { if ( !idx.isValid() || ! idx.model() ) { return QString(); } const QAbstractItemModel* model = idx.model(); if ( data( idx, TaskWorkPackageModel::NodeFinished, Qt::EditRole ).toBool() ) { // finished return xi18nc( "@info:tooltip", "Task: %1" "Actual finish: %2" "Planned finish: %3" "Status: %4" "Project: %5", model->data( idx, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeActualFinish, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeEndTime, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeStatus, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::ProjectName, Qt::DisplayRole ).toString() ); } if ( data( idx, TaskWorkPackageModel::NodeStarted, Qt::EditRole ).toBool() ) { // started return xi18nc( "@info:tooltip", "Task: %1" "Completion: %2 %" "Actual start: %3" "Planned: %4 - %5" "Status: %6" "Project: %7", model->data( idx, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeCompleted, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeActualStart, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeStartTime, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeEndTime, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeStatus, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::ProjectName, Qt::DisplayRole ).toString() ); } // Planned KGantt::StyleOptionGanttItem opt; int typ = data( idx, NodeModel::NodeType, Qt::EditRole ).toInt(); switch ( typ ) { case Node::Type_Task: return xi18nc( "@info:tooltip", "Task: %1" "Planned: %2 - %3" "Status: %4" "Project: %5", model->data( idx, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeStartTime, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeEndTime, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::NodeStatus, Qt::DisplayRole ).toString(), data( idx, TaskWorkPackageModel::ProjectName, Qt::DisplayRole ).toString() ); } return QString(); } GanttView::GanttView( Part *part, QWidget *parent ) : KPlato::GanttViewBase( parent ), m_part( part ), m_project( 0 ), m_ganttdelegate( new GanttItemDelegate( this ) ), m_itemmodel( new TaskWorkPackageModel( part, this ) ) { debugPlanWork<<"------------------- create GanttView -----------------------"; m_itemmodel->setObjectName( "Gantt model" ); graphicsView()->setItemDelegate( m_ganttdelegate ); GanttTreeView *tv = new GanttTreeView( this ); tv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); tv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); tv->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); // needed since qt 4.2 setLeftView( tv ); m_rowController = new KGantt::TreeViewRowController( tv, ganttProxyModel() ); setRowController( m_rowController ); tv->header()->setStretchLastSection( true ); KGantt::View::setModel( m_itemmodel ); QList show; show << TaskWorkPackageModel::NodeName << TaskWorkPackageModel::NodeDescription; tv->setDefaultColumns( show ); for ( int i = 0; i < m_itemmodel->columnCount(); ++i ) { if ( ! show.contains( i ) ) { tv->hideColumn( i ); } } debugPlanWork<<"mapping roles"; KGantt::ProxyModel *m = static_cast( ganttProxyModel() ); m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); // To provide correct format m->setRole( KGantt::StartTimeRole, Qt::EditRole ); // To provide correct format m->setRole( KGantt::EndTimeRole, Qt::EditRole ); // To provide correct format m->setColumn( KGantt::ItemTypeRole, TaskWorkPackageModel::NodeType ); m->setColumn( KGantt::StartTimeRole, TaskWorkPackageModel::NodeStartTime ); m->setColumn( KGantt::EndTimeRole, TaskWorkPackageModel::NodeEndTime ); m->setColumn( KGantt::TaskCompletionRole, TaskWorkPackageModel::NodeCompleted ); debugPlanWork<<"roles mapped"; KGantt::DateTimeGrid *g = static_cast( grid() ); g->setDayWidth( 30 ); // TODO: extend QLocale/KGantt to support formats for hourly time display // see bug #349030 // removed custom code here for ( int i = 0; i < part->workPackageCount(); ++i ) { updateDateTimeGrid( part->workPackage( i ) ); } - connect( m_itemmodel, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(slotRowsInserted(QModelIndex,int,int))); - connect( m_itemmodel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(slotRowsRemoved(QModelIndex,int,int))); + connect( m_itemmodel, &QAbstractItemModel::rowsInserted, this, &GanttView::slotRowsInserted); + connect( m_itemmodel, &QAbstractItemModel::rowsRemoved, this, &GanttView::slotRowsRemoved); - connect(tv, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), this, SIGNAL(contextMenuRequested(QModelIndex,QPoint))); - connect(tv, SIGNAL(headerContextMenuRequested(QPoint)), this, SIGNAL(headerContextMenuRequested(QPoint))); + connect(tv, &KPlato::TreeViewBase::contextMenuRequested, this, &GanttView::contextMenuRequested); + connect(tv, &KPlato::TreeViewBase::headerContextMenuRequested, this, &GanttView::headerContextMenuRequested); - connect(tv->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + connect(tv->selectionModel(), &QItemSelectionModel::selectionChanged, this, &GanttView::slotSelectionChanged); - connect(tv->header(), SIGNAL(sectionMoved(int,int,int)), SIGNAL(sectionsMoved())); + connect(tv->header(), &QHeaderView::sectionMoved, this, &GanttView::sectionsMoved); } GanttView::~GanttView() { delete m_rowController; } void GanttView::slotSelectionChanged( const QItemSelection &selected, const QItemSelection& ) { emit selectionChanged( selected.indexes() ); } void GanttView::slotRowsInserted( const QModelIndex &parent, int start, int end ) { debugPlanWork<workPackage( i ) ); } } } void GanttView::slotRowsRemoved( const QModelIndex &/*parent*/, int /*start*/, int /*end*/ ) { KGantt::DateTimeGrid *g = static_cast( grid() ); g->setStartDateTime( QDateTime() ); for ( int i = 0; i < m_part->workPackageCount(); ++i ) { updateDateTimeGrid( m_part->workPackage( i ) ); } } void GanttView::updateDateTimeGrid( WorkPackage *wp ) { debugPlanWork<project() || ! wp->project()->childNode( 0 ) ) { return; } Task *task = static_cast( wp->project()->childNode( 0 ) ); DateTime st = task->startTime(); if ( ! st.isValid() && task->completion().startTime().isValid() ) { st = qMin( st, task->completion().startTime() ); } if ( ! st.isValid() ) { return; } KGantt::DateTimeGrid *g = static_cast( grid() ); QDateTime gst = g->startDateTime(); if ( ! gst.isValid() || gst > st ) { st.setTime(QTime(0, 0, 0, 0)); g->setStartDateTime( st ); } } TaskWorkPackageModel *GanttView::itemModel() const { return m_itemmodel; } void GanttView::setProject( Project *project ) { itemModel()->setProject( project ); m_project = project; } QList GanttView::selectedNodes() const { QList nodes; foreach( const QModelIndex &idx, treeView()->selectionModel()->selectedRows() ) { nodes << itemModel()->nodeForIndex( idx ); } return nodes; } Node *GanttView::currentNode() const { return itemModel()->nodeForIndex( treeView()->selectionModel()->currentIndex() ); } bool GanttView::loadContext( const KoXmlElement &context ) { KoXmlElement e = context.namedItem( "itemview" ).toElement(); if ( ! e.isNull() ) { treeView()->loadContext( itemModel()->columnMap(), e ); } e = context.namedItem( "ganttview" ).toElement(); if ( ! e.isNull() ) { KPlato::GanttViewBase::loadContext( e ); } return true; } void GanttView::saveContext( QDomElement &context ) const { QDomElement e = context.ownerDocument().createElement( "itemview" ); context.appendChild( e ); treeView()->saveContext( itemModel()->columnMap(), e ); e = context.ownerDocument().createElement( "ganttview" ); context.appendChild( e ); KPlato::GanttViewBase::saveContext( e ); } //----------------------------------- TaskWPGanttView::TaskWPGanttView( Part *part, QWidget *parent ) : AbstractView( part, parent ) { debugPlanWork<<"-------------------- creating TaskWPGanttView -------------------"; QVBoxLayout * l = new QVBoxLayout( this ); l->setMargin( 0 ); m_view = new GanttView( part, this ); l->addWidget( m_view ); setupGui(); - connect(itemModel(), SIGNAL(executeCommand(KUndo2Command*)), part, SLOT(addCommand(KUndo2Command*))); + connect(itemModel(), &KPlato::ItemModelBase::executeCommand, part, &Part::addCommand); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint)), SLOT(slotContextMenuRequested(QModelIndex,QPoint))); - connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint))); + connect( m_view, &GanttView::headerContextMenuRequested, this, &TaskWPGanttView::slotHeaderContextMenuRequested); - connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), SLOT(slotSelectionChanged(QModelIndexList))); + connect( m_view, &GanttView::selectionChanged, this, &TaskWPGanttView::slotSelectionChanged); - connect(m_view, SIGNAL(sectionsMoved()), SLOT(sectionsMoved())); + connect(m_view, &GanttView::sectionsMoved, this, &TaskWPGanttView::sectionsMoved); } void TaskWPGanttView::slotSelectionChanged( const QModelIndexList& /*lst*/ ) { emit selectionChanged(); } QList TaskWPGanttView::selectedNodes() const { return m_view->selectedNodes(); } Node *TaskWPGanttView::currentNode() const { return m_view->currentNode(); } void TaskWPGanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint& pos ) { debugPlanWork<nodeForIndex( idx ); if ( node ) { return slotContextMenuRequested( node, pos ); } Document *doc = itemModel()->documentForIndex( idx ); if ( doc ) { return slotContextMenuRequested( doc, pos ); } return slotHeaderContextMenuRequested( pos ); } void TaskWPGanttView::setupGui() { actionOptions = new QAction(koIcon("configure"), i18n("Configure View..."), this); - connect(actionOptions, SIGNAL(triggered(bool)), SLOT(slotOptions())); + connect(actionOptions, &QAction::triggered, this, &TaskWPGanttView::slotOptions); addContextAction( actionOptions ); } void TaskWPGanttView::slotOptions() { debugPlanWork; QPointer dlg = new ItemViewSettupDialog( 0, m_view->treeView(), true, this ); dlg->exec(); delete dlg; saveContext(); } bool TaskWPGanttView::loadContext() { KoXmlDocument doc; doc.setContent( PlanWorkSettings::self()->taskWPGanttView() ); KoXmlElement context = doc.namedItem( "TaskWPGanttViewSettings" ).toElement(); if ( context.isNull() ) { debugPlanWork<<"No settings"; return false; } return m_view->loadContext( context ); } void TaskWPGanttView::saveContext() { QDomDocument doc ( "TaskWPGanttView" ); QDomElement context = doc.createElement( "TaskWPGanttViewSettings" ); doc.appendChild( context ); m_view->saveContext( context ); PlanWorkSettings::self()->setTaskWPGanttView( doc.toString() ); PlanWorkSettings::self()->save(); debugPlanWork< Copyright (C) 2002 - 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. */ #include "view.h" #include "mainwindow.h" #include "taskworkpackageview.h" #include "workpackage.h" #include "packagesettings.h" #include "taskcompletiondialog.h" #include "calligraplanworksettings.h" #include "kpttaskeditor.h" #include "kpttaskdescriptiondialog.h" #include "kptcommonstrings.h" #include "KoDocumentInfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "part.h" #include "factory.h" #include "kptviewbase.h" #include "kptdocumentseditor.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptcommand.h" #include "kptdocuments.h" #include "kpttaskprogressdialog.h" #include "kptcalendar.h" #include #include "debugarea.h" namespace KPlatoWork { View::View( Part *part, QWidget *parent, KActionCollection *collection ) : QStackedWidget( parent ), m_part( part ), m_scheduleActionGroup( new QActionGroup( this ) ), m_manager( 0 ) { m_readWrite = part->isReadWrite(); debugPlanWork<addAction("package_remove_selected", actionRemoveSelectedPackages ); - connect( actionRemoveSelectedPackages, SIGNAL(triggered(bool)), SLOT(slotRemoveSelectedPackages()) ); + connect( actionRemoveSelectedPackages, &QAction::triggered, this, &View::slotRemoveSelectedPackages ); actionRemoveCurrentPackage = new QAction(koIcon("edit-delete"), i18n("Remove Package"), this); collection->addAction("package_remove_current", actionRemoveCurrentPackage ); - connect( actionRemoveCurrentPackage, SIGNAL(triggered(bool)), SLOT(slotRemoveCurrentPackage()) ); + connect( actionRemoveCurrentPackage, &QAction::triggered, this, &View::slotRemoveCurrentPackage ); actionViewList = new QAction(koIcon("view-list-tree"), i18n("List"), this); actionViewList->setToolTip( i18nc( "@info:tooltip", "Select task list" ) ); collection->addAction("view_list", actionViewList ); - connect( actionViewList, SIGNAL(triggered(bool)), SLOT(slotViewList()) ); + connect( actionViewList, &QAction::triggered, this, &View::slotViewList ); actionViewGantt = new QAction(koIcon("view-time-schedule"), i18n("Gantt"), this); actionViewGantt->setToolTip( i18nc( "@info:tooltip", "Select timeline" ) ); collection->addAction("view_gantt", actionViewGantt ); - connect( actionViewGantt, SIGNAL(triggered(bool)), SLOT(slotViewGantt()) ); + connect( actionViewGantt, &QAction::triggered, this, &View::slotViewGantt ); // actionTaskProgress = new QAction(koIcon("document-edit"), i18n("Progress..."), this); // collection->addAction("task_progress", actionTaskProgress ); // connect( actionTaskProgress, SIGNAL(triggered(bool)), SLOT(slotTaskProgress()) ); //------ Settings actionConfigure = new QAction(koIcon("configure"), i18n("Configure PlanWork..."), this); collection->addAction("configure", actionConfigure ); - connect( actionConfigure, SIGNAL(triggered(bool)), SLOT(slotConfigure()) ); + connect( actionConfigure, &QAction::triggered, this, &View::slotConfigure ); //------ Popups actionEditDocument = new QAction(koIcon("document-edit"), i18n("Edit..."), this); collection->addAction("edit_document", actionEditDocument ); connect( actionEditDocument, SIGNAL(triggered(bool)), SLOT(slotEditDocument()) ); actionViewDocument = new QAction(koIcon("document-preview"), i18nc( "@verb", "View..."), this); collection->addAction("view_document", actionViewDocument ); - connect( actionViewDocument, SIGNAL(triggered(bool)), SLOT(slotViewDocument()) ); + connect( actionViewDocument, &QAction::triggered, this, &View::slotViewDocument ); // FIXME remove UndoText::removeDocument() when string freeze is lifted actionRemoveDocument = new QAction(koIcon("list-remove"), UndoText::removeDocument().toString(), this); collection->addAction("remove_document", actionRemoveDocument ); - connect( actionRemoveDocument, SIGNAL(triggered(bool)), SLOT(slotRemoveDocument()) ); + connect( actionRemoveDocument, &QAction::triggered, this, &View::slotRemoveDocument ); actionSendPackage = new QAction(koIcon("mail-send"), i18n("Send Package..."), this); collection->addAction("edit_sendpackage", actionSendPackage ); - connect( actionSendPackage, SIGNAL(triggered(bool)), SLOT(slotSendPackage()) ); + connect( actionSendPackage, &QAction::triggered, this, &View::slotSendPackage ); actionPackageSettings = new QAction(koIcon("document-properties"), i18n("Package Settings..."), this); collection->addAction("edit_packagesettings", actionPackageSettings ); - connect( actionPackageSettings, SIGNAL(triggered(bool)), SLOT(slotPackageSettings()) ); + connect( actionPackageSettings, &QAction::triggered, this, &View::slotPackageSettings ); actionTaskCompletion = new QAction(koIcon("document-edit"), i18n("Edit Progress..."), this); collection->addAction("task_progress", actionTaskCompletion ); - connect( actionTaskCompletion, SIGNAL(triggered(bool)), SLOT(slotTaskCompletion()) ); + connect( actionTaskCompletion, &QAction::triggered, this, &View::slotTaskCompletion ); actionViewDescription = new QAction(/*koIcon("document_view"),*/ i18n("View Description..."), this); collection->addAction("task_description", actionViewDescription ); - connect( actionViewDescription, SIGNAL(triggered(bool)), SLOT(slotTaskDescription()) ); + connect( actionViewDescription, &QAction::triggered, this, &View::slotTaskDescription ); updateReadWrite( m_readWrite ); //debugPlanWork<<" end"; loadContext(); slotCurrentChanged( currentIndex() ); - connect( this, SIGNAL(currentChanged(int)), SLOT(slotCurrentChanged(int)) ); + connect( this, &QStackedWidget::currentChanged, this, &View::slotCurrentChanged ); slotSelectionChanged(); } View::~View() { saveContext(); } void View::slotCurrentChanged( int index ) { actionViewList->setEnabled( index != 0 ); actionViewGantt->setEnabled( index != 1 ); saveContext(); } void View::slotViewList() { debugPlanWork; setCurrentIndex( 0 ); } void View::slotViewGantt() { debugPlanWork; setCurrentIndex( 1 ); } void View::createViews() { QWidget *v = createTaskWorkPackageView(); addWidget( v ); v = createGanttView(); addWidget( v ); } TaskWorkPackageView *View::createTaskWorkPackageView() { TaskWorkPackageView *v = new TaskWorkPackageView( part(), this ); - connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); + connect( v, &AbstractView::requestPopupMenu, this, &View::slotPopupMenu ); - connect( v, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()) ); + connect( v, &AbstractView::selectionChanged, this, &View::slotSelectionChanged ); v->updateReadWrite( m_readWrite ); v->loadContext(); return v; } TaskWPGanttView *View::createGanttView() { TaskWPGanttView *v = new TaskWPGanttView( part(), this ); - connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); + connect( v, &AbstractView::requestPopupMenu, this, &View::slotPopupMenu ); - connect( v, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()) ); + connect( v, &AbstractView::selectionChanged, this, &View::slotSelectionChanged ); v->updateReadWrite( m_readWrite ); v->loadContext(); return v; } void View::setupPrinter( QPrinter &/*printer*/, QPrintDialog &/*printDialog */) { //debugPlanWork; } void View::print( QPrinter &/*printer*/, QPrintDialog &/*printDialog*/ ) { } void View::slotSelectionChanged() { bool enable = ! currentView()->selectedNodes().isEmpty(); actionRemoveSelectedPackages->setEnabled( enable ); actionRemoveCurrentPackage->setEnabled( enable ); } void View::slotEditCut() { //debugPlanWork; } void View::slotEditCopy() { //debugPlanWork; } void View::slotEditPaste() { //debugPlanWork; } void View::slotProgressChanged( int ) { } void View::slotConfigure() { } ScheduleManager *View::currentScheduleManager() const { return 0; // atm we always work with default manager } void View::updateReadWrite( bool readwrite ) { debugPlanWork<"<setEnabled( readwrite ); emit sigUpdateReadWrite( readwrite ); } Part *View::part() const { return m_part; } void View::slotPopupMenu( const QString& name, const QPoint & pos ) { Q_ASSERT( m_part->factory() ); if ( m_part->factory() == 0 ) { return; } QMenu *menu = ( ( QMenu* ) m_part->factory() ->container( name, m_part ) ); if ( menu == 0 ) { return; } QList lst; AbstractView *v = currentView(); if ( v ) { lst = v->contextActionList(); debugPlanWork<addSeparator(); foreach ( QAction *a, lst ) { menu->addAction( a ); } } } menu->exec( pos ); foreach ( QAction *a, lst ) { menu->removeAction( a ); } } bool View::loadContext() { debugPlanWork; setCurrentIndex( PlanWorkSettings::self()->currentView() ); return true; } void View::saveContext() const { debugPlanWork; PlanWorkSettings::self()->setCurrentView( currentIndex() ); PlanWorkSettings::self()->save(); } void View::slotEditDocument() { slotEditDocument( currentDocument() ); } void View::slotEditDocument( Document *doc ) { debugPlanWork<type() != Document::Type_Product ) { KMessageBox::error( 0, i18n( "This file is not editable" ) ); return; } part()->editWorkpackageDocument( doc ); } void View::slotViewDocument() { emit viewDocument( currentDocument() ); } void View::slotRemoveDocument() { part()->removeDocument( currentDocument() ); } void View::slotPackageSettings() { WorkPackage *wp = part()->findWorkPackage( currentNode() ); if ( wp == 0 ) { return; } QPointer dia = new PackageSettingsDialog( *wp, this ); if ( dia->exec() == QDialog::Accepted && dia ) { KUndo2Command *cmd = dia->buildCommand(); if ( cmd ) { debugPlanWork; part()->addCommand( cmd ); } } delete dia; } void View::slotSendPackage() { Node *node = currentNode(); if ( node == 0 ) { KMessageBox::error(0, i18n("No work package is selected" ) ); return; } debugPlanWork<name(); WorkPackage *wp = part()->findWorkPackage( node ); if ( wp == 0 ) { KMessageBox::error(0, i18n("Cannot find work package" ) ); return; } /* if ( wp->isModified() ) { int r = KMessageBox::questionYesNoCancel( 0, i18n("This work package has been modified.\nDo you want to save it before sending?" ), node->name() ); switch ( r ) { case KMessageBox::Cancel: return; case KMessageBox::Yes: wp->saveToProjects( part() ); break; default: break; } }*/ QTemporaryFile temp(QDir::tempPath() + QLatin1String("/calligraplanwork_XXXXXX") + QLatin1String( ".planwork" )); temp.setAutoRemove( false ); if ( ! temp.open() ) { KMessageBox::error( 0, i18n("Could not open temporary file. Sending is aborted." ) ); return; } bool wasmodified = wp->isModified(); wp->saveNativeFormat( part(), temp.fileName() ); wp->setModified( wasmodified ); QStringList attachURLs; attachURLs << temp.fileName(); QString to = node->projectNode()->leader(); QString cc; QString bcc; QString subject = i18n( "Work Package: %1", node->name() ); QString body = node->projectNode()->name(); QString messageFile; KToolInvocation::invokeMailer( to, cc, bcc, subject, body, messageFile, attachURLs ); } void View::slotTaskDescription() { Task *node = qobject_cast( currentNode() ); if ( node == 0 ) { return; } QPointer dlg = new TaskDescriptionDialog( *node, this, true ); dlg->exec(); delete dlg; } AbstractView *View::currentView() const { return qobject_cast( currentWidget() ); } Node *View::currentNode() const { AbstractView *v = currentView(); return v ? v->currentNode() : 0; } Document *View::currentDocument() const { AbstractView *v = currentView(); return v ? v->currentDocument() : 0; } void View::slotTaskProgress() { debugPlanWork; Task *n = qobject_cast( currentNode() ); if ( n == 0 ) { return; } StandardWorktime *w = qobject_cast( n->projectNode() )->standardWorktime(); QPointer dlg = new TaskProgressDialog( *n, currentScheduleManager(), w, this ); if ( dlg->exec() == QDialog::Accepted && dlg ) { KUndo2Command *cmd = dlg->buildCommand(); if ( cmd ) { cmd->redo(); //FIXME m_part->addCommand( cmd ); } } } void View::slotTaskCompletion() { debugPlanWork; WorkPackage *wp = m_part->findWorkPackage( currentNode() ); if ( wp == 0 ) { return; } QPointer dlg = new TaskCompletionDialog( *wp, currentScheduleManager(), this ); if ( dlg->exec() == QDialog::Accepted && dlg ) { KUndo2Command *cmd = dlg->buildCommand(); if ( cmd ) { m_part->addCommand( cmd ); } } delete dlg; } void View::slotRemoveSelectedPackages() { debugPlanWork; QList lst = currentView()->selectedNodes(); if ( lst.isEmpty() ) { return; } m_part->removeWorkPackages( lst ); } void View::slotRemoveCurrentPackage() { debugPlanWork; Node *n = currentNode(); if ( n == 0 ) { return; } m_part->removeWorkPackage( n ); } } //KPlatoWork namespace diff --git a/src/workpackage/workpackage.cpp b/src/workpackage/workpackage.cpp index 2399be7d..d031cc2e 100644 --- a/src/workpackage/workpackage.cpp +++ b/src/workpackage/workpackage.cpp @@ -1,821 +1,821 @@ /* This file is part of the KDE project Copyright (C) 2009, 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. */ #include "workpackage.h" #include "KPlatoXmlLoader.h" //NOTE: this file should probably be moved #include "part.h" #include "kptglobal.h" #include "kptnode.h" #include "kptproject.h" #include "kptdocuments.h" #include "kptcommand.h" #include "kptxmlloaderobject.h" #include "kptconfigbase.h" #include "kptcommonstrings.h" #include #include #include #include #include #include #include #include #include #include #include "debugarea.h" using namespace KPlato; namespace KPlatoWork { WorkPackage::WorkPackage( bool fromProjectStore ) : m_project( new Project() ), m_fromProjectStore( fromProjectStore ), m_modified( false) { m_project->setConfig( &m_config ); } WorkPackage::WorkPackage( Project *project, bool fromProjectStore ) : m_project( project ), m_fromProjectStore( fromProjectStore ), m_modified( false) { Q_ASSERT( project ); Q_ASSERT ( project->childNode( 0 ) ); m_project->setConfig( &m_config ); if ( ! project->scheduleManagers().isEmpty() ) { // should be only one manager, so just get the first const QList &lst = m_project->scheduleManagers(); project->setCurrentSchedule(lst.first()->scheduleId()); } - connect( project, SIGNAL(projectChanged()), this, SLOT(projectChanged()) ); + connect( project, &KPlato::Project::projectChanged, this, &WorkPackage::projectChanged ); } WorkPackage::~WorkPackage() { delete m_project; qDeleteAll( m_childdocs ); } void WorkPackage::setSettings( const WorkPackageSettings &settings ) { if ( m_settings != settings ) { m_settings = settings; setModified( true ); } } //TODO find a way to know when changes are undone void WorkPackage::projectChanged() { debugPlanWork; setModified( true ); } bool WorkPackage::addChild( Part */*part*/, const Document *doc ) { DocumentChild *ch = findChild( doc ); if ( ch ) { if ( ch->isOpen() ) { KMessageBox::error( 0, i18n( "Document is already open" ) ); return false; } } else { ch = new DocumentChild( this ); if ( ! ch->setDoc( doc ) ) { delete ch; return false; } } if ( ! ch->editDoc() ) { delete ch; return false; } if ( ! m_childdocs.contains( ch ) ) { m_childdocs.append( ch ); - connect( ch, SIGNAL(fileModified(bool)), this, SLOT(slotChildModified(bool)) ); + connect( ch, &DocumentChild::fileModified, this, &WorkPackage::slotChildModified ); } return true; } void WorkPackage::slotChildModified( bool mod ) { debugPlanWork<documents().contains( doc ) : false; } DocumentChild *WorkPackage::findChild( const Document *doc ) const { foreach ( DocumentChild *c, m_childdocs ) { if ( c->doc() == doc ) { return c; } } return 0; } bool WorkPackage::loadXML( const KoXmlElement &element, XMLLoaderObject &status ) { bool ok = false; KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); debugPlanWork<load( e, status ) ) ) { status.addMsg( XMLLoaderObject::Errors, "Loading of work package failed" ); KMessageBox::error( 0, i18n( "Failed to load project: %1" , m_project->name() ) ); } } } if ( ok ) { KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); debugPlanWork<( m_project->childNode( 0 ) ); t->workPackage().setOwnerName( e.attribute( "owner" ) ); t->workPackage().setOwnerId( e.attribute( "owner-id" ) ); Resource *r = m_project->findResource( t->workPackage().ownerId() ); if ( r == 0 ) { debugPlanWork<<"Cannot find resource id!!"<workPackage().ownerId()<workPackage().ownerName(); } debugPlanWork<<"is this me?"<workPackage().ownerName(); KoXmlNode ch = e.firstChild(); for ( ; ! ch.isNull(); ch = ch.nextSibling() ) { if ( ! ch.isElement() ) { continue; } KoXmlElement el = ch.toElement(); debugPlanWork<scheduleManagers().isEmpty() ) { // should be only one manager const QList &lst = m_project->scheduleManagers(); m_project->setCurrentSchedule(lst.first()->scheduleId()); } return ok; } bool WorkPackage::loadKPlatoXML( const KoXmlElement &element, XMLLoaderObject &status ) { bool ok = false; KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); debugPlanWork<name() ) ); } } } if ( ok ) { KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); debugPlanWork<( m_project->childNode( 0 ) ); t->workPackage().setOwnerName( e.attribute( "owner" ) ); t->workPackage().setOwnerId( e.attribute( "owner-id" ) ); Resource *r = m_project->findResource( t->workPackage().ownerId() ); if ( r == 0 ) { debugPlanWork<<"Cannot find resource id!!"<workPackage().ownerId()<workPackage().ownerName(); } debugPlanWork<<"is this me?"<workPackage().ownerName(); KoXmlNode ch = e.firstChild(); for ( ; ! ch.isNull(); ch = ch.nextSibling() ) { if ( ! ch.isElement() ) { continue; } KoXmlElement el = ch.toElement(); debugPlanWork<scheduleManagers().isEmpty() ) { // should be only one manager const QList &lst = m_project->scheduleManagers(); m_project->setCurrentSchedule(lst.first()->scheduleId()); } return ok; } bool WorkPackage::saveToStream( QIODevice * dev ) { QDomDocument doc = saveXML(); // Save to buffer QByteArray s = doc.toByteArray(); // utf8 already dev->open(QIODevice::WriteOnly); int nwritten = dev->write(s.data(), s.size()); if (nwritten != (int)s.size()) warnPlanWork << "wrote " << nwritten << "- expected" << s.size(); return nwritten == (int)s.size(); } bool WorkPackage::saveNativeFormat( Part */*part*/, const QString &path ) { if ( path.isEmpty() ) { KMessageBox::error( 0, i18n("Cannot save to empty filename") ); return false; } debugPlanWork<name()<bad()) { KMessageBox::error( 0, i18n("Could not create the file for saving") ); delete store; return false; } if (store->open("root")) { KoStoreDevice dev(store); if ( ! saveToStream(&dev) || ! store->close() ) { debugPlanWork << "saveToStream failed"; delete store; return false; } } else { KMessageBox::error( 0, i18n("Not able to write '%1'. Partition full?", QString("maindoc.xml") ) ); delete store; return false; } if (!completeSaving(store)) { delete store; return false; } if (!store->finalize()) { delete store; return false; } // Success delete store; m_modified = false; return true; } bool WorkPackage::completeSaving( KoStore *store ) { debugPlanWork; KoStore *oldstore = KoStore::createStore( filePath(), KoStore::Read, "", KoStore::Zip ); if ( oldstore->bad() ) { KMessageBox::error( 0, i18n( "Failed to open store:\n %1", filePath() ) ); return false; } if (oldstore->hasFile( "documentinfo.xml" ) ) { copyFile( oldstore, store, "documentinfo.xml" ); } if (oldstore->hasFile( "preview.png" ) ) { copyFile( oldstore, store, "preview.png" ); } // First get all open documents debugPlanWork<saveToStore( store ) ) { } } // Then get new files foreach ( const Document *doc, node()->documents().documents() ) { if ( m_newdocs.contains( doc ) ) { store->addLocalFile( m_newdocs[ doc ].path(), doc->url().fileName() ); m_newdocs.remove( doc ); // TODO remove temp file ?? } } // Then get files from the old store copied to the new store foreach ( Document *doc, node()->documents().documents() ) { if ( doc->sendAs() != Document::SendAs_Copy ) { continue; } if ( ! store->hasFile( doc->url().fileName() ) ) { copyFile( oldstore, store, doc->url().fileName() ); } } return true; } QString WorkPackage::fileName( const Part *part ) const { Q_UNUSED(part); if ( m_project == 0 ) { warnPlanWork<<"No project in this package"; return QString(); } Node *n = node(); if ( n == 0 ) { warnPlanWork<<"No node in this project"; return QString(); } QString projectName = m_project->name().remove( ' ' ); // FIXME: workaround: KoResourcePaths::saveLocation( "projects", projectName + '/' ); const QString path = KoResourcePaths::saveLocation( "appdata", "projects/" + projectName + '/' ); QString wpName = QString( n->name().remove( ' ' ) + '_' + n->id() + ".planwork" ); return path + wpName; } void WorkPackage::removeFile() { QFile file( m_filePath ); if ( ! file.exists() ) { warnPlanWork<<"No project in this package"; return; } file.remove(); } void WorkPackage::saveToProjects( Part *part ) { debugPlanWork; QString path = fileName( part ); debugPlanWork<name(); if ( saveNativeFormat( part, path ) ) { m_fromProjectStore = true; m_filePath = path; } else { KMessageBox::error( 0, i18n( "Cannot save to projects store:\n%1" , path ) ); } return; } bool WorkPackage::isModified() const { if ( m_modified ) { return true; } foreach ( DocumentChild *ch, m_childdocs ) { if ( ch->isModified() || ch->isFileModified() ) { return true; } } return false; } Node *WorkPackage::node() const { return m_project == 0 ? 0 : m_project->childNode( 0 ); } Task *WorkPackage::task() const { Task *task = qobject_cast( node() ); Q_ASSERT( task ); return task; } bool WorkPackage::removeDocument( Part *part, Document *doc ) { Node *n = node(); if ( n == 0 ) { return false; } part->addCommand( new DocumentRemoveCmd( n->documents(), doc, UndoText::removeDocument() ) ); return true; } bool WorkPackage::copyFile( KoStore *from, KoStore *to, const QString &filename ) { QByteArray data; if ( ! from->extractFile( filename , data ) ) { KMessageBox::error( 0, i18n( "Failed read file:\n %1", filename ) ); return false; } if ( ! to->addDataToFile( data, filename ) ) { KMessageBox::error( 0, i18n( "Failed write file:\n %1", filename ) ); return false; } debugPlanWork<<"Copied file:"<( node() ); if ( t ) { wp.setAttribute( "owner", t->workPackage().ownerName() ); wp.setAttribute( "owner-id", t->workPackage().ownerId() ); } doc.appendChild( wp ); m_project->save( doc ); return document; } void WorkPackage::merge( Part *part, const WorkPackage *wp, KoStore *store ) { debugPlanWork; const Node *from = wp->node(); Node *to = node(); MacroCommand *m = new MacroCommand( kundo2_i18n( "Merge data" ) ); if ( to->name() != from->name() ) { m->addCommand( new NodeModifyNameCmd( *to, from->name() ) ); } if ( to->description() != from->description() ) { m->addCommand( new NodeModifyDescriptionCmd( *to, from->description() ) ); } if ( to->startTime() != from->startTime() && from->startTime().isValid() ) { m->addCommand( new NodeModifyStartTimeCmd( *to, from->startTime() ) ); } if ( to->endTime() != from->endTime() && from->endTime().isValid() ) { m->addCommand( new NodeModifyEndTimeCmd( *to, from->endTime() ) ); } if ( to->leader() != from->leader() ) { m->addCommand( new NodeModifyLeaderCmd( *to, from->leader() ) ); } if ( from->type() == Node::Type_Task && from->type() == Node::Type_Task ) { if ( static_cast( to )->workPackage().ownerId() != static_cast( from )->workPackage().ownerId() ) { debugPlanWork<<"merge:"<<"different owners"<( from )->workPackage().ownerName()<( to )->workPackage().ownerName(); if ( static_cast( to )->workPackage().ownerId().isEmpty() ) { //TODO cmd static_cast( to )->workPackage().setOwnerId( static_cast( from )->workPackage().ownerId() ); static_cast( to )->workPackage().setOwnerName( static_cast( from )->workPackage().ownerName() ); } } foreach ( Document *doc, from->documents().documents() ) { Document *org = to->documents().findDocument( doc->url() ); if ( org ) { // TODO: also handle modified type, sendas // update ? what if open, modified ... if ( doc->type() == Document::Type_Product ) { //### FIXME. user feedback warnPlanWork<<"We do not update existing deliverables (except name change)"; if ( doc->name() != org->name() ) { m->addCommand( new DocumentModifyNameCmd( org, doc->name() ) ); } } else { if ( doc->name() != org->name() ) { m->addCommand( new DocumentModifyNameCmd( org, doc->name() ) ); } if ( doc->sendAs() != org->sendAs() ) { m->addCommand( new DocumentModifySendAsCmd( org, doc->sendAs() ) ); } if ( doc->sendAs() == Document::SendAs_Copy ) { debugPlanWork<<"Update existing doc:"<url(); openNewDocument( org, store ); } } } else { debugPlanWork<<"new document:"<typeToString(doc->type())<url(); Document *newdoc = new Document( *doc ); m->addCommand( new DocumentAddCmd( to->documents(), newdoc ) ); if ( doc->sendAs() == Document::SendAs_Copy ) { debugPlanWork<<"Copy file"; openNewDocument( newdoc, store ); } } } } const Project *fromProject = wp->project(); Project *toProject = m_project; const ScheduleManager *fromSm = fromProject->scheduleManagers().value( 0 ); Q_ASSERT( fromSm ); ScheduleManager *toSm = toProject->scheduleManagers().value( 0 ); Q_ASSERT( toSm ); if ( fromSm->managerId() != toSm->managerId() || fromSm->scheduleId() != toSm->scheduleId() ) { // rescheduled, update schedules m->addCommand( new CopySchedulesCmd( *fromProject, *toProject ) ); } if ( m->isEmpty() ) { delete m; } else { part->addCommand( m ); } } void WorkPackage::openNewDocument( const Document *doc, KoStore *store ) { const QUrl url = extractFile( doc, store ); if ( url.url().isEmpty() ) { KMessageBox::error( 0, i18n( "Could not extract document from storage:
%1", doc->url().path() ) ); return; } if ( ! url.isValid() ) { KMessageBox::error( 0, i18n( "Invalid URL:
%1", url.path() ) ); return; } m_newdocs.insert( doc, url ); } int WorkPackage::queryClose( Part *part ) { debugPlanWork<name(); QStringList lst; if ( ! m_childdocs.isEmpty() ) { foreach ( DocumentChild *ch, m_childdocs ) { if ( ch->isOpen() && ch->doc()->sendAs() == Document::SendAs_Copy ) { lst << ch->doc()->url().fileName(); } } } if ( ! lst.isEmpty() ) { KMessageBox::ButtonCode result = KMessageBox::warningContinueCancelList( 0, i18np( "

The work package '%2' has an open document.

Data may be lost if you continue.

", "

The work package '%2' has open documents.

Data may be lost if you continue.

", lst.count(), name ), lst ); switch (result) { case KMessageBox::Continue: { debugPlanWork<<"Continue"; break; } default: // case KMessageBox::Cancel : debugPlanWork<<"Cancel"; return KMessageBox::Cancel; break; } } if ( ! isModified() ) { return KMessageBox::Yes; } KMessageBox::ButtonCode res = KMessageBox::warningYesNoCancel( 0, i18n("

The work package '%1' has been modified.

Do you want to save it?

", name), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard()); switch (res) { case KMessageBox::Yes: { debugPlanWork<<"Yes"; saveToProjects( part ); break; } case KMessageBox::No: debugPlanWork<<"No"; break; default: // case KMessageBox::Cancel : debugPlanWork<<"Cancel"; break; } return res; } QUrl WorkPackage::extractFile( const Document *doc ) { KoStore *store = KoStore::createStore( m_filePath, KoStore::Read, "", KoStore::Zip ); if ( store->bad() ) { KMessageBox::error( 0, i18n( "

Work package '%1'

Could not open store:

%2

", node()->name(), m_filePath ) ); delete store; return QUrl(); } const QUrl url = extractFile( doc, store ); delete store; return url; } QUrl WorkPackage::extractFile( const Document *doc, KoStore *store ) { //FIXME: should use a special tmp dir QString tmp = QDir::tempPath() + QLatin1Char('/') + doc->url().fileName(); const QUrl url = QUrl::fromLocalFile( tmp ); debugPlanWork<<"Extract: "<url().fileName()<<" -> "<extractFile( doc->url().fileName(), url.path() ) ) { KMessageBox::error( 0, i18n( "

Work package '%1'

Could not extract file:

%2

", node()->name(), doc->url().fileName() ) ); return QUrl(); } return url; } QString WorkPackage::id() const { QString id; if ( node() ) { id = m_project->id() + node()->id(); } return id; } //-------------------------------- PackageRemoveCmd::PackageRemoveCmd( Part *part, WorkPackage *value, const KUndo2MagicString& name ) : NamedCommand( name ), m_part( part ), m_value( value ), m_mine( false ) { } PackageRemoveCmd::~PackageRemoveCmd() { if ( m_mine ) { m_value->removeFile(); delete m_value; } } void PackageRemoveCmd::execute() { m_part->removeWorkPackage( m_value ); m_mine = true; } void PackageRemoveCmd::unexecute() { m_part->addWorkPackage( m_value ); m_mine = false; } //--------------------- ModifyPackageSettingsCmd::ModifyPackageSettingsCmd( WorkPackage *wp, WorkPackageSettings &value, const KUndo2MagicString& name ) : NamedCommand( name ), m_wp( wp ), m_value( value ), m_oldvalue( wp->settings() ) { } void ModifyPackageSettingsCmd::execute() { m_wp->setSettings( m_value ); } void ModifyPackageSettingsCmd::unexecute() { m_wp->setSettings( m_oldvalue ); } //--------------------- CopySchedulesCmd::CopySchedulesCmd( const Project &fromProject, Project &toProject, const KUndo2MagicString &name ) : NamedCommand( name ), m_project( toProject ) { QDomDocument olddoc; QDomElement e = olddoc.createElement( "old" ); olddoc.appendChild( e ); toProject.save( e ); m_olddoc = olddoc.toString(); QDomDocument newdoc; e = newdoc.createElement( "new" ); newdoc.appendChild( e ); fromProject.save( e ); m_newdoc = newdoc.toString(); } void CopySchedulesCmd::execute() { load( m_newdoc ); } void CopySchedulesCmd::unexecute() { load( m_olddoc ); } void CopySchedulesCmd::load( const QString &doc ) { clearSchedules(); KoXmlDocument d; d.setContent( doc ); KoXmlElement proj = d.documentElement().namedItem( "project").toElement(); Q_ASSERT( ! proj.isNull() ); KoXmlElement task = proj.namedItem( "task").toElement(); Q_ASSERT( ! task.isNull() ); KoXmlElement ts = task.namedItem( "schedules").namedItem( "schedule").toElement(); Q_ASSERT( ! ts.isNull() ); KoXmlElement ps = proj.namedItem( "schedules").namedItem( "plan" ).toElement(); Q_ASSERT( ! ps.isNull() ); XMLLoaderObject status; status.setProject( &m_project ); status.setVersion( PLAN_FILE_SYNTAX_VERSION ); // task first NodeSchedule *ns = new NodeSchedule(); if ( ns->loadXML( ts, status ) ) { debugPlanWork<name()<type()<id(); ns->setNode( m_project.childNode( 0 ) ); m_project.childNode( 0 )->addSchedule( ns ); } else { Q_ASSERT( false ); delete ns; } // schedule manager next (includes main schedule and resource schedule) ScheduleManager *sm = new ScheduleManager( m_project ); if ( sm->loadXML( ps, status ) ) { m_project.addScheduleManager( sm ); } else { Q_ASSERT( false ); delete sm; } if ( sm ) { m_project.setCurrentSchedule( sm->scheduleId() ); } m_project.childNode( 0 )->changed(); } void CopySchedulesCmd::clearSchedules() { foreach ( Schedule *s, m_project.schedules() ) { m_project.takeSchedule( s ); } foreach ( Schedule *s, m_project.childNode( 0 )->schedules() ) { foreach ( Appointment *a, s->appointments() ) { if ( a->resource() && a->resource()->resource() ) { a->resource()->resource()->takeSchedule( a->resource() ); } } m_project.childNode( 0 )->takeSchedule( s ); } foreach ( ScheduleManager *sm, m_project.scheduleManagers() ) { m_project.takeScheduleManager( sm ); delete sm; } } } //KPlatoWork namespace