~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/qt3support/widgets/q3header.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the Qt 3 compatibility classes of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "q3header.h"
 
30
#ifndef QT_NO_HEADER
 
31
#include "qapplication.h"
 
32
#include "qbitarray.h"
 
33
#include "qcursor.h"
 
34
#include "qdrawutil.h"
 
35
#include "qevent.h"
 
36
#include "qpainter.h"
 
37
#include "qpixmap.h"
 
38
#include "qstyle.h"
 
39
#include "qstyleoption.h"
 
40
#include "qvector.h"
 
41
 
 
42
class Q3HeaderData
 
43
{
 
44
public:
 
45
    Q3HeaderData(int n)
 
46
    {
 
47
        count = n;
 
48
        sizes.resize(n);
 
49
        positions.resize(n);
 
50
        labels.resize(n);
 
51
        icons.resize(n);
 
52
        i2s.resize(n);
 
53
        s2i.resize(n);
 
54
        clicks.resize(n);
 
55
        resize.resize(n);
 
56
        int p =0;
 
57
        for (int i = 0; i < n; i ++) {
 
58
            sizes[i] = 88;
 
59
            i2s[i] = i;
 
60
            s2i[i] = i;
 
61
            positions[i] = p;
 
62
            p += sizes[i];
 
63
        }
 
64
        clicks_default = true;
 
65
        resize_default = true;
 
66
        clicks.fill(clicks_default);
 
67
        resize.fill(resize_default);
 
68
        move = true;
 
69
        sortSection = -1;
 
70
        sortDirection = true;
 
71
        positionsDirty = true;
 
72
        lastPos = 0;
 
73
        fullSize = -2;
 
74
        pos_dirty = false;
 
75
        is_a_table_header = false;
 
76
        focusIdx = 0;
 
77
    }
 
78
    ~Q3HeaderData()
 
79
    {
 
80
        for (int i = 0; i < icons.size(); ++i)
 
81
            delete icons.at(i);
 
82
    }
 
83
 
 
84
 
 
85
    QVector<int>        sizes;
 
86
    int height; // we abuse the heights as widths for vertical layout
 
87
    bool heightDirty;
 
88
    QVector<int>        positions; // sorted by index
 
89
    QVector<QString>        labels;
 
90
    QVector<QIcon *> icons;
 
91
    QVector<int>                i2s;
 
92
    QVector<int>                s2i;
 
93
 
 
94
    QBitArray           clicks;
 
95
    QBitArray           resize;
 
96
    uint move : 1;
 
97
    uint clicks_default : 1; // default value for new clicks bits
 
98
    uint resize_default : 1; // default value for new resize bits
 
99
    uint pos_dirty : 1;
 
100
    uint is_a_table_header : 1;
 
101
    bool sortDirection;
 
102
    bool positionsDirty;
 
103
    int sortSection;
 
104
    int count;
 
105
    int lastPos;
 
106
    int fullSize;
 
107
    int focusIdx;
 
108
    int pressDelta;
 
109
 
 
110
    int sectionAt(int pos) {
 
111
        // positions is sorted by index, not by section
 
112
        if (!count)
 
113
            return -1;
 
114
        int l = 0;
 
115
        int r = count - 1;
 
116
        int i = ((l+r+1) / 2);
 
117
        while (r - l) {
 
118
            if (positions[i] > pos)
 
119
                r = i -1;
 
120
            else
 
121
                l = i;
 
122
            i = ((l+r+1) / 2);
 
123
        }
 
124
        if (positions[i] <= pos && pos <= positions[i] + sizes[i2s[i]])
 
125
            return i2s[i];
 
126
        return -1;
 
127
    }
 
128
};
 
129
 
 
130
static QStyleOptionHeader getStyleOption(const Q3Header *header, int section)
 
131
{
 
132
    QStyleOptionHeader opt;
 
133
    opt.init(header);
 
134
    opt.section = section;
 
135
    if (header->iconSet(section))
 
136
        opt.icon = *header->iconSet(section);
 
137
    opt.text = header->label(section);
 
138
    if (header->orientation() == Qt::Horizontal)
 
139
        opt.state = QStyle::State_Horizontal;
 
140
    return opt;
 
141
}
 
142
 
 
143
/*!
 
144
    \class Q3Header q3header.h
 
145
    \brief The Q3Header class provides a header row or column, e.g. for
 
146
    tables and listviews.
 
147
 
 
148
    \compat
 
149
 
 
150
    This class provides a header, e.g. a vertical header to display
 
151
    row labels, or a horizontal header to display column labels. It is
 
152
    used by Q3Table and Q3ListView for example.
 
153
 
 
154
    A header is composed of one or more \e sections, each of which can
 
155
    display a text label and an \link QIcon icon\endlink. A sort
 
156
    indicator (an arrow) can also be displayed using
 
157
    setSortIndicator().
 
158
 
 
159
    Sections are added with addLabel() and removed with removeLabel().
 
160
    The label and icon are set in addLabel() and can be changed
 
161
    later with setLabel(). Use count() to retrieve the number of
 
162
    sections in the header.
 
163
 
 
164
    The orientation of the header is set with setOrientation(). If
 
165
    setStretchEnabled() is true, the sections will expand to take up
 
166
    the full width (height for vertical headers) of the header. The
 
167
    user can resize the sections manually if setResizeEnabled() is
 
168
    true. Call adjustHeaderSize() to have the sections resize to
 
169
    occupy the full width (or height).
 
170
 
 
171
    A section can be moved with moveSection(). If setMovingEnabled()
 
172
    is true (the default)the user may drag a section from one position
 
173
    to another. If a section is moved, the index positions at which
 
174
    sections were added (with addLabel()), may not be the same after the
 
175
    move. You don't have to worry about this in practice because the
 
176
    Q3Header API works in terms of section numbers, so it doesn't matter
 
177
    where a particular section has been moved to.
 
178
 
 
179
    If you want the current index position of a section call
 
180
    mapToIndex() giving it the section number. (This is the number
 
181
    returned by the addLabel() call which created the section.) If you
 
182
    want to get the section number of a section at a particular index
 
183
    position call mapToSection() giving it the index number.
 
184
 
 
185
    Here's an example to clarify mapToSection() and mapToIndex():
 
186
 
 
187
    \table
 
188
    \header \i41 Index positions
 
189
    \row \i 0 \i 1 \i 2 \i 3
 
190
    \header \i41 Original section ordering
 
191
    \row \i Sect 0 \i Sect 1 \i Sect 2 \i Sect 3
 
192
    \header \i41 Ordering after the user moves a section
 
193
    \row \i Sect 0 \i Sect 2 \i Sect 3 \i Sect 1
 
194
    \endtable
 
195
 
 
196
    \table
 
197
    \header \i \e k \i mapToSection(\e k) \i mapToIndex(\e k)
 
198
    \row \i 0 \i 0 \i 0
 
199
    \row \i 1 \i 2 \i 3
 
200
    \row \i 2 \i 3 \i 1
 
201
    \row \i 3 \i 1 \i 2
 
202
    \endtable
 
203
 
 
204
    In the example above, if we wanted to find out which section is at
 
205
    index position 3 we'd call mapToSection(3) and get a section
 
206
    number of 1 since section 1 was moved. Similarly, if we wanted to
 
207
    know which index position section 2 occupied we'd call
 
208
    mapToIndex(2) and get an index of 1.
 
209
 
 
210
    Q3Header provides the clicked(), pressed() and released() signals.
 
211
    If the user changes the size of a section, the sizeChange() signal
 
212
    is emitted. If you want to have a sizeChange() signal emitted
 
213
    continuously whilst the user is resizing (rather than just after
 
214
    the resizing is finished), use setTracking(). If the user moves a
 
215
    section the indexChange() signal is emitted.
 
216
 
 
217
    \sa Q3ListView Q3Table
 
218
*/
 
219
 
 
220
 
 
221
 
 
222
/*!
 
223
    Constructs a horizontal header called \a name, with parent \a
 
224
    parent.
 
225
*/
 
226
 
 
227
Q3Header::Q3Header(QWidget *parent, const char *name)
 
228
    : QWidget(parent, name, Qt::WStaticContents)
 
229
{
 
230
    orient = Qt::Horizontal;
 
231
    init(0);
 
232
}
 
233
 
 
234
/*!
 
235
    Constructs a horizontal header called \a name, with \a n sections
 
236
    and parent \a parent.
 
237
*/
 
238
 
 
239
Q3Header::Q3Header(int n, QWidget *parent, const char *name)
 
240
    : QWidget(parent, name, Qt::WStaticContents)
 
241
{
 
242
    orient = Qt::Horizontal;
 
243
    init(n);
 
244
}
 
245
 
 
246
/*!
 
247
    Destroys the header and all its sections.
 
248
*/
 
249
 
 
250
Q3Header::~Q3Header()
 
251
{
 
252
    delete d;
 
253
    d = 0;
 
254
}
 
255
 
 
256
/*! \reimp
 
257
 */
 
258
 
 
259
void Q3Header::showEvent(QShowEvent *e)
 
260
{
 
261
    calculatePositions();
 
262
    QWidget::showEvent(e);
 
263
}
 
264
 
 
265
/*!
 
266
    \fn void Q3Header::sizeChange(int section, int oldSize, int newSize)
 
267
 
 
268
    This signal is emitted when the user has changed the size of a \a
 
269
    section from \a oldSize to \a newSize. This signal is typically
 
270
    connected to a slot that repaints the table or list that contains
 
271
    the header.
 
272
*/
 
273
 
 
274
/*!
 
275
    \fn void Q3Header::clicked(int section)
 
276
 
 
277
    If isClickEnabled() is true, this signal is emitted when the user
 
278
    clicks section \a section.
 
279
 
 
280
    \sa pressed(), released()
 
281
*/
 
