diff --git a/plan/kptmaindocument.cpp b/plan/kptmaindocument.cpp index e5362e76309..c4dbc831673 100644 --- a/plan/kptmaindocument.cpp +++ b/plan/kptmaindocument.cpp @@ -1,1409 +1,1410 @@ /* 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 ) { 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()) ); } 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,SchedulerPlugin*)), this, SLOT(addSchedulerPlugin(QString,SchedulerPlugin*))); 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()) ); delete m_project; } m_project = project; if ( m_project ) { connect( m_project, SIGNAL(projectChanged()), this, SIGNAL(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 ); 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 ); 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( m_config ); 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()) ); 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() ) { mergeWorkPackage( m_workpackages.values().at( i ) ); } // 'Yes' was hit so terminate all packages foreach( const Package *p, m_workpackages.values() ) { terminateWorkPackage( p ); } } qDeleteAll( m_workpackages ); m_workpackages.clear(); m_checkingForWorkPackages = false; dlg->deleteLater(); } void MainDocument::mergeWorkPackages() { foreach ( 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 foreach ( const QDate &d, org.entries().keys() ) { if ( ! curr.entries().contains( d ) ) { debugPlan<<"remove entry "<addCommand( new RemoveCompletionEntryCmd( org, d ) ); } } // add new entries / modify existing foreach ( const QDate &d, curr.entries().keys() ) { 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_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()) { QUrl url = QUrl::fromLocalFile(m_project->sharedResourcesFile()); if (url.isValid()) { insertResourcesFile(url, m_project->sharedProjectsUrl()); } } 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 simmulate 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))); 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 ); part->setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable connect(doc, SIGNAL(completed()), SLOT(insertResourcesFileCompleted())); connect(doc, SIGNAL(canceled(QString)), SLOT(insertFileCancelled(QString))); doc->openUrl( url ); } void MainDocument::insertResourcesFileCompleted() { debugPlan<( 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::insertSharedProjects(const QUrl &url) { m_sharedProjectsFiles.clear(); QFileInfo fi(url.path()); if (!fi.exists()) { qInfo()<() << url; debugPlan<<"Get all projects in file:"<resourceList()) { r->clearExternalAppointments(); } } void MainDocument::slotInsertSharedProject() { debugPlan<setDocument( doc ); doc->disconnect(); // doc shall not handle feedback from openUrl() doc->setAutoSave( 0 ); //disable connect(doc, SIGNAL(completed()), SLOT(insertSharedProjectCompleted())); connect(doc, SIGNAL(canceled(QString)), SLOT(insertSharedProjectCancelled(QString))); doc->openUrl(m_sharedProjectsFiles.takeFirst()); } void MainDocument::insertSharedProjectCompleted() { debugPlan<( sender() ); if (doc) { Project &p = doc->getProject(); debugPlan<id()<<"Loaded project:"<id()) { for (Resource *r : p.resourceList()) { Resource *res = m_project->resource(r->id()); debugPlan<<"Resource:"<name()<<"->"<isShared()) { for (const Appointment *a : r->appointments()) { Appointment *app = new Appointment(*a); app->setAuxcilliaryInfo(p.name()); res->addExternalAppointment(p.id(), app); debugPlan<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 ) { debugPlan<( 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 (!shared.calendar(c->id())) { result << c; } result += sortedRemoveCalendars(shared, c->calendars()); } return result; } bool MainDocument::mergeResources(Project &project) { debugPlan<<&project; // Just in case, remove stuff not related to resources for (Node *n : project.childNodeIterator()) { delete n; } for (ScheduleManager *m : project.allScheduleManagers()) { delete m; } // Mark all resources / groups as shared for (ResourceGroup *g : project.resourceGroups()) { g->setShared(true); } for (Resource *r : project.resourceList()) { r->setShared(true); } // Mark all calendars shared for (Calendar *c : project.allCalendars()) { c->setShared(true); } // check if any shared stuff has been removed QList removedGroups; QList removedResources; QList removedCalendars; QStringList removed; for (ResourceGroup *g : m_project->resourceGroups()) { if (g->isShared() && !project.findResourceGroup(g->id())) { removedGroups << g; removed << "Group: " + g->name(); } } for (Resource *r : m_project->resourceList()) { if (r->isShared() && !project.findResource(r->id())) { removedResources << r; removed << "Resource: " + r->name(); } } removedCalendars = sortedRemoveCalendars(project, m_project->calendars()); for (Calendar *c : removedCalendars) { removed << "Calendar: " + c->name(); } if (!removedCalendars.isEmpty() || !removedResources.isEmpty() || !removedGroups.isEmpty()) { // TODO show what has changed and give more detailed control if (QMessageBox::question(0, i18n("Shared resources removed"), i18n("Shall the removed shared resources be converted to local resources?")) == QMessageBox::Yes) { for (Resource *r : removedResources) { r->setShared(false); } for (ResourceGroup *g : removedGroups) { if (g->resources().isEmpty()) { g->setShared(false); } } for (Calendar *c : removedCalendars) { c->setShared(false); } } } // update values of already existsing objects for (ResourceGroup *g : project.resourceGroups()) { ResourceGroup *group = m_project->findResourceGroup(g->id()); if (group) { group->setName(g->name()); group->setType(g->type()); } } for (Resource *r : project.resourceList()) { Resource *resource = m_project->findResource(r->id()); if (resource) { 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()); } } for (Calendar *c : project.allCalendars()) { Calendar *calendar = m_project->findCalendar(c->id()); if (calendar) { *calendar = *c; } } // insert new objects 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<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->generateUniqueIds(); 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().values() ) { r->takeSchedule( s ); delete s; } } } } //KPlato namespace diff --git a/plan/kptview.cpp b/plan/kptview.cpp index 398dd117273..5dcda88215a 100644 --- a/plan/kptview.cpp +++ b/plan/kptview.cpp @@ -1,3224 +1,3224 @@ /* 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 #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_trigged( false ), m_nextScheduleManager( 0 ), 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(ScheduleManager*)), SLOT(slotSelectionChanged(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), m_viewlist, SLOT(setSelectedSchedule(ScheduleManager*)) ); connect( m_viewlist, SIGNAL(updateViewInfo(ViewListItem*)), SLOT(slotUpdateViewInfo(ViewListItem*)) ); } 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(ScheduleManager*)), SLOT(slotSelectionChanged(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), sd, SLOT(setSelectedSchedule(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()) ); // ------ 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)) ); // ------ 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()) ); actionEditStandardWorktime = new QAction(koIcon("configure"), i18n("Define Estimate Conversions..."), this); actionCollection()->addAction("project_worktime", actionEditStandardWorktime ); connect( actionEditStandardWorktime, SIGNAL(triggered(bool)), SLOT(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()) ); actionInsertFile = new QAction(koIcon("document-import"), i18n("Insert Project File..."), this); actionCollection()->addAction("insert_file", actionInsertFile ); connect( actionInsertFile, SIGNAL(triggered(bool)), SLOT(slotInsertFile()) ); // ------ Settings actionConfigure = new QAction(koIcon("configure"), i18n("Configure Plan..."), this); actionCollection()->addAction("configure", actionConfigure ); connect( actionConfigure, SIGNAL(triggered(bool)), SLOT(slotConfigure()) ); actionCurrencyConfig = new QAction(koIcon("configure"), i18n("Define Currency..."), this); actionCollection()->addAction( "config_currency", actionCurrencyConfig ); connect( actionCurrencyConfig, SIGNAL(triggered(bool)), SLOT(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()) ); // ------ 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()) ); 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()) ); actionIndentTask = new QAction(koIcon("format-indent-more"), i18n("Indent Task"), this); actionCollection()->addAction("indent_task", actionIndentTask ); connect( actionIndentTask, SIGNAL(triggered(bool)), SLOT(slotIndentTask()) ); actionUnindentTask= new QAction(koIcon("format-indent-less"), i18n("Unindent Task"), this); actionCollection()->addAction("unindent_task", actionUnindentTask ); connect( actionUnindentTask, SIGNAL(triggered(bool)), SLOT(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()) ); actionMoveTaskDown = new QAction(koIcon("arrow-down"), i18n("Move Task Down"), this); actionCollection()->addAction("move_task_down", actionMoveTaskDown ); connect( actionMoveTaskDown, SIGNAL(triggered(bool)), SLOT(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()) ); // Viewlist popup connect( m_viewlist, SIGNAL(createView()), SLOT(slotCreateView()) ); m_estlabel = new QLabel( "", 0 ); if ( statusBar() ) { addStatusBarItem( m_estlabel, 0, true ); } connect( &getProject(), SIGNAL(scheduleChanged(MainSchedule*)), SLOT(slotScheduleChanged(MainSchedule*)) ); connect( &getProject(), SIGNAL(scheduleAdded(const MainSchedule*)), SLOT(slotScheduleAdded(const MainSchedule*)) ); connect( &getProject(), SIGNAL(scheduleRemoved(const MainSchedule*)), SLOT(slotScheduleRemoved(const MainSchedule*)) ); slotPlugScheduleActions(); connect( doc, SIGNAL(changed()), SLOT(slotUpdate()) ); connect( m_scheduleActionGroup, SIGNAL(triggered(QAction*)), SLOT(slotViewSchedule(QAction*)) ); connect( getPart(), SIGNAL(workPackageLoaded()), SLOT(slotWorkPackageLoaded()) ); // hide unused dockers QTimer::singleShot( 0, this, SLOT(hideToolDocker()) ); // create views after dockers hidden, views take time for large projects QTimer::singleShot( 100, this, SLOT(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(); } } //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*)) ); // after createViews() !! connect( m_viewlist, SIGNAL(viewListItemRemoved(ViewListItem*)), SLOT(slotViewListItemRemoved(ViewListItem*)) ); // after createViews() !! connect( m_viewlist, SIGNAL(viewListItemInserted(ViewListItem*,ViewListItem*,int)), SLOT(slotViewListItemInserted(ViewListItem*,ViewListItem*,int)) ); 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)) ); slotSelectDefaultView(); loadContext(); QApplication::restoreOverrideCursor(); } void View::slotCreateTemplate() { KoTemplateCreateDia::createTemplate(koDocument()->documentPart()->templatesResourcePath(), ".plant", getPart(), this); } 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?" ) ) ) { 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 ); 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 // A little hack to get the user started... 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 } } 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)) ); 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( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(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( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(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, SIGNAL(deleteObjectList(QObjectList)), SLOT(slotDeleteResourceObjects(QObjectList)) ); 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(ScheduleManager*)), taskeditor, SLOT(setScheduleManager(ScheduleManager*)) ); connect( taskeditor, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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, 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, SIGNAL(saveTaskModule(QUrl,Project*)), SLOT(saveTaskModule(QUrl,Project*))); connect(taskeditor, SIGNAL(removeTaskModule(QUrl)), SLOT(removeTaskModule(QUrl))); 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)) ); 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, 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(Project*)), SLOT(slotAddScheduleManager(Project*)) ); connect( handler->scheduleEditor(), SIGNAL(deleteScheduleManager(Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(Project*,ScheduleManager*)) ); connect( handler->scheduleEditor(), SIGNAL(moveScheduleManager(ScheduleManager*,ScheduleManager*,int)), SLOT(slotMoveScheduleManager(ScheduleManager*,ScheduleManager*,int))); connect( handler->scheduleEditor(), SIGNAL(calculateSchedule(Project*,ScheduleManager*)), SLOT(slotCalculateSchedule(Project*,ScheduleManager*)) ); connect( handler->scheduleEditor(), SIGNAL(baselineSchedule(Project*,ScheduleManager*)), SLOT(slotBaselineSchedule(Project*,ScheduleManager*)) ); connect( handler, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), handler, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)) ); connect( handler, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); connect(handler, SIGNAL(editNode(Node*)), this, SLOT(slotOpenNode(Node*))); connect(handler, SIGNAL(editResource(Resource*)), this, SLOT(slotEditResource(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(Project*)), SLOT(slotAddScheduleManager(Project*)) ); connect( scheduleeditor, SIGNAL(deleteScheduleManager(Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(calculateSchedule(Project*,ScheduleManager*)), SLOT(slotCalculateSchedule(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(baselineSchedule(Project*,ScheduleManager*)), SLOT(slotBaselineSchedule(Project*,ScheduleManager*)) ); 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, SIGNAL(addScheduleManager(Project*)), SLOT(slotAddScheduleManager(Project*)) ); connect( scheduleeditor, SIGNAL(deleteScheduleManager(Project*,ScheduleManager*)), SLOT(slotDeleteScheduleManager(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(calculateSchedule(Project*,ScheduleManager*)), SLOT(slotCalculateSchedule(Project*,ScheduleManager*)) ); connect( scheduleeditor, SIGNAL(baselineSchedule(Project*,ScheduleManager*)), SLOT(slotBaselineSchedule(Project*,ScheduleManager*)) ); 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, SIGNAL(addRelation(Node*,Node*,int)), SLOT(slotAddRelation(Node*,Node*,int)) ); connect( editor, SIGNAL(modifyRelation(Relation*,int)), SLOT(slotModifyRelation(Relation*,int)) ); connect( editor, SIGNAL(modifyRelation(Relation*)), SLOT(slotModifyRelation(Relation*)) ); connect( editor, SIGNAL(editNode(Node*)), SLOT(slotOpenNode(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, SIGNAL(deleteTaskList(QList)), SLOT(slotDeleteTask(QList)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), editor, SLOT(setScheduleManager(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)) ); 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( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(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( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(setScheduleManager(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( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), taskstatusview, SLOT(setScheduleManager(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(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); connect( v, SIGNAL(requestPopupMenu(QString,QPoint)), this, SLOT(slotPopupMenu(QString,QPoint)) ); connect( v, SIGNAL(mailWorkpackage(Node*,Resource*)), SLOT(slotMailWorkpackage(Node*,Resource*)) ); connect( v, SIGNAL(mailWorkpackages(QList,Resource*)), SLOT(slotMailWorkpackages(QList,Resource*)) ); 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)) ); /* TODO: Review these connect( ganttview, SIGNAL(addRelation(Node*,Node*,int)), SLOT(slotAddRelation(Node*,Node*,int)) ); connect( ganttview, SIGNAL(modifyRelation(Relation*,int)), SLOT(slotModifyRelation(Relation*,int)) ); connect( ganttview, SIGNAL(modifyRelation(Relation*)), SLOT(slotModifyRelation(Relation*)) ); connect( ganttview, SIGNAL(itemDoubleClicked()), SLOT(slotOpenNode()) ); connect( ganttview, SIGNAL(itemRenamed(Node*,QString)), this, SLOT(slotRenameNode(Node*,QString)) );*/ connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), ganttview, SLOT(setScheduleManager(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( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), ganttview, SLOT(setScheduleManager(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(ScheduleManager*)), accountsview, SLOT(setScheduleManager(ScheduleManager*)) ); connect( accountsview, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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, 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(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(slotRefreshView())); v->setScheduleManager( currentScheduleManager() ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); 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(ScheduleManager*)), v, SLOT(setScheduleManager(ScheduleManager*)) ); connect( this, SIGNAL(currentScheduleManagerChanged(ScheduleManager*)), v, SLOT(slotRefreshView())); v->setScheduleManager( currentScheduleManager() ); connect( v, SIGNAL(guiActivated(ViewBase*,bool)), SLOT(slotGuiActivated(ViewBase*,bool)) ); v->updateReadWrite( m_readWrite ); return v; #else 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 ( idx < 0 ) { debugPlan<expected(); return; } QAction *a = m_scheduleActions.keys().at( idx ); Q_ASSERT( a ); a->setChecked( true ); // this doesn't trigger QActionGroup slotViewSchedule( a ); } QList View::sortedActionList() { QMap lst; foreach ( QAction *a, m_scheduleActions.keys() ) { lst.insert( a->objectName(), a ); } 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.keys().first()->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.keys().first()->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 ( m_scheduleActions.values().contains( 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(); } - emit currentScheduleManagerChanged( 0 ); + //emit currentScheduleManagerChanged( 0 ); setLabel( 0 ); m_nextScheduleManager = sm; // Performance is very dependent on schedule manager change since a lot is recalculated // In case of multiple changes, only issue the last change if ( ! m_trigged ) { m_trigged = true; - emit currentScheduleManagerChanged( 0 ); + //emit currentScheduleManagerChanged( 0 ); QTimer::singleShot( 0, this, SLOT(slotViewScheduleManager()) ); } } void View::slotActionDestroyed( QObject *o ) { //debugPlan<name(); m_scheduleActions.remove( static_cast( o ) ); // slotViewSchedule( m_scheduleActionGroup->checkedAction() ); } void View::slotPlugScheduleActions() { //debugPlan<removeAction( act ); delete act; } 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().first(); } 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(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); } 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))); 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))); 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))); 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))); 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(const QString&, const QUrl&)), this, SLOT(slotInsertResourcesFile(const QString&, const QUrl&))); 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))); 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))); 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; #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); #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(); } 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/plan/libs/models/kptnodeitemmodel.cpp b/plan/libs/models/kptnodeitemmodel.cpp index 5830f83914d..17c485dc0a6 100644 --- a/plan/libs/models/kptnodeitemmodel.cpp +++ b/plan/libs/models/kptnodeitemmodel.cpp @@ -1,5194 +1,5197 @@ /* This file is part of the KDE project Copyright (C) 2007 - 2009, 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 "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 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() ); } return xi18nc( "@info:tooltip 1=list of resources", "Allocated resources:%1", sl.join( "" ) ); } 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 ) { m_projectshown = on; reset(); 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 ) { 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(Node*)), this, SLOT(slotNodeChanged(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) ); disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int)) ); disconnect( m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*)) ); disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) ); disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) ); disconnect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*))); } 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 QMap 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 exixting 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" ) ); QMap 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 ) { QMap 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() ) ) { 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 ) ) { 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; } } 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; } } 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; } } 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; } } 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 ) { 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, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) ); disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) ); disconnect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) ); disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); disconnect(m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int))); disconnect(m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*))); disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) ); disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) ); } m_project = project; //debugPlan<"<allNodes() ) { m_nodemap.insert( n->wbsCode(true), n ); } } return cnt != m_nodemap.count(); } void MilestoneItemModel::resetModel() { resetData(); reset(); } 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) ); } 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; } // if ( ! m_nodemap.contains( node->wbsCode() ) || m_nodemap.value( node->wbsCode() ) != node ) { emit layoutAboutToBeChanged(); if ( resetData() ) { reset(); } else { emit layoutChanged(); } return; /* } int row = m_nodemap.values().indexOf( node ); debugPlan<name()<<": "<typeToString()<( 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 ) { beginInsertRows( QModelIndex(), m_modules.count(), m_modules.count() ); m_modules << project; 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 { 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(); 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 ); 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 "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 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(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); connect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); connect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } void ResourceAppointmentsItemModel::slotResourceToBeRemoved( const Resource *r ) { debugPlan<name(); int row = r->parentGroup()->indexOf( r ); beginRemoveRows( index( r->parentGroup() ), row, row ); disconnect( r, SIGNAL(externalAppointmentToBeAdded(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); disconnect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); disconnect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } 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; } m_showInternal = show; refreshData(); reset(); } void ResourceAppointmentsItemModel::setShowExternalAppointments( bool show ) { if ( m_showExternal == show ) { return; } m_showExternal = show; refreshData(); reset(); } void ResourceAppointmentsItemModel::setProject( Project *project ) { debugPlan; if ( m_project ) { disconnect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); disconnect( m_project, SIGNAL(resourceChanged(Resource*)), this, SLOT(slotResourceChanged(Resource*)) ); disconnect( m_project, SIGNAL(resourceGroupChanged(ResourceGroup*)), this, SLOT(slotResourceGroupChanged(ResourceGroup*)) ); disconnect( m_project, SIGNAL(resourceGroupToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const ResourceGroup*,int)) ); disconnect( m_project, SIGNAL(resourceGroupToBeRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const ResourceGroup*)) ); disconnect( m_project, SIGNAL(resourceToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const ResourceGroup*,int)) ); disconnect( m_project, SIGNAL(resourceToBeRemoved(const Resource*)), this, SLOT(slotResourceToBeRemoved(const Resource*)) ); disconnect( m_project, SIGNAL(resourceGroupAdded(const ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const ResourceGroup*)) ); disconnect( m_project, SIGNAL(resourceGroupRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const ResourceGroup*)) ); disconnect( m_project, SIGNAL(resourceAdded(const Resource*)), this, SLOT(slotResourceInserted(const Resource*)) ); disconnect( m_project, SIGNAL(resourceRemoved(const Resource*)), this, SLOT(slotResourceRemoved(const Resource*)) ); disconnect( m_project, SIGNAL(defaultCalendarChanged(Calendar*)), this, SLOT(slotCalendarChanged(Calendar*)) ); disconnect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); disconnect( m_project, SIGNAL(scheduleManagerChanged(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); foreach ( Resource *r, m_project->resourceList() ) { disconnect( r, SIGNAL(externalAppointmentToBeAdded(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); disconnect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); disconnect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } } m_project = project; if ( m_project ) { connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); connect( m_project, SIGNAL(resourceChanged(Resource*)), this, SLOT(slotResourceChanged(Resource*)) ); connect( m_project, SIGNAL(resourceGroupChanged(ResourceGroup*)), this, SLOT(slotResourceGroupChanged(ResourceGroup*)) ); connect( m_project, SIGNAL(resourceGroupToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const ResourceGroup*,int)) ); connect( m_project, SIGNAL(resourceGroupToBeRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const ResourceGroup*)) ); connect( m_project, SIGNAL(resourceToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const ResourceGroup*,int)) ); connect( m_project, SIGNAL(resourceToBeRemoved(const Resource*)), this, SLOT(slotResourceToBeRemoved(const Resource*)) ); connect( m_project, SIGNAL(resourceGroupAdded(const ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const ResourceGroup*)) ); connect( m_project, SIGNAL(resourceGroupRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const ResourceGroup*)) ); connect( m_project, SIGNAL(resourceAdded(const Resource*)), this, SLOT(slotResourceInserted(const Resource*)) ); connect( m_project, SIGNAL(resourceRemoved(const Resource*)), this, SLOT(slotResourceRemoved(const Resource*)) ); connect( m_project, SIGNAL(defaultCalendarChanged(Calendar*)), this, SLOT(slotCalendarChanged(Calendar*)) ); connect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); connect( m_project, SIGNAL(scheduleManagerChanged(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); foreach ( Resource *r, m_project->resourceList() ) { connect( r, SIGNAL(externalAppointmentToBeAdded(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); connect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); connect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } } refreshData(); reset(); 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; + } 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; QMap 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 ); 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 ) { //debugPlan<resourceList() ) { disconnect( r, SIGNAL(externalAppointmentToBeAdded(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); disconnect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); disconnect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } } m_project = project; if ( m_project ) { connect(m_project, SIGNAL(aboutToBeDeleted()), this, SLOT(projectDeleted())); connect( m_project, SIGNAL(resourceGroupToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const ResourceGroup*,int)) ); connect( m_project, SIGNAL(resourceGroupToBeRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const ResourceGroup*)) ); connect( m_project, SIGNAL(resourceToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const ResourceGroup*,int)) ); connect( m_project, SIGNAL(resourceToBeRemoved(const Resource*)), this, SLOT(slotResourceToBeRemoved(const Resource*)) ); connect( m_project, SIGNAL(resourceGroupAdded(const ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const ResourceGroup*)) ); connect( m_project, SIGNAL(resourceGroupRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const ResourceGroup*)) ); connect( m_project, SIGNAL(resourceAdded(const Resource*)), this, SLOT(slotResourceInserted(const Resource*)) ); connect( m_project, SIGNAL(resourceRemoved(const Resource*)), this, SLOT(slotResourceRemoved(const Resource*)) ); connect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); foreach ( Resource *r, m_project->resourceList() ) { connect( r, SIGNAL(externalAppointmentToBeAdded(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); connect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); connect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } } reset(); } void ResourceAppointmentsRowModel::setScheduleManager( ScheduleManager *sm ) { debugPlan<<"ResourceAppointmentsRowModel::setScheduleManager:"<expected() != m_schedule ) { m_manager = sm; m_schedule = sm ? sm->expected() : 0; qDeleteAll( m_datamap ); m_datamap.clear(); reset(); } } 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(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); connect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); connect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); connect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); } void ResourceAppointmentsRowModel::slotResourceToBeRemoved( const Resource *r ) { debugPlan<name(); int row = r->parentGroup()->indexOf( r ); beginRemoveRows( index( r->parentGroup() ), row, row ); disconnect( r, SIGNAL(externalAppointmentToBeAdded(Resource*,int)), this, SLOT(slotAppointmentToBeInserted(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentAdded(Resource*,Appointment*)), this, SLOT(slotAppointmentInserted(Resource*,Appointment*)) ); disconnect( r, SIGNAL(externalAppointmentToBeRemoved(Resource*,int)), this, SLOT(slotAppointmentToBeRemoved(Resource*,int)) ); disconnect( r, SIGNAL(externalAppointmentRemoved()), this, SLOT(slotAppointmentRemoved()) ); disconnect( r, SIGNAL(externalAppointmentChanged(Resource*,Appointment*)), this, SLOT(slotAppointmentChanged(Resource*,Appointment*)) ); 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); // external appointments only, (Internal handled in slotProjectCalculated) Private *p = m_datamap.value( r ); if ( p ) { p->externalCached = false; } reset(); } 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) reset(); } 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< 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 "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 ) { 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(Node*)), this, SLOT(slotNodeChanged(Node*)) ); disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) ); disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); disconnect(m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int))); disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) ); disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) ); disconnect(m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*))); } 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(Node*)), this, SLOT(slotNodeChanged(Node*)) ); connect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) ); connect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); connect(m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int))); connect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) ); connect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) ); connect(m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*))); } reset(); } void TaskStatusItemModel::setScheduleManager( ScheduleManager *sm ) { + if (sm == m_nodemodel.manager()) { + return; + } clear(); if ( m_nodemodel.manager() ) { } m_nodemodel.setManager( sm ); ItemModelBase::setScheduleManager( sm ); if ( sm ) { } reset(); 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 ( l->values().indexOf( n ) != -1 ) { 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"<values().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 ) { int row = l->values().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 ) { int row = l->values().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 ) { emit dataChanged( createIndex( row, NodeModel::NodeWBSCode, l->values().value( row ) ), createIndex( row, NodeModel::NodeWBSCode, l->values().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/plan/libs/ui/kptaccountseditor.cpp b/plan/libs/ui/kptaccountseditor.cpp index 76de32e4247..699e9a382ca 100644 --- a/plan/libs/ui/kptaccountseditor.cpp +++ b/plan/libs/ui/kptaccountseditor.cpp @@ -1,353 +1,364 @@ /* 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 "kptdebug.h" #include #include #include #include #include #include #include #include #include #include namespace KPlato { AccountseditorConfigDialog::AccountseditorConfigDialog( ViewBase *view, AccountTreeView *treeview, QWidget *p) : 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" ) ); connect( this, SIGNAL(accepted()), this, SLOT(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(headerContextMenuRequested(QPoint)) ); } void AccountTreeView::headerContextMenuRequested( 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())); l->addWidget( m_view ); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); 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)) ); } 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()) ); 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()) ); 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()) ); addAction( name, actionDeleteSelection ); createOptionAction(); } 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/plan/libs/ui/kptaccountseditor.h b/plan/libs/ui/kptaccountseditor.h index 1e0aa413b90..de3adc32fbd 100644 --- a/plan/libs/ui/kptaccountseditor.h +++ b/plan/libs/ui/kptaccountseditor.h @@ -1,149 +1,152 @@ /* This file is KoDocument 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 KPTACCOUNTSEDITOR_H #define KPTACCOUNTSEDITOR_H #include "kplatoui_export.h" #include #include "kptaccountsmodel.h" #include class KoPageLayoutWidget; class KoDocument; class QPoint; namespace KPlato { class Project; class Account; class AccountTreeView; class AccountseditorConfigDialog : public KPageDialog { Q_OBJECT public: AccountseditorConfigDialog( ViewBase *view, AccountTreeView *treeview, QWidget *parent ); public Q_SLOTS: void slotOk(); private: ViewBase *m_view; AccountTreeView *m_treeview; KoPageLayoutWidget *m_pagelayout; PrintingHeaderFooter *m_headerfooter; }; class KPLATOUI_EXPORT AccountTreeView : public TreeViewBase { Q_OBJECT public: explicit AccountTreeView(QWidget *parent); AccountItemModel *model() const { return static_cast( TreeViewBase::model() ); } Project *project() const { return model()->project(); } void setProject( Project *project ) { model()->setProject( project ); } Account *currentAccount() const; Account *selectedAccount() const; QList selectedAccounts() const; Q_SIGNALS: void currentChanged( const QModelIndex& ); void currentColumnChanged( const QModelIndex&, const QModelIndex& ); void selectionChanged( const QModelIndexList& ); void contextMenuRequested( const QModelIndex&, const QPoint& ); protected Q_SLOTS: void headerContextMenuRequested( const QPoint &pos ); virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); virtual void currentChanged ( const QModelIndex & current, const QModelIndex & previous ); protected: void contextMenuEvent ( QContextMenuEvent * event ); }; class KPLATOUI_EXPORT AccountsEditor : public ViewBase { Q_OBJECT public: AccountsEditor(KoPart *part, KoDocument *document, QWidget *parent); void setupGui(); Project *project() const { return m_view->project(); } virtual void draw( Project &project ); virtual void draw(); AccountItemModel *model() const { return m_view->model(); } virtual void updateReadWrite( bool readwrite ); virtual Account *currentAccount() const; KoPrintJob *createPrintJob(); - + + bool loadContext(const KoXmlElement &context); + void saveContext(QDomElement &context) const; + Q_SIGNALS: void addAccount( Account *account ); void deleteAccounts( const QList& ); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); protected: void updateActionsEnabled( bool on ); void insertAccount( Account *account, Account *parent, int row ); protected Q_SLOTS: virtual void slotOptions(); private Q_SLOTS: void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotHeaderContextMenuRequested( const QPoint &pos ); void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex& ); void slotEnableActions( bool on ); void slotAddAccount(); void slotAddSubAccount(); void slotDeleteSelection(); void slotAccountsOk(); private: AccountTreeView *m_view; QAction *actionAddAccount; QAction *actionAddSubAccount; QAction *actionDeleteSelection; }; } //KPlato namespace #endif diff --git a/plan/libs/ui/kptaccountsview.cpp b/plan/libs/ui/kptaccountsview.cpp index e513e5aa43e..bc587d25c21 100644 --- a/plan/libs/ui/kptaccountsview.cpp +++ b/plan/libs/ui/kptaccountsview.cpp @@ -1,292 +1,318 @@ /* 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 "kptdebug.h" #include #include #include #include #include #include #include namespace KPlato { AccountsTreeView::AccountsTreeView( QWidget *parent ) : DoubleTreeViewBase( parent ) { debugPlan<<"---------------"<header(); v->setStretchLastSection( false ); v->setResizeMode( 1, QHeaderView::Stretch ); v->setResizeMode ( 2, QHeaderView::ResizeToContents ); v = m_rightview->header(); v->setResizeMode ( QHeaderView::ResizeToContents ); v->setStretchLastSection( false ); hideColumns( m_rightview, QList() << 0 << 1 << 2 ); slotModelReset(); connect( m, SIGNAL(modelReset()), SLOT(slotModelReset()) ); } void AccountsTreeView::slotModelReset() { hideColumns( m_leftview, QList() << 3 << -1 ); QHeaderView *v = m_leftview->header(); debugPlan<sectionSize(2)<sectionSizeHint(2)<defaultSectionSize()<minimumSectionSize(); hideColumns( m_rightview, QList() << 0 << 1 << 2 ); } 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( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); 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() { createOptionAction(); } 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 ); 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/plan/libs/ui/kptaccountsview.h b/plan/libs/ui/kptaccountsview.h index 713a0477d0d..a0f5dd2e178 100644 --- a/plan/libs/ui/kptaccountsview.h +++ b/plan/libs/ui/kptaccountsview.h @@ -1,114 +1,115 @@ /* 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. */ #ifndef KPTACCOUNTSVIEW_H #define KPTACCOUNTSVIEW_H #include "kplatoui_export.h" #include "kptviewbase.h" #include #include #include "kptaccount.h" #include "kpteffortcostmap.h" namespace KPlato { class Account; class Project; class ScheduleManager; class CostBreakdownItemModel; class KPLATOUI_EXPORT AccountsTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit AccountsTreeView( QWidget *parent = 0 ); CostBreakdownItemModel *model() const; bool cumulative() const; void setCumulative( bool on ); int periodType() const; void setPeriodType( int period ); int startMode() const; void setStartMode( int mode ); int endMode() const; void setEndMode( int mode ); QDate startDate() const; void setStartDate( const QDate &date ); QDate endDate() const; void setEndDate( const QDate &date ); int showMode() const; void setShowMode( int show ); protected Q_SLOTS: void slotModelReset(); }; class KPLATOUI_EXPORT AccountsView : public ViewBase { Q_OBJECT public: AccountsView(KoPart *part, Project *project, KoDocument *doc, QWidget *parent); //~AccountsView(); void setupGui(); Project *project() const { return m_project; } virtual void setZoom( double zoom ); virtual void setProject( Project *project ); virtual bool loadContext( const KoXmlElement &context ); virtual void saveContext( QDomElement &context ) const; CostBreakdownItemModel *model() const; KoPrintJob *createPrintJob(); public Q_SLOTS: void setScheduleManager( ScheduleManager *sm ); protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); void slotHeaderContextMenuRequested( const QPoint &pos ); virtual void slotOptions(); private: void init(); private: Project *m_project; ScheduleManager *m_manager; AccountsTreeView *m_view; QDate m_date; int m_period; bool m_cumulative; + QDomDocument m_domdoc; }; } //KPlato namespace #endif diff --git a/plan/libs/ui/kptganttview.cpp b/plan/libs/ui/kptganttview.cpp index 396f56b1674..a085bbd0261 100644 --- a/plan/libs/ui/kptganttview.cpp +++ b/plan/libs/ui/kptganttview.cpp @@ -1,1353 +1,1398 @@ /* 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 "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 /// 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()) ); } 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 ) : 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" ) ); connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); connect( this, SIGNAL(accepted()), panel, SLOT(slotOk()) ); connect( button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(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))); w->setSinglePage( m_gantt->m_printOptions.singlePage ); connect(w->ui_singlePage, SIGNAL(toggled(bool)), SLOT(slotSinglePageToogled(bool))); 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))); } 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); } 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(Node*)), this, SLOT(slotNodeInserted(Node*)) ); } 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*)) ); } 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*)) ); } 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(); } 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())); 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(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } 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 ); connect(actionShowProject, SIGNAL(triggered(bool)), m_gantt->model(), SLOT(setShowProject(bool))); addContextAction( actionShowProject ); createOptionAction(); } void GanttView::slotOptions() { debugPlan; GanttViewSettingsDialog *dlg = new GanttViewSettingsDialog( m_gantt, m_gantt->delegate(), this ); 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 ) { - //debugPlan<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 ) : 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" ) ); 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); } 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*)) ); } NodeGanttViewBase::setProject( proj ); if ( proj ) { connect( proj, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalculated(ScheduleManager*)) ); } } 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(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } 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() { createOptionAction(); } 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 ); 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 ) : 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" ) ); 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())); 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)) ); } 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() { createOptionAction(); } 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); 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/plan/libs/ui/kptganttview.h b/plan/libs/ui/kptganttview.h index 38e3cf044d6..ad484df84a6 100644 --- a/plan/libs/ui/kptganttview.h +++ b/plan/libs/ui/kptganttview.h @@ -1,475 +1,477 @@ /* This file is part of the KDE project Copyright (C) 2005 Dag Andersen Copyright (C) 2006 Raphael Langerhorst 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 KPTGANTTVIEW_H #define KPTGANTTVIEW_H #include "kplatoui_export.h" #include "kptviewbase.h" #include "kptitemviewsettup.h" #include "kptnodeitemmodel.h" #include "kptganttitemdelegate.h" #include "ui_kptganttprintingoptions.h" #include "ui_kptganttchartdisplayoptions.h" #include #include #include class KoDocument; class QPoint; class QSplitter; class KoPrintJob; namespace KGantt { class TreeViewRowController; } namespace KPlato { class Node; class MilestoneItemModel; class GanttItemModel; class ResourceAppointmentsGanttModel; class Task; class Project; class Relation; class ScheduleManager; class MyKGanttView; class GanttPrintingOptions; class GanttViewBase; class NodeGanttViewBase; class GanttPrintingOptionsWidget; //--------------------------------------- class GanttChartDisplayOptionsPanel : public QWidget, public Ui::GanttChartDisplayOptions { Q_OBJECT public: explicit GanttChartDisplayOptionsPanel( GanttItemDelegate *delegate, QWidget *parent = 0 ); void setValues( const GanttItemDelegate &del ); public Q_SLOTS: void slotOk(); void setDefault(); Q_SIGNALS: void changed(); private: GanttItemDelegate *m_delegate; }; class GanttViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: explicit GanttViewSettingsDialog( GanttViewBase *gantt, GanttItemDelegate *delegate, ViewBase *view ); protected Q_SLOTS: void slotOk(); private: GanttViewBase *m_gantt; GanttPrintingOptionsWidget *m_printingoptions; }; //-------------------- class GanttPrintingOptions { public: GanttPrintingOptions(); bool loadContext( const KoXmlElement &settings ); void saveContext( QDomElement &settings ) const; bool printRowLabels; bool singlePage; }; class KPLATOUI_EXPORT GanttPrintingOptionsWidget : public QWidget, public Ui::GanttPrintingOptionsWidget { Q_OBJECT public: explicit GanttPrintingOptionsWidget( QWidget *parent = 0 ); GanttPrintingOptions options() const; void setPrintRowLabels( bool value ) { ui_printRowLabels->setChecked( value ); } bool printRowLabels() const { return ui_printRowLabels->isChecked(); } void setSinglePage( bool value ) { value ? ui_singlePage->setChecked( false ) : ui_multiplePages->setChecked( true ); } bool singlePage() const { return ui_singlePage->isChecked(); } public Q_SLOTS: void setOptions(const GanttPrintingOptions &opt); }; class GanttPrintingDialog : public PrintingDialog { Q_OBJECT public: GanttPrintingDialog( ViewBase *view, GanttViewBase *gantt ); void startPrinting( RemovePolicy removePolicy ); QList createOptionWidgets() const; void printPage( int page, QPainter &painter ); int documentLastPage() const; protected Q_SLOTS: void slotPrintRowLabelsToogled( bool on ); void slotSinglePageToogled( bool on ); protected: GanttViewBase *m_gantt; QRectF m_sceneRect; int m_horPages; int m_vertPages; double m_headerHeight; GanttPrintingOptionsWidget *m_options; QImage m_image; }; class KPLATOUI_EXPORT GanttTreeView : public TreeViewBase { Q_OBJECT public: explicit GanttTreeView(QWidget *parent); }; class GanttZoomWidget : public QSlider { Q_OBJECT public: explicit GanttZoomWidget( QWidget *parent ); void setGrid( KGantt::DateTimeGrid *grid ); void setEnableHideOnLeave( bool hide ); protected: void leaveEvent( QEvent *event ); private Q_SLOTS: void sliderValueChanged( int value ); private: bool m_hide; KGantt::DateTimeGrid *m_grid; }; class KPLATOUI_EXPORT GanttViewBase : public KGantt::View { Q_OBJECT public: explicit GanttViewBase(QWidget *parent); GanttTreeView *treeView() const; GanttPrintingOptions printingOptions() const { return m_printOptions; } virtual bool loadContext( const KoXmlElement &settings ); virtual void saveContext( QDomElement &settings ) const; public Q_SLOTS: void setPrintingOptions( const GanttPrintingOptions &opt ) { m_printOptions = opt; } protected: bool eventFilter(QObject *obj, QEvent *event); friend class GanttPrintingDialog; GanttPrintingOptions m_printOptions; private: GanttZoomWidget *m_zoomwidget; }; class NodeGanttViewBase : public GanttViewBase { Q_OBJECT public: explicit NodeGanttViewBase(QWidget *parent); ~NodeGanttViewBase(); NodeSortFilterProxyModel *sfModel() const; void setItemModel( ItemModelBase *model ); ItemModelBase *model() const; void setProject( Project *project ); Project *project() const { return m_project; } GanttItemDelegate *delegate() const { return m_ganttdelegate; } bool loadContext( const KoXmlElement &settings ); void saveContext( QDomElement &settings ) const; protected: Project *m_project; GanttItemDelegate *m_ganttdelegate; NodeItemModel m_defaultModel; KGantt::TreeViewRowController *m_rowController; }; class KPLATOUI_EXPORT MyKGanttView : public NodeGanttViewBase { Q_OBJECT public: explicit MyKGanttView(QWidget *parent); GanttItemModel *model() const; void setProject( Project *project ); void setScheduleManager( ScheduleManager *sm ); void clearDependencies(); void createDependencies(); public Q_SLOTS: void addDependency( Relation *rel ); void removeDependency( Relation *rel ); void slotProjectCalculated( ScheduleManager *sm ); void slotNodeInserted( Node *node ); protected: ScheduleManager *m_manager; }; class KPLATOUI_EXPORT GanttView : public ViewBase { Q_OBJECT public: GanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite = true); //~GanttView(); virtual void setZoom( double zoom ); void setupGui(); Project *project() const { return m_gantt->project(); } virtual void setProject( Project *project ); using ViewBase::draw; virtual void draw( Project &project ); virtual void drawChanges( Project &project ); Node *currentNode() const; void clear(); virtual bool loadContext( const KoXmlElement &context ); virtual void saveContext( QDomElement &context ) const; void updateReadWrite( bool on ); KoPrintJob *createPrintJob(); void setShowSpecialInfo( bool on ) { m_gantt->model()->setShowSpecial( on ); } bool showSpecialInfo() const { return m_gantt->model()->showSpecial(); } Q_SIGNALS: void modifyRelation( Relation *rel ) ; void addRelation( Node *par, Node *child ); void modifyRelation( Relation *rel, int linkType ) ; void addRelation( Node *par, Node *child, int linkType ); void itemDoubleClicked(); public Q_SLOTS: void setScheduleManager( ScheduleManager *sm ); void setShowResources( bool on ); void setShowTaskName( bool on ); void setShowTaskLinks( bool on ); void setShowProgress( bool on ); void setShowPositiveFloat( bool on ); void setShowCriticalTasks( bool on ); void setShowCriticalPath( bool on ); void setShowNoInformation( bool on ); void setShowAppointments( bool on ); protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); virtual void slotOptions(); virtual void slotOptionsFinished( int result ); private: bool m_readWrite; int m_defaultFontSize; QSplitter *m_splitter; MyKGanttView *m_gantt; Project *m_project; QAction *actionShowProject; + QDomDocument m_domdoc; }; class MilestoneGanttViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: MilestoneGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view ); protected Q_SLOTS: virtual void slotOk(); private: GanttViewBase *m_gantt; GanttPrintingOptionsWidget *m_printingoptions; }; class KPLATOUI_EXPORT MilestoneKGanttView : public NodeGanttViewBase { Q_OBJECT public: explicit MilestoneKGanttView(QWidget *parent); MilestoneItemModel *model() const; void setProject( Project *project ); void setScheduleManager( ScheduleManager *sm ); public Q_SLOTS: void slotProjectCalculated( ScheduleManager *sm ); protected: ScheduleManager *m_manager; }; class KPLATOUI_EXPORT MilestoneGanttView : public ViewBase { Q_OBJECT public: MilestoneGanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite = true); virtual void setZoom( double zoom ); void show(); virtual void setProject( Project *project ); Project *project() const { return m_gantt->project(); } using ViewBase::draw; virtual void draw( Project &project ); virtual void drawChanges( Project &project ); void setupGui(); Node *currentNode() const; void clear(); virtual bool loadContext( const KoXmlElement &context ); virtual void saveContext( QDomElement &context ) const; void updateReadWrite( bool on ); bool showNoInformation() const { return m_showNoInformation; } KoPrintJob *createPrintJob(); Q_SIGNALS: void itemDoubleClicked(); public Q_SLOTS: void setScheduleManager( ScheduleManager *sm ); void setShowTaskName( bool on ) { m_showTaskName = on; } void setShowProgress( bool on ) { m_showProgress = on; } void setShowPositiveFloat( bool on ) { m_showPositiveFloat = on; } void setShowCriticalTasks( bool on ) { m_showCriticalTasks = on; } void setShowNoInformation( bool on ) { m_showNoInformation = on; } protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); virtual void slotOptions(); private: bool m_readWrite; int m_defaultFontSize; QSplitter *m_splitter; MilestoneKGanttView *m_gantt; bool m_showTaskName; bool m_showProgress; bool m_showPositiveFloat; bool m_showCriticalTasks; bool m_showNoInformation; Project *m_project; }; class ResourceAppointmentsGanttViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: ResourceAppointmentsGanttViewSettingsDialog(GanttViewBase *gantt, ViewBase *view); public Q_SLOTS: void slotOk(); private: GanttViewBase *m_gantt; GanttPrintingOptionsWidget *m_printingoptions; }; class KPLATOUI_EXPORT ResourceAppointmentsGanttView : public ViewBase { Q_OBJECT public: ResourceAppointmentsGanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite = true); ~ResourceAppointmentsGanttView(); virtual void setZoom( double zoom ); virtual void setProject( Project *project ); Project *project() const; void setupGui(); virtual bool loadContext( const KoXmlElement &context ); virtual void saveContext( QDomElement &context ) const; void updateReadWrite( bool on ); KoPrintJob *createPrintJob(); GanttTreeView *treeView() const { return static_cast( m_gantt->leftView() ); } Node *currentNode() const; Q_SIGNALS: void itemDoubleClicked(); public Q_SLOTS: void setScheduleManager( ScheduleManager *sm ); protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); virtual void slotOptions(); private: GanttViewBase *m_gantt; Project *m_project; ResourceAppointmentsGanttModel *m_model; KGantt::TreeViewRowController *m_rowController; + QDomDocument m_domdoc; }; } //KPlato namespace #endif diff --git a/plan/libs/ui/kptresourceappointmentsview.cpp b/plan/libs/ui/kptresourceappointmentsview.cpp index 3af47c471db..b288b3d37ae 100644 --- a/plan/libs/ui/kptresourceappointmentsview.cpp +++ b/plan/libs/ui/kptresourceappointmentsview.cpp @@ -1,390 +1,416 @@ /* 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 "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()) ); } 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 ) : 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" ) ); connect( this, SIGNAL(accepted()), this, SLOT(slotOk())); connect( this, SIGNAL(accepted()), panel, SLOT(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()) ); 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())); l->addWidget( m_view ); m_view->setEditTriggers( m_view->editTriggers() | QAbstractItemView::EditKeyPressed ); connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); connect( m_view, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), this, SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } 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 createOptionAction(); } void ResourceAppointmentsView::slotOptions() { debugPlan; ResourceAppointmentsSettingsDialog *dlg = new ResourceAppointmentsSettingsDialog( this, m_view->model(), this ); 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/plan/libs/ui/kptresourceappointmentsview.h b/plan/libs/ui/kptresourceappointmentsview.h index 55b09da7597..e38e769d484 100644 --- a/plan/libs/ui/kptresourceappointmentsview.h +++ b/plan/libs/ui/kptresourceappointmentsview.h @@ -1,177 +1,180 @@ /* 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. */ #ifndef KPTRESOURCEAPPOINTMENTSVIEW_H #define KPTRESOURCEAPPOINTMENTSVIEW_H #include "kplatoui_export.h" #include "ui_kptresourceappointmentsdisplayoptions.h" #include "kptviewbase.h" #include "kptresourceappointmentsmodel.h" #include +#include + class KoPageLayoutWidget; class KoDocument; class QPoint; namespace KPlato { class View; class Project; class Resource; class ResourceGroup; class ScheduleManager; class ResourceAppointmentsItemModel; //------------------------------------------------- class ResourceAppointmentsDisplayOptionsPanel : public QWidget, public Ui::ResourceAppointmentsDisplayOptions { Q_OBJECT public: explicit ResourceAppointmentsDisplayOptionsPanel( ResourceAppointmentsItemModel *model, QWidget *parent = 0 ); void setValues( const ResourceAppointmentsItemModel &del ); public Q_SLOTS: void slotOk(); void setDefault(); Q_SIGNALS: void changed(); private: ResourceAppointmentsItemModel *m_model; }; class ResourceAppointmentsSettingsDialog : public KPageDialog { Q_OBJECT public: explicit ResourceAppointmentsSettingsDialog( ViewBase *view, ResourceAppointmentsItemModel *model, QWidget *parent = 0 ); public Q_SLOTS: void slotOk(); private: ViewBase *m_view; KoPageLayoutWidget *m_pagelayout; PrintingHeaderFooter *m_headerfooter; }; //------------------------ class KPLATOUI_EXPORT ResourceAppointmentsTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit ResourceAppointmentsTreeView(QWidget *parent); ResourceAppointmentsItemModel *model() const { return static_cast( DoubleTreeViewBase::model() ); } Project *project() const { return model()->project(); } void setProject( Project *project ) { model()->setProject( project ); } void setScheduleManager( ScheduleManager *sm ) { model()->setScheduleManager( sm ); } QModelIndex currentIndex() const; /// Load context info into this view. virtual bool loadContext( const KoXmlElement &context ); using DoubleTreeViewBase::loadContext; /// Save context info from this view. virtual void saveContext( QDomElement &context ) const; using DoubleTreeViewBase::saveContext; protected Q_SLOTS: void slotRefreshed(); private: ViewBase *m_view; }; class KPLATOUI_EXPORT ResourceAppointmentsView : public ViewBase { Q_OBJECT public: ResourceAppointmentsView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); virtual void setProject( Project *project ); Project *project() const { return m_view->project(); } virtual void draw( Project &project ); virtual void draw(); ResourceAppointmentsItemModel *model() const { return m_view->model(); } virtual void updateReadWrite( bool /*readwrite*/ ) {}; virtual Node *currentNode() const; virtual Resource *currentResource() const; virtual ResourceGroup *currentResourceGroup() const; /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); Q_SIGNALS: void requestPopupMenu( const QString&, const QPoint& ); void addResource( ResourceGroup* ); void deleteObjectList( const QObjectList& ); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); protected Q_SLOTS: virtual void slotOptions(); protected: void updateActionsEnabled( bool on = true ); private Q_SLOTS: void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex& ); void slotEnableActions( bool on ); void slotAddResource(); void slotAddGroup(); void slotDeleteSelection(); private: ResourceAppointmentsTreeView *m_view; QAction *actionAddResource; QAction *actionAddGroup; QAction *actionDeleteSelection; + QDomDocument m_domdoc; }; } //KPlato namespace #endif // KPTRESOURCEAPPOINTMENTSVIEW_H diff --git a/plan/libs/ui/kpttaskeditor.cpp b/plan/libs/ui/kpttaskeditor.cpp index e31a4504f40..5ecbd340760 100644 --- a/plan/libs/ui/kpttaskeditor.cpp +++ b/plan/libs/ui/kpttaskeditor.cpp @@ -1,1627 +1,1674 @@ /* 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 #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*)) ); } 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*)) ); } 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())); 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, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint,QModelIndexList)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); connect(baseModel(), SIGNAL(projectShownChanged(bool)), SLOT(slotProjectShown(bool))); connect(model(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, SLOT(slotEnableActions())); } 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(Project*)), m1, SLOT(setProject(Project*))); connect(this, SIGNAL(taskSelected(Task*)), m1, SLOT(setTask(Task*))); connect(m1, SIGNAL(expandAll()), x, SLOT(expandAll())); connect(m1, SIGNAL(resizeColumnToContents(int)), x, SLOT(resizeColumnToContents(int))); 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(const QItemSelection&, const QItemSelection&)), e, SLOT(setSelectedTasks(const QItemSelection&, const QItemSelection&))); connect(this, SIGNAL(projectChanged(Project*)), m, SLOT(setProject(Project*))); connect(this, SIGNAL(readWriteChanged(bool)), m, SLOT(setReadWrite(bool))); connect(m, SIGNAL(executeCommand(KUndo2Command*)), part(), SLOT(addCommand(KUndo2Command*))); 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 ); QTreeView *e = new QTreeView( ds ); TaskModuleModel *m = new TaskModuleModel( e ); e->setModel( m ); 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(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))); addDocker( ds ); } } 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("Edit..."); 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*))); lst << &tasksEdit; } lst += contextActionList(); if (!lst.isEmpty()) { QMenu::exec( lst, pos, lst.first() ); } } void TaskEditor::setScheduleManager( ScheduleManager *sm ) { - //debugPlan<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()) ); addAction( name, menuAddTask ); actionAddTask = new QAction( i18n( "Add Task" ), this); actionAddTask->setShortcut( Qt::CTRL + Qt::Key_I ); connect( actionAddTask, SIGNAL(triggered(bool)), SLOT(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()) ); 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()) ); 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()) ); 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()) ); 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()) ); 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())); 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())); 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())); 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())); 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))); addContextAction( actionShowProject ); connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); addContextAction( m_view->actionSplitView() ); createOptionAction(); 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(); 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 ) { - debugPlan; 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( baseModel()->columnMap(), context ); + 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())); 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, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } 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))); addContextAction( actionShowProject ); connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); addContextAction( m_view->actionSplitView() ); createOptionAction(); } 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(); 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())); 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, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); connect( m_view, SIGNAL(selectionChanged(QModelIndexList)), this, SLOT(slotSelectionChanged(QModelIndexList)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } 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()) ); addAction( name, actionMailWorkpackage ); // Add the context menu actions for the view options connect(m_view->actionSplitView(), SIGNAL(triggered(bool)), SLOT(slotSplitView())); addContextAction( m_view->actionSplitView() ); createOptionAction(); } 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(), SIGNAL(sendWorkpackages(QList,Resource*)), this, SLOT(slotWorkPackageSent(QList,Resource*)) ); 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(); 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/plan/libs/ui/kpttaskeditor.h b/plan/libs/ui/kpttaskeditor.h index 269b73a4ede..29705b2296d 100644 --- a/plan/libs/ui/kpttaskeditor.h +++ b/plan/libs/ui/kpttaskeditor.h @@ -1,353 +1,354 @@ /* This file is part of the KDE project Copyright (C) 2006 -20010 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 KPTTASKEDITOR_H #define KPTTASKEDITOR_H #include "kplatoui_export.h" #include "kptglobal.h" #include "kptnodeitemmodel.h" #include "kptviewbase.h" class KoDocument; class KActionMenu; namespace KPlato { class Project; class Node; class NodeItemModel; class MacroCommand; class KPLATOUI_EXPORT TaskEditorItemModel : public NodeItemModel { Q_OBJECT public: explicit TaskEditorItemModel( QObject *parent = 0 ); virtual Qt::ItemFlags flags( const QModelIndex & index ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) 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 ); protected: QVariant type( const Node *node, int role ) const; virtual bool setType( Node *node, const QVariant &value, int role ); }; class KPLATOUI_EXPORT TaskEditorTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit TaskEditorTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); NodeItemModel *baseModel() const; NodeSortFilterProxyModel *proxyModel() const { return qobject_cast( model() ); } Project *project() const { return baseModel()->project(); } void setProject( Project *project ) { baseModel()->setProject( project ); } Q_SIGNALS: void currentColumnChanged( const QModelIndex&, const QModelIndex& ); protected Q_SLOTS: void slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); }; class KPLATOUI_EXPORT NodeTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit NodeTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); NodeItemModel *baseModel() const; NodeSortFilterProxyModel *proxyModel() const { return qobject_cast( model() ); } Project *project() const { return baseModel()->project(); } void setProject( Project *project ) { baseModel()->setProject( project ); } Q_SIGNALS: void currentColumnChanged( const QModelIndex&, const QModelIndex& ); protected Q_SLOTS: void slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); }; class KPLATOUI_EXPORT TaskEditor : public ViewBase { Q_OBJECT public: TaskEditor(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); void setProject( Project *project ); Project *project() const { return m_view->project(); } virtual void createDockers(); virtual Node *currentNode() const; QList selectedNodes() const ; Node *selectedNode() const; virtual void updateReadWrite( bool readwrite ); NodeItemModel *baseModel() const { return m_view->baseModel(); } NodeSortFilterProxyModel *proxyModel() const { return m_view->proxyModel(); } QAbstractItemModel *model() const { return m_view->model(); } /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; virtual KoPrintJob *createPrintJob(); void setTaskModules( const QStringList &files ); Q_SIGNALS: void taskSelected( Task *task ); void openNode(); void addTask(); void addMilestone(); void addSubtask(); void addSubMilestone(); void deleteTaskList( const QList& ); void moveTaskUp(); void moveTaskDown(); void indentTask(); void unindentTask(); void loadTaskModules( const QStringList &files ); void saveTaskModule( const QUrl &url, Project *project ); void removeTaskModule( const QUrl &url ); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); protected: void updateActionsEnabled( bool on ); int selectedRowCount() const; QModelIndexList selectedRows() const; void editTasks(const QList &tasks, const QPoint &pos); protected Q_SLOTS: virtual void slotOptions(); private Q_SLOTS: void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested(const QModelIndex &index, const QPoint& pos , const QModelIndexList &rows); void slotEnableActions(); void slotAddTask(); void slotAddSubtask(); void slotAddMilestone(); void slotAddSubMilestone(); void slotDeleteTask(); void slotIndentTask(); void slotUnindentTask(); void slotMoveTaskUp(); void slotMoveTaskDown(); void slotSplitView(); void slotProjectShown( bool ); private: void edit( const QModelIndex &index ); private: TaskEditorTreeView *m_view; KActionMenu *menuAddTask; KActionMenu *menuAddSubTask; QAction *actionAddTask; QAction *actionAddMilestone; QAction *actionAddSubtask; QAction *actionAddSubMilestone; QAction *actionDeleteTask; QAction *actionMoveTaskUp; QAction *actionMoveTaskDown; QAction *actionIndentTask; QAction *actionUnindentTask; QAction *actionShowProject; + QDomDocument m_domdoc; }; class KPLATOUI_EXPORT TaskView : public ViewBase { Q_OBJECT public: TaskView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); Project *project() const { return m_view->project(); } virtual void draw( Project &project ); virtual void draw(); NodeItemModel *baseModel() const { return m_view->baseModel(); } NodeSortFilterProxyModel *proxyModel() const { return m_view->proxyModel(); } virtual Node *currentNode() const; QList selectedNodes() const ; Node *selectedNode() const; virtual void updateReadWrite( bool readwrite ); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); Q_SIGNALS: void openNode(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); protected: void updateActionsEnabled( bool on ); int selectedNodeCount() const; protected Q_SLOTS: virtual void slotOptions(); private Q_SLOTS: void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotEnableActions(); void slotSplitView(); private: NodeTreeView *m_view; QAction *actionShowProject; - + QDomDocument m_domdoc; }; //----------------------------------- class WorkPackageTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit WorkPackageTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); NodeItemModel *baseModel() const; WorkPackageProxyModel *proxyModel() const { return m; } Project *project() const { return baseModel()->project(); } void setProject( Project *project ) { m->setProject( project ); } ScheduleManager *scheduleManager() const { return baseModel()->manager(); } Q_SIGNALS: void currentColumnChanged( const QModelIndex&, const QModelIndex& ); protected Q_SLOTS: void slotDropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); protected: WorkPackageProxyModel *m; }; class KPLATOUI_EXPORT TaskWorkPackageView : public ViewBase { Q_OBJECT public: TaskWorkPackageView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); Project *project() const; void setProject( Project *project ); ScheduleManager *scheduleManager() const { return m_view->scheduleManager(); } WorkPackageProxyModel *proxyModel() const; virtual Node *currentNode() const; QList selectedNodes() const ; Node *selectedNode() const; virtual void updateReadWrite( bool readwrite ); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); Q_SIGNALS: void mailWorkpackage( Node *n, Resource *r = 0 ); void mailWorkpackages( const QList &nodes, Resource *r ); void checkForWorkPackages(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void slotRefreshView(); void setScheduleManager( ScheduleManager *sm ); protected: void updateActionsEnabled( bool on ); int selectedNodeCount() const; protected Q_SLOTS: virtual void slotOptions(); void slotMailWorkpackage(); void slotWorkPackageSent( const QList &nodes, Resource *resource ); private Q_SLOTS: void slotSelectionChanged( const QModelIndexList& ); void slotCurrentChanged( const QModelIndex&, const QModelIndex& ); void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotEnableActions(); void slotSplitView(); private: WorkPackageTreeView *m_view; MacroCommand *m_cmd; QAction *actionMailWorkpackage; }; } //namespace KPlato #endif diff --git a/plan/libs/ui/kpttaskstatusview.cpp b/plan/libs/ui/kpttaskstatusview.cpp index 725897c30d7..399d50b321a 100644 --- a/plan/libs/ui/kpttaskstatusview.cpp +++ b/plan/libs/ui/kpttaskstatusview.cpp @@ -1,1404 +1,1455 @@ /* 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 "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())); l->addWidget( m_view ); setupGui(); connect( model(), SIGNAL(executeCommand(KUndo2Command*)), doc, SLOT(addCommand(KUndo2Command*)) ); connect( m_view, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_view, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); } 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())); addContextAction( m_view->actionSplitView() ); createOptionAction(); } 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(); 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( 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()) ); } //----------------------------------- 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)) ); } 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<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())); 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() ) { ui_chart->takeCoordinatePlane( ui_chart->coordinatePlanes().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()) ); } m_project = project; if ( m_project ) { connect( m_project, SIGNAL(localeChanged()), this, SLOT(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)) ); QTimer::singleShot( 0, this, SLOT(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()) ); 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())); 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(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); } 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<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())); 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 ) : 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(); //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()) ); } //----------------- ProjectStatusViewSettingsDialog::ProjectStatusViewSettingsDialog( ViewBase *base, PerformanceStatusBase *view, QWidget *parent ) : 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" ) ); connect( this, SIGNAL(accepted()), panel, SLOT(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())); } void ProjectStatusViewSettingsDialog::slotOk() { debugPlan; m_base->setPageLayout( m_pagelayout->pageLayout() ); m_base->setPrintingOptions( m_headerfooter->options() ); } } // namespace KPlato diff --git a/plan/libs/ui/kpttaskstatusview.h b/plan/libs/ui/kpttaskstatusview.h index 85908076a26..004170c8b09 100644 --- a/plan/libs/ui/kpttaskstatusview.h +++ b/plan/libs/ui/kpttaskstatusview.h @@ -1,498 +1,501 @@ /* 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. */ #ifndef TASKSTATUSVIEW_H #define TASKSTATUSVIEW_H #include "kplatoui_export.h" #include "kptitemmodelbase.h" #include "kptviewbase.h" #include "ui_kpttaskstatusviewsettingspanel.h" #include "kptitemviewsettup.h" #include "ui_kptperformancestatus.h" #include "ui_kptperformancestatusviewsettingspanel.h" #include "kptnodechartmodel.h" #include #include class QItemSelection; class KoDocument; class KoPageLayoutWidget; class PrintingHeaderFooter; namespace KChart { class CartesianCoordinatePlane; class CartesianAxis; class Legend; }; namespace KPlato { class Project; class Node; class ScheduleManager; class TaskStatusItemModel; class NodeItemModel; class PerformanceStatusBase; typedef QList NodeList; class KPLATOUI_EXPORT TaskStatusTreeView : public DoubleTreeViewBase { Q_OBJECT public: explicit TaskStatusTreeView(QWidget *parent); //void setSelectionModel( QItemSelectionModel *selectionModel ); TaskStatusItemModel *model() const; Project *project() const; void setProject( Project *project ); int defaultWeekday() const { return Qt::Friday; } int weekday() const; void setWeekday( int day ); int defaultPeriod() const { return 7; } int period() const; void setPeriod( int days ); int defaultPeriodType() const; int periodType() const; void setPeriodType( int type ); protected: void dragMoveEvent(QDragMoveEvent *event); }; class KPLATOUI_EXPORT TaskStatusView : public ViewBase { Q_OBJECT public: TaskStatusView(KoPart *part, KoDocument *doc, QWidget *parent); void setupGui(); virtual void setProject( Project *project ); Project *project() const { return m_view->project(); } using ViewBase::draw; virtual void draw( Project &project ); TaskStatusItemModel *model() const { return m_view->model(); } virtual void updateReadWrite( bool readwrite ); virtual Node *currentNode() const; /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); Q_SIGNALS: void openNode(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); virtual void slotRefreshView(); protected Q_SLOTS: virtual void slotOptions(); protected: void updateActionsEnabled( bool on ); private Q_SLOTS: void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); void slotContextMenuRequested( Node *node, const QPoint& pos ); void slotSplitView(); private: Project *m_project; int m_id; TaskStatusTreeView *m_view; + QDomDocument m_domdoc; }; //-------------------------------------- class TaskStatusViewSettingsPanel : public QWidget, public Ui::TaskStatusViewSettingsPanel { Q_OBJECT public: explicit TaskStatusViewSettingsPanel( TaskStatusTreeView *view, QWidget *parent = 0 ); public Q_SLOTS: void slotOk(); void setDefault(); Q_SIGNALS: void changed(); private: TaskStatusTreeView *m_view; }; class TaskStatusViewSettingsDialog : public SplitItemViewSettupDialog { Q_OBJECT public: explicit TaskStatusViewSettingsDialog( ViewBase *view, TaskStatusTreeView *treeview, QWidget *parent = 0 ); }; struct PerformanceChartInfo { bool showBarChart; bool showLineChart; bool showTableView; bool showBaseValues; bool showIndices; bool showCost; bool showBCWSCost; bool showBCWPCost; bool showACWPCost; bool showEffort; bool showBCWSEffort; bool showBCWPEffort; bool showACWPEffort; bool showSpiCost; bool showCpiCost; bool showSpiEffort; bool showCpiEffort; bool effortShown() const { return ( showBaseValues && showEffort ) || ( showIndices && ( showSpiEffort || showCpiEffort ) ); } bool costShown() const { return ( showBaseValues && showCost ) || ( showIndices && ( showSpiCost || showCpiCost ) ); } bool bcwsCost() const { return showBaseValues && showCost && showBCWSCost; } bool bcwpCost() const { return showBaseValues && showCost && showBCWPCost; } bool acwpCost() const { return showBaseValues && showCost && showACWPCost; } bool bcwsEffort() const { return showBaseValues && showEffort && showBCWSEffort; } bool bcwpEffort() const { return showBaseValues && showEffort && showBCWPEffort; } bool acwpEffort() const { return showBaseValues && showEffort && showACWPEffort; } bool spiCost() const { return showIndices && showSpiCost; } bool cpiCost() const { return showIndices && showCpiCost; } bool spiEffort() const { return showIndices && showSpiEffort; } bool cpiEffort() const { return showIndices && showCpiEffort; } PerformanceChartInfo() { showBarChart = false; showLineChart = true; showTableView = false; showBaseValues = true; showIndices = false; showCost = showBCWSCost = showBCWPCost = showACWPCost = true; showEffort = showBCWSEffort = showBCWPEffort = showACWPEffort = true; showSpiCost = showCost = showSpiEffort = showCpiEffort = true; } bool operator!=( const PerformanceChartInfo &o ) const { return ! operator==( o ); } bool operator==( const PerformanceChartInfo &o ) const { return showBarChart == o.showBarChart && showLineChart == o.showLineChart && showBaseValues == o.showBaseValues && showIndices == o.showIndices && showCost == o.showCost && showBCWSCost == o.showBCWSCost && showBCWPCost == o.showBCWPCost && showACWPCost == o.showACWPCost && showEffort == o.showEffort && showBCWSEffort == o.showBCWSEffort && showBCWPEffort == o.showBCWPEffort && showACWPEffort == o.showACWPEffort && showSpiCost == o.showSpiCost && showCpiCost == o.showCpiCost && showSpiEffort == o.showSpiEffort && showCpiEffort == o.showCpiEffort; } }; //---------------------------------- class KPLATOUI_EXPORT PerformanceStatusPrintingDialog : public PrintingDialog { Q_OBJECT public: PerformanceStatusPrintingDialog( ViewBase *view, PerformanceStatusBase *chart, Project *project = 0 ); ~PerformanceStatusPrintingDialog() {} virtual int documentLastPage() const; virtual QList createOptionWidgets() const; protected: virtual void printPage( int pageNumber, QPainter &painter ); private: PerformanceStatusBase *m_chart; Project *m_project; }; class PerformanceStatusBase : public QWidget, public Ui::PerformanceStatus { Q_OBJECT public: explicit PerformanceStatusBase( QWidget *parent ); void setProject( Project *project ); void setScheduleManager( ScheduleManager *sm ); ChartItemModel *model() const { return const_cast( &m_chartmodel ); } void setupChart(); void setChartInfo( const PerformanceChartInfo &info ); PerformanceChartInfo chartInfo() const { return m_chartinfo; } /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &context ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &context ) const; /// Create a print job dialog KoPrintJob *createPrintJob( ViewBase *parent ); void setNodes( const QList &nodes ); public Q_SLOTS: void refreshChart(); protected: void contextMenuEvent( QContextMenuEvent *event ); void createBarChart(); void createLineChart(); void setEffortValuesVisible( bool visible ); void setCostValuesVisible( bool visible ); protected Q_SLOTS: void slotUpdate(); void slotLocaleChanged(); private: struct ChartContents { ~ChartContents() { delete dateaxis; delete effortaxis; delete costaxis; delete effortplane; delete costplane; delete effortdiagram; delete costdiagram; } ChartProxyModel costproxy; ChartProxyModel effortproxy; KChart::CartesianCoordinatePlane *effortplane; KChart::CartesianCoordinatePlane *costplane; KChart::AbstractDiagram *effortdiagram; KChart::AbstractDiagram *costdiagram; KChart::CartesianAxis *effortaxis; KChart::CartesianAxis *costaxis; KChart::CartesianAxis *dateaxis; ChartProxyModel piproxy; KChart::CartesianCoordinatePlane *piplane; KChart::AbstractDiagram *pidiagram; KChart::CartesianAxis *piaxis; }; void setupChart( ChartContents &cc ); private: Project *m_project; ScheduleManager *m_manager; PerformanceChartInfo m_chartinfo; ChartItemModel m_chartmodel; KChart::Legend *m_legend; KChart::BarDiagram m_legenddiagram; struct ChartContents m_barchart; struct ChartContents m_linechart; }; //---------------------------------- class KPLATOUI_EXPORT ProjectStatusView : public ViewBase { Q_OBJECT public: ProjectStatusView(KoPart *part, KoDocument *doc, QWidget *parent ); void setupGui(); Project *project() const { return m_project; } virtual void setProject( Project *project ); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &/*context*/ ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &/*context*/ ) const; KoPrintJob *createPrintJob(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); protected: void updateActionsEnabled( bool on ); protected Q_SLOTS: virtual void slotOptions(); private: Project *m_project; PerformanceStatusBase *m_view; }; //---------------------------------- class PerformanceStatusTreeView : public QSplitter { Q_OBJECT public: explicit PerformanceStatusTreeView( QWidget *parent ); NodeItemModel *nodeModel() const; Project *project() const; void setProject( Project *project ); void setScheduleManager( ScheduleManager *sm ); /// Loads context info into this view. virtual bool loadContext( const KoXmlElement &context ); /// Save context info from this view. virtual void saveContext( QDomElement &context ) const; TreeViewBase *treeView() const { return m_tree; } PerformanceStatusBase *chartView() const { return m_chart; } KoPrintJob *createPrintJob( ViewBase *view ); protected Q_SLOTS: void slotSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected ); void resizeSplitters(); private: TreeViewBase *m_tree; PerformanceStatusBase *m_chart; + ScheduleManager *m_manager; + QDomDocument m_domdoc; }; //---------------------------------- class KPLATOUI_EXPORT PerformanceStatusView : public ViewBase { Q_OBJECT public: PerformanceStatusView(KoPart *part, KoDocument *doc, QWidget *parent ); void setupGui(); Project *project() const { return m_view->project(); } virtual void setProject( Project *project ); /// Loads context info into this view. Reimplement. virtual bool loadContext( const KoXmlElement &context ); /// Save context info from this view. Reimplement. virtual void saveContext( QDomElement &context ) const; Node *currentNode() const; KoPrintJob *createPrintJob(); public Q_SLOTS: /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); void setScheduleManager( ScheduleManager *sm ); protected Q_SLOTS: virtual void slotOptions(); protected: void updateActionsEnabled( bool on ); private Q_SLOTS: void slotContextMenuRequested( Node *node, const QPoint& pos ); void slotContextMenuRequested( const QModelIndex &index, const QPoint& pos ); private: PerformanceStatusTreeView *m_view; }; //-------------------------------------- class PerformanceStatusViewSettingsPanel : public QWidget, public Ui::PerformanceStatusViewSettingsPanel { Q_OBJECT public: explicit PerformanceStatusViewSettingsPanel( PerformanceStatusBase *view, QWidget *parent = 0 ); public Q_SLOTS: void slotOk(); void setDefault(); Q_SIGNALS: void changed(); protected Q_SLOTS: void switchStackWidget(); private: PerformanceStatusBase *m_view; }; class PerformanceStatusViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: explicit PerformanceStatusViewSettingsDialog( PerformanceStatusView *view, PerformanceStatusTreeView *treeview, QWidget *parent = 0 ); }; class ProjectStatusViewSettingsDialog : public KPageDialog { Q_OBJECT public: explicit ProjectStatusViewSettingsDialog( ViewBase *base, PerformanceStatusBase *view, QWidget *parent = 0 ); protected Q_SLOTS: void slotOk(); private: ViewBase *m_base; KoPageLayoutWidget *m_pagelayout; PrintingHeaderFooter *m_headerfooter; }; } //namespace KPlato #endif diff --git a/plan/libs/ui/kptviewbase.cpp b/plan/libs/ui/kptviewbase.cpp index d314323add9..336305cca48 100644 --- a/plan/libs/ui/kptviewbase.cpp +++ b/plan/libs/ui/kptviewbase.cpp @@ -1,2405 +1,2481 @@ /* 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 #include #include #include #include #include "calligraversion.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 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))); } void DockWidget::activate( KoMainWindow *mainWindow ) { connect(this, SIGNAL(visibilityChanged(bool)), this, SLOT(setShown(bool))); 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))); 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_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())); } 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, 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))); 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))); 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::createOptionAction() { actionOptions = new QAction(koIcon("configure"), i18n("Configure View..."), this); connect(actionOptions, SIGNAL(triggered(bool)), SLOT(slotOptions())); addContextAction( actionOptions ); QAction *separator = new QAction(this); separator->setSeparator(true); addContextAction(separator); QAction *actionExpand = new QAction(koIcon("arrow-down"), i18n("Expand All"), this); connect(actionExpand, SIGNAL(triggered(bool)), this, SIGNAL(expandAll())); addContextAction(actionExpand); QAction *actionCollapse = new QAction(koIcon("arrow-up"), i18n("Collapse All"), this); connect(actionCollapse, SIGNAL(triggered(bool)), this, SIGNAL(collapseAll())); addContextAction(actionCollapse); } 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)) ); } 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( CALLIGRA_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 horisontally. 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 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)) ); } QTreeView::setModel( model ); if ( selectionModel() ) { connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); } setReadWrite( m_readWrite ); } void TreeViewBase::setSelectionModel( QItemSelectionModel *model ) { if ( selectionModel() ) { disconnect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); } QTreeView::setSelectionModel( model ); if ( selectionModel() ) { connect( selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex)) ); } } 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 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 ) const +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 = idx.model()->rowCount(idx); if (rowCount == 0) { return; } xpand ? expand(idx) : collapse(idx); for (int r = 0; r < rowCount; ++r) { expandRecursive(idx.child(r, 0), xpand); } } void TreeViewBase::slotExpand() { if (!m_contextMenuIndex.isValid()) { expandAll(); return; } QModelIndex idx = m_contextMenuIndex; if (!idx.column() != 0) { idx.model()->index(idx.row(), idx.column(), idx.parent()); } expandRecursive(idx, true); } void TreeViewBase::slotCollapse() { if (!m_contextMenuIndex.isValid()) { collapseAll(); return; } QModelIndex idx = m_contextMenuIndex; if (!idx.column() != 0) { idx.model()->index(idx.row(), idx.column(), 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())); +} + +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())); +} + +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 contaning 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( CALLIGRA_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_rightview, SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)) ); connect( m_rightview, SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotRightHeaderContextMenuRequested(QPoint)) ); connect( m_leftview->verticalScrollBar(), SIGNAL(valueChanged(int)), m_rightview->verticalScrollBar(), SLOT(setValue(int)) ); connect( m_rightview->verticalScrollBar(), SIGNAL(valueChanged(int)), m_leftview->verticalScrollBar(), SLOT(setValue(int)) ); connect( m_leftview, SIGNAL(moveAfterLastColumn(QModelIndex)), this, SLOT(slotToRightView(QModelIndex)) ); connect( m_rightview, SIGNAL(moveBeforeFirstColumn(QModelIndex)), this, SLOT(slotToLeftView(QModelIndex)) ); connect( m_leftview, SIGNAL(editAfterLastColumn(QModelIndex)), this, SLOT(slotEditToRightView(QModelIndex)) ); connect( m_rightview, SIGNAL(editBeforeFirstColumn(QModelIndex)), this, SLOT(slotEditToLeftView(QModelIndex)) ); connect( m_leftview, SIGNAL(expanded(QModelIndex)), m_rightview, SLOT(expand(QModelIndex)) ); connect( m_leftview, SIGNAL(collapsed(QModelIndex)), m_rightview, SLOT(collapse(QModelIndex)) ); connect( m_rightview, SIGNAL(expanded(QModelIndex)), m_leftview, SLOT(expand(QModelIndex)) ); connect( m_rightview, SIGNAL(collapsed(QModelIndex)), m_leftview, SLOT(collapse(QModelIndex)) ); 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*)) ); 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_rightview->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), SLOT(slotRightSortIndicatorChanged(int,Qt::SortOrder)) ); } 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, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(currentChanged(QModelIndex,QModelIndex)) ); } 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, SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SIGNAL(currentChanged(QModelIndex,QModelIndex)) ); 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, e ); + m_rightview->loadContext(map, slave, false); } - e = element.namedItem( "master" ).toElement(); - if ( ! e.isNull() ) { - m_leftview->loadContext( map, e ); + 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 { - //debugPlan<saveContext( map, e ); - e = element.ownerDocument().createElement( "slave" ); - element.appendChild( e ); - if ( m_rightview->isHidden() ) { - e.setAttribute( "hidden", "true" ); + 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, e ); + 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/plan/libs/ui/kptviewbase.h b/plan/libs/ui/kptviewbase.h index bab813ea96e..6d5579f94b8 100644 --- a/plan/libs/ui/kptviewbase.h +++ b/plan/libs/ui/kptviewbase.h @@ -1,659 +1,672 @@ /* This file is part of the KDE project Copyright (C) 2006 -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. */ #ifndef KPTVIEWBASE_H #define KPTVIEWBASE_H #include "kplatoui_export.h" #include "kptitemmodelbase.h" #include "ui_kptprintingheaderfooter.h" #include #include #include #include #include #include #include #include #include +#include class QMetaEnum; class QAbstractItemModel; +class QDomElement; +class QModelIndex; class KoDocument; class KoPrintJob; class KoPart; /// The main namespace namespace KPlato { class Project; class Node; class Resource; class ResourceGroup; class Relation; class Calendar; class ViewBase; class TreeViewBase; class DoubleTreeViewBase; //------------------ class KPLATOUI_EXPORT DockWidget : public QDockWidget { Q_OBJECT public: DockWidget( ViewBase *v, const QString &identity, const QString &title ); void activate( KoMainWindow *mainWindow ); void deactivate( KoMainWindow *mainWindow ); bool shown() const; bool saveXml( QDomElement &context ) const; void loadXml( const KoXmlElement &context ); const ViewBase *view; /// The view this docker belongs to QString id; /// Docker identity Qt::DockWidgetArea location; /// The area the docker should go when visible bool editor; /// Editor dockers will not be shown in read only mode public Q_SLOTS: void setShown( bool show ); void setLocation( Qt::DockWidgetArea area ); private: bool m_shown; /// The dockers visivbility when the view is active }; //------------------ class KPLATOUI_EXPORT PrintingOptions { public: PrintingOptions() { headerOptions.group = true; headerOptions.project = Qt::Checked; headerOptions.date = Qt::Checked; headerOptions.manager = Qt::Checked; headerOptions.page = Qt::Checked; footerOptions.group = false; footerOptions.project = Qt::Checked; footerOptions.date = Qt::Checked; footerOptions.manager = Qt::Checked; footerOptions.page = Qt::Checked; } ~PrintingOptions() {} bool loadXml( KoXmlElement &element ); void saveXml( QDomElement &element ) const; struct Data { bool group; Qt::CheckState project; Qt::CheckState date; Qt::CheckState manager; Qt::CheckState page; }; struct Data headerOptions; struct Data footerOptions; }; //------------------ class KPLATOUI_EXPORT PrintingHeaderFooter : public QWidget, public Ui::PrintingHeaderFooter { Q_OBJECT public: explicit PrintingHeaderFooter( const PrintingOptions &opt, QWidget *parent = 0 ); ~PrintingHeaderFooter(); void setOptions( const PrintingOptions &options ); PrintingOptions options() const; Q_SIGNALS: void changed(const PrintingOptions&); protected Q_SLOTS: void slotChanged(); private: PrintingOptions m_options; }; //------------------ class KPLATOUI_EXPORT PrintingDialog : public KoPrintingDialog { Q_OBJECT public: explicit PrintingDialog(ViewBase *view); ~PrintingDialog(); virtual QList createOptionWidgets() const; virtual QList shapesOnPage(int); QRect headerRect() const; QRect footerRect() const; void paintHeaderFooter( QPainter &p, const PrintingOptions &options, int pageNumber, const Project &project ); PrintingOptions printingOptions() const; QWidget *createPageLayoutWidget() const; QAbstractPrintDialog::PrintDialogOptions printDialogOptions() const; Q_SIGNALS: void changed( const PrintingOptions &opt ); void changed(); public Q_SLOTS: void setPrintingOptions( const PrintingOptions &opt); void setPrinterPageLayout( const KoPageLayout &pagelayout ); virtual void startPrinting(RemovePolicy removePolicy = DoNotDelete); protected: virtual void paint( QPainter &p, const PrintingOptions::Data &options, const QRect &rect, int pageNumber, const Project &project ); int headerFooterHeight( const PrintingOptions::Data &options ) const; void drawRect( QPainter &p, const QRect &r, Qt::Edges edges = Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); protected: ViewBase *m_view; PrintingHeaderFooter *m_widget; int m_textheight; }; class KPLATOUI_EXPORT ViewActionLists { public: ViewActionLists() : actionOptions( 0 ) {} virtual ~ViewActionLists() {} /// Returns the list of action lists that shall be plugged/unplugged virtual QStringList actionListNames() const { return m_actionListMap.keys(); } /// Returns the list of actions associated with the action list name virtual QList actionList( const QString &name ) const { return m_actionListMap[name]; } /// Add an action to the specified action list void addAction( const QString &list, QAction *action ) { m_actionListMap[list].append( action ); } virtual QList viewlistActionList() const { return m_viewlistActionList; } void addViewlistAction( QAction *action ) { m_viewlistActionList.append( action ); } QList contextActionList() const { return m_contextActionList; } void addContextAction( QAction *action ) { m_contextActionList.append( action ); } protected: /// List of all menu/toolbar actions (used for plug/unplug) QMap > m_actionListMap; /// List of actions that will be shown in the viewlist context menu QList m_viewlistActionList; /// List of actions that will be shown in the views header context menu QList m_contextActionList; // View options context menu QAction *actionOptions; }; /** ViewBase is the baseclass of all sub-views to View. */ class KPLATOUI_EXPORT ViewBase : public KoView, public ViewActionLists { Q_OBJECT public: /// Contructor ViewBase(KoPart *part, KoDocument *doc, QWidget *parent); /// Destructor virtual ~ViewBase(); /// Return the part (document) this view handles KoDocument *part() const; /// Return the page layout used for printing this view virtual KoPageLayout pageLayout() const; /// Return the type of view this is (class name) QString viewType() const { return metaObject()->className(); } /// Returns true if this view or any child widget has focus bool isActive() const; /// Set the project this view shall handle. virtual void setProject( Project *project ); /// Return the project virtual Project *project() const { return m_proj; } /// Return the schedule manager virtual ScheduleManager *scheduleManager() const { return m_schedulemanager; } /// Draw data from current part / project virtual void draw() {} /// Draw data from project. virtual void draw(Project &/*project*/) {} /// Draw changed data from project. virtual void drawChanges(Project &project) { draw(project); } /// Set readWrite mode virtual void updateReadWrite( bool ); bool isReadWrite() const { return m_readWrite; } /// Reimplement if your view handles nodes virtual Node* currentNode() const { return 0; } /// Reimplement if your view handles resources virtual Resource* currentResource() const { return 0; } /// Reimplement if your view handles resource groups virtual ResourceGroup* currentResourceGroup() const { return 0; } /// Reimplement if your view handles calendars virtual Calendar* currentCalendar() const { return 0; } /// Reimplement if your view handles relations virtual Relation *currentRelation() const { return 0; } /// Reimplement if your view handles zoom virtual KoZoomController *zoomController() const { return 0; } /// Loads context info (printer settings) into this view. virtual bool loadContext( const KoXmlElement &context ); /// Save context info (printer settings) from this view. virtual void saveContext( QDomElement &context ) const; virtual KoPrintJob *createPrintJob(); PrintingOptions printingOptions() const { return m_printingOptions; } static QWidget *createPageLayoutWidget( ViewBase *view ); static PrintingHeaderFooter *createHeaderFooterWidget( ViewBase *view ); void addAction( const QString &list, QAction *action ) { ViewActionLists::addAction( list, action ); } virtual void createDockers() {} void addDocker( DockWidget *ds ); QList dockers() const; DockWidget *findDocker( const QString &id ) const; public Q_SLOTS: void setPrintingOptions( const PrintingOptions &opt ) { m_printingOptions = opt; } /// Activate/deactivate the gui virtual void setGuiActive( bool activate ); virtual void setScheduleManager( ScheduleManager *sm ) { m_schedulemanager = sm; } void slotUpdateReadWrite( bool ); virtual void slotHeaderContextMenuRequested( const QPoint &pos ); virtual void slotEditCopy() {} virtual void slotEditCut() {} virtual void slotEditPaste() {} virtual void slotRefreshView() {} void setPageLayout( const KoPageLayout &layout ); Q_SIGNALS: /// Emitted when the gui has been activated or deactivated void guiActivated( ViewBase*, bool ); /// Request for a context menu popup void requestPopupMenu( const QString&, const QPoint & ); /// Emitted when options are modified void optionsModified(); void projectChanged( Project *project ); void readWriteChanged( bool ); void expandAll(); void collapseAll(); protected Q_SLOTS: virtual void slotOptions() {} virtual void slotOptionsFinished( int result ); protected: void createOptionAction(); bool m_readWrite; PrintingOptions m_printingOptions; Project *m_proj; ScheduleManager *m_schedulemanager; KoPageLayout m_pagelayout; QList m_dockers; }; //------------------ class KPLATOUI_EXPORT TreeViewPrintingDialog : public PrintingDialog { Q_OBJECT public: TreeViewPrintingDialog( ViewBase *view, TreeViewBase *treeview, Project *project = 0 ); ~TreeViewPrintingDialog() {} virtual int documentFirstPage() const { return 1; } virtual int documentLastPage() const; QList createOptionWidgets() const; protected: virtual void printPage( int pageNumber, QPainter &painter ); int firstRow( int page ) const; private: TreeViewBase *m_tree; Project *m_project; int m_firstRow; }; //----------------- class KPLATOUI_EXPORT TreeViewBase : public QTreeView { Q_OBJECT public: explicit TreeViewBase( QWidget *parent = 0 ); void setReadWrite( bool rw ); virtual void createItemDelegates( ItemModelBase *model ); void setArrowKeyNavigation( bool on ) { m_arrowKeyNavigation = on; } bool arrowKeyNavigation() const { return m_arrowKeyNavigation; } /// Move move to first visual QModelIndex firstColumn( int row, const QModelIndex &parent ); /// Move move to last visual QModelIndex lastColumn( int row, const QModelIndex &parent ); /// Move from @p current to next item QModelIndex nextColumn( const QModelIndex ¤t ); /// Move from @p current to next item QModelIndex previousColumn( const QModelIndex ¤t ); /// Move to first editable index in @p row with @p parent QModelIndex firstEditable( int row, const QModelIndex &parent ); /// Move to last editable index in @p row with @p parent QModelIndex lastEditable( int row, const QModelIndex &parent ); void setAcceptDropsOnView( bool mode ) { m_acceptDropsOnView = mode; } virtual void setModel( QAbstractItemModel *model ); virtual void setSelectionModel( QItemSelectionModel *model ); void setStretchLastSection( bool ); void mapToSection( int column, int section ); int section( int col ) const; void setColumnsHidden( const QList &list ); /// Loads context info into this view. Reimplement. - virtual bool loadContext( const QMetaEnum &map, const KoXmlElement &element ); + virtual bool loadContext(const QMetaEnum &map, const KoXmlElement &element, bool expand = true); /// Save context info from this view. Reimplement. - virtual void saveContext( const QMetaEnum &map, QDomElement &context ) const; + virtual void saveContext(const QMetaEnum &map, QDomElement &context , bool expand = true) const; /** Reimplemented to fix qt bug 160083: Doesn't scroll horisontally. Scroll the contents of the tree view until the given model item \a index is visible. The \a hint parameter specifies more precisely where the item should be located after the operation. If any of the parents of the model item are collapsed, they will be expanded to ensure that the model item is visible. */ void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible); void setDefaultColumns( const QList &lst ) { m_defaultColumns = lst; } QList defaultColumns() const { return m_defaultColumns; } KoPrintJob *createPrintJob( ViewBase *parent ); QModelIndex firstVisibleIndex( const QModelIndex &idx ) const; ItemModelBase *itemModel() const; void setContextMenuIndex(const QModelIndex &idx); + void loadExpanded(const KoXmlElement &element); + void saveExpanded(QDomElement &element, const QModelIndex &parent = QModelIndex()) const; + void expandRecursivly(QDomElement element, const QModelIndex &parent = QModelIndex()); + void doExpand(QDomDocument &doc); + public Q_SLOTS: void slotExpand(); void slotCollapse(); Q_SIGNALS: /// Context menu requested from viewport at global position @p pos void contextMenuRequested( const QModelIndex&, const QPoint &pos, const QModelIndexList& ); /// Context menu requested from header at global position @p pos void headerContextMenuRequested( const QPoint &pos ); void moveAfterLastColumn( const QModelIndex & ); void moveBeforeFirstColumn( const QModelIndex & ); void editAfterLastColumn( const QModelIndex & ); void editBeforeFirstColumn( const QModelIndex & ); void dropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); protected: void keyPressEvent(QKeyEvent *event); void mousePressEvent( QMouseEvent *event ); /** Reimplemented from QTreeView to make tab/backtab in editor work reasonably well. Move the cursor in the way described by \a cursorAction, *not* using the information provided by the button \a modifiers. */ QModelIndex moveCursor( CursorAction cursorAction, Qt::KeyboardModifiers modifiers ); /// Move cursor from @p index in direction @p cursorAction. @p modifiers is not used. QModelIndex moveCursor( const QModelIndex &index, CursorAction cursorAction, Qt::KeyboardModifiers = Qt::NoModifier ); /// Move from @p index to next editable item, in direction @p cursorAction. QModelIndex moveToEditable( const QModelIndex &index, CursorAction cursorAction ); void contextMenuEvent ( QContextMenuEvent * event ); void dragMoveEvent(QDragMoveEvent *event); void dropEvent( QDropEvent *e ); void updateSelection( const QModelIndex &oldidx, const QModelIndex &newidx, QKeyEvent *event ); void expandRecursive(const QModelIndex &parent, bool xpand); protected Q_SLOTS: /// Close the @p editor, using sender()->endEditHint(). /// Use @p hint if sender is not of type ItemDelegate. virtual void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint); virtual void slotCurrentChanged ( const QModelIndex & current, const QModelIndex & previous ); void slotHeaderContextMenuRequested( const QPoint& ); //Copied from QAbstractItemView inline QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const { switch (selectionBehavior()) { case QAbstractItemView::SelectRows: return QItemSelectionModel::Rows; case QAbstractItemView::SelectColumns: return QItemSelectionModel::Columns; case QAbstractItemView::SelectItems: default: return QItemSelectionModel::NoUpdate; } } + void doContextExpanded(); + void doExpanded(); + protected: virtual void focusInEvent(QFocusEvent *event); bool m_arrowKeyNavigation; bool m_acceptDropsOnView; QList m_hideList; bool m_readWrite; QList m_defaultColumns; QPersistentModelIndex m_contextMenuIndex; + QDomDocument m_loadContextDoc; + QDomDocument m_expandDoc; }; //------------------ class KPLATOUI_EXPORT DoubleTreeViewPrintingDialog : public PrintingDialog { Q_OBJECT public: DoubleTreeViewPrintingDialog( ViewBase *view, DoubleTreeViewBase *treeview, Project *project ); ~DoubleTreeViewPrintingDialog() {} virtual int documentFirstPage() const { return 1; } virtual int documentLastPage() const; QList createOptionWidgets() const; protected: virtual void printPage( int pageNumber, QPainter &painter ); int firstRow( int page ) const; private: DoubleTreeViewBase *m_tree; Project *m_project; int m_firstRow; }; class KPLATOUI_EXPORT DoubleTreeViewBase : public QSplitter { Q_OBJECT public: explicit DoubleTreeViewBase( QWidget *parent ); DoubleTreeViewBase( bool mode, QWidget *parent ); ~DoubleTreeViewBase(); void setReadWrite( bool rw ); void closePersistentEditor( const QModelIndex &index ); void setModel( QAbstractItemModel *model ); QAbstractItemModel *model() const; void setArrowKeyNavigation( bool on ) { m_arrowKeyNavigation = on; } bool arrowKeyNavigation() const { return m_arrowKeyNavigation; } QItemSelectionModel *selectionModel() const { return m_selectionmodel; } void setSelectionModel( QItemSelectionModel *model ); void setSelectionMode( QAbstractItemView::SelectionMode mode ); void setSelectionBehavior( QAbstractItemView::SelectionBehavior mode ); virtual void createItemDelegates( ItemModelBase *model ); void setItemDelegateForColumn( int col, QAbstractItemDelegate * delegate ); void setEditTriggers ( QAbstractItemView::EditTriggers ); QAbstractItemView::EditTriggers editTriggers() const; void setAcceptDrops( bool ); void setAcceptDropsOnView( bool ); void setDropIndicatorShown( bool ); void setDragDropMode( QAbstractItemView::DragDropMode mode ); void setDragDropOverwriteMode( bool mode ); void setDragEnabled ( bool mode ); void setDefaultDropAction( Qt::DropAction action ); void setStretchLastSection( bool ); /// Hide columns in the @p hideList, show all other columns. /// If the hideList.last() == -1, the rest of the columns are hidden. void hideColumns( TreeViewBase *view, const QList &hideList ); void hideColumns( const QList &masterList, const QList &slaveList = QList() ); void hideColumn( int col ) { m_leftview->hideColumn( col ); if ( m_rightview ) m_rightview->hideColumn( col ); } void showColumn( int col ) { if ( col == 0 || m_rightview == 0 ) m_leftview->showColumn( col ); else m_rightview->showColumn( col ); } bool isColumnHidden( int col ) const { return m_rightview ? m_rightview->isColumnHidden( col ) : m_leftview->isColumnHidden( col ); } TreeViewBase *masterView() const { return m_leftview; } TreeViewBase *slaveView() const { return m_rightview; } /// Loads context info into this view. Reimplement. virtual bool loadContext( const QMetaEnum &map, const KoXmlElement &element ); /// Save context info from this view. Reimplement. virtual void saveContext( const QMetaEnum &map, QDomElement &context ) const; void setViewSplitMode( bool split ); bool isViewSplit() const { return m_mode; } QAction *actionSplitView() const { return m_actionSplitView; } void setRootIsDecorated ( bool show ); KoPrintJob *createPrintJob( ViewBase *parent ); void setStretchFactors(); QModelIndex indexAt( const QPoint &pos ) const; void setParentsExpanded( const QModelIndex &idx, bool expanded ); void setSortingEnabled( bool on ) { m_leftview->setSortingEnabled( on ); m_rightview->setSortingEnabled( on ); } void sortByColumn( int col, Qt::SortOrder order = Qt::AscendingOrder ) { if ( ! m_leftview->isColumnHidden( col ) || ! m_rightview->isVisible() || m_rightview->isColumnHidden( col ) ) { m_leftview->sortByColumn( col, order ); } else { m_rightview->sortByColumn( col, order ); } } void setContextMenuIndex(const QModelIndex &idx); Q_SIGNALS: /// Context menu requested from the viewport, pointer over @p index at global position @p pos void contextMenuRequested( const QModelIndex &index, const QPoint& pos, const QModelIndexList& ); /// Context menu requested from master- or slave header at global position @p pos void headerContextMenuRequested( const QPoint &pos ); /// Context menu requested from master header at global position @p pos void masterHeaderContextMenuRequested( const QPoint &pos ); /// Context menu requested from slave header at global position @p pos void slaveHeaderContextMenuRequested( const QPoint &pos ); void currentChanged ( const QModelIndex & current, const QModelIndex & previous ); void selectionChanged( const QModelIndexList& ); void dropAllowed( const QModelIndex &index, int dropIndicatorPosition, QDragMoveEvent *event ); public Q_SLOTS: void edit( const QModelIndex &index ); void slotExpand(); void slotCollapse(); protected Q_SLOTS: void slotSelectionChanged( const QItemSelection &sel, const QItemSelection & ); void slotToRightView( const QModelIndex &index ); void slotToLeftView( const QModelIndex &index ); void slotEditToRightView( const QModelIndex &index ); void slotEditToLeftView( const QModelIndex &index ); void slotRightHeaderContextMenuRequested( const QPoint &pos ); void slotLeftHeaderContextMenuRequested( const QPoint &pos ); void slotLeftSortIndicatorChanged( int logicalIndex, Qt::SortOrder order ); void slotRightSortIndicatorChanged( int logicalIndex, Qt::SortOrder order ); protected: void init(); QList expandColumnList( const QList &lst ) const; protected: TreeViewBase *m_leftview; TreeViewBase *m_rightview; QItemSelectionModel *m_selectionmodel; bool m_arrowKeyNavigation; bool m_readWrite; bool m_mode; QAction *m_actionSplitView; }; } // namespace KPlato #endif