displaynameeditwidget.cpp 8.13 KB
Newer Older
1
/*
Tobias Koenig's avatar
Tobias Koenig committed
2
    This file is part of Akonadi Contact.
3 4 5

    Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>

Tobias Koenig's avatar
Tobias Koenig committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19
    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
20 21 22
*/

#include "displaynameeditwidget.h"
23

24

Laurent Montel's avatar
Laurent Montel committed
25
#include <QEvent>
26 27 28 29
#include <QAbstractItemView>
#include <QHBoxLayout>
#include <QPainter>
#include <QStyledItemDelegate>
30

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
31
#include <kcontacts/addressee.h>
Laurent Montel's avatar
Laurent Montel committed
32 33
#include <KComboBox>
#include <KLocalizedString>
34

35
// Tries to guess the display type that is used for the passed contact
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
36
static DisplayNameEditWidget::DisplayType guessedDisplayType(const KContacts::Addressee &contact)
37
{
Guy Maurel's avatar
Guy Maurel committed
38 39 40 41
    if (contact.formattedName() == (contact.givenName() + QLatin1Char(' ') + contact.familyName())) {
        return DisplayNameEditWidget::SimpleName;
    } else if (contact.formattedName() == contact.assembledName()) {
        return DisplayNameEditWidget::FullName;
42
    } else if (contact.formattedName() == (contact.familyName() + QStringLiteral(", ") + contact.givenName())) {
Guy Maurel's avatar
Guy Maurel committed
43 44 45 46 47 48 49 50
        return DisplayNameEditWidget::ReverseNameWithComma;
    } else if (contact.formattedName() == (contact.familyName() + QLatin1Char(' ') + contact.givenName())) {
        return DisplayNameEditWidget::ReverseName;
    } else if (contact.formattedName() == contact.organization()) {
        return DisplayNameEditWidget::Organization;
    } else {
        return DisplayNameEditWidget::CustomName;
    }
51 52
}

53
class DisplayNameDelegate : public QStyledItemDelegate
54
{
Laurent Montel's avatar
Laurent Montel committed
55
    Q_OBJECT
Guy Maurel's avatar
Guy Maurel committed
56
public:
Laurent Montel's avatar
Laurent Montel committed
57
    DisplayNameDelegate(QAbstractItemView *view, QObject *parent = nullptr)
Guy Maurel's avatar
Guy Maurel committed
58 59
        : QStyledItemDelegate(parent)
        , mMaxDescriptionWidth(0)
60
    {
Guy Maurel's avatar
Guy Maurel committed
61 62 63 64 65 66 67 68 69 70
        mDescriptions.append(i18n("Short Name"));
        mDescriptions.append(i18n("Full Name"));
        mDescriptions.append(i18n("Reverse Name with Comma"));
        mDescriptions.append(i18n("Reverse Name"));
        mDescriptions.append(i18n("Organization"));
        mDescriptions.append(i18nc("@item:inlistbox A custom name format", "Custom"));

        QFont font = view->font();
        font.setStyle(QFont::StyleItalic);
        QFontMetrics metrics(font);
Laurent Montel's avatar
Laurent Montel committed
71
        for (const QString &description : qAsConst(mDescriptions)) {
Guy Maurel's avatar
Guy Maurel committed
72 73 74 75
            mMaxDescriptionWidth = qMax(mMaxDescriptionWidth, metrics.width(description));
        }

        mMaxDescriptionWidth += 3;
76 77
    }

78
    int maximumDescriptionWidth() const
79
    {
Guy Maurel's avatar
Guy Maurel committed
80
        return mMaxDescriptionWidth;
81 82
    }

83
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
84
    {
Guy Maurel's avatar
Guy Maurel committed
85 86 87 88 89 90 91 92 93 94 95 96 97
        QStyledItemDelegate::paint(painter, option, index);
        const QRect rect(option.rect.width() - mMaxDescriptionWidth, option.rect.y(), mMaxDescriptionWidth, option.rect.height());
        painter->save();
        QFont font(painter->font());
        font.setStyle(QFont::StyleItalic);
        painter->setFont(font);
        if (option.state & QStyle::State_Selected) {
            painter->setPen(option.palette.color(QPalette::Normal, QPalette::BrightText));
        } else {
            painter->setPen(option.palette.color(QPalette::Disabled, QPalette::Text));
        }
        painter->drawText(rect, Qt::AlignLeft, mDescriptions.at(index.row()));
        painter->restore();
98 99
    }

100
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
101
    {
Guy Maurel's avatar
Guy Maurel committed
102 103
        QSize size = QStyledItemDelegate::sizeHint(option, index);
        size.setWidth(size.width() + mMaxDescriptionWidth);
104

Guy Maurel's avatar
Guy Maurel committed
105
        return size;
106 107
    }

Guy Maurel's avatar
Guy Maurel committed
108
private:
109 110
    QStringList mDescriptions;
    int mMaxDescriptionWidth;
111 112
};