282
 
 
283
/*!
 
284
    \fn void Q3Header::pressed(int section)
 
285
 
 
286
    This signal is emitted when the user presses section \a section
 
287
    down.
 
288
 
 
289
    \sa released()
 
290
*/
 
291
 
 
292
/*!
 
293
    \fn void Q3Header::released(int section)
 
294
 
 
295
    This signal is emitted when section \a section is released.
 
296
 
 
297
    \sa pressed()
 
298
*/
 
299
 
 
300
 
 
301
/*!
 
302
    \fn void Q3Header::indexChange(int section, int fromIndex, int toIndex)
 
303
 
 
304
    This signal is emitted when the user moves section \a section from
 
305
    index position \a fromIndex, to index position \a toIndex.
 
306
*/
 
307
 
 
308
/*!
 
309
  \fn void Q3Header::moved(int fromIndex, int toIndex)
 
310
 
 
311
  Use indexChange() instead.
 
312
 
 
313
  This signal is emitted when the user has moved the section which
 
314
  is displayed at the index \a fromIndex to the index \a toIndex.
 
315
*/
 
316
 
 
317
/*!
 
318
  \fn void Q3Header::sectionClicked(int index)
 
319
 
 
320
  Use clicked() instead.
 
321
 
 
322
  This signal is emitted when a part of the header is clicked. \a
 
323
  index is the index at which the section is displayed.
 
324
 
 
325
  In a list view this signal would typically be connected to a slot
 
326
  that sorts the specified column (or row).
 
327
*/
 
328
 
 
329
/*! \fn int Q3Header::cellSize(int) const
 
330
 
 
331
  Use sectionSize() instead.
 
332
 
 
333
  Returns the size in pixels of the section that is displayed at
 
334
  the index \a i.
 
335
*/
 
336
 
 
337
/*!
 
338
    \fn void Q3Header::sectionHandleDoubleClicked(int section)
 
339
 
 
340
    This signal is emitted when the user doubleclicks on the edge
 
341
    (handle) of section \a section.
 
342
*/
 
343
 
 
344
/*!
 
345
 
 
346
  Use sectionPos() instead.
 
347
 
 
348
  Returns the position in pixels of the section that is displayed at the
 
349
  index \a i. The  position is measured from the start of the header.
 
350
*/
 
351
 
 
352
int Q3Header::cellPos(int i) const
 
353
{
 
354
    if (i == count() && i > 0)
 
355
        return  d->positions[i-1] + d->sizes[d->i2s[i-1]]; // compatibility
 
356
    return sectionPos(mapToSection(i));
 
357
}
 
358
 
 
359
 
 
360
/*!
 
361
    \property Q3Header::count
 
362
    \brief the number of sections in the header
 
363
*/
 
364
 
 
365
int Q3Header::count() const
 
366
{
 
367
    return d->count;
 
368
}
 
369
 
 
370
 
 
371
/*!
 
372
    \property Q3Header::tracking
 
373
    \brief whether the sizeChange() signal is emitted continuously
 
374
 
 
375
    If tracking is on, the sizeChange() signal is emitted continuously
 
376
    while the mouse is moved (i.e. when the header is resized),
 
377
    otherwise it is only emitted when the mouse button is released at
 
378
    the end of resizing.
 
379
 
 
380
    Tracking defaults to false.
 
381
*/
 
382
 
 
383
 
 
384
/*
 
385
    Initializes with \a n columns.
 
386
*/
 
387
void Q3Header::init(int n)
 
388
{
 
389
    state = Idle;
 
390
    cachedPos = 0; // unused
 
391
    d = new Q3HeaderData(n);
 
392
    d->height = 0;
 
393
    d->heightDirty = true;
 
394
    offs = 0;
 
395
    if(reverse())
 
396
        offs = d->lastPos - width();
 
397
    oldHandleIdx = oldHIdxSize = handleIdx = 0;
 
398
 
 
399
    setMouseTracking(true);
 
400
    trackingIsOn = false;
 
401
    setBackgroundRole(QPalette::Button);
 
402
    setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
 
403
}
 
404
 
 
405
/*!
 
406
    \property Q3Header::orientation
 
407
    \brief the header's orientation
 
408
 
 
409
    The orientation is either \c Qt::Vertical or \c Qt::Horizontal (the
 
410
    default).
 
411
 
 
412
    Call setOrientation() before adding labels if you don't provide a
 
413
    size parameter otherwise the sizes will be incorrect.
 
414
*/
 
415
 
 
416
void Q3Header::setOrientation(Qt::Orientation orientation)
 
417
{
 
418
    if (orient == orientation)
 
419
        return;
 
420
    orient = orientation;
 
421
    if (orient == Qt::Horizontal)
 
422
        setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
 
423
    else
 
424
        setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred));
 
425
    update();
 
426
    updateGeometry();
 
427
}
 
428
 
 
429
 
 
430
/*
 
431
    Paints a rectangle starting at \a p, with length \s.
 
432
*/
 
433
void Q3Header::paintRect(int p, int s)
 
434
{
 
435
    QPainter paint(this);
 
436
    paint.setPen(QPen(Qt::black, 1, Qt::DotLine));
 
437
    if (reverse())
 
438
        paint.drawRect(p - s, 3, s, height() - 5);
 
439
    else if (orient == Qt::Horizontal)
 
440
        paint.drawRect(p, 3, s, height() - 5);
 
441
    else
 
442
        paint.drawRect(3, p, height() - 5, s);
 
443
}
 
444
 
 
445
/*
 
446
  Marks the division line at \a idx.
 
447
*/
 
448
void Q3Header::markLine(int idx)
 
449
{
 
450
    QPainter paint(this);
 
451
    paint.setPen(QPen(Qt::black, 1, Qt::DotLine));
 
452
    int MARKSIZE = style()->pixelMetric(QStyle::PM_HeaderMarkSize);
 
453
    int p = pPos(idx);
 
454
    int x = p - MARKSIZE/2;
 
455
    int y = 2;
 
456
    int x2 = p + MARKSIZE/2;
 
457
    int y2 = height() - 3;
 
458
    if (orient == Qt::Vertical) {
 
459
        int t = x; x = y; y = t;
 
460
        t = x2; x2 = y2; y2 = t;
 
461
    }
 
462
 
 
463
    paint.drawLine(x, y, x2, y);
 
464
    paint.drawLine(x, y+1, x2, y+1);
 
465
 
 
466
    paint.drawLine(x, y2, x2, y2);
 
467
    paint.drawLine(x, y2-1, x2, y2-1);
 
468
 
 
469
    paint.drawLine(x, y, x, y2);
 
470
    paint.drawLine(x+1, y, x+1, y2);
 
471
 
 
472
    paint.drawLine(x2, y, x2, y2);
 
473
    paint.drawLine(x2-1, y, x2-1, y2);
 
474
}
 
475
 
 
476
/*
 
477
  Removes the mark at the division line at \a idx.
 
478
*/
 
479
void Q3Header::unMarkLine(int idx)
 
480
{
 
481
    if (idx < 0)
 
482
        return;
 
483
    int MARKSIZE = style()->pixelMetric(QStyle::PM_HeaderMarkSize);
 
484
    int p = pPos(idx);
 
485
    int x = p - MARKSIZE/2;
 
486
    int y = 2;
 
487
    int x2 = p + MARKSIZE/2;
 
488
    int y2 = height() - 3;
 
489
    if (orient == Qt::Vertical) {
 
490
        int t = x; x = y; y = t;
 
491
        t = x2; x2 = y2; y2 = t;
 
492
    }
 
493
    repaint(x, y, x2-x+1, y2-y+1);
 
494
}
 
495
 
 
496
/*! \fn int Q3Header::cellAt(int) const
 
497
 
 
498
  Use sectionAt() instead.
 
499
 
 
500
  Returns the index at which the section is displayed, which contains
 
501
  \a pos in widget coordinates, or -1 if \a pos is outside the header
 
502
  sections.
 
503
*/
 
504
 
 
505
/*
 
506
  Tries to find a line that is not a neighbor of  \c handleIdx.
 
507
*/
 
508
int Q3Header::findLine(int c)
 
509
{
 
510
    int i = 0;
 
511
    if (c > d->lastPos || (reverse() && c < 0)) {
 
512
        return d->count;
 
513
    } else {
 
514
        int section = sectionAt(c);
 
515
        if (section < 0)
 
516
            return handleIdx;
 
517
        i = d->s2i[section];
 
518
    }
 
519
    int MARKSIZE = style()->pixelMetric(QStyle::PM_HeaderMarkSize);
 
520
    if (i == handleIdx)
 
521
        return i;
 
522
    if (i == handleIdx - 1 &&  pPos(handleIdx) - c > MARKSIZE/2)
 
523
        return i;
 
524
    if (i == handleIdx + 1 && c - pPos(i) > MARKSIZE/2)
 
525
        return i + 1;
 
526
    if (c - pPos(i) > pSize(i) / 2)
 
527
        return i + 1;
 
528
    else
 
529
        return i;
 
530
}
 
531
 
 
532
/*!
 
533
    Returns the handle at position \a p, or -1 if there is no handle at \a p.
 
534
*/
 
535
int Q3Header::handleAt(int p)
 
536
{
 
537
    int section = d->sectionAt(p);
 
538
    if (section >= 0) {
 
539
        int GripMargin = (bool)d->resize[section] ?
 
540
            style()->pixelMetric(QStyle::PM_HeaderGripMargin) : 0;
 
541
        int index = d->s2i[section];
 
542
        if ((index > 0 && p < d->positions[index] + GripMargin) ||
 
543
            (p > d->positions[index] + d->sizes[section] - GripMargin)) {
 
544
            if (index > 0 && p < d->positions[index]  + GripMargin)
 
545
                section = d->i2s[--index];
 
546
            // dont show icon if streaching is enabled it is at the end of the last section
 
547
            if (d->resize.testBit(section) && (d->fullSize == -2 || index != count() - 1)) {
 
548
                return section;
 
549
            }
 
550
        }
 
551
    }
 
552
 
 
553
    return -1;
 
554
}
 
