diff --git a/examples/DrawIntoPainter/framewidget.h b/examples/DrawIntoPainter/framewidget.h
index b5ca671..5623150 100644
--- a/examples/DrawIntoPainter/framewidget.h
+++ b/examples/DrawIntoPainter/framewidget.h
@@ -1,47 +1,47 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KD Chart library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef FRAMEWIDGET_H
#define FRAMEWIDGET_H
#include
namespace KChart {
class Chart;
}
class FrameWidget : public QWidget
{
Q_OBJECT
public:
- explicit FrameWidget( QWidget * parent = 0, Qt::WindowFlags f = 0 );
+ explicit FrameWidget( QWidget * parent = 0, Qt::WindowFlags f = Qt::WindowFlags() );
void paintEvent( QPaintEvent* ) Q_DECL_OVERRIDE;
void setChart( KChart::Chart* chart );
private:
KChart::Chart* mChart;
};
#endif /* FRAMEWIDGET_H */
diff --git a/examples/Gantt/legend_example/entrydialog.h b/examples/Gantt/legend_example/entrydialog.h
index d0f1522..10d9a3a 100644
--- a/examples/Gantt/legend_example/entrydialog.h
+++ b/examples/Gantt/legend_example/entrydialog.h
@@ -1,68 +1,68 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef ENTRYDIALOG_H
#define ENTRYDIALOG_H
#include
#include
#include
QT_BEGIN_NAMESPACE
class QAbstractItemModel;
namespace Ui {
class EntryDialog;
}
QT_END_NAMESPACE
namespace KGantt {
class ConstraintModel;
}
class EntryDialog : public QDialog {
Q_OBJECT
public:
- explicit EntryDialog( const QAbstractItemModel* model, QWidget* parent = 0, Qt::WindowFlags f = 0 );
+ explicit EntryDialog( const QAbstractItemModel* model, QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags() );
void initFrom( const QModelIndex& index, const KGantt::ConstraintModel* constraintModel );
QString name() const;
int type() const;
QDateTime startDate() const;
QDateTime endDate() const;
int completion() const;
bool readOnly() const;
QModelIndex depends() const;
QString legend() const;
private slots:
void updateEndDate( const QDateTime& startDate );
void disableEditing( bool disable );
void typeChanged( int index );
private:
void init();
void addDependItem( const QAbstractItemModel* model, const QModelIndex& index, int indent = 0 );
QList indexList;
const QAbstractItemModel* model;
Ui::EntryDialog* ui;
};
#endif /* ENTRYDIALOG_H */
diff --git a/examples/Gantt/legend_example/mainwindow.h b/examples/Gantt/legend_example/mainwindow.h
index 8882da5..b305095 100644
--- a/examples/Gantt/legend_example/mainwindow.h
+++ b/examples/Gantt/legend_example/mainwindow.h
@@ -1,86 +1,86 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
QT_BEGIN_NAMESPACE
class QStandardItemModel;
class QCloseEvent;
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
namespace KGantt {
class ConstraintModel;
class DateTimeGrid;
class Legend;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
- explicit MainWindow( QWidget * parent = 0, Qt::WindowFlags flags = 0 );
+ explicit MainWindow( QWidget * parent = 0, Qt::WindowFlags flags = Qt::WindowFlags() );
virtual ~MainWindow();
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
private slots:
void addNewEntry();
void removeEntry();
void showContextMenu( const QPoint& );
void enableActions( const QItemSelection& selected );
void zoomIn();
void zoomOut();
void zoomFit();
void scaleAuto();
void scaleHour();
void scaleDay();
void scaleWeek();
void scaleMonth();
private:
void initModel();
void initActions();
void initItemDelegate();
void initGrid();
void setReadOnly( const QModelIndex& index, bool readOnly );
void addConstraint( const QModelIndex& index1, const QModelIndex& index2 );
QStandardItemModel* model;
KGantt::ConstraintModel* constraintModel;
KGantt::DateTimeGrid* grid;
KGantt::Legend* smallLegend;
KGantt::Legend* detailedLegend;
QAction* newEntryAction;
QAction* removeEntryAction;
QAction* zoomInAction;
QAction* zoomOutAction;
QAction* zoomFitAction;
Ui::MainWindow* ui;
};
#endif /* MAINWINDOW_H */
diff --git a/qtests/DrawIntoPainter/framewidget.h b/qtests/DrawIntoPainter/framewidget.h
index b5ca671..5623150 100644
--- a/qtests/DrawIntoPainter/framewidget.h
+++ b/qtests/DrawIntoPainter/framewidget.h
@@ -1,47 +1,47 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KD Chart library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef FRAMEWIDGET_H
#define FRAMEWIDGET_H
#include
namespace KChart {
class Chart;
}
class FrameWidget : public QWidget
{
Q_OBJECT
public:
- explicit FrameWidget( QWidget * parent = 0, Qt::WindowFlags f = 0 );
+ explicit FrameWidget( QWidget * parent = 0, Qt::WindowFlags f = Qt::WindowFlags() );
void paintEvent( QPaintEvent* ) Q_DECL_OVERRIDE;
void setChart( KChart::Chart* chart );
private:
KChart::Chart* mChart;
};
#endif /* FRAMEWIDGET_H */
diff --git a/src/KChart/KChartChart.cpp b/src/KChart/KChartChart.cpp
index e14a823..0d8c39c 100644
--- a/src/KChart/KChartChart.cpp
+++ b/src/KChart/KChartChart.cpp
@@ -1,1805 +1,1805 @@
/*
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KD Chart library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "KChartChart.h"
#include "KChartChart_p.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KChartCartesianCoordinatePlane.h"
#include "KChartAbstractCartesianDiagram.h"
#include "KChartHeaderFooter.h"
#include "KChartEnums.h"
#include "KChartLegend.h"
#include "KChartLayoutItems.h"
#include
#include
#include "KChartPainterSaver_p.h"
#include "KChartPrintingParameters.h"
#include
#if defined KDAB_EVAL
#include "../evaldialog/evaldialog.h"
#endif
#if 0
// dumpLayoutTree dumps a QLayout tree in a hopefully easy to read format to stderr - feel free to
// use, improve and extend; it is very useful for looking at any layout problem.
#include
// this is this different from both QRect::isEmpty() and QRect::isNull() for "wrong" QRects,
// i.e. those where topLeft() is actually below and / or right of bottomRight().
static bool isZeroArea(const QRect &r)
{
return !r.width() || !r.height();
}
static QString lineProlog(int nestingDepth, int lineno)
{
QString numbering(QString::number(lineno).rightJustified(5).append(QChar::fromAscii(':')));
QString indent(nestingDepth * 4, QLatin1Char(' '));
return numbering + indent;
}
static void dumpLayoutTreeRecurse(QLayout *l, int *counter, int depth)
{
const QLatin1String colorOn(isZeroArea(l->geometry()) ? "\033[0m" : "\033[32m");
const QLatin1String colorOff("\033[0m");
QString prolog = lineProlog(depth, *counter);
(*counter)++;
qDebug() << colorOn + prolog << l->metaObject()->className() << l->geometry()
<< "hint" << l->sizeHint()
<< l->hasHeightForWidth() << "min" << l->minimumSize()
<< "max" << l->maximumSize()
<< l->expandingDirections() << l->alignment()
<< colorOff;
for (int i = 0; i < l->count(); i++) {
QLayoutItem *child = l->itemAt(i);
if (QLayout *childL = child->layout()) {
dumpLayoutTreeRecurse(childL, counter, depth + 1);
} else {
// The isZeroArea check culls usually largely useless output - you might want to remove it in
// some debugging situations. Add a boolean parameter to this and dumpLayoutTree() if you do.
if (!isZeroArea(child->geometry())) {
prolog = lineProlog(depth + 1, *counter);
(*counter)++;
qDebug() << colorOn + prolog << typeid(*child).name() << child->geometry()
<< "hint" << child->sizeHint()
<< child->hasHeightForWidth() << "min" << child->minimumSize()
<< "max" << child->maximumSize()
<< child->expandingDirections() << child->alignment()
<< colorOff;
}
}
}
}
static void dumpLayoutTree(QLayout *l)
{
int counter = 0;
dumpLayoutTreeRecurse(l, &counter, 0);
}
#endif
static const Qt::Alignment s_gridAlignments[ 3 ][ 3 ] = { // [ row ][ column ]
{ Qt::AlignTop | Qt::AlignLeft, Qt::AlignTop | Qt::AlignHCenter, Qt::AlignTop | Qt::AlignRight },
{ Qt::AlignVCenter | Qt::AlignLeft, Qt::AlignVCenter | Qt::AlignHCenter, Qt::AlignVCenter | Qt::AlignRight },
{ Qt::AlignBottom | Qt::AlignLeft, Qt::AlignBottom | Qt::AlignHCenter, Qt::AlignBottom | Qt::AlignRight }
};
static void getRowAndColumnForPosition(KChartEnums::PositionValue pos, int* row, int* column)
{
switch ( pos ) {
case KChartEnums::PositionNorthWest: *row = 0; *column = 0;
break;
case KChartEnums::PositionNorth: *row = 0; *column = 1;
break;
case KChartEnums::PositionNorthEast: *row = 0; *column = 2;
break;
case KChartEnums::PositionEast: *row = 1; *column = 2;
break;
case KChartEnums::PositionSouthEast: *row = 2; *column = 2;
break;
case KChartEnums::PositionSouth: *row = 2; *column = 1;
break;
case KChartEnums::PositionSouthWest: *row = 2; *column = 0;
break;
case KChartEnums::PositionWest: *row = 1; *column = 0;
break;
case KChartEnums::PositionCenter: *row = 1; *column = 1;
break;
default: *row = -1; *column = -1;
break;
}
}
using namespace KChart;
// Layout widgets even if they are not visible (that's why isEmpty() is overridden) - at least that
// was the original reason...
class MyWidgetItem : public QWidgetItem
{
public:
- explicit MyWidgetItem(QWidget *w, Qt::Alignment alignment = 0)
+ explicit MyWidgetItem(QWidget *w, Qt::Alignment alignment = Qt::Alignment())
: QWidgetItem( w )
{
setAlignment( alignment );
}
// All of the methods are reimplemented from QWidgetItem, and work around some oddity in QLayout and / or
// KD Chart - I forgot the details between writing this code as an experiment and committing it, very
// sorry about that!
// Feel free to comment out any of them and then try the line-breaking feature in horizontal legends in
// the Legends/Advanced example. It will not work well in various ways - won't get enough space and look
// very broken, will inhibit resizing the window etc.
QSize sizeHint() const Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
return w->sizeHint();
}
QSize minimumSize() const Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
return w->minimumSize();
}
QSize maximumSize() const Q_DECL_OVERRIDE
{
// Not just passing on w->maximumSize() fixes that the size policy of Legend is disregarded, making
// Legend take all available space, which makes both the Legend internal layout and the overall
// layout of chart + legend look bad. QWidget::maximumSize() is not a virtual method, it's a
// property, so "overriding" that one would be even uglier, and prevent user-set property
// values from doing anything.
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
QSize ret = w->maximumSize();
const QSize hint = w->sizeHint();
const QSizePolicy::Policy hPolicy = w->sizePolicy().horizontalPolicy();
if (hPolicy == QSizePolicy::Fixed || hPolicy == QSizePolicy::Maximum) {
ret.rwidth() = hint.width();
}
const QSizePolicy::Policy vPolicy = w->sizePolicy().verticalPolicy();
if (vPolicy == QSizePolicy::Fixed || vPolicy == QSizePolicy::Maximum) {
ret.rheight() = hint.height();
}
return ret;
}
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
if ( isEmpty() ) {
return Qt::Orientations(0);
}
Qt::Orientations e = w->sizePolicy().expandingDirections();
return e;
}
void setGeometry(const QRect &g) Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
w->setGeometry(g);
}
QRect geometry() const Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
return w->geometry();
}
bool hasHeightForWidth() const Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
bool ret = !isEmpty() &&
qobject_cast< Legend* >( w )->hasHeightForWidth();
return ret;
}
int heightForWidth( int width ) const Q_DECL_OVERRIDE
{
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
int ret = w->heightForWidth( width );
return ret;
}
bool isEmpty() const Q_DECL_OVERRIDE {
QWidget* w = const_cast< MyWidgetItem * >( this )->widget();
// legend->hide() should indeed hide the legend,
// but a legend in a chart that hasn't been shown yet isn't hidden
// (as can happen when using Chart::paint() without showing the chart)
return w->isHidden() && w->testAttribute( Qt::WA_WState_ExplicitShowHide );
}
};
// When "abusing" QLayouts to lay out items with different geometry from the backing QWidgets,
// some manual work is required to correctly update all the sublayouts.
// This is because all the convenient ways to deal with QLayouts assume QWidgets somewhere.
// What this does is somewhat similar to QLayout::activate(), but it never refers to the parent
// QWidget which has the wrong geometry.
static void invalidateLayoutTree( QLayoutItem *item )
{
QLayout *layout = item->layout();
if ( layout ) {
const int count = layout->count();
for ( int i = 0; i < count; i++ ) {
invalidateLayoutTree( layout->itemAt( i ) );
}
}
item->invalidate();
}
void Chart::Private::slotUnregisterDestroyedLegend( Legend *l )
{
chart->takeLegend( l );
}
void Chart::Private::slotUnregisterDestroyedHeaderFooter( HeaderFooter* hf )
{
chart->takeHeaderFooter( hf );
}
void Chart::Private::slotUnregisterDestroyedPlane( AbstractCoordinatePlane* plane )
{
coordinatePlanes.removeAll( plane );
Q_FOREACH ( AbstractCoordinatePlane* p, coordinatePlanes ) {
if ( p->referenceCoordinatePlane() == plane) {
p->setReferenceCoordinatePlane( 0 );
}
}
plane->layoutPlanes();
}
Chart::Private::Private( Chart* chart_ )
: chart( chart_ )
, useNewLayoutSystem( false )
, layout( 0 )
, vLayout( 0 )
, planesLayout( 0 )
, headerLayout( 0 )
, footerLayout( 0 )
, dataAndLegendLayout( 0 )
, leftOuterSpacer( 0 )
, rightOuterSpacer( 0 )
, topOuterSpacer( 0 )
, bottomOuterSpacer( 0 )
, isFloatingLegendsLayoutDirty( true )
, isPlanesLayoutDirty( true )
, globalLeadingLeft( 0 )
, globalLeadingRight( 0 )
, globalLeadingTop( 0 )
, globalLeadingBottom( 0 )
{
for ( int row = 0; row < 3; ++row ) {
for ( int column = 0; column < 3; ++column ) {
for ( int i = 0; i < 2; i++ ) {
innerHdFtLayouts[ i ][ row ][ column ] = 0;
}
}
}
}
Chart::Private::~Private()
{
}
enum VisitorState{ Visited, Unknown };
struct ConnectedComponentsComparator{
bool operator()( const LayoutGraphNode *lhs, const LayoutGraphNode *rhs ) const
{
return lhs->priority < rhs->priority;
}
};
static QVector< LayoutGraphNode* > getPrioritySortedConnectedComponents( QVector< LayoutGraphNode* > &nodeList )
{
QVector< LayoutGraphNode* >connectedComponents;
QHash< LayoutGraphNode*, VisitorState > visitedComponents;
Q_FOREACH ( LayoutGraphNode* node, nodeList )
visitedComponents[ node ] = Unknown;
for ( int i = 0; i < nodeList.size(); ++i )
{
LayoutGraphNode *curNode = nodeList[ i ];
LayoutGraphNode *representativeNode = curNode;
if ( visitedComponents[ curNode ] != Visited )
{
QStack< LayoutGraphNode* > stack;
stack.push( curNode );
while ( !stack.isEmpty() )
{
curNode = stack.pop();
Q_ASSERT( visitedComponents[ curNode ] != Visited );
visitedComponents[ curNode ] = Visited;
if ( curNode->bottomSuccesor && visitedComponents[ curNode->bottomSuccesor ] != Visited )
stack.push( curNode->bottomSuccesor );
if ( curNode->leftSuccesor && visitedComponents[ curNode->leftSuccesor ] != Visited )
stack.push( curNode->leftSuccesor );
if ( curNode->sharedSuccesor && visitedComponents[ curNode->sharedSuccesor ] != Visited )
stack.push( curNode->sharedSuccesor );
if ( curNode->priority < representativeNode->priority )
representativeNode = curNode;
}
connectedComponents.append( representativeNode );
}
}
std::sort( connectedComponents.begin(), connectedComponents.end(), ConnectedComponentsComparator() );
return connectedComponents;
}
struct PriorityComparator{
public:
PriorityComparator( QHash< AbstractCoordinatePlane*, LayoutGraphNode* > mapping )
: m_mapping( mapping )
{}
bool operator() ( AbstractCoordinatePlane *lhs, AbstractCoordinatePlane *rhs ) const
{
const LayoutGraphNode *lhsNode = m_mapping[ lhs ];
Q_ASSERT( lhsNode );
const LayoutGraphNode *rhsNode = m_mapping[ rhs ];
Q_ASSERT( rhsNode );
return lhsNode->priority < rhsNode->priority;
}
const QHash< AbstractCoordinatePlane*, LayoutGraphNode* > m_mapping;
};
void checkExistingAxes( LayoutGraphNode* node )
{
if ( node && node->diagramPlane && node->diagramPlane->diagram() )
{
AbstractCartesianDiagram *diag = qobject_cast< AbstractCartesianDiagram* >( node->diagramPlane->diagram() );
if ( diag )
{
Q_FOREACH( const CartesianAxis* axis, diag->axes() )
{
switch ( axis->position() )
{
case( CartesianAxis::Top ):
node->topAxesLayout = true;
break;
case( CartesianAxis::Bottom ):
node->bottomAxesLayout = true;
break;
case( CartesianAxis::Left ):
node->leftAxesLayout = true;
break;
case( CartesianAxis::Right ):
node->rightAxesLayout = true;
break;
}
}
}
}
}
static void mergeNodeAxisInformation( LayoutGraphNode* lhs, LayoutGraphNode* rhs )
{
lhs->topAxesLayout |= rhs->topAxesLayout;
rhs->topAxesLayout = lhs->topAxesLayout;
lhs->bottomAxesLayout |= rhs->bottomAxesLayout;
rhs->bottomAxesLayout = lhs->bottomAxesLayout;
lhs->leftAxesLayout |= rhs->leftAxesLayout;
rhs->leftAxesLayout = lhs->leftAxesLayout;
lhs->rightAxesLayout |= rhs->rightAxesLayout;
rhs->rightAxesLayout = lhs->rightAxesLayout;
}
static CoordinatePlaneList findSharingAxisDiagrams( AbstractCoordinatePlane* plane,
const CoordinatePlaneList& list,
Chart::Private::AxisType type,
QVector< CartesianAxis* >* sharedAxes )
{
if ( !plane || !plane->diagram() )
return CoordinatePlaneList();
Q_ASSERT( plane );
Q_ASSERT( plane->diagram() );
CoordinatePlaneList result;
AbstractCartesianDiagram* diagram = qobject_cast< AbstractCartesianDiagram* >( plane->diagram() );
if ( !diagram )
return CoordinatePlaneList();
QList< CartesianAxis* > axes;
Q_FOREACH( CartesianAxis* axis, diagram->axes() ) {
if ( ( type == Chart::Private::Ordinate &&
( axis->position() == CartesianAxis::Left || axis->position() == CartesianAxis::Right ) )
||
( type == Chart::Private::Abscissa &&
( axis->position() == CartesianAxis::Top || axis->position() == CartesianAxis::Bottom ) ) ) {
axes.append( axis );
}
}
Q_FOREACH( AbstractCoordinatePlane *curPlane, list )
{
AbstractCartesianDiagram* diagram =
qobject_cast< AbstractCartesianDiagram* > ( curPlane->diagram() );
if ( !diagram )
continue;
Q_FOREACH( CartesianAxis* curSearchedAxis, axes )
{
Q_FOREACH( CartesianAxis* curAxis, diagram->axes() )
{
if ( curSearchedAxis == curAxis )
{
result.append( curPlane );
if ( !sharedAxes->contains( curSearchedAxis ) )
sharedAxes->append( curSearchedAxis );
}
}
}
}
return result;
}
/**
* this method determines the needed layout of the graph
* taking care of the sharing problematic
* its NOT allowed to have a diagram that shares
* more than one axis in the same direction
*/
QVector< LayoutGraphNode* > Chart::Private::buildPlaneLayoutGraph()
{
QHash< AbstractCoordinatePlane*, LayoutGraphNode* > planeNodeMapping;
QVector< LayoutGraphNode* > allNodes;
// create all nodes and a mapping between plane and nodes
Q_FOREACH( AbstractCoordinatePlane* curPlane, coordinatePlanes )
{
if ( curPlane->diagram() )
{
allNodes.append( new LayoutGraphNode );
allNodes[ allNodes.size() - 1 ]->diagramPlane = curPlane;
allNodes[ allNodes.size() - 1 ]->priority = allNodes.size();
checkExistingAxes( allNodes[ allNodes.size() - 1 ] );
planeNodeMapping[ curPlane ] = allNodes[ allNodes.size() - 1 ];
}
}
// build the graph connections
Q_FOREACH( LayoutGraphNode* curNode, allNodes )
{
QVector< CartesianAxis* > sharedAxes;
CoordinatePlaneList xSharedPlanes = findSharingAxisDiagrams( curNode->diagramPlane, coordinatePlanes, Abscissa, &sharedAxes );
Q_ASSERT( sharedAxes.size() < 2 );
// TODO duplicated code make a method out of it
if ( sharedAxes.size() == 1 && xSharedPlanes.size() > 1 )
{
//xSharedPlanes.removeAll( sharedAxes.first()->diagram()->coordinatePlane() );
//std::sort( xSharedPlanes.begin(), xSharedPlanes.end(), PriorityComparator( planeNodeMapping ) );
for ( int i = 0; i < xSharedPlanes.size() - 1; ++i )
{
LayoutGraphNode *tmpNode = planeNodeMapping[ xSharedPlanes[ i ] ];
Q_ASSERT( tmpNode );
LayoutGraphNode *tmpNode2 = planeNodeMapping[ xSharedPlanes[ i + 1 ] ];
Q_ASSERT( tmpNode2 );
tmpNode->bottomSuccesor = tmpNode2;
}
// if ( sharedAxes.first()->diagram() && sharedAxes.first()->diagram()->coordinatePlane() )
// {
// LayoutGraphNode *lastNode = planeNodeMapping[ xSharedPlanes.last() ];
// Q_ASSERT( lastNode );
// Q_ASSERT( sharedAxes.first()->diagram()->coordinatePlane() );
// LayoutGraphNode *ownerNode = planeNodeMapping[ sharedAxes.first()->diagram()->coordinatePlane() ];
// Q_ASSERT( ownerNode );
// lastNode->bottomSuccesor = ownerNode;
// }
//merge AxisInformation, needs a two pass run
LayoutGraphNode axisInfoNode;
for ( int count = 0; count < 2; ++count )
{
for ( int i = 0; i < xSharedPlanes.size(); ++i )
{
mergeNodeAxisInformation( &axisInfoNode, planeNodeMapping[ xSharedPlanes[ i ] ] );
}
}
}
sharedAxes.clear();
CoordinatePlaneList ySharedPlanes = findSharingAxisDiagrams( curNode->diagramPlane, coordinatePlanes, Ordinate, &sharedAxes );
Q_ASSERT( sharedAxes.size() < 2 );
if ( sharedAxes.size() == 1 && ySharedPlanes.size() > 1 )
{
//ySharedPlanes.removeAll( sharedAxes.first()->diagram()->coordinatePlane() );
//std::sort( ySharedPlanes.begin(), ySharedPlanes.end(), PriorityComparator( planeNodeMapping ) );
for ( int i = 0; i < ySharedPlanes.size() - 1; ++i )
{
LayoutGraphNode *tmpNode = planeNodeMapping[ ySharedPlanes[ i ] ];
Q_ASSERT( tmpNode );
LayoutGraphNode *tmpNode2 = planeNodeMapping[ ySharedPlanes[ i + 1 ] ];
Q_ASSERT( tmpNode2 );
tmpNode->leftSuccesor = tmpNode2;
}
// if ( sharedAxes.first()->diagram() && sharedAxes.first()->diagram()->coordinatePlane() )
// {
// LayoutGraphNode *lastNode = planeNodeMapping[ ySharedPlanes.last() ];
// Q_ASSERT( lastNode );
// Q_ASSERT( sharedAxes.first()->diagram()->coordinatePlane() );
// LayoutGraphNode *ownerNode = planeNodeMapping[ sharedAxes.first()->diagram()->coordinatePlane() ];
// Q_ASSERT( ownerNode );
// lastNode->bottomSuccesor = ownerNode;
// }
//merge AxisInformation, needs a two pass run
LayoutGraphNode axisInfoNode;
for ( int count = 0; count < 2; ++count )
{
for ( int i = 0; i < ySharedPlanes.size(); ++i )
{
mergeNodeAxisInformation( &axisInfoNode, planeNodeMapping[ ySharedPlanes[ i ] ] );
}
}
}
sharedAxes.clear();
if ( curNode->diagramPlane->referenceCoordinatePlane() )
curNode->sharedSuccesor = planeNodeMapping[ curNode->diagramPlane->referenceCoordinatePlane() ];
}
return allNodes;
}
QHash Chart::Private::buildPlaneLayoutInfos()
{
/* There are two ways in which planes can be caused to interact in
* where they are put layouting wise: The first is the reference plane. If
* such a reference plane is set, on a plane, it will use the same cell in the
* layout as that one. In addition to this, planes can share an axis. In that case
* they will be laid out in relation to each other as suggested by the position
* of the axis. If, for example Plane1 and Plane2 share an axis at position Left,
* that will result in the layout: Axis Plane1 Plane 2, vertically. If Plane1
* also happens to be Plane2's referece plane, both planes are drawn over each
* other. The reference plane concept allows two planes to share the same space
* even if neither has any axis, and in case there are shared axis, it is used
* to decided, whether the planes should be painted on top of each other or
* laid out vertically or horizontally next to each other. */
QHash axisInfos;
QHash planeInfos;
Q_FOREACH(AbstractCoordinatePlane* plane, coordinatePlanes ) {
PlaneInfo p;
// first check if we share space with another plane
p.referencePlane = plane->referenceCoordinatePlane();
planeInfos.insert( plane, p );
Q_FOREACH( AbstractDiagram* abstractDiagram, plane->diagrams() ) {
AbstractCartesianDiagram* diagram =
qobject_cast ( abstractDiagram );
if ( !diagram ) {
continue;
}
Q_FOREACH( CartesianAxis* axis, diagram->axes() ) {
if ( !axisInfos.contains( axis ) ) {
/* If this is the first time we see this axis, add it, with the
* current plane. The first plane added to the chart that has
* the axis associated with it thus "owns" it, and decides about
* layout. */
AxisInfo i;
i.plane = plane;
axisInfos.insert( axis, i );
} else {
AxisInfo i = axisInfos[axis];
if ( i.plane == plane ) {
continue; // we don't want duplicates, only shared
}
/* The user expects diagrams to be added on top, and to the right
* so that horizontally we need to move the new diagram, vertically
* the reference one. */
PlaneInfo pi = planeInfos[plane];
// plane-to-plane linking overrides linking via axes
if ( !pi.referencePlane ) {
// we're not the first plane to see this axis, mark us as a slave
pi.referencePlane = i.plane;
if ( axis->position() == CartesianAxis::Left ||
axis->position() == CartesianAxis::Right ) {
pi.horizontalOffset += 1;
}
planeInfos[plane] = pi;
pi = planeInfos[i.plane];
if ( axis->position() == CartesianAxis::Top ||
axis->position() == CartesianAxis::Bottom ) {
pi.verticalOffset += 1;
}
planeInfos[i.plane] = pi;
}
}
}
}
// Create a new grid layout for each plane that has no reference.
p = planeInfos[plane];
if ( p.referencePlane == 0 ) {
p.gridLayout = new QGridLayout();
p.gridLayout->setMargin( 0 );
planeInfos[plane] = p;
}
}
return planeInfos;
}
void Chart::Private::slotLayoutPlanes()
{
/*TODO make sure this is really needed */
const QBoxLayout::Direction oldPlanesDirection = planesLayout ? planesLayout->direction()
: QBoxLayout::TopToBottom;
if ( planesLayout && dataAndLegendLayout )
dataAndLegendLayout->removeItem( planesLayout );
const bool hadPlanesLayout = planesLayout != 0;
int left, top, right, bottom;
if ( hadPlanesLayout )
planesLayout->getContentsMargins(&left, &top, &right, &bottom);
Q_FOREACH( AbstractLayoutItem* plane, planeLayoutItems ) {
plane->removeFromParentLayout();
}
//TODO they should get a correct parent, but for now it works
Q_FOREACH( AbstractLayoutItem* plane, planeLayoutItems ) {
if ( dynamic_cast< AutoSpacerLayoutItem* >( plane ) )
delete plane;
}
planeLayoutItems.clear();
delete planesLayout;
//hint: The direction is configurable by the user now, as
// we are using a QBoxLayout rather than a QVBoxLayout. (khz, 2007/04/25)
planesLayout = new QBoxLayout( oldPlanesDirection );
isPlanesLayoutDirty = true; // here we create the layouts; we need to "run" them before painting
if ( useNewLayoutSystem )
{
gridPlaneLayout = new QGridLayout;
planesLayout->addLayout( gridPlaneLayout );
if (hadPlanesLayout)
planesLayout->setContentsMargins(left, top, right, bottom);
planesLayout->setObjectName( QString::fromLatin1( "planesLayout" ) );
/* First go through all planes and all axes and figure out whether the planes
* need to coordinate. If they do, they share a grid layout, if not, each
* get their own. See buildPlaneLayoutInfos() for more details. */
QVector< LayoutGraphNode* > vals = buildPlaneLayoutGraph();
//qDebug() << Q_FUNC_INFO << "GraphNodes" << vals.size();
QVector< LayoutGraphNode* > connectedComponents = getPrioritySortedConnectedComponents( vals );
//qDebug() << Q_FUNC_INFO << "SubGraphs" << connectedComponents.size();
int row = 0;
int col = 0;
QSet< CartesianAxis* > laidOutAxes;
for ( int i = 0; i < connectedComponents.size(); ++i )
{
LayoutGraphNode *curComponent = connectedComponents[ i ];
for ( LayoutGraphNode *curRowComponent = curComponent; curRowComponent; curRowComponent = curRowComponent->bottomSuccesor )
{
col = 0;
for ( LayoutGraphNode *curColComponent = curRowComponent; curColComponent; curColComponent = curColComponent->leftSuccesor )
{
Q_ASSERT( curColComponent->diagramPlane->diagrams().size() == 1 );
Q_FOREACH( AbstractDiagram* diagram, curColComponent->diagramPlane->diagrams() )
{
const int planeRowOffset = 1;//curColComponent->topAxesLayout ? 1 : 0;
const int planeColOffset = 1;//curColComponent->leftAxesLayout ? 1 : 0;
//qDebug() << Q_FUNC_INFO << row << col << planeRowOffset << planeColOffset;
//qDebug() << Q_FUNC_INFO << row + planeRowOffset << col + planeColOffset;
planeLayoutItems << curColComponent->diagramPlane;
AbstractCartesianDiagram *cartDiag = qobject_cast< AbstractCartesianDiagram* >( diagram );
if ( cartDiag )
{
gridPlaneLayout->addItem( curColComponent->diagramPlane, row + planeRowOffset, col + planeColOffset, 2, 2 );
curColComponent->diagramPlane->setParentLayout( gridPlaneLayout );
QHBoxLayout *leftLayout = 0;
QHBoxLayout *rightLayout = 0;
QVBoxLayout *topLayout = 0;
QVBoxLayout *bottomLayout = 0;
if ( curComponent->sharedSuccesor )
{
gridPlaneLayout->addItem( curColComponent->sharedSuccesor->diagramPlane, row + planeRowOffset, col + planeColOffset, 2, 2 );
curColComponent->sharedSuccesor->diagramPlane->setParentLayout( gridPlaneLayout );
planeLayoutItems << curColComponent->sharedSuccesor->diagramPlane;
}
Q_FOREACH( CartesianAxis* axis, cartDiag->axes() )
{
if ( axis->isAbscissa() )
{
if ( curColComponent->bottomSuccesor )
continue;
}
if ( laidOutAxes.contains( axis ) )
continue;
// if ( axis->diagram() != diagram )
// continue;
switch ( axis->position() )
{
case( CartesianAxis::Top ):
if ( !topLayout )
topLayout = new QVBoxLayout;
topLayout->addItem( axis );
axis->setParentLayout( topLayout );
break;
case( CartesianAxis::Bottom ):
if ( !bottomLayout )
bottomLayout = new QVBoxLayout;
bottomLayout->addItem( axis );
axis->setParentLayout( bottomLayout );
break;
case( CartesianAxis::Left ):
if ( !leftLayout )
leftLayout = new QHBoxLayout;
leftLayout->addItem( axis );
axis->setParentLayout( leftLayout );
break;
case( CartesianAxis::Right ):
if ( !rightLayout )
{
rightLayout = new QHBoxLayout;
}
rightLayout->addItem( axis );
axis->setParentLayout( rightLayout );
break;
}
planeLayoutItems << axis;
laidOutAxes.insert( axis );
}
if ( leftLayout )
gridPlaneLayout->addLayout( leftLayout, row + planeRowOffset, col, 2, 1,
Qt::AlignRight | Qt::AlignVCenter );
if ( rightLayout )
gridPlaneLayout->addLayout( rightLayout, row, col + planeColOffset + 2, 2, 1,
Qt::AlignLeft | Qt::AlignVCenter );
if ( topLayout )
gridPlaneLayout->addLayout( topLayout, row, col + planeColOffset, 1, 2,
Qt::AlignBottom | Qt::AlignHCenter );
if ( bottomLayout )
gridPlaneLayout->addLayout( bottomLayout, row + planeRowOffset + 2,
col + planeColOffset, 1, 2, Qt::AlignTop | Qt::AlignHCenter );
}
else
{
gridPlaneLayout->addItem( curColComponent->diagramPlane, row, col, 4, 4 );
curColComponent->diagramPlane->setParentLayout( gridPlaneLayout );
}
col += planeColOffset + 2 + ( 1 );
}
}
int axisOffset = 2;//curRowComponent->topAxesLayout ? 1 : 0;
//axisOffset += curRowComponent->bottomAxesLayout ? 1 : 0;
const int rowOffset = axisOffset + 2;
row += rowOffset;
}
// if ( planesLayout->direction() == QBoxLayout::TopToBottom )
// ++row;
// else
// ++col;
}
qDeleteAll( vals );
// re-add our grid(s) to the chart's layout
if ( dataAndLegendLayout ) {
dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
dataAndLegendLayout->setRowStretch( 1, 1000 );
dataAndLegendLayout->setColumnStretch( 1, 1000 );
}
slotResizePlanes();
#ifdef NEW_LAYOUT_DEBUG
for ( int i = 0; i < gridPlaneLayout->rowCount(); ++i )
{
for ( int j = 0; j < gridPlaneLayout->columnCount(); ++j )
{
if ( gridPlaneLayout->itemAtPosition( i, j ) )
qDebug() << Q_FUNC_INFO << "item at" << i << j << gridPlaneLayout->itemAtPosition( i, j )->geometry();
else
qDebug() << Q_FUNC_INFO << "item at" << i << j << "no item present";
}
}
//qDebug() << Q_FUNC_INFO << "Relayout ended";
#endif
} else {
if ( hadPlanesLayout ) {
planesLayout->setContentsMargins( left, top, right, bottom );
}
planesLayout->setMargin( 0 );
planesLayout->setSpacing( 0 );
planesLayout->setObjectName( QString::fromLatin1( "planesLayout" ) );
/* First go through all planes and all axes and figure out whether the planes
* need to coordinate. If they do, they share a grid layout, if not, each
* gets their own. See buildPlaneLayoutInfos() for more details. */
QHash planeInfos = buildPlaneLayoutInfos();
QHash axisInfos;
Q_FOREACH( AbstractCoordinatePlane* plane, coordinatePlanes ) {
Q_ASSERT( planeInfos.contains(plane) );
PlaneInfo& pi = planeInfos[ plane ];
const int column = pi.horizontalOffset;
const int row = pi.verticalOffset;
//qDebug() << "processing plane at column" << column << "and row" << row;
QGridLayout *planeLayout = pi.gridLayout;
if ( !planeLayout ) {
PlaneInfo& refPi = pi;
// if this plane is sharing an axis with another one, recursively check for the original plane and use
// the grid of that as planeLayout.
while ( !planeLayout && refPi.referencePlane ) {
refPi = planeInfos[refPi.referencePlane];
planeLayout = refPi.gridLayout;
}
Q_ASSERT_X( planeLayout,
"Chart::Private::slotLayoutPlanes()",
"Invalid reference plane. Please check that the reference plane has been added to the Chart." );
} else {
planesLayout->addLayout( planeLayout );
}
/* Put the plane in the center of the layout. If this is our own, that's
* the middle of the layout, if we are sharing, it's a cell in the center
* column of the shared grid. */
planeLayoutItems << plane;
plane->setParentLayout( planeLayout );
- planeLayout->addItem( plane, row, column, 1, 1, 0 );
+ planeLayout->addItem( plane, row, column, 1, 1 );
//qDebug() << "Chart slotLayoutPlanes() calls planeLayout->addItem("<< row << column << ")";
planeLayout->setRowStretch( row, 2 );
planeLayout->setColumnStretch( column, 2 );
Q_FOREACH( AbstractDiagram* abstractDiagram, plane->diagrams() )
{
AbstractCartesianDiagram* diagram =
qobject_cast< AbstractCartesianDiagram* >( abstractDiagram );
if ( !diagram ) {
continue; // FIXME what about polar ?
}
if ( pi.referencePlane != 0 )
{
pi.topAxesLayout = planeInfos[ pi.referencePlane ].topAxesLayout;
pi.bottomAxesLayout = planeInfos[ pi.referencePlane ].bottomAxesLayout;
pi.leftAxesLayout = planeInfos[ pi.referencePlane ].leftAxesLayout;
pi.rightAxesLayout = planeInfos[ pi.referencePlane ].rightAxesLayout;
}
// collect all axes of a kind into sublayouts
if ( pi.topAxesLayout == 0 )
{
pi.topAxesLayout = new QVBoxLayout;
pi.topAxesLayout->setMargin( 0 );
pi.topAxesLayout->setObjectName( QString::fromLatin1( "topAxesLayout" ) );
}
if ( pi.bottomAxesLayout == 0 )
{
pi.bottomAxesLayout = new QVBoxLayout;
pi.bottomAxesLayout->setMargin( 0 );
pi.bottomAxesLayout->setObjectName( QString::fromLatin1( "bottomAxesLayout" ) );
}
if ( pi.leftAxesLayout == 0 )
{
pi.leftAxesLayout = new QHBoxLayout;
pi.leftAxesLayout->setMargin( 0 );
pi.leftAxesLayout->setObjectName( QString::fromLatin1( "leftAxesLayout" ) );
}
if ( pi.rightAxesLayout == 0 )
{
pi.rightAxesLayout = new QHBoxLayout;
pi.rightAxesLayout->setMargin( 0 );
pi.rightAxesLayout->setObjectName( QString::fromLatin1( "rightAxesLayout" ) );
}
if ( pi.referencePlane != 0 )
{
planeInfos[ pi.referencePlane ].topAxesLayout = pi.topAxesLayout;
planeInfos[ pi.referencePlane ].bottomAxesLayout = pi.bottomAxesLayout;
planeInfos[ pi.referencePlane ].leftAxesLayout = pi.leftAxesLayout;
planeInfos[ pi.referencePlane ].rightAxesLayout = pi.rightAxesLayout;
}
//pi.leftAxesLayout->setSizeConstraint( QLayout::SetFixedSize );
Q_FOREACH( CartesianAxis* axis, diagram->axes() ) {
if ( axisInfos.contains( axis ) ) {
continue; // already laid out this one
}
Q_ASSERT ( axis );
axis->setCachedSizeDirty();
//qDebug() << "--------------- axis added to planeLayoutItems -----------------";
planeLayoutItems << axis;
switch ( axis->position() ) {
case CartesianAxis::Top:
axis->setParentLayout( pi.topAxesLayout );
pi.topAxesLayout->addItem( axis );
break;
case CartesianAxis::Bottom:
axis->setParentLayout( pi.bottomAxesLayout );
pi.bottomAxesLayout->addItem( axis );
break;
case CartesianAxis::Left:
axis->setParentLayout( pi.leftAxesLayout );
pi.leftAxesLayout->addItem( axis );
break;
case CartesianAxis::Right:
axis->setParentLayout( pi.rightAxesLayout );
pi.rightAxesLayout->addItem( axis );
break;
default:
Q_ASSERT_X( false, "Chart::paintEvent", "unknown axis position" );
break;
};
axisInfos.insert( axis, AxisInfo() );
}
/* Put each stack of axes-layouts in the cells surrounding the
* associated plane. We are laying out in the oder the planes
* were added, and the first one gets to lay out shared axes.
* Private axes go here as well, of course. */
if ( !pi.topAxesLayout->parent() ) {
planeLayout->addLayout( pi.topAxesLayout, row - 1, column );
}
if ( !pi.bottomAxesLayout->parent() ) {
planeLayout->addLayout( pi.bottomAxesLayout, row + 1, column );
}
if ( !pi.leftAxesLayout->parent() ) {
planeLayout->addLayout( pi.leftAxesLayout, row, column - 1 );
}
if ( !pi.rightAxesLayout->parent() ) {
planeLayout->addLayout( pi.rightAxesLayout,row, column + 1 );
}
}
// use up to four auto-spacer items in the corners around the diagrams:
#define ADD_AUTO_SPACER_IF_NEEDED( \
spacerRow, spacerColumn, hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ) \
{ \
if ( hLayout || vLayout ) { \
AutoSpacerLayoutItem * spacer \
= new AutoSpacerLayoutItem( hLayoutIsAtTop, hLayout, vLayoutIsAtLeft, vLayout ); \
planeLayout->addItem( spacer, spacerRow, spacerColumn, 1, 1 ); \
spacer->setParentLayout( planeLayout ); \
planeLayoutItems << spacer; \
} \
}
if ( plane->isCornerSpacersEnabled() ) {
ADD_AUTO_SPACER_IF_NEEDED( row - 1, column - 1, false, pi.leftAxesLayout, false, pi.topAxesLayout )
ADD_AUTO_SPACER_IF_NEEDED( row + 1, column - 1, true, pi.leftAxesLayout, false, pi.bottomAxesLayout )
ADD_AUTO_SPACER_IF_NEEDED( row - 1, column + 1, false, pi.rightAxesLayout, true, pi.topAxesLayout )
ADD_AUTO_SPACER_IF_NEEDED( row + 1, column + 1, true, pi.rightAxesLayout, true, pi.bottomAxesLayout )
}
}
// re-add our grid(s) to the chart's layout
if ( dataAndLegendLayout ) {
dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
dataAndLegendLayout->setRowStretch( 1, 1000 );
dataAndLegendLayout->setColumnStretch( 1, 1000 );
}
slotResizePlanes();
}
}
void Chart::Private::createLayouts()
{
// The toplevel layout provides the left and right global margins
layout = new QHBoxLayout( chart );
layout->setMargin( 0 );
layout->setObjectName( QString::fromLatin1( "Chart::Private::layout" ) );
layout->addSpacing( globalLeadingLeft );
leftOuterSpacer = layout->itemAt( layout->count() - 1 )->spacerItem();
// The vLayout provides top and bottom global margins and lays
// out headers, footers and the diagram area.
vLayout = new QVBoxLayout();
vLayout->setMargin( 0 );
vLayout->setObjectName( QString::fromLatin1( "vLayout" ) );
layout->addLayout( vLayout, 1000 );
layout->addSpacing( globalLeadingRight );
rightOuterSpacer = layout->itemAt( layout->count() - 1 )->spacerItem();
// 1. the spacing above the header area
vLayout->addSpacing( globalLeadingTop );
topOuterSpacer = vLayout->itemAt( vLayout->count() - 1 )->spacerItem();
// 2. the header area
headerLayout = new QGridLayout();
headerLayout->setMargin( 0 );
vLayout->addLayout( headerLayout );
// 3. the area containing coordinate planes, axes, and legends
dataAndLegendLayout = new QGridLayout();
dataAndLegendLayout->setMargin( 0 );
dataAndLegendLayout->setObjectName( QString::fromLatin1( "dataAndLegendLayout" ) );
vLayout->addLayout( dataAndLegendLayout, 1000 );
// 4. the footer area
footerLayout = new QGridLayout();
footerLayout->setMargin( 0 );
footerLayout->setObjectName( QString::fromLatin1( "footerLayout" ) );
vLayout->addLayout( footerLayout );
// 5. Prepare the header / footer layout cells:
// Each of the 9 header cells (the 9 footer cells)
// contain their own QVBoxLayout
// since there can be more than one header (footer) per cell.
for ( int row = 0; row < 3; ++row ) {
for ( int column = 0; column < 3; ++ column ) {
const Qt::Alignment align = s_gridAlignments[ row ][ column ];
for ( int headOrFoot = 0; headOrFoot < 2; headOrFoot++ ) {
QVBoxLayout* innerLayout = new QVBoxLayout();
innerLayout->setMargin( 0 );
innerLayout->setAlignment( align );
innerHdFtLayouts[ headOrFoot ][ row ][ column ] = innerLayout;
QGridLayout* outerLayout = headOrFoot == 0 ? headerLayout : footerLayout;
outerLayout->addLayout( innerLayout, row, column, align );
}
}
}
// 6. the spacing below the footer area
vLayout->addSpacing( globalLeadingBottom );
bottomOuterSpacer = vLayout->itemAt( vLayout->count() - 1 )->spacerItem();
// the data+axes area
dataAndLegendLayout->addLayout( planesLayout, 1, 1 );
dataAndLegendLayout->setRowStretch( 1, 1 );
dataAndLegendLayout->setColumnStretch( 1, 1 );
}
void Chart::Private::slotResizePlanes()
{
if ( !dataAndLegendLayout ) {
return;
}
if ( !overrideSize.isValid() ) {
// activate() takes the size from the layout's parent QWidget, which is not updated when overrideSize
// is set. So don't let the layout grab the wrong size in that case.
// When overrideSize *is* set, we call layout->setGeometry() in paint( QPainter*, const QRect& ),
// which also "activates" the layout in the sense that it distributes space internally.
layout->activate();
}
// Adapt diagram drawing to the new size
Q_FOREACH (AbstractCoordinatePlane* plane, coordinatePlanes ) {
plane->layoutDiagrams();
}
}
void Chart::Private::updateDirtyLayouts()
{
if ( isPlanesLayoutDirty ) {
Q_FOREACH ( AbstractCoordinatePlane* p, coordinatePlanes ) {
p->setGridNeedsRecalculate();
p->layoutPlanes();
p->layoutDiagrams();
}
}
if ( isPlanesLayoutDirty || isFloatingLegendsLayoutDirty ) {
chart->reLayoutFloatingLegends();
}
isPlanesLayoutDirty = false;
isFloatingLegendsLayoutDirty = false;
}
void Chart::Private::reapplyInternalLayouts()
{
QRect geo = layout->geometry();
invalidateLayoutTree( layout );
layout->setGeometry( geo );
slotResizePlanes();
}
void Chart::Private::paintAll( QPainter* painter )
{
updateDirtyLayouts();
QRect rect( QPoint( 0, 0 ), overrideSize.isValid() ? overrideSize : chart->size() );
//qDebug() << this<<"::paintAll() uses layout size" << currentLayoutSize;
// Paint the background (if any)
AbstractAreaBase::paintBackgroundAttributes( *painter, rect, backgroundAttributes );
// Paint the frame (if any)
AbstractAreaBase::paintFrameAttributes( *painter, rect, frameAttributes );
chart->reLayoutFloatingLegends();
Q_FOREACH( AbstractLayoutItem* planeLayoutItem, planeLayoutItems ) {
planeLayoutItem->paintAll( *painter );
}
Q_FOREACH( TextArea* textLayoutItem, textLayoutItems ) {
textLayoutItem->paintAll( *painter );
}
Q_FOREACH( Legend *legend, legends ) {
const bool hidden = legend->isHidden() && legend->testAttribute( Qt::WA_WState_ExplicitShowHide );
if ( !hidden ) {
//qDebug() << "painting legend at " << legend->geometry();
legend->paintIntoRect( *painter, legend->geometry() );
}
}
}
// ******** Chart interface implementation ***********
#define d d_func()
Chart::Chart ( QWidget* parent )
: QWidget ( parent )
, _d( new Private( this ) )
{
#if defined KDAB_EVAL
EvalDialog::checkEvalLicense( "KD Chart" );
#endif
FrameAttributes frameAttrs;
// no frame per default...
// frameAttrs.setVisible( true );
frameAttrs.setPen( QPen( Qt::black ) );
frameAttrs.setPadding( 1 );
setFrameAttributes( frameAttrs );
addCoordinatePlane( new CartesianCoordinatePlane ( this ) );
d->createLayouts();
}
Chart::~Chart()
{
delete d;
}
void Chart::setFrameAttributes( const FrameAttributes &a )
{
d->frameAttributes = a;
}
FrameAttributes Chart::frameAttributes() const
{
return d->frameAttributes;
}
void Chart::setBackgroundAttributes( const BackgroundAttributes &a )
{
d->backgroundAttributes = a;
}
BackgroundAttributes Chart::backgroundAttributes() const
{
return d->backgroundAttributes;
}
//TODO KChart 3.0; change QLayout into QBoxLayout::Direction
void Chart::setCoordinatePlaneLayout( QLayout * layout )
{
if (layout == d->planesLayout)
return;
if (d->planesLayout) {
// detach all QLayoutItem's the previous planesLayout has cause
// otherwise deleting the planesLayout would delete them too.
for(int i = d->planesLayout->count() - 1; i >= 0; --i) {
d->planesLayout->takeAt(i);
}
delete d->planesLayout;
}
d->planesLayout = qobject_cast( layout );
d->slotLayoutPlanes();
}
QLayout* Chart::coordinatePlaneLayout()
{
return d->planesLayout;
}
AbstractCoordinatePlane* Chart::coordinatePlane()
{
if ( d->coordinatePlanes.isEmpty() ) {
qWarning() << "Chart::coordinatePlane: warning: no coordinate plane defined.";
return 0;
} else {
return d->coordinatePlanes.first();
}
}
CoordinatePlaneList Chart::coordinatePlanes()
{
return d->coordinatePlanes;
}
void Chart::addCoordinatePlane( AbstractCoordinatePlane* plane )
{
// Append
insertCoordinatePlane( d->coordinatePlanes.count(), plane );
}
void Chart::insertCoordinatePlane( int index, AbstractCoordinatePlane* plane )
{
if ( index < 0 || index > d->coordinatePlanes.count() ) {
return;
}
connect( plane, SIGNAL(destroyedCoordinatePlane(AbstractCoordinatePlane*)),
d, SLOT(slotUnregisterDestroyedPlane(AbstractCoordinatePlane*)) );
connect( plane, SIGNAL(needUpdate()), this, SLOT(update()) );
connect( plane, SIGNAL(needRelayout()), d, SLOT(slotResizePlanes()) ) ;
connect( plane, SIGNAL(needLayoutPlanes()), d, SLOT(slotLayoutPlanes()) ) ;
connect( plane, SIGNAL(propertiesChanged()),this, SIGNAL(propertiesChanged()) );
d->coordinatePlanes.insert( index, plane );
plane->setParent( this );
d->slotLayoutPlanes();
}
void Chart::replaceCoordinatePlane( AbstractCoordinatePlane* plane,
AbstractCoordinatePlane* oldPlane_ )
{
if ( plane && oldPlane_ != plane ) {
AbstractCoordinatePlane* oldPlane = oldPlane_;
if ( d->coordinatePlanes.count() ) {
if ( ! oldPlane ) {
oldPlane = d->coordinatePlanes.first();
if ( oldPlane == plane )
return;
}
takeCoordinatePlane( oldPlane );
}
delete oldPlane;
addCoordinatePlane( plane );
}
}
void Chart::takeCoordinatePlane( AbstractCoordinatePlane* plane )
{
const int idx = d->coordinatePlanes.indexOf( plane );
if ( idx != -1 ) {
d->coordinatePlanes.takeAt( idx );
disconnect( plane, 0, d, 0 );
disconnect( plane, 0, this, 0 );
plane->removeFromParentLayout();
plane->setParent( 0 );
d->mouseClickedPlanes.removeAll(plane);
}
d->slotLayoutPlanes();
// Need to emit the signal: In case somebody has connected the signal
// to her own slot for e.g. calling update() on a widget containing the chart.
emit propertiesChanged();
}
void Chart::setGlobalLeading( int left, int top, int right, int bottom )
{
setGlobalLeadingLeft( left );
setGlobalLeadingTop( top );
setGlobalLeadingRight( right );
setGlobalLeadingBottom( bottom );
}
void Chart::setGlobalLeadingLeft( int leading )
{
d->globalLeadingLeft = leading;
d->leftOuterSpacer->changeSize( leading, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
d->reapplyInternalLayouts();
}
int Chart::globalLeadingLeft() const
{
return d->globalLeadingLeft;
}
void Chart::setGlobalLeadingTop( int leading )
{
d->globalLeadingTop = leading;
d->topOuterSpacer->changeSize( 0, leading, QSizePolicy::Minimum, QSizePolicy::Fixed );
d->reapplyInternalLayouts();
}
int Chart::globalLeadingTop() const
{
return d->globalLeadingTop;
}
void Chart::setGlobalLeadingRight( int leading )
{
d->globalLeadingRight = leading;
d->rightOuterSpacer->changeSize( leading, 0, QSizePolicy::Fixed, QSizePolicy::Minimum );
d->reapplyInternalLayouts();
}
int Chart::globalLeadingRight() const
{
return d->globalLeadingRight;
}
void Chart::setGlobalLeadingBottom( int leading )
{
d->globalLeadingBottom = leading;
d->bottomOuterSpacer->changeSize( 0, leading, QSizePolicy::Minimum, QSizePolicy::Fixed );
d->reapplyInternalLayouts();
}
int Chart::globalLeadingBottom() const
{
return d->globalLeadingBottom;
}
void Chart::paint( QPainter* painter, const QRect& target )
{
if ( target.isEmpty() || !painter ) {
return;
}
QPaintDevice* prevDevice = GlobalMeasureScaling::paintDevice();
GlobalMeasureScaling::setPaintDevice( painter->device() );
// Output on a widget
if ( dynamic_cast< QWidget* >( painter->device() ) != 0 ) {
GlobalMeasureScaling::setFactors( qreal( target.width() ) / qreal( geometry().size().width() ),
qreal( target.height() ) / qreal( geometry().size().height() ) );
} else {
// Output onto a QPixmap
PrintingParameters::setScaleFactor( qreal( painter->device()->logicalDpiX() ) / qreal( logicalDpiX() ) );
const qreal resX = qreal( logicalDpiX() ) / qreal( painter->device()->logicalDpiX() );
const qreal resY = qreal( logicalDpiY() ) / qreal( painter->device()->logicalDpiY() );
GlobalMeasureScaling::setFactors( qreal( target.width() ) / qreal( geometry().size().width() ) * resX,
qreal( target.height() ) / qreal( geometry().size().height() ) * resY );
}
const QPoint translation = target.topLeft();
painter->translate( translation );
// the following layout logic has the disadvantage that repeatedly calling this method can
// cause a relayout every time, but since this method's main use seems to be printing, the
// gratuitous relayouts shouldn't be much of a performance problem.
const bool differentSize = target.size() != size();
QRect oldGeometry;
if ( differentSize ) {
oldGeometry = geometry();
d->isPlanesLayoutDirty = true;
d->isFloatingLegendsLayoutDirty = true;
invalidateLayoutTree( d->dataAndLegendLayout );
d->dataAndLegendLayout->setGeometry( QRect( QPoint(), target.size() ) );
}
d->overrideSize = target.size();
d->paintAll( painter );
d->overrideSize = QSize();
if ( differentSize ) {
invalidateLayoutTree( d->dataAndLegendLayout );
d->dataAndLegendLayout->setGeometry( oldGeometry );
d->isPlanesLayoutDirty = true;
d->isFloatingLegendsLayoutDirty = true;
}
// for debugging
// painter->setPen( QPen( Qt::blue, 8 ) );
// painter->drawRect( target );
painter->translate( -translation.x(), -translation.y() );
GlobalMeasureScaling::instance()->resetFactors();
PrintingParameters::resetScaleFactor();
GlobalMeasureScaling::setPaintDevice( prevDevice );
}
void Chart::resizeEvent ( QResizeEvent* event )
{
d->isPlanesLayoutDirty = true;
d->isFloatingLegendsLayoutDirty = true;
QWidget::resizeEvent( event );
}
void Chart::reLayoutFloatingLegends()
{
Q_FOREACH( Legend *legend, d->legends ) {
const bool hidden = legend->isHidden() && legend->testAttribute( Qt::WA_WState_ExplicitShowHide );
if ( legend->position().isFloating() && !hidden ) {
// resize the legend
const QSize legendSize( legend->sizeHint() );
legend->setGeometry( QRect( legend->geometry().topLeft(), legendSize ) );
// find the legends corner point (reference point plus any paddings)
const RelativePosition relPos( legend->floatingPosition() );
QPointF pt( relPos.calculatedPoint( size() ) );
//qDebug() << pt;
// calculate the legend's top left point
const Qt::Alignment alignTopLeft = Qt::AlignBottom | Qt::AlignLeft;
if ( (relPos.alignment() & alignTopLeft) != alignTopLeft ) {
if ( relPos.alignment() & Qt::AlignRight )
pt.rx() -= legendSize.width();
else if ( relPos.alignment() & Qt::AlignHCenter )
pt.rx() -= 0.5 * legendSize.width();
if ( relPos.alignment() & Qt::AlignBottom )
pt.ry() -= legendSize.height();
else if ( relPos.alignment() & Qt::AlignVCenter )
pt.ry() -= 0.5 * legendSize.height();
}
//qDebug() << pt << endl;
legend->move( static_cast(pt.x()), static_cast(pt.y()) );
}
}
}
void Chart::paintEvent( QPaintEvent* )
{
QPainter painter( this );
d->paintAll( &painter );
emit finishedDrawing();
}
void Chart::addHeaderFooter( HeaderFooter* hf )
{
Q_ASSERT( hf->type() == HeaderFooter::Header || hf->type() == HeaderFooter::Footer );
int row;
int column;
getRowAndColumnForPosition( hf->position().value(), &row, &column );
if ( row == -1 ) {
qWarning( "Unknown header/footer position" );
return;
}
d->headerFooters.append( hf );
d->textLayoutItems.append( hf );
connect( hf, SIGNAL(destroyedHeaderFooter(HeaderFooter*)),
d, SLOT(slotUnregisterDestroyedHeaderFooter(HeaderFooter*)) );
connect( hf, SIGNAL(positionChanged(HeaderFooter*)),
d, SLOT(slotHeaderFooterPositionChanged(HeaderFooter*)) );
// set the text attributes (why?)
TextAttributes textAttrs( hf->textAttributes() );
Measure measure( textAttrs.fontSize() );
measure.setRelativeMode( this, KChartEnums::MeasureOrientationMinimum );
measure.setValue( 20 );
textAttrs.setFontSize( measure );
hf->setTextAttributes( textAttrs );
// add it to the appropriate layout
int innerLayoutIdx = hf->type() == HeaderFooter::Header ? 0 : 1;
QVBoxLayout* headerFooterLayout = d->innerHdFtLayouts[ innerLayoutIdx ][ row ][ column ];
hf->setParentLayout( headerFooterLayout );
hf->setAlignment( s_gridAlignments[ row ][ column ] );
headerFooterLayout->addItem( hf );
d->slotResizePlanes();
}
void Chart::replaceHeaderFooter( HeaderFooter* headerFooter,
HeaderFooter* oldHeaderFooter_ )
{
if ( headerFooter && oldHeaderFooter_ != headerFooter ) {
HeaderFooter* oldHeaderFooter = oldHeaderFooter_;
if ( d->headerFooters.count() ) {
if ( ! oldHeaderFooter ) {
oldHeaderFooter = d->headerFooters.first();
if ( oldHeaderFooter == headerFooter )
return;
}
takeHeaderFooter( oldHeaderFooter );
}
delete oldHeaderFooter;
addHeaderFooter( headerFooter );
}
}
void Chart::takeHeaderFooter( HeaderFooter* headerFooter )
{
const int idx = d->headerFooters.indexOf( headerFooter );
if ( idx == -1 ) {
return;
}
disconnect( headerFooter, SIGNAL(destroyedHeaderFooter(HeaderFooter*)),
d, SLOT(slotUnregisterDestroyedHeaderFooter(HeaderFooter*)) );
d->headerFooters.takeAt( idx );
headerFooter->removeFromParentLayout();
headerFooter->setParentLayout( 0 );
d->textLayoutItems.remove( d->textLayoutItems.indexOf( headerFooter ) );
d->slotResizePlanes();
}
void Chart::Private::slotHeaderFooterPositionChanged( HeaderFooter* hf )
{
chart->takeHeaderFooter( hf );
chart->addHeaderFooter( hf );
}
HeaderFooter* Chart::headerFooter()
{
if ( d->headerFooters.isEmpty() ) {
return 0;
} else {
return d->headerFooters.first();
}
}
HeaderFooterList Chart::headerFooters()
{
return d->headerFooters;
}
void Chart::Private::slotLegendPositionChanged( AbstractAreaWidget* aw )
{
Legend* legend = qobject_cast< Legend* >( aw );
Q_ASSERT( legend );
chart->takeLegend( legend );
chart->addLegendInternal( legend, false );
}
void Chart::addLegend( Legend* legend )
{
legend->show();
addLegendInternal( legend, true );
emit propertiesChanged();
}
void Chart::addLegendInternal( Legend* legend, bool setMeasures )
{
if ( !legend ) {
return;
}
KChartEnums::PositionValue pos = legend->position().value();
if ( pos == KChartEnums::PositionCenter ) {
qWarning( "Not showing legend because PositionCenter is not supported for legends." );
}
int row;
int column;
getRowAndColumnForPosition( pos, &row, &column );
if ( row < 0 && pos != KChartEnums::PositionFloating ) {
qWarning( "Not showing legend because of unknown legend position." );
return;
}
d->legends.append( legend );
legend->setParent( this );
// set text attributes (why?)
if ( setMeasures ) {
TextAttributes textAttrs( legend->textAttributes() );
Measure measure( textAttrs.fontSize() );
measure.setRelativeMode( this, KChartEnums::MeasureOrientationMinimum );
measure.setValue( 20 );
textAttrs.setFontSize( measure );
legend->setTextAttributes( textAttrs );
textAttrs = legend->titleTextAttributes();
measure.setRelativeMode( this, KChartEnums::MeasureOrientationMinimum );
measure.setValue( 24 );
textAttrs.setFontSize( measure );
legend->setTitleTextAttributes( textAttrs );
legend->setReferenceArea( this );
}
// add it to the appropriate layout
if ( pos != KChartEnums::PositionFloating ) {
legend->needSizeHint();
// in each edge and corner of the outer layout, there's a grid for the different alignments that we create
// on demand. we don't remove it when empty.
QLayoutItem* edgeItem = d->dataAndLegendLayout->itemAtPosition( row, column );
QGridLayout* alignmentsLayout = dynamic_cast< QGridLayout* >( edgeItem );
Q_ASSERT( !edgeItem || alignmentsLayout ); // if it exists, it must be a QGridLayout
if ( !alignmentsLayout ) {
alignmentsLayout = new QGridLayout;
d->dataAndLegendLayout->addLayout( alignmentsLayout, row, column );
alignmentsLayout->setMargin( 0 );
}
// in case there are several legends in the same edge or corner with the same alignment, they are stacked
// vertically using a QVBoxLayout. it is created on demand as above.
row = 1;
column = 1;
for ( int i = 0; i < 3; i++ ) {
for ( int j = 0; j < 3; j++ ) {
Qt::Alignment align = s_gridAlignments[ i ][ j ];
if ( align == legend->alignment() ) {
row = i;
column = j;
break;
}
}
}
QLayoutItem* alignmentItem = alignmentsLayout->itemAtPosition( row, column );
QVBoxLayout* sameAlignmentLayout = dynamic_cast< QVBoxLayout* >( alignmentItem );
Q_ASSERT( !alignmentItem || sameAlignmentLayout ); // if it exists, it must be a QVBoxLayout
if ( !sameAlignmentLayout ) {
sameAlignmentLayout = new QVBoxLayout;
alignmentsLayout->addLayout( sameAlignmentLayout, row, column );
sameAlignmentLayout->setMargin( 0 );
}
sameAlignmentLayout->addItem( new MyWidgetItem( legend, legend->alignment() ) );
}
connect( legend, SIGNAL(destroyedLegend(Legend*)),
d, SLOT(slotUnregisterDestroyedLegend(Legend*)) );
connect( legend, SIGNAL(positionChanged(AbstractAreaWidget*)),
d, SLOT(slotLegendPositionChanged(AbstractAreaWidget*)) );
connect( legend, SIGNAL(propertiesChanged()), this, SIGNAL(propertiesChanged()) );
d->slotResizePlanes();
}
void Chart::replaceLegend( Legend* legend, Legend* oldLegend_ )
{
if ( legend && oldLegend_ != legend ) {
Legend* oldLegend = oldLegend_;
if ( d->legends.count() ) {
if ( ! oldLegend ) {
oldLegend = d->legends.first();
if ( oldLegend == legend )
return;
}
takeLegend( oldLegend );
}
delete oldLegend;
addLegend( legend );
}
}
void Chart::takeLegend( Legend* legend )
{
const int idx = d->legends.indexOf( legend );
if ( idx == -1 ) {
return;
}
d->legends.takeAt( idx );
disconnect( legend, 0, d, 0 );
disconnect( legend, 0, this, 0 );
// the following removes the legend from its layout and destroys its MyWidgetItem (the link to the layout)
legend->setParent( 0 );
d->slotResizePlanes();
emit propertiesChanged();
}
Legend* Chart::legend()
{
return d->legends.isEmpty() ? 0 : d->legends.first();
}
LegendList Chart::legends()
{
return d->legends;
}
void Chart::mousePressEvent( QMouseEvent* event )
{
const QPoint pos = mapFromGlobal( event->globalPos() );
Q_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes ) {
if ( plane->geometry().contains( event->pos() ) && plane->diagrams().size() > 0 ) {
QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
event->button(), event->buttons(), event->modifiers() );
plane->mousePressEvent( &ev );
d->mouseClickedPlanes.append( plane );
}
}
}
void Chart::mouseDoubleClickEvent( QMouseEvent* event )
{
const QPoint pos = mapFromGlobal( event->globalPos() );
Q_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes ) {
if ( plane->geometry().contains( event->pos() ) && plane->diagrams().size() > 0 ) {
QMouseEvent ev( QEvent::MouseButtonPress, pos, event->globalPos(),
event->button(), event->buttons(), event->modifiers() );
plane->mouseDoubleClickEvent( &ev );
}
}
}
void Chart::mouseMoveEvent( QMouseEvent* event )
{
QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList( d->mouseClickedPlanes );
Q_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes ) {
if ( plane->geometry().contains( event->pos() ) && plane->diagrams().size() > 0 ) {
eventReceivers.insert( plane );
}
}
const QPoint pos = mapFromGlobal( event->globalPos() );
Q_FOREACH( AbstractCoordinatePlane* plane, eventReceivers ) {
QMouseEvent ev( QEvent::MouseMove, pos, event->globalPos(),
event->button(), event->buttons(), event->modifiers() );
plane->mouseMoveEvent( &ev );
}
}
void Chart::mouseReleaseEvent( QMouseEvent* event )
{
QSet< AbstractCoordinatePlane* > eventReceivers = QSet< AbstractCoordinatePlane* >::fromList( d->mouseClickedPlanes );
Q_FOREACH( AbstractCoordinatePlane* plane, d->coordinatePlanes ) {
if ( plane->geometry().contains( event->pos() ) && plane->diagrams().size() > 0 ) {
eventReceivers.insert( plane );
}
}
const QPoint pos = mapFromGlobal( event->globalPos() );
Q_FOREACH( AbstractCoordinatePlane* plane, eventReceivers ) {
QMouseEvent ev( QEvent::MouseButtonRelease, pos, event->globalPos(),
event->button(), event->buttons(), event->modifiers() );
plane->mouseReleaseEvent( &ev );
}
d->mouseClickedPlanes.clear();
}
bool Chart::event( QEvent* event )
{
if ( event->type() == QEvent::ToolTip ) {
const QHelpEvent* const helpEvent = static_cast< QHelpEvent* >( event );
Q_FOREACH( const AbstractCoordinatePlane* const plane, d->coordinatePlanes ) {
// iterate diagrams in reverse, so that the top-most painted diagram is
// queried first for a tooltip before the diagrams behind it
const ConstAbstractDiagramList& diagrams = plane->diagrams();
for (int i = diagrams.size() - 1; i >= 0; --i) {
const AbstractDiagram* diagram = diagrams[i];
if (diagram->isHidden()) {
continue;
}
const QModelIndex index = diagram->indexAt( helpEvent->pos() );
const QVariant toolTip = index.data( Qt::ToolTipRole );
if ( toolTip.isValid() ) {
QPoint pos = mapFromGlobal( helpEvent->pos() );
QRect rect( pos - QPoint( 1, 1 ), QSize( 3, 3 ) );
QToolTip::showText( QCursor::pos(), toolTip.toString(), this, rect );
return true;
}
}
}
}
return QWidget::event( event );
}
bool Chart::useNewLayoutSystem() const
{
return d_func()->useNewLayoutSystem;
}
void Chart::setUseNewLayoutSystem( bool value )
{
if ( d_func()->useNewLayoutSystem != value )
d_func()->useNewLayoutSystem = value;
}
diff --git a/src/KChart/KChartLayoutItems.cpp b/src/KChart/KChartLayoutItems.cpp
index 4af97d9..b69fde4 100644
--- a/src/KChart/KChartLayoutItems.cpp
+++ b/src/KChart/KChartLayoutItems.cpp
@@ -1,1026 +1,1026 @@
/*
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KD Chart library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "KChartLayoutItems.h"
#include "KTextDocument.h"
#include "KChartAbstractArea.h"
#include "KChartAbstractDiagram.h"
#include "KChartBackgroundAttributes.h"
#include "KChartFrameAttributes.h"
#include "KChartPaintContext.h"
#include "KChartPainterSaver_p.h"
#include "KChartPrintingParameters.h"
#include "KChartMath_p.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#define DEBUG_ITEMS_PAINT
/**
Inform the item about its widget: This enables the item,
to trigger that widget's update, whenever the size of the item's
contents has changed.
Thus, you need to call setParentWidget on every item, that
has a non-fixed size.
*/
void KChart::AbstractLayoutItem::setParentWidget( QWidget* widget )
{
mParent = widget;
}
void KChart::AbstractLayoutItem::paintAll( QPainter& painter )
{
paint( &painter );
}
/**
* Default impl: Paint the complete item using its layouted position and size.
*/
void KChart::AbstractLayoutItem::paintCtx( PaintContext* context )
{
if ( context )
paint( context->painter() );
}
/**
Report changed size hint: ask the parent widget to recalculate the layout.
*/
void KChart::AbstractLayoutItem::sizeHintChanged() const
{
// This is exactly like what QWidget::updateGeometry does.
// qDebug("KChart::AbstractLayoutItem::sizeHintChanged() called");
if ( mParent ) {
if ( mParent->layout() )
mParent->layout()->invalidate();
else
QApplication::postEvent( mParent, new QEvent( QEvent::LayoutRequest ) );
}
}
KChart::TextBubbleLayoutItem::TextBubbleLayoutItem( const QString& text,
const KChart::TextAttributes& attributes,
const QObject* area,
KChartEnums::MeasureOrientation orientation,
Qt::Alignment alignment )
: AbstractLayoutItem( alignment ),
m_text( new TextLayoutItem( text, attributes, area, orientation, alignment ) )
{
}
KChart::TextBubbleLayoutItem::TextBubbleLayoutItem()
: AbstractLayoutItem( Qt::AlignLeft ),
m_text( new TextLayoutItem() )
{
}
KChart::TextBubbleLayoutItem::~TextBubbleLayoutItem()
{
delete m_text;
}
void KChart::TextBubbleLayoutItem::setAutoReferenceArea( const QObject* area )
{
m_text->setAutoReferenceArea( area );
}
const QObject* KChart::TextBubbleLayoutItem::autoReferenceArea() const
{
return m_text->autoReferenceArea();
}
void KChart::TextBubbleLayoutItem::setText( const QString& text )
{
m_text->setText( text );
}
QString KChart::TextBubbleLayoutItem::text() const
{
return m_text->text();
}
void KChart::TextBubbleLayoutItem::setTextAttributes( const TextAttributes& a )
{
m_text->setTextAttributes( a );
}
KChart::TextAttributes KChart::TextBubbleLayoutItem::textAttributes() const
{
return m_text->textAttributes();
}
bool KChart::TextBubbleLayoutItem::isEmpty() const
{
return m_text->isEmpty();
}
Qt::Orientations KChart::TextBubbleLayoutItem::expandingDirections() const
{
return m_text->expandingDirections();
}
QSize KChart::TextBubbleLayoutItem::maximumSize() const
{
const int border = borderWidth();
return m_text->maximumSize() + QSize( 2 * border, 2 * border );
}
QSize KChart::TextBubbleLayoutItem::minimumSize() const
{
const int border = borderWidth();
return m_text->minimumSize() + QSize( 2 * border, 2 * border );
}
QSize KChart::TextBubbleLayoutItem::sizeHint() const
{
const int border = borderWidth();
return m_text->sizeHint() + QSize( 2 * border, 2 * border );
}
void KChart::TextBubbleLayoutItem::setGeometry( const QRect& r )
{
const int border = borderWidth();
m_text->setGeometry( r.adjusted( border, border, -border, -border ) );
}
QRect KChart::TextBubbleLayoutItem::geometry() const
{
const int border = borderWidth();
return m_text->geometry().adjusted( -border, -border, border, border );
}
void KChart::TextBubbleLayoutItem::paint( QPainter* painter )
{
const QPen oldPen = painter->pen();
const QBrush oldBrush = painter->brush();
painter->setPen( Qt::black );
painter->setBrush( QColor( 255, 255, 220 ) );
painter->drawRoundRect( geometry(), 10 );
painter->setPen( oldPen );
painter->setBrush( oldBrush );
m_text->paint( painter );
}
int KChart::TextBubbleLayoutItem::borderWidth() const
{
return 1;
}
KChart::TextLayoutItem::TextLayoutItem( const QString& text,
const KChart::TextAttributes& attributes,
const QObject* area,
KChartEnums::MeasureOrientation orientation,
Qt::Alignment alignment )
: AbstractLayoutItem( alignment )
, mText( text )
, mTextAlignment( alignment )
, mAttributes( attributes )
, mAutoReferenceArea( area )
, mAutoReferenceOrientation( orientation )
, cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
, cachedFontSize( 0.0 )
, cachedFont( mAttributes.font() )
{
}
KChart::TextLayoutItem::TextLayoutItem()
: AbstractLayoutItem( Qt::AlignLeft )
, mText()
, mTextAlignment( Qt::AlignLeft )
, mAttributes()
, mAutoReferenceArea( 0 )
, mAutoReferenceOrientation( KChartEnums::MeasureOrientationHorizontal )
, cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
, cachedFontSize( 0.0 )
, cachedFont( mAttributes.font() )
{
}
void KChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
{
mAutoReferenceArea = area;
cachedSizeHint = QSize();
sizeHint();
}
const QObject* KChart::TextLayoutItem::autoReferenceArea() const
{
return mAutoReferenceArea;
}
void KChart::TextLayoutItem::setText(const QString & text)
{
mText = text;
cachedSizeHint = QSize();
sizeHint();
if ( mParent )
mParent->update();
}
QString KChart::TextLayoutItem::text() const
{
return mText;
}
void KChart::TextLayoutItem::setTextAlignment( Qt::Alignment alignment)
{
if ( mTextAlignment == alignment )
return;
mTextAlignment = alignment;
if ( mParent )
mParent->update();
}
Qt::Alignment KChart::TextLayoutItem::textAlignment() const
{
return mTextAlignment;
}
/**
\brief Use this to specify the text attributes to be used for this item.
\sa textAttributes
*/
void KChart::TextLayoutItem::setTextAttributes( const TextAttributes &a )
{
mAttributes = a;
cachedFont = a.font();
cachedSizeHint = QSize(); // invalidate size hint
sizeHint();
if ( mParent )
mParent->update();
}
/**
Returns the text attributes to be used for this item.
\sa setTextAttributes
*/
KChart::TextAttributes KChart::TextLayoutItem::textAttributes() const
{
return mAttributes;
}
Qt::Orientations KChart::TextLayoutItem::expandingDirections() const
{
- return 0; // Grow neither vertically nor horizontally
+ return Qt::Orientations(); // Grow neither vertically nor horizontally
}
QRect KChart::TextLayoutItem::geometry() const
{
return mRect;
}
bool KChart::TextLayoutItem::isEmpty() const
{
return false; // never empty, otherwise the layout item would not exist
}
QSize KChart::TextLayoutItem::maximumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
QSize KChart::TextLayoutItem::minimumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
void KChart::TextLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
// returns the bounding box of rect rotated around its center
QRectF rotatedRect( const QRectF& rect, qreal rotation )
{
QTransform t;
QPointF center = rect.center();
t.translate( center.x(), center.y() );
t.rotate( rotation );
t.translate( -center.x(), -center.y() );
return t.mapRect( rect );
}
qreal KChart::TextLayoutItem::fitFontSizeToGeometry() const
{
QFont f = realFont();
const qreal origResult = f.pointSizeF();
qreal result = origResult;
const qreal minSize = mAttributes.minimalFontSize().value();
const QSize mySize = geometry().size();
if ( mySize.isNull() ) {
return result;
}
QFontMetrics fm( f );
while ( true ) {
const QSizeF textSize = rotatedRect( fm.boundingRect( mText ), mAttributes.rotation() ).normalized().size();
if ( textSize.height() <= mySize.height() && textSize.width() <= mySize.width() ) {
return result;
}
result -= 0.5;
if ( minSize > 0 && result < minSize ) {
return result + 0.5;
} else if ( result <= 0.0 ) {
return origResult;
}
f.setPointSizeF( result );
fm = QFontMetrics( f );
}
}
qreal KChart::TextLayoutItem::realFontSize() const
{
return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
}
bool KChart::TextLayoutItem::maybeUpdateRealFont() const
{
const qreal fntSiz = realFontSize();
const bool doUpdate = !cachedSizeHint.isValid() || cachedFontSize != fntSiz;
if ( doUpdate && fntSiz > 0.0 ) {
cachedFontSize = fntSiz;
cachedFont.setPointSizeF( fntSiz );
}
return doUpdate; // "didUpdate" by now
}
QFont KChart::TextLayoutItem::realFont() const
{
maybeUpdateRealFont();
return cachedFont;
}
QPolygon KChart::TextLayoutItem::boundingPolygon() const
{
// should probably call sizeHint() here, but that one is expensive (see TODO there)
return mCachedBoundingPolygon;
}
bool KChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
{
return intersects( other, myPos.toPoint(), otherPos.toPoint() );
}
bool KChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const
{
QRegion myRegion( boundingPolygon().translated( myPos - otherPos ) );
QRegion otherRegion( other.boundingPolygon() );
return myRegion.intersects( otherRegion );
}
QSize KChart::TextLayoutItem::sizeHint() const
{
// ### we only really need to recalculate the size hint when mAttributes.rotation has *changed*
if ( maybeUpdateRealFont() || mAttributes.rotation() || !cachedSizeHint.isValid() ) {
const QSize newSizeHint( calcSizeHint( cachedFont ) );
Q_ASSERT( newSizeHint.isValid() );
if ( newSizeHint != cachedSizeHint ) {
cachedSizeHint = newSizeHint;
sizeHintChanged();
}
}
return cachedSizeHint;
}
QSize KChart::TextLayoutItem::sizeHintUnrotated() const
{
maybeUpdateRealFont(); // make sure the cached font is up to date
return unrotatedSizeHint( cachedFont );
}
// PENDING(kalle) Support auto shrink
QSize KChart::TextLayoutItem::unrotatedTextSize( QFont fnt ) const
{
if ( fnt == QFont() ) {
fnt = realFont(); // this is the cached font in most cases
}
const QFontMetricsF fm( fnt, GlobalMeasureScaling::paintDevice() );
QRect veryLarge( 0, 0, 100000, 100000 );
// this overload of boundingRect() interprets \n as line breaks, not as regular characters.
return fm.boundingRect( veryLarge, Qt::AlignLeft | Qt::AlignTop, mText ).size().toSize();
}
int KChart::TextLayoutItem::marginWidth() const
{
return marginWidth( unrotatedTextSize() );
}
int KChart::TextLayoutItem::marginWidth( const QSize& textSize ) const
{
return qMin ( QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 ),
// decrease frame size if the text is small
textSize.height() * 2 / 3 );
}
QSize KChart::TextLayoutItem::unrotatedSizeHint( const QFont& fnt ) const
{
QSize ret = unrotatedTextSize( fnt );
const int margin = marginWidth( ret );
ret += QSize( margin, margin );
return ret;
}
QSize KChart::TextLayoutItem::calcSizeHint( const QFont& font ) const
{
const QSize size = unrotatedSizeHint( font );
QPoint topLeft( -size.width() * 0.5, -size.height() * 0.5 );
if ( !mAttributes.rotation() ) {
mCachedBoundingPolygon.resize( 4 );
// using the same winding order as returned by QPolygon QTransform::mapToPolygon(const QRect&),
// which is: 0-1: top edge, 1-2: right edge, 2-3: bottom edge, 3-0: left edge (of input rect)
mCachedBoundingPolygon[ 0 ] = topLeft;
mCachedBoundingPolygon[ 1 ] = topLeft + QPoint( size.width(), 0 ); // top right
mCachedBoundingPolygon[ 2 ] = topLeft + QPoint( size.width(), size.height() ); // bottom right
mCachedBoundingPolygon[ 3 ] = topLeft + QPoint( 0, size.height() ); // bottom left
return size;
}
const QRect rect( topLeft, size );
QTransform t;
t.rotate( mAttributes.rotation() );
mCachedBoundingPolygon = t.mapToPolygon( rect );
return mCachedBoundingPolygon.boundingRect().size();
}
void KChart::TextLayoutItem::paint( QPainter* painter )
{
if ( !mRect.isValid() ) {
return;
}
const PainterSaver painterSaver( painter );
QFont f = realFont();
if ( mAttributes.autoShrink() ) {
f.setPointSizeF( fitFontSizeToGeometry() );
}
painter->setFont( f );
QSize innerSize = unrotatedTextSize();
QRectF rect = QRectF( QPointF( 0, 0 ), innerSize );
rect.translate( -rect.center() );
painter->translate( mRect.center() );
painter->rotate( mAttributes.rotation() );
#ifdef DEBUG_ITEMS_PAINT
painter->setPen( Qt::red );
painter->drawRect( rect );
#endif
painter->setPen( PrintingParameters::scalePen( mAttributes.pen() ) );
QTextDocument* document = mAttributes.textDocument();
if ( document ) {
document->setPageSize( rect.size() );
document->setHtml( mText );
QAbstractTextDocumentLayout::PaintContext paintcontext;
// ### this doesn't work for rotated painting because clip does not translate the painting
// TODO translate the painting either using a QTransform or one of QPainter's transform stages
paintcontext.clip = rect;
document->documentLayout()->draw( painter, paintcontext );
} else {
painter->drawText( rect, mTextAlignment, mText );
}
}
KChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
: AbstractLayoutItem( Qt::AlignCenter )
{
}
Qt::Orientations KChart::HorizontalLineLayoutItem::expandingDirections() const
{
return Qt::Horizontal;
}
QRect KChart::HorizontalLineLayoutItem::geometry() const
{
return mRect;
}
bool KChart::HorizontalLineLayoutItem::isEmpty() const
{
return false; // never empty, otherwise the layout item would not exist
}
QSize KChart::HorizontalLineLayoutItem::maximumSize() const
{
return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
}
QSize KChart::HorizontalLineLayoutItem::minimumSize() const
{
return QSize( 0, 0 );
}
void KChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
QSize KChart::HorizontalLineLayoutItem::sizeHint() const
{
return QSize( -1, 3 ); // see qframe.cpp
}
void KChart::HorizontalLineLayoutItem::paint( QPainter* painter )
{
if ( !mRect.isValid() )
return;
painter->drawLine( QPointF( mRect.left(), mRect.center().y() ),
QPointF( mRect.right(), mRect.center().y() ) );
}
KChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
: AbstractLayoutItem( Qt::AlignCenter )
{
}
Qt::Orientations KChart::VerticalLineLayoutItem::expandingDirections() const
{
return Qt::Vertical;
}
QRect KChart::VerticalLineLayoutItem::geometry() const
{
return mRect;
}
bool KChart::VerticalLineLayoutItem::isEmpty() const
{
return false; // never empty, otherwise the layout item would not exist
}
QSize KChart::VerticalLineLayoutItem::maximumSize() const
{
return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
}
QSize KChart::VerticalLineLayoutItem::minimumSize() const
{
return QSize( 0, 0 );
}
void KChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
QSize KChart::VerticalLineLayoutItem::sizeHint() const
{
return QSize( 3, -1 ); // see qframe.cpp
}
void KChart::VerticalLineLayoutItem::paint( QPainter* painter )
{
if ( !mRect.isValid() )
return;
painter->drawLine( QPointF( mRect.center().x(), mRect.top() ),
QPointF( mRect.center().x(), mRect.bottom() ) );
}
KChart::MarkerLayoutItem::MarkerLayoutItem( KChart::AbstractDiagram* diagram,
const MarkerAttributes& marker,
const QBrush& brush, const QPen& pen,
Qt::Alignment alignment )
: AbstractLayoutItem( alignment )
, mDiagram( diagram )
, mMarker( marker )
, mBrush( brush )
, mPen( pen )
{
}
Qt::Orientations KChart::MarkerLayoutItem::expandingDirections() const
{
- return 0; // Grow neither vertically nor horizontally
+ return Qt::Orientations(); // Grow neither vertically nor horizontally
}
QRect KChart::MarkerLayoutItem::geometry() const
{
return mRect;
}
bool KChart::MarkerLayoutItem::isEmpty() const
{
return false; // never empty, otherwise the layout item would not exist
}
QSize KChart::MarkerLayoutItem::maximumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
QSize KChart::MarkerLayoutItem::minimumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
void KChart::MarkerLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
QSize KChart::MarkerLayoutItem::sizeHint() const
{
//qDebug() << "KChart::MarkerLayoutItem::sizeHint() returns:"<(( rect.width() - siz.width()) / 2.0 ),
static_cast(( rect.height() - siz.height()) / 2.0 ) );
#ifdef DEBUG_ITEMS_PAINT
QPointF oldPos = pos;
#endif
// And finally, drawMarker() assumes the position to be the center
// of the marker, adjust again.
pos += QPointF( static_cast( siz.width() ) / 2.0,
static_cast( siz.height() )/ 2.0 );
diagram->paintMarker( painter, marker, brush, pen, pos.toPoint(), siz );
#ifdef DEBUG_ITEMS_PAINT
const QPen oldPen( painter->pen() );
painter->setPen( Qt::red );
painter->drawRect( QRect( oldPos.toPoint(), siz ) );
painter->setPen( oldPen );
#endif
}
KChart::LineLayoutItem::LineLayoutItem( KChart::AbstractDiagram* diagram,
int length,
const QPen& pen,
Qt::Alignment legendLineSymbolAlignment,
Qt::Alignment alignment )
: AbstractLayoutItem( alignment )
, mDiagram( diagram )
, mLength( length )
, mPen( pen )
, mLegendLineSymbolAlignment(legendLineSymbolAlignment)
{
// enforce a minimum pen width
if ( pen.width() < 2 )
mPen.setWidth( 2 );
}
Qt::Orientations KChart::LineLayoutItem::expandingDirections() const
{
- return 0; // Grow neither vertically nor horizontally
+ return Qt::Orientations(); // Grow neither vertically nor horizontally
}
QRect KChart::LineLayoutItem::geometry() const
{
return mRect;
}
bool KChart::LineLayoutItem::isEmpty() const
{
return false; // never empty, otherwise the layout item would not exist
}
QSize KChart::LineLayoutItem::maximumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
QSize KChart::LineLayoutItem::minimumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
void KChart::LineLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
QSize KChart::LineLayoutItem::sizeHint() const
{
return QSize( mLength, mPen.width() + 2 );
}
void KChart::LineLayoutItem::setLegendLineSymbolAlignment(Qt::Alignment legendLineSymbolAlignment)
{
if (mLegendLineSymbolAlignment == legendLineSymbolAlignment)
return;
mLegendLineSymbolAlignment = legendLineSymbolAlignment;
}
Qt::Alignment KChart::LineLayoutItem::legendLineSymbolAlignment() const
{
return mLegendLineSymbolAlignment;
}
void KChart::LineLayoutItem::paint( QPainter* painter )
{
paintIntoRect( painter, mRect, mPen, mLegendLineSymbolAlignment );
}
void KChart::LineLayoutItem::paintIntoRect(
QPainter* painter,
const QRect& rect,
const QPen& pen,
Qt::Alignment lineAlignment)
{
if ( ! rect.isValid() )
return;
const QPen oldPen = painter->pen();
painter->setPen( PrintingParameters::scalePen( pen ) );
qreal y = 0;
if (lineAlignment == Qt::AlignTop)
y = rect.top();
else if (lineAlignment == Qt::AlignBottom)
y = rect.bottom();
else
y = rect.center().y();
painter->drawLine( QPointF( rect.left(), y ),
QPointF( rect.right(), y ) );
painter->setPen( oldPen );
}
KChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
KChart::AbstractDiagram* diagram,
int lineLength,
const QPen& linePen,
int markerOffs,
const MarkerAttributes& marker,
const QBrush& markerBrush,
const QPen& markerPen,
Qt::Alignment alignment )
: AbstractLayoutItem( alignment )
, mDiagram( diagram )
, mLineLength( lineLength )
, mLinePen( linePen )
, mMarkerOffs( markerOffs )
, mMarker( marker )
, mMarkerBrush( markerBrush )
, mMarkerPen( markerPen )
{
}
Qt::Orientations KChart::LineWithMarkerLayoutItem::expandingDirections() const
{
- return 0; // Grow neither vertically nor horizontally
+ return Qt::Orientations(); // Grow neither vertically nor horizontally
}
QRect KChart::LineWithMarkerLayoutItem::geometry() const
{
return mRect;
}
bool KChart::LineWithMarkerLayoutItem::isEmpty() const
{
return false; // never empty, otherwise the layout item would not exist
}
QSize KChart::LineWithMarkerLayoutItem::maximumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
QSize KChart::LineWithMarkerLayoutItem::minimumSize() const
{
return sizeHint(); // PENDING(kalle) Review, quite inflexible
}
void KChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
QSize KChart::LineWithMarkerLayoutItem::sizeHint() const
{
const QSize lineSize( mLineLength, mLinePen.width() + 2 );
return lineSize.expandedTo( mMarker.markerSize().toSize() );
}
void KChart::LineWithMarkerLayoutItem::paint( QPainter* painter )
{
// paint the line over the full width, into the vertical middle of the rect
LineLayoutItem::paintIntoRect( painter, mRect, mLinePen, Qt::AlignCenter );
// paint the marker with the given offset from the left side of the line
const QRect r(
QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
MarkerLayoutItem::paintIntoRect(
painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
}
KChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout )
: AbstractLayoutItem( Qt::AlignCenter )
, mLayoutIsAtTopPosition( layoutIsAtTopPosition )
, mRightLeftLayout( rightLeftLayout )
, mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
, mTopBottomLayout( topBottomLayout )
{
}
Qt::Orientations KChart::AutoSpacerLayoutItem::expandingDirections() const
{
- return 0; // Grow neither vertically nor horizontally
+ return Qt::Orientations(); // Grow neither vertically nor horizontally
}
QRect KChart::AutoSpacerLayoutItem::geometry() const
{
return mRect;
}
bool KChart::AutoSpacerLayoutItem::isEmpty() const
{
return true; // never empty, otherwise the layout item would not exist
}
QSize KChart::AutoSpacerLayoutItem::maximumSize() const
{
return sizeHint();
}
QSize KChart::AutoSpacerLayoutItem::minimumSize() const
{
return sizeHint();
}
void KChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
{
mRect = r;
}
static void updateCommonBrush( QBrush& commonBrush, bool& bStart, const KChart::AbstractArea& area )
{
const KChart::BackgroundAttributes ba( area.backgroundAttributes() );
const bool hasSimpleBrush = (
! area.frameAttributes().isVisible() &&
ba.isVisible() &&
ba.pixmapMode() == KChart::BackgroundAttributes::BackgroundPixmapModeNone &&
ba.brush().gradient() == 0 );
if ( bStart ) {
bStart = false;
commonBrush = hasSimpleBrush ? ba.brush() : QBrush();
} else {
if ( ! hasSimpleBrush || ba.brush() != commonBrush )
{
commonBrush = QBrush();
}
}
}
QSize KChart::AutoSpacerLayoutItem::sizeHint() const
{
QBrush commonBrush;
bool bStart=true;
// calculate the maximal overlap of the top/bottom axes:
int topBottomOverlap = 0;
if ( mTopBottomLayout ) {
for (int i = 0; i < mTopBottomLayout->count(); ++i) {
AbstractArea* area = dynamic_cast(mTopBottomLayout->itemAt(i));
if ( area ) {
//qDebug() << "AutoSpacerLayoutItem testing" << area;
topBottomOverlap = qMax( topBottomOverlap,
mLayoutIsAtLeftPosition ? area->rightOverlap()
: area->leftOverlap() );
updateCommonBrush( commonBrush, bStart, *area );
}
}
}
// calculate the maximal overlap of the left/right axes:
int leftRightOverlap = 0;
if ( mRightLeftLayout ) {
for (int i = 0; i < mRightLeftLayout->count(); ++i) {
AbstractArea* area = dynamic_cast(mRightLeftLayout->itemAt(i));
if ( area ) {
//qDebug() << "AutoSpacerLayoutItem testing" << area;
leftRightOverlap = qMax( leftRightOverlap,
mLayoutIsAtTopPosition ? area->bottomOverlap()
: area->topOverlap() );
updateCommonBrush( commonBrush, bStart, *area );
}
}
}
if ( topBottomOverlap > 0 && leftRightOverlap > 0 )
mCommonBrush = commonBrush;
else
mCommonBrush = QBrush();
mCachedSize = QSize( topBottomOverlap, leftRightOverlap );
//qDebug() << mCachedSize;
return mCachedSize;
}
void KChart::AutoSpacerLayoutItem::paint( QPainter* painter )
{
if ( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
mCommonBrush.style() != Qt::NoBrush )
{
QPoint p1( mRect.topLeft() );
QPoint p2( mRect.bottomRight() );
if ( mLayoutIsAtLeftPosition )
p1.rx() += mCachedSize.width() - mParentLayout->spacing();
else
p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
if ( mLayoutIsAtTopPosition ) {
p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
p2.ry() -= 1;
} else
p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
//qDebug() << mLayoutIsAtTopPosition << mLayoutIsAtLeftPosition;
//qDebug() << mRect;
//qDebug() << mParentLayout->margin();
//qDebug() << QRect( p1, p2 );
const QPoint oldBrushOrigin( painter->brushOrigin() );
const QBrush oldBrush( painter->brush() );
const QPen oldPen( painter->pen() );
const QPointF newTopLeft( painter->deviceMatrix().map( p1 ) );
painter->setBrushOrigin( newTopLeft );
painter->setBrush( mCommonBrush );
painter->setPen( Qt::NoPen );
painter->drawRect( QRect( p1, p2 ) );
painter->setBrushOrigin( oldBrushOrigin );
painter->setBrush( oldBrush );
painter->setPen( oldPen );
}
// debug code:
#if 0
//qDebug() << "KChart::AutoSpacerLayoutItem::paint()";
if ( !mRect.isValid() )
return;
painter->drawRect( mRect );
painter->drawLine( QPointF( mRect.topLeft(), mRect.bottomRight() ) );
painter->drawLine( QPointF( mRect.topRight(), mRect.bottomLeft() ) );
#endif
}
diff --git a/src/KChart/KChartLayoutItems.h b/src/KChart/KChartLayoutItems.h
index 5e9dfff..2437457 100644
--- a/src/KChart/KChartLayoutItems.h
+++ b/src/KChart/KChartLayoutItems.h
@@ -1,476 +1,476 @@
/*
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KD Chart library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef KCHARTLAYOUTITEMS_H
#define KCHARTLAYOUTITEMS_H
#include
#include
#include
#include
#include
#include
#include "KChartTextAttributes.h"
#include "KChartMarkerAttributes.h"
QT_BEGIN_NAMESPACE
class QPainter;
class KTextDocument;
QT_END_NAMESPACE
// TODO remove
QRectF rotatedRect( const QRectF& pt, qreal rotation );
namespace KChart {
class AbstractDiagram;
class PaintContext;
/**
* Base class for all layout items of KChart
* \internal
*/
class KCHART_EXPORT AbstractLayoutItem : public QLayoutItem
{
public:
- AbstractLayoutItem( Qt::Alignment itemAlignment = 0 ) :
+ AbstractLayoutItem( Qt::Alignment itemAlignment = Qt::Alignment() ) :
QLayoutItem( itemAlignment ),
mParent( 0 ),
mParentLayout( 0 ) {}
/**
* Default impl: just call paint.
*
* Derived classes like KChart::AbstractArea are providing
* additional action here.
*/
virtual void paintAll( QPainter& painter );
virtual void paint( QPainter* ) = 0;
virtual void paintCtx( PaintContext* context );
virtual void setParentWidget( QWidget* widget );
virtual void sizeHintChanged() const;
void setParentLayout( QLayout* lay )
{
mParentLayout = lay;
}
QLayout* parentLayout()
{
return mParentLayout;
}
void removeFromParentLayout()
{
if ( mParentLayout ) {
if ( widget() )
mParentLayout->removeWidget( widget() );
else
mParentLayout->removeItem( this );
}
}
protected:
QWidget* mParent;
QLayout* mParentLayout;
};
/**
* Layout item showing a text
*\internal
*/
class KCHART_EXPORT TextLayoutItem : public AbstractLayoutItem
{
public:
TextLayoutItem();
TextLayoutItem( const QString& text,
const TextAttributes& attributes,
const QObject* autoReferenceArea,
KChartEnums::MeasureOrientation autoReferenceOrientation,
- Qt::Alignment alignment = 0 );
+ Qt::Alignment alignment = Qt::Alignment() );
void setAutoReferenceArea( const QObject* area );
const QObject* autoReferenceArea() const;
void setText(const QString & text);
QString text() const;
void setTextAlignment( Qt::Alignment );
Qt::Alignment textAlignment() const;
void setTextAttributes( const TextAttributes& a );
TextAttributes textAttributes() const;
/** pure virtual in QLayoutItem */
bool isEmpty() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QSize maximumSize() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QSize minimumSize() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QSize sizeHint() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QRect geometry() const Q_DECL_OVERRIDE;
virtual int marginWidth() const;
virtual QSize sizeHintUnrotated() const;
virtual bool intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const;
virtual bool intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const;
virtual qreal realFontSize() const;
virtual QFont realFont() const;
void paint( QPainter* ) Q_DECL_OVERRIDE;
QPolygon boundingPolygon() const;
private:
bool maybeUpdateRealFont() const;
QSize unrotatedSizeHint( const QFont& fnt = QFont() ) const;
QSize unrotatedTextSize( QFont fnt = QFont() ) const;
QSize calcSizeHint( const QFont& font ) const;
int marginWidth( const QSize& textSize ) const;
qreal fitFontSizeToGeometry() const;
QRect mRect;
QString mText;
Qt::Alignment mTextAlignment;
TextAttributes mAttributes;
const QObject* mAutoReferenceArea;
KChartEnums::MeasureOrientation mAutoReferenceOrientation;
mutable QSize cachedSizeHint;
mutable QPolygon mCachedBoundingPolygon;
mutable qreal cachedFontSize;
mutable QFont cachedFont;
};
class KCHART_EXPORT TextBubbleLayoutItem : public AbstractLayoutItem
{
public:
TextBubbleLayoutItem();
TextBubbleLayoutItem( const QString& text,
const TextAttributes& attributes,
const QObject* autoReferenceArea,
KChartEnums::MeasureOrientation autoReferenceOrientation,
- Qt::Alignment alignment = 0 );
+ Qt::Alignment alignment = Qt::Alignment() );
~TextBubbleLayoutItem();
void setAutoReferenceArea( const QObject* area );
const QObject* autoReferenceArea() const;
void setText(const QString & text);
QString text() const;
void setTextAttributes( const TextAttributes& a );
TextAttributes textAttributes() const;
/** pure virtual in QLayoutItem */
bool isEmpty() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QSize maximumSize() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QSize minimumSize() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QSize sizeHint() const Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
/** pure virtual in QLayoutItem */
QRect geometry() const Q_DECL_OVERRIDE;
void paint( QPainter* painter ) Q_DECL_OVERRIDE;
protected:
int borderWidth() const;
private:
TextLayoutItem* const m_text;
};
/**
* Layout item showing a data point marker
* \internal
*/
class KCHART_EXPORT MarkerLayoutItem : public AbstractLayoutItem
{
public:
MarkerLayoutItem( AbstractDiagram* diagram,
const MarkerAttributes& marker,
const QBrush& brush,
const QPen& pen,
- Qt::Alignment alignment = 0 );
+ Qt::Alignment alignment = Qt::Alignment() );
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
bool isEmpty() const Q_DECL_OVERRIDE;
QSize maximumSize() const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
void paint( QPainter* ) Q_DECL_OVERRIDE;
static void paintIntoRect(
QPainter* painter,
const QRect& rect,
AbstractDiagram* diagram,
const MarkerAttributes& marker,
const QBrush& brush,
const QPen& pen );
private:
AbstractDiagram* mDiagram;
QRect mRect;
MarkerAttributes mMarker;
QBrush mBrush;
QPen mPen;
};
/**
* Layout item showing a coloured line
* \internal
*/
class KCHART_EXPORT LineLayoutItem : public AbstractLayoutItem
{
public:
LineLayoutItem( AbstractDiagram* diagram,
int length,
const QPen& pen,
Qt::Alignment mLegendLineSymbolAlignment,
- Qt::Alignment alignment = 0 );
+ Qt::Alignment alignment = Qt::Alignment() );
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
bool isEmpty() const Q_DECL_OVERRIDE;
QSize maximumSize() const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
void setLegendLineSymbolAlignment(Qt::Alignment legendLineSymbolAlignment);
virtual Qt::Alignment legendLineSymbolAlignment() const;
void paint( QPainter* ) Q_DECL_OVERRIDE;
static void paintIntoRect(
QPainter* painter,
const QRect& rect,
const QPen& pen,
Qt::Alignment lineAlignment);
private:
AbstractDiagram* mDiagram; //TODO: not used. remove it
int mLength;
QPen mPen;
QRect mRect;
Qt::Alignment mLegendLineSymbolAlignment;
};
/**
* Layout item showing a coloured line and a data point marker
* \internal
*/
class KCHART_EXPORT LineWithMarkerLayoutItem : public AbstractLayoutItem
{
public:
LineWithMarkerLayoutItem( AbstractDiagram* diagram,
int lineLength,
const QPen& linePen,
int markerOffs,
const MarkerAttributes& marker,
const QBrush& markerBrush,
const QPen& markerPen,
- Qt::Alignment alignment = 0 );
+ Qt::Alignment alignment = Qt::Alignment() );
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
bool isEmpty() const Q_DECL_OVERRIDE;
QSize maximumSize() const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
void paint( QPainter* ) Q_DECL_OVERRIDE;
private:
AbstractDiagram* mDiagram;
QRect mRect;
int mLineLength;
QPen mLinePen;
int mMarkerOffs;
MarkerAttributes mMarker;
QBrush mMarkerBrush;
QPen mMarkerPen;
};
/**
* Layout item showing a horizontal line
* \internal
*/
class KCHART_EXPORT HorizontalLineLayoutItem : public AbstractLayoutItem
{
public:
HorizontalLineLayoutItem();
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
bool isEmpty() const Q_DECL_OVERRIDE;
QSize maximumSize() const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
void paint( QPainter* ) Q_DECL_OVERRIDE;
private:
QRect mRect;
};
/**
* Layout item showing a vertial line
* \internal
*/
class KCHART_EXPORT VerticalLineLayoutItem : public AbstractLayoutItem
{
public:
VerticalLineLayoutItem();
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
bool isEmpty() const Q_DECL_OVERRIDE;
QSize maximumSize() const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
void paint( QPainter* ) Q_DECL_OVERRIDE;
private:
QRect mRect;
};
/**
* @brief An empty layout item
* \internal
*
* The AutoSpacerLayoutItem is automatically put into each corner cell of
* the planeLayout grid: one of its reference-layouts is a QVBoxLayout (for
* the top, or bottom axes resp.), the other one is a QHBoxLayout (for the
* left/right sided axes).
*
* The spacer reserves enough space so all of the AbstractAreas contained
* in the two reference-layouts can display not only their in-bounds
* content but also their overlapping content reaching out of their area.
*
* KChart's layouting is applying this schema:
\verbatim
+------------------+-------------------------+-----------------+
| +--------------+ | +---------------------+ | +-------------+ |
| | | | | QVBoxLayout for | | | | |
| | AUTO | | | the top axis/axes | | | AUTO | |
| | SPACER | | +---------------------+ | | SPACER | |
| | ITEM | | | | | | ITEM | |
| | | | | | | | | |
| +--------------+ | +---------------------+ | +-------------+ |
+------------------+-------------------------+-----------------+
| +--------+-----+ | +---------------------+ | +-------+-----+ |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | QHBox- | | | | | | | Right | | |
| | Layout | | | | | | | | | |
| | | | | | | | | axes | | |
| | for | | | | | | | | | |
| | | | | | | | | layout| | |
| | the | | | | DIAGRAM(s) | | | | | |
| | | | | | | | | | | |
| | left | | | | | | | | | |
| | | | | | | | | | | |
| | axis | | | | | | | | | |
| | or | | | | | | | | | |
| | axes | | | | | | | | | |
| | | | | | | | | | | |
| +--------+-----+ | +---------------------+ | +-------+-----+ |
+------------------+-------------------------+-----------------+
| +--------------+ | +---------------------+ | +-------------+ |
| | | | | QVBoxLayout for | | | | |
| | AUTO | | | the bottom axes | | | AUTO | |
| | SPACER | | +---------------------+ | | SPACER | |
| | ITEM | | | | | | ITEM | |
| | | | | | | | | |
| +--------------+ | +---------------------+ | +-------------+ |
+------------------+-------------------------+-----------------+
\endverbatim
*
* A typical use case is an Abscissa axis with long labels:
\verbatim
2 -|
|
1 -|
|
0 -+------------------------------------
| | | | |
Monday Tuesday Wednesday Thursday Friday
\endverbatim
* The last letters of the word "Friday" would have been
* cut off in previous versions of KChart - that is
* if you did not call KChart::Chart::setGlobalLeading().
*
* Now the word will be shown completely because there
* is an auto-spacer-item taking care for the additional
* space needed in the lower/right corner.
*/
class KCHART_EXPORT AutoSpacerLayoutItem : public AbstractLayoutItem
{
public:
AutoSpacerLayoutItem(
bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout );
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
QRect geometry() const Q_DECL_OVERRIDE;
bool isEmpty() const Q_DECL_OVERRIDE;
QSize maximumSize() const Q_DECL_OVERRIDE;
QSize minimumSize() const Q_DECL_OVERRIDE;
void setGeometry( const QRect& r ) Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
void paint( QPainter* ) Q_DECL_OVERRIDE;
private:
QRect mRect;
bool mLayoutIsAtTopPosition;
QHBoxLayout *mRightLeftLayout;
bool mLayoutIsAtLeftPosition;
QVBoxLayout *mTopBottomLayout;
mutable QBrush mCommonBrush;
mutable QSize mCachedSize;
};
}
#endif /* KCHARTLAYOUTITEMS_H */
diff --git a/tests/Gantt/apireview/entrydialog.h b/tests/Gantt/apireview/entrydialog.h
index 44db3d6..d6c03df 100644
--- a/tests/Gantt/apireview/entrydialog.h
+++ b/tests/Gantt/apireview/entrydialog.h
@@ -1,67 +1,67 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef ENTRYDIALOG_H
#define ENTRYDIALOG_H
#include
#include
#include
QT_BEGIN_NAMESPACE
class QAbstractItemModel;
namespace Ui {
class EntryDialog;
}
QT_END_NAMESPACE
namespace KGantt {
class ConstraintModel;
}
class EntryDialog : public QDialog {
Q_OBJECT
public:
- EntryDialog( const QAbstractItemModel* model, QWidget* parent = 0, Qt::WindowFlags f = 0 );
+ EntryDialog( const QAbstractItemModel* model, QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags() );
void initFrom( const QModelIndex& index, const KGantt::ConstraintModel* constraintModel );
QString name() const;
int type() const;
QDateTime startDate() const;
QDateTime endDate() const;
int completion() const;
bool readOnly() const;
QModelIndex depends() const;
QString legend() const;
private slots:
void updateEndDate( const QDateTime& startDate );
void disableEditing( bool disable );
private:
void init();
void addDependItem( const QAbstractItemModel* model, const QModelIndex& index, int indent = 0 );
QList indexList;
const QAbstractItemModel* model;
Ui::EntryDialog* ui;
};
#endif /* ENTRYDIALOG_H */
diff --git a/tests/Gantt/apireview/mainwindow.h b/tests/Gantt/apireview/mainwindow.h
index 64f727f..1657126 100644
--- a/tests/Gantt/apireview/mainwindow.h
+++ b/tests/Gantt/apireview/mainwindow.h
@@ -1,83 +1,83 @@
/**
* Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
*
* This file is part of the KGantt library.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
QT_BEGIN_NAMESPACE
class QStandardItem;
class QStandardItemModel;
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
namespace KGantt {
class ConstraintModel;
class DateTimeGrid;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
- MainWindow( QWidget * parent = 0, Qt::WindowFlags flags = 0 );
+ MainWindow( QWidget * parent = 0, Qt::WindowFlags flags = Qt::WindowFlags() );
private slots:
void addNewEntry();
void removeEntry();
void addDemoEntry();
void printPreview();
void showContextMenu( const QPoint& );
void enableActions( const QItemSelection& selected );
void zoomIn();
void zoomOut();
void slotClicked( const QModelIndex& );
void slotDoubleClicked( const QModelIndex& );
private:
void initModel();
void initActions();
void initItemDelegate();
void initGrid();
void setReadOnly( const QModelIndex& index, bool readOnly );
void addConstraint( const QModelIndex& index1, const QModelIndex& index2 );
void addConstraint( const QStandardItem* item1, const QStandardItem* item2 );
QStandardItemModel* model;
KGantt::ConstraintModel* constraintModel;
KGantt::DateTimeGrid* grid;
int dayWidth;
QAction* newEntryAction;
QAction* removeEntryAction;
QAction* demoAction;
QAction* printAction;
QAction* zoomInAction;
QAction* zoomOutAction;
Ui::MainWindow* ui;
};
#endif /* MAINWINDOW_H */