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