555
 
 
556
/*!
 
557
  Use moveSection() instead.
 
558
 
 
559
  Moves the section that is currently displayed at index \a fromIdx
 
560
  to index \a toIdx.
 
561
*/
 
562
 
 
563
void Q3Header::moveCell(int fromIdx, int toIdx)
 
564
{
 
565
    moveSection(mapToSection(fromIdx), toIdx);
 
566
}
 
567
 
 
568
 
 
569
 
 
570
/*!
 
571
  Move and signal and repaint.
 
572
 */
 
573
 
 
574
void Q3Header::handleColumnMove(int fromIdx, int toIdx)
 
575
{
 
576
    int s = d->i2s[fromIdx];
 
577
    if (fromIdx < toIdx)
 
578
        toIdx++; //Convert to
 
579
    QRect r = sRect(fromIdx);
 
580
    r |= sRect(toIdx);
 
581
    moveSection(s, toIdx);
 
582
    update(r);
 
583
    emit moved(fromIdx, toIdx);
 
584
    emit indexChange(s, fromIdx, toIdx);
 
585
}
 
586
 
 
587
/*!
 
588
  \reimp
 
589
*/
 
590
void Q3Header::keyPressEvent(QKeyEvent *e)
 
591
{
 
592
    int i = d->focusIdx;
 
593
    if (e->key() == Qt::Key_Space) {
 
594
        //don't do it if we're doing something with the mouse
 
595
        if (state == Idle && d->clicks[d->i2s[d->focusIdx] ]) {
 
596
            handleIdx = i;
 
597
            state = Pressed;
 
598
            repaint(sRect(handleIdx));
 
599
            emit pressed(d->i2s[i]);
 
600
        }
 
601
    } else if (orientation() == Qt::Horizontal &&
 
602
                (e->key() == Qt::Key_Right || e->key() == Qt::Key_Left)
 
603
                || orientation() == Qt::Vertical &&
 
604
                (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) {
 
605
        int dir = e->key() == Qt::Key_Right || e->key() == Qt::Key_Down ? 1 : -1;
 
606
        int s = d->i2s[i];
 
607
        if (e->state() & Qt::ControlButton  && d->resize[s]) {
 
608
            //resize
 
609
            int step = e->state() & Qt::ShiftButton ? dir : 10*dir;
 
610
            int c = d->positions[i] + d->sizes[s] +  step;
 
611
            handleColumnResize(i, c, true);
 
612
        } else         if (e->state() & (Qt::AltButton|Qt::MetaButton) && d->move) {
 
613
            //move section
 
614
            int i2 = (i + count() + dir) % count();
 
615
            d->focusIdx = i2;
 
616
            handleColumnMove(i, i2);
 
617
        } else {
 
618
            //focus on different section
 
619
            QRect r = sRect(d->focusIdx);
 
620
            d->focusIdx = (d->focusIdx + count() + dir) % count();
 
621
            r |= sRect(d->focusIdx);
 
622
            update(r);
 
623
        }
 
624
    } else {
 
625
        e->ignore();
 
626
    }
 
627
}
 
628
 
 
629
/*!
 
630
  \reimp
 
631
*/
 
632
void Q3Header::keyReleaseEvent(QKeyEvent *e)
 
633
{
 
634
    switch (e->key()) {
 
635
    case Qt::Key_Space:
 
636
        //double check that this wasn't started with the mouse
 
637
        if (state == Pressed && handleIdx == d->focusIdx) {
 
638
            repaint(sRect(handleIdx));
 
639
            int section = d->i2s[d->focusIdx];
 
640
            emit released(section);
 
641
            emit sectionClicked(handleIdx);
 
642
            emit clicked(section);
 
643
            state = Idle;
 
644
            handleIdx = -1;
 
645
        }
 
646
        break;
 
647
    default:
 
648
        e->ignore();
 
649
    }
 
650
}
 
651
 
 
652
 
 
653
/*!
 
654
  \reimp
 
655
*/
 
656
void Q3Header::mousePressEvent(QMouseEvent *e)
 
657
{
 
658
    if (e->button() != Qt::LeftButton || state != Idle)
 
659
        return;
 
660
    oldHIdxSize = handleIdx;
 
661
    handleIdx = 0;
 
662
    int c = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();
 
663
    c += offset();
 
664
    if (reverse())
 
665
        c = d->lastPos - c;
 
666
 
 
667
    int section = d->sectionAt(c);
 
668
    if (section < 0)
 
669
        return;
 
670
    int GripMargin = (bool)d->resize[section] ?
 
671
        style()->pixelMetric(QStyle::PM_HeaderGripMargin) : 0;
 
672
    int index = d->s2i[section];
 
673
 
 
674
    if ((index > 0 && c < d->positions[index] + GripMargin) ||
 
675
         (c > d->positions[index] + d->sizes[section] - GripMargin)) {
 
676
        if (c < d->positions[index] + GripMargin)
 
677
            handleIdx = index-1;
 
678
        else
 
679
            handleIdx = index;
 
680
        if (d->lastPos <= (orient == Qt::Horizontal ? width() :
 
681
                             height()) && d->fullSize != -2 && handleIdx == count() - 1) {
 
682
            handleIdx = -1;
 
683
            return;
 
684
        }
 
685
        oldHIdxSize = d->sizes[d->i2s[handleIdx]];
 
686
        state = d->resize[d->i2s[handleIdx] ] ? Sliding : Blocked;
 
687
    } else if (index >= 0) {
 
688
        oldHandleIdx = handleIdx = index;
 
689
        moveToIdx = -1;
 
690
        state = d->clicks[d->i2s[handleIdx] ] ? Pressed : Blocked;
 
691
        clickPos = c;
 
692
        repaint(sRect(handleIdx));
 
693
        if(oldHandleIdx != handleIdx)
 
694
            repaint(sRect(oldHandleIdx));
 
695
        emit pressed(section);
 
696
    }
 
697
 
 
698
    d->pressDelta = c - (d->positions[handleIdx] + d->sizes[d->i2s[handleIdx]]);
 
699
}
 
700
 
 
701
/*!
 
702
  \reimp
 
703
*/
 
704
void Q3Header::mouseReleaseEvent(QMouseEvent *e)
 
705
{
 
706
    if (e->button() != Qt::LeftButton)
 
707
        return;
 
708
    int oldOldHandleIdx = oldHandleIdx;
 
709
    State oldState = state;
 
710
    state = Idle;
 
711
    switch (oldState) {
 
712
    case Pressed: {
 
713
        int section = d->i2s[handleIdx];
 
714
        emit released(section);
 
715
        if (sRect(handleIdx).contains(e->pos())) {
 
716
            oldHandleIdx = handleIdx;
 
717
            emit sectionClicked(handleIdx);
 
718
            emit clicked(section);
 
719
        } else {
 
720
            handleIdx = oldHandleIdx;
 
721
        }
 
722
        repaint(sRect(handleIdx));
 
723
        if (oldOldHandleIdx != handleIdx)
 
724
            repaint(sRect(oldOldHandleIdx));
 
725
        } break;
 
726
    case Sliding: {
 
727
        int c = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();
 
728
        c += offset();
 
729
        if (reverse())
 
730
            c = d->lastPos - c;
 
731
        handleColumnResize(handleIdx, c - d->pressDelta, true);
 
732
    } break;
 
733
    case Moving: {
 
734
#ifndef QT_NO_CURSOR
 
735
        unsetCursor();
 
736
#endif
 
737
        int section = d->i2s[handleIdx];
 
738
        if (handleIdx != moveToIdx && moveToIdx != -1) {
 
739
            moveSection(section, moveToIdx);
 
740
            handleIdx = oldHandleIdx;
 
741
            emit moved(handleIdx, moveToIdx);
 
742
            emit indexChange(section, handleIdx, moveToIdx);
 
743
            emit released(section);
 
744
            repaint(); // a bit overkill, but removes the handle as well
 
745
        } else {
 
746
            if (sRect(handleIdx).contains(e->pos())) {
 
747
                oldHandleIdx = handleIdx;
 
748
                emit released(section);
 
749
                emit sectionClicked(handleIdx);
 
750
                emit clicked(section);
 
751
            } else {
 
752
                handleIdx = oldHandleIdx;
 
753
            }
 
754
            repaint(sRect(handleIdx));
 
755
            if(oldOldHandleIdx != handleIdx)
 
756
                repaint(sRect(oldOldHandleIdx));
 
757
        }
 
758
        break;
 
759
    }
 
760
    case Blocked:
 
761
        //nothing
 
762
        break;
 
763
    default:
 
764
        // empty, probably.  Idle, at any rate.
 
765
        break;
 
766
    }
 
767
}
 
768
 
 
769
/*!
 
770
  \reimp
 
771
*/
 
772
void Q3Header::mouseMoveEvent(QMouseEvent *e)
 
773
{
 
774
    int c = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();
 
775
    c += offset();
 
776
 
 
777
    int pos = c;
 
778
    if(reverse())
 
779
        c = d->lastPos - c;
 
780
 
 
781
    switch(state) {
 
782
    case Idle:
 
783
#ifndef QT_NO_CURSOR
 
784
        if (handleAt(c) < 0)
 
785
            unsetCursor();
 
786
        else if (orient == Qt::Horizontal)
 
787
            setCursor(Qt::splitHCursor);
 
788
        else
 
789
            setCursor(Qt::splitVCursor);
 
790
#endif
 
791
        break;
 
792
    case Blocked:
 
793
        break;
 
794
    case Pressed:
 
795
        if (QABS(c - clickPos) > 4 && d->move) {
 
796
            state = Moving;
 
797
            moveToIdx = -1;
 
798
#ifndef QT_NO_CURSOR
 
799
            if (orient == Qt::Horizontal)
 
800
                setCursor(Qt::SizeHorCursor);
 
801
            else
 
802
                setCursor(Qt::SizeVerCursor);
 
803
#endif
 
804
        }
 
805
        break;
 
806
    case Sliding:
 
807
        handleColumnResize(handleIdx, c, false, false);
 
808
        break;
 
809
    case Moving: {
 
810
        int newPos = findLine(pos);
 
811
        if (newPos != moveToIdx) {
 
812
            if (moveToIdx == handleIdx || moveToIdx == handleIdx + 1)
 
813
                repaint(sRect(handleIdx));
 
814
            else
 
815
                unMarkLine(moveToIdx);
 
816
            moveToIdx = newPos;
 
817
            if (moveToIdx == handleIdx || moveToIdx == handleIdx + 1)
 
818
                paintRect(pPos(handleIdx), pSize(handleIdx));
 
819
            else
 
820
                markLine(moveToIdx);
 
821
        }
 
822
        break;
 
823
    }
 
824
    default:
 
825
        qWarning("Q3Header::mouseMoveEvent: (%s) unknown state", objectName().toLocal8Bit().data());
 
826
        break;
 
827
    }
 
828
}
 
829
 
 
830
/*! \reimp */
 
831
 
 
832
void Q3Header::mouseDoubleClickEvent(QMouseEvent *e)
 
833
{
 
834
    int p = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();
 
835
    p += offset();
 
836
    if(reverse())
 
837
        p = d->lastPos - p;
 
838
 
 
839
    int header = handleAt(p);
 
840
    if (header >= 0)
 
841
        emit sectionHandleDoubleClicked(header);
 
842
}
 
843
 
 
844
/*
 
845
  Handles resizing of sections. This means it redraws the relevant parts
 
846
  of the header.
 
847
*/
 
848
 
 
849
void Q3Header::handleColumnResize(int index, int c, bool final, bool recalcAll)
 
850
{
 
851
    int section = d->i2s[index];
 
852
    int GripMargin = (bool)d->resize[section] ?
 
853
        style()->pixelMetric(QStyle::PM_HeaderGripMargin) : 0;
 
854
    int lim = d->positions[index] + 2*GripMargin;
 
855
    if (c == lim)
 
856
        return;
 
857
    if (c < lim)
 
858
        c = lim;
 
859
    int oldSize = d->sizes[section];
 
860
    int newSize = c - d->positions[index];
 
861
    d->sizes[section] = newSize;
 
862
 
 
863
    calculatePositions(!recalcAll, !recalcAll ? section : 0);
 
864
 
 
865
    int pos = d->positions[index]-offset();
 
866
    if(reverse()) // repaint the whole thing. Could be optimized (lars)
 
867
        repaint(0, 0, width(), height());
 
868
    else if (orient == Qt::Horizontal)
 
869
        repaint(pos, 0, width() - pos, height());
 
870
    else
 
871
        repaint(0, pos, width(), height() - pos);
 
872
 
 
873
    int os = 0, ns = 0;
 
874
    if (tracking() && oldSize != newSize) {
 
875
        os = oldSize;
 
876
        ns = newSize;
 
877
        emit sizeChange(section, oldSize, newSize);
 
878
    } else if (!tracking() && final && oldHIdxSize != newSize) {
 
879
        os = oldHIdxSize;
 
880
        ns = newSize;
 
881
        emit sizeChange(section, oldHIdxSize, newSize);
 
882
    }
 
883
 
 
884
    if (os != ns) {
 
885
        if (d->fullSize == -1) {
 
886
            d->fullSize = count() - 1;
 
887
            adjustHeaderSize();
 
888
            d->fullSize = -1;
 
889
        } else if (d->fullSize >= 0) {
 
890
            int old = d->fullSize;
 
891
            d->fullSize = count() - 1;
 
892
            adjustHeaderSize();
 
893
            d->fullSize = old;
 
894
        }
 
895
    }
 
896
}
 
897
 
 
898
/*!
 
899
    Returns the rectangle covered by the section at index \a index.
 
900
*/
 
901
 
 
902
QRect Q3Header::sRect(int index)
 
903
{
 
904
 
 
905
    int section = mapToSection(index);
 
906
    if (count() > 0 && index >= count()) {
 
907
        int s = d->positions[count() - 1] - offset() +
 
908
                d->sizes[mapToSection(count() - 1)];
 
909
        if (orient == Qt::Horizontal)
 
910
            return QRect(s, 0, width() - s + 10, height());
 
911
        else
 
912
            return QRect(0, s, width(), height() - s + 10);
 
913
    }
 
914
    if (section < 0)
 
915
        return rect(); // ### eeeeevil
 
916
 
 
917
    if (reverse())
 
918
        return QRect( d->lastPos - d->positions[index] - d->sizes[section] -offset(),
 
919
                       0, d->sizes[section], height());
 
920
    else if (orient == Qt::Horizontal)
 
921
        return QRect( d->positions[index]-offset(), 0, d->sizes[section], height());
 
922
    else
 
923
        return QRect(0, d->positions[index]-offset(), width(), d->sizes[section]);
 
924
}
 
925
 
 
926
/*!
 
927
    Returns the rectangle covered by section \a section.
 
928
*/
 
929
 
 
930
QRect Q3Header::sectionRect(int section) const
 
931
{
 
932
    int index = mapToIndex(section);
 
933
    if (section < 0)
 
934
        return rect(); // ### eeeeevil
 
935
 
 
936
    if (reverse())
 
937
        return QRect( d->lastPos - d->positions[index] - d->sizes[section] -offset(),
 
938
                       0, d->sizes[section], height());
 
939
    else if (orient == Qt::Horizontal)
 
940
        return QRect( d->positions[index]-offset(), 0, d->sizes[section], height());
 
941
    else
 
942
        return QRect(0, d->positions[index]-offset(), width(), d->sizes[section]);
 
943
}
 
944
 
 
945
/*!
 
946
    \overload
 
947
 
 
948
    Sets the icon for section \a section to \a icon and the text to
 
949
    \a s. The section's width is set to \a size if \a size \>= 0;
 
950
    otherwise it is left unchanged.
 
951
 
 
952
    If the section does not exist, nothing happens.
 
953
*/
 
954
 
 
955
void Q3Header::setLabel(int section, const QIcon& icon,
 
956
                        const QString &s, int size)
 
957
{
 
958
    if (section < 0 || section >= count())
 
959
        return;
 
960
    d->icons.insert(section, new QIcon(icon));
 
961
    setLabel(section, s, size);
 
962
}
 
963
 
 
964
/*!
 
965
    Sets the text of section \a section to \a s. The section's width
 
966
    is set to \a size if \a size \>= 0; otherwise it is left
 
967
    unchanged. Any icon set that has been set for this section remains
 
968
    unchanged.
 
969
 
 
970
    If the section does not exist, nothing happens.
 
971
*/
 
972
void Q3Header::setLabel(int section, const QString &s, int size)
 
973
{
 
974
    if (section < 0 || section >= count())
 
975
        return;
 
976
    d->labels[section] = s;
 
977
 
 
978
    setSectionSizeAndHeight(section, size);
 
979
 
 
980
    if (updatesEnabled()) {
 
981
        updateGeometry();
 
982
        calculatePositions();
 
983
        update();
 
984
    }
 
985
}
 
986
 
 
987
 
 
988
bool qt_qheader_label_return_null_strings = false;
 
989
/*!
 
990
    Returns the text for section \a section. If the section does not
 
991
    exist, returns an empty string.
 
992
*/
 
993
QString Q3Header::label(int section) const
 
994
{
 
995
    if (section < 0 || section >= count())
 
996
        return QString();
 
997
    QString l = d->labels.value(section);
 
998
    if (!l.isNull() || qt_qheader_label_return_null_strings)
 
999
        return l;
 
1000
    else
 
1001
        return QString::number(section + 1);
 
1002
}
 
1003
 
 
1004
/*!
 
1005
    Returns the icon set for section \a section. If the section does
 
1006
    not exist, 0 is returned.
 
1007
*/
 
1008
 
 
1009
QIcon *Q3Header::iconSet(int section) const
 
1010
{
 
1011
    if (section < 0 || section >= count())
 
1012
        return 0;
 
1013
    return d->icons[section];
 
1014
}
 
1015
 
 
1016
 
 
1017
/*!
 
1018
    \overload
 
1019
 
 
1020
    Adds a new section with icon \a icon and label text \a s.
 
1021
    Returns the index position where the section was added (at the
 
1022
    right for horizontal headers, at the bottom for vertical headers).
 
1023
    The section's width is set to \a size, unless size is negative in
 
1024
    which case the size is calculated taking account of the size of
 
1025
    the text.
 
1026
*/
 
1027
int Q3Header::addLabel(const QIcon& icon, const QString &s, int size)
 
1028
{
 
1029
    int n = count() + 1;
 
1030
    d->icons.resize(n + 1);
 
1031
    d->icons.insert(n - 1, new QIcon(icon));
 
1032
    return addLabel(s, size);
 
1033
}
 
1034
 
 
1035
/*!
 
1036
    Removes section \a section. If the section does not exist, nothing
 
1037
    happens.
 
1038
*/
 
1039
void Q3Header::removeLabel(int section)
 
1040
{
 
1041
    if (section < 0 || section > count() - 1)
 
1042
        return;
 
1043
 
 
1044
    int index = d->s2i[section];
 
1045
    int n = --d->count;
 
1046
    int i;
 
1047
    for (i = section; i < n; ++i) {
 
1048
        d->sizes[i] = d->sizes[i+1];
 
1049
        d->labels[i] = d->labels[i+1];
 
1050
        d->labels[i+1] = QString();
 
1051
        d->icons[i] = d->icons[i+1];
 
1052
        d->icons[i+1] = 0;
 
1053
    }
 
1054
 
 
1055
    d->sizes.resize(n);
 
1056
    d->positions.resize(n);
 
1057
    d->labels.resize(n);
 
1058
    d->icons.resize(n);
 
1059
 
 
1060
    for (i = section; i < n; ++i)
 
1061
        d->s2i[i] = d->s2i[i+1];
 
1062
    d->s2i.resize(n);
 
1063
 
 
1064
    if (updatesEnabled()) {
 
1065
        for (i = 0; i < n; ++i)
 
1066
            if (d->s2i[i] > index)
 
1067
                --d->s2i[i];
 
1068
    }
 
1069
 
 
1070
    for (i = index; i < n; ++i)
 
1071
        d->i2s[i] = d->i2s[i+1];
 
1072
    d->i2s.resize(n);
 
1073
 
 
1074
    if (updatesEnabled()) {
 
1075
        for (i = 0; i < n; ++i)
 
1076
            if (d->i2s[i] > section)
 
1077
                --d->i2s[i];
 
1078
    }
 
1079
 
 
1080
    if (updatesEnabled()) {
 
1081
        updateGeometry();
 
1082
        calculatePositions();
 
1083
        update();
 
1084
    }
 
1085
}
 
1086
 
 
1087
QSize Q3Header::sectionSizeHint(int section, const QFontMetrics& fm) const
 
1088
{
 
1089
    int iw = 0;
 
1090
    int ih = 0;
 
1091
    if (d->icons[section] != 0) {
 
1092
        QSize isize = d->icons[section]->pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize),
 
1093
                                                    QIcon::Normal).size();
 
1094
        iw = isize.width() + 2;
 
1095
        ih = isize.height();
 
1096
    }
 
