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();
}
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 );
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);
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::slotGanttHeaderContextMenuRequested(const QPoint &pt)
{
- QMenu menu;
- menu.addAction(actionCollection()->action("scale_auto"));
- menu.addAction(actionCollection()->action("scale_month"));
- menu.addAction(actionCollection()->action("scale_week"));
- menu.addAction(actionCollection()->action("scale_day"));
- menu.addAction(actionCollection()->action("scale_hour"));
- menu.addSeparator();
- menu.addAction(actionCollection()->action("zoom_in"));
- menu.addAction(actionCollection()->action("zoom_out"));
- menu.exec(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->show();
dlg->raise();
dlg->activateWindow();
}
void GanttView::slotOptionsFinished( int result )
{
GanttViewSettingsDialog *dlg = qobject_cast( sender() );
if ( dlg && result == QDialog::Accepted ) {
m_gantt->graphicsView()->updateScene();
}
ViewBase::slotOptionsFinished( result );
}
void GanttView::clear()
{
// m_gantt->clear();
}
void GanttView::setShowResources( bool on )
{
m_gantt->delegate()->showResources = on;
}
void GanttView::setShowTaskName( bool on )
{
m_gantt->delegate()->showTaskName = on;
}
void GanttView::setShowProgress( bool on )
{
m_gantt->delegate()->showProgress = on;
}
void GanttView::setShowPositiveFloat( bool on )
{
m_gantt->delegate()->showPositiveFloat = on;
}
void GanttView::setShowCriticalTasks( bool on )
{
m_gantt->delegate()->showCriticalTasks = on;
}
void GanttView::setShowCriticalPath( bool on )
{
m_gantt->delegate()->showCriticalPath = on;
}
void GanttView::setShowNoInformation( bool on )
{
m_gantt->delegate()->showNoInformation = on;
}
void GanttView::setShowAppointments( bool on )
{
m_gantt->delegate()->showAppointments = on;
}
void GanttView::setShowTaskLinks( bool on )
{
m_gantt->delegate()->showTaskLinks = on;
}
void GanttView::setProject( Project *project )
{
m_gantt->setProject( project );
}
void GanttView::setScheduleManager( ScheduleManager *sm )
{
if (!sm && scheduleManager()) {
// we should only get here if the only schedule manager is scheduled,
// or when last schedule manager is deleted
m_domdoc.clear();
QDomElement element = m_domdoc.createElement("expanded");
m_domdoc.appendChild(element);
m_gantt->treeView()->saveExpanded(element);
}
bool tryexpand = sm && !scheduleManager();
bool expand = sm && scheduleManager() && sm != scheduleManager();
QDomDocument doc;
if (expand) {
QDomElement element = doc.createElement("expanded");
doc.appendChild(element);
m_gantt->treeView()->saveExpanded(element);
}
ViewBase::setScheduleManager(sm);
m_gantt->setScheduleManager( sm );
if (expand) {
m_gantt->treeView()->doExpand(doc);
} else if (tryexpand) {
m_gantt->treeView()->doExpand(m_domdoc);
}
}
void GanttView::draw( Project &project )
{
setProject( &project );
}
void GanttView::drawChanges( Project &project )
{
if ( m_project != &project ) {
setProject( &project );
}
}
Node *GanttView::currentNode() const
{
QModelIndex idx = m_gantt->treeView()->selectionModel()->currentIndex();
return m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) );
}
void GanttView::slotContextMenuRequested( const QModelIndex &idx, const QPoint &pos )
{
debugPlan;
QString name;
Node *node = m_gantt->model()->node( m_gantt->sfModel()->mapToSource( idx ) );
if ( node ) {
switch ( node->type() ) {
case Node::Type_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;
}
//----
MilestoneGanttViewSettingsDialog::MilestoneGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint )
: ItemViewSettupDialog( view, gantt->treeView(), true, view ),
m_gantt( gantt )
{
QTabWidget *tab = new QTabWidget();
QWidget *w = ViewBase::createPageLayoutWidget( view );
tab->addTab( w, w->windowTitle() );
m_pagelayout = w->findChild();
Q_ASSERT( m_pagelayout );
m_printingoptions = new GanttPrintingOptionsWidget( this );
m_printingoptions->setOptions( gantt->printingOptions() );
tab->addTab( m_printingoptions, m_printingoptions->windowTitle() );
KPageWidgetItem *page = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) );
if (selectPrint) {
setCurrentPage(page);
}
connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) );
}
void MilestoneGanttViewSettingsDialog::slotOk()
{
debugPlan;
m_gantt->setPrintingOptions( m_printingoptions->options());
ItemViewSettupDialog::slotOk();
}
//------------------------
MilestoneKGanttView::MilestoneKGanttView( QWidget *parent )
: NodeGanttViewBase( parent ),
m_manager( 0 )
{
debugPlan<<"------------------- create MilestoneKGanttView -----------------------";
MilestoneItemModel *mm = new MilestoneItemModel( this );
setItemModel( mm );
treeView()->createItemDelegates( mm );
sfModel()->setFilterRole ( Qt::EditRole );
sfModel()->setFilterFixedString( QString::number( Node::Type_Milestone ) );
sfModel()->setFilterKeyColumn( NodeModel::NodeType );
QList show;
show << NodeModel::NodeWBSCode
<< NodeModel::NodeName
<< NodeModel::NodeStartTime;
treeView()->setDefaultColumns( show );
for ( int i = 0; i < model()->columnCount(); ++i ) {
if ( ! show.contains( i ) ) {
treeView()->hideColumn( i );
}
}
treeView()->header()->moveSection(NodeModel::NodeWBSCode, show.indexOf(NodeModel::NodeWBSCode));
treeView()->setRootIsDecorated ( false );
KGantt::ProxyModel *m = static_cast( ganttProxyModel() );
m->setRole( KGantt::ItemTypeRole, KGantt::ItemTypeRole ); // To provide correct format
m->setRole( KGantt::StartTimeRole, Qt::EditRole ); // To provide correct format
m->setRole( KGantt::EndTimeRole, Qt::EditRole ); // To provide correct format
m->removeColumn( Qt::DisplayRole );
m->setColumn( KGantt::ItemTypeRole, NodeModel::NodeType );
m->setColumn( KGantt::StartTimeRole, NodeModel::NodeStartTime );
m->setColumn( KGantt::EndTimeRole, NodeModel::NodeEndTime );
m->setColumn( KGantt::TaskCompletionRole, NodeModel::NodeCompleted );
KGantt::DateTimeGrid *g = static_cast( grid() );
g->setDayWidth( 30 );
// TODO: extend QLocale/KGantt to support formats for hourly time display
// see bug #349030
// removed custom code here
// TODO: add to context
treeView()->sortByColumn(NodeModel::NodeWBSCode, Qt::AscendingOrder);
treeView()->setSortingEnabled(true);
Help::add(this,
xi18nc("@info:whatsthis",
"Milestone Gantt View"
""
"Displays scheduled milestones in a Gantt diagram."
" The chart area can be zoomed in and out with a slider"
" positioned in the upper left corner of the time scale."
" You need to hoover over it with the mouse for it to show."
""
"This view supports configuration and printing using the context menu."
"More..."
"", Help::page("Manual/Milestone_Gantt_View")));
}
MilestoneItemModel *MilestoneKGanttView::model() const
{
return static_cast( NodeGanttViewBase::model() );
}
void MilestoneKGanttView::setProject( Project *proj )
{
if ( project() ) {
disconnect( project(), &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);
}
void MilestoneGanttView::slotGanttHeaderContextMenuRequested(const QPoint &pt)
{
- QMenu menu;
- menu.addAction(actionCollection()->action("scale_auto"));
- menu.addAction(actionCollection()->action("scale_month"));
- menu.addAction(actionCollection()->action("scale_week"));
- menu.addAction(actionCollection()->action("scale_day"));
- menu.addAction(actionCollection()->action("scale_hour"));
- menu.addSeparator();
- menu.addAction(actionCollection()->action("zoom_in"));
- menu.addAction(actionCollection()->action("zoom_out"));
- menu.exec(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->show();
dlg->raise();
dlg->activateWindow();
}
bool MilestoneGanttView::loadContext( const KoXmlElement &settings )
{
debugPlan;
ViewBase::loadContext( settings );
return m_gantt->loadContext( settings );
}
void MilestoneGanttView::saveContext( QDomElement &settings ) const
{
debugPlan;
ViewBase::saveContext( settings );
return m_gantt->saveContext( settings );
}
void MilestoneGanttView::updateReadWrite( bool on )
{
m_readWrite = on;
}
KoPrintJob *MilestoneGanttView::createPrintJob()
{
return new GanttPrintingDialog( this, m_gantt );
}
//--------------------
ResourceAppointmentsGanttViewSettingsDialog::ResourceAppointmentsGanttViewSettingsDialog( GanttViewBase *gantt, ViewBase *view, bool selectPrint )
: ItemViewSettupDialog( view, gantt->treeView(), true, view )
, m_gantt(gantt)
{
QTabWidget *tab = new QTabWidget();
QWidget *w = ViewBase::createPageLayoutWidget( view );
tab->addTab( w, w->windowTitle() );
m_pagelayout = w->findChild();
Q_ASSERT( m_pagelayout );
m_printingoptions = new GanttPrintingOptionsWidget( this );
m_printingoptions->setOptions( gantt->printingOptions() );
tab->addTab( m_printingoptions, m_printingoptions->windowTitle() );
KPageWidgetItem *page = insertWidget( -1, tab, i18n( "Printing" ), i18n( "Printing Options" ) );
if (selectPrint) {
setCurrentPage(page);
}
connect( this, SIGNAL(accepted()), this, SLOT(slotOk()) );
}
void ResourceAppointmentsGanttViewSettingsDialog::slotOk()
{
debugPlan;
m_gantt->setPrintingOptions( m_printingoptions->options());
ItemViewSettupDialog::slotOk();
}
//------------------------------------------
ResourceAppointmentsGanttView::ResourceAppointmentsGanttView(KoPart *part, KoDocument *doc, QWidget *parent, bool readWrite)
: ViewBase(part, doc, parent),
m_project( 0 ),
m_model( new ResourceAppointmentsGanttModel( this ) )
{
debugPlan <<" ---------------- KPlato: Creating ResourceAppointmentsGanttView ----------------";
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::slotGanttHeaderContextMenuRequested(const QPoint &pt)
{
- QMenu menu;
- menu.addAction(actionCollection()->action("scale_auto"));
- menu.addAction(actionCollection()->action("scale_month"));
- menu.addAction(actionCollection()->action("scale_week"));
- menu.addAction(actionCollection()->action("scale_day"));
- menu.addAction(actionCollection()->action("scale_hour"));
- menu.addSeparator();
- menu.addAction(actionCollection()->action("zoom_in"));
- menu.addAction(actionCollection()->action("zoom_out"));
- menu.exec(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->show();
dlg->raise();
dlg->activateWindow();
}
bool ResourceAppointmentsGanttView::loadContext( const KoXmlElement &settings )
{
debugPlan;
ViewBase::loadContext( settings );
m_gantt->loadContext( settings );
return treeView()->loadContext( m_model->columnMap(), settings );
}
void ResourceAppointmentsGanttView::saveContext( QDomElement &settings ) const
{
debugPlan;
ViewBase::saveContext( settings );
m_gantt->saveContext( settings );
treeView()->saveContext( m_model->columnMap(), settings );
}
void ResourceAppointmentsGanttView::updateReadWrite( bool on )
{
m_readWrite = on;
}
KoPrintJob *ResourceAppointmentsGanttView::createPrintJob()
{
return new GanttPrintingDialog( this, m_gantt );
}
} //KPlato namespace
#include "moc_kptganttview.cpp"
diff --git a/src/libs/ui/kptganttview.h b/src/libs/ui/kptganttview.h
index daa356d3..601cca92 100644
--- a/src/libs/ui/kptganttview.h
+++ b/src/libs/ui/kptganttview.h
@@ -1,501 +1,500 @@
/* 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;
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
{
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(); }
- void setMenuFile(const QString &name) { setXMLFile(name); }
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);
void itemDoubleClicked();
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 );
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();
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();
Q_SIGNALS:
void itemDoubleClicked();
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; }
protected Q_SLOTS:
void slotContextMenuRequested( const QModelIndex&, const QPoint &pos );
void slotGanttHeaderContextMenuRequested(const QPoint &pt);
void slotDateTimeGridChanged();
virtual void slotOptions();
void ganttActions();
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);
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/kptviewbase.cpp b/src/libs/ui/kptviewbase.cpp
index 972d62c2..b327796d 100644
--- a/src/libs/ui/kptviewbase.cpp
+++ b/src/libs/ui/kptviewbase.cpp
@@ -1,2767 +1,2776 @@
/* This file is part of the KDE project
Copyright (C) 2006 -2010, 2012 Dag Andersen
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
// clazy:excludeall=qstring-arg
#include "kptviewbase.h"
#include "kptitemmodelbase.h"
#include "kptproject.h"
#include "kptdebug.h"
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace KPlato
{
DockWidget::DockWidget( ViewBase *v, const QString &identity, const QString &title )
: QDockWidget( v ),
view( v ),
id( identity ),
location( Qt::RightDockWidgetArea ),
editor( false ),
m_shown( true )
{
setWindowTitle( title );
setObjectName( v->objectName() + '-' + identity );
toggleViewAction()->setObjectName( objectName() );
connect(this, &QDockWidget::dockLocationChanged, this, &DockWidget::setLocation);
}
void DockWidget::activate( KoMainWindow *mainWindow )
{
connect(this, &QDockWidget::visibilityChanged, this, &DockWidget::setShown);
setVisible( m_shown );
mainWindow->addDockWidget( location, this );
foreach(const KActionCollection *c, KActionCollection::allCollections()) {
KActionMenu *a = qobject_cast(c->action("settings_dockers_menu"));
if ( a ) {
a->addAction( toggleViewAction() );
break;
}
}
}
void DockWidget::deactivate( KoMainWindow *mainWindow )
{
disconnect(this, &QDockWidget::visibilityChanged, this, &DockWidget::setShown);
mainWindow->removeDockWidget( this );
// activation re-parents to QMainWindow, so re-parent back to view
setParent( const_cast( view ) );
foreach(const KActionCollection *c, KActionCollection::allCollections()) {
KActionMenu *a = qobject_cast(c->action("settings_dockers_menu"));
if ( a ) {
a->removeAction( toggleViewAction() );
break;
}
}
}
void DockWidget::setShown( bool show )
{
m_shown = show;
setVisible( show );
}
bool KPlato::DockWidget::shown() const
{
return m_shown;
}
void DockWidget::setLocation( Qt::DockWidgetArea area )
{
location = area;
}
bool DockWidget::saveXml( QDomElement &context ) const
{
QDomElement e = context.ownerDocument().createElement( "docker" );
context.appendChild( e );
e.setAttribute( "id", id );
e.setAttribute( "location", QString::number(location) );
e.setAttribute( "floating", QString::number(isFloating()) );
e.setAttribute( "visible", QString::number(m_shown) );
return true;
}
void DockWidget::loadXml(const KoXmlElement& context)
{
location = static_cast( context.attribute( "location", "0" ).toInt() );
setFloating( (bool) context.attribute( "floating", "0" ).toInt() );
m_shown = context.attribute( "visible", "1" ).toInt();
}
//------------------------
bool PrintingOptions::loadXml( KoXmlElement &element )
{
KoXmlElement e;
forEachElement( e, element ) {
if ( e.tagName() == "header" ) {
headerOptions.group = e.attribute( "group", "0" ).toInt();
headerOptions.project = static_cast( e.attribute( "project", "0" ).toInt() );
headerOptions.date = static_cast( e.attribute( "date", "0" ).toInt() );
headerOptions.manager = static_cast( e.attribute( "manager", "0" ).toInt() );
headerOptions.page = static_cast( e.attribute( "page", "0" ).toInt() );
} else if ( e.tagName() == "footer" ) {
footerOptions.group = e.attribute( "group", "0" ).toInt();
footerOptions.project = static_cast( e.attribute( "project", "0" ).toInt() );
footerOptions.date = static_cast( e.attribute( "date", "0" ).toInt() );
footerOptions.manager = static_cast( e.attribute( "manager", "0" ).toInt() );
footerOptions.page = static_cast( e.attribute( "page", "0" ).toInt() );
}
}
return true;
}
void PrintingOptions::saveXml( QDomElement &element ) const
{
QDomElement me = element.ownerDocument().createElement( "printing-options" );
element.appendChild( me );
QDomElement h = me.ownerDocument().createElement( "header" );
me.appendChild( h );
h.setAttribute( "group", QString::number(headerOptions.group) );
h.setAttribute( "project", QString::number(headerOptions.project) );
h.setAttribute( "date", QString::number(headerOptions.date) );
h.setAttribute( "manager", QString::number(headerOptions.manager) );
h.setAttribute( "page", QString::number(headerOptions.page) );
QDomElement f = me.ownerDocument().createElement( "footer" );
me.appendChild( f );
f.setAttribute( "group", QString::number(footerOptions.group) );
f.setAttribute( "project", QString::number(footerOptions.project) );
f.setAttribute( "date", QString::number(footerOptions.date) );
f.setAttribute( "manager", QString::number(footerOptions.manager) );
f.setAttribute( "page", QString::number(footerOptions.page) );
}
//----------------------
PrintingHeaderFooter::PrintingHeaderFooter( const PrintingOptions &opt, QWidget *parent )
: QWidget( parent )
{
setupUi( this );
setWindowTitle( i18n("Header and Footer" ));
setOptions( opt );
connect(ui_header, &QGroupBox::toggled, this, &PrintingHeaderFooter::slotChanged);
connect(ui_headerProject, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_headerPage, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_headerManager, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_headerDate, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_footer, &QGroupBox::toggled, this, &PrintingHeaderFooter::slotChanged);
connect(ui_footerProject, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_footerPage, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_footerManager, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
connect(ui_footerDate, &QCheckBox::stateChanged, this, &PrintingHeaderFooter::slotChanged);
}
PrintingHeaderFooter::~PrintingHeaderFooter()
{
//debugPlan;
}
void PrintingHeaderFooter::slotChanged()
{
debugPlan;
emit changed( options() );
}
void PrintingHeaderFooter::setOptions( const PrintingOptions &options )
{
m_options = options;
ui_header->setChecked( m_options.headerOptions.group );
ui_headerProject->setCheckState( m_options.headerOptions.project );
ui_headerDate->setCheckState( m_options.headerOptions.date );
ui_headerManager->setCheckState( m_options.headerOptions.manager );
ui_headerPage->setCheckState( m_options.headerOptions.page );
ui_footer->setChecked( m_options.footerOptions.group );
ui_footerProject->setCheckState( m_options.footerOptions.project );
ui_footerDate->setCheckState( m_options.footerOptions.date );
ui_footerManager->setCheckState( m_options.footerOptions.manager );
ui_footerPage->setCheckState( m_options.footerOptions.page );
}
PrintingOptions PrintingHeaderFooter::options() const
{
//debugPlan;
PrintingOptions opt;
opt.headerOptions.group = ui_header->isChecked();
opt.headerOptions.project = ui_headerProject->checkState();
opt.headerOptions.date = ui_headerDate->checkState();
opt.headerOptions.manager = ui_headerManager->checkState();
opt.headerOptions.page = ui_headerPage->checkState();
opt.footerOptions.group = ui_footer->isChecked();
opt.footerOptions.project = ui_footerProject->checkState();
opt.footerOptions.date = ui_footerDate->checkState( );
opt.footerOptions.manager = ui_footerManager->checkState();
opt.footerOptions.page = ui_footerPage->checkState();
return opt;
}
PrintingDialog::PrintingDialog( ViewBase *view )
: KoPrintingDialog( view ),
m_view( view ),
m_widget( 0 )
{
setPrinterPageLayout( view->pageLayout() );
QImage px( 100, 600, QImage::Format_Mono );
int dpm = printer().resolution() * 40;
px.setDotsPerMeterX( dpm );
px.setDotsPerMeterY( dpm );
QPainter p( &px );
m_textheight = p.boundingRect( QRectF(), Qt::AlignTop, "Aj" ).height();
debugPlan<<"textheight:"<printingOptions();
}
void PrintingDialog::setPrintingOptions( const PrintingOptions &opt )
{
debugPlan;
m_view->setPrintingOptions( opt );
emit changed( opt );
emit changed();
}
void PrintingDialog::setPrinterPageLayout( const KoPageLayout &pagelayout )
{
QPrinter &p = printer();
QPrinter::Orientation o;
switch ( pagelayout.orientation ) {
case KoPageFormat::Portrait: o = QPrinter::Portrait; break;
case KoPageFormat::Landscape: o = QPrinter::Landscape; break;
default: o = QPrinter::Portrait; break;
}
p.setOrientation( o );
p.setPaperSize( KoPageFormat::printerPageSize( pagelayout.format ) );
p.setPageMargins( pagelayout.leftMargin, pagelayout.topMargin, pagelayout.rightMargin, pagelayout.bottomMargin, QPrinter::Point );
}
void PrintingDialog::startPrinting(RemovePolicy removePolicy )
{
setPrinterPageLayout( m_view->pageLayout() ); // FIXME: Something resets printer().paperSize() to A4 !
KoPrintingDialog::startPrinting( removePolicy );
}
QWidget *PrintingDialog::createPageLayoutWidget() const
{
QWidget *w = ViewBase::createPageLayoutWidget( m_view );
KoPageLayoutWidget *pw = w->findChild();
connect(pw, SIGNAL(layoutChanged(KoPageLayout)), m_view, SLOT(setPageLayout(KoPageLayout)));
connect(pw, &KoPageLayoutWidget::layoutChanged, this, &PrintingDialog::setPrinterPageLayout);
connect(pw, SIGNAL(layoutChanged(KoPageLayout)), this, SIGNAL(changed()));
return w;
}
QList PrintingDialog::createOptionWidgets() const
{
//debugPlan;
PrintingHeaderFooter *w = new PrintingHeaderFooter( printingOptions() );
connect(w, &PrintingHeaderFooter::changed, this, &PrintingDialog::setPrintingOptions);
const_cast( this )->m_widget = w;
return QList() << w;
}
/*QList PrintingDialog::shapesOnPage(int)
{
return QList();
}*/
void PrintingDialog::drawRect( QPainter &p, const QRect &r, Qt::Edges edges )
{
p.save();
QPen pen = p.pen();
pen.setColor(Qt::gray);
p.setPen(pen);
if (edges & Qt::LeftEdge) {
p.drawLine( r.topLeft(), r.bottomLeft() );
}
if (edges & Qt::BottomEdge) {
p.drawLine( r.bottomLeft(), r.bottomRight() );
}
if (edges & Qt::TopEdge) {
p.drawLine( r.topRight(), r.bottomRight() );
}
if (edges & Qt::RightEdge) {
p.drawLine( r.topRight(), r.bottomRight() );
}
p.restore();
}
QRect PrintingDialog::headerRect() const
{
PrintingOptions options = m_view->printingOptions();
if ( options.headerOptions.group == false ) {
return QRect();
}
int height = headerFooterHeight( options.headerOptions );
return QRect( 0, 0, const_cast( this )->printer().pageRect().width(), height );
}
QRect PrintingDialog::footerRect() const
{
PrintingOptions options = m_view->printingOptions();
if ( options.footerOptions.group == false ) {
return QRect();
}
int height = headerFooterHeight( options.footerOptions );
QRect r = const_cast( this )->printer().pageRect();
return QRect( 0, r.height() - height, r.width(), height );
}
int PrintingDialog::headerFooterHeight( const PrintingOptions::Data &options ) const
{
int height = 0.0;
if ( options.page == Qt::Checked || options.project == Qt::Checked || options.manager == Qt::Checked || options.date == Qt::Checked ) {
height += m_textheight * 1.5;
}
if ( options.project == Qt::Checked && options.manager == Qt::Checked && ( options.date == Qt::Checked || options.page == Qt::Checked ) ) {
height *= 2.0;
}
debugPlan< pageRect.left()) {
pageRect.setLeft(r.left());
}
p.restore();
if ( options.project == Qt::Checked || options.manager == Qt::Checked || options.date == Qt::Checked ) {
p.drawLine( rect_1.topRight(), rect_1.bottomRight() );
}
}
if ( options.date == Qt::Checked ) {
p.save();
QFont f = p.font();
f.setPointSize( f.pointSize() * 0.5 );
p.setFont( f );
QRect rct = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, i18n("Date:") );
p.restore();
if ( ( options.project == Qt::Checked && options.manager != Qt::Checked ) ||
( options.project != Qt::Checked && options.manager == Qt::Checked ) )
{
dateRect = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, date );
dateRect.setHeight( rect_1.height() );
rect_1.setRight( dateRect.left() - 2 );
if (rct.right() > dateRect.right()) {
dateRect.setRight(rct.right());
}
p.drawLine( rect_1.topRight(), rect_1.bottomRight() );
} else if ( options.project == Qt::Checked && options.manager == Qt::Checked ) {
dateRect = p.boundingRect( rect_2, Qt::AlignRight|Qt::AlignTop, date );
dateRect.setHeight( rect_2.height() );
rect_2.setRight( dateRect.left() - 2 );
if (rct.right() > dateRect.right()) {
dateRect.setRight(rct.right());
}
p.drawLine( rect_2.topRight(), rect_2.bottomRight() );
} else {
dateRect = p.boundingRect( rect_2, Qt::AlignLeft|Qt::AlignTop, date );
if (rct.right() > dateRect.right()) {
dateRect.setRight(rct.right());
}
dateRect.setHeight( rect_2.height() );
rect_2.setRight( dateRect.left() - 2 );
if ( rect_2.left() != rect.left() ) {
p.drawLine( rect_2.topRight(), rect_2.bottomRight() );
}
}
}
if ( options.manager == Qt::Checked ) {
p.save();
QFont f = p.font();
f.setPointSize( f.pointSize() * 0.5 );
p.setFont( f );
QRect rct = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, i18n("Manager:") );
p.restore();
if ( options.project != Qt::Checked ) {
managerRect = p.boundingRect( rect_1, Qt::AlignLeft|Qt::AlignTop, manager );
managerRect.setHeight( rect_1.height() );
if (rct.right() > managerRect.right()) {
managerRect.setRight(rct.right());
}
} else if ( options.date != Qt::Checked && options.page != Qt::Checked ) {
managerRect = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, manager );
managerRect.setHeight( rect_1.height() );
if (rct.right() > managerRect.right()) {
managerRect.setRight(rct.right());
}
rect_1.setRight( managerRect.left() - 2 );
p.drawLine( rect_1.topRight(), rect_1.bottomRight() );
} else {
managerRect = p.boundingRect( rect_2, Qt::AlignLeft|Qt::AlignTop, manager );
managerRect.setHeight( rect_2.height() );
if (rct.right() > managerRect.right()) {
managerRect.setRight(rct.right());
}
}
}
if ( options.project == Qt::Checked ) {
projectRect = p.boundingRect( rect_1, Qt::AlignLeft|Qt::AlignTop, projectName );
projectRect.setHeight( rect_1.height() );
p.save();
QFont f = p.font();
f.setPointSize( f.pointSize() * 0.5 );
p.setFont( f );
QRect rct = p.boundingRect( rect_1, Qt::AlignRight|Qt::AlignTop, i18n("Project:") );
if (rct.right() > projectRect.right()) {
projectRect.setRight(rct.right());
}
p.restore();
}
if ( options.page == Qt::Checked ) {
p.drawText( pageRect, Qt::AlignHCenter|Qt::AlignBottom, page );
}
if ( options.project == Qt::Checked ) {
p.drawText( projectRect.adjusted(3, 0, 3, 0), Qt::AlignLeft|Qt::AlignBottom, projectName );
}
if ( options.date == Qt::Checked ) {
p.drawText( dateRect, Qt::AlignHCenter|Qt::AlignBottom, date );
}
if ( options.manager == Qt::Checked ) {
p.drawText( managerRect.adjusted(3, 0, 3, 0), Qt::AlignLeft|Qt::AlignBottom, manager );
}
QFont f = p.font();
f.setPointSize( f.pointSize() * 0.5 );
p.setFont( f );
if ( options.page == Qt::Checked ) {
p.drawText( pageRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Page:" ) );
}
if ( options.project == Qt::Checked ) {
p.drawText( projectRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Project:" ) );
}
if ( options.date == Qt::Checked ) {
p.drawText( dateRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Date:" ) );
}
if ( options.manager == Qt::Checked ) {
p.drawText( managerRect, Qt::AlignTop|Qt::AlignLeft, i18n( "Manager:" ) );
}
p.restore();
}
//--------------
ViewBase::ViewBase(KoPart *part, KoDocument *doc, QWidget *parent)
: KoView(part, doc, parent),
m_readWrite( false ),
m_proj( 0 ),
m_schedulemanager( 0 ),
m_singleTreeView(nullptr),
m_doubleTreeView(nullptr)
{
}
ViewBase::~ViewBase()
{
if (factory()) {
factory()->removeClient(this);
}
if ( koDocument() ) {
//HACK to avoid ~View to access koDocument()
setDocumentDeleted();
}
}
+QMenu *ViewBase::popupMenu(const QString& name)
+{
+ //debugPlan;
+ if (factory()) {
+ return dynamic_cast(factory()->container(name, this));
+ }
+ return nullptr;
+}
+
void ViewBase::setProject( Project *project )
{
m_proj = project;
emit projectChanged( project );
}
KoDocument *ViewBase::part() const
{
return koDocument();
}
KoPageLayout ViewBase::pageLayout() const
{
return m_pagelayout;
}
void ViewBase::setPageLayout( const KoPageLayout &layout )
{
m_pagelayout = layout;
}
bool ViewBase::isActive() const
{
if ( hasFocus() ) {
return true;
}
foreach ( QWidget *v, findChildren() ) {
if ( v->hasFocus() ) {
return true;
}
}
return false;
}
void ViewBase::updateReadWrite( bool readwrite )
{
m_readWrite = readwrite;
emit readWriteChanged( readwrite );
}
void ViewBase::setGuiActive( bool active ) // virtual slot
{
//debugPlan<setWindowTitle( xi18nc( "@title:tab", "Page Layout" ) );
QHBoxLayout *lay = new QHBoxLayout(widget);
KoPageLayoutWidget *w = new KoPageLayoutWidget( widget, view->pageLayout() );
w->showPageSpread( false );
lay->addWidget( w, 1 );
KoPagePreviewWidget *prev = new KoPagePreviewWidget( widget );
prev->setPageLayout( view->pageLayout() );
lay->addWidget( prev, 1 );
connect (w, &KoPageLayoutWidget::layoutChanged, prev, &KoPagePreviewWidget::setPageLayout);
return widget;
}
/*static*/
PrintingHeaderFooter *ViewBase::createHeaderFooterWidget( ViewBase *view )
{
PrintingHeaderFooter *widget = new PrintingHeaderFooter( view->printingOptions() );
widget->setWindowTitle( xi18nc( "@title:tab", "Header and Footer" ) );
widget->setOptions( view->printingOptions() );
return widget;
}
void ViewBase::slotHeaderContextMenuRequested( const QPoint &pos )
{
debugPlan;
QList lst = contextActionList();
if ( ! lst.isEmpty() ) {
QMenu::exec( lst, pos, lst.first() );
}
}
void ViewBase::createOptionActions(int actions, const QString &prefix)
{
QAction *action;
action = new QAction(this);
action->setSeparator(true);
addContextAction(action);
if (actions & OptionExpand) {
action = new QAction(koIcon("arrow-down"), i18n("Expand All"), this);
action->setObjectName(prefix + "expand_all");
connect(action, &QAction::triggered, this, &ViewBase::expandAll);
addContextAction(action);
}
if (actions & OptionExpand) {
action = new QAction(koIcon("arrow-up"), i18n("Collapse All"), this);
action->setObjectName(prefix + "collapse_all");
connect(action, &QAction::triggered, this, &ViewBase::collapseAll);
addContextAction(action);
}
action = new QAction(this);
action->setSeparator(true);
addContextAction(action);
if (actions & OptionPrint) {
action = KStandardAction::create(KStandardAction::Print, mainWindow(), SLOT(slotFilePrint()), this);
action->setObjectName(prefix + "print");
addContextAction(action);
}
if (actions & OptionPrintPreview) {
action = KStandardAction::create(KStandardAction::PrintPreview, mainWindow(), SLOT(slotFilePrintPreview()), this);
action->setObjectName(prefix + "print_preview");
addContextAction(action);
}
if (actions & OptionPrintPdf) {
action = new QAction(koIcon("application-pdf"), i18n("Print to PDF..."), this);
action->setObjectName(prefix + "print_pdf");
connect(action, SIGNAL(triggered()), mainWindow(), SLOT(exportToPdf()));
addContextAction(action);
}
if (actions & OptionPrintConfig) {
action = new QAction(koIcon("configure"), i18n("Print Options..."), this);
action->setObjectName(prefix + "print_options");
connect(action, &QAction::triggered, this, &ViewBase::slotOptions);
addContextAction(action);
}
action = new QAction(this);
action->setSeparator(true);
addContextAction(action);
if (actions & OptionViewConfig) {
action = new QAction(koIcon("configure"), i18n("Configure View..."), this);
action->setObjectName(prefix + "configure_view");
connect(action, &QAction::triggered, this, &ViewBase::slotOptions);
addContextAction(action);
}
}
void ViewBase::slotOptionsFinished( int result )
{
if ( result == QDialog::Accepted ) {
emit optionsModified();
}
if ( sender() ) {
sender()->deleteLater();
}
}
bool ViewBase::loadContext( const KoXmlElement &context )
{
KoXmlElement me;
forEachElement( me, context ) {
if ( me.tagName() == "page-layout" ) {
m_pagelayout.format = KoPageFormat::formatFromString( me.attribute( "format" ) );
m_pagelayout.orientation = me.attribute( "orientation" ) == "landscape" ? KoPageFormat::Landscape : KoPageFormat::Portrait;
m_pagelayout.width = me.attribute( "width", "0.0" ).toDouble();
m_pagelayout.height = me.attribute( "height", "0.0" ).toDouble();
m_pagelayout.leftMargin = me.attribute( "left-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble();
m_pagelayout.rightMargin = me.attribute( "right-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble();
m_pagelayout.topMargin = me.attribute( "top-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble();
m_pagelayout.bottomMargin = me.attribute( "bottom-margin", QString::number( MM_TO_POINT( 20.0 ) ) ).toDouble();
} else if ( me.tagName() == "printing-options" ) {
m_printingOptions.loadXml( me );
} else if ( me.tagName() == "dockers" ) {
KoXmlElement e;
forEachElement ( e, me ) {
DockWidget *ds = findDocker( e.attribute( "id" ) );
if ( ds ) {
ds->loadXml( e );
}
}
}
}
return true;
}
void ViewBase::saveContext( QDomElement &context ) const
{
QDomElement me = context.ownerDocument().createElement( "page-layout" );
context.appendChild( me );
me.setAttribute( "format", KoPageFormat::formatString( m_pagelayout.format ) );
me.setAttribute( "orientation", m_pagelayout.orientation == KoPageFormat::Portrait ? "portrait" : "landscape" );
me.setAttribute( "width", QString::number(m_pagelayout.width) );
me.setAttribute( "height",QString::number(m_pagelayout. height) );
me.setAttribute( "left-margin", QString::number(m_pagelayout.leftMargin) );
me.setAttribute( "right-margin", QString::number(m_pagelayout.rightMargin) );
me.setAttribute( "top-margin", QString::number(m_pagelayout.topMargin) );
me.setAttribute( "bottom-margin",QString::number( m_pagelayout.bottomMargin) );
m_printingOptions.saveXml( context );
if ( ! m_dockers.isEmpty() ) {
QDomElement e = context.ownerDocument().createElement( "dockers" );
context.appendChild( e );
foreach ( const DockWidget *ds, m_dockers ) {
ds->saveXml( e );
}
}
}
void ViewBase::addDocker( DockWidget *ds )
{
//addAction( "view_docker_list", ds->toggleViewAction() );
m_dockers << ds;
}
QList ViewBase::dockers() const
{
return m_dockers;
}
DockWidget* ViewBase::findDocker( const QString &id ) const
{
foreach ( DockWidget *ds, m_dockers ) {
if ( ds->id == id ) {
return ds;
}
}
return 0;
}
void ViewBase::setViewSplitMode(bool split)
{
if (m_doubleTreeView) {
m_doubleTreeView->setViewSplitMode(split);
}
}
void ViewBase::showColumns(const QList &left, const QList &right)
{
TreeViewBase *view1 = m_singleTreeView;
TreeViewBase *view2 = nullptr;
if (m_doubleTreeView) {
view1 = m_doubleTreeView->masterView();
view2 = m_doubleTreeView->slaveView();
m_doubleTreeView->setViewSplitMode(!right.isEmpty());
}
if (view1) {
const QAbstractItemModel *model = view1->model();
if (model) {
int count = model->columnCount();
for (int i = 0; i < count; ++i) {
view1->setColumnHidden(i, !left.contains(i));
if (view2) {
view2->setColumnHidden(i, !right.contains(i));
}
}
// sort columns
for (int i = 0; i < left.count(); ++i) {
view1->mapToSection(left.at(i), i);
}
if (view2) {
for (int i = 0; i < right.count(); ++i) {
view2->mapToSection(right.at(i), i);
}
}
}
}
}
void ViewBase::addActionList(const QString &name, const QList actions) {
for (QAction *a : actions) {
const QString &tag = a->objectName();
if (!tag.isEmpty()) {
addAction(name, a);
actionCollection()->addAction(tag, a);
}
}
}
//----------------------
TreeViewPrintingDialog::TreeViewPrintingDialog( ViewBase *view, TreeViewBase *treeview, Project *project )
: PrintingDialog( view ),
m_tree( treeview ),
m_project( project ),
m_firstRow( -1 )
{
printer().setFromTo( documentFirstPage(), documentLastPage() );
}
int TreeViewPrintingDialog::documentLastPage() const
{
int page = documentFirstPage();
while ( firstRow( page ) != -1 ) {
++page;
}
if ( page > documentFirstPage() ) {
--page;
}
return page;
}
int TreeViewPrintingDialog::firstRow( int page ) const
{
debugPlan<header();
int height = mh->height();
int hHeight = headerRect().height();
int fHeight = footerRect().height();
QRect pageRect = const_cast( this )->printer().pageRect();
int gap = 8;
int pageHeight = pageRect.height() - height;
if ( hHeight > 0 ) {
pageHeight -= ( hHeight + gap );
}
if ( fHeight > 0 ) {
pageHeight -= ( fHeight + gap );
}
int rowsPrPage = pageHeight / height;
int rows = m_tree->model()->rowCount();
int row = -1;
for ( int i = 0; i < rows; ++i ) {
if ( ! m_tree->isRowHidden( i, QModelIndex() ) ) {
row = i;
break;
}
}
if ( row != -1 ) {
QModelIndex idx = m_tree->model()->index( row, 0, QModelIndex() );
row = 0;
while ( idx.isValid() ) {
if ( row >= rowsPrPage * pageNumber ) {
debugPlan<indexBelow( idx );
}
if ( ! idx.isValid() ) {
row = -1;
}
}
debugPlan<<"Page"< TreeViewPrintingDialog::createOptionWidgets() const
{
QList lst;
lst << createPageLayoutWidget();
lst += PrintingDialog::createOptionWidgets();
return lst;
}
void TreeViewPrintingDialog::printPage( int page, QPainter &painter )
{
m_firstRow = firstRow( page );
QHeaderView *mh = m_tree->header();
int length = mh->length();
int height = mh->height();
QRect hRect = headerRect();
QRect fRect = footerRect();
QRect pageRect = printer().pageRect();
pageRect.moveTo( 0, 0 );
QRect paperRect = printer().paperRect();
QAbstractItemModel *model = m_tree->model();
debugPlan<printingOptions(), page, *(m_project) );
}
int gap = 8;
int pageHeight = pageRect.height() - height;
if ( hRect.isValid() ) {
pageHeight -= ( hRect.height() + gap );
}
if ( fRect.isValid() ) {
pageHeight -= ( fRect.height() + gap );
}
int rowsPrPage = pageHeight / height;
double sx = pageRect.width() > length ? 1.0 : (double)pageRect.width() / (double)length;
double sy = 1.0;
painter.scale( sx, sy );
int h = 0;
painter.translate( 0, hRect.height() + gap );
h = hRect.height() + gap;
painter.setPen(Qt::black);
painter.setBrush( Qt::lightGray );
int higestIndex = 0;
int rightpos = 0;
for ( int i = 0; i < mh->count(); ++i ) {
QString text = model->headerData( i, Qt::Horizontal ).toString();
QVariant a = model->headerData( i, Qt::Horizontal, Qt::TextAlignmentRole );
int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter);
if ( ! mh->isSectionHidden( i ) ) {
QRect r = QRect( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height ).adjusted(0, 0, 0, -painter.pen().width());
if (rightpos < r.right()) {
higestIndex = i;
rightpos = r.right();
}
painter.drawRect( r );
// FIXME There is a bug somewhere, the text somehow overwites the rect outline for the first column!
painter.save();
painter.setBrush(QBrush());
painter.drawText( r.adjusted(3, 1, -3, -1), align, text );
painter.drawRect( r );
painter.restore();
}
//debugPlan<isSectionHidden( i )<sectionPosition( i );
}
if ( m_firstRow == -1 ) {
debugPlan<<"No data";
return;
}
painter.setBrush( QBrush() );
QModelIndex idx = model->index( m_firstRow, 0, QModelIndex() );
int numRows = 0;
//debugPlan<count(); ++i ) {
if ( mh->isSectionHidden( i ) ) {
continue;
}
Qt::Edges edges = Qt::BottomEdge | Qt::LeftEdge;
QModelIndex index = model->index( idx.row(), i, idx.parent() );
QString text = model->data( index ).toString();
QVariant a = model->data( index, Qt::TextAlignmentRole );
int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter);
QRect r( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height );
if (higestIndex == i) {
edges |= Qt::RightEdge;
r.adjust(0, 0, 1, 0);
}
drawRect( painter, r, edges );
painter.drawText( r.adjusted(3, 1, -3, -1) , align, text );
}
++numRows;
idx = m_tree->indexBelow( idx );
}
}
/**
* TreeViewBase is a QTreeView adapted for operation by keyboard only and as components in DoubleTreeViewBase.
* Note that keyboard navigation and selection behavior may not be fully compliant with QTreeView.
* If you use other settings than QAbstractItemView::ExtendedSelection and QAbstractItemView::SelectRows,
* you should have a look at the implementation keyPressEvent() and updateSelection().
*/
TreeViewBase::TreeViewBase( QWidget *parent )
: QTreeView( parent ),
m_arrowKeyNavigation( true ),
m_acceptDropsOnView( false ),
m_readWrite( false ),
m_handleDrag(true)
{
m_dragPixmap = koIcon("application-x-vnd.kde.plan").pixmap(32);
setDefaultDropAction( Qt::MoveAction );
setItemDelegate( new ItemDelegate( this ) );
setAlternatingRowColors ( true );
setExpandsOnDoubleClick(false);
header()->setContextMenuPolicy( Qt::CustomContextMenu );
connect( header(), &QWidget::customContextMenuRequested, this, &TreeViewBase::slotHeaderContextMenuRequested );
}
void TreeViewBase::dropEvent( QDropEvent *e )
{
debugPlan;
QTreeView::dropEvent( e );
}
KoPrintJob * TreeViewBase::createPrintJob( ViewBase *parent )
{
TreeViewPrintingDialog *dia = new TreeViewPrintingDialog( parent, this, parent->project() );
dia->printer().setCreator( QString( "Plan %1" ).arg( PLAN_VERSION_STRING ) );
// dia->printer().setFullPage(true); // ignore printer margins
return dia;
}
void TreeViewBase::setReadWrite( bool rw )
{
m_readWrite = rw;
if ( model() ) {
model()->setData( QModelIndex(), rw, Role::ReadWrite );
}
}
void TreeViewBase::createItemDelegates( ItemModelBase *model )
{
for ( int c = 0; c < model->columnCount(); ++c ) {
QAbstractItemDelegate *delegate = model->createDelegate( c, this );
if ( delegate ) {
setItemDelegateForColumn( c, delegate );
}
}
}
void TreeViewBase::slotHeaderContextMenuRequested( const QPoint& pos )
{
//debugPlan;
emit headerContextMenuRequested( header()->mapToGlobal( pos ) );
}
void TreeViewBase::setColumnsHidden( const QList &lst )
{
//debugPlan< xlst;
foreach ( int c, lst ) {
if ( c == -1 ) {
// hide rest
for ( int i = prev+1; i < model()->columnCount(); ++i ) {
if ( ! lst.contains( i ) ) {
xlst << i;
}
}
break;
}
xlst << c;
prev = c;
}
for ( int c = 0; c < model()->columnCount(); ++c ) {
setColumnHidden( c, xlst.contains( c ) );
}
}
QModelIndex TreeViewBase::firstColumn( int row, const QModelIndex &parent )
{
int s;
for ( s = 0; s < header()->count(); ++s ) {
if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) {
break;
}
}
if ( s == -1 ) {
return QModelIndex();
}
return model()->index( row, header()->logicalIndex( s ), parent );
}
QModelIndex TreeViewBase::lastColumn( int row, const QModelIndex &parent )
{
int s;
for ( s = header()->count() - 1; s >= 0; --s ) {
if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) {
break;
}
}
if ( s == -1 ) {
return QModelIndex();
}
return model()->index( row, header()->logicalIndex( s ), parent );
}
QModelIndex TreeViewBase::nextColumn( const QModelIndex &curr )
{
return moveCursor( curr, QAbstractItemView::MoveRight );
}
QModelIndex TreeViewBase::previousColumn( const QModelIndex &curr )
{
return moveCursor( curr, QAbstractItemView::MoveLeft );
}
QModelIndex TreeViewBase::firstEditable( int row, const QModelIndex &parent )
{
QModelIndex index = firstColumn( row, parent );
if ( model()->flags( index ) & Qt::ItemIsEditable ) {
return index;
}
return moveToEditable( index, QAbstractItemView::MoveRight );
}
QModelIndex TreeViewBase::lastEditable( int row, const QModelIndex &parent )
{
QModelIndex index = lastColumn( row, parent );
if ( model()->flags( index ) & Qt::ItemIsEditable ) {
return index;
}
return moveToEditable( index, QAbstractItemView::MoveLeft );
}
// Reimplemented to fix qt bug 160083: Doesn't scroll horizontally.
void TreeViewBase::scrollTo(const QModelIndex &index, ScrollHint hint)
{
//debugPlan<width();
int horizontalOffset = header()->offset();
int horizontalPosition = header()->sectionPosition(index.column());
int cellWidth = header()->sectionSize(index.column());
if (hint == PositionAtCenter) {
horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
} else {
if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
horizontalScrollBar()->setValue(horizontalPosition);
else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
}
}
void TreeViewBase::focusInEvent(QFocusEvent *event)
{
//debugPlan<reason();
QAbstractScrollArea::focusInEvent(event); //NOTE: not QTreeView
if ( event->reason() == Qt::MouseFocusReason ) {
return;
}
QModelIndex curr = currentIndex();
if ( ! curr.isValid() || ! isIndexHidden( curr ) ) {
return;
}
QModelIndex idx = curr;
for ( int s = 0; s < header()->count(); ++s) {
idx = model()->index( curr.row(), header()->logicalIndex( s ), curr.parent() );
if ( ! isIndexHidden( idx ) ) {
selectionModel()->setCurrentIndex(idx, QItemSelectionModel::NoUpdate);
scrollTo( idx );
break;
}
}
}
/*!
\reimp
*/
void TreeViewBase::keyPressEvent(QKeyEvent *event)
{
//debugPlan<key()<<","<key()) {
case Qt::Key_Right: {
QModelIndex nxt = moveCursor( MoveRight, Qt::NoModifier );
if ( nxt.isValid() ) {
selectionModel()->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate );
} else {
emit moveAfterLastColumn( current );
}
event->accept();
return;
break;
}
case Qt::Key_Left: {
QModelIndex prv = moveCursor( MoveLeft, Qt::NoModifier );
if ( prv.isValid() ) {
selectionModel()->setCurrentIndex( prv, QItemSelectionModel::NoUpdate );
} else {
emit moveBeforeFirstColumn( current );
}
event->accept();
return;
break;
}
case Qt::Key_Down: {
QModelIndex i = moveCursor( MoveDown, Qt::NoModifier );
updateSelection( current, i, event );
event->accept();
return;
break;
}
case Qt::Key_Up: {
QModelIndex i = moveCursor( MoveUp, Qt::NoModifier );
updateSelection( current, i, event );
event->accept();
return;
break;
}
default: break;
}
}
QTreeView::keyPressEvent(event);
}
void TreeViewBase::updateSelection( const QModelIndex &oldidx, const QModelIndex &newidx, QKeyEvent *event )
{
if ( newidx == oldidx || ! newidx.isValid() ) {
return;
}
if ( !hasFocus() && QApplication::focusWidget() == indexWidget(oldidx) ) {
setFocus();
}
QItemSelectionModel::SelectionFlags command;
// NoUpdate on Key movement and Ctrl
Qt::KeyboardModifiers modifiers = static_cast(event)->modifiers();
switch (static_cast(event)->key()) {
case Qt::Key_Backtab:
modifiers = modifiers & ~Qt::ShiftModifier; // special case for backtab
Q_FALLTHROUGH();
case Qt::Key_Down:
case Qt::Key_Up:
case Qt::Key_Left:
case Qt::Key_Right:
if (modifiers & Qt::ControlModifier)
command = QItemSelectionModel::NoUpdate;
else if (modifiers & Qt::ShiftModifier)
command = QItemSelectionModel::Select | selectionBehaviorFlags();
else
command = QItemSelectionModel::ClearAndSelect | selectionBehaviorFlags();
break;
default:
break;
}
selectionModel()->setCurrentIndex( newidx, command );
}
void TreeViewBase::mousePressEvent(QMouseEvent *event)
{
// If the mouse is pressed outside any item, the current item should be/remain selected
QPoint pos = event->pos();
QModelIndex index = indexAt(pos);
debugPlan<pos();
if ( ! index.isValid() ) {
index = selectionModel()->currentIndex();
if ( index.isValid() && ! selectionModel()->isSelected( index ) ) {
pos = visualRect( index ).center();
QMouseEvent e( event->type(), pos, mapToGlobal( pos ), event->button(), event->buttons(), event->modifiers() );
QTreeView::mousePressEvent( &e );
event->setAccepted( e.isAccepted() );
debugPlan<( sender() );
if ( delegate == 0 ) {
warnPlan<<"Not a KPlato::ItemDelegate, try standard treatment"<endEditHint();
// Close editor, do nothing else
QTreeView::closeEditor( editor, QAbstractItemDelegate::NoHint );
QModelIndex index;
switch ( endHint ) {
case Delegate::EditLeftItem:
index = moveToEditable( currentIndex(), MoveLeft );
break;
case Delegate::EditRightItem:
index = moveToEditable( currentIndex(), MoveRight );
break;
case Delegate::EditDownItem:
index = moveToEditable( currentIndex(), MoveDown );
break;
case Delegate::EditUpItem:
index = moveToEditable( currentIndex(), MoveUp );
break;
default:
//debugPlan<<"Standard treatment"<setCurrentIndex(persistent, flags);
// currentChanged signal would have already started editing
if (!(editTriggers() & QAbstractItemView::CurrentChanged)) {
edit(persistent);
}
}
}
QModelIndex TreeViewBase::moveToEditable( const QModelIndex &index, CursorAction cursorAction )
{
QModelIndex ix = index;
do {
ix = moveCursor( ix, cursorAction );
} while ( ix.isValid() && ! ( model()->flags( ix ) & Qt::ItemIsEditable ) );
//debugPlan<= model()->columnCount(ix.parent()) ) {
//debugPlan<columnCount(ix.parent())<index( ix.row(), col, ix.parent() );
} // else Here we could go to the top
return ix;
}
case MoveUp: {
// TODO: span
// Fetch the index above current.
// This should be the previous non-hidden row, same column as current,
// that has a column in current.column()
ix = indexAbove( current );
while ( ix.isValid() && col >= model()->columnCount(ix.parent()) ) {
ix = indexAbove( ix );
}
if ( ix.isValid() ) {
ix = model()->index( ix.row(), col, ix.parent() );
} // else Here we could go to the bottom
return ix;
}
case MovePrevious:
case MoveLeft: {
for ( int s = header()->visualIndex( col ) - 1; s >= 0; --s ) {
if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) {
ix = model()->index( current.row(), header()->logicalIndex( s ), current.parent() );
break;
}
}
return ix;
}
case MoveNext:
case MoveRight: {
for ( int s = header()->visualIndex( col ) + 1; s < header()->count(); ++s ) {
if ( ! header()->isSectionHidden( header()->logicalIndex( s ) ) ) {
ix = model()->index( current.row(), header()->logicalIndex( s ), current.parent() );
break;
}
}
return ix;
}
case MovePageUp:
case MovePageDown: {
ix = QTreeView::moveCursor( cursorAction, modifiers );
// Now we are at the correct row, so move to correct column
if ( ix.isValid() ) {
ix = model()->index( ix.row(), col, ix.parent() );
} // else Here we could go to the bottom
return ix;
}
case MoveHome: {
if ( ( modifiers & Qt::ControlModifier ) == 0 ) {
ix = QTreeView::moveCursor( cursorAction, modifiers ); // move to first row
} else { //stay at this row
ix = current;
}
for ( int s = 0; s < header()->count(); ++s ) {
int logicalIndex = header()->logicalIndex( s );
if ( ! isColumnHidden( logicalIndex ) ) {
ix = model()->index( ix.row(), header()->logicalIndex( s ), ix.parent() );
break;
}
}
return ix;
}
case MoveEnd: {
if ( ( modifiers & Qt::ControlModifier ) == 0 ) {
ix = QTreeView::moveCursor( cursorAction, modifiers ); // move to last row
} else { //stay at this row
ix = current;
}
for ( int s = header()->count() - 1; s >= 0; --s ) {
int logicalIndex = header()->logicalIndex( s );
if ( ! isColumnHidden( logicalIndex ) ) {
ix = model()->index( ix.row(), logicalIndex, ix.parent() );
break;
}
}
return ix;
}
default: break;
}
return ix;
}
void TreeViewBase::contextMenuEvent ( QContextMenuEvent *event )
{
debugPlan<selectedRows();
emit contextMenuRequested( indexAt(event->pos()), event->globalPos(), selectionModel()->selectedRows() );
}
void TreeViewBase::slotCurrentChanged( const QModelIndex ¤t, const QModelIndex & )
{
if ( current.isValid() ) {
scrollTo( current );
}
}
void TreeViewBase::setModel( QAbstractItemModel *model )
{
if ( selectionModel() ) {
disconnect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged );
}
QTreeView::setModel( model );
if ( selectionModel() ) {
connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged );
}
setReadWrite( m_readWrite );
}
void TreeViewBase::setSelectionModel( QItemSelectionModel *model )
{
if ( selectionModel() ) {
disconnect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged );
}
QTreeView::setSelectionModel( model );
if ( selectionModel() ) {
connect( selectionModel(), &QItemSelectionModel::currentChanged, this, &TreeViewBase::slotCurrentChanged );
}
}
void TreeViewBase::setStretchLastSection( bool mode )
{
header()->setStretchLastSection( mode );
}
void TreeViewBase::mapToSection( int col, int section )
{
header()->moveSection( header()->visualIndex( col ), section );
}
int TreeViewBase::section( int col ) const
{
return header()->visualIndex( col );
}
void TreeViewBase::dragMoveEvent(QDragMoveEvent *event)
{
//debugPlan;
if (dragDropMode() == InternalMove
&& (event->source() != this || !(event->possibleActions() & Qt::MoveAction))) {
//debugPlan<<"Internal:"<isAccepted();
return;
}
QTreeView::dragMoveEvent( event );
if ( dropIndicatorPosition() == QAbstractItemView::OnViewport ) {
if ( ! m_acceptDropsOnView ) {
event->ignore();
}
debugPlan<<"On viewport:"<isAccepted();
} else {
QModelIndex index = indexAt( event->pos() );
if ( index.isValid() ) {
emit dropAllowed( index, dropIndicatorPosition(), event );
} else {
event->ignore();
debugPlan<<"Invalid index:"<isAccepted();
}
}
if ( event->isAccepted() ) {
if ( viewport()->cursor().shape() == Qt::ForbiddenCursor ) {
viewport()->unsetCursor();
}
} else if ( viewport()->cursor().shape() != Qt::ForbiddenCursor ) {
viewport()->setCursor( Qt::ForbiddenCursor );
}
debugPlan<isAccepted()<cursor().shape();
}
QModelIndex TreeViewBase::firstVisibleIndex( const QModelIndex &idx ) const
{
int count = model()->columnCount();
for ( int c = 0; c < count; ++c ) {
if ( ! isColumnHidden( c ) ) {
return model()->index( idx.row(), c, model()->parent( idx ) );
}
}
return QModelIndex();
}
bool TreeViewBase::loadContext( const QMetaEnum &map, const KoXmlElement &element, bool expand )
{
//debugPlan<setStretchLastSection( (bool)( element.attribute( "stretch-last-column", "1" ).toInt() ) );
KoXmlElement e = element.namedItem( "columns" ).toElement();
if ( ! e.isNull() ) {
if ( ! map.isValid() ) {
// try numbers
debugPlan<<"invalid map";
for ( int i = model()->columnCount() - 1; i >= 0; --i ) {
QString s = e.attribute( QString( "column-%1" ).arg( i ), "" );
if ( s == "hidden" ) {
hideColumn( i );
} else if ( s == "shown" ) {
showColumn( i );
} else debugPlan<columnCount() - 1; i >= 0; --i ) {
QString n = map.key( i );
//debugPlan<count(); ++i ) {
if ( e.hasAttribute( s.arg( i ) ) ) {
int index = e.attribute( s.arg( i ), "-1" ).toInt();
if ( index >= 0 && index < h->count() ) {
header()->moveSection( h->visualIndex( index ), i );
}
}
}
} else {
QMap m; // QMap
for ( int i = 0; i < h->count(); ++i ) {
QString n = e.attribute( s.arg( i ) );
if ( n.isEmpty() ) {
continue;
}
int col = map.keyToValue( n.toUtf8() );
if ( col >= 0 && col < h->count() ) {
m.insert( i, col );
}
}
for ( QMap::const_iterator it = m.constBegin(); it != m.constEnd(); ++it ) {
QString n = e.attribute( s.arg( it.key() ) );
int current = h->visualIndex( it.value() );
header()->moveSection( current, it.key() );
}
}
}
if (expand) {
loadExpanded(element);
}
if (!e.isNull()) {
// FIXME: This only works for column 0
QHeaderView *h = header();
QString s("size-%1");
for (int i = 0; i < model()->columnCount(); ++i) {
if (!h->isSectionHidden(i) && e.hasAttribute(s.arg(i))) {
int size = e.attribute(s.arg(i)).toInt();
if (size > 0) {
h->resizeSection(i, size);
}
}
}
}
return true;
}
void TreeViewBase::saveContext( const QMetaEnum &map, QDomElement &element, bool expand ) const
{
//debugPlan<stretchLastSection()) );
QDomElement e = element.ownerDocument().createElement( "columns" );
element.appendChild( e );
for ( int i = 0; i < model()->columnCount(); ++i ) {
bool h = isColumnHidden( i );
if ( ! map.isValid() ) {
debugPlan<<"invalid map";
e.setAttribute( QString( "column-%1" ).arg( i ), h ? "hidden" : "shown" );
} else {
QString n = map.key( i );
//debugPlan<count(); ++i ) {
if ( ! isColumnHidden( h->logicalIndex( i ) ) ) {
if ( ! map.isValid() ) {
e.setAttribute( QString( "section-%1" ).arg( i ), h->logicalIndex( i ) );
} else {
QString n = map.key( h->logicalIndex( i ) );
if ( ! n.isEmpty() ) {
e.setAttribute( QString( "section-%1" ).arg( i ), n );
e.setAttribute( QString("size-%1").arg(i), h->sectionSize(h->logicalIndex(i)));
}
}
}
}
if (expand) {
QDomElement expanded = element.ownerDocument().createElement("expanded");
element.appendChild(expanded);
saveExpanded(expanded);
}
}
ItemModelBase *TreeViewBase::itemModel() const
{
QAbstractItemModel *m = model();
QAbstractProxyModel *p = qobject_cast( m );
while ( p ) {
m = p->sourceModel();
p = qobject_cast( m );
}
return qobject_cast( m );
}
void TreeViewBase::expandRecursive(const QModelIndex &idx, bool xpand)
{
int rowCount = model()->rowCount(idx);
if (rowCount == 0) {
return;
}
xpand ? expand(idx) : collapse(idx);
for (int r = 0; r < rowCount; ++r) {
QModelIndex i = model()->index(r, 0, idx);
Q_ASSERT(i.isValid());
expandRecursive(i, xpand);
}
}
void TreeViewBase::slotExpand()
{
// NOTE: Do not use this, KGantt does not like it
// if (!m_contextMenuIndex.isValid()) {
// expandAll();
// return;
// }
QModelIndex idx = m_contextMenuIndex;
if (idx.column() > 0) {
idx = idx.model()->index(idx.row(), idx.column(), idx.parent());
}
expandRecursive(idx, true);
}
void TreeViewBase::slotCollapse()
{
// NOTE: Do not use this, KGantt does not like it
// if (!m_contextMenuIndex.isValid()) {
// collapseAll();
// return;
// }
QModelIndex idx = m_contextMenuIndex;
if (idx.column() > 0) {
idx = idx.model()->index(idx.row(), 0, idx.parent());
}
expandRecursive(idx, false);
}
void TreeViewBase::setContextMenuIndex(const QModelIndex &idx)
{
m_contextMenuIndex = idx;
}
void TreeViewBase::loadExpanded(const KoXmlElement &element)
{
// we get here on loadContext()
m_loadContextDoc.clear();
KoXmlElement expanded = element.namedItem("expanded").toElement();
if (expanded.isNull()) {
return;
}
KoXml::asQDomElement(m_loadContextDoc, expanded);
// FIXME:
// if data is dependent on schedule manger
// we cannot do anything until schedulemanger is set,
// so we wait a bit and hope everything is ok
QTimer::singleShot(500, this, &TreeViewBase::doContextExpanded);
}
void TreeViewBase::expandRecursivly(QDomElement element, const QModelIndex &parent)
{
if (element.isNull()) {
return;
}
for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) {
QDomElement e = n.toElement();
if (e.tagName() != "item") {
continue;
}
int childRow = e.attribute("row", "-1").toInt();
if (childRow > -1) {
QModelIndex idx = model()->index(childRow, 0, parent);
if (idx.isValid()) {
setExpanded(idx, true);
expandRecursivly(e, idx);
}
}
}
}
void TreeViewBase::doExpand(QDomDocument &doc)
{
// we get here on setScheduleManager()
m_expandDoc = doc;
QTimer::singleShot(0, this, &TreeViewBase::doExpanded);
}
void TreeViewBase::doContextExpanded()
{
expandRecursivly(m_loadContextDoc.documentElement());
}
void TreeViewBase::doExpanded()
{
expandRecursivly(m_expandDoc.documentElement());
}
void TreeViewBase::saveExpanded(QDomElement &element, const QModelIndex &parent) const
{
for (int r = 0; r < model()->rowCount(parent); ++r) {
QModelIndex idx = model()->index(r, 0, parent);
if (isExpanded(idx)) {
QDomElement e = element.ownerDocument().createElement("item");
e.setAttribute("row", r);
element.appendChild(e);
saveExpanded(e, idx);
}
}
}
void TreeViewBase::setHandleDrag(bool state)
{
m_handleDrag = state;
}
void TreeViewBase::startDrag(Qt::DropActions supportedActions)
{
Qt::DropAction defaultDropAction = Qt::IgnoreAction;
if (this->defaultDropAction() != Qt::IgnoreAction && (supportedActions & this->defaultDropAction())) {
defaultDropAction = this->defaultDropAction();
} else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove) {
defaultDropAction = Qt::CopyAction;
}
if (m_handleDrag) {
QModelIndexList indexes = selectionModel()->selectedRows();
if (!indexes.isEmpty()) {
QMimeData *data = model()->mimeData(indexes);
if (!data) {
debugPlan<<"No mimedata";
return;
}
QDrag *drag = new QDrag(this);
drag->setPixmap(m_dragPixmap);
drag->setMimeData(data);
drag->exec(supportedActions, defaultDropAction);
}
} else {
static_cast(parent())->handleDrag(supportedActions, defaultDropAction);
}
}
QList TreeViewBase::visualColumns() const
{
if (!isVisible()) {
return QList();
}
QMap columns;
for (int i = 0; i < model()->columnCount(); ++i) {
if (!isColumnHidden(i)) {
columns.insert(header()->visualIndex(i), i);
}
}
return columns.values();
}
void TreeViewBase::setDragPixmap(const QPixmap &pixmap)
{
m_dragPixmap = pixmap;
}
QPixmap TreeViewBase::dragPixmap() const
{
return m_dragPixmap;
}
void TreeViewBase::editCopy()
{
}
void TreeViewBase::editPaste()
{
}
QModelIndexList TreeViewBase::selectedIndexes() const
{
QModelIndexList viewSelected;
QModelIndexList modelSelected;
if (selectionModel())
modelSelected = selectionModel()->selectedIndexes();
for (int i = 0; i < modelSelected.count(); ++i) {
// check that neither the parents nor the index is hidden before we add
QModelIndex index = modelSelected.at(i);
while (index.isValid() && !isIndexHidden(index)) {
int column = index.column();
index = index.parent();
if (index.isValid() && column != index.column()) {
index = index.sibling(index.row(), column);
}
}
if (index.isValid())
continue;
viewSelected.append(modelSelected.at(i));
}
return viewSelected;
}
//----------------------
DoubleTreeViewPrintingDialog::DoubleTreeViewPrintingDialog( ViewBase *view, DoubleTreeViewBase *treeview, Project *project )
: PrintingDialog( view ),
m_tree( treeview ),
m_project( project ),
m_firstRow( -1 )
{
printer().setFromTo( documentFirstPage(), documentLastPage() );
}
int DoubleTreeViewPrintingDialog::documentLastPage() const
{
debugPlan<pageLayout().format );
int page = documentFirstPage();
while ( firstRow( page ) != -1 ) {
++page;
}
if ( page > documentFirstPage() ) {
--page;
}
return page;
}
int DoubleTreeViewPrintingDialog::firstRow( int page ) const
{
debugPlan<masterView()->header();
QHeaderView *sh = m_tree->slaveView()->header();
int height = mh->height() > sh->height() ? mh->height() : sh->height();
int hHeight = headerRect().height();
int fHeight = footerRect().height();
QRect pageRect = const_cast( this )->printer().pageRect();
int gap = 8;
int pageHeight = pageRect.height() - height;
if ( hHeight > 0 ) {
pageHeight -= ( hHeight + gap );
}
if ( fHeight > 0 ) {
pageHeight -= ( fHeight + gap );
}
int rowsPrPage = pageHeight / height;
debugPlan<<"rowsPrPage"< 0 );
int rows = m_tree->model()->rowCount();
int row = -1;
for ( int i = 0; i < rows; ++i ) {
if ( ! m_tree->masterView()->isRowHidden( i, QModelIndex() ) ) {
row = i;
break;
}
}
if ( row != -1 ) {
QModelIndex idx = m_tree->model()->index( row, 0, QModelIndex() );
row = 0;
while ( idx.isValid() ) {
if ( row >= rowsPrPage * pageNumber ) {
debugPlan<masterView()->indexBelow( idx );
}
if ( ! idx.isValid() ) {
row = -1;
}
}
debugPlan<<"Page"< DoubleTreeViewPrintingDialog::createOptionWidgets() const
{
QList lst;
lst << createPageLayoutWidget();
lst += PrintingDialog::createOptionWidgets();
return lst;
}
void DoubleTreeViewPrintingDialog::printPage( int page, QPainter &painter )
{
debugPlan<pageLayout() );
qreal t, l, b, r; printer().getPageMargins( &l, &t, &r, &b, QPrinter::Point );
debugPlan<masterView()->header();
QHeaderView *sh = m_tree->slaveView()->header();
int length = mh->length() + sh->length();
int height = mh->height() > sh->height() ? mh->height() : sh->height();
QRect hRect = headerRect();
QRect fRect = footerRect();
QRect pageRect = printer().pageRect();
pageRect.moveTo( 0, 0 );
QRect paperRect = printer().paperRect();
QAbstractItemModel *model = m_tree->model();
Q_ASSERT( model != 0 );
debugPlan< length ? 1.0 : (double)pageRect.width() / (double)length;
double sy = 1.0;
painter.scale( sx, sy );
int h = 0;
painter.translate( 0, hRect.height() + gap );
h = hRect.height() + gap;
painter.setPen(Qt::black);
painter.setBrush( Qt::lightGray );
int higestIndex = 0;
int rightpos = 0;
for ( int i = 0; i < mh->count(); ++i ) {
QString text = model->headerData( i, Qt::Horizontal ).toString();
QVariant a = model->headerData( i, Qt::Horizontal, Qt::TextAlignmentRole );
int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter);
if ( ! mh->isSectionHidden( i ) ) {
QRect r = QRect( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height ).adjusted(0, 0, 0, -painter.pen().width());
if (rightpos < r.right()) {
higestIndex = i;
rightpos = r.right();
}
painter.drawRect( r );
// FIXME There is a bug somewhere, the text somehow overwites the rect outline for the first column!
painter.save();
painter.setBrush(QBrush());
painter.drawText( r.adjusted(3, 1, -3, -1), align, text );
painter.drawRect( r );
painter.restore();
}
if ( ! sh->isSectionHidden( i ) ) {
QRect r = QRect( sh->sectionPosition( i ) + mh->length(), 0, sh->sectionSize( i ), height ).adjusted(0, 0, 0, -painter.pen().width());
if (rightpos < r.right()) {
higestIndex = i;
rightpos = r.right();
}
painter.drawRect( r );
painter.drawText( r.adjusted(3, 1, -3, -1), align, text );
}
//debugPlan<isSectionHidden( i )<sectionPosition( i );
}
if ( m_firstRow == -1 || model->rowCount() == 0 ) {
debugPlan<<"No data";
painter.restore();
return;
}
painter.setBrush( QBrush() );
QModelIndex idx = model->index( 0, 0 );
for ( int r = 0; r < m_firstRow && idx.isValid(); ++r ) {
idx = m_tree->masterView()->indexBelow( idx );
}
int numRows = 0;
//debugPlan<count(); ++i ) {
if ( mh->isSectionHidden( i ) && sh->isSectionHidden( i ) ) {
continue;
}
Qt::Edges edges = Qt::BottomEdge | Qt::LeftEdge;
QModelIndex index = model->index( idx.row(), i, idx.parent() );
QString text = model->data( index ).toString();
QVariant a = model->data( index, Qt::TextAlignmentRole );
int align = a.isValid() ? a.toInt() : (int)(Qt::AlignLeft|Qt::AlignVCenter);
if ( ! mh->isSectionHidden( i ) ) {
QRect r( mh->sectionPosition( i ), 0, mh->sectionSize( i ), height );
if (higestIndex == i) {
edges |= Qt::RightEdge;
r.adjust(0, 0, 1, 0);
}
drawRect( painter, r, edges );
painter.drawText( r.adjusted(3, 1, -3, -1) , align, text );
}
if ( ! sh->isSectionHidden( i ) ) {
QRect r( sh->sectionPosition( i ) + mh->length(), 0, sh->sectionSize( i ), height );
if (higestIndex == i) {
edges |= Qt::RightEdge;
r.adjust(0, 0, 1, 0);
}
drawRect( painter, r, edges );
painter.drawText( r.adjusted(3, 1, -3, -1), align, text );
}
}
++numRows;
idx = m_tree->masterView()->indexBelow( idx );
}
painter.restore();
}
/**
* DoubleTreeViewBase is a QSplitter containing two treeviews.
* This makes it possible to keep columns visible in one view when scrolling the other view horizontally.
*/
DoubleTreeViewBase::DoubleTreeViewBase( bool /*mode*/, QWidget *parent )
: QSplitter( parent ),
m_rightview( 0 ),
m_selectionmodel( 0 ),
m_readWrite( false ),
m_mode( false )
{
init();
}
DoubleTreeViewBase::DoubleTreeViewBase( QWidget *parent )
: QSplitter( parent ),
m_rightview( 0 ),
m_selectionmodel( 0 ),
m_mode( false )
{
init();
}
DoubleTreeViewBase::~DoubleTreeViewBase()
{
}
KoPrintJob *DoubleTreeViewBase::createPrintJob( ViewBase *parent )
{
DoubleTreeViewPrintingDialog *dia = new DoubleTreeViewPrintingDialog( parent, this, parent->project() );
dia->printer().setCreator( QString( "Plan %1" ).arg( PLAN_VERSION_STRING ) );
// dia->printer().setFullPage(true); // ignore printer margins
return dia;
}
void DoubleTreeViewBase::slotExpand()
{
m_leftview->slotExpand();
}
void DoubleTreeViewBase::slotCollapse()
{
m_leftview->slotCollapse();
}
void DoubleTreeViewBase::setParentsExpanded( const QModelIndex &idx, bool expanded )
{
//debugPlan<isExpanded( idx )<isExpanded( idx );
QModelIndex p = model()->parent( idx );
QList lst;
while ( p.isValid() ) {
lst << p;
p = model()->parent( p );
}
while ( ! lst.isEmpty() ) {
p = lst.takeLast();
m_leftview->setExpanded( p, expanded );
m_rightview->setExpanded( m_rightview->firstVisibleIndex( p ), expanded ); //HACK: qt can't handle that column 0 is hidden!
//debugPlan<isExpanded( p )<isExpanded( p );
}
}
void DoubleTreeViewBase::init()
{
setOrientation( Qt::Horizontal );
setHandleWidth( 3 );
m_leftview = new TreeViewBase(this);
m_leftview->setObjectName("Left view");
m_leftview->setHandleDrag(false);
addWidget( m_leftview );
setStretchFactor( 0, 1 );
m_rightview = new TreeViewBase(this);
m_rightview->setObjectName("Right view");
m_rightview->setHandleDrag(false);
addWidget( m_rightview );
setStretchFactor( 1, 1 );
m_leftview->setTreePosition(-1); // always visual index 0
connect( m_leftview, &TreeViewBase::contextMenuRequested, this, &DoubleTreeViewBase::contextMenuRequested );
connect( m_leftview, &TreeViewBase::headerContextMenuRequested, this, &DoubleTreeViewBase::slotLeftHeaderContextMenuRequested );
connect( m_rightview, &TreeViewBase::contextMenuRequested, this, &DoubleTreeViewBase::contextMenuRequested );
connect( m_rightview, &TreeViewBase::headerContextMenuRequested, this, &DoubleTreeViewBase::slotRightHeaderContextMenuRequested );
connect( m_leftview->verticalScrollBar(), &QAbstractSlider::valueChanged, m_rightview->verticalScrollBar(), &QAbstractSlider::setValue );
connect( m_rightview->verticalScrollBar(), &QAbstractSlider::valueChanged, m_leftview->verticalScrollBar(), &QAbstractSlider::setValue );
connect( m_leftview, &TreeViewBase::moveAfterLastColumn, this, &DoubleTreeViewBase::slotToRightView );
connect( m_rightview, &TreeViewBase::moveBeforeFirstColumn, this, &DoubleTreeViewBase::slotToLeftView );
connect( m_leftview, &TreeViewBase::editAfterLastColumn, this, &DoubleTreeViewBase::slotEditToRightView );
connect( m_rightview, &TreeViewBase::editBeforeFirstColumn, this, &DoubleTreeViewBase::slotEditToLeftView );
connect( m_leftview, &QTreeView::expanded, m_rightview, &QTreeView::expand );
connect( m_leftview, &QTreeView::collapsed, m_rightview, &QTreeView::collapse );
connect( m_rightview, &QTreeView::expanded, m_leftview, &QTreeView::expand );
connect( m_rightview, &QTreeView::collapsed, m_leftview, &QTreeView::collapse );
connect( m_leftview, &TreeViewBase::dropAllowed, this, &DoubleTreeViewBase::dropAllowed );
connect( m_rightview, &TreeViewBase::dropAllowed, this, &DoubleTreeViewBase::dropAllowed );
m_actionSplitView = new QAction(koIcon("view-split-left-right"), QString(), this);
setViewSplitMode( true );
connect( m_leftview->header(), &QHeaderView::sortIndicatorChanged, this, &DoubleTreeViewBase::slotLeftSortIndicatorChanged );
connect( m_rightview->header(), &QHeaderView::sortIndicatorChanged, this, &DoubleTreeViewBase::slotRightSortIndicatorChanged );
}
void DoubleTreeViewBase::slotLeftSortIndicatorChanged( int logicalIndex, Qt::SortOrder /*order*/ )
{
QSortFilterProxyModel *sf = qobject_cast( model() );
if ( sf ) {
ItemModelBase *m = m_rightview->itemModel();
if ( m ) {
sf->setSortRole( m->sortRole( logicalIndex ) );
}
}
m_leftview->header()->setSortIndicatorShown( true );
// sorting controlled by left treeview, turn right off
m_rightview->header()->setSortIndicatorShown( false );
}
void DoubleTreeViewBase::slotRightSortIndicatorChanged( int logicalIndex, Qt::SortOrder /*order*/ )
{
QSortFilterProxyModel *sf = qobject_cast( model() );
if ( sf ) {
ItemModelBase *m = m_rightview->itemModel();
if ( m ) {
sf->setSortRole( m->sortRole( logicalIndex ) );
}
}
m_rightview->header()->setSortIndicatorShown( true );
// sorting controlled by right treeview, turn left off
m_leftview->header()->setSortIndicatorShown( false );
}
QList DoubleTreeViewBase::expandColumnList( const QList &lst ) const
{
QList mlst = lst;
if ( ! mlst.isEmpty() ) {
int v = 0;
if ( mlst.last() == -1 && mlst.count() > 1 ) {
v = mlst[ mlst.count() - 2 ] + 1;
mlst.removeLast();
}
for ( int c = v; c < model()->columnCount(); ++c ) {
mlst << c;
}
}
return mlst;
}
void DoubleTreeViewBase::hideColumns( TreeViewBase *view, const QList &list )
{
view->setColumnsHidden( list );
}
void DoubleTreeViewBase::hideColumns( const QList &masterList, const QList &slaveList )
{
m_leftview->setColumnsHidden( masterList );
m_rightview->setColumnsHidden( slaveList );
if ( m_rightview->isHidden() ) {
QList mlst = expandColumnList( masterList );
QList slst = expandColumnList( slaveList );
QList lst;
for ( int c = 0; c < model()->columnCount(); ++c ) {
// only hide columns hidden in *both* views
//debugPlan<= 0) && (slst.indexOf( c ) >= 0) ) {
lst << c;
}
}
//debugPlan<setColumnsHidden( lst );
} else {
setStretchFactors();
}
}
void DoubleTreeViewBase::slotToRightView( const QModelIndex &index )
{
//debugPlan<firstColumn( index.row(), model()->parent( index ) );
m_rightview->setFocus();
if ( nxt.isValid() ) {
m_selectionmodel->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate );
}
}
void DoubleTreeViewBase::slotToLeftView( const QModelIndex &index )
{
//debugPlan<lastColumn( index.row(), model()->parent( index ) );
m_leftview->setFocus();
if ( prv.isValid() ) {
m_selectionmodel->setCurrentIndex( prv, QItemSelectionModel::NoUpdate );
}
}
void DoubleTreeViewBase::slotEditToRightView( const QModelIndex &index )
{
//debugPlan<isHidden() ) {
return;
}
m_rightview->setFocus();
QModelIndex nxt = m_rightview->firstEditable( index.row(), model()->parent ( index ) );
if ( nxt.isValid() && ( model()->flags( nxt ) & Qt::ItemIsEditable ) ) {
m_selectionmodel->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate );
m_rightview->edit( nxt );
} else {
slotToRightView( index );
}
}
void DoubleTreeViewBase::slotEditToLeftView( const QModelIndex &index )
{
//debugPlan<isHidden() ) {
return;
}
m_leftview->setFocus();
QModelIndex nxt = m_leftview->lastEditable( index.row(), model()->parent ( index ) );
if ( nxt.isValid() && ( model()->flags( nxt ) & Qt::ItemIsEditable ) ) {
m_selectionmodel->setCurrentIndex( nxt, QItemSelectionModel::NoUpdate );
m_leftview->edit( nxt );
} else {
slotToLeftView( index );
}
}
void DoubleTreeViewBase::setReadWrite( bool rw )
{
m_readWrite = rw;
m_leftview->setReadWrite( rw );
m_rightview->setReadWrite( rw );
}
void DoubleTreeViewBase::closePersistentEditor( const QModelIndex &index )
{
m_leftview->closePersistentEditor( index );
m_rightview->closePersistentEditor( index );
}
void DoubleTreeViewBase::setModel( QAbstractItemModel *model )
{
m_leftview->setModel( model );
m_rightview->setModel( model );
if ( m_selectionmodel ) {
disconnect( m_selectionmodel, &QItemSelectionModel::selectionChanged, this, &DoubleTreeViewBase::slotSelectionChanged );
disconnect( m_selectionmodel, &QItemSelectionModel::currentChanged, this, &DoubleTreeViewBase::currentChanged );
}
m_selectionmodel = m_leftview->selectionModel();
m_rightview->setSelectionModel( m_selectionmodel );
connect( m_selectionmodel, &QItemSelectionModel::selectionChanged, this, &DoubleTreeViewBase::slotSelectionChanged );
connect( m_selectionmodel, &QItemSelectionModel::currentChanged, this, &DoubleTreeViewBase::currentChanged );
setReadWrite( m_readWrite );
}
QAbstractItemModel *DoubleTreeViewBase::model() const
{
return m_leftview->model();
}
void DoubleTreeViewBase::slotSelectionChanged( const QItemSelection &sel, const QItemSelection & )
{
emit selectionChanged( sel.indexes() );
}
void DoubleTreeViewBase::setSelectionModel( QItemSelectionModel *model )
{
m_leftview->setSelectionModel( model );
m_rightview->setSelectionModel( model );
}
void DoubleTreeViewBase::setSelectionMode( QAbstractItemView::SelectionMode mode )
{
m_leftview->setSelectionMode( mode );
m_rightview->setSelectionMode( mode );
}
void DoubleTreeViewBase::setSelectionBehavior( QAbstractItemView::SelectionBehavior mode )
{
m_leftview->setSelectionBehavior( mode );
m_rightview->setSelectionBehavior( mode );
}
void DoubleTreeViewBase::setItemDelegateForColumn( int col, QAbstractItemDelegate * delegate )
{
m_leftview->setItemDelegateForColumn( col, delegate );
m_rightview->setItemDelegateForColumn( col, delegate );
}
void DoubleTreeViewBase::createItemDelegates( ItemModelBase *model )
{
m_leftview->createItemDelegates( model );
m_rightview->createItemDelegates( model );
}
void DoubleTreeViewBase::setEditTriggers( QAbstractItemView::EditTriggers mode )
{
m_leftview->setEditTriggers( mode );
m_rightview->setEditTriggers( mode );
}
QAbstractItemView::EditTriggers DoubleTreeViewBase::editTriggers() const
{
return m_leftview->editTriggers();
}
void DoubleTreeViewBase::setStretchLastSection( bool mode )
{
m_rightview->header()->setStretchLastSection( mode );
if ( m_rightview->isHidden() ) {
m_leftview->header()->setStretchLastSection( mode );
}
}
void DoubleTreeViewBase::edit( const QModelIndex &index )
{
if ( ! m_leftview->isColumnHidden( index.column() ) ) {
m_leftview->edit( index );
} else if ( ! m_rightview->isHidden() && ! m_rightview->isColumnHidden( index.column() ) ) {
m_rightview->edit( index );
}
}
void DoubleTreeViewBase::setDragDropMode( QAbstractItemView::DragDropMode mode )
{
m_leftview->setDragDropMode( mode );
m_rightview->setDragDropMode( mode );
}
void DoubleTreeViewBase::setDragDropOverwriteMode( bool mode )
{
m_leftview->setDragDropOverwriteMode( mode );
m_rightview->setDragDropOverwriteMode( mode );
}
void DoubleTreeViewBase::setDropIndicatorShown( bool mode )
{
m_leftview->setDropIndicatorShown( mode );
m_rightview->setDropIndicatorShown( mode );
}
void DoubleTreeViewBase::setDragEnabled ( bool mode )
{
m_leftview->setDragEnabled( mode );
m_rightview->setDragEnabled( mode );
}
void DoubleTreeViewBase::setAcceptDrops( bool mode )
{
m_leftview->setAcceptDrops( mode );
m_rightview->setAcceptDrops( mode );
}
void DoubleTreeViewBase::setAcceptDropsOnView( bool mode )
{
m_leftview->setAcceptDropsOnView( mode );
m_rightview->setAcceptDropsOnView( mode );
}
void DoubleTreeViewBase::setDefaultDropAction( Qt::DropAction action )
{
m_leftview->setDefaultDropAction( action );
m_rightview->setDefaultDropAction( action );
}
void DoubleTreeViewBase::slotRightHeaderContextMenuRequested( const QPoint &pos )
{
//debugPlan;
emit slaveHeaderContextMenuRequested( pos );
emit headerContextMenuRequested( pos );
}
void DoubleTreeViewBase::slotLeftHeaderContextMenuRequested( const QPoint &pos )
{
//debugPlan;
emit masterHeaderContextMenuRequested( pos );
emit headerContextMenuRequested( pos );
}
void DoubleTreeViewBase::setStretchFactors()
{
int lc = m_leftview->header()->count() - m_leftview->header()->hiddenSectionCount();
int rc = m_rightview->header()->count() - m_rightview->header()->hiddenSectionCount();
setStretchFactor( indexOf( m_rightview ), qMax( 1, qMin( 4, rc / qMax( 1, lc ) ) ) );
//debugPlan<loadContext(map, slave, false);
}
KoXmlElement master = element.namedItem("master").toElement();
if (!master.isNull()) {
m_leftview->loadContext(map, master);
}
return true;
}
void DoubleTreeViewBase::saveContext( const QMetaEnum &map, QDomElement &element ) const
{
QDomElement master = element.ownerDocument().createElement( "master" );
element.appendChild(master);
m_leftview->saveContext(map, master);
QDomElement slave = element.ownerDocument().createElement( "slave" );
element.appendChild(slave);
if (m_rightview->isHidden()) {
slave.setAttribute("hidden", "true");
}
m_rightview->saveContext(map, slave, false);
}
void DoubleTreeViewBase::setViewSplitMode( bool split )
{
if ( split ) {
m_actionSplitView->setText( i18n( "Unsplit View" ) );
m_actionSplitView->setIcon(koIcon("view-close"));
} else {
m_actionSplitView->setText( i18n( "Split View" ) );
m_actionSplitView->setIcon(koIcon("view-split-left-right"));
}
if ( m_mode == split ) {
return;
}
m_mode = split;
if ( split ) {
m_leftview->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
m_leftview->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
if ( model() ) {
m_rightview->setColumnHidden( 0, true );
m_leftview->resizeColumnToContents( 0 );
for ( int c = 1; c < m_rightview->model()->columnCount(); ++c ) {
if ( m_leftview->isColumnHidden( c ) ) {
m_rightview->setColumnHidden( c, true );
} else {
m_rightview->setColumnHidden( c, false );
m_rightview->mapToSection( c, m_leftview->section( c ) );
m_leftview->setColumnHidden( c, true );
m_rightview->resizeColumnToContents( c );
}
}
}
m_rightview->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
m_rightview->show();
} else {
m_rightview->hide();
if ( model() ) {
int offset = m_rightview->isColumnHidden( 0 ) ? 1 : 0;
for ( int c = 0; c < model()->columnCount(); ++c ) {
if ( ! m_rightview->isColumnHidden( c ) ) {
m_leftview->setColumnHidden( c, false );
m_leftview->mapToSection( c, m_rightview->section( c ) + offset );
m_leftview->resizeColumnToContents( c );
}
}
}
m_leftview->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
m_leftview->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
}
}
void DoubleTreeViewBase::setRootIsDecorated ( bool show )
{
m_leftview->setRootIsDecorated( show );
m_rightview->setRootIsDecorated( show );
}
QModelIndex DoubleTreeViewBase::indexAt( const QPoint &pos ) const
{
QModelIndex idx = m_leftview->indexAt( pos );
if ( ! idx.isValid() ) {
idx = m_rightview->indexAt( pos );
}
return idx;
}
void DoubleTreeViewBase::setContextMenuIndex(const QModelIndex &idx)
{
m_leftview->setContextMenuIndex(idx);
m_rightview->setContextMenuIndex(idx);
}
void sort(QTreeView *view, QModelIndexList &list)
{
QModelIndexList i; i << list.takeFirst();
for (QModelIndex idx = view->indexAbove(i.first()); idx.isValid() && !list.isEmpty(); idx = view->indexAbove(idx)) {
if (list.contains(idx)) {
i.prepend(idx);
list.removeOne(idx);
}
}
for (QModelIndex idx = view->indexBelow(i.last()); idx.isValid() && !list.isEmpty(); idx = view->indexBelow(idx)) {
if (list.contains(idx)) {
i.append(idx);
list.removeOne(idx);
}
}
list = i;
}
QMimeData *DoubleTreeViewBase::mimeData() const
{
QModelIndexList rows = selectionModel()->selectedRows();
sort(m_leftview, rows);
if (rows.isEmpty()) {
debugPlan<<"No rows selected";
return 0;
}
QList columns;;
columns = m_leftview->visualColumns() + m_rightview->visualColumns();
QModelIndexList indexes;
for (int r = 0; r < rows.count(); ++r) {
int row = rows.at(r).row();
const QModelIndex &parent = rows.at(r).parent();
for (int i = 0; i < columns.count(); ++i) {
indexes << model()->index(row, columns.at(i), parent);
}
}
return model()->mimeData(indexes);
}
void DoubleTreeViewBase::handleDrag(Qt::DropActions supportedActions, Qt::DropAction defaultDropAction)
{
QMimeData *data = mimeData();
if (!data) {
debugPlan<<"No mimedata";
return;
}
QDrag *drag = new QDrag(this);
drag->setPixmap(m_leftview->dragPixmap());
drag->setMimeData(data);
Qt::DropAction a = drag->exec(supportedActions, defaultDropAction);
}
void DoubleTreeViewBase::setDragPixmap(const QPixmap &pixmap)
{
m_leftview->setDragPixmap(pixmap);
}
QPixmap DoubleTreeViewBase::dragPixmap() const
{
return m_leftview->dragPixmap();
}
void DoubleTreeViewBase::editCopy()
{
QMimeData *data = mimeData();
if (!data) {
debugPlan<<"No mimedata";
return;
}
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setMimeData(data);
}
void DoubleTreeViewBase::editPaste()
{
}
} // namespace KPlato
diff --git a/src/libs/ui/kptviewbase.h b/src/libs/ui/kptviewbase.h
index 25e3f442..85a23c16 100644
--- a/src/libs/ui/kptviewbase.h
+++ b/src/libs/ui/kptviewbase.h
@@ -1,726 +1,728 @@
/* This file is part of the KDE project
Copyright (C) 2006 -2010 Dag Andersen
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KPTVIEWBASE_H
#define KPTVIEWBASE_H
#include "planui_export.h"
#include "kptitemmodelbase.h"
#include "ui_kptprintingheaderfooter.h"
#include
#include
#include