diff --git a/src/libs/ui/kptganttview.cpp b/src/libs/ui/kptganttview.cpp index 9133827f..8e7fc2f6 100644 --- a/src/libs/ui/kptganttview.cpp +++ b/src/libs/ui/kptganttview.cpp @@ -1,1932 +1,1957 @@ /* 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. */ // clazy:excludeall=qstring-arg #include "kptganttview.h" #include "kptnodeitemmodel.h" #include "kptappointment.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptrelation.h" #include "kptschedule.h" #include "kptviewbase.h" #include "kptitemviewsettup.h" #include "kptduration.h" #include "kptdatetime.h" #include "kptresourceappointmentsmodel.h" #include "Help.h" #include "kptdebug.h" #include "gantt/DateTimeTimeLine.h" #include "gantt/DateTimeGrid.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include /// The main namespace namespace KPlato { class GanttItemDelegate; //------------------------------------------------- GanttChartDisplayOptionsPanel::GanttChartDisplayOptionsPanel( GanttViewBase *gantt, GanttItemDelegate *delegate, QWidget *parent ) : QWidget( parent ) , m_delegate( delegate ) , m_gantt(gantt) { setupUi( this ); setValues( *delegate ); connect( ui_showTaskName, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showResourceNames, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showDependencies, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showPositiveFloat, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showNegativeFloat, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showCriticalPath, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showCriticalTasks, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showCompletion, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showSchedulingError, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); connect( ui_showTimeConstraint, &QCheckBox::stateChanged, this, &GanttChartDisplayOptionsPanel::changed ); } void GanttChartDisplayOptionsPanel::slotOk() { m_delegate->showTaskName = ui_showTaskName->checkState() == Qt::Checked; m_delegate->showResources = ui_showResourceNames->checkState() == Qt::Checked; m_delegate->showTaskLinks = ui_showDependencies->checkState() == Qt::Checked; m_delegate->showPositiveFloat = ui_showPositiveFloat->checkState() == Qt::Checked; m_delegate->showNegativeFloat = ui_showNegativeFloat->checkState() == Qt::Checked; m_delegate->showCriticalPath = ui_showCriticalPath->checkState() == Qt::Checked; m_delegate->showCriticalTasks = ui_showCriticalTasks->checkState() == Qt::Checked; m_delegate->showProgress = ui_showCompletion->checkState() == Qt::Checked; m_delegate->showSchedulingError = ui_showSchedulingError->checkState() == Qt::Checked; m_delegate->showTimeConstraint = ui_showTimeConstraint->checkState() == Qt::Checked; DateTimeTimeLine *timeline = m_gantt->timeLine(); timeline->setInterval(ui_timeLineInterval->value() * 60000); QPen pen; pen.setWidth(ui_timeLineStroke->value()); pen.setColor(ui_timeLineColor->color()); timeline->setPen(pen); DateTimeTimeLine::Options opt = timeline->options(); opt.setFlag(DateTimeTimeLine::Foreground, ui_timeLineForeground->isChecked()); opt.setFlag(DateTimeTimeLine::Background, ui_timeLineBackground->isChecked()); opt.setFlag(DateTimeTimeLine::UseCustomPen, ui_timeLineUseCustom->isChecked()); timeline->setOptions(opt); } 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 ); DateTimeTimeLine *timeline = m_gantt->timeLine(); ui_timeLineInterval->setValue(timeline->interval() / 60000); QPen pen = timeline->pen(); ui_timeLineStroke->setValue(pen.width()); ui_timeLineColor->setColor(pen.color()); ui_timeLineHide->setChecked(true); DateTimeTimeLine::Options opt = timeline->options(); ui_timeLineBackground->setChecked(opt & DateTimeTimeLine::Background); ui_timeLineForeground->setChecked(opt & DateTimeTimeLine::Foreground); ui_timeLineUseCustom->setChecked(opt & DateTimeTimeLine::UseCustomPen); } void GanttChartDisplayOptionsPanel::setDefault() { GanttItemDelegate del; setValues( del ); } //---- GanttViewSettingsDialog::GanttViewSettingsDialog( GanttViewBase *gantt, GanttItemDelegate *delegate, ViewBase *view, bool selectPrint ) : ItemViewSettupDialog( view, gantt->treeView(), true, view ), m_gantt( gantt ) { GanttChartDisplayOptionsPanel *panel = new GanttChartDisplayOptionsPanel( gantt, delegate ); /*KPageWidgetItem *page = */insertWidget( 1, panel, i18n( "Chart" ), i18n( "Gantt Chart Settings" ) ); QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_printingoptions = new GanttPrintingOptionsWidget( this ); m_printingoptions->setOptions( gantt->printingOptions() ); tab->addTab( m_printingoptions, m_printingoptions->windowTitle() ); KPageWidgetItem *page = insertWidget( 2, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); connect( this, &QDialog::accepted, panel, &GanttChartDisplayOptionsPanel::slotOk ); connect( button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, panel, &GanttChartDisplayOptionsPanel::setDefault ); } void GanttViewSettingsDialog::slotOk() { debugPlan; m_gantt->setPrintingOptions( m_printingoptions->options()); ItemViewSettupDialog::slotOk(); } //------------------------- GanttPrintingOptions::GanttPrintingOptions() : printRowLabels( true ), singlePage( true ) { } bool GanttPrintingOptions::loadContext( const KoXmlElement &settings ) { KoXmlElement e = settings.namedItem( "print-options" ).toElement(); if ( ! e.isNull() ) { printRowLabels = (bool)( e.attribute( "print-rowlabels", "0" ).toInt() ); singlePage = (bool)( e.attribute( "print-singlepage", "0" ).toInt() ); } debugPlan <<"..........."<treeView()->header()->height(); // same header hight m_sceneRect = gantt->graphicsView()->sceneRect(); m_horPages = 1; qreal c = m_sceneRect.width() - printer().pageRect().width(); while ( c > 0 ) { ++m_horPages; c -= printer().pageRect().width(); } m_vertPages = 1; c = m_sceneRect.height() - printer().pageRect().height() - m_headerHeight; while ( c > 0 ) { ++m_vertPages; c -= printer().pageRect().height(); } debugPlan< pages; if ( printer().fromPage() > 0 ) { pages << printer().fromPage(); if ( ! m_gantt->m_printOptions.singlePage ) { int last = printer().toPage(); for ( int i = pages.first() + 1; i <= last; ++i ) { pages << i; } if (m_vertPages > 1) { m_image = QImage(m_sceneRect.width(), m_sceneRect.height() + m_headerHeight, QImage::Format_ARGB32); m_image.fill(Qt::white); QPainter p(&m_image); m_gantt->print(&p, m_image.rect(), m_gantt->m_printOptions.printRowLabels, true); } } } setPageRange( pages ); PrintingDialog::startPrinting( removePolicy ); } QList GanttPrintingDialog::createOptionWidgets() const { //debugPlan; GanttPrintingOptionsWidget *w = new GanttPrintingOptionsWidget(); w->setPrintRowLabels( m_gantt->m_printOptions.printRowLabels ); connect(w->ui_printRowLabels, &QAbstractButton::toggled, this, &GanttPrintingDialog::slotPrintRowLabelsToogled); w->setSinglePage( m_gantt->m_printOptions.singlePage ); connect(w->ui_singlePage, &QAbstractButton::toggled, this, &GanttPrintingDialog::slotSinglePageToogled); const_cast( this )->m_options = w; return QList() << createPageLayoutWidget() << m_options; } void GanttPrintingDialog::slotPrintRowLabelsToogled( bool on ) { m_gantt->m_printOptions.printRowLabels = on; } void GanttPrintingDialog::slotSinglePageToogled( bool on ) { m_gantt->m_printOptions.singlePage = on; printer().setFromTo( documentFirstPage(), documentLastPage() ); } int GanttPrintingDialog::documentLastPage() const { //debugPlan<m_printOptions.singlePage<m_printOptions.singlePage ? documentFirstPage() : m_horPages * m_vertPages; } void GanttPrintingDialog::printPage( int page, QPainter &painter ) { debugPlan<<"page:"<m_printOptions.singlePage; int vert = singlePage ? 0 : p / m_horPages; int hor = singlePage ? 0 : p % m_horPages; // painter.setClipRect( pageRect.adjusted( -1.0, -1.0, 1.0, 1.0 ) ); if (singlePage) { // single page: use KGantt m_gantt->print( &painter, m_sceneRect.left(), m_sceneRect.right(), pageRect, m_gantt->m_printOptions.printRowLabels, true ); } else if (m_vertPages == 1) { // single vertical page: use KGantt qreal hh = vert == 0 ? m_headerHeight : 0; qreal ho = vert > 0 ? m_headerHeight : 0; QRectF sourceRect = QRectF( m_sceneRect.x() + ( pageRect.width() * hor ), m_sceneRect.y() + ( ( pageRect.height() * vert ) - ho ), pageRect.width(), pageRect.height() - hh ); debugPlan<print( &painter, sourceRect.left(), sourceRect.right(), pageRect, hor == 0 && m_gantt->m_printOptions.printRowLabels, true ); } else { // print on multiple vertical pages: use pixmap // QT5TODO Make KGantt able to print multiple pages vertically QRectF sourceRect = m_image.rect(); qreal hh = vert == 0 ? m_headerHeight : 0; qreal ho = vert > 0 ? m_headerHeight : 0; sourceRect = QRectF( sourceRect.x() + ( pageRect.width() * hor ), sourceRect.y() + ( ( pageRect.height() * vert ) - ho ), pageRect.width(), pageRect.height() - hh ); debugPlan<setContextMenuPolicy( Qt::CustomContextMenu ); connect( header(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotHeaderContextMenuRequested(QPoint)) ); } //------------------------------------------- GanttZoomWidget::GanttZoomWidget( QWidget *parent ) : QSlider( parent ), m_hide( true ), m_grid( 0 ) { setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); setGeometry( 0, 0, 200, minimumSizeHint().height() ); setContextMenuPolicy( Qt::PreventContextMenu ); setOrientation( Qt::Horizontal ); setPageStep( 5 ); setMaximum( 125 ); connect(this, &QAbstractSlider::valueChanged, this, &GanttZoomWidget::sliderValueChanged); } void GanttZoomWidget::setEnableHideOnLeave( bool hide ) { m_hide = hide; } void GanttZoomWidget::setGrid( KGantt::DateTimeGrid *grid ) { m_grid = grid; if ( grid ) { int pos = -1; // daywidth always >= 0.1 for ( qreal dw = grid->dayWidth(); dw >= 0.1 && pos < maximum(); ++pos ) { dw *= 1.0 / 1.1; } blockSignals( true ); setValue( pos ); blockSignals( false ); } } void GanttZoomWidget::leaveEvent( QEvent *e ) { if ( m_hide ) { setVisible( false ); } QSlider::leaveEvent( e ); } void GanttZoomWidget::sliderValueChanged( int value ) { //debugPlan<setDayWidth( v ); } } //------------------------------------------- GanttViewBase::GanttViewBase( QWidget *parent ) : KGantt::View( parent ) { setGrid(new DateTimeGrid()); 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"))); g->timeNow()->setInterval(5000); QLocale locale; g->setWeekStart( locale.firstDayOfWeek() ); const QList weekdays = locale.weekdays(); QSet fd; for ( int i = Qt::Monday; i <= Qt::Sunday; ++i ) { if (!weekdays.contains(static_cast(i))) { fd << static_cast( i ); } } g->setFreeDays( fd ); m_zoomwidget = new GanttZoomWidget( graphicsView() ); m_zoomwidget->setGrid( g ); m_zoomwidget->setEnableHideOnLeave( true ); m_zoomwidget->hide(); m_zoomwidget->move( 6, 6 ); graphicsView()->installEventFilter(this); graphicsView()->setMouseTracking(true); } GanttViewBase::~GanttViewBase() { // HACK: avoid crash due to access of graphicsview scrollbar after death // KGantt tries to sync leftview scrollbar with graphicsview scrollbar // and seems sometimes graphicsview has already been deleted. // Note: this will be fixed in next KGantt release leftView()->verticalScrollBar()->disconnect(); } +void GanttViewBase::editCopy() +{ + QMimeData *mimeData = new QMimeData; + QPixmap pixmap(size()); + render(&pixmap); + mimeData->setImageData(pixmap); + QGuiApplication::clipboard()->setMimeData(mimeData); +} + DateTimeTimeLine *GanttViewBase::timeLine() const { DateTimeGrid *g = static_cast( grid() ); return g->timeNow(); } 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() ); DateTimeTimeLine::Options opt; opt.setFlag(DateTimeTimeLine::Foreground, settings.attribute("timeline-foreground").toInt()); opt.setFlag(DateTimeTimeLine::Background, settings.attribute("timeline-background").toInt()); opt.setFlag(DateTimeTimeLine::UseCustomPen, settings.attribute("timeline-custom").toInt()); timeLine()->setOptions(opt); timeLine()->setInterval(settings.attribute("timeline-interval", 0).toInt() * 60000); QPen pen; pen.setWidth(settings.attribute("timeline-width").toInt()); pen.setColor(QColor(settings.attribute("timeline-color"))); timeLine()->setPen(pen); 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()) ); settings.setAttribute("timeline-foreground", timeLine()->options() & DateTimeTimeLine::Foreground); settings.setAttribute("timeline-background", timeLine()->options() & DateTimeTimeLine::Background); settings.setAttribute("timeline-interval", timeLine()->interval() / 60000); settings.setAttribute("timeline-custom", timeLine()->options() & DateTimeTimeLine::UseCustomPen); settings.setAttribute("timeline-width", timeLine()->pen().width()); settings.setAttribute("timeline-color", timeLine()->pen().color().name()); } void GanttViewBase::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_dragStartPosition = event->pos(); } KGantt::View::mousePressEvent(event); } void GanttViewBase::mouseMoveEvent(QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) { KGantt::View::mouseMoveEvent(event); return; } if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { KGantt::View::mouseMoveEvent(event); return; } QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; QPixmap pixmap(size()); render(&pixmap); mimeData->setImageData(pixmap); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } //------------------------------------------- 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, true); 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 ); } void NodeGanttViewBase::setShowUnscheduledTasks(bool show) { NodeSortFilterProxyModel *m = qobject_cast(KGantt::View::model()); if (m) { m->setFilterUnscheduled(!show); } } //------------------------------------------- MyKGanttView::MyKGanttView( QWidget *parent ) : NodeGanttViewBase( parent ), m_manager( 0 ) { debugPlan<<"------------------- create MyKGanttView -----------------------"; GanttItemModel *gm = new GanttItemModel( this ); for (int i = 0; i < gm->columnCount(); ++i) { if (i != NodeModel::NodeCompleted) { gm->setReadOnly(i, true); } } 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(), &NodeItemModel::nodeInserted, this, &MyKGanttView::slotNodeInserted ); } GanttItemModel *MyKGanttView::model() const { return static_cast( NodeGanttViewBase::model() ); } void MyKGanttView::setProject( Project *proj ) { clearDependencies(); if ( project() ) { disconnect( project(), &Project::relationToBeModified, this, &MyKGanttView::removeDependency); disconnect( project(), &Project::relationModified, this, &MyKGanttView::addDependency); disconnect( project(), &Project::relationAdded, this, &MyKGanttView::addDependency ); disconnect( project(), &Project::relationToBeRemoved, this, &MyKGanttView::removeDependency ); disconnect( project(), &Project::projectCalculated, this, &MyKGanttView::slotProjectCalculated ); } NodeGanttViewBase::setProject( proj ); if ( proj ) { connect( project(), &Project::relationToBeModified, this, &MyKGanttView::removeDependency); connect( project(), &Project::relationModified, this, &MyKGanttView::addDependency); connect( proj, &Project::relationAdded, this, &MyKGanttView::addDependency ); connect( proj, &Project::relationToBeRemoved, this, &MyKGanttView::removeDependency ); connect( proj, &Project::projectCalculated, this, &MyKGanttView::slotProjectCalculated ); } createDependencies(); } void MyKGanttView::slotProjectCalculated( ScheduleManager *sm ) { if ( m_manager == sm ) { setScheduleManager( sm ); } } void MyKGanttView::setScheduleManager( ScheduleManager *sm ) { constraintModel()->clear(); m_manager = sm; KGantt::DateTimeGrid *g = static_cast( grid() ); if ( sm && project() ) { QDateTime start = project()->startTime( sm->scheduleId() ); if ( start.isValid() && g->startDateTime() != start ) { g->setStartDateTime( start ); } } if ( ! g->startDateTime().isValid() ) { g->setStartDateTime( QDateTime::currentDateTime() ); } model()->setScheduleManager( sm ); createDependencies(); } void MyKGanttView::slotNodeInserted( Node *node ) { foreach( Relation *r, node->dependChildNodes() ) { addDependency( r ); } foreach( Relation *r, node->dependParentNodes() ) { addDependency( r ); } } void MyKGanttView::addDependency( Relation *rel ) { QModelIndex par = sfModel()->mapFromSource( model()->index( rel->parent() ) ); QModelIndex ch = sfModel()->mapFromSource( model()->index( rel->child() ) ); // debugPlan<<"addDependency() "<( rel->type() )/*NOTE!!*/ ); if ( ! constraintModel()->hasConstraint( con ) ) { constraintModel()->addConstraint( con ); } } } void MyKGanttView::removeDependency( Relation *rel ) { QModelIndex par = sfModel()->mapFromSource( model()->index( rel->parent() ) ); QModelIndex ch = sfModel()->mapFromSource( model()->index( rel->child() ) ); KGantt::Constraint con( par, ch, KGantt::Constraint::TypeSoft, static_cast( rel->type() )/*NOTE!!*/ ); constraintModel()->removeConstraint( con ); } void MyKGanttView::clearDependencies() { constraintModel()->clear(); // Remove old deps from view // NOTE: This should be handled by KGantt graphicsView()->updateScene(); } void MyKGanttView::createDependencies() { clearDependencies(); if ( project() == 0 || m_manager == 0 ) { return; } foreach ( Node* n, project()->allNodes() ) { foreach ( Relation *r, n->dependChildNodes() ) { addDependency( r ); } } } //------------------------------------------ GanttView::GanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite) : ViewBase(part, doc, parent), m_readWrite( readWrite ), m_project( 0 ) { debugPlan <<" ---------------- KPlato: Creating GanttView ----------------"; setXMLFile("GanttViewUi.rc"); 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 ); m_gantt->graphicsView()->setHeaderContextMenuPolicy(Qt::CustomContextMenu); connect(this, &ViewBase::expandAll, m_gantt->treeView(), &TreeViewBase::slotExpand); connect(this, &ViewBase::collapseAll, m_gantt->treeView(), &TreeViewBase::slotCollapse); setupGui(); updateReadWrite( readWrite ); //connect( m_gantt->constraintModel(), SIGNAL(constraintAdded(Constraint)), this, SLOT(update()) ); debugPlan <constraintModel(); connect( m_gantt->treeView(), &TreeViewBase::contextMenuRequested, this, &GanttView::slotContextMenuRequested ); connect( m_gantt->treeView(), &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); connect(m_gantt->graphicsView(), &KGantt::GraphicsView::headerContextMenuRequested, this, &GanttView::slotGanttHeaderContextMenuRequested); connect(qobject_cast(m_gantt->graphicsView()->grid()), &KGantt::DateTimeGrid::gridChanged, this, &GanttView::slotDateTimeGridChanged); connect(m_gantt->leftView(), &GanttTreeView::doubleClicked, this, &GanttView::itemDoubleClicked); Help::add(this, xi18nc("@info:whatsthis", "Gantt View" "" "Displays scheduled tasks in a Gantt diagram." " The chart area can be zoomed in and out with a slider" " positioned in the upper left corner of the time scale." " You need to hoover over it with the mouse for it to show." "" "This view supports configuration and printing using the context menu of the tree view." "More..." "", Help::page("Manual/Task_Gantt_View"))); } +void GanttView::slotEditCopy() +{ + m_gantt->editCopy(); +} + void GanttView::itemDoubleClicked(const QPersistentModelIndex &idx) { if (idx.column() == NodeModel::NodeDescription) { emit openTaskDescription(isReadWrite() && (idx.flags() & Qt::ItemIsEditable)); } } void GanttView::slotGanttHeaderContextMenuRequested(const QPoint &pt) { QMenu *menu = popupMenu("gantt_datetimegrid_popup"); if (menu) { menu->exec(pt); } } 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 ); actionCollection()->addAction("show_project", actionShowProject); // FIXME: Dependencies depend on these methods being called in the correct order connect(actionShowProject, &QAction::triggered, m_gantt, &MyKGanttView::clearDependencies); connect(actionShowProject, &QAction::triggered, m_gantt->model(), &NodeItemModel::setShowProject); connect(actionShowProject, &QAction::triggered, m_gantt, &MyKGanttView::createDependencies); addContextAction( actionShowProject ); actionShowUnscheduled = new KToggleAction( i18n( "Show Unscheduled Tasks" ), this ); actionCollection()->addAction("show_unscheduled_tasks", actionShowUnscheduled); connect(actionShowUnscheduled, &QAction::triggered, m_gantt, &MyKGanttView::setShowUnscheduledTasks); addContextAction(actionShowUnscheduled); createOptionActions(ViewBase::OptionAll); for (QAction *a : contextActionList()) { actionCollection()->addAction(a->objectName(), a); } m_scalegroup = new QActionGroup(this); QAction *a = new QAction(i18nc("@action:inmenu", "Auto"), this); a->setCheckable(true); a->setChecked(true); actionCollection()->addAction("scale_auto", a); connect(a, &QAction::triggered, this, &GanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Month"), this); actionCollection()->addAction("scale_month", a); a->setCheckable(true); connect(a, &QAction::triggered, this, &GanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Week"), this); actionCollection()->addAction("scale_week", a); a->setCheckable(true); connect(a, &QAction::triggered, this, &GanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Day"), this); a->setCheckable(true); actionCollection()->addAction("scale_day", a); connect(a, &QAction::triggered, this, &GanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Hour"), this); a->setCheckable(true); actionCollection()->addAction("scale_hour", a); connect(a, &QAction::triggered, this, &GanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Zoom In"), this); a->setIcon(koIcon("zoom-in")); actionCollection()->addAction("zoom_in", a); connect(a, &QAction::triggered, this, &GanttView::ganttActions); a = new QAction(i18nc("@action:inmenu", "Zoom Out"), this); a->setIcon(koIcon("zoom-out")); actionCollection()->addAction("zoom_out", a); connect(a, &QAction::triggered, this, &GanttView::ganttActions); } void GanttView::slotDateTimeGridChanged() { DateTimeGrid *grid = qobject_cast(m_gantt->grid()); Q_ASSERT(grid); if (!grid) { return; } QAction *a = m_scalegroup->checkedAction(); switch (grid->scale()) { case KGantt::DateTimeGrid::ScaleAuto: actionCollection()->action("scale_auto")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleHour: actionCollection()->action("scale_hour")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleDay: actionCollection()->action("scale_day")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleWeek: actionCollection()->action("scale_week")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleMonth: actionCollection()->action("scale_month")->setChecked(true); break; default: warnPlan<<"Unused scale:"<scale(); break; } } void GanttView::ganttActions() { QAction *action = qobject_cast(sender()); if (!action) { return; } DateTimeGrid *grid = qobject_cast(m_gantt->grid()); Q_ASSERT(grid); if (!grid) { return; } if (action->objectName() == "scale_auto") { grid->setScale(DateTimeGrid::ScaleAuto); } else if (action->objectName() == "scale_month") { grid->setScale(DateTimeGrid::ScaleMonth); } else if (action->objectName() == "scale_week") { grid->setScale( DateTimeGrid::ScaleWeek); } else if (action->objectName() == "scale_day") { grid->setScale( DateTimeGrid::ScaleDay); } else if (action->objectName() == "scale_hour") { grid->setScale( DateTimeGrid::ScaleHour); } else if (action->objectName() == "zoom_in") { grid->setDayWidth(grid->dayWidth() * 1.25); } else if (action->objectName() == "zoom_out") { // daywidth *MUST NOT* go below 1.0, it is used as an integer later on grid->setDayWidth(qMax(1.0, grid->dayWidth() * 0.8)); } else { warnPlan<<"Unknown gantt action:"<delegate(), this, sender()->objectName() == "print_options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->open(); } void GanttView::slotOptionsFinished( int result ) { GanttViewSettingsDialog *dlg = qobject_cast( sender() ); if ( dlg && result == QDialog::Accepted ) { m_gantt->graphicsView()->updateScene(); } ViewBase::slotOptionsFinished( result ); } void GanttView::clear() { // m_gantt->clear(); } void GanttView::setShowResources( bool on ) { m_gantt->delegate()->showResources = on; } void GanttView::setShowTaskName( bool on ) { m_gantt->delegate()->showTaskName = on; } void GanttView::setShowProgress( bool on ) { m_gantt->delegate()->showProgress = on; } void GanttView::setShowPositiveFloat( bool on ) { m_gantt->delegate()->showPositiveFloat = on; } void GanttView::setShowCriticalTasks( bool on ) { m_gantt->delegate()->showCriticalTasks = on; } void GanttView::setShowCriticalPath( bool on ) { m_gantt->delegate()->showCriticalPath = on; } void GanttView::setShowNoInformation( bool on ) { m_gantt->delegate()->showNoInformation = on; } void GanttView::setShowAppointments( bool on ) { m_gantt->delegate()->showAppointments = on; } void GanttView::setShowTaskLinks( bool on ) { m_gantt->delegate()->showTaskLinks = on; } void GanttView::setProject( Project *project ) { m_gantt->setProject( project ); } void GanttView::setScheduleManager( ScheduleManager *sm ) { if (!sm && scheduleManager()) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); m_gantt->treeView()->saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); bool expand = sm && scheduleManager() && sm != scheduleManager(); QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); m_gantt->treeView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_gantt->setScheduleManager( sm ); if (expand) { m_gantt->treeView()->doExpand(doc); } else if (tryexpand) { m_gantt->treeView()->doExpand(m_domdoc); } } void GanttView::draw( Project &project ) { setProject( &project ); } void GanttView::drawChanges( Project &project ) { if ( m_project != &project ) { setProject( &project ); } } Node *GanttView::currentNode() const { QModelIndex idx = m_gantt->treeView()->selectionModel()->currentIndex(); return m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); } void GanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint &pos ) { debugPlan; QString name; Node *node = m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); if ( node ) { switch ( node->type() ) { case Node::Type_Project: name = "taskview_project_popup"; break; 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? show = (bool)(settings.attribute( "show-unscheduled", "1" ).toInt() ); actionShowUnscheduled->setChecked(show); m_gantt->setShowUnscheduledTasks(show); return m_gantt->loadContext( settings ); } void GanttView::saveContext( QDomElement &settings ) const { debugPlan; ViewBase::saveContext( settings ); settings.setAttribute( "show-project", QString::number(actionShowProject->isChecked()) ); settings.setAttribute( "show-unscheduled", QString::number(actionShowUnscheduled->isChecked()) ); m_gantt->saveContext( settings ); } void GanttView::updateReadWrite( bool on ) { // TODO: KGanttView needs read/write mode m_readWrite = on; if (m_gantt->model()) { m_gantt->model()->setReadWrite(on); } } //---- MilestoneGanttViewSettingsDialog::MilestoneGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint ) : ItemViewSettupDialog( view, gantt->treeView(), true, view ), m_gantt( gantt ) { QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_printingoptions = new GanttPrintingOptionsWidget( this ); m_printingoptions->setOptions( gantt->printingOptions() ); tab->addTab( m_printingoptions, m_printingoptions->windowTitle() ); KPageWidgetItem *page = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); } void MilestoneGanttViewSettingsDialog::slotOk() { debugPlan; m_gantt->setPrintingOptions( m_printingoptions->options()); ItemViewSettupDialog::slotOk(); } //------------------------ MilestoneKGanttView::MilestoneKGanttView( QWidget *parent ) : NodeGanttViewBase( parent ), m_manager( 0 ) { debugPlan<<"------------------- create MilestoneKGanttView -----------------------"; MilestoneItemModel *mm = new MilestoneItemModel( this ); for (int i = 0; i < mm->columnCount(); ++i) { if (i != NodeModel::NodeCompleted) { mm->setReadOnly(i, true); } } setItemModel( mm ); treeView()->createItemDelegates( mm ); sfModel()->setFilterRole ( Qt::EditRole ); sfModel()->setFilterFixedString( QString::number( Node::Type_Milestone ) ); sfModel()->setFilterKeyColumn( NodeModel::NodeType ); QList show; show << NodeModel::NodeWBSCode << NodeModel::NodeName << NodeModel::NodeStartTime; treeView()->setDefaultColumns( show ); for ( int i = 0; i < model()->columnCount(); ++i ) { if ( ! show.contains( i ) ) { treeView()->hideColumn( i ); } } treeView()->header()->moveSection(NodeModel::NodeWBSCode, show.indexOf(NodeModel::NodeWBSCode)); treeView()->setRootIsDecorated ( false ); KGantt::ProxyModel *m = static_cast( ganttProxyModel() ); m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); // To provide correct format m->setRole( KGantt::StartTimeRole, Qt::EditRole ); // To provide correct format m->setRole( KGantt::EndTimeRole, Qt::EditRole ); // To provide correct format m->removeColumn( Qt::DisplayRole ); m->setColumn( KGantt::ItemTypeRole, NodeModel::NodeType ); m->setColumn( KGantt::StartTimeRole, NodeModel::NodeStartTime ); m->setColumn( KGantt::EndTimeRole, NodeModel::NodeEndTime ); m->setColumn( KGantt::TaskCompletionRole, NodeModel::NodeCompleted ); KGantt::DateTimeGrid *g = static_cast( grid() ); g->setDayWidth( 30 ); // TODO: extend QLocale/KGantt to support formats for hourly time display // see bug #349030 // removed custom code here // TODO: add to context treeView()->sortByColumn(NodeModel::NodeWBSCode, Qt::AscendingOrder); treeView()->setSortingEnabled(true); Help::add(this, xi18nc("@info:whatsthis", "Milestone Gantt View" "" "Displays scheduled milestones in a Gantt diagram." " The chart area can be zoomed in and out with a slider" " positioned in the upper left corner of the time scale." " You need to hoover over it with the mouse for it to show." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Milestone_Gantt_View"))); } MilestoneItemModel *MilestoneKGanttView::model() const { return static_cast( NodeGanttViewBase::model() ); } void MilestoneKGanttView::setProject( Project *proj ) { if ( project() ) { disconnect( project(), &Project::projectCalculated, this, &MilestoneKGanttView::slotProjectCalculated ); } NodeGanttViewBase::setProject( proj ); if ( proj ) { connect( proj, &Project::projectCalculated, this, &MilestoneKGanttView::slotProjectCalculated ); } } void MilestoneKGanttView::slotProjectCalculated( ScheduleManager *sm ) { if ( m_manager == sm ) { setScheduleManager( sm ); } } void MilestoneKGanttView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<setScheduleManager( 0 ); m_manager = sm; KGantt::DateTimeGrid *g = static_cast( grid() ); if ( sm && m_project ) { QDateTime start; foreach ( const Node *n, model()->mileStones() ) { QDateTime nt = n->startTime( sm->scheduleId() ); if ( ! nt.isValid() ) { continue; } if ( ! start.isValid() || start > nt ) { start = nt; debugPlan<name()<startTime( sm->scheduleId() ); } if (start.isValid() && 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 ----------------"; setXMLFile("GanttViewUi.rc"); 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_gantt->graphicsView()->setHeaderContextMenuPolicy(Qt::CustomContextMenu); 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(), &TreeViewBase::contextMenuRequested, this, &MilestoneGanttView::slotContextMenuRequested ); connect( m_gantt->treeView(), &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested ); connect(m_gantt->graphicsView(), &KGantt::GraphicsView::headerContextMenuRequested, this, &MilestoneGanttView::slotGanttHeaderContextMenuRequested); connect(qobject_cast(m_gantt->graphicsView()->grid()), &KGantt::DateTimeGrid::gridChanged, this, &MilestoneGanttView::slotDateTimeGridChanged); connect(m_gantt->treeView(), &GanttTreeView::doubleClicked, this, &MilestoneGanttView::itemDoubleClicked); } +void MilestoneGanttView::slotEditCopy() +{ + m_gantt->editCopy(); +} + void MilestoneGanttView::itemDoubleClicked(const QPersistentModelIndex &idx) { if (idx.column() == NodeModel::NodeDescription) { emit openTaskDescription(isReadWrite() && (idx.flags() & Qt::ItemIsEditable)); } } void MilestoneGanttView::slotGanttHeaderContextMenuRequested(const QPoint &pt) { QMenu *menu = popupMenu("gantt_datetimegrid_popup"); if (menu) { menu->exec(pt); } } void MilestoneGanttView::setZoom( double ) { //debugPlan <<"setting gantt zoom:" << zoom; //m_gantt->setZoomFactor(zoom,true); NO!!! setZoomFactor() is something else } void MilestoneGanttView::show() { } void MilestoneGanttView::clear() { } void MilestoneGanttView::setProject( Project *project ) { m_gantt->setProject( project ); } void MilestoneGanttView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<setScheduleManager( sm ); } void MilestoneGanttView::draw( Project &project ) { setProject( &project ); } void MilestoneGanttView::drawChanges( Project &project ) { if ( m_project != &project ) { setProject( &project ); } } Node *MilestoneGanttView::currentNode() const { QModelIndex idx = m_gantt->treeView()->selectionModel()->currentIndex(); return m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) ); } void MilestoneGanttView::setupGui() { createOptionActions(ViewBase::OptionAll & ~(ViewBase::OptionExpand|ViewBase::OptionCollapse)); for (QAction *a : contextActionList()) { actionCollection()->addAction(a->objectName(), a); } m_scalegroup = new QActionGroup(this); QAction *a = new QAction(i18nc("@action:inmenu", "Auto"), this); a->setCheckable(true); a->setChecked(true); actionCollection()->addAction("scale_auto", a); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Month"), this); actionCollection()->addAction("scale_month", a); a->setCheckable(true); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Week"), this); actionCollection()->addAction("scale_week", a); a->setCheckable(true); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Day"), this); a->setCheckable(true); actionCollection()->addAction("scale_day", a); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Hour"), this); a->setCheckable(true); actionCollection()->addAction("scale_hour", a); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Zoom In"), this); a->setIcon(koIcon("zoom-in")); actionCollection()->addAction("zoom_in", a); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); a = new QAction(i18nc("@action:inmenu", "Zoom Out"), this); a->setIcon(koIcon("zoom-out")); actionCollection()->addAction("zoom_out", a); connect(a, &QAction::triggered, this, &MilestoneGanttView::ganttActions); } void MilestoneGanttView::slotDateTimeGridChanged() { DateTimeGrid *grid = qobject_cast(m_gantt->grid()); Q_ASSERT(grid); if (!grid) { return; } QAction *a = m_scalegroup->checkedAction(); switch (grid->scale()) { case KGantt::DateTimeGrid::ScaleAuto: actionCollection()->action("scale_auto")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleHour: actionCollection()->action("scale_hour")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleDay: actionCollection()->action("scale_day")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleWeek: actionCollection()->action("scale_week")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleMonth: actionCollection()->action("scale_month")->setChecked(true); break; default: warnPlan<<"Unused scale:"<scale(); break; } } void MilestoneGanttView::ganttActions() { QAction *action = qobject_cast(sender()); if (!action) { return; } DateTimeGrid *grid = qobject_cast(m_gantt->grid()); Q_ASSERT(grid); if (!grid) { return; } if (action->objectName() == "scale_auto") { grid->setScale(DateTimeGrid::ScaleAuto); } else if (action->objectName() == "scale_month") { grid->setScale(DateTimeGrid::ScaleMonth); } else if (action->objectName() == "scale_week") { grid->setScale( DateTimeGrid::ScaleWeek); } else if (action->objectName() == "scale_day") { grid->setScale( DateTimeGrid::ScaleDay); } else if (action->objectName() == "scale_hour") { grid->setScale( DateTimeGrid::ScaleHour); } else if (action->objectName() == "zoom_in") { grid->setDayWidth(grid->dayWidth() * 1.25); } else if (action->objectName() == "zoom_out") { // daywidth *MUST NOT* go below 1.0, it is used as an integer later on grid->setDayWidth(qMax(1.0, grid->dayWidth() * 0.8)); } else { warnPlan<<"Unknown gantt action:"<model()->node( m_gantt->sfModel()->mapToSource( idx ) ); if ( node ) { switch ( node->type() ) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } } else debugPlan<<"No node"; m_gantt->treeView()->setContextMenuIndex(idx); if ( name.isEmpty() ) { debugPlan<<"No menu"; slotHeaderContextMenuRequested( pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); } void MilestoneGanttView::slotOptions() { debugPlan; MilestoneGanttViewSettingsDialog *dlg = new MilestoneGanttViewSettingsDialog( m_gantt, this, sender()->objectName() == "print_options" ); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->open(); } 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; if (m_gantt->model()) { m_gantt->model()->setReadWrite(on); } } KoPrintJob *MilestoneGanttView::createPrintJob() { return new GanttPrintingDialog( this, m_gantt ); } //-------------------- ResourceAppointmentsGanttViewSettingsDialog::ResourceAppointmentsGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint ) : ItemViewSettupDialog( view, gantt->treeView(), true, view ) , m_gantt(gantt) { QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget( view ); tab->addTab( w, w->windowTitle() ); m_pagelayout = w->findChild(); Q_ASSERT( m_pagelayout ); m_printingoptions = new GanttPrintingOptionsWidget( this ); m_printingoptions->setOptions( gantt->printingOptions() ); tab->addTab( m_printingoptions, m_printingoptions->windowTitle() ); KPageWidgetItem *page = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) ); if (selectPrint) { setCurrentPage(page); } connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) ); } void ResourceAppointmentsGanttViewSettingsDialog::slotOk() { debugPlan; m_gantt->setPrintingOptions( m_printingoptions->options()); ItemViewSettupDialog::slotOk(); } //------------------------------------------ ResourceAppointmentsGanttView::ResourceAppointmentsGanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite) : ViewBase(part, doc, parent), m_project( 0 ), m_model( new ResourceAppointmentsGanttModel( this ) ) { debugPlan <<" ---------------- KPlato: Creating ResourceAppointmentsGanttView ----------------"; setXMLFile("GanttViewUi.rc"); m_gantt = new GanttViewBase( this ); m_gantt->graphicsView()->setHeaderContextMenuPolicy(Qt::CustomContextMenu); 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, &ViewBase::expandAll, tv, &TreeViewBase::slotExpand); connect(this, &ViewBase::collapseAll, tv, &TreeViewBase::slotCollapse); m_rowController = new KGantt::TreeViewRowController( tv, m_gantt->ganttProxyModel() ); m_gantt->setRowController( m_rowController ); tv->header()->setStretchLastSection( true ); tv->setTreePosition(-1); KGantt::ProxyModel *m = static_cast( m_gantt->ganttProxyModel() ); m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); m->setRole( KGantt::StartTimeRole, KGantt::StartTimeRole ); m->setRole( KGantt::EndTimeRole, KGantt::EndTimeRole ); m->setRole( KGantt::TaskCompletionRole, KGantt::TaskCompletionRole ); m_gantt->setModel( m_model ); QVBoxLayout *l = new QVBoxLayout( this ); l->setMargin( 0 ); l->addWidget( m_gantt ); setupGui(); updateReadWrite( readWrite ); connect( m_gantt->leftView(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint)) ); connect( m_gantt->leftView(), SIGNAL(headerContextMenuRequested(QPoint)), SLOT(slotHeaderContextMenuRequested(QPoint)) ); connect(m_gantt->graphicsView(), &KGantt::GraphicsView::headerContextMenuRequested, this, &ResourceAppointmentsGanttView::slotGanttHeaderContextMenuRequested); connect(qobject_cast(m_gantt->graphicsView()->grid()), &KGantt::DateTimeGrid::gridChanged, this, &ResourceAppointmentsGanttView::slotDateTimeGridChanged); Help::add(this, xi18nc("@info:whatsthis", "Resource Assignments (Gantt)" "" "Displays the scheduled resource - task assignments in a Gantt diagram." " The chart area can be zoomed in and out with a slider" " positioned in the upper left corner of the time scale." " You need to hoover over it with the mouse for it to show." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Resource_Assignment_Gantt_View"))); } ResourceAppointmentsGanttView::~ResourceAppointmentsGanttView() { delete m_rowController; } +void ResourceAppointmentsGanttView::slotEditCopy() +{ + m_gantt->editCopy(); +} + void ResourceAppointmentsGanttView::slotGanttHeaderContextMenuRequested(const QPoint &pt) { QMenu *menu = popupMenu("gantt_datetimegrid_popup"); if (menu) { menu->exec(pt); } } void ResourceAppointmentsGanttView::setZoom( double ) { //debugPlan <<"setting gantt zoom:" << zoom; //m_gantt->setZoomFactor(zoom,true); NO!!! setZoomFactor() is something else } Project *ResourceAppointmentsGanttView::project() const { return m_model->project(); } void ResourceAppointmentsGanttView::setProject( Project *project ) { m_model->setProject( project ); } void ResourceAppointmentsGanttView::setScheduleManager( ScheduleManager *sm ) { //debugPlan<saveExpanded(element); } bool tryexpand = sm && !scheduleManager(); bool expand = sm && scheduleManager() && sm != scheduleManager(); QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); treeView()->saveExpanded(element); } ViewBase::setScheduleManager(sm); m_model->setScheduleManager( sm ); if (expand) { treeView()->doExpand(doc); } else if (tryexpand) { treeView()->doExpand(m_domdoc); } } void ResourceAppointmentsGanttView::setupGui() { createOptionActions(ViewBase::OptionAll); for (QAction *a : contextActionList()) { actionCollection()->addAction(a->objectName(), a); } m_scalegroup = new QActionGroup(this); QAction *a = new QAction(i18nc("@action:inmenu", "Auto"), this); a->setCheckable(true); a->setChecked(true); actionCollection()->addAction("scale_auto", a); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Month"), this); actionCollection()->addAction("scale_month", a); a->setCheckable(true); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Week"), this); actionCollection()->addAction("scale_week", a); a->setCheckable(true); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Day"), this); a->setCheckable(true); actionCollection()->addAction("scale_day", a); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Hour"), this); a->setCheckable(true); actionCollection()->addAction("scale_hour", a); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); m_scalegroup->addAction(a); a = new QAction(i18nc("@action:inmenu", "Zoom In"), this); a->setIcon(koIcon("zoom-in")); actionCollection()->addAction("zoom_in", a); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); a = new QAction(i18nc("@action:inmenu", "Zoom Out"), this); a->setIcon(koIcon("zoom-out")); actionCollection()->addAction("zoom_out", a); connect(a, &QAction::triggered, this, &ResourceAppointmentsGanttView::ganttActions); } void ResourceAppointmentsGanttView::slotDateTimeGridChanged() { DateTimeGrid *grid = qobject_cast(m_gantt->grid()); Q_ASSERT(grid); if (!grid) { return; } QAction *a = m_scalegroup->checkedAction(); switch (grid->scale()) { case KGantt::DateTimeGrid::ScaleAuto: actionCollection()->action("scale_auto")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleHour: actionCollection()->action("scale_hour")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleDay: actionCollection()->action("scale_day")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleWeek: actionCollection()->action("scale_week")->setChecked(true); break; case KGantt::DateTimeGrid::ScaleMonth: actionCollection()->action("scale_month")->setChecked(true); break; default: warnPlan<<"Unused scale:"<scale(); break; } } void ResourceAppointmentsGanttView::ganttActions() { QAction *action = qobject_cast(sender()); if (!action) { return; } DateTimeGrid *grid = qobject_cast(m_gantt->grid()); Q_ASSERT(grid); if (!grid) { return; } if (action->objectName() == "scale_auto") { grid->setScale(DateTimeGrid::ScaleAuto); } else if (action->objectName() == "scale_month") { grid->setScale(DateTimeGrid::ScaleMonth); } else if (action->objectName() == "scale_week") { grid->setScale( DateTimeGrid::ScaleWeek); } else if (action->objectName() == "scale_day") { grid->setScale( DateTimeGrid::ScaleDay); } else if (action->objectName() == "scale_hour") { grid->setScale( DateTimeGrid::ScaleHour); } else if (action->objectName() == "zoom_in") { grid->setDayWidth(grid->dayWidth() * 1.25); } else if (action->objectName() == "zoom_out") { // daywidth *MUST NOT* go below 1.0, it is used as an integer later on grid->setDayWidth(qMax(1.0, grid->dayWidth() * 0.8)); } else { warnPlan<<"Unknown gantt action:"<selectionModel()->currentIndex(); return m_model->node( idx ); } void ResourceAppointmentsGanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint &pos ) { debugPlan<node( idx ); if ( n ) { name = "taskview_popup"; } } m_gantt->treeView()->setContextMenuIndex(idx); if ( name.isEmpty() ) { slotHeaderContextMenuRequested( pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); return; } emit requestPopupMenu( name, pos ); m_gantt->treeView()->setContextMenuIndex(QModelIndex()); } void ResourceAppointmentsGanttView::slotOptions() { debugPlan; ItemViewSettupDialog *dlg = new ResourceAppointmentsGanttViewSettingsDialog(m_gantt, this, sender()->objectName() == "print_options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->open(); } bool ResourceAppointmentsGanttView::loadContext( const KoXmlElement &settings ) { debugPlan; ViewBase::loadContext( settings ); m_gantt->loadContext( settings ); return treeView()->loadContext( m_model->columnMap(), settings ); } void ResourceAppointmentsGanttView::saveContext( QDomElement &settings ) const { debugPlan; ViewBase::saveContext( settings ); m_gantt->saveContext( settings ); treeView()->saveContext( m_model->columnMap(), settings ); } void ResourceAppointmentsGanttView::updateReadWrite( bool on ) { m_readWrite = on; } KoPrintJob *ResourceAppointmentsGanttView::createPrintJob() { return new GanttPrintingDialog( this, m_gantt ); } } //KPlato namespace #include "moc_kptganttview.cpp" diff --git a/src/libs/ui/kptganttview.h b/src/libs/ui/kptganttview.h index 36073934..f706999e 100644 --- a/src/libs/ui/kptganttview.h +++ b/src/libs/ui/kptganttview.h @@ -1,498 +1,505 @@ /* 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 "planui_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 QActionGroup; 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 DateTimeTimeLine; //--------------------------------------- class GanttChartDisplayOptionsPanel : public QWidget, public Ui::GanttChartDisplayOptions { Q_OBJECT public: explicit GanttChartDisplayOptionsPanel( GanttViewBase *gantt, 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; GanttViewBase *m_gantt; }; class GanttViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: explicit GanttViewSettingsDialog( GanttViewBase *gantt, GanttItemDelegate *delegate, ViewBase *view, bool selectPrint = false ); 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 PLANUI_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 KPlato::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 PLANUI_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 PLANUI_EXPORT GanttViewBase : public KGantt::View { Q_OBJECT public: explicit GanttViewBase(QWidget *parent); ~GanttViewBase(); GanttTreeView *treeView() const; GanttPrintingOptions printingOptions() const { return m_printOptions; } virtual bool loadContext( const KoXmlElement &settings ); virtual void saveContext( QDomElement &settings ) const; DateTimeTimeLine *timeLine() const; + void editCopy(); + public Q_SLOTS: void setPrintingOptions(const KPlato::GanttPrintingOptions &opt) { m_printOptions = opt; } protected: bool eventFilter(QObject *obj, QEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); friend class GanttPrintingDialog; GanttPrintingOptions m_printOptions; private: GanttZoomWidget *m_zoomwidget; QPoint m_dragStartPosition; }; -class NodeGanttViewBase : public GanttViewBase +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; public Q_SLOTS: void setShowUnscheduledTasks(bool show); protected: Project *m_project; GanttItemDelegate *m_ganttdelegate; NodeItemModel m_defaultModel; KGantt::TreeViewRowController *m_rowController; }; class PLANUI_EXPORT MyKGanttView : public NodeGanttViewBase { Q_OBJECT public: explicit MyKGanttView(QWidget *parent); GanttItemModel *model() const; void setProject( Project *project ); void setScheduleManager( ScheduleManager *sm ); public Q_SLOTS: void clearDependencies(); void createDependencies(); void addDependency(KPlato::Relation *rel); void removeDependency(KPlato::Relation *rel); void slotProjectCalculated(KPlato::ScheduleManager *sm); void slotNodeInserted(KPlato::Node *node); protected: ScheduleManager *m_manager; }; class PLANUI_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(KPlato::Relation *rel) ; void addRelation(KPlato::Node *par, KPlato::Node *child); void modifyRelation(KPlato::Relation *rel, int linkType) ; void addRelation(KPlato::Node *par, KPlato::Node *child, int linkType); public Q_SLOTS: void setScheduleManager(KPlato::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 ); + void slotEditCopy(); + protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); void slotGanttHeaderContextMenuRequested(const QPoint &pt); void slotDateTimeGridChanged(); virtual void slotOptions(); virtual void slotOptionsFinished( int result ); void ganttActions(); void itemDoubleClicked(const QPersistentModelIndex &idx); private: bool m_readWrite; int m_defaultFontSize; QSplitter *m_splitter; MyKGanttView *m_gantt; Project *m_project; QAction *actionShowProject; QAction *actionShowUnscheduled; QDomDocument m_domdoc; QActionGroup *m_scalegroup; }; class MilestoneGanttViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: MilestoneGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint = false ); protected Q_SLOTS: virtual void slotOk(); private: GanttViewBase *m_gantt; GanttPrintingOptionsWidget *m_printingoptions; }; class PLANUI_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(KPlato::ScheduleManager *sm); protected: ScheduleManager *m_manager; }; class PLANUI_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(); public Q_SLOTS: void setScheduleManager(KPlato::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; } + void slotEditCopy(); + protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); void slotGanttHeaderContextMenuRequested(const QPoint &pt); void slotDateTimeGridChanged(); virtual void slotOptions(); void ganttActions(); void itemDoubleClicked(const QPersistentModelIndex &idx); 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; QActionGroup *m_scalegroup; }; class ResourceAppointmentsGanttViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: ResourceAppointmentsGanttViewSettingsDialog(GanttViewBase *gantt, ViewBase *view, bool selectPrint = false); public Q_SLOTS: void slotOk(); private: GanttViewBase *m_gantt; GanttPrintingOptionsWidget *m_printingoptions; }; class PLANUI_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(KPlato::ScheduleManager *sm); + void slotEditCopy(); protected Q_SLOTS: void slotContextMenuRequested( const QModelIndex&, const QPoint &pos ); void slotGanttHeaderContextMenuRequested(const QPoint &pt); void slotDateTimeGridChanged(); virtual void slotOptions(); void ganttActions(); private: GanttViewBase *m_gantt; Project *m_project; ResourceAppointmentsGanttModel *m_model; KGantt::TreeViewRowController *m_rowController; QDomDocument m_domdoc; QActionGroup *m_scalegroup; }; } //KPlato namespace #endif diff --git a/src/libs/ui/performance/PerformanceStatusBase.cpp b/src/libs/ui/performance/PerformanceStatusBase.cpp index 6ac927a6..6e99fbe6 100644 --- a/src/libs/ui/performance/PerformanceStatusBase.cpp +++ b/src/libs/ui/performance/PerformanceStatusBase.cpp @@ -1,692 +1,702 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * 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. */ // clazy:excludeall=qstring-arg #include "PerformanceStatusBase.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptproject.h" #include "kptschedule.h" #include "kpteffortcostmap.h" #include "Help.h" #include "kptdebug.h" #include #include "KoDocument.h" #include "KoPageLayoutWidget.h" #include #include #include #include #include #include #include #include #include +#include using namespace KChart; using namespace KPlato; 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, &QAbstractItemModel::modelReset, this, &PerformanceStatusBase::slotUpdate); setContextMenuPolicy (Qt::DefaultContextMenu); } +void PerformanceStatusBase::editCopy() +{ + QMimeData *mimeData = new QMimeData; + QPixmap pixmap(size()); + render(&pixmap); + mimeData->setImageData(pixmap); + QGuiApplication::clipboard()->setMimeData(mimeData); +} + void PerformanceStatusBase::setChartInfo(const PerformanceChartInfo &info) { if (info != m_chartinfo) { m_chartinfo = info; setupChart(); } } void PerformanceStatusBase::refreshChart() { ui_performancetable->resize(QSize()); // NOTE: Force grid/axis recalculation, couldn't find a better way :( QResizeEvent event(ui_chart->size(), QSize()); QApplication::sendEvent(ui_chart, &event); m_legend->forceRebuild(); } void PerformanceStatusBase::createBarChart() { m_barchart.effortplane = new CartesianCoordinatePlane(ui_chart); m_barchart.effortplane->setObjectName("Bar chart, Effort"); m_barchart.costplane = new CartesianCoordinatePlane(ui_chart); m_barchart.costplane->setObjectName("Bar chart, Cost"); BarDiagram *effortdiagram = new BarDiagram(ui_chart, m_barchart.effortplane); effortdiagram->setObjectName("Effort diagram"); m_barchart.dateaxis = new CartesianAxis(); m_barchart.dateaxis->setPosition(CartesianAxis::Bottom); m_barchart.effortaxis = new CartesianAxis(effortdiagram); m_barchart.effortaxis->setPosition(CartesianAxis::Right); effortdiagram->addAxis(m_barchart.effortaxis); m_barchart.effortplane->addDiagram(effortdiagram); // Hide cost in effort diagram effortdiagram->setHidden(0, true); effortdiagram->setHidden(1, true); effortdiagram->setHidden(2, true); m_barchart.effortproxy.setZeroColumns(QList() << 0 << 1 << 2); m_barchart.effortproxy.setSourceModel(&m_chartmodel); effortdiagram->setModel(&(m_barchart.effortproxy)); BarDiagram *costdiagram = new BarDiagram(ui_chart, m_barchart.costplane); costdiagram->setObjectName("Cost diagram"); m_barchart.costaxis = new CartesianAxis(costdiagram); m_barchart.costaxis->setPosition(CartesianAxis::Left); costdiagram->addAxis(m_barchart.costaxis); m_barchart.costplane->addDiagram(costdiagram); // Hide effort in cost diagram costdiagram->setHidden(3, true); costdiagram->setHidden(4, true); costdiagram->setHidden(5, true); m_barchart.costproxy.setZeroColumns(QList() << 3 << 4 << 5); m_barchart.costproxy.setObjectName("Bar: Cost"); m_barchart.costproxy.setSourceModel(&m_chartmodel); costdiagram->setModel(&(m_barchart.costproxy)); m_barchart.effortdiagram = effortdiagram; m_barchart.costdiagram = costdiagram; m_barchart.piplane = new CartesianCoordinatePlane(ui_chart); m_barchart.piplane->setObjectName("Performance Indices"); BarDiagram *pidiagram = new BarDiagram(ui_chart, m_barchart.piplane); pidiagram->setObjectName("PI diagram"); m_barchart.piaxis = new CartesianAxis(pidiagram); pidiagram->addAxis(m_barchart.piaxis); m_barchart.piplane->addDiagram(pidiagram); m_barchart.piproxy.setSourceModel(&m_chartmodel); pidiagram->setModel(&(m_barchart.piproxy)); } void PerformanceStatusBase::createLineChart() { m_linechart.effortplane = new CartesianCoordinatePlane(ui_chart); m_linechart.effortplane->setObjectName("Line chart, Effort"); m_linechart.effortplane->setRubberBandZoomingEnabled(true); m_linechart.costplane = new CartesianCoordinatePlane(ui_chart); m_linechart.costplane->setObjectName("Line chart, Cost"); m_linechart.costplane->setRubberBandZoomingEnabled(true); LineDiagram *effortdiagram = new LineDiagram(ui_chart, m_linechart.effortplane); effortdiagram->setObjectName("Effort diagram"); m_linechart.dateaxis = new CartesianAxis(); m_linechart.dateaxis->setPosition(CartesianAxis::Bottom); m_linechart.effortaxis = new CartesianAxis(effortdiagram); m_linechart.effortaxis->setPosition(CartesianAxis::Right); effortdiagram->addAxis(m_linechart.effortaxis); m_linechart.effortplane->addDiagram(effortdiagram); // Hide cost in effort diagram effortdiagram->setHidden(0, true); effortdiagram->setHidden(1, true); effortdiagram->setHidden(2, true); m_linechart.effortproxy.setZeroColumns(QList() << 0 << 1 << 2); m_linechart.effortproxy.setObjectName("Line: Effort"); m_linechart.effortproxy.setSourceModel(&m_chartmodel); effortdiagram->setModel(&(m_linechart.effortproxy)); LineDiagram *costdiagram = new LineDiagram(ui_chart, m_linechart.costplane); costdiagram->setObjectName("Cost diagram"); m_linechart.costaxis = new CartesianAxis(costdiagram); m_linechart.costaxis->setPosition(CartesianAxis::Left); costdiagram->addAxis(m_linechart.costaxis); m_linechart.costplane->addDiagram(costdiagram); // Hide effort in cost diagram costdiagram->setHidden(3, true); costdiagram->setHidden(4, true); costdiagram->setHidden(5, true); m_linechart.costproxy.setObjectName("Line: Cost"); m_linechart.costproxy.setZeroColumns(QList() << 3 << 4 << 5); m_linechart.costproxy.setSourceModel(&m_chartmodel); costdiagram->setModel(&(m_linechart.costproxy)); m_linechart.effortdiagram = effortdiagram; m_linechart.costdiagram = costdiagram; m_linechart.piplane = new CartesianCoordinatePlane(ui_chart); m_linechart.piplane->setObjectName("Performance Indices"); m_linechart.piplane->setRubberBandZoomingEnabled(true); LineDiagram *pidiagram = new LineDiagram(ui_chart, m_linechart.piplane); pidiagram->setObjectName("PI diagram"); m_linechart.piaxis = new CartesianAxis(pidiagram); pidiagram->addAxis(m_linechart.piaxis); m_linechart.piplane->addDiagram(pidiagram); m_linechart.piproxy.setSourceModel(&m_chartmodel); pidiagram->setModel(&(m_linechart.piproxy)); } void PerformanceStatusBase::setupChart() { while (! ui_chart->coordinatePlanes().isEmpty()) { const CoordinatePlaneList &planes = ui_chart->coordinatePlanes(); ui_chart->takeCoordinatePlane(planes.last()); } if (m_chartinfo.showBarChart) { setupChart(m_barchart); } else if (m_chartinfo.showLineChart) { setupChart(m_linechart); } else { #ifdef PLAN_CHART_DEBUG ui_stack->setCurrentIndex(1); refreshChart(); return; #else setupChart(m_linechart); #endif } ui_stack->setCurrentIndex(0); debugPlan<<"Planes:"<coordinatePlanes(); foreach (AbstractCoordinatePlane *pl, ui_chart->coordinatePlanes()) { CartesianCoordinatePlane *p = dynamic_cast(pl); if (p == 0) continue; GridAttributes ga = p->globalGridAttributes(); ga.setGridVisible(p->referenceCoordinatePlane() == 0); p->setGlobalGridAttributes(ga); } m_legend->setDatasetHidden(0, ! (m_chartinfo.showBaseValues && m_chartinfo.showCost && m_chartinfo.showBCWSCost)); m_legend->setDatasetHidden(1, ! (m_chartinfo.showBaseValues && m_chartinfo.showCost && m_chartinfo.showBCWPCost)); m_legend->setDatasetHidden(2, ! (m_chartinfo.showBaseValues && m_chartinfo.showCost && m_chartinfo.showACWPCost)); m_legend->setDatasetHidden(3, ! (m_chartinfo.showBaseValues && m_chartinfo.showEffort && m_chartinfo.showBCWSEffort)); m_legend->setDatasetHidden(4, ! (m_chartinfo.showBaseValues && m_chartinfo.showEffort && m_chartinfo.showBCWPEffort)); m_legend->setDatasetHidden(5, ! (m_chartinfo.showBaseValues && m_chartinfo.showEffort && m_chartinfo.showACWPEffort)); // spi/cpi m_legend->setDatasetHidden(6, ! (m_chartinfo.showIndices && m_chartinfo.showSpiCost)); m_legend->setDatasetHidden(7, ! (m_chartinfo.showIndices && m_chartinfo.showCpiCost)); m_legend->setDatasetHidden(8, ! (m_chartinfo.showIndices && m_chartinfo.showSpiEffort)); m_legend->setDatasetHidden(9, ! (m_chartinfo.showIndices && m_chartinfo.showCpiEffort)); setEffortValuesVisible(m_chartinfo.effortShown()); setCostValuesVisible(m_chartinfo.costShown()); refreshChart(); } void PerformanceStatusBase::setEffortValuesVisible(bool visible) { ui_performancetable->verticalHeader()->setSectionHidden(1, ! visible); ui_performancetable->setMaximumHeight(ui_performancetable->sizeHint().height()); } void PerformanceStatusBase::setCostValuesVisible(bool visible) { ui_performancetable->verticalHeader()->setSectionHidden(0, ! visible); ui_performancetable->setMaximumHeight(ui_performancetable->sizeHint().height()); } void PerformanceStatusBase::setupChart(ChartContents &cc) { QList erc, ezc, crc, czc; // sourcemodel column numbers int effort_start_column = 3; // proxy column number const PerformanceChartInfo &info = m_chartinfo; debugPlan<<"cost="<(cc.effortplane->diagram())->takeAxis(cc.dateaxis); static_cast(cc.costplane->diagram())->takeAxis(cc.dateaxis); static_cast(cc.piplane->diagram())->takeAxis(cc.dateaxis); cc.costplane->setReferenceCoordinatePlane(0); if (info.showBaseValues) { if (info.showEffort) { // filter cost columns if cost is *not* shown, else hide them and zero out if (! info.showCost) { erc << 0 << 1 << 2; effort_start_column = 0; // no cost, so effort start at 0 } else { ezc << 0 << 1 << 2; cc.effortplane->diagram()->setHidden(0, true); cc.effortplane->diagram()->setHidden(1, true); cc.effortplane->diagram()->setHidden(2, true); } // always disable spi/cpi erc << 6 << 7 << 8 << 9; ezc << 6 << 7 << 8 << 9; // if cost is shown don't return a cost value or else it goes into the effort axis scale calculation //cc.effortproxy.setZeroColumns(info.showCost ? QList() << 0 << 1 << 2 : QList() << 3 << 4 << 5 ); cc.effortaxis->setPosition(info.showCost ? CartesianAxis::Right : CartesianAxis::Left); ui_chart->addCoordinatePlane(cc.effortplane); static_cast(cc.effortplane->diagram())->addAxis(cc.dateaxis); cc.effortplane->setGridNeedsRecalculate(); } if (info.showCost) { // Should never get any effort values in cost diagram czc << 3 << 4 << 5; // remove effort columns from cost if no effort is shown, else hide them if (! info.showEffort) { crc << 3 << 4 << 5; } else { cc.costplane->diagram()->setHidden(3, true); cc.costplane->diagram()->setHidden(4, true); cc.costplane->diagram()->setHidden(5, true); } // always disable spi/cpi erc << 6 << 7 << 8 << 9; ezc << 6 << 7 << 8 << 9; cc.costplane->setReferenceCoordinatePlane(info.showEffort ? cc.effortplane : 0); ui_chart->addCoordinatePlane(cc.costplane); static_cast(cc.costplane->diagram())->addAxis(cc.dateaxis); cc.costplane->setGridNeedsRecalculate(); cc.costplane->diagram()->setHidden(0, ! info.showBCWSCost); cc.costplane->diagram()->setHidden(1, ! info.showBCWPCost); cc.costplane->diagram()->setHidden(2, ! info.showACWPCost); } if (info.showEffort) { cc.effortplane->diagram()->setHidden(effort_start_column, ! info.showBCWSEffort); cc.effortplane->diagram()->setHidden(effort_start_column+1, ! info.showBCWPEffort); cc.effortplane->diagram()->setHidden(effort_start_column+2, ! info.showACWPEffort); cc.effortaxis->setCachedSizeDirty(); cc.effortproxy.reset(); cc.effortproxy.setZeroColumns(ezc); cc.effortproxy.setRejectColumns(erc); } if (info.showCost) { cc.costaxis->setCachedSizeDirty(); cc.costproxy.reset(); cc.costproxy.setZeroColumns(czc); cc.costproxy.setRejectColumns(crc); } } else if (info.showIndices) { cc.piaxis->setPosition(CartesianAxis::Left); ui_chart->addCoordinatePlane(cc.piplane); static_cast(cc.piplane->diagram())->addAxis(cc.dateaxis); cc.piplane->setGridNeedsRecalculate(); cc.piaxis->setCachedSizeDirty(); cc.piproxy.reset(); QList reject; reject << 0 << 1 << 2 << 3 << 4 << 5; if (! info.showSpiCost) { reject << ChartItemModel::SPICost; } if (! info.showCpiCost) { reject << ChartItemModel::CPICost; } if (! info.showSpiEffort) { reject << ChartItemModel::SPIEffort; } if (! info.showCpiEffort) { reject << ChartItemModel::CPIEffort; } cc.piproxy.setRejectColumns(reject); } #if 0 debugPlan<<"Effort:"< 0) { debugPlan<<"Effort:"<diagram()->isHidden(i)?"hide":"show"); } } debugPlan<<"Cost:"< 0) { debugPlan<<"Cost:"<diagram()->isHidden(i)?"hide":"show"); } } foreach(AbstractCoordinatePlane *p, ui_chart->coordinatePlanes()) { debugPlan<referenceCoordinatePlane(); foreach (AbstractDiagram *d, p->diagrams()) { debugPlan<globalPos(); if (event->modifiers() == Qt::NoModifier) { 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, &Project::localeChanged, this, &PerformanceStatusBase::slotLocaleChanged); } m_project = project; if (m_project) { connect(m_project, &Project::localeChanged, this, &PerformanceStatusBase::slotLocaleChanged); } m_chartmodel.setProject(project); static_cast(ui_performancetable->model())->setProject(project); slotLocaleChanged(); } void PerformanceStatusBase::slotLocaleChanged() { debugPlan; const QString currencySymbol = m_project->locale()->currencySymbol(); m_linechart.costaxis->setTitleText(i18nc("Chart axis title 1=currency symbol", "Cost (%1)", currencySymbol)); m_linechart.effortaxis->setTitleText(i18nc("Chart axis title", "Effort (hours)")); m_barchart.costaxis->setTitleText(i18nc("Chart axis title 1=currency symbol", "Cost (%1)", currencySymbol)); m_barchart.effortaxis->setTitleText(i18nc("Chart axis title", "Effort (hours)")); } bool PerformanceStatusBase::loadContext(const KoXmlElement &context) { debugPlan; m_chartinfo.showBarChart = context.attribute("show-bar-chart", "0").toInt(); m_chartinfo.showLineChart = context.attribute("show-line-chart", "1").toInt(); m_chartinfo.showTableView = context.attribute("show-table-view", "0").toInt(); m_chartinfo.showBaseValues = context.attribute("show-base-values", "1").toInt(); m_chartinfo.showIndices = context.attribute("show-indeces", "0").toInt(); m_chartinfo.showCost = context.attribute("show-cost", "1").toInt(); m_chartinfo.showBCWSCost = context.attribute("show-bcws-cost", "1").toInt(); m_chartinfo.showBCWPCost = context.attribute("show-bcwp-cost", "1").toInt(); m_chartinfo.showACWPCost = context.attribute("show-acwp-cost", "1").toInt(); m_chartinfo.showEffort = context.attribute("show-effort", "1").toInt(); m_chartinfo.showBCWSEffort = context.attribute("show-bcws-effort", "1").toInt(); m_chartinfo.showBCWPEffort = context.attribute("show-bcwp-effort", "1").toInt(); m_chartinfo.showACWPEffort = context.attribute("show-acwp-effort", "1").toInt(); m_chartinfo.showSpiCost = context.attribute("show-spi-cost", "1").toInt(); m_chartinfo.showCpiCost = context.attribute("show-cpi-cost", "1").toInt(); m_chartinfo.showSpiEffort = context.attribute("show-spi-effort", "1").toInt(); m_chartinfo.showCpiEffort = context.attribute("show-cpi-effort", "1").toInt(); debugPlan<<"Cost:"<project()); dia->printer().setCreator("Plan"); return dia; } void PerformanceStatusBase::setNodes(const QList &nodes) { m_chartmodel.setNodes(nodes); static_cast(ui_performancetable->model())->setNodes(nodes); } //------------------------------------------------ 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, &QAbstractButton::toggled, this, &PerformanceStatusViewSettingsPanel::switchStackWidget); connect(ui_showindices, &QAbstractButton::toggled, this, &PerformanceStatusViewSettingsPanel::switchStackWidget); switchStackWidget(); } void PerformanceStatusViewSettingsPanel::slotOk() { PerformanceChartInfo info; info.showLineChart = ui_linechart->isChecked(); info.showBarChart = ui_barchart->isChecked(); info.showTableView = ui_table->isChecked(); info.showBaseValues = ui_showbasevalues->isChecked(); info.showIndices = ui_showindices->isChecked(); info.showBCWSCost = ui_bcwsCost->checkState() == Qt::Unchecked ? false : true; info.showBCWPCost = ui_bcwpCost->checkState() == Qt::Unchecked ? false : true; info.showACWPCost = ui_acwpCost->checkState() == Qt::Unchecked ? false : true; info.showCost = ui_cost->isChecked(); info.showBCWSEffort = ui_bcwsEffort->checkState() == Qt::Unchecked ? false : true; info.showBCWPEffort = ui_bcwpEffort->checkState() == Qt::Unchecked ? false : true; info.showACWPEffort = ui_acwpEffort->checkState() == Qt::Unchecked ? false : true; info.showEffort = ui_effort->isChecked(); info.showSpiCost = ui_spicost->isChecked(); info.showCpiCost = ui_cpicost->isChecked(); info.showSpiEffort = ui_spieffort->isChecked(); info.showCpiEffort = ui_cpieffort->isChecked(); m_view->setChartInfo(info); } void PerformanceStatusViewSettingsPanel::setDefault() { ui_linechart->setChecked(true); ui_bcwsCost->setCheckState(Qt::Checked); ui_bcwpCost->setCheckState(Qt::Checked); ui_acwpCost->setCheckState(Qt::Checked); ui_cost->setChecked(true); ui_bcwsEffort->setCheckState(Qt::Checked); ui_bcwpEffort->setCheckState(Qt::Checked); ui_acwpEffort->setCheckState(Qt::Checked); ui_effort->setChecked(Qt::Unchecked); ui_showbasevalues->setChecked(true); ui_showindices->setChecked(false); ui_spicost->setCheckState(Qt::Checked); ui_cpicost->setCheckState(Qt::Checked); ui_spieffort->setCheckState(Qt::Checked); ui_cpieffort->setCheckState(Qt::Checked); } void PerformanceStatusViewSettingsPanel::switchStackWidget() { if (ui_showbasevalues->isChecked()) { ui_stackWidget->setCurrentIndex(0); } else if (ui_showindices->isChecked()) { ui_stackWidget->setCurrentIndex(1); } //debugPlan<currentIndex(); } diff --git a/src/libs/ui/performance/PerformanceStatusBase.h b/src/libs/ui/performance/PerformanceStatusBase.h index 9d27682c..5739c0ba 100644 --- a/src/libs/ui/performance/PerformanceStatusBase.h +++ b/src/libs/ui/performance/PerformanceStatusBase.h @@ -1,257 +1,259 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * 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 PERFORMANCESTATUSBASE_H #define PERFORMANCESTATUSBASE_H #include "planui_export.h" #include "kptitemmodelbase.h" #include "kptviewbase.h" #include "kptitemviewsettup.h" #include "ui_PerformanceStatus.h" #include "ui_PerformanceStatusViewSettingsPanel.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; 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 PLANUI_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); + void editCopy(); + 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 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; }; } //namespace KPlato #endif diff --git a/src/libs/ui/performance/PerformanceStatusView.cpp b/src/libs/ui/performance/PerformanceStatusView.cpp index 821d4e84..07f1637e 100644 --- a/src/libs/ui/performance/PerformanceStatusView.cpp +++ b/src/libs/ui/performance/PerformanceStatusView.cpp @@ -1,357 +1,372 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * 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. */ // clazy:excludeall=qstring-arg #include "PerformanceStatusView.h" #include "PerformanceStatusBase.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptproject.h" #include "kptschedule.h" #include "kpteffortcostmap.h" #include "Help.h" #include "kptnodeitemmodel.h" #include "kptdebug.h" #include #include "KoDocument.h" #include "KoPageLayoutWidget.h" #include #include #include #include #include #include #include #include #include #include #include +#include using namespace KChart; using namespace KPlato; //----------------------------------- 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(), &QItemSelectionModel::selectionChanged, this, &PerformanceStatusTreeView::slotSelectionChanged); QTimer::singleShot(0, this, &PerformanceStatusTreeView::resizeSplitters); } void PerformanceStatusTreeView::slotSelectionChanged(const QItemSelection&, const QItemSelection&) { //debugPlan; QList nodes; foreach (const QModelIndex &i, m_tree->selectionModel()->selectedIndexes()) { Node *n = nodeModel()->node(i); if (! nodes.contains(n)) { nodes.append(n); } } m_chart->setNodes(nodes); } NodeItemModel *PerformanceStatusTreeView::nodeModel() const { return static_cast(m_tree->model()); } void PerformanceStatusTreeView::setScheduleManager(ScheduleManager *sm) { if (!sm && m_manager) { // we should only get here if the only schedule manager is scheduled, // or when last schedule manager is deleted m_domdoc.clear(); QDomElement element = m_domdoc.createElement("expanded"); m_domdoc.appendChild(element); treeView()->saveExpanded(element); } bool tryexpand = sm && !m_manager; bool expand = sm && m_manager && sm != m_manager; QDomDocument doc; if (expand) { QDomElement element = doc.createElement("expanded"); doc.appendChild(element); treeView()->saveExpanded(element); } m_manager = sm; nodeModel()->setScheduleManager(sm); m_chart->setScheduleManager(sm); if (expand) { treeView()->doExpand(doc); } else if (tryexpand) { treeView()->doExpand(m_domdoc); } } Project *PerformanceStatusTreeView::project() const { return nodeModel()->project(); } void PerformanceStatusTreeView::setProject(Project *project) { nodeModel()->setProject(project); m_chart->setProject(project); } bool PerformanceStatusTreeView::loadContext(const KoXmlElement &context) { debugPlan; bool res = false; res = m_chart->loadContext(context.namedItem("chart").toElement()); res &= m_tree->loadContext(nodeModel()->columnMap(), context.namedItem("tree").toElement()); return res; } void PerformanceStatusTreeView::saveContext(QDomElement &context) const { QDomElement c = context.ownerDocument().createElement("chart"); context.appendChild(c); m_chart->saveContext(c); QDomElement t = context.ownerDocument().createElement("tree"); context.appendChild(t); m_tree->saveContext(nodeModel()->columnMap(), t); } KoPrintJob *PerformanceStatusTreeView::createPrintJob(ViewBase *view) { return m_chart->createPrintJob(view); } // hackish way to get reasonable initial splitter sizes void PerformanceStatusTreeView::resizeSplitters() { int x1 = sizes().value(0); int x2 = sizes().value(1); if (x1 == 0 && x2 == 0) { // not shown yet, try later QTimer::singleShot(100, this, &PerformanceStatusTreeView::resizeSplitters); return; } if (x1 == 0 || x2 == 0) { // one is hidden, do nothing return; } int tot = x1 + x2; x1 = qMax(x1, qMin((tot) / 2, 150)); setSizes(QList() << x1 << (tot - x1)); } +void PerformanceStatusTreeView::editCopy() +{ + QMimeData *mimeData = new QMimeData; + QPixmap pixmap(size()); + render(&pixmap); + mimeData->setImageData(pixmap); + QGuiApplication::clipboard()->setMimeData(mimeData); +} + //----------------------------------- PerformanceStatusView::PerformanceStatusView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent) { debugPlan<<"-------------------- creating PerformanceStatusView -------------------"; setXMLFile("PerformanceStatusViewUi.rc"); QVBoxLayout * l = new QVBoxLayout(this); l->setMargin(0); m_view = new PerformanceStatusTreeView(this); connect(this, &ViewBase::expandAll, m_view->treeView(), &TreeViewBase::slotExpand); connect(this, &ViewBase::collapseAll, m_view->treeView(), &TreeViewBase::slotCollapse); l->addWidget(m_view); setupGui(); connect(m_view->treeView(), &TreeViewBase::headerContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested); connect(m_view->chartView(), &QWidget::customContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested); connect(m_view->treeView(), SIGNAL(contextMenuRequested(QModelIndex,QPoint,QModelIndexList)), SLOT(slotContextMenuRequested(QModelIndex,QPoint))); Help::add(this, xi18nc("@info:whatsthis", "Task Performance View" "" "Displays performance data aggregated to the selected task." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Task_Performance_View"))); } +void PerformanceStatusView::slotEditCopy() +{ + m_view->editCopy(); +} + void PerformanceStatusView::slotContextMenuRequested(const QModelIndex &index, const QPoint& pos) { debugPlan<treeView()->setContextMenuIndex(index); if (! index.isValid()) { slotHeaderContextMenuRequested(pos); return; } Node *node = m_view->nodeModel()->node(index); if (node == 0) { slotHeaderContextMenuRequested(pos); m_view->treeView()->setContextMenuIndex(QModelIndex()); return; } slotContextMenuRequested(node, pos); m_view->treeView()->setContextMenuIndex(QModelIndex()); } Node *PerformanceStatusView::currentNode() const { return m_view->nodeModel()->node(m_view->treeView()->selectionModel()->currentIndex()); } void PerformanceStatusView::slotContextMenuRequested(Node *node, const QPoint& pos) { debugPlan<name()<<" :"<type()) { case Node::Type_Task: name = "taskview_popup"; break; case Node::Type_Milestone: name = "taskview_milestone_popup"; break; case Node::Type_Summarytask: name = "taskview_summary_popup"; break; default: break; } //debugPlan<setScheduleManager(sm); } void PerformanceStatusView::setProject(Project *project) { m_view->setProject(project); } void PerformanceStatusView::setGuiActive(bool activate) { debugPlan<objectName() == "print_options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->open(); } 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); } void PerformanceStatusView::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_dragStartPosition = event->pos(); } ViewBase::mousePressEvent(event); } void PerformanceStatusView::mouseMoveEvent(QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) { ViewBase::mouseMoveEvent(event); return; } if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { ViewBase::mouseMoveEvent(event); return; } event->accept(); QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; QPixmap pixmap(m_view->size()); m_view->render(&pixmap); mimeData->setImageData(pixmap); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } //----------------- PerformanceStatusViewSettingsDialog::PerformanceStatusViewSettingsDialog(PerformanceStatusView *view, PerformanceStatusTreeView *treeview, QWidget *parent, bool selectPrint) : ItemViewSettupDialog(view, treeview->treeView(), true, parent) { PerformanceStatusViewSettingsPanel *panel = new PerformanceStatusViewSettingsPanel(treeview->chartView(), this); KPageWidgetItem *page = insertWidget(0, panel, i18n("Chart"), i18n("Chart Settings")); setCurrentPage(page); addPrintingOptions(selectPrint); //connect(panel, SIGNAL(changed(bool)), this, SLOT(enableButtonOk(bool))); connect(this, &QDialog::accepted, panel, &PerformanceStatusViewSettingsPanel::slotOk); connect(button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, panel, &PerformanceStatusViewSettingsPanel::setDefault); } diff --git a/src/libs/ui/performance/PerformanceStatusView.h b/src/libs/ui/performance/PerformanceStatusView.h index 58763ad0..13c794b1 100644 --- a/src/libs/ui/performance/PerformanceStatusView.h +++ b/src/libs/ui/performance/PerformanceStatusView.h @@ -1,152 +1,156 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * 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 PERFORMANCESTATUSVIEW_H #define PERFORMANCESTATUSVIEW_H #include "planui_export.h" #include "PerformanceStatusBase.h" #include "kptitemmodelbase.h" #include "kptviewbase.h" #include "kptitemviewsettup.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; 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); + void editCopy(); + 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 PLANUI_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(KPlato::ScheduleManager *sm); + void slotEditCopy(); + protected Q_SLOTS: virtual void slotOptions(); protected: void updateActionsEnabled(bool on); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); private Q_SLOTS: void slotContextMenuRequested(KPlato::Node *node, const QPoint& pos); void slotContextMenuRequested(const QModelIndex &index, const QPoint& pos); private: PerformanceStatusTreeView *m_view; QPoint m_dragStartPosition; }; class PerformanceStatusViewSettingsDialog : public ItemViewSettupDialog { Q_OBJECT public: explicit PerformanceStatusViewSettingsDialog(PerformanceStatusView *view, PerformanceStatusTreeView *treeview, QWidget *parent = 0, bool selectPrint = false); }; } //namespace KPlato #endif diff --git a/src/libs/ui/performance/ProjectStatusView.cpp b/src/libs/ui/performance/ProjectStatusView.cpp index f529d479..42b8a111 100644 --- a/src/libs/ui/performance/ProjectStatusView.cpp +++ b/src/libs/ui/performance/ProjectStatusView.cpp @@ -1,197 +1,202 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * 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. */ // clazy:excludeall=qstring-arg #include "ProjectStatusView.h" #include "PerformanceStatusBase.h" #include "kptglobal.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.h" #include "kptproject.h" #include "kptschedule.h" #include "kpteffortcostmap.h" #include "Help.h" #include "kptdebug.h" #include #include "KoDocument.h" #include "KoPageLayoutWidget.h" #include #include #include #include using namespace KChart; using namespace KPlato; ProjectStatusView::ProjectStatusView(KoPart *part, KoDocument *doc, QWidget *parent) : ViewBase(part, doc, parent), m_project(0) { debugPlan<<"-------------------- creating ProjectStatusView -------------------"; setXMLFile("ProjectStatusViewUi.rc"); QVBoxLayout * l = new QVBoxLayout(this); l->setMargin(0); m_view = new PerformanceStatusBase(this); l->addWidget(m_view); setupGui(); connect(m_view, &QWidget::customContextMenuRequested, this, &ViewBase::slotHeaderContextMenuRequested); Help::add(this, xi18nc("@info:whatsthis", "Project Performance View" "" "Displays performance data aggregated to the project level." "" "This view supports configuration and printing using the context menu." "More..." "", Help::page("Manual/Project_Performance_View"))); } void ProjectStatusView::setScheduleManager(ScheduleManager *sm) { //debugPlan; m_view->setScheduleManager(sm); m_view->model()->clearNodes(); if (m_project) { m_view->setNodes(QList() << m_project); } } void ProjectStatusView::setProject(Project *project) { m_project = project; m_view->model()->clearNodes(); m_view->setProject(project); } void ProjectStatusView::setGuiActive(bool activate) { debugPlan<objectName() == "print_options"); connect(dlg, SIGNAL(finished(int)), SLOT(slotOptionsFinished(int))); dlg->open(); } 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); } void ProjectStatusView::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_dragStartPosition = event->pos(); } ViewBase::mousePressEvent(event); } void ProjectStatusView::mouseMoveEvent(QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) { ViewBase::mouseMoveEvent(event); return; } if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) { ViewBase::mouseMoveEvent(event); return; } event->accept(); QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; QPixmap pixmap(m_view->size()); m_view->render(&pixmap); mimeData->setImageData(pixmap); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); } +void ProjectStatusView::slotEditCopy() +{ + m_view->editCopy(); +} + //----------------- ProjectStatusViewSettingsDialog::ProjectStatusViewSettingsDialog(ViewBase *base, PerformanceStatusBase *view, QWidget *parent, bool selectPrint) : KPageDialog(parent), m_base(base) { PerformanceStatusViewSettingsPanel *panel = new PerformanceStatusViewSettingsPanel(view, this); KPageWidgetItem *page = new KPageWidgetItem(panel, i18n("Chart")); page->setHeader(i18n("Chart Settings")); addPage(page); QTabWidget *tab = new QTabWidget(); QWidget *w = ViewBase::createPageLayoutWidget(base); tab->addTab(w, w->windowTitle()); m_pagelayout = w->findChild(); Q_ASSERT(m_pagelayout); m_headerfooter = ViewBase::createHeaderFooterWidget(base); m_headerfooter->setOptions(base->printingOptions()); tab->addTab(m_headerfooter, m_headerfooter->windowTitle()); page = addPage(tab, i18n("Printing")); page->setHeader(i18n("Printing Options")); if (selectPrint) { setCurrentPage(page); } connect(this, &QDialog::accepted, panel, &PerformanceStatusViewSettingsPanel::slotOk); //TODO: there was no default button configured, should there? // connect(button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), panel, SLOT(setDefault())); connect(this, &QDialog::accepted, this, &ProjectStatusViewSettingsDialog::slotOk); } void ProjectStatusViewSettingsDialog::slotOk() { debugPlan; m_base->setPageLayout(m_pagelayout->pageLayout()); m_base->setPrintingOptions(m_headerfooter->options()); } diff --git a/src/libs/ui/performance/ProjectStatusView.h b/src/libs/ui/performance/ProjectStatusView.h index e5169e01..da6803ea 100644 --- a/src/libs/ui/performance/ProjectStatusView.h +++ b/src/libs/ui/performance/ProjectStatusView.h @@ -1,120 +1,121 @@ /* This file is part of the KDE project * Copyright (C) 2019 Dag Andersen * 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 PROJECTSTATUSVIEW_H #define PROJECTSTATUSVIEW_H #include "planui_export.h" #include "PerformanceStatusBase.h" #include "kptitemmodelbase.h" #include "kptviewbase.h" #include "kptitemviewsettup.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; class PLANUI_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(KPlato::ScheduleManager *sm); + void slotEditCopy(); protected: void updateActionsEnabled(bool on); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); protected Q_SLOTS: virtual void slotOptions(); private: Project *m_project; PerformanceStatusBase *m_view; QPoint m_dragStartPosition; }; //-------------------------------------- class ProjectStatusViewSettingsDialog : public KPageDialog { Q_OBJECT public: explicit ProjectStatusViewSettingsDialog(ViewBase *base, PerformanceStatusBase *view, QWidget *parent = 0, bool selectPrint = false); protected Q_SLOTS: void slotOk(); private: ViewBase *m_base; KoPageLayoutWidget *m_pagelayout; PrintingHeaderFooter *m_headerfooter; }; } //namespace KPlato #endif