|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt3Support module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |