15#include <kconfiggroup.h>
18#include <ksharedconfig.h>
22#include <QContextMenuEvent>
28#include <QPersistentModelIndex>
29#include <QApplication>
36#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
37#define QT6_SHIFT_SELECTION_WORKAROUND
41#define DRAG_WHILE_DRAG_WORKAROUND
44#ifdef DRAG_WHILE_DRAG_WORKAROUND
45#define DRAG_WHILE_DRAG_WORKAROUND_START() d->isDragging = true
46#define DRAG_WHILE_DRAG_WORKAROUND_STOP() d->isDragging = false
48#define DRAG_WHILE_DRAG_WORKAROUND_START()
49#define DRAG_WHILE_DRAG_WORKAROUND_STOP()
58#ifdef DRAG_WHILE_DRAG_WORKAROUND
62 , shiftClickFix(false)
70#ifdef DRAG_WHILE_DRAG_WORKAROUND
73#ifdef QT6_SHIFT_SELECTION_WORKAROUND
76 bool ignoreDataChanged =
false;
82 , m_draggingFlag(false)
85 setItemDelegate(&
d->delegate);
87 setMouseTracking(
true);
88 setSelectionBehavior(SelectRows);
89 setDefaultDropAction(Qt::MoveAction);
90 setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
91 setSelectionMode(QAbstractItemView::ExtendedSelection);
92 setRootIsDecorated(
false);
96 setDragDropMode(QAbstractItemView::DragDrop);
98 setDropIndicatorShown(
true);
103 connect(scroller, SIGNAL(stateChanged(QScroller::State)),
116 QTreeView::setModel(model);
118 if (!this->model()->inherits(
"KisNodeModel") && !this->model()->inherits(
"KisNodeFilterProxyModel")) {
119 qWarning() <<
"NodeView may not work with" << model->metaObject()->className();
121 if (this->model()->columnCount() != 3) {
122 qWarning() <<
"NodeView: expected 2 model columns, got " << this->model()->columnCount();
142 for (
int i = 0, n = list.count(); i < n; ++i) {
143 if (list.at(i).isMutable) {
145 connect(a, SIGNAL(toggled(
bool,QPersistentModelIndex,
int)),
158 d->delegate.toggleSolo(index);
164 if (!event && QApplication::keyboardModifiers() != Qt::NoModifier
169#ifdef QT6_SHIFT_SELECTION_WORKAROUND
170 d->shiftClickFix =
false;
172 return QItemSelectionModel::ClearAndSelect;
175#ifdef QT6_SHIFT_SELECTION_WORKAROUND
177 d->shiftClickFix =
false;
182 (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::KeyPress) &&
183 QApplication::keyboardModifiers() & Qt::ShiftModifier)
184 d->shiftClickFix =
true;
189 event->type() == QEvent::MouseButtonPress && (
static_cast<const QMouseEvent*
>(event)->modifiers() & Qt::ControlModifier))
190 return QItemSelectionModel::NoUpdate;
192 return QTreeView::selectionCommand(index, event);
199 QModelIndex index = QTreeView::indexAt(point);
200 if (!index.isValid()) {
203 index = QTreeView::indexAt(point - QPoint(point.x(), 0) + QPoint(width() / 2, 0));
213 case QEvent::MouseButtonPress: {
216 const QPoint pos =
static_cast<QMouseEvent*
>(e)->pos();
220 return QTreeView::viewportEvent(e);
222 QModelIndex index = model()->buddy(
indexAt(pos));
223 if (
d->delegate.editorEvent(e, model(),
optionForIndex(index), index)) {
227 case QEvent::MouseButtonRelease: {
228 const QPoint pos =
static_cast<QMouseEvent*
>(e)->pos();
229 QModelIndex index = model()->buddy(
indexAt(pos));
231 return QTreeView::viewportEvent(e);
233 if (
d->delegate.editorEvent(e, model(),
optionForIndex(index), index)) {
236 if (active_ind.has_value()) {
242 case QEvent::Leave: {
243 QEvent e(QEvent::Leave);
245 d->hovered = QModelIndex();
247 case QEvent::MouseMove: {
248#ifdef DRAG_WHILE_DRAG_WORKAROUND
254 const QPoint pos =
static_cast<QMouseEvent*
>(e)->pos();
257 if (
d->hovered.isValid()) {
258 QEvent e(QEvent::Leave);
262 QEvent e(QEvent::Enter);
269 Qt::MouseButtons
buttons =
static_cast<QMouseEvent*
>(e)->
buttons();
270 if ((Qt::LeftButton | Qt::MiddleButton) &
buttons) {
271 if ((pos -
d->lastPos).manhattanLength() > qApp->startDragDistance()) {
272 return QTreeView::viewportEvent(e);
277 case QEvent::ToolTip: {
278 const QPoint pos =
static_cast<QHelpEvent*
>(e)->pos();
280 return QTreeView::viewportEvent(e);
282 QModelIndex index = model()->buddy(
indexAt(pos));
283 return d->delegate.editorEvent(e, model(),
optionForIndex(index), index);
285 case QEvent::Resize: {
286 scheduleDelayedItemsLayout();
293 return QTreeView::viewportEvent(e);
298 QTreeView::contextMenuEvent(e);
299 QModelIndex i =
indexAt(e->pos());
301 i = model()->buddy(i);
312 QTreeView::currentChanged(current, previous);
313 if (current != previous) {
314 Q_ASSERT(!current.isValid() || current.model() == model());
322 QTreeView::dataChanged(topLeft, bottomRight);
324 if (
d->ignoreDataChanged){
325 d->ignoreDataChanged =
false;
329 for (
int x = topLeft.row(); x <= bottomRight.row(); ++x) {
330 for (
int y = topLeft.column(); y <= bottomRight.column(); ++y) {
331 QModelIndex index = topLeft.sibling(x, y);
333 if (currentIndex() != index) {
334 setCurrentIndex(index);
345 QTreeView::selectionChanged(selected, deselected);
353 list[num].state = on;
359#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
360 QStyleOptionViewItem option = viewOptions();
362 QStyleOptionViewItem option;
363 initViewItemOption(&option);
365 option.rect = visualRect(index);
366 if (index == currentIndex())
367 option.state |= QStyle::State_HasFocus;
374 QTreeView::startDrag(supportedActions);
379 const QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
380 Q_ASSERT(!selectedIndexes.isEmpty());
382 const int itemCount = selectedIndexes.count();
392 else if (itemCount > 4) {
396 else if (itemCount < xCount) {
400 int yCount = itemCount / xCount;
401 if (itemCount % xCount != 0) {
405 if (yCount > xCount) {
410 QPixmap dragPixmap(xCount * size + xCount - 1, yCount * size + yCount - 1);
411 dragPixmap.fill(Qt::transparent);
413 QPainter painter(&dragPixmap);
416 Q_FOREACH (
const QModelIndex &selectedIndex, selectedIndexes) {
418 painter.drawPixmap(x, y, QPixmap::fromImage(img.scaled(QSize(size, size), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
421 if (x >= dragPixmap.width()) {
425 if (y >= dragPixmap.height()) {
436 header()->setStretchLastSection(
false);
441 if (
KisConfig(
false).useLayerSelectionCheckbox()) {
444 header()->resizeSection(
DEFAULT_COL, event->size().width() - otherColumnsWidth);
449 QTreeView::resizeEvent(event);
455 QTreeView::paintEvent(event);
459 const QModelIndex &index)
const
461#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
462 QStyleOptionViewItem option = viewOptions();
464 QStyleOptionViewItem option;
465 initViewItemOption(&option);
469 d->delegate.drawBranches(painter, option, index);
474 QTreeView::dropEvent(ev);
480 QSize size(visualRect(model()->index(0, 0, QModelIndex())).width(), visualRect(model()->index(0, 0, QModelIndex())).height());
481 int scrollBarValue = verticalScrollBar()->value();
483 QPoint cursorPosition = QWidget::mapFromGlobal(QCursor::pos());
485 int numberRow = (cursorPosition.y() + scrollBarValue) / size.height();
489 if (abs((cursorPosition.y() + scrollBarValue) - size.height()*numberRow) > (size.height()/2)) {
493 if (numberRow > model()->rowCount(QModelIndex())) {
494 numberRow = model()->rowCount(QModelIndex());
504 QVariant data = QVariant::fromValue(
505 static_cast<void*
>(
const_cast<QMimeData*
>(ev->mimeData())));
508 QTreeView::dragEnterEvent(ev);
514 QTreeView::dragMoveEvent(ev);
519 QTreeView::dragLeaveEvent(e);
524 if (!(e->modifiers() & Qt::ControlModifier)) {
525 QTreeView::mousePressEvent(e);
530 QTreeView::mousePressEvent(e);
532 if (ind.has_value()) {
549 d->delegate.slotUpdateIcon();
560 d->delegate.slotConfigChanged();
579 QAbstractItemModel* mdl = model();
581 int rows = mdl->rowCount();
582 int clmns = mdl->columnCount();
584 for (
int i = 0; i < rows; i++) {
585 for (
int j = 0; j < clmns; j++) {
586 auto index = mdl->index(i, j);
598 QAbstractItemModel* mdl = model();
600 int rows = mdl->rowCount();
601 int clmns = mdl->columnCount();
603 for (
int i = 0; i < rows; i++) {
604 for (
int j = 0; j < clmns; j++) {
605 QModelIndex ind = mdl->index(i, j);
608 d->ignoreDataChanged =
true;
613 d->ignoreDataChanged =
true;
#define QT6_SHIFT_SELECTION_WORKAROUND
#define DRAG_WHILE_DRAG_WORKAROUND_START()
#define DRAG_WHILE_DRAG_WORKAROUND_STOP()
bool useLayerSelectionCheckbox(bool defaultValue=false) const
@ PropertiesRole
A list of properties the part has.
@ ActiveRole
Whether the section is the active one.
int selectedButtonColumnWidth() const
int visibilityColumnWidth() const
static KisNodeViewColorScheme * instance()
QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index, const QEvent *event) const override
void setDraggingFlag(bool flag=true)
virtual void showContextMenu(const QPoint &globalPos, const QModelIndex &index)
void contextMenuRequested(const QPoint &globalPos, const QModelIndex &index)
void setExclusiveActiveItem(QModelIndex index)
void paintEvent(QPaintEvent *event) override
void mousePressEvent(QMouseEvent *e) override
void selectionChanged(const QModelIndexList &)
void dragMoveEvent(QDragMoveEvent *ev) override
void updateNode(const QModelIndex &index)
void resizeEvent(QResizeEvent *event) override
bool viewportEvent(QEvent *event) override
int cursorPageIndex() const
void drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const override
NodeView(QWidget *parent=0)
void slotScrollerStateChanged(QScroller::State state)
void toggleSolo(const QModelIndex &index)
void slotConfigurationChanged()
void slotUpdateIcons()
called with a theme change to refresh icon colors
void dropEvent(QDropEvent *ev) override
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector< int > &roles=QVector< int >()) override
QStyleOptionViewItem optionForIndex(const QModelIndex &index) const
void slotActionToggled(bool on, const QPersistentModelIndex &index, int property)
QPixmap createDragPixmap() const
QPersistentModelIndex hovered
void dragEnterEvent(QDragEnterEvent *e) override
void addPropertyActions(QMenu *menu, const QModelIndex &index)
std::optional< QModelIndex > getActiveItem()
void startDrag(Qt::DropActions supportedActions) override
void setModel(QAbstractItemModel *model) override
void dragLeaveEvent(QDragLeaveEvent *e) override
void updateSelectedCheckboxColumn()
void contextMenuEvent(QContextMenuEvent *event) override
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override
QModelIndex indexAt(const QPoint &point) const override
QString buttons(const T &ev)