1097
 
 
1098
    QRect bound;
 
1099
    QString label = d->labels[section];
 
1100
    if (!label.isNull()) {
 
1101
        int lines = label.count('\n') + 1;
 
1102
        int w = 0;
 
1103
        if (lines > 1) {
 
1104
            bound.setHeight(fm.height() + fm.lineSpacing() * (lines - 1));
 
1105
            QStringList list = label.split('\n');
 
1106
            for (int i=0; i < list.count(); ++i) {
 
1107
                int tmpw = fm.width(list.at(i));
 
1108
                w = QMAX(w, tmpw);
 
1109
            }
 
1110
        } else {
 
1111
            bound.setHeight(fm.height());
 
1112
            w = fm.width(label);
 
1113
        }
 
1114
        bound.setWidth(w);
 
1115
    }
 
1116
    int arrowWidth = 0;
 
1117
    if (d->sortSection == section)
 
1118
        arrowWidth = ((orient == Qt::Horizontal ? height() : width()) / 2) + 8;
 
1119
    int height = qMax(bound.height() + 2, ih) + 4;
 
1120
    int width = bound.width() + style()->pixelMetric(QStyle::PM_HeaderMargin) * 4
 
1121
        + iw + arrowWidth;
 
1122
    return QSize(width, height);
 
1123
}
 
1124
 
 
1125
/*
 
1126
    Sets d->sizes[\a section] to a bounding rect based on its size
 
1127
    hint and font metrics, but constrained by \a size. It also updates
 
1128
    d->height.
 
1129
*/
 
1130
void Q3Header::setSectionSizeAndHeight(int section, int size)
 
1131
{
 
1132
    QSize sz = sectionSizeHint(section, fontMetrics());
 
1133
 
 
1134
    if (size < 0) {
 
1135
        if (d->sizes[section] < 0)
 
1136
            d->sizes[section] = (orient == Qt::Horizontal) ? sz.width()
 
1137
                                                         : sz.height();
 
1138
    } else {
 
1139
        d->sizes[section] = size;
 
1140
    }
 
1141
 
 
1142
    int newHeight = (orient == Qt::Horizontal) ? sz.height() : sz.width();
 
1143
    if (newHeight > d->height) {
 
1144
        d->height = newHeight;
 
1145
    } else if (newHeight < d->height) {
 
1146
        /*
 
1147
          We could be smarter, but we aren't. This makes a difference
 
1148
          only for users with many columns and '\n's in their headers
 
1149
          at the same time.
 
1150
        */
 
1151
        d->heightDirty = true;
 
1152
    }
 
1153
}
 
1154
 
 
1155
/*!
 
1156
    Adds a new section with label text \a s. Returns the index
 
1157
    position where the section was added (at the right for horizontal
 
1158
    headers, at the bottom for vertical headers). The section's width
 
1159
    is set to \a size. If \a size \< 0, an appropriate size for the
 
1160
    text \a s is chosen.
 
1161
*/
 
1162
int Q3Header::addLabel(const QString &s, int size)
 
1163
{
 
1164
    int n = ++d->count;
 
1165
    if ((int)d->icons.size() < n )
 
1166
        d->icons.resize(n);
 
1167
    if ((int)d->sizes.size() < n ) {
 
1168
        d->labels.resize(n);
 
1169
        d->sizes.resize(n);
 
1170
        d->positions.resize(n);
 
1171
        d->i2s.resize(n);
 
1172
        d->s2i.resize(n);
 
1173
        d->clicks.resize(n);
 
1174
        d->resize.resize(n);
 
1175
    }
 
1176
    int section = d->count - 1;
 
1177
    if (!d->is_a_table_header || !s.isNull())
 
1178
        d->labels.insert(section, s);
 
1179
 
 
1180
    if (size >= 0 && s.isNull() && d->is_a_table_header) {
 
1181
        d->sizes[section] = size;
 
1182
    } else {
 
1183
        d->sizes[section] = -1;
 
1184
        setSectionSizeAndHeight(section, size);
 
1185
    }
 
1186
 
 
1187
    int index = section;
 
1188
    d->positions[index] = d->lastPos;
 
1189
 
 
1190
    d->s2i[section] = index;
 
1191
    d->i2s[index] = section;
 
1192
    d->clicks.setBit(section, d->clicks_default);
 
1193
    d->resize.setBit(section, d->resize_default);
 
1194
 
 
1195
    if (updatesEnabled()) {
 
1196
        updateGeometry();
 
1197
        calculatePositions();
 
1198
        update();
 
1199
    }
 
1200
    return index;
 
1201
}
 
1202
 
 
1203
void Q3Header::resizeArrays(int size)
 
1204
{
 
1205
    d->icons.resize(size);
 
1206
    d->labels.resize(size);
 
1207
    d->sizes.resize(size);
 
1208
    d->positions.resize(size);
 
1209
    d->i2s.resize(size);
 
1210
    d->s2i.resize(size);
 
1211
    d->clicks.resize(size);
 
1212
    d->resize.resize(size);
 
1213
}
 
1214
 
 
1215
void Q3Header::setIsATableHeader(bool b)
 
1216
{
 
1217
    d->is_a_table_header = b;
 
1218
}
 
1219
 
 
1220
/*! \reimp */
 
1221
QSize Q3Header::sizeHint() const
 
1222
{
 
1223
    int width;
 
1224
    int height;
 
1225
 
 
1226
    ensurePolished();
 
1227
    QFontMetrics fm = fontMetrics();
 
1228
 
 
1229
    if (d->heightDirty) {
 
1230
        d->height = fm.lineSpacing() + 6;
 
1231
        for (int i = 0; i < count(); i++) {
 
1232
            int h = orient == Qt::Horizontal ?
 
1233
                    sectionSizeHint(i, fm).height() : sectionSizeHint(i, fm).width();
 
1234
            d->height = qMax(d->height, h);
 
1235
        }
 
1236
        d->heightDirty = false;
 
1237
    }
 
1238
 
 
1239
    if (orient == Qt::Horizontal) {
 
1240
        height = fm.lineSpacing() + 6;
 
1241
        width = 0;
 
1242
        height = qMax(height, d->height);
 
1243
        for (int i = 0; i < count(); i++)
 
1244
            width += d->sizes[i];
 
1245
    } else {
 
1246
        width = fm.width(' ');
 
1247
        height = 0;
 
1248
        width = qMax(width, d->height);
 
1249
        for (int i = 0; i < count(); i++)
 
1250
            height += d->sizes[i];
 
1251
    }
 
1252
    QStyleOptionHeader opt = getStyleOption(this, 0);
 
1253
    return style()->sizeFromContents(QStyle::CT_Q3Header, &opt, QSize(width, height),
 
1254
                                    this).expandedTo(QApplication::globalStrut());
 
1255
}
 
1256
 
 
1257
/*!
 
1258
    \property Q3Header::offset
 
1259
    \brief the header's left-most (or top-most) visible pixel
 
1260
 
 
1261
    Setting this property will scroll the header so that \e offset
 
1262
    becomes the left-most (or top-most for vertical headers) visible
 
1263
    pixel.
 
1264
*/
 
1265
int Q3Header::offset() const
 
1266
{
 
1267
    if (reverse())
 
1268
        return d->lastPos - width() - offs;
 
1269
    return offs;
 
1270
}
 
1271
 
 
1272
void Q3Header::setOffset(int x)
 
1273
{
 
1274
    int oldOff = offset();
 
1275
    offs = x;
 
1276
    if(d->lastPos < (orient == Qt::Horizontal ? width() : height()))
 
1277
        offs = 0;
 
1278
    else if (reverse())
 
1279
        offs = d->lastPos - width() - x;
 
1280
    if (orient == Qt::Horizontal)
 
1281
        scroll(oldOff-offset(), 0);
 
1282
    else
 
1283
        scroll(0, oldOff-offset());
 
1284
}
 
1285
 
 
1286
 
 
1287
 
 
1288
/*
 
1289
  Returns the position of actual division line \a i in widget
 
1290
  coordinates. May return a position outside the widget.
 
1291
 
 
1292
  Note that the last division line is numbered count(). (There is one
 
1293
  more line than the number of sections).
 
1294
*/
 