Guy Maurel's avatar
Guy Maurel committed
113 114 115
DisplayNameEditWidget::DisplayNameEditWidget(QWidget *parent)
    : QWidget(parent)
    , mDisplayType(FullName)
116
{
Guy Maurel's avatar
Guy Maurel committed
117 118
    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setMargin(0);
119

Guy Maurel's avatar
Guy Maurel committed
120 121
    mView = new KComboBox(this);
    mView->addItems(QStringList() << QString() << QString() << QString()
Guy Maurel's avatar
Guy Maurel committed
122
                    << QString() << QString() << QString());
123

Guy Maurel's avatar
Guy Maurel committed
124 125 126
    layout->addWidget(mView);
    setFocusProxy(mView);
    setFocusPolicy(Qt::StrongFocus);
Laurent Montel's avatar
Laurent Montel committed
127
    connect(mView, static_cast<void (KComboBox::*)(int)>(&KComboBox::activated), this, &DisplayNameEditWidget::displayTypeChanged);
128

Guy Maurel's avatar
Guy Maurel committed
129 130
    DisplayNameDelegate *delegate = new DisplayNameDelegate(mView->view());
    mView->view()->setItemDelegate(delegate);
131

Guy Maurel's avatar
Guy Maurel committed
132
    mAdditionalPopupWidth = delegate->maximumDescriptionWidth();
133

Guy Maurel's avatar
Guy Maurel committed
134 135
    mViewport = mView->view()->viewport();
    mViewport->installEventFilter(this);
136 137 138 139 140 141
}

DisplayNameEditWidget::~DisplayNameEditWidget()
{
}

Guy Maurel's avatar
Guy Maurel committed
142
void DisplayNameEditWidget::setReadOnly(bool readOnly)
143
{
Guy Maurel's avatar
Guy Maurel committed
144
    mView->setEnabled(!readOnly);
145 146
}

Guy Maurel's avatar
Guy Maurel committed
147
void DisplayNameEditWidget::setDisplayType(DisplayType type)
148
{
149
    if ((int)type == -1) {
Guy Maurel's avatar
Guy Maurel committed
150 151 152 153 154
        // guess the used display type
        mDisplayType = guessedDisplayType(mContact);
    } else {
        mDisplayType = type;
    }
155

Guy Maurel's avatar
Guy Maurel committed
156
    updateView();
157 158 159 160
}

