lineedit.cpp 5.14 KB
Newer Older
1
2
3
/*
 *  lineedit.cpp  -  Line edit widget with extra drag and drop options
 *  Program:  kalarm
4
 *  SPDX-FileCopyrightText: 2003-2020 David Jarvie <djarvie@kde.org>
5
 *
6
 *  SPDX-License-Identifier: GPL-2.0-or-later
7
8
 */

Laurent Montel's avatar
Laurent Montel committed
9
#include "lineedit.h"
10

11
12
#include "dragdrop.h"

David Jarvie's avatar
David Jarvie committed
13
14
#include <KContacts/VCardDrag>
#include <KCalUtils/ICalDrag>
15

16
17
#include <KUrlCompletion>
#include <KShell>
18

Daniel Vrátil's avatar
Daniel Vrátil committed
19
#include <QUrl>
David Jarvie's avatar
David Jarvie committed
20
#include <QRegExp>
David Jarvie's avatar
David Jarvie committed
21
#include <QMimeData>
Laurent Montel's avatar
Qt3to4    
Laurent Montel committed
22
23
#include <QDragEnterEvent>
#include <QDropEvent>
David Jarvie's avatar
David Jarvie committed
24
#include <QFocusEvent>
25
26
27
28
29
30
31
32


/*=============================================================================
= Class LineEdit
= Line edit which accepts drag and drop of text, URLs and/or email addresses.
* It has an option to prevent its contents being selected when it receives
= focus.
=============================================================================*/
David Jarvie's avatar
David Jarvie committed
33
LineEdit::LineEdit(Type type, QWidget* parent)
34
35
    : KLineEdit(parent)
    , mType(type)
36
{
37
    init();
38
39
}

David Jarvie's avatar
David Jarvie committed
40
LineEdit::LineEdit(QWidget* parent)
41
42
    : KLineEdit(parent)
    , mType(Text)
43
{
44
    init();
45
46
47
48
}

void LineEdit::init()
{
49
50
    if (mType == Url)
    {
Laurent Montel's avatar
Laurent Montel committed
51
        setCompletionMode(KCompletion::CompletionShell);
Laurent Montel's avatar
Laurent Montel committed
52
        auto* comp = new KUrlCompletion(KUrlCompletion::FileCompletion);
53
54
55
56
        comp->setReplaceHome(true);
        setCompletionObject(comp);
        setAutoDeleteCompletionObject(true);
    }
57
    else
Laurent Montel's avatar
Laurent Montel committed
58
        setCompletionMode(KCompletion::CompletionNone);
59
60
61
62
63
64
65
66
}

/******************************************************************************
*  Called when the line edit receives focus.
*  If 'noSelect' is true, prevent the contents being selected.
*/
void LineEdit::focusInEvent(QFocusEvent* e)
{
67
68
69
    QFocusEvent newe(QEvent::FocusIn, (mNoSelect ? Qt::OtherFocusReason : e->reason()));
    KLineEdit::focusInEvent(&newe);
    mNoSelect = false;
70
71
}

72
73
QString LineEdit::text() const
{
74
75
76
    if (mType == Url)
        return KShell::tildeExpand(KLineEdit::text());
    return KLineEdit::text();
77
78
}

79
80
void LineEdit::setText(const QString& text)
{
81
82
    KLineEdit::setText(text);
    setCursorPosition(mSetCursorAtEnd ? text.length() : 0);
83
84
85
86
}

void LineEdit::dragEnterEvent(QDragEnterEvent* e)
{
87
88
89
90
91
92
    const QMimeData* data = e->mimeData();
    bool ok;
    if (KCalUtils::ICalDrag::canDecode(data))
        ok = false;   // don't accept "text/calendar" objects
    else
        ok = (data->hasText()
Daniel Vrátil's avatar
Daniel Vrátil committed
93
           || data->hasUrls()
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
94
           || (mType == Emails && KContacts::VCardDrag::canDecode(data)));
95
    if (ok)
96
        e->acceptProposedAction();
97
    else
98
        e->ignore();
99
100
101
102
}

void LineEdit::dropEvent(QDropEvent* e)
{
103
    const QMimeData* data = e->mimeData();
104
    QString               txt;
105
106
    QString               newText;
    QStringList           newEmails;
Daniel Vrátil's avatar
Daniel Vrátil committed
107
    QList<QUrl>           files;
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
108
    KContacts::Addressee::List addrList;
109

110
    if (mType == Emails
111
    &&  KContacts::VCardDrag::canDecode(data)  &&  KContacts::VCardDrag::fromMimeData(data, addrList))
112
113
    {
        // KAddressBook entries
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
114
        for (KContacts::Addressee::List::Iterator it = addrList.begin();  it != addrList.end();  ++it)
115
        {
116
            const QString em((*it).fullEmail());
117
118
119
120
            if (!em.isEmpty())
                newEmails.append(em);
        }
    }
Daniel Vrátil's avatar
Daniel Vrátil committed
121
    else if (!(files = data->urls()).isEmpty())
122
123
124
125
126
127
    {
        // URL(s)
        switch (mType)
        {
            case Url:
                // URL entry field - ignore all but the first dropped URL
Daniel Vrátil's avatar
Daniel Vrátil committed
128
                setText(files.first().toDisplayString());    // replace any existing text
129
130
131
132
                break;
            case Emails:
            {
                // Email entry field - ignore all but mailto: URLs
133
134
                const QString mailto = QStringLiteral("mailto");
                for (const QUrl& file : qAsConst(files))
135
                {
136
137
                    if (file.scheme() == mailto)
                        newEmails.append(file.path());
138
139
140
141
                }
                break;
            }
            case Text:
Daniel Vrátil's avatar
Daniel Vrátil committed
142
                newText = files.first().toDisplayString();
143
144
145
                break;
        }
    }
146
    else if (DragDrop::dropPlainText(data, txt))
147
148
149
150
    {
        // Plain text
        if (mType == Emails)
        {
Laurent Montel's avatar
Laurent Montel committed
151
            // Remove newlines from a list of email addresses, and allow an eventual mailto: scheme
152
            const QString mailto = QStringLiteral("mailto:");
153
            newEmails = txt.split(QRegExp(QLatin1String("[\r\n]+")), Qt::SkipEmptyParts);
154
155
156
157
            for (QStringList::Iterator it = newEmails.begin();  it != newEmails.end();  ++it)
            {
                if ((*it).startsWith(mailto))
                {
158
                    const QUrl url = QUrl::fromUserInput(*it);
159
160
161
162
163
164
                    *it = url.path();
                }
            }
        }
        else
        {
165
            const int newline = txt.indexOf(QLatin1Char('\n'));
166
167
168
169
            newText = (newline >= 0) ? txt.left(newline) : txt;
        }
    }

David Jarvie's avatar
David Jarvie committed
170
    if (!newEmails.isEmpty())
171
    {
Laurent Montel's avatar
Laurent Montel committed
172
        newText = newEmails.join(QLatin1Char(','));
173
        const int c = cursorPosition();
174
        if (c > 0)
Laurent Montel's avatar
Laurent Montel committed
175
            newText.prepend(QLatin1Char(','));
176
        if (c < static_cast<int>(text().length()))
Laurent Montel's avatar
Laurent Montel committed
177
            newText.append(QLatin1Char(','));
178
179
180
    }
    if (!newText.isEmpty())
        insert(newText);
181
}
182

183
// vim: et sw=4: