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

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