/****************************************************************************+ −
**+ −
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (qt-info@nokia.com)+ −
**+ −
** This file is part of the Qt3Support module of the Qt Toolkit.+ −
**+ −
** $QT_BEGIN_LICENSE:LGPL$+ −
** No Commercial Usage+ −
** This file contains pre-release code and may not be distributed.+ −
** You may use this file in accordance with the terms and conditions+ −
** contained in the Technology Preview License Agreement accompanying+ −
** this package.+ −
**+ −
** GNU Lesser General Public License Usage+ −
** Alternatively, this file may be used under the terms of the GNU Lesser+ −
** General Public License version 2.1 as published by the Free Software+ −
** Foundation and appearing in the file LICENSE.LGPL included in the+ −
** packaging of this file. Please review the following information to+ −
** ensure the GNU Lesser General Public License version 2.1 requirements+ −
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.+ −
**+ −
** In addition, as a special exception, Nokia gives you certain additional+ −
** rights. These rights are described in the Nokia Qt LGPL Exception+ −
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.+ −
**+ −
** If you have questions regarding the use of this file, please contact+ −
** Nokia at qt-info@nokia.com.+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
**+ −
** $QT_END_LICENSE$+ −
**+ −
****************************************************************************/+ −
+ −
#include "q3header.h"+ −
#ifndef QT_NO_HEADER+ −
#include "qapplication.h"+ −
#include "qbitarray.h"+ −
#include "qcursor.h"+ −
#include "qdrawutil.h"+ −
#include "qevent.h"+ −
#include "qpainter.h"+ −
#include "qpixmap.h"+ −
#include "qstyle.h"+ −
#include "qstyleoption.h"+ −
#include "qvector.h"+ −
+ −
QT_BEGIN_NAMESPACE+ −
+ −
class Q3HeaderData+ −
{+ −
public:+ −
Q3HeaderData(int n)+ −
{+ −
count = n;+ −
sizes.resize(n);+ −
positions.resize(n);+ −
labels.resize(n);+ −
nullStringLabels.resize(n);+ −
icons.resize(n);+ −
i2s.resize(n);+ −
s2i.resize(n);+ −
clicks.resize(n);+ −
resize.resize(n);+ −
int p =0;+ −
for (int i = 0; i < n; i ++) {+ −
sizes[i] = 88;+ −
i2s[i] = i;+ −
s2i[i] = i;+ −
positions[i] = p;+ −
p += sizes[i];+ −
}+ −
clicks_default = true;+ −
resize_default = true;+ −
clicks.fill(clicks_default);+ −
resize.fill(resize_default);+ −
move = true;+ −
sortSection = -1;+ −
sortDirection = true;+ −
positionsDirty = true;+ −
lastPos = 0;+ −
fullSize = -2;+ −
pos_dirty = false;+ −
is_a_table_header = false;+ −
focusIdx = 0;+ −
}+ −
~Q3HeaderData()+ −
{+ −
for (int i = 0; i < icons.size(); ++i)+ −
delete icons.at(i);+ −
}+ −
+ −
+ −
QVector<int> sizes;+ −
int height; // we abuse the heights as widths for vertical layout+ −
bool heightDirty;+ −
QVector<int> positions; // sorted by index+ −
QVector<QString> labels;+ −
QVector<QIcon *> icons;+ −
QVector<int> i2s;+ −
QVector<int> s2i;+ −
+ −
QBitArray clicks;+ −
QBitArray resize;+ −
QBitArray nullStringLabels;+ −
uint move : 1;+ −
uint clicks_default : 1; // default value for new clicks bits+ −
uint resize_default : 1; // default value for new resize bits+ −
uint pos_dirty : 1;+ −
uint is_a_table_header : 1;+ −
bool sortDirection;+ −
bool positionsDirty;+ −
int sortSection;+ −
int count;+ −
int lastPos;+ −
int fullSize;+ −
int focusIdx;+ −
int pressDelta;+ −
+ −
int sectionAt(int pos) {+ −
// positions is sorted by index, not by section+ −
if (!count)+ −
return -1;+ −
int l = 0;+ −
int r = count - 1;+ −
int i = ((l+r+1) / 2);+ −
while (r - l) {+ −
if (positions[i] > pos)+ −
r = i -1;+ −
else+ −
l = i;+ −
i = ((l+r+1) / 2);+ −
}+ −
if (positions[i] <= pos && pos <= positions[i] + sizes[i2s[i]])+ −
return i2s[i];+ −
return -1;+ −
}+ −
};+ −
+ −
static QStyleOptionHeader getStyleOption(const Q3Header *header, int section)+ −
{+ −
QStyleOptionHeader opt;+ −
opt.init(header);+ −
opt.section = section;+ −
opt.textAlignment = Qt::AlignVCenter;+ −
opt.iconAlignment = Qt::AlignVCenter;+ −
if (header->iconSet(section))+ −
opt.icon = *header->iconSet(section);+ −
opt.text = header->label(section);+ −
if (header->orientation() == Qt::Horizontal)+ −
opt.state = QStyle::State_Horizontal;+ −
return opt;+ −
}+ −
+ −
bool qt_get_null_label_bit(Q3HeaderData *data, int section)+ −
{+ −
return data->nullStringLabels.testBit(section);+ −
}+ −
+ −
void qt_set_null_label_bit(Q3HeaderData *data, int section, bool b)+ −
{+ −
data->nullStringLabels.setBit(section, b);+ −
}+ −
+ −
/*!+ −
\class Q3Header+ −
\brief The Q3Header class provides a header row or column, e.g. for+ −
tables and listviews.+ −
+ −
\compat+ −
+ −
This class provides a header, e.g. a vertical header to display+ −
row labels, or a horizontal header to display column labels. It is+ −
used by Q3Table and Q3ListView for example.+ −
+ −
A header is composed of one or more \e sections, each of which can+ −
display a text label and an \link QIcon icon\endlink. A sort+ −
indicator (an arrow) can also be displayed using+ −
setSortIndicator().+ −
+ −
Sections are added with addLabel() and removed with removeLabel().+ −
The label and icon are set in addLabel() and can be changed+ −
later with setLabel(). Use count() to retrieve the number of+ −
sections in the header.+ −
+ −
The orientation of the header is set with setOrientation(). If+ −
setStretchEnabled() is true, the sections will expand to take up+ −
the full width (height for vertical headers) of the header. The+ −
user can resize the sections manually if setResizeEnabled() is+ −
true. Call adjustHeaderSize() to have the sections resize to+ −
occupy the full width (or height).+ −
+ −
A section can be moved with moveSection(). If setMovingEnabled()+ −
is true (the default)the user may drag a section from one position+ −
to another. If a section is moved, the index positions at which+ −
sections were added (with addLabel()), may not be the same after the+ −
move. You don't have to worry about this in practice because the+ −
Q3Header API works in terms of section numbers, so it doesn't matter+ −
where a particular section has been moved to.+ −
+ −
If you want the current index position of a section call+ −
mapToIndex() giving it the section number. (This is the number+ −
returned by the addLabel() call which created the section.) If you+ −
want to get the section number of a section at a particular index+ −
position call mapToSection() giving it the index number.+ −
+ −
Here's an example to clarify mapToSection() and mapToIndex():+ −
+ −
\table+ −
\header \i41 Index positions+ −
\row \i 0 \i 1 \i 2 \i 3+ −
\header \i41 Original section ordering+ −
\row \i Sect 0 \i Sect 1 \i Sect 2 \i Sect 3+ −
\header \i41 Ordering after the user moves a section+ −
\row \i Sect 0 \i Sect 2 \i Sect 3 \i Sect 1+ −
\endtable+ −
+ −
\table+ −
\header \i \e k \i mapToSection(\e k) \i mapToIndex(\e k)+ −
\row \i 0 \i 0 \i 0+ −
\row \i 1 \i 2 \i 3+ −
\row \i 2 \i 3 \i 1+ −
\row \i 3 \i 1 \i 2+ −
\endtable+ −
+ −
In the example above, if we wanted to find out which section is at+ −
index position 3 we'd call mapToSection(3) and get a section+ −
number of 1 since section 1 was moved. Similarly, if we wanted to+ −
know which index position section 2 occupied we'd call+ −
mapToIndex(2) and get an index of 1.+ −
+ −
Q3Header provides the clicked(), pressed() and released() signals.+ −
If the user changes the size of a section, the sizeChange() signal+ −
is emitted. If you want to have a sizeChange() signal emitted+ −
continuously whilst the user is resizing (rather than just after+ −
the resizing is finished), use setTracking(). If the user moves a+ −
section the indexChange() signal is emitted.+ −
+ −
\sa Q3ListView Q3Table+ −
*/+ −
+ −
+ −
+ −
/*!+ −
Constructs a horizontal header called \a name, with parent \a+ −
parent.+ −
*/+ −
+ −
Q3Header::Q3Header(QWidget *parent, const char *name)+ −
: QWidget(parent, name, Qt::WStaticContents)+ −
{+ −
orient = Qt::Horizontal;+ −
init(0);+ −
}+ −
+ −
/*!+ −
Constructs a horizontal header called \a name, with \a n sections+ −
and parent \a parent.+ −
*/+ −
+ −
Q3Header::Q3Header(int n, QWidget *parent, const char *name)+ −
: QWidget(parent, name, Qt::WStaticContents)+ −
{+ −
orient = Qt::Horizontal;+ −
init(n);+ −
}+ −
+ −
/*!+ −
Destroys the header and all its sections.+ −
*/+ −
+ −
Q3Header::~Q3Header()+ −
{+ −
delete d;+ −
d = 0;+ −
}+ −
+ −
/*! \reimp+ −
*/+ −
+ −
void Q3Header::showEvent(QShowEvent *e)+ −
{+ −
calculatePositions();+ −
QWidget::showEvent(e);+ −
}+ −
+ −
/*!+ −
\fn void Q3Header::sizeChange(int section, int oldSize, int newSize)+ −
+ −
This signal is emitted when the user has changed the size of a \a+ −
section from \a oldSize to \a newSize. This signal is typically+ −
connected to a slot that repaints the table or list that contains+ −
the header.+ −
*/+ −
+ −
/*!+ −
\fn void Q3Header::clicked(int section)+ −
+ −
If isClickEnabled() is true, this signal is emitted when the user+ −
clicks section \a section.+ −
+ −
\sa pressed(), released()+ −
*/+ −
+ −
/*!+ −
\fn void Q3Header::pressed(int section)+ −
+ −
This signal is emitted when the user presses section \a section+ −
down.+ −
+ −
\sa released()+ −
*/+ −
+ −
/*!+ −
\fn void Q3Header::released(int section)+ −
+ −
This signal is emitted when section \a section is released.+ −
+ −
\sa pressed()+ −
*/+ −
+ −
+ −
/*!+ −
\fn void Q3Header::indexChange(int section, int fromIndex, int toIndex)+ −
+ −
This signal is emitted when the user moves section \a section from+ −
index position \a fromIndex, to index position \a toIndex.+ −
*/+ −
+ −
/*!+ −
\fn void Q3Header::moved(int fromIndex, int toIndex)+ −
+ −
Use indexChange() instead.+ −
+ −
This signal is emitted when the user has moved the section which+ −
is displayed at the index \a fromIndex to the index \a toIndex.+ −
*/+ −
+ −
/*!+ −
\fn void Q3Header::sectionClicked(int index)+ −
+ −
Use clicked() instead.+ −
+ −
This signal is emitted when a part of the header is clicked. \a+ −
index is the index at which the section is displayed.+ −
+ −
In a list view this signal would typically be connected to a slot+ −
that sorts the specified column (or row).+ −
*/+ −
+ −
/*! \fn int Q3Header::cellSize(int) const+ −
+ −
Use sectionSize() instead.+ −
+ −
Returns the size in pixels of the section that is displayed at+ −
the index \a i.+ −
*/+ −
+ −
/*!+ −
\fn void Q3Header::sectionHandleDoubleClicked(int section)+ −
+ −
This signal is emitted when the user doubleclicks on the edge+ −
(handle) of section \a section.+ −
*/+ −
+ −
/*!+ −
+ −
Use sectionPos() instead.+ −
+ −
Returns the position in pixels of the section that is displayed at the+ −
index \a i. The position is measured from the start of the header.+ −
*/+ −
+ −
int Q3Header::cellPos(int i) const+ −
{+ −
if (i == count() && i > 0)+ −
return d->positions[i-1] + d->sizes[d->i2s[i-1]]; // compatibility+ −
return sectionPos(mapToSection(i));+ −
}+ −
+ −
+ −
/*!+ −
\property Q3Header::count+ −
\brief the number of sections in the header+ −
*/+ −
+ −
int Q3Header::count() const+ −
{+ −
return d->count;+ −
}+ −
+ −
+ −
/*!+ −
\property Q3Header::tracking+ −
\brief whether the sizeChange() signal is emitted continuously+ −
+ −
If tracking is on, the sizeChange() signal is emitted continuously+ −
while the mouse is moved (i.e. when the header is resized),+ −
otherwise it is only emitted when the mouse button is released at+ −
the end of resizing.+ −
+ −
Tracking defaults to false.+ −
*/+ −
+ −
+ −
/*+ −
Initializes with \a n columns.+ −
*/+ −
void Q3Header::init(int n)+ −
{+ −
state = Idle;+ −
cachedPos = 0; // unused+ −
d = new Q3HeaderData(n);+ −
d->height = 0;+ −
d->heightDirty = true;+ −
offs = 0;+ −
if(reverse())+ −
offs = d->lastPos - width();+ −
oldHandleIdx = oldHIdxSize = handleIdx = 0;+ −
+ −
setMouseTracking(true);+ −
trackingIsOn = false;+ −
setBackgroundRole(QPalette::Button);+ −
setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));+ −
setAttribute(Qt::WA_PaintOutsidePaintEvent);+ −
}+ −
+ −
/*!+ −
\property Q3Header::orientation+ −
\brief the header's orientation+ −
+ −
The orientation is either Qt::Vertical or Qt::Horizontal (the+ −
default).+ −
+ −
Call setOrientation() before adding labels if you don't provide a+ −
size parameter otherwise the sizes will be incorrect.+ −
*/+ −
+ −
void Q3Header::setOrientation(Qt::Orientation orientation)+ −
{+ −
if (orient == orientation)+ −
return;+ −
orient = orientation;+ −
if (orient == Qt::Horizontal)+ −
setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));+ −
else+ −
setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));+ −
update();+ −
updateGeometry();+ −
}+ −
+ −
+ −
/*+ −
Paints a rectangle starting at \a p, with length \s.+ −
*/+ −
void Q3Header::paintRect(int p, int s)+ −
{+ −
QPainter paint(this);+ −
paint.setPen(QPen(Qt::black, 1, Qt::DotLine));+ −
if (reverse())+ −
paint.drawRect(p - s, 3, s, height() - 5);+ −
else if (orient == Qt::Horizontal)+ −
paint.drawRect(p, 3, s, height() - 5);+ −
else+ −
paint.drawRect(3, p, height() - 5, s);+ −
}+ −
+ −
/*+ −
Marks the division line at \a idx.+ −
*/+ −
void Q3Header::markLine(int idx)+ −
{+ −
QPainter paint(this);+ −
paint.setPen(QPen(Qt::black, 1, Qt::DotLine));+ −
int MARKSIZE = style()->pixelMetric(QStyle::PM_HeaderMarkSize);+ −
int p = pPos(idx);+ −
int x = p - MARKSIZE/2;+ −
int y = 2;+ −
int x2 = p + MARKSIZE/2;+ −
int y2 = height() - 3;+ −
if (orient == Qt::Vertical) {+ −
int t = x; x = y; y = t;+ −
t = x2; x2 = y2; y2 = t;+ −
}+ −
+ −
paint.drawLine(x, y, x2, y);+ −
paint.drawLine(x, y+1, x2, y+1);+ −
+ −
paint.drawLine(x, y2, x2, y2);+ −
paint.drawLine(x, y2-1, x2, y2-1);+ −
+ −
paint.drawLine(x, y, x, y2);+ −
paint.drawLine(x+1, y, x+1, y2);+ −
+ −
paint.drawLine(x2, y, x2, y2);+ −
paint.drawLine(x2-1, y, x2-1, y2);+ −
}+ −
+ −
/*+ −
Removes the mark at the division line at \a idx.+ −
*/+ −
void Q3Header::unMarkLine(int idx)+ −
{+ −
if (idx < 0)+ −
return;+ −
int MARKSIZE = style()->pixelMetric(QStyle::PM_HeaderMarkSize);+ −
int p = pPos(idx);+ −
int x = p - MARKSIZE/2;+ −
int y = 2;+ −
int x2 = p + MARKSIZE/2;+ −
int y2 = height() - 3;+ −
if (orient == Qt::Vertical) {+ −
int t = x; x = y; y = t;+ −
t = x2; x2 = y2; y2 = t;+ −
}+ −
repaint(x, y, x2-x+1, y2-y+1);+ −
}+ −
+ −
/*! \fn int Q3Header::cellAt(int) const+ −
+ −
Use sectionAt() instead.+ −
+ −
Returns the index at which the section is displayed, which contains+ −
\a pos in widget coordinates, or -1 if \a pos is outside the header+ −
sections.+ −
*/+ −
+ −
/*+ −
Tries to find a line that is not a neighbor of \c handleIdx.+ −
*/+ −
int Q3Header::findLine(int c)+ −
{+ −
int i = 0;+ −
if (c > d->lastPos || (reverse() && c < 0)) {+ −
return d->count;+ −
} else {+ −
int section = sectionAt(c);+ −
if (section < 0)+ −
return handleIdx;+ −
i = d->s2i[section];+ −
}+ −
int MARKSIZE = style()->pixelMetric(QStyle::PM_HeaderMarkSize);+ −
if (i == handleIdx)+ −
return i;+ −
if (i == handleIdx - 1 && pPos(handleIdx) - c > MARKSIZE/2)+ −
return i;+ −
if (i == handleIdx + 1 && c - pPos(i) > MARKSIZE/2)+ −
return i + 1;+ −
if (c - pPos(i) > pSize(i) / 2)+ −
return i + 1;+ −
else+ −
return i;+ −
}+ −
+ −
/*!+ −
Returns the handle at position \a p, or -1 if there is no handle at \a p.+ −
*/+ −
int Q3Header::handleAt(int p)+ −
{+ −
int section = d->sectionAt(p);+ −
if (section >= 0) {+ −
int GripMargin = (bool)d->resize[section] ?+ −
style()->pixelMetric(QStyle::PM_HeaderGripMargin) : 0;+ −
int index = d->s2i[section];+ −
if ((index > 0 && p < d->positions[index] + GripMargin) ||+ −
(p > d->positions[index] + d->sizes[section] - GripMargin)) {+ −
if (index > 0 && p < d->positions[index] + GripMargin)+ −
section = d->i2s[--index];+ −
// don't show icon if streaching is enabled it is at the end of the last section+ −
if (d->resize.testBit(section) && (d->fullSize == -2 || index != count() - 1)) {+ −
return section;+ −
}+ −
}+ −
}+ −
+ −
return -1;+ −
}+ −
+ −
/*!+ −
Use moveSection() instead.+ −
+ −
Moves the section that is currently displayed at index \a fromIdx+ −
to index \a toIdx.+ −
*/+ −
+ −
void Q3Header::moveCell(int fromIdx, int toIdx)+ −
{+ −
moveSection(mapToSection(fromIdx), toIdx);+ −
}+ −
+ −
+ −
+ −
/*!+ −
Move and signal and repaint.+ −
*/+ −
+ −
void Q3Header::handleColumnMove(int fromIdx, int toIdx)+ −
{+ −
int s = d->i2s[fromIdx];+ −
if (fromIdx < toIdx)+ −
toIdx++; //Convert to+ −
QRect r = sRect(fromIdx);+ −
r |= sRect(toIdx);+ −
moveSection(s, toIdx);+ −
update(r);+ −
emit moved(fromIdx, toIdx);+ −
emit indexChange(s, fromIdx, toIdx);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void Q3Header::keyPressEvent(QKeyEvent *e)+ −
{+ −
int i = d->focusIdx;+ −
if (e->key() == Qt::Key_Space) {+ −
//don't do it if we're doing something with the mouse+ −
if (state == Idle && d->clicks[d->i2s[d->focusIdx] ]) {+ −
handleIdx = i;+ −
state = Pressed;+ −
repaint(sRect(handleIdx));+ −
emit pressed(d->i2s[i]);+ −
}+ −
} else if ((orientation() == Qt::Horizontal && (e->key() == Qt::Key_Right || e->key() == Qt::Key_Left))+ −
|| (orientation() == Qt::Vertical && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down))) {+ −
int dir = e->key() == Qt::Key_Right || e->key() == Qt::Key_Down ? 1 : -1;+ −
int s = d->i2s[i];+ −
if (e->state() & Qt::ControlButton && d->resize[s]) {+ −
//resize+ −
int step = e->state() & Qt::ShiftButton ? dir : 10*dir;+ −
int c = d->positions[i] + d->sizes[s] + step;+ −
handleColumnResize(i, c, true);+ −
} else if (e->state() & (Qt::AltButton|Qt::MetaButton) && d->move) {+ −
//move section+ −
int i2 = (i + count() + dir) % count();+ −
d->focusIdx = i2;+ −
handleColumnMove(i, i2);+ −
} else {+ −
//focus on different section+ −
QRect r = sRect(d->focusIdx);+ −
d->focusIdx = (d->focusIdx + count() + dir) % count();+ −
r |= sRect(d->focusIdx);+ −
update(r);+ −
}+ −
} else {+ −
e->ignore();+ −
}+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void Q3Header::keyReleaseEvent(QKeyEvent *e)+ −
{+ −
switch (e->key()) {+ −
case Qt::Key_Space:+ −
//double check that this wasn't started with the mouse+ −
if (state == Pressed && handleIdx == d->focusIdx) {+ −
repaint(sRect(handleIdx));+ −
int section = d->i2s[d->focusIdx];+ −
emit released(section);+ −
emit sectionClicked(handleIdx);+ −
emit clicked(section);+ −
state = Idle;+ −
handleIdx = -1;+ −
}+ −
break;+ −
default:+ −
e->ignore();+ −
}+ −
}+ −
+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void Q3Header::mousePressEvent(QMouseEvent *e)+ −
{+ −
if (e->button() != Qt::LeftButton || state != Idle)+ −
return;+ −
oldHIdxSize = handleIdx;+ −
handleIdx = 0;+ −
int c = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();+ −
c += offset();+ −
if (reverse())+ −
c = d->lastPos - c;+ −
+ −
int section = d->sectionAt(c);+ −
if (section < 0)+ −
return;+ −
int GripMargin = (bool)d->resize[section] ?+ −
style()->pixelMetric(QStyle::PM_HeaderGripMargin) : 0;+ −
int index = d->s2i[section];+ −
+ −
if ((index > 0 && c < d->positions[index] + GripMargin) ||+ −
(c > d->positions[index] + d->sizes[section] - GripMargin)) {+ −
if (c < d->positions[index] + GripMargin)+ −
handleIdx = index-1;+ −
else+ −
handleIdx = index;+ −
if (d->lastPos <= (orient == Qt::Horizontal ? width() :+ −
height()) && d->fullSize != -2 && handleIdx == count() - 1) {+ −
handleIdx = -1;+ −
return;+ −
}+ −
oldHIdxSize = d->sizes[d->i2s[handleIdx]];+ −
state = d->resize[d->i2s[handleIdx] ] ? Sliding : Blocked;+ −
} else if (index >= 0) {+ −
oldHandleIdx = handleIdx = index;+ −
moveToIdx = -1;+ −
state = d->clicks[d->i2s[handleIdx] ] ? Pressed : Blocked;+ −
clickPos = c;+ −
repaint(sRect(handleIdx));+ −
if(oldHandleIdx != handleIdx)+ −
repaint(sRect(oldHandleIdx));+ −
emit pressed(section);+ −
}+ −
+ −
d->pressDelta = c - (d->positions[handleIdx] + d->sizes[d->i2s[handleIdx]]);+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void Q3Header::mouseReleaseEvent(QMouseEvent *e)+ −
{+ −
if (e->button() != Qt::LeftButton)+ −
return;+ −
int oldOldHandleIdx = oldHandleIdx;+ −
State oldState = state;+ −
state = Idle;+ −
switch (oldState) {+ −
case Pressed: {+ −
int section = d->i2s[handleIdx];+ −
emit released(section);+ −
if (sRect(handleIdx).contains(e->pos())) {+ −
oldHandleIdx = handleIdx;+ −
emit sectionClicked(handleIdx);+ −
emit clicked(section);+ −
} else {+ −
handleIdx = oldHandleIdx;+ −
}+ −
repaint(sRect(handleIdx));+ −
if (oldOldHandleIdx != handleIdx)+ −
repaint(sRect(oldOldHandleIdx));+ −
} break;+ −
case Sliding: {+ −
int c = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();+ −
c += offset();+ −
if (reverse())+ −
c = d->lastPos - c;+ −
handleColumnResize(handleIdx, c - d->pressDelta, true);+ −
} break;+ −
case Moving: {+ −
#ifndef QT_NO_CURSOR+ −
unsetCursor();+ −
#endif+ −
int section = d->i2s[handleIdx];+ −
if (handleIdx != moveToIdx && moveToIdx != -1) {+ −
moveSection(section, moveToIdx);+ −
handleIdx = oldHandleIdx;+ −
emit moved(handleIdx, moveToIdx);+ −
emit indexChange(section, handleIdx, moveToIdx);+ −
emit released(section);+ −
repaint(); // a bit overkill, but removes the handle as well+ −
} else {+ −
if (sRect(handleIdx).contains(e->pos())) {+ −
oldHandleIdx = handleIdx;+ −
emit released(section);+ −
emit sectionClicked(handleIdx);+ −
emit clicked(section);+ −
} else {+ −
handleIdx = oldHandleIdx;+ −
}+ −
repaint(sRect(handleIdx));+ −
if(oldOldHandleIdx != handleIdx)+ −
repaint(sRect(oldOldHandleIdx));+ −
}+ −
break;+ −
}+ −
case Blocked:+ −
//nothing+ −
break;+ −
default:+ −
// empty, probably. Idle, at any rate.+ −
break;+ −
}+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void Q3Header::mouseMoveEvent(QMouseEvent *e)+ −
{+ −
int c = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();+ −
c += offset();+ −
+ −
int pos = c;+ −
if(reverse())+ −
c = d->lastPos - c;+ −
+ −
switch(state) {+ −
case Idle:+ −
#ifndef QT_NO_CURSOR+ −
if (handleAt(c) < 0)+ −
unsetCursor();+ −
else if (orient == Qt::Horizontal)+ −
setCursor(Qt::splitHCursor);+ −
else+ −
setCursor(Qt::splitVCursor);+ −
#endif+ −
break;+ −
case Blocked:+ −
break;+ −
case Pressed:+ −
if (QABS(c - clickPos) > 4 && d->move) {+ −
state = Moving;+ −
moveToIdx = -1;+ −
#ifndef QT_NO_CURSOR+ −
if (orient == Qt::Horizontal)+ −
setCursor(Qt::SizeHorCursor);+ −
else+ −
setCursor(Qt::SizeVerCursor);+ −
#endif+ −
}+ −
break;+ −
case Sliding:+ −
handleColumnResize(handleIdx, c, false, false);+ −
break;+ −
case Moving: {+ −
int newPos = findLine(pos);+ −
if (newPos != moveToIdx) {+ −
if (moveToIdx == handleIdx || moveToIdx == handleIdx + 1)+ −
repaint(sRect(handleIdx));+ −
else+ −
unMarkLine(moveToIdx);+ −
moveToIdx = newPos;+ −
if (moveToIdx == handleIdx || moveToIdx == handleIdx + 1)+ −
paintRect(pPos(handleIdx), pSize(handleIdx));+ −
else+ −
markLine(moveToIdx);+ −
}+ −
break;+ −
}+ −
default:+ −
qWarning("Q3Header::mouseMoveEvent: (%s) unknown state", objectName().toLocal8Bit().data());+ −
break;+ −
}+ −
}+ −
+ −
/*! \reimp */+ −
+ −
void Q3Header::mouseDoubleClickEvent(QMouseEvent *e)+ −
{+ −
int p = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();+ −
p += offset();+ −
if(reverse())+ −
p = d->lastPos - p;+ −
+ −
int header = handleAt(p);+ −
if (header >= 0)+ −
emit sectionHandleDoubleClicked(header);+ −
}+ −
+ −
/*+ −
Handles resizing of sections. This means it redraws the relevant parts+ −
of the header.+ −
*/+ −
+ −
void Q3Header::handleColumnResize(int index, int c, bool final, bool recalcAll)+ −
{+ −
int section = d->i2s[index];+ −
int GripMargin = (bool)d->resize[section] ?+ −
style()->pixelMetric(QStyle::PM_HeaderGripMargin) : 0;+ −
int lim = d->positions[index] + 2*GripMargin;+ −
if (c == lim)+ −
return;+ −
if (c < lim)+ −
c = lim;+ −
int oldSize = d->sizes[section];+ −
int newSize = c - d->positions[index];+ −
d->sizes[section] = newSize;+ −
+ −
calculatePositions(!recalcAll, !recalcAll ? section : 0);+ −
+ −
int pos = d->positions[index]-offset();+ −
if(reverse()) // repaint the whole thing. Could be optimized (lars)+ −
repaint(0, 0, width(), height());+ −
else if (orient == Qt::Horizontal)+ −
repaint(pos, 0, width() - pos, height());+ −
else+ −
repaint(0, pos, width(), height() - pos);+ −
+ −
int os = 0, ns = 0;+ −
if (tracking() && oldSize != newSize) {+ −
os = oldSize;+ −
ns = newSize;+ −
emit sizeChange(section, oldSize, newSize);+ −
} else if (!tracking() && final && oldHIdxSize != newSize) {+ −
os = oldHIdxSize;+ −
ns = newSize;+ −
emit sizeChange(section, oldHIdxSize, newSize);+ −
}+ −
+ −
if (os != ns) {+ −
if (d->fullSize == -1) {+ −
d->fullSize = count() - 1;+ −
adjustHeaderSize();+ −
d->fullSize = -1;+ −
} else if (d->fullSize >= 0) {+ −
int old = d->fullSize;+ −
d->fullSize = count() - 1;+ −
adjustHeaderSize();+ −
d->fullSize = old;+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
Returns the rectangle covered by the section at index \a index.+ −
*/+ −
+ −
QRect Q3Header::sRect(int index)+ −
{+ −
+ −
int section = mapToSection(index);+ −
if (count() > 0 && index >= count()) {+ −
int s = d->positions[count() - 1] - offset() ++ −
d->sizes[mapToSection(count() - 1)];+ −
if (orient == Qt::Horizontal)+ −
return QRect(s, 0, width() - s + 10, height());+ −
else+ −
return QRect(0, s, width(), height() - s + 10);+ −
}+ −
if (section < 0)+ −
return rect(); // ### eeeeevil+ −
+ −
if (reverse())+ −
return QRect( d->lastPos - d->positions[index] - d->sizes[section] -offset(),+ −
0, d->sizes[section], height());+ −
else if (orient == Qt::Horizontal)+ −
return QRect( d->positions[index]-offset(), 0, d->sizes[section], height());+ −
else+ −
return QRect(0, d->positions[index]-offset(), width(), d->sizes[section]);+ −
}+ −
+ −
/*!+ −
Returns the rectangle covered by section \a section.+ −
*/+ −
+ −
QRect Q3Header::sectionRect(int section) const+ −
{+ −
int index = mapToIndex(section);+ −
if (section < 0)+ −
return rect(); // ### eeeeevil+ −
+ −
if (reverse())+ −
return QRect( d->lastPos - d->positions[index] - d->sizes[section] -offset(),+ −
0, d->sizes[section], height());+ −
else if (orient == Qt::Horizontal)+ −
return QRect( d->positions[index]-offset(), 0, d->sizes[section], height());+ −
else+ −
return QRect(0, d->positions[index]-offset(), width(), d->sizes[section]);+ −
}+ −
+ −
/*!+ −
\overload+ −
+ −
Sets the icon for section \a section to \a icon and the text to+ −
\a s. The section's width is set to \a size if \a size \>= 0;+ −
otherwise it is left unchanged.+ −
+ −
If the section does not exist, nothing happens.+ −
*/+ −
+ −
void Q3Header::setLabel(int section, const QIcon& icon,+ −
const QString &s, int size)+ −
{+ −
if (section < 0 || section >= count())+ −
return;+ −
delete d->icons[section];+ −
d->icons[section] = new QIcon(icon);+ −
setLabel(section, s, size);+ −
}+ −
+ −
/*!+ −
Sets the text of section \a section to \a s. The section's width+ −
is set to \a size if \a size \>= 0; otherwise it is left+ −
unchanged. Any icon set that has been set for this section remains+ −
unchanged.+ −
+ −
If the section does not exist, nothing happens.+ −
*/+ −
void Q3Header::setLabel(int section, const QString &s, int size)+ −
{+ −
if (section < 0 || section >= count())+ −
return;+ −
d->labels[section] = s;+ −
d->nullStringLabels.setBit(section, s.isNull());+ −
+ −
setSectionSizeAndHeight(section, size);+ −
+ −
if (updatesEnabled()) {+ −
updateGeometry();+ −
calculatePositions();+ −
update();+ −
}+ −
}+ −
+ −
+ −
bool qt_qheader_label_return_null_strings = false;+ −
/*!+ −
Returns the text for section \a section. If the section does not+ −
exist, returns an empty string.+ −
*/+ −
QString Q3Header::label(int section) const+ −
{+ −
if (section < 0 || section >= count())+ −
return QString();+ −
QString l = d->labels.value(section);+ −
if (!l.isNull())+ −
return l;+ −
if (d->nullStringLabels.testBit(section) || qt_qheader_label_return_null_strings)+ −
return l;+ −
else+ −
return QString::number(section + 1);+ −
}+ −
+ −
/*!+ −
Returns the icon set for section \a section. If the section does+ −
not exist, 0 is returned.+ −
*/+ −
+ −
QIcon *Q3Header::iconSet(int section) const+ −
{+ −
if (section < 0 || section >= count())+ −
return 0;+ −
return d->icons[section];+ −
}+ −
+ −
+ −
/*!+ −
\overload+ −
+ −
Adds a new section with icon \a icon and label text \a s.+ −
Returns the index position where the section was added (at the+ −
right for horizontal headers, at the bottom for vertical headers).+ −
The section's width is set to \a size, unless size is negative in+ −
which case the size is calculated taking account of the size of+ −
the text.+ −
*/+ −
int Q3Header::addLabel(const QIcon& icon, const QString &s, int size)+ −
{+ −
int n = count() + 1;+ −
d->icons.resize(n + 1);+ −
d->icons.insert(n - 1, new QIcon(icon));+ −
return addLabel(s, size);+ −
}+ −
+ −
/*!+ −
Removes section \a section. If the section does not exist, nothing+ −
happens.+ −
*/+ −
void Q3Header::removeLabel(int section)+ −
{+ −
if (section < 0 || section > count() - 1)+ −
return;+ −
+ −
int index = d->s2i[section];+ −
int n = --d->count;+ −
int i;+ −
for (i = section; i < n; ++i) {+ −
d->sizes[i] = d->sizes[i+1];+ −
d->labels[i] = d->labels[i+1];+ −
d->labels[i+1] = QString();+ −
d->nullStringLabels[i] = d->nullStringLabels[i+1];+ −
d->nullStringLabels[i+1] = 0;+ −
d->icons[i] = d->icons[i+1];+ −
d->icons[i+1] = 0;+ −
}+ −
+ −
d->sizes.resize(n);+ −
d->positions.resize(n);+ −
d->labels.resize(n);+ −
d->nullStringLabels.resize(n);+ −
d->icons.resize(n);+ −
+ −
for (i = section; i < n; ++i)+ −
d->s2i[i] = d->s2i[i+1];+ −
d->s2i.resize(n);+ −
+ −
if (updatesEnabled()) {+ −
for (i = 0; i < n; ++i)+ −
if (d->s2i[i] > index)+ −
--d->s2i[i];+ −
}+ −
+ −
for (i = index; i < n; ++i)+ −
d->i2s[i] = d->i2s[i+1];+ −
d->i2s.resize(n);+ −
+ −
if (updatesEnabled()) {+ −
for (i = 0; i < n; ++i)+ −
if (d->i2s[i] > section)+ −
--d->i2s[i];+ −
}+ −
+ −
if (updatesEnabled()) {+ −
updateGeometry();+ −
calculatePositions();+ −
update();+ −
}+ −
}+ −
+ −
QSize Q3Header::sectionSizeHint(int section, const QFontMetrics& fm) const+ −
{+ −
int iw = 0;+ −
int ih = 0;+ −
if (d->icons[section] != 0) {+ −
QSize isize = d->icons[section]->pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize),+ −
QIcon::Normal).size();+ −
iw = isize.width() + 2;+ −
ih = isize.height();+ −
}+ −
+ −
QRect bound;+ −
QString label = d->labels[section];+ −
if (!label.isNull() || d->nullStringLabels.testBit(section)) {+ −
int lines = label.count(QLatin1Char('\n')) + 1;+ −
int w = 0;+ −
if (lines > 1) {+ −
bound.setHeight(fm.height() + fm.lineSpacing() * (lines - 1));+ −
QStringList list = label.split(QLatin1Char('\n'));+ −
for (int i=0; i < list.count(); ++i) {+ −
int tmpw = fm.width(list.at(i));+ −
w = QMAX(w, tmpw);+ −
}+ −
} else {+ −
bound.setHeight(fm.height());+ −
w = fm.width(label);+ −
}+ −
bound.setWidth(w);+ −
}+ −
int arrowWidth = 0;+ −
if (d->sortSection == section)+ −
arrowWidth = ((orient == Qt::Horizontal ? height() : width()) / 2) + 8;+ −
int height = qMax(bound.height() + 2, ih) + 4;+ −
int width = bound.width() + style()->pixelMetric(QStyle::PM_HeaderMargin) * 4+ −
+ iw + arrowWidth;+ −
return QSize(width, height);+ −
}+ −
+ −
/*+ −
Sets d->sizes[\a section] to a bounding rect based on its size+ −
hint and font metrics, but constrained by \a size. It also updates+ −
d->height.+ −
*/+ −
void Q3Header::setSectionSizeAndHeight(int section, int size)+ −
{+ −
QSize sz = sectionSizeHint(section, fontMetrics());+ −
+ −
if (size < 0) {+ −
if (d->sizes[section] < 0)+ −
d->sizes[section] = (orient == Qt::Horizontal) ? sz.width()+ −
: sz.height();+ −
} else {+ −
d->sizes[section] = size;+ −
}+ −
+ −
int newHeight = (orient == Qt::Horizontal) ? sz.height() : sz.width();+ −
if (newHeight > d->height) {+ −
d->height = newHeight;+ −
} else if (newHeight < d->height) {+ −
/*+ −
We could be smarter, but we aren't. This makes a difference+ −
only for users with many columns and '\n's in their headers+ −
at the same time.+ −
*/+ −
d->heightDirty = true;+ −
}+ −
}+ −
+ −
/*!+ −
Adds a new section with label text \a s. Returns the index+ −
position where the section was added (at the right for horizontal+ −
headers, at the bottom for vertical headers). The section's width+ −
is set to \a size. If \a size \< 0, an appropriate size for the+ −
text \a s is chosen.+ −
*/+ −
int Q3Header::addLabel(const QString &s, int size)+ −
{+ −
int n = ++d->count;+ −
if ((int)d->icons.size() < n )+ −
d->icons.resize(n);+ −
if ((int)d->sizes.size() < n ) {+ −
d->labels.resize(n);+ −
d->nullStringLabels.resize(n);+ −
d->sizes.resize(n);+ −
d->positions.resize(n);+ −
d->i2s.resize(n);+ −
d->s2i.resize(n);+ −
d->clicks.resize(n);+ −
d->resize.resize(n);+ −
}+ −
int section = d->count - 1;+ −
if (!d->is_a_table_header || !s.isNull()) {+ −
d->labels.insert(section, s);+ −
d->nullStringLabels.setBit(section, s.isNull());+ −
}+ −
+ −
if (size >= 0 && s.isNull() && d->is_a_table_header) {+ −
d->sizes[section] = size;+ −
} else {+ −
d->sizes[section] = -1;+ −
setSectionSizeAndHeight(section, size);+ −
}+ −
+ −
int index = section;+ −
d->positions[index] = d->lastPos;+ −
+ −
d->s2i[section] = index;+ −
d->i2s[index] = section;+ −
d->clicks.setBit(section, d->clicks_default);+ −
d->resize.setBit(section, d->resize_default);+ −
+ −
if (updatesEnabled()) {+ −
updateGeometry();+ −
calculatePositions();+ −
update();+ −
}+ −
return index;+ −
}+ −
+ −
void Q3Header::resizeArrays(int size)+ −
{+ −
d->icons.resize(size);+ −
d->labels.resize(size);+ −
d->nullStringLabels.resize(size);+ −
d->sizes.resize(size);+ −
d->positions.resize(size);+ −
d->i2s.resize(size);+ −
d->s2i.resize(size);+ −
d->clicks.resize(size);+ −
d->resize.resize(size);+ −
}+ −
+ −
void Q3Header::setIsATableHeader(bool b)+ −
{+ −
d->is_a_table_header = b;+ −
}+ −
+ −
/*! \reimp */+ −
QSize Q3Header::sizeHint() const+ −
{+ −
int width;+ −
int height;+ −
+ −
ensurePolished();+ −
QFontMetrics fm = fontMetrics();+ −
+ −
if (d->heightDirty) {+ −
d->height = fm.lineSpacing() + 6;+ −
for (int i = 0; i < count(); i++) {+ −
int h = orient == Qt::Horizontal ?+ −
sectionSizeHint(i, fm).height() : sectionSizeHint(i, fm).width();+ −
d->height = qMax(d->height, h);+ −
}+ −
d->heightDirty = false;+ −
}+ −
+ −
if (orient == Qt::Horizontal) {+ −
height = fm.lineSpacing() + 6;+ −
width = 0;+ −
height = qMax(height, d->height);+ −
for (int i = 0; i < count(); i++)+ −
width += d->sizes[i];+ −
} else {+ −
width = fm.width(QLatin1Char(' '));+ −
height = 0;+ −
width = qMax(width, d->height);+ −
for (int i = 0; i < count(); i++)+ −
height += d->sizes[i];+ −
}+ −
QStyleOptionHeader opt = getStyleOption(this, 0);+ −
return style()->sizeFromContents(QStyle::CT_Q3Header, &opt, QSize(width, height),+ −
this).expandedTo(QApplication::globalStrut());+ −
}+ −
+ −
/*!+ −
\property Q3Header::offset+ −
\brief the header's left-most (or top-most) visible pixel+ −
+ −
Setting this property will scroll the header so that \e offset+ −
becomes the left-most (or top-most for vertical headers) visible+ −
pixel.+ −
*/+ −
int Q3Header::offset() const+ −
{+ −
if (reverse())+ −
return d->lastPos - width() - offs;+ −
return offs;+ −
}+ −
+ −
void Q3Header::setOffset(int x)+ −
{+ −
int oldOff = offset();+ −
offs = x;+ −
if(d->lastPos < (orient == Qt::Horizontal ? width() : height()))+ −
offs = 0;+ −
else if (reverse())+ −
offs = d->lastPos - width() - x;+ −
if (orient == Qt::Horizontal)+ −
scroll(oldOff-offset(), 0);+ −
else+ −
scroll(0, oldOff-offset());+ −
}+ −
+ −
+ −
+ −
/*+ −
Returns the position of actual division line \a i in widget+ −
coordinates. May return a position outside the widget.+ −
+ −
Note that the last division line is numbered count(). (There is one+ −
more line than the number of sections).+ −
*/+ −
int Q3Header::pPos(int i) const+ −
{+ −
int pos;+ −
if (i == count())+ −
pos = d->lastPos;+ −
else+ −
pos = d->positions[i];+ −
if (reverse())+ −
pos = d->lastPos - pos;+ −
return pos - offset();+ −
}+ −
+ −
+ −
/*+ −
Returns the size of the section at index position \a i.+ −
*/+ −
int Q3Header::pSize(int i) const+ −
{+ −
return d->sizes[d->i2s[i]];+ −
}+ −
+ −
/*!+ −
Use mapToSection() instead.+ −
+ −
Translates from actual index \a a (index at which the section is displayed) to+ −
logical index of the section. Returns -1 if \a a is outside the legal range.+ −
+ −
\sa mapToActual()+ −
*/+ −
+ −
int Q3Header::mapToLogical(int a) const+ −
{+ −
return mapToSection(a);+ −
}+ −
+ −
+ −
/*!+ −
Use mapToIndex() instead.+ −
+ −
Translates from logical index \a l to actual index (index at which the section \a l is displayed) .+ −
Returns -1 if \a l is outside the legal range.+ −
+ −
\sa mapToLogical()+ −
*/+ −
+ −
int Q3Header::mapToActual(int l) const+ −
{+ −
return mapToIndex(l);+ −
}+ −
+ −
+ −
/*!+ −
Use resizeSection() instead.+ −
+ −
Sets the size of the section \a section to \a s pixels.+ −
+ −
\warning does not repaint or send out signals+ −
*/+ −
+ −
void Q3Header::setCellSize(int section, int s)+ −
{+ −
if (section < 0 || section >= count())+ −
return;+ −
d->sizes[section] = s;+ −
if (updatesEnabled())+ −
calculatePositions();+ −
else+ −
d->positionsDirty = true;+ −
}+ −
+ −
+ −
/*!+ −
If \a enable is true the user may resize section \a section;+ −
otherwise the section may not be manually resized.+ −
+ −
If \a section is negative (the default) then the \a enable value+ −
is set for all existing sections and will be applied to any new+ −
sections that are added.+ −
Example:+ −
\snippet doc/src/snippets/code/src_qt3support_widgets_q3header.cpp 0+ −
+ −
If the user resizes a section, a sizeChange() signal is emitted.+ −
+ −
\sa setMovingEnabled() setClickEnabled() setTracking()+ −
*/+ −
+ −
void Q3Header::setResizeEnabled(bool enable, int section)+ −
{+ −
if (section < 0) {+ −
d->resize.fill(enable);+ −
// and future ones...+ −
d->resize_default = enable;+ −
} else if (section < count()) {+ −
d->resize[section] = enable;+ −
}+ −
}+ −
+ −
+ −
/*!+ −
\property Q3Header::moving+ −
\brief whether the header sections can be moved+ −
+ −
If this property is true (the default) the user can move sections.+ −
If the user moves a section the indexChange() signal is emitted.+ −
+ −
\sa setClickEnabled(), setResizeEnabled()+ −
*/+ −
+ −
void Q3Header::setMovingEnabled(bool enable)+ −
{+ −
d->move = enable;+ −
}+ −
+ −
+ −
/*!+ −
If \a enable is true, any clicks on section \a section will result+ −
in clicked() signals being emitted; otherwise the section will+ −
ignore clicks.+ −
+ −
If \a section is -1 (the default) then the \a enable value is set+ −
for all existing sections and will be applied to any new sections+ −
that are added.+ −
+ −
\sa setMovingEnabled(), setResizeEnabled()+ −
*/+ −
+ −
void Q3Header::setClickEnabled(bool enable, int section)+ −
{+ −
if (section < 0) {+ −
d->clicks.fill(enable);+ −
// and future ones...+ −
d->clicks_default = enable;+ −
} else if (section < count()) {+ −
d->clicks[section] = enable;+ −
}+ −
}+ −
+ −
+ −
/*!+ −
Paints the section at position \a index, inside rectangle \a fr+ −
(which uses widget coordinates) using painter \a p.+ −
+ −
Calls paintSectionLabel().+ −
*/+ −
+ −
void Q3Header::paintSection(QPainter *p, int index, const QRect& fr)+ −
{+ −
int section = mapToSection(index);+ −
QStyleOptionHeader opt = getStyleOption(this, section);+ −
opt.state |= QStyle::State_Raised;+ −
opt.rect = fr;+ −
+ −
if (section < 0) {+ −
style()->drawControl(QStyle::CE_Header, &opt, p, this);+ −
return;+ −
}+ −
+ −
if (sectionSize(section) <= 0)+ −
return;+ −
+ −
opt.state = (orient == Qt::Horizontal ? QStyle::State_Horizontal : QStyle::State_None);+ −
if (d->sortSection == section)+ −
opt.sortIndicator = d->sortDirection ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;+ −
+ −
if (isEnabled())+ −
opt.state |= QStyle::State_Enabled;+ −
if (isClickEnabled(section) && (state == Pressed || state == Moving) && index == handleIdx)+ −
opt.state |= QStyle::State_Sunken; //currently pressed+ −
if (!(opt.state & QStyle::State_Sunken))+ −
opt.state |= QStyle::State_Raised;+ −
p->setBrushOrigin(fr.topLeft());+ −
if (d->clicks[section]) {+ −
style()->drawControl(QStyle::CE_Header, &opt, p, this);+ −
} else {+ −
p->save();+ −
p->setClipRect(fr); // hack to keep styles working+ −
opt.rect.setRect(fr.x() + 1, fr.y(), fr.width(), fr.height());+ −
style()->drawControl(QStyle::CE_Header, &opt, p, this);+ −
if (orient == Qt::Horizontal) {+ −
p->setPen(palette().color(QPalette::Mid));+ −
p->drawLine(fr.x() - 1, fr.y() + fr.height() - 1,+ −
fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);+ −
p->drawLine(fr.x() + fr.width() - 1, fr.y(),+ −
fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);+ −
} else {+ −
p->setPen(palette().color(QPalette::Mid));+ −
p->drawLine(fr.x() + width() - 1, fr.y(),+ −
fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);+ −
p->drawLine(fr.x(), fr.y() + fr.height() - 1,+ −
fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);+ −
p->setPen(palette().color(QPalette::Light));+ −
if (index > 0)+ −
p->drawLine(fr.x(), fr.y(), fr.x() + fr.width() - 1, fr.y());+ −
if (index == count() - 1) {+ −
p->drawLine(fr.x(), fr.y() + fr.height() - 1,+ −
fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);+ −
p->setPen(palette().color(QPalette::Mid));+ −
p->drawLine(fr.x(), fr.y() + fr.height() - 2,+ −
fr.x() + fr.width() - 1, fr.y() + fr.height() - 2);+ −
}+ −
}+ −
p->restore();+ −
}+ −
}+ −
+ −
/*!+ −
Paints the label of the section at position \a index, inside+ −
rectangle \a fr (which uses widget coordinates) using painter \a+ −
p.+ −
+ −
Called by paintSection()+ −
*/+ −
void Q3Header::paintSectionLabel(QPainter *p, int index, const QRect& fr)+ −
{+ −
int section = mapToSection(index);+ −
if (section < 0)+ −
return;+ −
+ −
int dx = 0, dy = 0;+ −
QStyleOptionHeader opt = getStyleOption(this, section);+ −
if (d->sortSection == section)+ −
opt.sortIndicator = d->sortDirection ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;+ −
if (index == handleIdx && (state == Pressed || state == Moving)) {+ −
dx = style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &opt, this);+ −
dy = style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &opt, this);+ −
opt.state |= QStyle::State_Sunken;+ −
}+ −
if (isEnabled())+ −
opt.state |= QStyle::State_Enabled;+ −
+ −
+ −
opt.rect.setRect(fr.x() + style()->pixelMetric(QStyle::PM_HeaderMargin) + dx, fr.y() + 2 + dy,+ −
fr.width() - 6, fr.height() - 4);+ −
+ −
style()->drawControl(QStyle::CE_HeaderLabel, &opt, p, this);+ −
+ −
int arrowWidth = (orient == Qt::Horizontal ? height() : width()) / 2;+ −
int arrowHeight = fr.height() - 6;+ −
QSize ssh = sectionSizeHint(section, p->fontMetrics());+ −
int tw = (orient == Qt::Horizontal ? ssh.width() : ssh.height());+ −
int ew = 0;+ −
+ −
if (style()->styleHint(QStyle::SH_Header_ArrowAlignment, 0, this) & Qt::AlignRight)+ −
ew = fr.width() - tw - 8;+ −
if (d->sortSection == section && tw <= fr.width()) {+ −
if (reverse()) {+ −
tw = fr.width() - tw;+ −
ew = fr.width() - ew - tw;+ −
}+ −
opt.state = QStyle::State_None;+ −
if (isEnabled())+ −
opt.state |= QStyle::State_Enabled;+ −
if (d->sortDirection)+ −
opt.state |= QStyle::State_DownArrow;+ −
else+ −
opt.state |= QStyle::State_UpArrow;+ −
QRect ar(fr.x() + tw - arrowWidth - 6 + ew, 4, arrowWidth, arrowHeight);+ −
if (label(section).isRightToLeft())+ −
ar.moveBy( 2*(fr.right() - ar.right()) + ar.width() - fr.width(), 0 );+ −
opt.rect = ar;+ −
style()->drawPrimitive(QStyle::PE_IndicatorHeaderArrow, &opt, p, this);+ −
}+ −
}+ −
+ −
+ −
/*! \reimp */+ −
void Q3Header::paintEvent(QPaintEvent *e)+ −
{+ −
QPainter p(this);+ −
p.setPen(palette().buttonText().color());+ −
int pos = orient == Qt::Horizontal ? e->rect().left() : e->rect().top();+ −
int id = mapToIndex(sectionAt(pos + offset()));+ −
if (id < 0) {+ −
if (pos > 0)+ −
id = d->count;+ −
else if (reverse())+ −
id = d->count - 1;+ −
else+ −
id = 0;+ −
}+ −
if (reverse()) {+ −
for (int i = id; i >= 0; i--) {+ −
QRect r = sRect(i);+ −
paintSection(&p, i, r);+ −
if (r.right() >= e->rect().right())+ −
return;+ −
}+ −
} else {+ −
if (count() > 0) {+ −
for (int i = id; i <= count(); i++) {+ −
QRect r = sRect(i);+ −
/*+ −
If the last section is clickable (and thus is+ −
painted raised), draw the virtual section count()+ −
as well. Otherwise it looks ugly.+ −
*/+ −
if (i < count() || d->clicks[mapToSection(count() - 1)])+ −
paintSection(&p, i, r);+ −
if (hasFocus() && d->focusIdx == i) {+ −
QStyleOptionFocusRect opt;+ −
opt.rect.setRect(r.x()+2, r.y()+2, r.width()-4, r.height()-4);+ −
opt.palette = palette();+ −
opt.state = QStyle::State_None;+ −
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);+ −
}+ −
if ((orient == Qt::Horizontal && r. right() >= e->rect().right())+ −
|| (orient == Qt::Vertical && r. bottom() >= e->rect().bottom()))+ −
return;+ −
}+ −
}+ −
}+ −
}+ −
+ −
/*!+ −
\overload+ −
+ −
Sets the sort indicator to \a ascending. Use the other overload instead.+ −
*/+ −
+ −
void Q3Header::setSortIndicator(int section, bool ascending)+ −
{+ −
d->sortSection = section;+ −
if (section != -1)+ −
oldHandleIdx = section;+ −
d->sortDirection = ascending;+ −
update();+ −
updateGeometry();+ −
}+ −
+ −
/*!+ −
\fn void Q3Header::setSortIndicator(int section, Qt::SortOrder order)+ −
+ −
Sets a sort indicator onto the specified \a section. The indicator's+ −
\a order is either Ascending or Descending.+ −
+ −
Only one section can show a sort indicator at any one time. If you+ −
don't want any section to show a sort indicator pass a \a section+ −
number of -1.+ −
+ −
\sa sortIndicatorSection(), sortIndicatorOrder()+ −
*/+ −
+ −
/*!+ −
Returns the section showing the sort indicator or -1 if there is no sort indicator.+ −
+ −
\sa setSortIndicator(), sortIndicatorOrder()+ −
*/+ −
+ −
int Q3Header::sortIndicatorSection() const+ −
{+ −
return d->sortSection;+ −
}+ −
+ −
/*!+ −
Returns the implied sort order of the Q3Headers sort indicator.+ −
+ −
\sa setSortIndicator(), sortIndicatorSection()+ −
*/+ −
+ −
Qt::SortOrder Q3Header::sortIndicatorOrder() const+ −
{+ −
return d->sortDirection ? Qt::AscendingOrder : Qt::DescendingOrder;+ −
}+ −
+ −
/*!+ −
Resizes section \a section to \a s pixels wide (or high).+ −
*/+ −
+ −
void Q3Header::resizeSection(int section, int s)+ −
{+ −
setCellSize(section, s);+ −
update();+ −
}+ −
+ −
/*!+ −
Returns the width (or height) of the \a section in pixels.+ −
*/+ −
+ −
int Q3Header::sectionSize(int section) const+ −
{+ −
if (section < 0 || section >= count())+ −
return 0;+ −
return d->sizes[section];+ −
}+ −
+ −
/*!+ −
Returns the position (in pixels) at which the \a section starts.+ −
+ −
\sa offset()+ −
*/+ −
+ −
int Q3Header::sectionPos(int section) const+ −
{+ −
if (d->positionsDirty)+ −
((Q3Header *)this)->calculatePositions();+ −
if (section < 0 || section >= count() )+ −
return 0;+ −
return d->positions[d->s2i[section]];+ −
}+ −
+ −
/*!+ −
Returns the index of the section which contains the position \a+ −
pos given in pixels from the left (or top).+ −
+ −
\sa offset()+ −
*/+ −
+ −
int Q3Header::sectionAt(int pos) const+ −
{+ −
if (reverse())+ −
pos = d->lastPos - pos;+ −
return d->sectionAt(pos);+ −
}+ −
+ −
/*!+ −
Returns the number of the section that is displayed at index+ −
position \a index.+ −
*/+ −
+ −
int Q3Header::mapToSection(int index) const+ −
{+ −
return (index >= 0 && index < count()) ? d->i2s[index] : -1;+ −
}+ −
+ −
/*!+ −
Returns the index position at which section \a section is+ −
displayed.+ −
*/+ −
+ −
int Q3Header::mapToIndex(int section) const+ −
{+ −
return (section >= 0 && section < count()) ? d->s2i[section] : -1;+ −
}+ −
+ −
/*!+ −
Moves section \a section to index position \a toIndex.+ −
*/+ −
+ −
void Q3Header::moveSection(int section, int toIndex)+ −
{+ −
int fromIndex = mapToIndex(section);+ −
if (fromIndex == toIndex ||+ −
fromIndex < 0 || fromIndex > count() ||+ −
toIndex < 0 || toIndex > count())+ −
return;+ −
int i;+ −
int idx = d->i2s[fromIndex];+ −
if (fromIndex < toIndex) {+ −
for (i = fromIndex; i < toIndex - 1; i++) {+ −
int t;+ −
d->i2s[i] = t = d->i2s[i+1];+ −
d->s2i[t] = i;+ −
}+ −
d->i2s[toIndex-1] = idx;+ −
d->s2i[idx] = toIndex-1;+ −
} else {+ −
for (i = fromIndex; i > toIndex; i--) {+ −
int t;+ −
d->i2s[i] = t = d->i2s[i-1];+ −
d->s2i[t] = i;+ −
}+ −
d->i2s[toIndex] = idx;+ −
d->s2i[idx] = toIndex;+ −
}+ −
calculatePositions();+ −
}+ −
+ −
/*!+ −
Returns true if section \a section is clickable; otherwise returns+ −
false.+ −
+ −
If \a section is out of range (negative or larger than count() -+ −
1): returns true if all sections are clickable; otherwise returns+ −
false.+ −
+ −
\sa setClickEnabled()+ −
*/+ −
+ −
bool Q3Header::isClickEnabled(int section) const+ −
{+ −
if (section >= 0 && section < count()) {+ −
return (bool)d->clicks[section];+ −
}+ −
+ −
for (int i = 0; i < count(); ++i) {+ −
if (!d->clicks[i])+ −
return false;+ −
}+ −
return true;+ −
}+ −
+ −
/*!+ −
Returns true if section \a section is resizeable; otherwise+ −
returns false.+ −
+ −
If \a section is -1 then this function applies to all sections,+ −
i.e. returns true if all sections are resizeable; otherwise+ −
returns false.+ −
+ −
\sa setResizeEnabled()+ −
*/+ −
+ −
bool Q3Header::isResizeEnabled(int section) const+ −
{+ −
if (section >= 0 && section < count()) {+ −
return (bool)d->resize[section];+ −
}+ −
+ −
for (int i = 0; i < count();++i) {+ −
if (!d->resize[i])+ −
return false;+ −
}+ −
return true;+ −
}+ −
+ −
bool Q3Header::isMovingEnabled() const+ −
{+ −
return d->move;+ −
}+ −
+ −
/*! \internal */+ −
+ −
void Q3Header::setUpdatesEnabled(bool enable)+ −
{+ −
if (enable)+ −
calculatePositions();+ −
QWidget::setUpdatesEnabled(enable);+ −
}+ −
+ −
+ −
bool Q3Header::reverse () const+ −
{+ −
#if 0+ −
return (orient == Qt::Horizontal && QApplication::reverseLayout());+ −
#else+ −
return false;+ −
#endif+ −
}+ −
+ −
/*! \reimp */+ −
void Q3Header::resizeEvent(QResizeEvent *e)+ −
{+ −
if (e)+ −
QWidget::resizeEvent(e);+ −
+ −
if(d->lastPos < width()) {+ −
offs = 0;+ −
}+ −
+ −
if (e) {+ −
adjustHeaderSize(orientation() == Qt::Horizontal ?+ −
width() - e->oldSize().width() : height() - e->oldSize().height());+ −
if ((orientation() == Qt::Horizontal && height() != e->oldSize().height())+ −
|| (orientation() == Qt::Vertical && width() != e->oldSize().width()))+ −
update();+ −
} else+ −
adjustHeaderSize();+ −
}+ −
+ −
/*!+ −
\fn void Q3Header::adjustHeaderSize()+ −
+ −
Adjusts the size of the sections to fit the size of the header as+ −
completely as possible. Only sections for which isStretchEnabled()+ −
is true will be resized.+ −
*/+ −
+ −
void Q3Header::adjustHeaderSize(int diff)+ −
{+ −
if (!count())+ −
return;+ −
+ −
// we skip the adjustHeaderSize when trying to resize the last column which is set to stretchable+ −
if (d->fullSize == (count() -1) &&+ −
(d->lastPos - d->sizes[count() -1]) > (orient == Qt::Horizontal ? width() : height()))+ −
return;+ −
+ −
if (d->fullSize >= 0) {+ −
int sec = mapToSection(d->fullSize);+ −
int lsec = mapToSection(count() - 1);+ −
int ns = sectionSize(sec) ++ −
(orientation() == Qt::Horizontal ?+ −
width() : height()) - (sectionPos(lsec) + sectionSize(lsec));+ −
int os = sectionSize(sec);+ −
if (ns < 20)+ −
ns = 20;+ −
setCellSize(sec, ns);+ −
repaint();+ −
emit sizeChange(sec, os, ns);+ −
} else if (d->fullSize == -1) {+ −
int df = diff / count();+ −
int part = orientation() == Qt::Horizontal ? width() / count() : height() / count();+ −
for (int i = 0; i < count() - 1; ++i) {+ −
int sec = mapToIndex(i);+ −
int os = sectionSize(sec);+ −
int ns = diff != -1 ? os + df : part;+ −
if (ns < 20)+ −
ns = 20;+ −
setCellSize(sec, ns);+ −
emit sizeChange(sec, os, ns);+ −
}+ −
int sec = mapToIndex(count() - 1);+ −
int ns = (orientation() == Qt::Horizontal ? width() : height()) - sectionPos(sec);+ −
int os = sectionSize(sec);+ −
if (ns < 20)+ −
ns = 20;+ −
setCellSize(sec, ns);+ −
repaint();+ −
emit sizeChange(sec, os, ns);+ −
}+ −
}+ −
+ −
/*!+ −
Returns the total width of all the header columns.+ −
*/+ −
int Q3Header::headerWidth() const+ −
{+ −
if (d->pos_dirty) {+ −
((Q3Header*)this)->calculatePositions();+ −
d->pos_dirty = false;+ −
}+ −
return d->lastPos;+ −
}+ −
+ −
void Q3Header::calculatePositions(bool onlyVisible, int start)+ −
{+ −
d->positionsDirty = false;+ −
d->lastPos = count() > 0 ? d->positions[start] : 0;+ −
for (int i = start; i < count(); i++) {+ −
d->positions[i] = d->lastPos;+ −
d->lastPos += d->sizes[d->i2s[i]];+ −
if (onlyVisible && d->lastPos > offset() ++ −
(orientation() == Qt::Horizontal ? width() : height()))+ −
break;+ −
}+ −
d->pos_dirty = onlyVisible;+ −
}+ −
+ −
+ −
/*!+ −
\property Q3Header::stretching+ −
\brief whether the header sections always take up the full width+ −
(or height) of the header+ −
*/+ −
+ −
+ −
/*!+ −
If \a b is true, section \a section will be resized when the+ −
header is resized, so that the sections take up the full width (or+ −
height for vertical headers) of the header; otherwise section \a+ −
section will be set to be unstretchable and will not resize when+ −
the header is resized.+ −
+ −
If \a section is -1, and if \a b is true, then all sections will+ −
be resized equally when the header is resized so that they take up+ −
the full width (or height for vertical headers) of the header;+ −
otherwise all the sections will be set to be unstretchable and+ −
will not resize when the header is resized.+ −
+ −
\sa adjustHeaderSize()+ −
*/+ −
+ −
void Q3Header::setStretchEnabled(bool b, int section)+ −
{+ −
if (b)+ −
d->fullSize = section;+ −
else+ −
d->fullSize = -2;+ −
adjustHeaderSize();+ −
}+ −
+ −
bool Q3Header::isStretchEnabled() const+ −
{+ −
return d->fullSize == -1;+ −
}+ −
+ −
/*!+ −
\overload+ −
+ −
Returns true if section \a section will resize to take up the full+ −
width (or height) of the header; otherwise returns false. If at+ −
least one section has stretch enabled the sections will always+ −
take up the full width of the header.+ −
+ −
\sa setStretchEnabled()+ −
*/+ −
+ −
bool Q3Header::isStretchEnabled(int section) const+ −
{+ −
return d->fullSize == section;+ −
}+ −
+ −
/*!+ −
\reimp+ −
*/+ −
void Q3Header::changeEvent(QEvent *ev)+ −
{+ −
if(ev->type() == QEvent::FontChange) {+ −
QFontMetrics fm = fontMetrics();+ −
d->height = (orient == Qt::Horizontal) ? fm.lineSpacing() + 6 : fm.width(QLatin1Char(' '));+ −
}+ −
QWidget::changeEvent(ev);+ −
}+ −
+ −
QT_END_NAMESPACE+ −
+ −
#endif // QT_NO_HEADER+ −