1295
int Q3Header::pPos(int i) const
 
1296
{
 
1297
    int pos;
 
1298
    if (i == count())
 
1299
        pos = d->lastPos;
 
1300
    else
 
1301
        pos = d->positions[i];
 
1302
    if (reverse())
 
1303
        pos = d->lastPos - pos;
 
1304
    return pos - offset();
 
1305
}
 
1306
 
 
1307
 
 
1308
/*
 
1309
  Returns the size of the section at index position \a i.
 
1310
*/
 
1311
int Q3Header::pSize(int i) const
 
1312
{
 
1313
    return d->sizes[d->i2s[i]];
 
1314
}
 
1315
 
 
1316
/*!
 
1317
  Use mapToSection() instead.
 
1318
 
 
1319
  Translates from actual index \a a (index at which the section is displayed)  to
 
1320
  logical index of the section.  Returns -1 if \a a is outside the legal range.
 
1321
 
 
1322
  \sa mapToActual()
 
1323
*/
 
1324
 
 
1325
int Q3Header::mapToLogical(int a) const
 
1326
{
 
1327
    return mapToSection(a);
 
1328
}
 
1329
 
 
1330
 
 
1331
/*!
 
1332
  Use mapToIndex() instead.
 
1333
 
 
1334
  Translates from logical index \a l to actual index (index at which the section \a l is displayed) .
 
1335
  Returns -1 if \a l is outside the legal range.
 
1336
 
 
1337
  \sa mapToLogical()
 
1338
*/
 
1339
 
 
1340
int Q3Header::mapToActual(int l) const
 
1341
{
 
1342
    return mapToIndex(l);
 
1343
}
 
1344
 
 
1345
 
 
1346
/*!
 
1347
  Use resizeSection() instead.
 
1348
 
 
1349
  Sets the size of the section \a section to \a s pixels.
 
1350
 
 
1351
  \warning does not repaint or send out signals
 
1352
*/
 
1353
 
 
1354
void Q3Header::setCellSize(int section, int s)
 
1355
{
 
1356
    if (section < 0 || section >= count())
 
1357
        return;
 
1358
    d->sizes[section] = s;
 
1359
    if (updatesEnabled())
 
1360
        calculatePositions();
 
1361
}
 
1362
 
 
1363
 
 
1364
/*!
 
1365
    If \a enable is true the user may resize section \a section;
 
1366
    otherwise the section may not be manually resized.
 
1367
 
 
1368
    If \a section is negative (the default) then the \a enable value
 
1369
    is set for all existing sections and will be applied to any new
 
1370
    sections that are added.
 
1371
    Example:
 
1372
    \code
 
1373
    // Allow resizing of all current and future sections
 
1374
    header->setResizeEnabled(true);
 
1375
    // Disable resizing of section 3, (the fourth section added)
 
1376
    header->setResizeEnabled(false, 3);
 
1377
    \endcode
 
1378
 
 
1379
    If the user resizes a section, a sizeChange() signal is emitted.
 
1380
 
 
1381
    \sa setMovingEnabled() setClickEnabled() setTracking()
 
1382
*/
 
1383
 
 
1384
void Q3Header::setResizeEnabled(bool enable, int section)
 
1385
{
 
1386
    if (section < 0) {
 
1387
        d->resize.fill(enable);
 
1388
        // and future ones...
 
1389
        d->resize_default = enable;
 
1390
    } else if (section < count()) {
 
1391
        d->resize[section] = enable;
 
1392
    }
 
1393
}
 
1394
 
 
1395
 
 
1396
/*!
 
1397
    \property Q3Header::moving
 
1398
    \brief whether the header sections can be moved
 
1399
 
 
1400
    If this property is true (the default) the user can move sections.
 
1401
    If the user moves a section the indexChange() signal is emitted.
 
1402
 
 
1403
    \sa setClickEnabled(), setResizeEnabled()
 
1404
*/
 
1405
 
 
1406
void Q3Header::setMovingEnabled(bool enable)
 
1407
{
 
1408
    d->move = enable;
 
1409
}
 
1410
 
 
1411
 
 
1412
/*!
 
1413
    If \a enable is true, any clicks on section \a section will result
 
1414
    in clicked() signals being emitted; otherwise the section will
 
1415
    ignore clicks.
 
1416
 
 
1417
    If \a section is -1 (the default) then the \a enable value is set
 
1418
    for all existing sections and will be applied to any new sections
 
1419
    that are added.
 
1420
 
 
1421
    \sa setMovingEnabled(), setResizeEnabled()
 
1422
*/
 
1423
 
 
1424
void Q3Header::setClickEnabled(bool enable, int section)
 
1425
{
 
1426
    if (section < 0) {
 
1427
        d->clicks.fill(enable);
 
1428
        // and future ones...
 
1429
        d->clicks_default = enable;
 
1430
    } else if (section < count()) {
 
1431
        d->clicks[section] = enable;
 
1432
    }
 
1433
}
 
1434
 
 
1435
 
 
1436
/*!
 
1437
    Paints the section at position \a index, inside rectangle \a fr
 
1438
    (which uses widget coordinates) using painter \a p.
 
1439
 
 
1440
    Calls paintSectionLabel().
 
1441
*/
 
1442
 
 
1443
void Q3Header::paintSection(QPainter *p, int index, const QRect& fr)
 
1444
{
 
1445
    int section = mapToSection(index);
 
1446
    QStyleOptionHeader opt = getStyleOption(this, section);
 
1447
    opt.state |= QStyle::State_Raised;
 
1448
    opt.rect = fr;
 
1449
 
 
1450
    if (section < 0) {
 
1451
        style()->drawControl(QStyle::CE_HeaderSection, &opt, p, this);
 
1452
        return;
 
1453
    }
 
1454
 
 
1455
    if (sectionSize(section) <= 0)
 
1456
        return;
 
1457
 
 
1458
    opt.state = (orient == Qt::Horizontal ? QStyle::State_Horizontal : QStyle::State_None);
 
1459
    if (d->sortSection == section)
 
1460
        opt.sortIndicator = d->sortDirection ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
 
1461
 
 
1462
    if (isEnabled())
 
1463
        opt.state |= QStyle::State_Enabled;
 
1464
    if (isClickEnabled(section) && (state == Pressed || state == Moving) && index == handleIdx)
 
1465
        opt.state |= QStyle::State_Sunken; //currently pressed
 
1466
    if (!(opt.state & QStyle::State_Sunken))
 
1467
        opt.state |= QStyle::State_Raised;
 
1468
    p->setBrushOrigin(fr.topLeft());
 
1469
    if (d->clicks[section]) {
 
1470
        style()->drawControl(QStyle::CE_HeaderSection, &opt, p, this);
 
1471
    } else {
 
1472
        p->save();
 
1473
        p->setClipRect(fr); // hack to keep styles working
 
1474
        opt.rect.setRect(fr.x() - 2, fr.y() - 2, fr.width() + 4, fr.height() + 4);
 
1475
        style()->drawControl(QStyle::CE_Header, &opt, p, this);
 
1476
        if (orient == Qt::Horizontal) {
 
1477
            p->setPen(palette().color(QPalette::Mid));
 
1478
            p->drawLine(fr.x(), fr.y() + fr.height() - 1,
 
1479
                         fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);
 
1480
            p->drawLine(fr.x() + fr.width() - 1, fr.y(),
 
1481
                         fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);
 
1482
            p->setPen(palette().color(QPalette::Light));
 
1483
            if (index > 0)
 
1484
                p->drawLine(fr.x(), fr.y(), fr.x(), fr.y() + fr.height() - 1);
 
1485
            if (index == count() - 1) {
 
1486
                p->drawLine(fr.x() + fr.width() - 1, fr.y(),
 
1487
                             fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);
 
1488
                p->setPen(palette().color(QPalette::Mid));
 
1489
                p->drawLine(fr.x() + fr.width() - 2, fr.y(),
 
1490
                             fr.x() + fr.width() - 2, fr.y() + fr.height() - 1);
 
1491
            }
 
1492
        } else {
 
1493
            p->setPen(palette().color(QPalette::Mid));
 
1494
            p->drawLine(fr.x() + width() - 1, fr.y(),
 
1495
                         fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);
 
1496
            p->drawLine(fr.x(), fr.y() + fr.height() - 1,
 
1497
                         fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);
 
1498
            p->setPen(palette().color(QPalette::Light));
 
1499
            if (index > 0)
 
1500
                p->drawLine(fr.x(), fr.y(), fr.x() + fr.width() - 1, fr.y());
 
1501
            if (index == count() - 1) {
 
1502
                p->drawLine(fr.x(), fr.y() + fr.height() - 1,
 
1503
                             fr.x() + fr.width() - 1, fr.y() + fr.height() - 1);
 
1504
                p->setPen(palette().color(QPalette::Mid));
 
1505
                p->drawLine(fr.x(), fr.y() + fr.height() - 2,
 
1506
                             fr.x() + fr.width() - 1, fr.y() + fr.height() - 2);
 
1507
            }
 
1508
        }
 
1509
        p->restore();
 
1510
    }
 
1511
 
 
1512
    paintSectionLabel(p, index, fr);
 
1513
}
 
1514
 
 
1515
/*!
 
1516
    Paints the label of the section at position \a index, inside
 
1517
    rectangle \a fr (which uses widget coordinates) using painter \a
 
1518
    p.
 
1519
 
 
1520
    Called by paintSection()
 
1521
*/
 
1522
void Q3Header::paintSectionLabel(QPainter *p, int index, const QRect& fr)
 
