| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the QtWidgets module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 | #include <qglobal.h> | 
| 41 | #include "qcolumnview.h" | 
| 42 |  | 
| 43 | #if QT_CONFIG(columnview) | 
| 44 |  | 
| 45 | #include "qcolumnview_p.h" | 
| 46 | #include "qcolumnviewgrip_p.h" | 
| 47 |  | 
| 48 | #include <qlistview.h> | 
| 49 | #include <qabstractitemdelegate.h> | 
| 50 | #include <qscrollbar.h> | 
| 51 | #include <qpainter.h> | 
| 52 | #include <qdebug.h> | 
| 53 |  | 
| 54 | QT_BEGIN_NAMESPACE | 
| 55 |  | 
| 56 | /*! | 
| 57 |     \since 4.3 | 
| 58 |     \class QColumnView | 
| 59 |     \brief The QColumnView class provides a model/view implementation of a column view. | 
| 60 |     \ingroup model-view | 
| 61 |     \ingroup advanced | 
| 62 |     \inmodule QtWidgets | 
| 63 |  | 
| 64 |     QColumnView displays a model in a number of QListViews, one for each | 
| 65 |     hierarchy in the tree.  This is sometimes referred to as a cascading list. | 
| 66 |  | 
| 67 |     The QColumnView class is one of the \l{Model/View Classes} | 
| 68 |     and is part of Qt's \l{Model/View Programming}{model/view framework}. | 
| 69 |  | 
| 70 |     QColumnView implements the interfaces defined by the | 
| 71 |     QAbstractItemView class to allow it to display data provided by | 
| 72 |     models derived from the QAbstractItemModel class. | 
| 73 |  | 
| 74 |     \image qcolumnview.png | 
| 75 |  | 
| 76 |     \sa {Model/View Programming} | 
| 77 | */ | 
| 78 |  | 
| 79 | /*! | 
| 80 |     Constructs a column view with a \a parent to represent a model's | 
| 81 |     data. Use setModel() to set the model. | 
| 82 |  | 
| 83 |     \sa QAbstractItemModel | 
| 84 | */ | 
| 85 | QColumnView::QColumnView(QWidget * parent) | 
| 86 | :  QAbstractItemView(*new QColumnViewPrivate, parent) | 
| 87 | { | 
| 88 |     Q_D(QColumnView); | 
| 89 |     d->initialize(); | 
| 90 | } | 
| 91 |  | 
| 92 | /*! | 
| 93 |     \internal | 
| 94 | */ | 
| 95 | QColumnView::QColumnView(QColumnViewPrivate & dd, QWidget * parent) | 
| 96 | :  QAbstractItemView(dd, parent) | 
| 97 | { | 
| 98 |     Q_D(QColumnView); | 
| 99 |     d->initialize(); | 
| 100 | } | 
| 101 |  | 
| 102 | void QColumnViewPrivate::initialize() | 
| 103 | { | 
| 104 |     Q_Q(QColumnView); | 
| 105 |     q->setTextElideMode(Qt::ElideMiddle); | 
| 106 | #if QT_CONFIG(animation) | 
| 107 |     QObject::connect(sender: ¤tAnimation, SIGNAL(finished()), receiver: q, SLOT(_q_changeCurrentColumn())); | 
| 108 |     currentAnimation.setTargetObject(hbar); | 
| 109 |     currentAnimation.setPropertyName("value" ); | 
| 110 |     currentAnimation.setEasingCurve(QEasingCurve::InOutQuad); | 
| 111 | #endif // animation | 
| 112 |     delete itemDelegate; | 
| 113 |     q->setItemDelegate(new QColumnViewDelegate(q)); | 
| 114 | } | 
| 115 |  | 
| 116 | /*! | 
| 117 |     Destroys the column view. | 
| 118 | */ | 
| 119 | QColumnView::~QColumnView() | 
| 120 | { | 
| 121 | } | 
| 122 |  | 
| 123 | /*! | 
| 124 |     \property QColumnView::resizeGripsVisible | 
| 125 |     \brief the way to specify if the list views gets resize grips or not | 
| 126 |  | 
| 127 |     By default, \c visible is set to true | 
| 128 |  | 
| 129 |     \sa setRootIndex() | 
| 130 | */ | 
| 131 | void QColumnView::setResizeGripsVisible(bool visible) | 
| 132 | { | 
| 133 |     Q_D(QColumnView); | 
| 134 |     if (d->showResizeGrips == visible) | 
| 135 |         return; | 
| 136 |     d->showResizeGrips = visible; | 
| 137 |     for (int i = 0; i < d->columns.count(); ++i) { | 
| 138 |         QAbstractItemView *view = d->columns[i]; | 
| 139 |         if (visible) { | 
| 140 |             QColumnViewGrip *grip = new QColumnViewGrip(view); | 
| 141 |             view->setCornerWidget(grip); | 
| 142 |             connect(sender: grip, SIGNAL(gripMoved(int)), receiver: this, SLOT(_q_gripMoved(int))); | 
| 143 |         } else { | 
| 144 |             QWidget *widget = view->cornerWidget(); | 
| 145 |             view->setCornerWidget(nullptr); | 
| 146 |             widget->deleteLater(); | 
| 147 |         } | 
| 148 |     } | 
| 149 | } | 
| 150 |  | 
| 151 | bool QColumnView::resizeGripsVisible() const | 
| 152 | { | 
| 153 |     Q_D(const QColumnView); | 
| 154 |     return d->showResizeGrips; | 
| 155 | } | 
| 156 |  | 
| 157 | /*! | 
| 158 |     \reimp | 
| 159 | */ | 
| 160 | void QColumnView::setModel(QAbstractItemModel *model) | 
| 161 | { | 
| 162 |     Q_D(QColumnView); | 
| 163 |     if (model == d->model) | 
| 164 |         return; | 
| 165 |     d->closeColumns(); | 
| 166 |     QAbstractItemView::setModel(model); | 
| 167 | } | 
| 168 |  | 
| 169 | /*! | 
| 170 |     \reimp | 
| 171 | */ | 
| 172 | void QColumnView::setRootIndex(const QModelIndex &index) | 
| 173 | { | 
| 174 |     Q_D(QColumnView); | 
| 175 |     if (!model()) | 
| 176 |         return; | 
| 177 |  | 
| 178 |     d->closeColumns(); | 
| 179 |     Q_ASSERT(d->columns.count() == 0); | 
| 180 |  | 
| 181 |     QAbstractItemView *view = d->createColumn(index, show: true); | 
| 182 |     if (view->selectionModel()) | 
| 183 |         view->selectionModel()->deleteLater(); | 
| 184 |     if (view->model()) | 
| 185 |         view->setSelectionModel(selectionModel()); | 
| 186 |  | 
| 187 |     QAbstractItemView::setRootIndex(index); | 
| 188 |     d->updateScrollbars(); | 
| 189 | } | 
| 190 |  | 
| 191 | /*! | 
| 192 |     \reimp | 
| 193 | */ | 
| 194 | bool QColumnView::isIndexHidden(const QModelIndex &index) const | 
| 195 | { | 
| 196 |     Q_UNUSED(index); | 
| 197 |     return false; | 
| 198 | } | 
| 199 |  | 
| 200 | /*! | 
| 201 |     \reimp | 
| 202 | */ | 
| 203 | QModelIndex QColumnView::indexAt(const QPoint &point) const | 
| 204 | { | 
| 205 |     Q_D(const QColumnView); | 
| 206 |     for (int i = 0; i < d->columns.size(); ++i) { | 
| 207 |         QPoint topLeft = d->columns.at(i)->frameGeometry().topLeft(); | 
| 208 |         QPoint adjustedPoint(point.x() - topLeft.x(), point.y() - topLeft.y()); | 
| 209 |         QModelIndex index = d->columns.at(i)->indexAt(point: adjustedPoint); | 
| 210 |         if (index.isValid()) | 
| 211 |             return index; | 
| 212 |     } | 
| 213 |     return QModelIndex(); | 
| 214 | } | 
| 215 |  | 
| 216 | /*! | 
| 217 |     \reimp | 
| 218 | */ | 
| 219 | QRect QColumnView::visualRect(const QModelIndex &index) const | 
| 220 | { | 
| 221 |     if (!index.isValid()) | 
| 222 |         return QRect(); | 
| 223 |  | 
| 224 |     Q_D(const QColumnView); | 
| 225 |     for (int i = 0; i < d->columns.size(); ++i) { | 
| 226 |         QRect rect = d->columns.at(i)->visualRect(index); | 
| 227 |         if (!rect.isNull()) { | 
| 228 |             rect.translate(p: d->columns.at(i)->frameGeometry().topLeft()); | 
| 229 |             return rect; | 
| 230 |         } | 
| 231 |     } | 
| 232 |     return QRect(); | 
| 233 | } | 
| 234 |  | 
| 235 | /*! | 
| 236 |     \reimp | 
| 237 |  */ | 
| 238 | void QColumnView::scrollContentsBy(int dx, int dy) | 
| 239 | { | 
| 240 |     Q_D(QColumnView); | 
| 241 |     if (d->columns.isEmpty() || dx == 0) | 
| 242 |         return; | 
| 243 |  | 
| 244 |     dx = isRightToLeft() ? -dx : dx; | 
| 245 |     for (int i = 0; i < d->columns.count(); ++i) | 
| 246 |         d->columns.at(i)->move(ax: d->columns.at(i)->x() + dx, ay: 0); | 
| 247 |     d->offset += dx; | 
| 248 |     QAbstractItemView::scrollContentsBy(dx, dy); | 
| 249 | } | 
| 250 |  | 
| 251 | /*! | 
| 252 |     \reimp | 
| 253 | */ | 
| 254 | void QColumnView::scrollTo(const QModelIndex &index, ScrollHint hint) | 
| 255 | { | 
| 256 |     Q_D(QColumnView); | 
| 257 |     Q_UNUSED(hint); | 
| 258 |     if (!index.isValid() || d->columns.isEmpty()) | 
| 259 |         return; | 
| 260 |  | 
| 261 | #if QT_CONFIG(animation) | 
| 262 |     if (d->currentAnimation.state() == QPropertyAnimation::Running) | 
| 263 |         return; | 
| 264 |  | 
| 265 |     d->currentAnimation.stop(); | 
| 266 | #endif // animation | 
| 267 |  | 
| 268 |     // Fill up what is needed to get to index | 
| 269 |     d->closeColumns(parent: index, build: true); | 
| 270 |  | 
| 271 |     QModelIndex indexParent = index.parent(); | 
| 272 |     // Find the left edge of the column that contains index | 
| 273 |     int currentColumn = 0; | 
| 274 |     int leftEdge = 0; | 
| 275 |     while (currentColumn < d->columns.size()) { | 
| 276 |         if (indexParent == d->columns.at(i: currentColumn)->rootIndex()) | 
| 277 |             break; | 
| 278 |         leftEdge += d->columns.at(i: currentColumn)->width(); | 
| 279 |         ++currentColumn; | 
| 280 |     } | 
| 281 |  | 
| 282 |     // Don't let us scroll above the root index | 
| 283 |     if (currentColumn == d->columns.size()) | 
| 284 |         return; | 
| 285 |  | 
| 286 |     int indexColumn = currentColumn; | 
| 287 |     // Find the width of what we want to show (i.e. the right edge) | 
| 288 |     int visibleWidth = d->columns.at(i: currentColumn)->width(); | 
| 289 |     // We want to always try to show two columns | 
| 290 |     if (currentColumn + 1 < d->columns.size()) { | 
| 291 |         ++currentColumn; | 
| 292 |         visibleWidth += d->columns.at(i: currentColumn)->width(); | 
| 293 |     } | 
| 294 |  | 
| 295 |     int rightEdge = leftEdge + visibleWidth; | 
| 296 |     if (isRightToLeft()) { | 
| 297 |         leftEdge = viewport()->width() - leftEdge; | 
| 298 |         rightEdge = leftEdge - visibleWidth; | 
| 299 |         qSwap(value1&: rightEdge, value2&: leftEdge); | 
| 300 |     } | 
| 301 |  | 
| 302 |     // If it is already visible don't animate | 
| 303 |     if (leftEdge > -horizontalOffset() | 
| 304 |         && rightEdge <= ( -horizontalOffset() + viewport()->size().width())) { | 
| 305 |             d->columns.at(i: indexColumn)->scrollTo(index); | 
| 306 |             d->_q_changeCurrentColumn(); | 
| 307 |             return; | 
| 308 |     } | 
| 309 |  | 
| 310 |     int newScrollbarValue = 0; | 
| 311 |     if (isRightToLeft()) { | 
| 312 |         if (leftEdge < 0) { | 
| 313 |             // scroll to the right | 
| 314 |             newScrollbarValue = viewport()->size().width() - leftEdge; | 
| 315 |         } else { | 
| 316 |             // scroll to the left | 
| 317 |             newScrollbarValue = rightEdge + horizontalOffset(); | 
| 318 |         } | 
| 319 |     } else { | 
| 320 |         if (leftEdge > -horizontalOffset()) { | 
| 321 |             // scroll to the right | 
| 322 |             newScrollbarValue = rightEdge - viewport()->size().width(); | 
| 323 |         } else { | 
| 324 |             // scroll to the left | 
| 325 |             newScrollbarValue = leftEdge; | 
| 326 |         } | 
| 327 |     } | 
| 328 |  | 
| 329 | #if QT_CONFIG(animation) | 
| 330 |     if (const int animationDuration = style()->styleHint(stylehint: QStyle::SH_Widget_Animation_Duration, opt: nullptr, widget: this)) { | 
| 331 |         d->currentAnimation.setDuration(animationDuration); | 
| 332 |         d->currentAnimation.setEndValue(newScrollbarValue); | 
| 333 |         d->currentAnimation.start(); | 
| 334 |     } else | 
| 335 | #endif // animation | 
| 336 |     { | 
| 337 |         horizontalScrollBar()->setValue(newScrollbarValue); | 
| 338 |     } | 
| 339 | } | 
| 340 |  | 
| 341 | /*! | 
| 342 |     \reimp | 
| 343 |     Move left should go to the parent index | 
| 344 |     Move right should go to the child index or down if there is no child | 
| 345 | */ | 
| 346 | QModelIndex QColumnView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) | 
| 347 | { | 
| 348 |     // the child views which have focus get to deal with this first and if | 
| 349 |     // they don't accept it then it comes up this view and we only grip left/right | 
| 350 |     Q_UNUSED(modifiers); | 
| 351 |     if (!model()) | 
| 352 |         return QModelIndex(); | 
| 353 |  | 
| 354 |     QModelIndex current = currentIndex(); | 
| 355 |     if (isRightToLeft()) { | 
| 356 |         if (cursorAction == MoveLeft) | 
| 357 |             cursorAction = MoveRight; | 
| 358 |         else if (cursorAction == MoveRight) | 
| 359 |             cursorAction = MoveLeft; | 
| 360 |     } | 
| 361 |     switch (cursorAction) { | 
| 362 |     case MoveLeft: | 
| 363 |         if (current.parent().isValid() && current.parent() != rootIndex()) | 
| 364 |             return (current.parent()); | 
| 365 |         else | 
| 366 |             return current; | 
| 367 |  | 
| 368 |     case MoveRight: | 
| 369 |         if (model()->hasChildren(parent: current)) | 
| 370 |             return model()->index(row: 0, column: 0, parent: current); | 
| 371 |         else | 
| 372 |             return current.sibling(arow: current.row() + 1, acolumn: current.column()); | 
| 373 |  | 
| 374 |     default: | 
| 375 |         break; | 
| 376 |     } | 
| 377 |  | 
| 378 |     return QModelIndex(); | 
| 379 | } | 
| 380 |  | 
| 381 | /*! | 
| 382 |     \reimp | 
| 383 | */ | 
| 384 | void QColumnView::resizeEvent(QResizeEvent *event) | 
| 385 | { | 
| 386 |     Q_D(QColumnView); | 
| 387 |     d->doLayout(); | 
| 388 |     d->updateScrollbars(); | 
| 389 |     if (!isRightToLeft()) { | 
| 390 |         int diff = event->oldSize().width() - event->size().width(); | 
| 391 |         if (diff < 0 && horizontalScrollBar()->isVisible() | 
| 392 |             && horizontalScrollBar()->value() == horizontalScrollBar()->maximum()) { | 
| 393 |             horizontalScrollBar()->setMaximum(horizontalScrollBar()->maximum() + diff); | 
| 394 |         } | 
| 395 |     } | 
| 396 |     QAbstractItemView::resizeEvent(event); | 
| 397 | } | 
| 398 |  | 
| 399 | /*! | 
| 400 |     \internal | 
| 401 | */ | 
| 402 | void QColumnViewPrivate::updateScrollbars() | 
| 403 | { | 
| 404 |     Q_Q(QColumnView); | 
| 405 | #if QT_CONFIG(animation) | 
| 406 |     if (currentAnimation.state() == QPropertyAnimation::Running) | 
| 407 |         return; | 
| 408 | #endif // animation | 
| 409 |  | 
| 410 |     // find the total horizontal length of the laid out columns | 
| 411 |     int horizontalLength = 0; | 
| 412 |     if (!columns.isEmpty()) { | 
| 413 |         horizontalLength = (columns.constLast()->x() + columns.constLast()->width()) - columns.constFirst()->x(); | 
| 414 |         if (horizontalLength <= 0) // reverse mode | 
| 415 |             horizontalLength = (columns.constFirst()->x() + columns.constFirst()->width()) - columns.constLast()->x(); | 
| 416 |     } | 
| 417 |  | 
| 418 |     QSize viewportSize = viewport->size(); | 
| 419 |     if (horizontalLength < viewportSize.width() && hbar->value() == 0) { | 
| 420 |         hbar->setRange(min: 0, max: 0); | 
| 421 |     } else { | 
| 422 |         int visibleLength = qMin(a: horizontalLength + q->horizontalOffset(), b: viewportSize.width()); | 
| 423 |         int hiddenLength = horizontalLength - visibleLength; | 
| 424 |         if (hiddenLength != hbar->maximum()) | 
| 425 |             hbar->setRange(min: 0, max: hiddenLength); | 
| 426 |     } | 
| 427 |     if (!columns.isEmpty()) { | 
| 428 |         int pageStepSize = columns.at(i: 0)->width(); | 
| 429 |         if (pageStepSize != hbar->pageStep()) | 
| 430 |             hbar->setPageStep(pageStepSize); | 
| 431 |     } | 
| 432 |     bool visible = (hbar->maximum() > 0); | 
| 433 |     if (visible != hbar->isVisible()) | 
| 434 |         hbar->setVisible(visible); | 
| 435 | } | 
| 436 |  | 
| 437 | /*! | 
| 438 |     \reimp | 
| 439 | */ | 
| 440 | int QColumnView::horizontalOffset() const | 
| 441 | { | 
| 442 |     Q_D(const QColumnView); | 
| 443 |     return d->offset; | 
| 444 | } | 
| 445 |  | 
| 446 | /*! | 
| 447 |     \reimp | 
| 448 | */ | 
| 449 | int QColumnView::verticalOffset() const | 
| 450 | { | 
| 451 |     return 0; | 
| 452 | } | 
| 453 |  | 
| 454 | /*! | 
| 455 |     \reimp | 
| 456 | */ | 
| 457 | QRegion QColumnView::visualRegionForSelection(const QItemSelection &selection) const | 
| 458 | { | 
| 459 |     int ranges = selection.count(); | 
| 460 |  | 
| 461 |     if (ranges == 0) | 
| 462 |         return QRect(); | 
| 463 |  | 
| 464 |     // Note that we use the top and bottom functions of the selection range | 
| 465 |     // since the data is stored in rows. | 
| 466 |     int firstRow = selection.at(i: 0).top(); | 
| 467 |     int lastRow = selection.at(i: 0).top(); | 
| 468 |     for (int i = 0; i < ranges; ++i) { | 
| 469 |         firstRow = qMin(a: firstRow, b: selection.at(i).top()); | 
| 470 |         lastRow = qMax(a: lastRow, b: selection.at(i).bottom()); | 
| 471 |     } | 
| 472 |  | 
| 473 |     QModelIndex firstIdx = model()->index(row: qMin(a: firstRow, b: lastRow), column: 0, parent: rootIndex()); | 
| 474 |     QModelIndex lastIdx = model()->index(row: qMax(a: firstRow, b: lastRow), column: 0, parent: rootIndex()); | 
| 475 |  | 
| 476 |     if (firstIdx == lastIdx) | 
| 477 |         return visualRect(index: firstIdx); | 
| 478 |  | 
| 479 |     QRegion firstRegion = visualRect(index: firstIdx); | 
| 480 |     QRegion lastRegion = visualRect(index: lastIdx); | 
| 481 |     return firstRegion.united(r: lastRegion); | 
| 482 | } | 
| 483 |  | 
| 484 | /*! | 
| 485 |     \reimp | 
| 486 | */ | 
| 487 | void QColumnView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) | 
| 488 | { | 
| 489 |     Q_UNUSED(rect); | 
| 490 |     Q_UNUSED(command); | 
| 491 | } | 
| 492 |  | 
| 493 | /*! | 
| 494 |     \reimp | 
| 495 | */ | 
| 496 | void QColumnView::setSelectionModel(QItemSelectionModel *newSelectionModel) | 
| 497 | { | 
| 498 |     Q_D(const QColumnView); | 
| 499 |     for (int i = 0; i < d->columns.size(); ++i) { | 
| 500 |         if (d->columns.at(i)->selectionModel() == selectionModel()) { | 
| 501 |             d->columns.at(i)->setSelectionModel(newSelectionModel); | 
| 502 |             break; | 
| 503 |         } | 
| 504 |     } | 
| 505 |     QAbstractItemView::setSelectionModel(newSelectionModel); | 
| 506 | } | 
| 507 |  | 
| 508 | /*! | 
| 509 |     \reimp | 
| 510 | */ | 
| 511 | QSize QColumnView::sizeHint() const | 
| 512 | { | 
| 513 |     Q_D(const QColumnView); | 
| 514 |     QSize sizeHint; | 
| 515 |     for (int i = 0; i < d->columns.size(); ++i) { | 
| 516 |         sizeHint += d->columns.at(i)->sizeHint(); | 
| 517 |     } | 
| 518 |     return sizeHint.expandedTo(otherSize: QAbstractItemView::sizeHint()); | 
| 519 | } | 
| 520 |  | 
| 521 | /*! | 
| 522 |     \internal | 
| 523 |     Move all widgets from the corner grip and to the right | 
| 524 |   */ | 
| 525 | void QColumnViewPrivate::_q_gripMoved(int offset) | 
| 526 | { | 
| 527 |     Q_Q(QColumnView); | 
| 528 |  | 
| 529 |     QObject *grip = q->sender(); | 
| 530 |     Q_ASSERT(grip); | 
| 531 |  | 
| 532 |     if (q->isRightToLeft()) | 
| 533 |         offset = -1 * offset; | 
| 534 |  | 
| 535 |     bool found = false; | 
| 536 |     for (int i = 0; i < columns.size(); ++i) { | 
| 537 |         if (!found && columns.at(i)->cornerWidget() == grip) { | 
| 538 |             found = true; | 
| 539 |             columnSizes[i] = columns.at(i)->width(); | 
| 540 |             if (q->isRightToLeft()) | 
| 541 |                 columns.at(i)->move(ax: columns.at(i)->x() + offset, ay: 0); | 
| 542 |             continue; | 
| 543 |         } | 
| 544 |         if (!found) | 
| 545 |             continue; | 
| 546 |  | 
| 547 |         int currentX = columns.at(i)->x(); | 
| 548 |         columns.at(i)->move(ax: currentX + offset, ay: 0); | 
| 549 |     } | 
| 550 |  | 
| 551 |     updateScrollbars(); | 
| 552 | } | 
| 553 |  | 
| 554 | /*! | 
| 555 |     \internal | 
| 556 |  | 
| 557 |     Find where the current columns intersect parent's columns | 
| 558 |  | 
| 559 |     Delete any extra columns and insert any needed columns. | 
| 560 |   */ | 
| 561 | void QColumnViewPrivate::closeColumns(const QModelIndex &parent, bool build) | 
| 562 | { | 
| 563 |     if (columns.isEmpty()) | 
| 564 |         return; | 
| 565 |  | 
| 566 |     bool clearAll = !parent.isValid(); | 
| 567 |     bool passThroughRoot = false; | 
| 568 |  | 
| 569 |     QVector<QModelIndex> dirsToAppend; | 
| 570 |  | 
| 571 |     // Find the last column that matches the parent's tree | 
| 572 |     int currentColumn = -1; | 
| 573 |     QModelIndex parentIndex = parent; | 
| 574 |     while (currentColumn == -1 && parentIndex.isValid()) { | 
| 575 |         if (columns.isEmpty()) | 
| 576 |             break; | 
| 577 |         parentIndex = parentIndex.parent(); | 
| 578 |         if (root == parentIndex) | 
| 579 |             passThroughRoot = true; | 
| 580 |         if (!parentIndex.isValid()) | 
| 581 |             break; | 
| 582 |         for (int i = columns.size() - 1; i >= 0; --i) { | 
| 583 |             if (columns.at(i)->rootIndex() == parentIndex) { | 
| 584 |                 currentColumn = i; | 
| 585 |                 break; | 
| 586 |             } | 
| 587 |         } | 
| 588 |         if (currentColumn == -1) | 
| 589 |             dirsToAppend.append(t: parentIndex); | 
| 590 |     } | 
| 591 |  | 
| 592 |     // Someone wants to go to an index that can be reached without changing | 
| 593 |     // the root index, don't allow them | 
| 594 |     if (!clearAll && !passThroughRoot && currentColumn == -1) | 
| 595 |         return; | 
| 596 |  | 
| 597 |     if (currentColumn == -1 && parent.isValid()) | 
| 598 |         currentColumn = 0; | 
| 599 |  | 
| 600 |     // Optimization so we don't go deleting and then creating the same thing | 
| 601 |     bool alreadyExists = false; | 
| 602 |     if (build && columns.size() > currentColumn + 1) { | 
| 603 |         bool viewingParent = (columns.at(i: currentColumn + 1)->rootIndex() == parent); | 
| 604 |         bool viewingChild = (!model->hasChildren(parent) | 
| 605 |                              && !columns.at(i: currentColumn + 1)->rootIndex().isValid()); | 
| 606 |         if (viewingParent || viewingChild) { | 
| 607 |             currentColumn++; | 
| 608 |             alreadyExists = true; | 
| 609 |         } | 
| 610 |     } | 
| 611 |  | 
| 612 |     // Delete columns that don't match our path | 
| 613 |     for (int i = columns.size() - 1; i > currentColumn; --i) { | 
| 614 |         QAbstractItemView* notShownAnymore = columns.at(i); | 
| 615 |         columns.removeAt(i); | 
| 616 |         notShownAnymore->setVisible(false); | 
| 617 |         if (notShownAnymore != previewColumn) | 
| 618 |             notShownAnymore->deleteLater(); | 
| 619 |     } | 
| 620 |  | 
| 621 |     if (columns.isEmpty()) { | 
| 622 |         offset = 0; | 
| 623 |         updateScrollbars(); | 
| 624 |     } | 
| 625 |  | 
| 626 |     // Now fill in missing columns | 
| 627 |     while (!dirsToAppend.isEmpty()) { | 
| 628 |         QAbstractItemView *newView = createColumn(index: dirsToAppend.takeLast(), show: true); | 
| 629 |         if (!dirsToAppend.isEmpty()) | 
| 630 |             newView->setCurrentIndex(dirsToAppend.constLast()); | 
| 631 |     } | 
| 632 |  | 
| 633 |     if (build && !alreadyExists) | 
| 634 |         createColumn(index: parent, show: false); | 
| 635 | } | 
| 636 |  | 
| 637 | void QColumnViewPrivate::_q_clicked(const QModelIndex &index) | 
| 638 | { | 
| 639 |     Q_Q(QColumnView); | 
| 640 |     QModelIndex parent = index.parent(); | 
| 641 |     QAbstractItemView *columnClicked = nullptr; | 
| 642 |     for (int column = 0; column < columns.count(); ++column) { | 
| 643 |         if (columns.at(i: column)->rootIndex() == parent) { | 
| 644 |             columnClicked = columns[column]; | 
| 645 |             break; | 
| 646 |         } | 
| 647 |     } | 
| 648 |     if (q->selectionModel() && columnClicked) { | 
| 649 |         QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Current; | 
| 650 |         if (columnClicked->selectionModel()->isSelected(index)) | 
| 651 |             flags |= QItemSelectionModel::Select; | 
| 652 |         q->selectionModel()->setCurrentIndex(index, command: flags); | 
| 653 |     } | 
| 654 | } | 
| 655 |  | 
| 656 | /*! | 
| 657 |     \internal | 
| 658 |     Create a new column for \a index.  A grip is attached if requested and it is shown | 
| 659 |     if requested. | 
| 660 |  | 
| 661 |     Return the new view | 
| 662 |  | 
| 663 |     \sa createColumn(), setPreviewWidget() | 
| 664 |     \sa doLayout() | 
| 665 | */ | 
| 666 | QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bool show) | 
| 667 | { | 
| 668 |     Q_Q(QColumnView); | 
| 669 |     QAbstractItemView *view = nullptr; | 
| 670 |     if (model->hasChildren(parent: index)) { | 
| 671 |         view = q->createColumn(rootIndex: index); | 
| 672 |         q->connect(sender: view, SIGNAL(clicked(QModelIndex)), | 
| 673 |                    receiver: q, SLOT(_q_clicked(QModelIndex))); | 
| 674 |     } else { | 
| 675 |         if (!previewColumn) | 
| 676 |             setPreviewWidget(new QWidget(q)); | 
| 677 |         view = previewColumn; | 
| 678 |         view->setMinimumWidth(qMax(a: view->minimumWidth(), b: previewWidget->minimumWidth())); | 
| 679 |     } | 
| 680 |  | 
| 681 |     q->connect(sender: view, SIGNAL(activated(QModelIndex)), | 
| 682 |             receiver: q, SIGNAL(activated(QModelIndex))); | 
| 683 |     q->connect(sender: view, SIGNAL(clicked(QModelIndex)), | 
| 684 |             receiver: q, SIGNAL(clicked(QModelIndex))); | 
| 685 |     q->connect(sender: view, SIGNAL(doubleClicked(QModelIndex)), | 
| 686 |             receiver: q, SIGNAL(doubleClicked(QModelIndex))); | 
| 687 |     q->connect(sender: view, SIGNAL(entered(QModelIndex)), | 
| 688 |             receiver: q, SIGNAL(entered(QModelIndex))); | 
| 689 |     q->connect(sender: view, SIGNAL(pressed(QModelIndex)), | 
| 690 |             receiver: q, SIGNAL(pressed(QModelIndex))); | 
| 691 |  | 
| 692 |     view->setFocusPolicy(Qt::NoFocus); | 
| 693 |     view->setParent(viewport); | 
| 694 |     Q_ASSERT(view); | 
| 695 |  | 
| 696 |     // Setup corner grip | 
| 697 |     if (showResizeGrips) { | 
| 698 |         QColumnViewGrip *grip = new QColumnViewGrip(view); | 
| 699 |         view->setCornerWidget(grip); | 
| 700 |         q->connect(sender: grip, SIGNAL(gripMoved(int)), receiver: q, SLOT(_q_gripMoved(int))); | 
| 701 |     } | 
| 702 |  | 
| 703 |     if (columnSizes.count() > columns.count()) { | 
| 704 |         view->setGeometry(ax: 0, ay: 0, aw: columnSizes.at(i: columns.count()), ah: viewport->height()); | 
| 705 |     } else { | 
| 706 |         int initialWidth = view->sizeHint().width(); | 
| 707 |         if (q->isRightToLeft()) | 
| 708 |             view->setGeometry(ax: viewport->width() - initialWidth, ay: 0, aw: initialWidth, ah: viewport->height()); | 
| 709 |         else | 
| 710 |             view->setGeometry(ax: 0, ay: 0, aw: initialWidth, ah: viewport->height()); | 
| 711 |         columnSizes.resize(size: qMax(a: columnSizes.count(), b: columns.count() + 1)); | 
| 712 |         columnSizes[columns.count()] = initialWidth; | 
| 713 |     } | 
| 714 |     if (!columns.isEmpty() && columns.constLast()->isHidden()) | 
| 715 |         columns.constLast()->setVisible(true); | 
| 716 |  | 
| 717 |     columns.append(t: view); | 
| 718 |     doLayout(); | 
| 719 |     updateScrollbars(); | 
| 720 |     if (show && view->isHidden()) | 
| 721 |         view->setVisible(true); | 
| 722 |     return view; | 
| 723 | } | 
| 724 |  | 
| 725 | /*! | 
| 726 |     \fn void QColumnView::updatePreviewWidget(const QModelIndex &index) | 
| 727 |  | 
| 728 |     This signal is emitted when the preview widget should be updated to | 
| 729 |     provide rich information about \a index | 
| 730 |  | 
| 731 |     \sa previewWidget() | 
| 732 |  */ | 
| 733 |  | 
| 734 | /*! | 
| 735 |     To use a custom widget for the final column when you select | 
| 736 |     an item overload this function and return a widget. | 
| 737 |     \a index is the root index that will be assigned to the view. | 
| 738 |  | 
| 739 |     Return the new view.  QColumnView will automatically take ownership of the widget. | 
| 740 |  | 
| 741 |     \sa setPreviewWidget() | 
| 742 |  */ | 
| 743 | QAbstractItemView *QColumnView::createColumn(const QModelIndex &index) | 
| 744 | { | 
| 745 |     QListView *view = new QListView(viewport()); | 
| 746 |  | 
| 747 |     initializeColumn(column: view); | 
| 748 |  | 
| 749 |     view->setRootIndex(index); | 
| 750 |     if (model()->canFetchMore(parent: index)) | 
| 751 |         model()->fetchMore(parent: index); | 
| 752 |  | 
| 753 |     return view; | 
| 754 | } | 
| 755 |  | 
| 756 | /*! | 
| 757 |     Copies the behavior and options of the column view and applies them to | 
| 758 |     the \a column such as the iconSize(), textElideMode() and | 
| 759 |     alternatingRowColors(). This can be useful when reimplementing | 
| 760 |     createColumn(). | 
| 761 |  | 
| 762 |     \since 4.4 | 
| 763 |     \sa createColumn() | 
| 764 |  */ | 
| 765 | void QColumnView::initializeColumn(QAbstractItemView *column) const | 
| 766 | { | 
| 767 |     Q_D(const QColumnView); | 
| 768 |  | 
| 769 |     column->setFrameShape(QFrame::NoFrame); | 
| 770 |     column->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | 
| 771 |     column->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); | 
| 772 |     column->setMinimumWidth(100); | 
| 773 |     column->setAttribute(Qt::WA_MacShowFocusRect, on: false); | 
| 774 |  | 
| 775 | #if QT_CONFIG(draganddrop) | 
| 776 |     column->setDragDropMode(dragDropMode()); | 
| 777 |     column->setDragDropOverwriteMode(dragDropOverwriteMode()); | 
| 778 |     column->setDropIndicatorShown(showDropIndicator()); | 
| 779 | #endif | 
| 780 |     column->setAlternatingRowColors(alternatingRowColors()); | 
| 781 |     column->setAutoScroll(hasAutoScroll()); | 
| 782 |     column->setEditTriggers(editTriggers()); | 
| 783 |     column->setHorizontalScrollMode(horizontalScrollMode()); | 
| 784 |     column->setIconSize(iconSize()); | 
| 785 |     column->setSelectionBehavior(selectionBehavior()); | 
| 786 |     column->setSelectionMode(selectionMode()); | 
| 787 |     column->setTabKeyNavigation(tabKeyNavigation()); | 
| 788 |     column->setTextElideMode(textElideMode()); | 
| 789 |     column->setVerticalScrollMode(verticalScrollMode()); | 
| 790 |  | 
| 791 |     column->setModel(model()); | 
| 792 |  | 
| 793 |     // Copy the custom delegate per row | 
| 794 |     for (auto i = d->rowDelegates.cbegin(), end = d->rowDelegates.cend(); i != end; ++i) | 
| 795 |         column->setItemDelegateForRow(row: i.key(), delegate: i.value()); | 
| 796 |  | 
| 797 |     // set the delegate to be the columnview delegate | 
| 798 |     QAbstractItemDelegate *delegate = column->itemDelegate(); | 
| 799 |     column->setItemDelegate(d->itemDelegate); | 
| 800 |     delete delegate; | 
| 801 | } | 
| 802 |  | 
| 803 | /*! | 
| 804 |     Returns the preview widget, or \nullptr if there is none. | 
| 805 |  | 
| 806 |     \sa setPreviewWidget(), updatePreviewWidget() | 
| 807 | */ | 
| 808 | QWidget *QColumnView::previewWidget() const | 
| 809 | { | 
| 810 |     Q_D(const QColumnView); | 
| 811 |     return d->previewWidget; | 
| 812 | } | 
| 813 |  | 
| 814 | /*! | 
| 815 |     Sets the preview \a widget. | 
| 816 |  | 
| 817 |     The \a widget becomes a child of the column view, and will be | 
| 818 |     destroyed when the column area is deleted or when a new widget is | 
| 819 |     set. | 
| 820 |  | 
| 821 |     \sa previewWidget(), updatePreviewWidget() | 
| 822 | */ | 
| 823 | void QColumnView::setPreviewWidget(QWidget *widget) | 
| 824 | { | 
| 825 |     Q_D(QColumnView); | 
| 826 |     d->setPreviewWidget(widget); | 
| 827 | } | 
| 828 |  | 
| 829 | /*! | 
| 830 |     \internal | 
| 831 | */ | 
| 832 | void QColumnViewPrivate::setPreviewWidget(QWidget *widget) | 
| 833 | { | 
| 834 |     Q_Q(QColumnView); | 
| 835 |     if (previewColumn) { | 
| 836 |         if (!columns.isEmpty() && columns.constLast() == previewColumn) | 
| 837 |             columns.removeLast(); | 
| 838 |         previewColumn->deleteLater(); | 
| 839 |     } | 
| 840 |     QColumnViewPreviewColumn *column = new QColumnViewPreviewColumn(q); | 
| 841 |     column->setPreviewWidget(widget); | 
| 842 |     previewColumn = column; | 
| 843 |     previewColumn->hide(); | 
| 844 |     previewColumn->setFrameShape(QFrame::NoFrame); | 
| 845 |     previewColumn->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); | 
| 846 |     previewColumn->setSelectionMode(QAbstractItemView::NoSelection); | 
| 847 |     previewColumn->setMinimumWidth(qMax(a: previewColumn->verticalScrollBar()->width(), | 
| 848 |                 b: previewColumn->minimumWidth())); | 
| 849 |     previewWidget = widget; | 
| 850 |     previewWidget->setParent(previewColumn->viewport()); | 
| 851 | } | 
| 852 |  | 
| 853 | /*! | 
| 854 |     Sets the column widths to the values given in the \a list.  Extra values in the list are | 
| 855 |     kept and used when the columns are created. | 
| 856 |  | 
| 857 |     If list contains too few values, only width of the rest of the columns will not be modified. | 
| 858 |  | 
| 859 |     \sa columnWidths(), createColumn() | 
| 860 | */ | 
| 861 | void QColumnView::setColumnWidths(const QList<int> &list) | 
| 862 | { | 
| 863 |     Q_D(QColumnView); | 
| 864 |     int i = 0; | 
| 865 |     const int listCount = list.count(); | 
| 866 |     const int count = qMin(a: listCount, b: d->columns.count()); | 
| 867 |     for (; i < count; ++i) { | 
| 868 |         d->columns.at(i)->resize(w: list.at(i), h: d->columns.at(i)->height()); | 
| 869 |         d->columnSizes[i] = list.at(i); | 
| 870 |     } | 
| 871 |  | 
| 872 |     d->columnSizes.reserve(size: listCount); | 
| 873 |     for (; i < listCount; ++i) | 
| 874 |         d->columnSizes.append(t: list.at(i)); | 
| 875 | } | 
| 876 |  | 
| 877 | /*! | 
| 878 |     Returns a list of the width of all the columns in this view. | 
| 879 |  | 
| 880 |     \sa setColumnWidths() | 
| 881 | */ | 
| 882 | QList<int> QColumnView::columnWidths() const | 
| 883 | { | 
| 884 |     Q_D(const QColumnView); | 
| 885 |     QList<int> list; | 
| 886 |     const int columnCount = d->columns.count(); | 
| 887 |     list.reserve(size: columnCount); | 
| 888 |     for (int i = 0; i < columnCount; ++i) | 
| 889 |         list.append(t: d->columnSizes.at(i)); | 
| 890 |     return list; | 
| 891 | } | 
| 892 |  | 
| 893 | /*! | 
| 894 |     \reimp | 
| 895 | */ | 
| 896 | void QColumnView::rowsInserted(const QModelIndex &parent, int start, int end) | 
| 897 | { | 
| 898 |     QAbstractItemView::rowsInserted(parent, start, end); | 
| 899 |     d_func()->checkColumnCreation(parent); | 
| 900 | } | 
| 901 |  | 
| 902 | /*! | 
| 903 |     \reimp | 
| 904 | */ | 
| 905 | void QColumnView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) | 
| 906 | { | 
| 907 |     Q_D(QColumnView); | 
| 908 |     if (!current.isValid()) { | 
| 909 |         QAbstractItemView::currentChanged(current, previous); | 
| 910 |         return; | 
| 911 |     } | 
| 912 |  | 
| 913 |     QModelIndex currentParent = current.parent(); | 
| 914 |     // optimize for just moving up/down in a list where the child view doesn't change | 
| 915 |     if (currentParent == previous.parent() | 
| 916 |             && model()->hasChildren(parent: current) && model()->hasChildren(parent: previous)) { | 
| 917 |         for (int i = 0; i < d->columns.size(); ++i) { | 
| 918 |             if (currentParent == d->columns.at(i)->rootIndex()) { | 
| 919 |                 if (d->columns.size() > i + 1) { | 
| 920 |                     QAbstractItemView::currentChanged(current, previous); | 
| 921 |                     return; | 
| 922 |                 } | 
| 923 |                 break; | 
| 924 |             } | 
| 925 |         } | 
| 926 |     } | 
| 927 |  | 
| 928 |     // Scrolling to the right we need to have an empty spot | 
| 929 |     bool found = false; | 
| 930 |     if (currentParent == previous) { | 
| 931 |         for (int i = 0; i < d->columns.size(); ++i) { | 
| 932 |             if (currentParent == d->columns.at(i)->rootIndex()) { | 
| 933 |                 found = true; | 
| 934 |                 if (d->columns.size() < i + 2) { | 
| 935 |                     d->createColumn(index: current, show: false); | 
| 936 |                 } | 
| 937 |                 break; | 
| 938 |             } | 
| 939 |         } | 
| 940 |     } | 
| 941 |     if (!found) | 
| 942 |         d->closeColumns(parent: current, build: true); | 
| 943 |  | 
| 944 |     if (!model()->hasChildren(parent: current)) | 
| 945 |         emit updatePreviewWidget(index: current); | 
| 946 |  | 
| 947 |     QAbstractItemView::currentChanged(current, previous); | 
| 948 | } | 
| 949 |  | 
| 950 | /* | 
| 951 |     We have change the current column and need to update focus and selection models | 
| 952 |     on the new current column. | 
| 953 | */ | 
| 954 | void QColumnViewPrivate::_q_changeCurrentColumn() | 
| 955 | { | 
| 956 |     Q_Q(QColumnView); | 
| 957 |     if (columns.isEmpty()) | 
| 958 |         return; | 
| 959 |  | 
| 960 |     QModelIndex current = q->currentIndex(); | 
| 961 |     if (!current.isValid()) | 
| 962 |         return; | 
| 963 |  | 
| 964 |     // We might have scrolled far to the left so we need to close all of the children | 
| 965 |     closeColumns(parent: current, build: true); | 
| 966 |  | 
| 967 |     // Set up the "current" column with focus | 
| 968 |     int currentColumn = qMax(a: 0, b: columns.size() - 2); | 
| 969 |     QAbstractItemView *parentColumn = columns.at(i: currentColumn); | 
| 970 |     if (q->hasFocus()) | 
| 971 |         parentColumn->setFocus(Qt::OtherFocusReason); | 
| 972 |     q->setFocusProxy(parentColumn); | 
| 973 |  | 
| 974 |     // find the column that is our current selection model and give it a new one. | 
| 975 |     for (int i = 0; i < columns.size(); ++i) { | 
| 976 |         if (columns.at(i)->selectionModel() == q->selectionModel()) { | 
| 977 |             QItemSelectionModel *replacementSelectionModel = | 
| 978 |                 new QItemSelectionModel(parentColumn->model()); | 
| 979 |             replacementSelectionModel->setCurrentIndex( | 
| 980 |                 index: q->selectionModel()->currentIndex(), command: QItemSelectionModel::Current); | 
| 981 |             replacementSelectionModel->select( | 
| 982 |                 selection: q->selectionModel()->selection(), command: QItemSelectionModel::Select); | 
| 983 |             QAbstractItemView *view = columns.at(i); | 
| 984 |             view->setSelectionModel(replacementSelectionModel); | 
| 985 |             view->setFocusPolicy(Qt::NoFocus); | 
| 986 |             if (columns.size() > i + 1) { | 
| 987 |                 const QModelIndex newRootIndex = columns.at(i: i + 1)->rootIndex(); | 
| 988 |                 if (newRootIndex.isValid()) | 
| 989 |                     view->setCurrentIndex(newRootIndex); | 
| 990 |             } | 
| 991 |             break; | 
| 992 |         } | 
| 993 |     } | 
| 994 |     parentColumn->selectionModel()->deleteLater(); | 
| 995 |     parentColumn->setFocusPolicy(Qt::StrongFocus); | 
| 996 |     parentColumn->setSelectionModel(q->selectionModel()); | 
| 997 |     // We want the parent selection to stay highlighted (but dimmed depending upon the color theme) | 
| 998 |     if (currentColumn > 0) { | 
| 999 |         parentColumn = columns.at(i: currentColumn - 1); | 
| 1000 |         if (parentColumn->currentIndex() != current.parent()) | 
| 1001 |             parentColumn->setCurrentIndex(current.parent()); | 
| 1002 |     } | 
| 1003 |  | 
| 1004 |     if (columns.constLast()->isHidden()) { | 
| 1005 |         columns.constLast()->setVisible(true); | 
| 1006 |     } | 
| 1007 |     if (columns.constLast()->selectionModel()) | 
| 1008 |         columns.constLast()->selectionModel()->clear(); | 
| 1009 |     updateScrollbars(); | 
| 1010 | } | 
| 1011 |  | 
| 1012 | /*! | 
| 1013 |     \reimp | 
| 1014 | */ | 
| 1015 | void QColumnView::selectAll() | 
| 1016 | { | 
| 1017 |     if (!model() || !selectionModel()) | 
| 1018 |         return; | 
| 1019 |  | 
| 1020 |     QModelIndexList indexList = selectionModel()->selectedIndexes(); | 
| 1021 |     QModelIndex parent = rootIndex(); | 
| 1022 |     QItemSelection selection; | 
| 1023 |     if (indexList.count() >= 1) | 
| 1024 |         parent = indexList.at(i: 0).parent(); | 
| 1025 |     if (indexList.count() == 1) { | 
| 1026 |         parent = indexList.at(i: 0); | 
| 1027 |         if (!model()->hasChildren(parent)) | 
| 1028 |             parent = parent.parent(); | 
| 1029 |         else | 
| 1030 |             selection.append(t: QItemSelectionRange(parent, parent)); | 
| 1031 |     } | 
| 1032 |  | 
| 1033 |     QModelIndex tl = model()->index(row: 0, column: 0, parent); | 
| 1034 |     QModelIndex br = model()->index(row: model()->rowCount(parent) - 1, | 
| 1035 |                                     column: model()->columnCount(parent) - 1, | 
| 1036 |                                     parent); | 
| 1037 |     selection.append(t: QItemSelectionRange(tl, br)); | 
| 1038 |     selectionModel()->select(selection, command: QItemSelectionModel::ClearAndSelect); | 
| 1039 | } | 
| 1040 |  | 
| 1041 | /* | 
| 1042 |  * private object implementation | 
| 1043 |  */ | 
| 1044 | QColumnViewPrivate::QColumnViewPrivate() | 
| 1045 | :  QAbstractItemViewPrivate() | 
| 1046 | ,showResizeGrips(true) | 
| 1047 | ,offset(0) | 
| 1048 | ,previewWidget(nullptr) | 
| 1049 | ,previewColumn(nullptr) | 
| 1050 | { | 
| 1051 | } | 
| 1052 |  | 
| 1053 | QColumnViewPrivate::~QColumnViewPrivate() | 
| 1054 | { | 
| 1055 | } | 
| 1056 |  | 
| 1057 | /*! | 
| 1058 |     \internal | 
| 1059 |  | 
| 1060 |   */ | 
| 1061 | void QColumnViewPrivate::_q_columnsInserted(const QModelIndex &parent, int start, int end) | 
| 1062 | { | 
| 1063 |     QAbstractItemViewPrivate::_q_columnsInserted(parent, start, end); | 
| 1064 |     checkColumnCreation(parent); | 
| 1065 | } | 
| 1066 |  | 
| 1067 | /*! | 
| 1068 |     \internal | 
| 1069 |  | 
| 1070 |     Makes sure we create a corresponding column as a result of changing the model. | 
| 1071 |  | 
| 1072 |   */ | 
| 1073 | void QColumnViewPrivate::checkColumnCreation(const QModelIndex &parent) | 
| 1074 | { | 
| 1075 |     if (parent == q_func()->currentIndex() && model->hasChildren(parent)) { | 
| 1076 |         //the parent has children and is the current | 
| 1077 |         //let's try to find out if there is already a mapping that is good | 
| 1078 |         for (int i = 0; i < columns.count(); ++i) { | 
| 1079 |             QAbstractItemView *view = columns.at(i); | 
| 1080 |             if (view->rootIndex() == parent) { | 
| 1081 |                 if (view == previewColumn) { | 
| 1082 |                     //let's recreate the parent | 
| 1083 |                     closeColumns(parent, build: false); | 
| 1084 |                     createColumn(index: parent, show: true /*show*/); | 
| 1085 |                 } | 
| 1086 |                 break; | 
| 1087 |             } | 
| 1088 |         } | 
| 1089 |     } | 
| 1090 | } | 
| 1091 |  | 
| 1092 | /*! | 
| 1093 |     \internal | 
| 1094 |     Place all of the columns where they belong inside of the viewport, resize as necessary. | 
| 1095 | */ | 
| 1096 | void QColumnViewPrivate::doLayout() | 
| 1097 | { | 
| 1098 |     Q_Q(QColumnView); | 
| 1099 |     if (!model || columns.isEmpty()) | 
| 1100 |         return; | 
| 1101 |  | 
| 1102 |     int viewportHeight = viewport->height(); | 
| 1103 |     int x = columns.at(i: 0)->x(); | 
| 1104 |  | 
| 1105 |     if (q->isRightToLeft()) { | 
| 1106 |         x = viewport->width() + q->horizontalOffset(); | 
| 1107 |         for (int i = 0; i < columns.size(); ++i) { | 
| 1108 |             QAbstractItemView *view = columns.at(i); | 
| 1109 |             x -= view->width(); | 
| 1110 |             if (x != view->x() || viewportHeight != view->height()) | 
| 1111 |                 view->setGeometry(ax: x, ay: 0, aw: view->width(), ah: viewportHeight); | 
| 1112 |         } | 
| 1113 |     } else { | 
| 1114 |         for (int i = 0; i < columns.size(); ++i) { | 
| 1115 |             QAbstractItemView *view = columns.at(i); | 
| 1116 |             int currentColumnWidth = view->width(); | 
| 1117 |             if (x != view->x() || viewportHeight != view->height()) | 
| 1118 |                 view->setGeometry(ax: x, ay: 0, aw: currentColumnWidth, ah: viewportHeight); | 
| 1119 |             x += currentColumnWidth; | 
| 1120 |         } | 
| 1121 |     } | 
| 1122 | } | 
| 1123 |  | 
| 1124 | /*! | 
| 1125 |     \internal | 
| 1126 |  | 
| 1127 |     Draws a delegate with a > if an object has children. | 
| 1128 |  | 
| 1129 |     \sa {Model/View Programming}, QItemDelegate | 
| 1130 | */ | 
| 1131 | void QColumnViewDelegate::paint(QPainter *painter, | 
| 1132 |                           const QStyleOptionViewItem &option, | 
| 1133 |                           const QModelIndex &index) const | 
| 1134 | { | 
| 1135 |     drawBackground(painter, option, index ); | 
| 1136 |  | 
| 1137 |     bool reverse = (option.direction == Qt::RightToLeft); | 
| 1138 |     int width = ((option.rect.height() * 2) / 3); | 
| 1139 |     // Modify the options to give us room to add an arrow | 
| 1140 |     QStyleOptionViewItem opt = option; | 
| 1141 |     if (reverse) | 
| 1142 |         opt.rect.adjust(dx1: width,dy1: 0,dx2: 0,dy2: 0); | 
| 1143 |     else | 
| 1144 |         opt.rect.adjust(dx1: 0,dy1: 0,dx2: -width,dy2: 0); | 
| 1145 |  | 
| 1146 |     if (!(index.model()->flags(index) & Qt::ItemIsEnabled)) { | 
| 1147 |         opt.showDecorationSelected = true; | 
| 1148 |         opt.state |= QStyle::State_Selected; | 
| 1149 |     } | 
| 1150 |  | 
| 1151 |     QItemDelegate::paint(painter, option: opt, index); | 
| 1152 |  | 
| 1153 |     if (reverse) | 
| 1154 |         opt.rect = QRect(option.rect.x(), option.rect.y(), width, option.rect.height()); | 
| 1155 |     else | 
| 1156 |         opt.rect = QRect(option.rect.x() + option.rect.width() - width, option.rect.y(), | 
| 1157 |                          width, option.rect.height()); | 
| 1158 |  | 
| 1159 |     // Draw > | 
| 1160 |     if (index.model()->hasChildren(parent: index)) { | 
| 1161 |         const QWidget *view = opt.widget; | 
| 1162 |         QStyle *style = view ? view->style() : QApplication::style(); | 
| 1163 |         style->drawPrimitive(pe: QStyle::PE_IndicatorColumnViewArrow, opt: &opt, p: painter, w: view); | 
| 1164 |     } | 
| 1165 | } | 
| 1166 |  | 
| 1167 | QT_END_NAMESPACE | 
| 1168 |  | 
| 1169 | #include "moc_qcolumnview.cpp" | 
| 1170 |  | 
| 1171 | #endif // QT_CONFIG(columnview) | 
| 1172 |  |