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