1523
{
 
1524
    int section = mapToSection(index);
 
1525
    if (section < 0)
 
1526
        return;
 
1527
 
 
1528
    int dx = 0, dy = 0;
 
1529
    QStyleOptionHeader opt = getStyleOption(this, section);
 
1530
    if (d->sortSection == section)
 
1531
        opt.sortIndicator = d->sortDirection ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
 
1532
    if (index == handleIdx && (state == Pressed || state == Moving)) {
 
1533
        dx = style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &opt, this);
 
1534
        dy = style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &opt, this);
 
1535
        opt.state |= QStyle::State_Sunken;
 
1536
    }
 
1537
    if (isEnabled())
 
1538
        opt.state |= QStyle::State_Enabled;
 
1539
 
 
1540
 
 
1541
    opt.rect.setRect(fr.x() + style()->pixelMetric(QStyle::PM_HeaderMargin) + dx, fr.y() + 2 + dy,
 
1542
                     fr.width() - 6, fr.height() - 4);
 
1543
 
 
1544
    style()->drawControl(QStyle::CE_HeaderLabel, &opt, p, this);
 
1545
 
 
1546
    int arrowWidth = (orient == Qt::Horizontal ? height() : width()) / 2;
 
1547
    int arrowHeight = fr.height() - 6;
 
1548
    QSize ssh = sectionSizeHint(section, p->fontMetrics());
 
1549
    int tw = (orient == Qt::Horizontal ? ssh.width() : ssh.height());
 
1550
    int ew = 0;
 
1551
 
 
1552
    if (style()->styleHint(QStyle::SH_Header_ArrowAlignment, 0, this) & Qt::AlignRight)
 
1553
        ew = fr.width() - tw - 8;
 
1554
    if (d->sortSection == section && tw <= fr.width()) {
 
1555
        if (reverse()) {
 
1556
            tw = fr.width() - tw;
 
1557
            ew = fr.width() - ew - tw;
 
1558
        }
 
1559
        opt.state = QStyle::State_None;
 
1560
        if (isEnabled())
 
1561
            opt.state |= QStyle::State_Enabled;
 
1562
        if (d->sortDirection)
 
1563
            opt.state |= QStyle::State_DownArrow;
 
1564
        else
 
1565
            opt.state |= QStyle::State_UpArrow;
 
1566
        QRect ar(fr.x() + tw - arrowWidth - 6 + ew, 4, arrowWidth, arrowHeight);
 
1567
        if (label(section).isRightToLeft())
 
1568
            ar.moveBy( 2*(fr.right() - ar.right()) + ar.width() - fr.width(), 0 );
 
1569
        opt.rect = ar;
 
1570
        style()->drawPrimitive(QStyle::PE_IndicatorHeaderArrow, &opt, p, this);
 
1571
    }
 
1572
}
 
1573
 
 
1574
 
 
1575
/*! \reimp */
 
1576
void Q3Header::paintEvent(QPaintEvent *e)
 
1577
{
 
1578
    QPainter p(this);
 
1579
    p.setPen(palette().buttonText().color());
 
1580
    int pos = orient == Qt::Horizontal ? e->rect().left() : e->rect().top();
 
1581
    int id = mapToIndex(sectionAt(pos + offset()));
 
1582
    if (id < 0) {
 
1583
        if (pos > 0)
 
1584
            id = d->count;
 
1585
        else if (reverse())
 
1586
            id = d->count - 1;
 
1587
        else
 
1588
            id = 0;
 
1589
    }
 
1590
    if (reverse()) {
 
1591
        for (int i = id; i >= 0; i--) {
 
1592
            QRect r = sRect(i);
 
1593
            paintSection(&p, i, r);
 
1594
            if (r.right() >= e->rect().right())
 
1595
                return;
 
1596
        }
 
1597
    } else {
 
1598
        if (count() > 0) {
 
1599
            for (int i = id; i <= count(); i++) {
 
1600
                QRect r = sRect(i);
 
1601
                /*
 
1602
                  If the last section is clickable (and thus is
 
1603
                  painted raised), draw the virtual section count()
 
1604
                  as well. Otherwise it looks ugly.
 
1605
                */
 
1606
                if (i < count() || d->clicks[mapToSection(count() - 1)])
 
1607
                    paintSection(&p, i, r);
 
1608
                if (hasFocus() && d->focusIdx == i) {
 
1609
                    QStyleOptionFocusRect opt;
 
1610
                    opt.rect.setRect(r.x()+2, r.y()+2, r.width()-4, r.height()-4);
 
1611
                    opt.palette = palette();
 
1612
                    opt.state = QStyle::State_None;
 
1613
                    style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &p, this);
 
1614
                }
 
1615
                if (orient == Qt::Horizontal && r. right() >= e->rect().right() ||
 
1616
                     orient == Qt::Vertical && r. bottom() >= e->rect().bottom())
 
1617
                    return;
 
1618
            }
 
1619
        }
 
1620
    }
 
1621
}
 
1622
 
 
1623
/*!
 
1624
    \overload
 
1625
 
 
1626
    Sets the sort indicator to \a ascending. Use the other overload instead.
 
1627
*/
 
1628
 
 
1629
void Q3Header::setSortIndicator(int section, bool ascending)
 
1630
{
 
1631
    d->sortSection = section;
 
1632
    if (section != -1)
 
1633
        oldHandleIdx = section;
 
1634
    d->sortDirection = ascending;
 
1635
    update();
 
1636
    updateGeometry();
 
1637
}
 
1638
 
 
1639
/*!
 
1640
  \fn void Q3Header::setSortIndicator(int section, Qt::SortOrder order)
 
1641
 
 
1642
  Sets a sort indicator onto the specified \a section. The indicator's
 
1643
  \a order is either Ascending or Descending.
 
1644
 
 
1645
  Only one section can show a sort indicator at any one time. If you
 
1646
  don't want any section to show a sort indicator pass a \a section
 
1647
  number of -1.
 
1648
 
 
1649
  \sa sortIndicatorSection(), sortIndicatorOrder()
 
1650
*/
 
1651
 
 
1652
/*!
 
1653
    Returns the section showing the sort indicator or -1 if there is no sort indicator.
 
1654
 
 
1655
    \sa setSortIndicator(), sortIndicatorOrder()
 
1656
*/
 
1657
 
 
1658
int Q3Header::sortIndicatorSection() const
 
1659
{
 
1660
    return d->sortSection;
 
1661
}
 
1662
 
 
1663
/*!
 
1664
    Returns the implied sort order of the Q3Headers sort indicator.
 
1665
 
 
1666
    \sa setSortIndicator(), sortIndicatorSection()
 
1667
*/
 
1668
 
 
1669
Qt::SortOrder Q3Header::sortIndicatorOrder() const
 
1670
{
 
1671
    return d->sortDirection ? Qt::AscendingOrder : Qt::DescendingOrder;
 
1672
}
 
1673
 
 
1674
/*!
 
1675
    Resizes section \a section to \a s pixels wide (or high).
 
1676
*/
 
1677
 
 
1678
void Q3Header::resizeSection(int section, int s)
 
1679
{
 
1680
    setCellSize(section, s);
 
1681
    update();
 
1682
}
 
1683
 
 
1684
/*!
 
1685
    Returns the width (or height) of the \a section in pixels.
 
1686
*/
 
1687
 
 
1688
int Q3Header::sectionSize(int section) const
 
1689
{
 
1690
    if (section < 0 || section >= count())
 
1691
        return 0;
 
1692
    return d->sizes[section];
 
1693
}
 
1694
 
 
1695
/*!
 
1696
    Returns the position (in pixels) at which the \a section starts.
 
1697
 
 
1698
    \sa offset()
 
1699
*/
 
1700
 
 
1701
int Q3Header::sectionPos(int section) const
 
1702
{
 
1703
    if (d->positionsDirty)
 
1704
        ((Q3Header *)this)->calculatePositions();
 
1705
    if (section < 0 || section >= count() )
 
1706
        return 0;
 
1707
    return d->positions[d->s2i[section]];
 
1708
}
 
1709
 
 
1710
/*!
 
1711
    Returns the index of the section which contains the position \a
 
1712
    pos given in pixels from the left (or top).
 
1713
 
 
1714
    \sa offset()
 
1715
*/
 
1716
 
 
1717
int Q3Header::sectionAt(int pos) const
 
1718
{
 
1719
    if (reverse())
 
1720
        pos = d->lastPos - pos;
 
1721
    return d->sectionAt(pos);
 
1722
}
 
1723
 
 
1724
/*!
 
1725
    Returns the number of the section that is displayed at index
 
1726
    position \a index.
 
1727
*/
 
1728
 
 
1729
int Q3Header::mapToSection(int index) const
 
1730
{
 
1731
    return (index >= 0 && index < count()) ? d->i2s[index] : -1;
 
1732
}
 
1733
 
 
1734
/*!
 
1735
    Returns the index position at which section \a section is
 
1736
    displayed.
 
1737
*/
 
1738
 
 
1739
int Q3Header::mapToIndex(int section) const
 
1740
{
 
1741
    return (section >= 0 && section < count()) ? d->s2i[section] : -1;
 
1742
}
 
1743
 
 
1744
/*!
 
1745
    Moves section \a section to index position \a toIndex.
 
1746
*/
 
1747
 
 
1748
void Q3Header::moveSection(int section, int toIndex)
 
1749
{
 
1750
    int fromIndex = mapToIndex(section);
 
1751
    if (fromIndex == toIndex ||
 
1752
         fromIndex < 0 || fromIndex > count() ||
 
1753
         toIndex < 0 || toIndex > count())
 
1754
        return;
 
1755
    int i;
 
1756
    int idx = d->i2s[fromIndex];
 
1757
    if (fromIndex < toIndex) {
 
1758
        for (i = fromIndex; i < toIndex - 1; i++) {
 
1759
            int t;
 
1760
            d->i2s[i] = t = d->i2s[i+1];
 
1761
            d->s2i[t] = i;
 
1762
        }
 
1763
        d->i2s[toIndex-1] = idx;
 
1764
        d->s2i[idx] = toIndex-1;
 
1765
    } else {
 
1766
        for (i = fromIndex; i > toIndex; i--) {
 
1767
            int t;
 
1768
            d->i2s[i] = t = d->i2s[i-1];
 
1769
            d->s2i[t] = i;
 
1770
        }
 
1771
        d->i2s[toIndex] = idx;
 
1772
        d->s2i[idx] = toIndex;
 
1773
    }
 
1774
    calculatePositions();
 
1775
}
 
