1 /*
2 This file is part of Contact Editor.
3
4 SPDX-FileCopyrightText: 2010 Tobias Koenig <tokoe@kde.org>
5 SPDX-FileCopyrightText: 2016-2021 Laurent Montel <montel@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
10 #include "customfieldslistdelegate.h"
11
12 #include "customfieldsmodel.h"
13
14 #include <KLocalizedString>
15 #include <KMessageBox>
16
17 #include <QAbstractItemView>
18 #include <QCheckBox>
19 #include <QDateEdit>
20 #include <QDateTimeEdit>
21 #include <QMouseEvent>
22 #include <QSpinBox>
23 #include <QTimeEdit>
24 #include <QTimer>
25
26 using namespace ContactEditor;
CustomFieldsListDelegate(QAbstractItemView * view,QObject * parent)27 CustomFieldsListDelegate::CustomFieldsListDelegate(QAbstractItemView *view, QObject *parent)
28 : QStyledItemDelegate(parent)
29 , mIcon(QIcon::fromTheme(QStringLiteral("list-remove")))
30 , mButtonSize(16, 16)
31 , mItemView(view)
32 {
33 }
34
~CustomFieldsListDelegate()35 CustomFieldsListDelegate::~CustomFieldsListDelegate()
36 {
37 }
38
createEditor(QWidget * parent,const QStyleOptionViewItem & item,const QModelIndex & index) const39 QWidget *CustomFieldsListDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &item, const QModelIndex &index) const
40 {
41 if (index.column() == 1) {
42 const CustomField::Type type = static_cast<CustomField::Type>(index.data(CustomFieldsModel::TypeRole).toInt());
43
44 switch (type) {
45 case CustomField::TextType:
46 case CustomField::UrlType:
47 default:
48 return QStyledItemDelegate::createEditor(parent, item, index);
49 case CustomField::NumericType: {
50 auto editor = new QSpinBox(parent);
51 editor->setFrame(false);
52 editor->setAutoFillBackground(true);
53 return editor;
54 }
55 case CustomField::BooleanType: {
56 auto editor = new QCheckBox(parent);
57 return editor;
58 }
59 case CustomField::DateType: {
60 auto editor = new QDateEdit(parent);
61 editor->setFrame(false);
62 editor->setAutoFillBackground(true);
63 return editor;
64 }
65 case CustomField::TimeType: {
66 auto editor = new QTimeEdit(parent);
67 editor->setFrame(false);
68 editor->setAutoFillBackground(true);
69 return editor;
70 }
71 case CustomField::DateTimeType: {
72 auto editor = new QDateTimeEdit(parent);
73 editor->setFrame(false);
74 editor->setAutoFillBackground(true);
75 return editor;
76 }
77 }
78 } else {
79 return QStyledItemDelegate::createEditor(parent, item, index);
80 }
81 }
82
setEditorData(QWidget * editor,const QModelIndex & index) const83 void CustomFieldsListDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
84 {
85 if (index.column() == 1) {
86 const CustomField::Type type = static_cast<CustomField::Type>(index.data(CustomFieldsModel::TypeRole).toInt());
87
88 switch (type) {
89 case CustomField::TextType:
90 case CustomField::UrlType:
91 QStyledItemDelegate::setEditorData(editor, index);
92 break;
93 case CustomField::NumericType: {
94 auto widget = qobject_cast<QSpinBox *>(editor);
95 widget->setValue(index.data(Qt::EditRole).toInt());
96 break;
97 }
98 case CustomField::BooleanType: {
99 auto widget = qobject_cast<QCheckBox *>(editor);
100 widget->setChecked(index.data(Qt::EditRole).toString() == QLatin1String("true"));
101 break;
102 }
103 case CustomField::DateType: {
104 auto widget = qobject_cast<QDateEdit *>(editor);
105 widget->setDisplayFormat(QStringLiteral("dd.MM.yyyy"));
106 widget->setDate(QDate::fromString(index.data(Qt::EditRole).toString(), Qt::ISODate));
107 break;
108 }
109 case CustomField::TimeType: {
110 auto widget = qobject_cast<QTimeEdit *>(editor);
111 widget->setDisplayFormat(QStringLiteral("hh:mm"));
112 widget->setTime(QTime::fromString(index.data(Qt::EditRole).toString(), Qt::ISODate));
113 break;
114 }
115 case CustomField::DateTimeType: {
116 auto widget = qobject_cast<QDateTimeEdit *>(editor);
117 widget->setDisplayFormat(QStringLiteral("dd.MM.yyyy hh:mm"));
118 widget->setDateTime(QDateTime::fromString(index.data(Qt::EditRole).toString(), Qt::ISODate));
119 break;
120 }
121 }
122 } else {
123 QStyledItemDelegate::setEditorData(editor, index);
124 }
125 }
126
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const127 void CustomFieldsListDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
128 {
129 if (index.column() == 1) {
130 const CustomField::Type type = static_cast<CustomField::Type>(index.data(CustomFieldsModel::TypeRole).toInt());
131
132 switch (type) {
133 case CustomField::TextType:
134 case CustomField::UrlType:
135 QStyledItemDelegate::setModelData(editor, model, index);
136 break;
137 case CustomField::NumericType: {
138 auto widget = qobject_cast<QSpinBox *>(editor);
139 model->setData(index, QString::number(widget->value()));
140 break;
141 }
142 case CustomField::BooleanType: {
143 auto widget = qobject_cast<QCheckBox *>(editor);
144 model->setData(index, widget->isChecked() ? QStringLiteral("true") : QStringLiteral("false"));
145 break;
146 }
147 case CustomField::DateType: {
148 auto widget = qobject_cast<QDateEdit *>(editor);
149 model->setData(index, widget->date().toString(Qt::ISODate));
150 break;
151 }
152 case CustomField::TimeType: {
153 auto widget = qobject_cast<QTimeEdit *>(editor);
154 model->setData(index, widget->time().toString(Qt::ISODate));
155 break;
156 }
157 case CustomField::DateTimeType: {
158 auto widget = qobject_cast<QDateTimeEdit *>(editor);
159 model->setData(index, widget->dateTime().toString(Qt::ISODate));
160 break;
161 }
162 }
163 } else {
164 QStyledItemDelegate::setModelData(editor, model, index);
165 }
166 }
167
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const168 void CustomFieldsListDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
169 {
170 // TODO: somehow mark local/global/external fields
171 QStyledItemDelegate::paint(painter, option, index);
172 if (index.column() == 1) {
173 mIcon.paint(painter, option.rect, Qt::AlignRight);
174 }
175 }
176
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const177 QSize CustomFieldsListDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
178 {
179 Q_UNUSED(option)
180
181 QSize hint = QStyledItemDelegate::sizeHint(option, index);
182 hint.setHeight(qMax(hint.height(), mButtonSize.height()));
183
184 if (index.column() == 1) {
185 hint.setWidth(hint.width() + mButtonSize.width());
186 }
187
188 return hint;
189 }
190
editorEvent(QEvent * event,QAbstractItemModel * model,const QStyleOptionViewItem & option,const QModelIndex & index)191 bool CustomFieldsListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
192 {
193 if (index.column() == 1) {
194 if (event->type() == QEvent::MouseButtonRelease) {
195 const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
196 QRect buttonRect = mItemView->visualRect(index);
197 buttonRect.setLeft(buttonRect.right() - mButtonSize.width());
198
199 if (buttonRect.contains(mouseEvent->pos())) {
200 removeField(index.row(), model);
201 return true;
202 }
203 }
204 }
205 return QStyledItemDelegate::editorEvent(event, model, option, index);
206 }
207
setFirstColumnAsCurrent()208 void CustomFieldsListDelegate::setFirstColumnAsCurrent()
209 {
210 mItemView->setCurrentIndex(mItemView->model()->index(mItemView->currentIndex().row(), 0));
211 }
212
removeField(int row,QAbstractItemModel * model)213 void CustomFieldsListDelegate::removeField(int row, QAbstractItemModel *model)
214 {
215 if (KMessageBox::warningContinueCancel(mItemView,
216 i18nc("Custom Fields", "Do you really want to delete the selected custom field?"),
217 i18n("Confirm Delete"),
218 KStandardGuiItem::del())
219 != KMessageBox::Continue) {
220 return;
221 }
222
223 model->removeRow(row);
224 QTimer::singleShot(0, this, &CustomFieldsListDelegate::setFirstColumnAsCurrent);
225 }
226