1 /***************************************************************************
2 * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3 * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 ***************************************************************************/
6 /** @file
7 * A table widget with more features.
8 *
9 * @author Stephane MANKOWSKI / Guillaume DE BURE
10 */
11 #include "skgtablewidget.h"
12
13 #include <qapplication.h>
14 #include <qclipboard.h>
15 #include <qevent.h>
16 #include <qscrollbar.h>
17
18 #include <algorithm>
19
20 #include "skgtraces.h"
21
SKGTableWidget(QWidget * iParent)22 SKGTableWidget::SKGTableWidget(QWidget* iParent)
23 : QTableWidget(iParent), stickH(false), stickV(false)
24 {
25 this->installEventFilter(this);
26 connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &SKGTableWidget::onActionTriggered);
27 connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &SKGTableWidget::onActionTriggered);
28 connect(horizontalScrollBar(), &QScrollBar::rangeChanged, this, &SKGTableWidget::onRangeChanged);
29 connect(verticalScrollBar(), &QScrollBar::rangeChanged, this, &SKGTableWidget::onRangeChanged);
30 }
31
32 SKGTableWidget::~SKGTableWidget()
33 = default;
34
onRangeChanged()35 void SKGTableWidget::onRangeChanged()
36 {
37 auto* scrollb = qobject_cast<QScrollBar*>(sender());
38 if ((stickH && scrollb == horizontalScrollBar()) || (stickV && scrollb == verticalScrollBar())) {
39 scrollb->setValue(scrollb->maximum());
40 }
41 }
42
onActionTriggered()43 void SKGTableWidget::onActionTriggered()
44 {
45 auto* scrollb = qobject_cast<QScrollBar*>(sender());
46 if (scrollb != nullptr) {
47 if (scrollb == horizontalScrollBar()) {
48 stickH = (scrollb->value() == scrollb->maximum());
49 }
50 if (scrollb == verticalScrollBar()) {
51 stickV = (scrollb->value() == scrollb->maximum());
52 }
53 }
54 }
55
setStickHorizontal(bool iStick)56 void SKGTableWidget::setStickHorizontal(bool iStick)
57 {
58 stickH = iStick;
59 }
60
stickHorizontal() const61 bool SKGTableWidget::stickHorizontal() const
62 {
63 return stickH;
64 }
65
setStickVertical(bool iStick)66 void SKGTableWidget::setStickVertical(bool iStick)
67 {
68 stickV = iStick;
69 }
stickVertical() const70 bool SKGTableWidget::stickVertical() const
71 {
72 return stickV;
73 }
74
eventFilter(QObject * iObject,QEvent * iEvent)75 bool SKGTableWidget::eventFilter(QObject* iObject, QEvent* iEvent)
76 {
77 if (iObject == this && iEvent != nullptr && iEvent->type() == QEvent::KeyPress) {
78 auto* kevent = dynamic_cast<QKeyEvent*>(iEvent);
79 if (kevent != nullptr) {
80 if (kevent->key() == Qt::Key_Delete && state() != QAbstractItemView::EditingState) {
81 QList<QTableWidgetItem*> listOfSelectedItems = this->selectedItems();
82 int nb = listOfSelectedItems.count();
83 if (nb > 0) {
84 // Build list of indexes
85 QList<int> listIndex;
86 listIndex.reserve(nb);
87 for (int i = 0; i < nb; ++i) {
88 QModelIndex mIndex = this->indexFromItem(listOfSelectedItems.at(i));
89 if (!listIndex.contains(mIndex.row())) {
90 listIndex.append(mIndex.row());
91 }
92 }
93
94 // Sort reverse
95 std::sort(listIndex.begin(), listIndex.end(), std::greater<int>());
96
97 // Emit events
98 nb = listIndex.count();
99 for (int i = 0; i < nb; ++i) {
100 Q_EMIT removeLine(listIndex.at(i));
101 }
102
103 if (iEvent != nullptr) {
104 iEvent->accept();
105 }
106 return true; // stop the process
107 }
108 } else if (kevent->matches(QKeySequence::Copy) && this->state() != QAbstractItemView::EditingState) {
109 copy();
110 if (iEvent != nullptr) {
111 iEvent->accept();
112 }
113 return true; // stop the process
114 }
115 }
116 }
117
118 return QTableWidget::eventFilter(iObject, iEvent);
119 }
120
copy()121 void SKGTableWidget::copy()
122 {
123 QItemSelectionModel* selection = selectionModel();
124 if (selection != nullptr) {
125 QModelIndexList indexes = selection->selectedIndexes();
126
127 if (indexes.empty()) {
128 return;
129 }
130
131 std::sort(indexes.begin(), indexes.end());
132
133 // You need a pair of indexes to find the row changes
134 QModelIndex previous = indexes.first();
135 indexes.removeFirst();
136 QString header_text;
137 bool header_done = false;
138 QString selected_text;
139 for (const auto& current : qAsConst(indexes)) {
140 selected_text.append(model()->data(previous).toString());
141 if (!header_done) {
142 header_text.append(model()->headerData(previous.column(), Qt::Horizontal).toString());
143 }
144 if (current.row() != previous.row()) {
145 selected_text.append(QLatin1Char('\n'));
146 header_done = true;
147 } else {
148 selected_text.append(QLatin1Char(';'));
149 if (!header_done) {
150 header_text.append(QLatin1Char(';'));
151 }
152 }
153 previous = current;
154 }
155
156 // add last element
157 selected_text.append(model()->data(previous).toString());
158 selected_text.append(QLatin1Char('\n'));
159 QApplication::clipboard()->setText(header_text + '\n' + selected_text);
160 }
161 }
162
163
164