1776
 
 
1777
/*!
 
1778
    Returns true if section \a section is clickable; otherwise returns
 
1779
    false.
 
1780
 
 
1781
    If \a section is out of range (negative or larger than count() -
 
1782
    1): returns true if all sections are clickable; otherwise returns
 
1783
    false.
 
1784
 
 
1785
    \sa setClickEnabled()
 
1786
*/
 
1787
 
 
1788
bool Q3Header::isClickEnabled(int section) const
 
1789
{
 
1790
    if (section >= 0 && section < count()) {
 
1791
        return (bool)d->clicks[section];
 
1792
    }
 
1793
 
 
1794
    for (int i = 0; i < count(); ++i) {
 
1795
        if (!d->clicks[i])
 
1796
            return false;
 
1797
    }
 
1798
    return true;
 
1799
}
 
1800
 
 
1801
/*!
 
1802
    Returns true if section \a section is resizeable; otherwise
 
1803
    returns false.
 
1804
 
 
1805
    If \a section is -1 then this function applies to all sections,
 
1806
    i.e. returns true if all sections are resizeable; otherwise
 
1807
    returns false.
 
1808
 
 
1809
    \sa setResizeEnabled()
 
1810
*/
 
1811
 
 
1812
bool Q3Header::isResizeEnabled(int section) const
 
1813
{
 
1814
    if (section >= 0 && section < count()) {
 
1815
        return (bool)d->resize[section];
 
1816
    }
 
1817
 
 
1818
    for (int i = 0; i < count();++i) {
 
1819
        if (!d->resize[i])
 
1820
            return false;
 
1821
    }
 
1822
    return true;
 
1823
}
 
1824
 
 
1825
bool Q3Header::isMovingEnabled() const
 
1826
{
 
1827
    return d->move;
 
1828
}
 
1829
 
 
1830
/*! \internal */
 
1831
 
 
1832
void Q3Header::setUpdatesEnabled(bool enable)
 
1833
{
 
1834
    if (enable)
 
1835
        calculatePositions();
 
1836
    QWidget::setUpdatesEnabled(enable);
 
1837
}
 
1838
 
 
1839
 
 
1840
bool Q3Header::reverse () const
 
1841
{
 
1842
#if 0
 
1843
    return (orient == Qt::Horizontal && QApplication::reverseLayout());
 
1844
#else
 
1845
    return false;
 
1846
#endif
 
1847
}
 
1848
 
 
1849
/*! \reimp */
 
1850
void Q3Header::resizeEvent(QResizeEvent *e)
 
1851
{
 
1852
    if (e)
 
1853
        QWidget::resizeEvent(e);
 
1854
 
 
1855
    if(d->lastPos < width()) {
 
1856
            offs = 0;
 
1857
    }
 
1858
 
 
1859
    if (e) {
 
1860
        adjustHeaderSize(orientation() == Qt::Horizontal ?
 
1861
                          width() - e->oldSize().width() : height() - e->oldSize().height());
 
1862
        if ((orientation() == Qt::Horizontal && height() != e->oldSize().height())
 
1863
             || (orientation() == Qt::Vertical && width() != e->oldSize().width()))
 
1864
            update();
 
1865
    } else
 
1866
        adjustHeaderSize();
 
1867
}
 
1868
 
 
1869
/*!
 
1870
    \fn void Q3Header::adjustHeaderSize()
 
1871
 
 
1872
    Adjusts the size of the sections to fit the size of the header as
 
1873
    completely as possible. Only sections for which isStretchEnabled()
 
1874
    is true will be resized.
 
1875
*/
 
1876
 
 
1877
void Q3Header::adjustHeaderSize(int diff)
 
1878
{
 
1879
    if (!count())
 
1880
        return;
 
1881
 
 
1882
    // we skip the adjustHeaderSize when trying to resize the last column which is set to stretchable
 
1883
    if (d->fullSize == (count() -1) &&
 
1884
         (d->lastPos - d->sizes[count() -1]) > (orient == Qt::Horizontal ? width() : height()))
 
1885
        return;
 
1886
 
 
1887
    if (d->fullSize >= 0) {
 
1888
        int sec = mapToSection(d->fullSize);
 
1889
        int lsec = mapToSection(count() - 1);
 
1890
        int ns = sectionSize(sec) +
 
1891
                 (orientation() == Qt::Horizontal ?
 
1892
                   width() : height()) - (sectionPos(lsec) + sectionSize(lsec));
 
1893
        int os = sectionSize(sec);
 
1894
        if (ns < 20)
 
1895
            ns = 20;
 
1896
        setCellSize(sec, ns);
 
1897
        repaint();
 
1898
        emit sizeChange(sec, os, ns);
 
1899
    } else if (d->fullSize == -1) {
 
1900
        int df = diff / count();
 
1901
        int part = orientation() == Qt::Horizontal ? width() / count() : height() / count();
 
1902
        for (int i = 0; i < count() - 1; ++i) {
 
1903
            int sec = mapToIndex(i);
 
1904
            int os = sectionSize(sec);
 
1905
            int ns = diff != -1 ? os + df : part;
 
1906
            if (ns < 20)
 
1907
                ns = 20;
 
1908
            setCellSize(sec, ns);
 
1909
            emit sizeChange(sec, os, ns);
 
1910
        }
 
1911
        int sec = mapToIndex(count() - 1);
 
1912
        int ns = (orientation() == Qt::Horizontal ? width() : height()) - sectionPos(sec);
 
1913
        int os = sectionSize(sec);
 
1914
        if (ns < 20)
 
1915
            ns = 20;
 
1916
        setCellSize(sec, ns);
 
1917
        repaint();
 
1918
        emit sizeChange(sec, os, ns);
 
1919
    }
 
1920
}
 
1921
 
 
1922
/*!
 
1923
    Returns the total width of all the header columns.
 
1924
*/
 
1925
int Q3Header::headerWidth() const
 
1926
{
 
1927
    if (d->pos_dirty) {
 
1928
        ((Q3Header*)this)->calculatePositions();
 
1929
        d->pos_dirty = false;
 
1930
    }
 
1931
    return d->lastPos;
 
1932
}
 
1933
 
 
1934
void Q3Header::calculatePositions(bool onlyVisible, int start)
 
1935
{
 
1936
    d->positionsDirty = false;
 
1937
    d->lastPos = count() > 0 ? d->positions[start] : 0;
 
1938
    for (int i = start; i < count(); i++) {
 
1939
        d->positions[i] = d->lastPos;
 
1940
        d->lastPos += d->sizes[d->i2s[i]];
 
1941
        if (onlyVisible && d->lastPos > offset() +
 
1942
             (orientation() == Qt::Horizontal ? width() : height()))
 
1943
            break;
 
1944
    }
 
1945
    d->pos_dirty = onlyVisible;
 
1946
}
 
1947
 
 
1948
 
 
1949
/*!
 
1950
    \property Q3Header::stretching
 
1951
    \brief whether the header sections always take up the full width
 
1952
    (or height) of the header
 
1953
*/
 
1954
 
 
1955
 
 
1956
/*!
 
1957
    If \a b is true, section \a section will be resized when the
 
1958
    header is resized, so that the sections take up the full width (or
 
1959
    height for vertical headers) of the header; otherwise section \a
 
1960
    section will be set to be unstretchable and will not resize when
 
1961
    the header is resized.
 
1962
 
 
1963
    If \a section is -1, and if \a b is true, then all sections will
 
1964
    be resized equally when the header is resized so that they take up
 
1965
    the full width (or height for vertical headers) of the header;
 
1966
    otherwise all the sections will be set to be unstretchable and
 
1967
    will not resize when the header is resized.
 
1968
 
 
1969
    \sa adjustHeaderSize()
 
1970
*/
 
1971
 
 
1972
void Q3Header::setStretchEnabled(bool b, int section)
 
1973
{
 
1974
    if (b)
 
1975
        d->fullSize = section;
 
1976
    else
 
1977
        d->fullSize = -2;
 
1978
    adjustHeaderSize();
 
1979
}
 
1980
 
 
1981
bool Q3Header::isStretchEnabled() const
 
1982
{
 
1983
    return d->fullSize == -1;
 
1984
}
 
1985
 
 
1986
/*!
 
1987
    \overload
 
1988
 
 
1989
    Returns true if section \a section will resize to take up the full
 
1990
    width (or height) of the header; otherwise returns false. If at
 
1991
    least one section has stretch enabled the sections will always
 
1992
    take up the full width of the header.
 
1993
 
 
1994
    \sa setStretchEnabled()
 
1995
*/
 
1996
 
 
1997
bool Q3Header::isStretchEnabled(int section) const
 
1998
{
 
1999
    return d->fullSize == section;
 
2000
}
 
2001
 
 
2002
/*!
 
2003
  \reimp
 
2004
*/
 
2005
void Q3Header::changeEvent(QEvent *ev)
 
2006
{
 
2007
    if(ev->type() == QEvent::FontChange) {
 
2008
        QFontMetrics fm = fontMetrics();
 
2009
        d->height = (orient == Qt::Horizontal) ? fm.lineSpacing() + 6 : fm.width(' ');
 
2010
    }
 
2011
    QWidget::changeEvent(ev);
 
2012
}
 
2013
 
 
2014
#endif // QT_NO_HEADER