1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "openpageswidget.h"
5
6#include "centralwidget.h"
7#include "openpagesmodel.h"
8#include "tracer.h"
9
10#include <QtWidgets/QApplication>
11#include <QtWidgets/QHeaderView>
12#include <QtGui/QKeyEvent>
13#include <QtGui/QMouseEvent>
14#include <QtWidgets/QMenu>
15#include <QtGui/QPainter>
16
17QT_BEGIN_NAMESPACE
18
19OpenPagesDelegate::OpenPagesDelegate(QObject *parent)
20 : QStyledItemDelegate(parent)
21{
22 TRACE_OBJ
23}
24
25void OpenPagesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
26 const QModelIndex &index) const
27{
28 TRACE_OBJ
29 if (option.state & QStyle::State_MouseOver) {
30QT_WARNING_PUSH
31QT_WARNING_DISABLE_DEPRECATED
32 if ((QApplication::mouseButtons() & Qt::LeftButton) == 0)
33 pressedIndex = QModelIndex();
34QT_WARNING_POP
35 QBrush brush = option.palette.alternateBase();
36 if (index == pressedIndex)
37 brush = option.palette.dark();
38 painter->fillRect(option.rect, brush);
39 }
40
41 QStyledItemDelegate::paint(painter, option, index);
42
43 if (index.column() == 1 && index.model()->rowCount() > 1
44 && option.state & QStyle::State_MouseOver) {
45 QIcon icon((option.state & QStyle::State_Selected)
46 ? ":/qt-project.org/assistant/images/closebutton.png"
47 : ":/qt-project.org/assistant/images/darkclosebutton.png");
48
49 const QRect iconRect(option.rect.right() - option.rect.height(),
50 option.rect.top(), option.rect.height(), option.rect.height());
51 icon.paint(painter, rect: iconRect, alignment: Qt::AlignRight | Qt::AlignVCenter);
52 }
53}
54
55// -- OpenPagesWidget
56
57OpenPagesWidget::OpenPagesWidget(OpenPagesModel *model)
58 : m_allowContextMenu(true)
59{
60 TRACE_OBJ
61 setModel(model);
62 setIndentation(0);
63 setItemDelegate((m_delegate = new OpenPagesDelegate(this)));
64
65 setTextElideMode(Qt::ElideMiddle);
66 setAttribute(Qt::WA_MacShowFocusRect, on: false);
67
68 viewport()->setAttribute(Qt::WA_Hover);
69 setSelectionBehavior(QAbstractItemView::SelectRows);
70 setSelectionMode(QAbstractItemView::SingleSelection);
71
72 header()->hide();
73 header()->setStretchLastSection(false);
74 header()->setSectionResizeMode(logicalIndex: 0, mode: QHeaderView::Stretch);
75 header()->setSectionResizeMode(logicalIndex: 1, mode: QHeaderView::Fixed);
76 header()->resizeSection(logicalIndex: 1, size: 18);
77
78 installEventFilter(filterObj: this);
79 setUniformRowHeights(true);
80 setContextMenuPolicy(Qt::CustomContextMenu);
81
82 connect(sender: this, signal: &QAbstractItemView::clicked,
83 context: this, slot: &OpenPagesWidget::handleClicked);
84 connect(sender: this, signal: &QAbstractItemView::pressed,
85 context: this, slot: &OpenPagesWidget::handlePressed);
86 connect(sender: this, signal: &QWidget::customContextMenuRequested,
87 context: this, slot: &OpenPagesWidget::contextMenuRequested);
88}
89
90OpenPagesWidget::~OpenPagesWidget()
91{
92 TRACE_OBJ
93}
94
95void OpenPagesWidget::selectCurrentPage()
96{
97 TRACE_OBJ
98 const QModelIndex &current =
99 model()->index(row: CentralWidget::instance()->currentIndex(), column: 0);
100
101 QItemSelectionModel * const selModel = selectionModel();
102 selModel->select(index: current,
103 command: QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
104 selModel->clearSelection();
105
106 setCurrentIndex(current);
107 scrollTo(index: currentIndex());
108}
109
110void OpenPagesWidget::allowContextMenu(bool ok)
111{
112 TRACE_OBJ
113 m_allowContextMenu = ok;
114}
115
116void OpenPagesWidget::contextMenuRequested(QPoint pos)
117{
118 TRACE_OBJ
119 QModelIndex index = indexAt(p: pos);
120 if (!index.isValid() || !m_allowContextMenu)
121 return;
122
123 if (index.column() == 1)
124 index = index.sibling(arow: index.row(), acolumn: 0);
125 QMenu contextMenu;
126 QAction *closeEditor = contextMenu.addAction(text: tr(s: "Close %1").arg(a: index.data()
127 .toString()));
128 QAction *closeOtherEditors = contextMenu.addAction(text: tr(s: "Close All Except %1")
129 .arg(a: index.data().toString()));
130
131 if (model()->rowCount() == 1) {
132 closeEditor->setEnabled(false);
133 closeOtherEditors->setEnabled(false);
134 }
135
136 QAction *action = contextMenu.exec(pos: mapToGlobal(pos));
137 if (action == closeEditor)
138 emit closePage(index);
139 else if (action == closeOtherEditors)
140 emit closePagesExcept(index);
141}
142
143void OpenPagesWidget::handlePressed(const QModelIndex &index)
144{
145 TRACE_OBJ
146 if (index.column() == 0)
147 emit setCurrentPage(index);
148
149 if (index.column() == 1)
150 m_delegate->pressedIndex = index;
151}
152
153void OpenPagesWidget::handleClicked(const QModelIndex &index)
154{
155 TRACE_OBJ
156 // implemented here to handle the funky close button and to work around a
157 // bug in item views where the delegate wouldn't get the QStyle::State_MouseOver
158 if (index.column() == 1) {
159 if (model()->rowCount() > 1)
160 emit closePage(index);
161
162 QWidget *vp = viewport();
163 const QPoint &cursorPos = QCursor::pos();
164 QMouseEvent e(QEvent::MouseMove, vp->mapFromGlobal(cursorPos), cursorPos,
165 Qt::NoButton, {}, {});
166 QCoreApplication::sendEvent(receiver: vp, event: &e);
167 }
168}
169
170bool OpenPagesWidget::eventFilter(QObject *obj, QEvent *event)
171{
172 TRACE_OBJ
173 if (obj != this)
174 return QWidget::eventFilter(watched: obj, event);
175
176 if (event->type() == QEvent::KeyPress) {
177 QKeyEvent *ke = static_cast<QKeyEvent*>(event);
178 if (currentIndex().isValid() && ke->modifiers() == 0) {
179 const int key = ke->key();
180 if (key == Qt::Key_Return || key == Qt::Key_Enter
181 || key == Qt::Key_Space) {
182 emit setCurrentPage(currentIndex());
183 } else if ((key == Qt::Key_Delete || key == Qt::Key_Backspace)
184 && model()->rowCount() > 1) {
185 emit closePage(index: currentIndex());
186 }
187 }
188 } else if (event->type() == QEvent::KeyRelease) {
189 QKeyEvent *ke = static_cast<QKeyEvent*>(event);
190 if (ke->modifiers() == 0
191 && (ke->key() == Qt::Key_Up || ke->key() == Qt::Key_Down)) {
192 emit setCurrentPage(currentIndex());
193 }
194 }
195 return QWidget::eventFilter(watched: obj, event);
196}
197
198QT_END_NAMESPACE
199

source code of qttools/src/assistant/assistant/openpageswidget.cpp