Akonadi Contacts

displaynameeditwidget.cpp
1 /*
2  This file is part of Contact Editor.
3 
4  SPDX-FileCopyrightText: 2009 Tobias Koenig <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "displaynameeditwidget.h"
10 
11 #include <QAbstractItemView>
12 #include <QEvent>
13 #include <QHBoxLayout>
14 #include <QPainter>
15 #include <QStyledItemDelegate>
16 
17 #include <KComboBox>
18 #include <KLocalizedString>
19 
20 // Tries to guess the display type that is used for the passed contact
21 static DisplayNameEditWidget::DisplayType guessedDisplayType(const KContacts::Addressee &contact)
22 {
23  if (contact.formattedName() == (contact.givenName() + QLatin1Char(' ') + contact.familyName())) {
25  } else if (contact.formattedName() == contact.assembledName()) {
27  } else if (contact.formattedName() == (contact.familyName() + QLatin1String(", ") + contact.givenName())) {
29  } else if (contact.formattedName() == (contact.familyName() + QLatin1Char(' ') + contact.givenName())) {
31  } else if (contact.formattedName() == contact.organization()) {
33  } else {
35  }
36 }
37 
38 class DisplayNameDelegate : public QStyledItemDelegate
39 {
40  Q_OBJECT
41 public:
42  DisplayNameDelegate(QAbstractItemView *view, QObject *parent = nullptr)
44  {
45  mDescriptions.append(i18n("Short Name"));
46  mDescriptions.append(i18n("Full Name"));
47  mDescriptions.append(i18n("Reverse Name with Comma"));
48  mDescriptions.append(i18n("Reverse Name"));
49  mDescriptions.append(i18n("Organization"));
50  mDescriptions.append(i18nc("@item:inlistbox A custom name format", "Custom"));
51 
52  QFont font = view->font();
54  QFontMetrics metrics(font);
55  for (const QString &description : std::as_const(mDescriptions)) {
56  mMaxDescriptionWidth = qMax(mMaxDescriptionWidth, metrics.boundingRect(description).width());
57  }
58 
59  mMaxDescriptionWidth += 2;
60  }
61 
62  int maximumDescriptionWidth() const
63  {
64  return mMaxDescriptionWidth;
65  }
66 
67  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
68  {
69  QStyledItemDelegate::paint(painter, option, index);
70  const QRect rect(option.rect.width() - mMaxDescriptionWidth, option.rect.y(), mMaxDescriptionWidth, option.rect.height());
71  painter->save();
72  QFont font(painter->font());
74  painter->setFont(font);
75  if (option.state & QStyle::State_Selected) {
76  painter->setPen(option.palette.color(QPalette::Normal, QPalette::BrightText));
77  } else {
78  painter->setPen(option.palette.color(QPalette::Disabled, QPalette::Text));
79  }
80  painter->drawText(rect, Qt::AlignLeft, mDescriptions.at(index.row()));
81  painter->restore();
82  }
83 
84  QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
85  {
86  QSize size = QStyledItemDelegate::sizeHint(option, index);
87  size.setWidth(size.width() + mMaxDescriptionWidth);
88 
89  return size;
90  }
91 
92 private:
93  QStringList mDescriptions;
94  int mMaxDescriptionWidth = 0;
95 };
96 
97 DisplayNameEditWidget::DisplayNameEditWidget(QWidget *parent)
98  : QWidget(parent)
99  , mDisplayType(FullName)
100 {
101  auto layout = new QHBoxLayout(this);
102  layout->setContentsMargins({});
103 
104  mView = new KComboBox(this);
105  mView->addItems(QStringList() << QString() << QString() << QString() << QString() << QString() << QString());
106 
107  layout->addWidget(mView);
108  setFocusProxy(mView);
109  setFocusPolicy(Qt::StrongFocus);
110  connect(mView, &KComboBox::activated, this, &DisplayNameEditWidget::displayTypeChanged);
111 
112  auto delegate = new DisplayNameDelegate(mView->view(), this);
113  mView->view()->setItemDelegate(delegate);
114 
115  mAdditionalPopupWidth = delegate->maximumDescriptionWidth();
116 
117  mViewport = mView->view()->viewport();
118  mViewport->installEventFilter(this);
119 }
120 
121 DisplayNameEditWidget::~DisplayNameEditWidget() = default;
122 
123 void DisplayNameEditWidget::setReadOnly(bool readOnly)
124 {
125  mView->setEnabled(!readOnly);
126 }
127 
128 void DisplayNameEditWidget::setDisplayType(DisplayType type)
129 {
130  if ((int)type == -1) {
131  // guess the used display type
132  mDisplayType = guessedDisplayType(mContact);
133  } else {
134  mDisplayType = type;
135  }
136 
137  updateView();
138 }
139 
140 DisplayNameEditWidget::DisplayType DisplayNameEditWidget::displayType() const
141 {
142  return mDisplayType;
143 }
144 
145 void DisplayNameEditWidget::loadContact(const KContacts::Addressee &contact)
146 {
147  mContact = contact;
148 
149  mDisplayType = guessedDisplayType(mContact);
150 
151  updateView();
152 }
153 
154 void DisplayNameEditWidget::storeContact(KContacts::Addressee &contact) const
155 {
156  contact.setFormattedName(mView->currentText());
157 }
158 
159 void DisplayNameEditWidget::changeName(const KContacts::Addressee &contact)
160 {
161  const QString organization = mContact.organization();
162  mContact = contact;
163  mContact.setOrganization(organization);
164  if (mDisplayType == CustomName) {
165  mContact.setFormattedName(mView->currentText());
166  }
167 
168  updateView();
169 }
170 
171 void DisplayNameEditWidget::changeOrganization(const QString &organization)
172 {
173  mContact.setOrganization(organization);
174 
175  updateView();
176 }
177 
178 void DisplayNameEditWidget::displayTypeChanged(int type)
179 {
180  mDisplayType = (DisplayType)type;
181 
182  updateView();
183 }
184 
185 bool DisplayNameEditWidget::eventFilter(QObject *object, QEvent *event)
186 {
187  if (object == mViewport) {
188  if (event->type() == QEvent::Show) {
189  // retrieve the widget that contains the popup view
190  QWidget *parentWidget = mViewport->parentWidget()->parentWidget();
191 
192  int maxWidth = 0;
193  QFontMetrics metrics(mView->font());
194  const int viewCount(mView->count());
195  for (int i = 0; i < viewCount; ++i) {
196  maxWidth = qMax(maxWidth, metrics.boundingRect(mView->itemText(i)).width());
197  }
198 
199  // resize it to show the complete content
200  parentWidget->resize(maxWidth + mAdditionalPopupWidth + 20, parentWidget->height());
201  }
202  return false;
203  }
204 
205  return QWidget::eventFilter(object, event);
206 }
207 
208 void DisplayNameEditWidget::updateView()
209 {
210  // SimpleName:
211  mView->setItemText(0, mContact.givenName() + QLatin1Char(' ') + mContact.familyName());
212 
213  // FullName:
214  mView->setItemText(1, mContact.assembledName());
215 
216  // ReverseNameWithComma:
217  mView->setItemText(2, mContact.familyName() + QStringLiteral(", ") + mContact.givenName());
218 
219  // ReverseName:
220  mView->setItemText(3, mContact.familyName() + QLatin1Char(' ') + mContact.givenName());
221 
222  // Organization:
223  mView->setItemText(4, mContact.organization());
224 
225  // CustomName:
226  mView->setItemText(5, mContact.formattedName());
227 
228  // delay the state change here, since we might have been called from mView via a signal
230  this,
231  [this]() {
232  setComboBoxEditable(mDisplayType == CustomName);
233  },
235 
236  mView->setCurrentIndex((int)mDisplayType);
237 }
238 
239 void DisplayNameEditWidget::setComboBoxEditable(bool value)
240 {
241  mView->setEditable(value);
242 }
243 
244 #include "displaynameeditwidget.moc"
Q_OBJECTQ_OBJECT
QString assembledName() const
@ FullName
A name of the form: prefix givenName additionalName familyName suffix.
AlignLeft
void setPen(const QColor &color)
void setStyle(QFont::Style style)
QString organization() const
Type type(const QSqlDatabase &db)
QString formattedName() const
int width() const const
QString givenName() const
void setFormattedName(const QString &formattedName)
void drawText(const QPointF &position, const QString &text)
void setWidth(int width)
@ SimpleName
A name of the form: givenName familyName.
virtual bool eventFilter(QObject *watched, QEvent *event)
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
QString i18n(const char *text, const TYPE &arg...)
@ Organization
The organization name.
DisplayType
Describes what the display name should look like.
QueuedConnection
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
void setOrganization(const QString &organization)
@ CustomName
Let the user input a display name.
int row() const const
void resize(int w, int h)
QString familyName() const
@ ReverseName
A name of the form: familyName givenName.
bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9)
const QFont & font() const const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void restore()
void save()
@ ReverseNameWithComma
A name of the form: familyName, givenName.
StrongFocus
void setFont(const QFont &font)
void activated(int index)
QWidget * parentWidget() const const
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const const override
QObject * parent() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sat Apr 1 2023 04:09:04 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.