DisplayNameEditWidget::DisplayType DisplayNameEditWidget::displayType() const
{
Guy Maurel's avatar
Guy Maurel committed
161
    return mDisplayType;
162 163
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
164
void DisplayNameEditWidget::loadContact(const KContacts::Addressee &contact)
165
{
Guy Maurel's avatar
Guy Maurel committed
166
    mContact = contact;
167

Guy Maurel's avatar
Guy Maurel committed
168
    mDisplayType = guessedDisplayType(mContact);
169

Guy Maurel's avatar
Guy Maurel committed
170
    updateView();
171 172
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
173
void DisplayNameEditWidget::storeContact(KContacts::Addressee &contact) const
174
{
Guy Maurel's avatar
Guy Maurel committed
175
    contact.setFormattedName(mView->currentText());
176 177
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
178
void DisplayNameEditWidget::changeName(const KContacts::Addressee &contact)
179
{
Guy Maurel's avatar
Guy Maurel committed
180 181 182 183 184 185 186 187
    const QString organization = mContact.organization();
    mContact = contact;
    mContact.setOrganization(organization);
    if (mDisplayType == CustomName) {
        mContact.setFormattedName(mView->currentText());
    }

    updateView();
188 189
}

Guy Maurel's avatar
Guy Maurel committed
190
void DisplayNameEditWidget::changeOrganization(const QString &organization)
191
{
Guy Maurel's avatar
Guy Maurel committed
192
    mContact.setOrganization(organization);
193

Guy Maurel's avatar
Guy Maurel committed
194
    updateView();
195 196
}

Guy Maurel's avatar
Guy Maurel committed
197
void DisplayNameEditWidget::displayTypeChanged(int type)
198
{
Guy Maurel's avatar
Guy Maurel committed
199
    mDisplayType = (DisplayType)type;
200

Guy Maurel's avatar
Guy Maurel committed
201
    updateView();
202 203
}

Guy Maurel's avatar
Guy Maurel committed
204
bool DisplayNameEditWidget::eventFilter(QObject *object, QEvent *event)
205
{
Guy Maurel's avatar
Guy Maurel committed
206 207 208 209 210 211 212
    if (object == mViewport) {
        if (event->type() == QEvent::Show) {
            // retrieve the widget that contains the popup view
            QWidget *parentWidget = mViewport->parentWidget()->parentWidget();

            int maxWidth = 0;
            QFontMetrics metrics(mView->font());
213 214
            const int viewCount(mView->count());
            for (int i = 0; i < viewCount; ++i) {
Guy Maurel's avatar
Guy Maurel committed
215 216 217 218 219 220 221
                maxWidth = qMax(maxWidth, metrics.width(mView->itemText(i)));
            }

            // resize it to show the complete content
            parentWidget->resize(maxWidth + mAdditionalPopupWidth + 20, parentWidget->height());
        }
        return false;
222
    }
223

Guy Maurel's avatar
Guy Maurel committed
224
    return QWidget::eventFilter(object, event);
225 226 227 228
}

void DisplayNameEditWidget::updateView()
{
Guy Maurel's avatar
Guy Maurel committed
229 230
    // SimpleName:
    mView->setItemText(0, mContact.givenName() + QLatin1Char(' ') + mContact.familyName());
231

Guy Maurel's avatar
Guy Maurel committed
232 233
    // FullName:
    mView->setItemText(1, mContact.assembledName());
234

Guy Maurel's avatar
Guy Maurel committed
235
    // ReverseNameWithComma:
236
    mView->setItemText(2, mContact.familyName() + QStringLiteral(", ") + mContact.givenName());
237

Guy Maurel's avatar
Guy Maurel committed
238 239
    // ReverseName:
    mView->setItemText(3, mContact.familyName() + QLatin1Char(' ') + mContact.givenName());
240

Guy Maurel's avatar
Guy Maurel committed
241 242
    // Organization:
    mView->setItemText(4, mContact.organization());
243

Guy Maurel's avatar
Guy Maurel committed
244 245
    // CustomName:
    mView->setItemText(5, mContact.formattedName());
246

Guy Maurel's avatar
Guy Maurel committed
247 248
    // delay the state change here, since we might have been called from mView via a signal
    QMetaObject::invokeMethod(this, "setComboBoxEditable", Qt::QueuedConnection, Q_ARG(bool, mDisplayType == CustomName));
249

Guy Maurel's avatar
Guy Maurel committed
250
    mView->setCurrentIndex((int)mDisplayType);
251 252
}

Guy Maurel's avatar
Guy Maurel committed
253
void DisplayNameEditWidget::setComboBoxEditable(bool value)
254
{
Guy Maurel's avatar
Guy Maurel committed
255
    mView->setEditable(value);
256
}
Laurent Montel's avatar
Laurent Montel committed
257 258

#include "displaynameeditwidget.moc"