Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PIM
KMail
Commits
3a41f765
Commit
3a41f765
authored
Sep 28, 2021
by
Marco Rebhan
Committed by
Laurent Montel
Sep 28, 2021
Browse files
Add Face header support
parent
c44e8d91
Pipeline
#83199
passed with stage
in 25 minutes and 26 seconds
Changes
11
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
3a41f765
...
...
@@ -46,7 +46,7 @@ set(KDEPIM_VERSION "${PIM_VERSION}${KDEPIM_DEV_VERSION} (${RELEASE_SERVICE_VERSI
set
(
AKONADI_MIMELIB_VERSION
"5.18.40"
)
set
(
AKONADI_CONTACT_VERSION
"5.18.40"
)
set
(
CALENDARUTILS_LIB_VERSION
"5.18.40"
)
set
(
IDENTITYMANAGEMENT_LIB_VERSION
"5.18.4
0
"
)
set
(
IDENTITYMANAGEMENT_LIB_VERSION
"5.18.4
3
"
)
set
(
KLDAP_LIB_VERSION
"5.18.40"
)
set
(
KMAILTRANSPORT_LIB_VERSION
"5.18.40"
)
set
(
KONTACTINTERFACE_LIB_VERSION
"5.18.40"
)
...
...
src/CMakeLists.txt
View file @
3a41f765
...
...
@@ -75,6 +75,7 @@ target_sources(kmailprivate PRIVATE
identity/identitylistview.cpp
identity/identitydialog.cpp
identity/xfaceconfigurator.cpp
identity/encodedimagepicker.cpp
identity/identitypage.cpp
identity/newidentitydialog.cpp
identity/identityeditvcarddialog.cpp
...
...
@@ -221,6 +222,8 @@ ki18n_wrap_ui(kmailprivate
ui/accountspagereceivingtab.ui
ui/searchwindow.ui
ui/incompleteindexdialog.ui
ui/xfaceconfigurator.ui
ui/encodedimagepicker.ui
)
# KCFG files. The main kmail.kcfg is configured by CMake and put
...
...
src/editor/kmcomposerwin.cpp
View file @
3a41f765
...
...
@@ -1650,7 +1650,7 @@ uint KMComposerWin::currentIdentity() const
return
mComposerBase
->
identityCombo
()
->
currentIdentity
();
}
void
KMComposerWin
::
add
X
Face
(
const
KIdentityManagement
::
Identity
&
ident
,
const
KMime
::
Message
::
Ptr
&
msg
)
void
KMComposerWin
::
addFace
Headers
(
const
KIdentityManagement
::
Identity
&
ident
,
const
KMime
::
Message
::
Ptr
&
msg
)
{
if
(
!
ident
.
isXFaceEnabled
()
||
ident
.
xface
().
isEmpty
())
{
msg
->
removeHeader
(
"X-Face"
);
...
...
@@ -1666,6 +1666,30 @@ void KMComposerWin::addXFace(const KIdentityManagement::Identity &ident, const K
msg
->
setHeader
(
header
);
}
}
if
(
!
ident
.
isFaceEnabled
()
||
ident
.
face
().
isEmpty
())
{
msg
->
removeHeader
(
"Face"
);
}
else
{
QString
face
=
ident
.
face
();
if
(
!
face
.
isEmpty
())
{
// The first line of data is 72 lines long to account for the
// header name, the following lines are 76 lines long, like in
// https://quimby.gnus.org/circus/face/
if
(
face
.
length
()
>
72
)
{
int
numNL
=
(
face
.
length
()
-
73
)
/
76
;
for
(
int
i
=
numNL
;
i
>
0
;
--
i
)
{
face
.
insert
(
72
+
i
*
76
,
QStringLiteral
(
"
\n\t
"
));
}
face
.
insert
(
72
,
QStringLiteral
(
"
\n\t
"
));
}
auto
header
=
new
KMime
::
Headers
::
Generic
(
"Face"
);
header
->
fromUnicodeString
(
face
,
"utf-8"
);
msg
->
setHeader
(
header
);
}
}
}
void
KMComposerWin
::
setMessage
(
const
KMime
::
Message
::
Ptr
&
newMsg
,
...
...
@@ -1783,7 +1807,7 @@ void KMComposerWin::setMessage(const KMime::Message::Ptr &newMsg,
const
auto
&
ident
=
identity
();
add
X
Face
(
ident
,
mMsg
);
addFace
Headers
(
ident
,
mMsg
);
// if these headers are present, the state of the message should be overruled
if
(
auto
hdr
=
mMsg
->
headerByType
(
"X-KMail-SignatureActionEnabled"
))
{
...
...
@@ -3238,7 +3262,8 @@ void KMComposerWin::slotIdentityChanged(uint uoid, bool initialChange)
organization
->
fromUnicodeString
(
ident
.
organization
(),
"utf-8"
);
mMsg
->
setHeader
(
organization
);
}
addXFace
(
ident
,
mMsg
);
addFaceHeaders
(
ident
,
mMsg
);
if
(
initialChange
)
{
if
(
auto
hrd
=
mMsg
->
headerByType
(
"X-KMail-Transport"
))
{
...
...
src/editor/kmcomposerwin.h
View file @
3a41f765
...
...
@@ -582,7 +582,7 @@ private:
Q_REQUIRED_RESULT
bool
sendLaterRegistered
()
const
;
void
slotRecipientEditorLineFocused
();
void
updateHamburgerMenu
();
void
add
X
Face
(
const
KIdentityManagement
::
Identity
&
ident
,
const
KMime
::
Message
::
Ptr
&
msg
);
void
addFace
Headers
(
const
KIdentityManagement
::
Identity
&
ident
,
const
KMime
::
Message
::
Ptr
&
msg
);
Akonadi
::
Collection
mCollectionForNewMessage
;
QMap
<
QByteArray
,
QString
>
mExtraHeaders
;
...
...
src/identity/encodedimagepicker.cpp
0 → 100644
View file @
3a41f765
/*
encodedimagepicker.cpp
KMail, the KDE mail client.
SPDX-FileCopyrightText: 2021 the KMail authors.
See file AUTHORS for details
SPDX-License-Identifier: GPL-2.0-only
*/
#include "encodedimagepicker.h"
#include "ui_encodedimagepicker.h"
#include <Akonadi/Contact/ContactSearchJob>
#include <KIdentityManagement/Identity>
#include <KIdentityManagement/IdentityManager>
#include <KPIMTextEdit/PlainTextEditor>
#include <KIO/StoredTransferJob>
#include <KJobWidgets>
#include <KLocalizedString>
#include <KMessageBox>
#include <QFileDialog>
#include <QImageReader>
using
namespace
KMail
;
using
KContacts
::
Addressee
;
EncodedImagePicker
::
EncodedImagePicker
(
QWidget
*
parent
)
:
QGroupBox
(
parent
)
,
mUi
(
new
Ui
::
EncodedImagePicker
)
{
mUi
->
setupUi
(
this
);
mUi
->
source
->
editor
()
->
setFont
(
QFontDatabase
::
systemFont
(
QFontDatabase
::
FixedFont
));
// wrap anywhere, these contain encoded data
mUi
->
source
->
editor
()
->
setWordWrapMode
(
QTextOption
::
WrapAnywhere
);
connect
(
mUi
->
openImageButton
,
&
QAbstractButton
::
clicked
,
this
,
&
EncodedImagePicker
::
selectFile
);
connect
(
mUi
->
selectContactsButton
,
&
QPushButton
::
released
,
this
,
&
EncodedImagePicker
::
selectFromAddressBook
);
connect
(
mUi
->
source
->
editor
(),
&
KPIMTextEdit
::
PlainTextEditor
::
textChanged
,
this
,
&
EncodedImagePicker
::
sourceChanged
);
}
EncodedImagePicker
::~
EncodedImagePicker
()
=
default
;
void
EncodedImagePicker
::
setInfo
(
const
QString
&
info
)
{
mUi
->
infoLabel
->
setText
(
info
);
}
QString
EncodedImagePicker
::
source
()
const
{
return
mUi
->
source
->
editor
()
->
toPlainText
();
}
void
EncodedImagePicker
::
setSource
(
const
QString
&
source
)
{
mUi
->
source
->
editor
()
->
setPlainText
(
source
);
}
void
EncodedImagePicker
::
setImage
(
const
QImage
&
image
)
{
if
(
image
.
isNull
())
{
mUi
->
image
->
clear
();
}
else
{
const
QPixmap
p
=
QPixmap
::
fromImage
(
image
);
mUi
->
image
->
setPixmap
(
p
);
}
}
void
EncodedImagePicker
::
selectFile
()
{
QString
filter
;
const
QList
<
QByteArray
>
supportedImage
=
QImageReader
::
supportedImageFormats
();
for
(
const
QByteArray
&
ba
:
supportedImage
)
{
if
(
!
filter
.
isEmpty
())
{
filter
+=
QLatin1Char
(
' '
);
}
filter
+=
QLatin1String
(
"*."
)
+
QString
::
fromLatin1
(
ba
);
}
filter
=
QStringLiteral
(
"%1 (%2)"
).
arg
(
i18n
(
"Image"
),
filter
);
const
QUrl
url
=
QFileDialog
::
getOpenFileUrl
(
this
,
QString
(),
QUrl
(),
filter
);
if
(
!
url
.
isEmpty
())
{
setFromFile
(
url
);
}
}
void
EncodedImagePicker
::
setFromFile
(
const
QUrl
&
url
)
{
auto
job
=
KIO
::
storedGet
(
url
);
KJobWidgets
::
setWindow
(
job
,
this
);
connect
(
job
,
&
KJob
::
result
,
this
,
&
EncodedImagePicker
::
setFromFileDone
);
job
->
start
();
}
void
EncodedImagePicker
::
setFromFileDone
(
KJob
*
job
)
{
const
KIO
::
StoredTransferJob
*
kioJob
=
qobject_cast
<
KIO
::
StoredTransferJob
*>
(
job
);
if
(
kioJob
->
error
()
==
0
)
{
const
QImage
image
=
QImage
::
fromData
(
kioJob
->
data
());
Q_EMIT
imageSelected
(
image
);
}
else
{
KMessageBox
::
error
(
this
,
kioJob
->
errorString
());
}
}
void
EncodedImagePicker
::
selectFromAddressBook
()
{
using
namespace
KIdentityManagement
;
const
IdentityManager
manager
(
true
);
const
Identity
defaultIdentity
=
manager
.
defaultIdentity
();
const
QString
email
=
defaultIdentity
.
primaryEmailAddress
().
toLower
();
auto
job
=
new
Akonadi
::
ContactSearchJob
(
this
);
job
->
setLimit
(
1
);
job
->
setQuery
(
Akonadi
::
ContactSearchJob
::
Email
,
email
,
Akonadi
::
ContactSearchJob
::
ExactMatch
);
connect
(
job
,
&
KJob
::
result
,
this
,
&
EncodedImagePicker
::
selectFromAddressBookDone
);
}
void
EncodedImagePicker
::
selectFromAddressBookDone
(
KJob
*
job
)
{
const
Akonadi
::
ContactSearchJob
*
searchJob
=
qobject_cast
<
Akonadi
::
ContactSearchJob
*>
(
job
);
if
(
searchJob
->
contacts
().
isEmpty
())
{
KMessageBox
::
information
(
this
,
i18n
(
"You do not have your own contact defined in the address book."
),
i18n
(
"No Picture"
));
return
;
}
const
Addressee
contact
=
searchJob
->
contacts
().
at
(
0
);
if
(
contact
.
photo
().
isIntern
())
{
const
QImage
photo
=
contact
.
photo
().
data
();
if
(
photo
.
isNull
())
{
KMessageBox
::
information
(
this
,
i18n
(
"No picture set for your address book entry."
),
i18n
(
"No Picture"
));
}
else
{
Q_EMIT
imageSelected
(
photo
);
}
}
else
{
const
QUrl
url
(
contact
.
photo
().
url
());
if
(
url
.
isEmpty
())
{
KMessageBox
::
information
(
this
,
i18n
(
"No picture set for your address book entry."
),
i18n
(
"No Picture"
));
}
else
{
setFromFile
(
url
);
}
}
}
src/identity/encodedimagepicker.h
0 → 100644
View file @
3a41f765
/* -*- c++ -*-
encodedimagepicker.h
KMail, the KDE mail client.
SPDX-FileCopyrightText: 2021 the KMail authors.
See file AUTHORS for details
SPDX-License-Identifier: GPL-2.0-only
*/
#pragma once
#include <QGroupBox>
class
KJob
;
namespace
Ui
{
class
EncodedImagePicker
;
}
namespace
KMail
{
class
EncodedImagePicker
:
public
QGroupBox
{
Q_OBJECT
public:
explicit
EncodedImagePicker
(
QWidget
*
parent
=
nullptr
);
~
EncodedImagePicker
()
override
;
void
setInfo
(
const
QString
&
info
);
Q_REQUIRED_RESULT
QString
source
()
const
;
void
setSource
(
const
QString
&
source
);
void
setImage
(
const
QImage
&
image
);
Q_SIGNALS:
void
imageSelected
(
const
QImage
&
);
void
sourceChanged
();
private:
void
setFromFile
(
const
QUrl
&
url
);
void
selectFile
();
void
setFromFileDone
(
KJob
*
);
void
selectFromAddressBook
();
void
selectFromAddressBookDone
(
KJob
*
);
private:
QScopedPointer
<
Ui
::
EncodedImagePicker
>
mUi
;
};
}
// namespace KMail
src/identity/identitydialog.cpp
View file @
3a41f765
...
...
@@ -952,6 +952,8 @@ void IdentityDialog::setIdentity(KIdentityManagement::Identity &ident)
mSignatureConfigurator
->
setSignature
(
ident
.
signature
());
mXFaceConfigurator
->
setXFace
(
ident
.
xface
());
mXFaceConfigurator
->
setXFaceEnabled
(
ident
.
isXFaceEnabled
());
mXFaceConfigurator
->
setFace
(
ident
.
face
());
mXFaceConfigurator
->
setFaceEnabled
(
ident
.
isFaceEnabled
());
}
void
IdentityDialog
::
unregisterSpecialCollection
(
qint64
colId
)
...
...
@@ -1064,6 +1066,8 @@ void IdentityDialog::updateIdentity(KIdentityManagement::Identity &ident)
ident
.
setSignature
(
mSignatureConfigurator
->
signature
());
ident
.
setXFace
(
mXFaceConfigurator
->
xface
());
ident
.
setXFaceEnabled
(
mXFaceConfigurator
->
isXFaceEnabled
());
ident
.
setFace
(
mXFaceConfigurator
->
face
());
ident
.
setFaceEnabled
(
mXFaceConfigurator
->
isFaceEnabled
());
}
void
IdentityDialog
::
slotEditVcard
()
...
...
src/identity/xfaceconfigurator.cpp
View file @
3a41f765
...
...
@@ -7,252 +7,266 @@
*/
#include "xfaceconfigurator.h"
#include "encodedimagepicker.h"
#include "ui_xfaceconfigurator.h"
#include <Akonadi/Contact/ContactSearchJob>
#include <KIdentityManagement/Identity>
#include <KIdentityManagement/IdentityManager>
#include <KPIMTextEdit/PlainTextEditor>
#include <KPIMTextEdit/PlainTextEditorWidget>
#include <MessageViewer/KXFace>
#include <KIO/StoredTransferJob>
#include <KJobWidgets>
#include <KLocalizedString>
#include <KMessageBox>
#include <QComboBox>
#include <QCheckBox>
#include <QFileDialog>
#include <QFontDatabase>
#include <QHBoxLayout>
#include <QImageReader>
#include <QLabel>
#include <QPushButton>
#include <QStackedWidget>
#include <QVBoxLayout>
using
namespace
KContacts
;
using
namespace
KIO
;
using
namespace
KMail
;
using
namespace
MessageViewer
;
#include <QBuffer>
#include <QProcess>
using
namespace
KMail
;
using
MessageViewer
::
KXFace
;
// The size of the PNG used in the Face header must be at most 725 bytes, as
// explained here: https://quimby.gnus.org/circus/face/
#define FACE_MAX_SIZE 725
XFaceConfigurator
::
XFaceConfigurator
(
QWidget
*
parent
)
:
QWidget
(
parent
)
,
m
EnableCheck
(
new
QCheckBox
(
i18n
(
"&Send picture with every message"
),
this
)
)
,
m
XFaceLabel
(
new
QLabel
(
this
))
,
m
Ui
(
new
Ui
::
XFaceConfigurator
)
,
m
PngquantProc
(
new
QProcess
(
this
))
{
auto
vlay
=
new
QVBoxLayout
(
this
);
vlay
->
setObjectName
(
QStringLiteral
(
"main layout"
));
auto
hlay
=
new
QHBoxLayout
();
vlay
->
addLayout
(
hlay
);
// "enable X-Face" checkbox:
mEnableCheck
->
setWhatsThis
(
i18n
(
"Check this box if you want KMail to add a so-called X-Face header to messages "
"written with this identity. An X-Face is a small (48x48 pixels) black and "
"white image that some mail clients are able to display."
));
hlay
->
addWidget
(
mEnableCheck
,
Qt
::
AlignLeft
|
Qt
::
AlignVCenter
);
mXFaceLabel
->
setWhatsThis
(
i18n
(
"This is a preview of the picture selected/entered below."
));
mXFaceLabel
->
setFixedSize
(
48
,
48
);
mXFaceLabel
->
setFrameShape
(
QFrame
::
Box
);
hlay
->
addWidget
(
mXFaceLabel
);
// label1 = new QLabel( "X-Face:", this );
// vlay->addWidget( label1 );
// "obtain X-Face from" combo and label:
hlay
=
new
QHBoxLayout
();
// inherits spacing
vlay
->
addLayout
(
hlay
);
auto
sourceCombo
=
new
QComboBox
(
this
);
sourceCombo
->
setWhatsThis
(
i18n
(
"Click on the widgets below to obtain help on the input methods."
));
sourceCombo
->
setEnabled
(
false
);
// since !mEnableCheck->isChecked()
sourceCombo
->
addItems
(
QStringList
()
<<
i18nc
(
"continuation of
\"
obtain picture from
\"
"
,
"External Source"
)
<<
i18nc
(
"continuation of
\"
obtain picture from
\"
"
,
"Input Field Below"
));
auto
label
=
new
QLabel
(
i18n
(
"Obtain pic&ture from:"
),
this
);
label
->
setBuddy
(
sourceCombo
);
label
->
setEnabled
(
false
);
// since !mEnableCheck->isChecked()
hlay
->
addWidget
(
label
);
hlay
->
addWidget
(
sourceCombo
,
1
);
// widget stack that is controlled by the source combo:
auto
widgetStack
=
new
QStackedWidget
(
this
);
widgetStack
->
setEnabled
(
false
);
// since !mEnableCheck->isChecked()
vlay
->
addWidget
(
widgetStack
,
1
);
connect
(
sourceCombo
,
&
QComboBox
::
highlighted
,
widgetStack
,
&
QStackedWidget
::
setCurrentIndex
);
connect
(
sourceCombo
,
&
QComboBox
::
activated
,
widgetStack
,
&
QStackedWidget
::
setCurrentIndex
);
connect
(
mEnableCheck
,
&
QCheckBox
::
toggled
,
sourceCombo
,
&
QComboBox
::
setEnabled
);
connect
(
mEnableCheck
,
&
QCheckBox
::
toggled
,
widgetStack
,
&
QStackedWidget
::
setEnabled
);
connect
(
mEnableCheck
,
&
QCheckBox
::
toggled
,
label
,
&
QLabel
::
setEnabled
);
// The focus might be still in the widget that is disabled
connect
(
mEnableCheck
,
&
QAbstractButton
::
clicked
,
mEnableCheck
,
qOverload
<>
(
&
QWidget
::
setFocus
));
int
pageno
=
0
;
// page 0: create X-Face from image file or address book entry
auto
page
=
new
QWidget
(
widgetStack
);
widgetStack
->
insertWidget
(
pageno
,
page
);
// force sequential numbers (play safe)
auto
page_vlay
=
new
QVBoxLayout
(
page
);
page_vlay
->
setContentsMargins
({});
hlay
=
new
QHBoxLayout
();
// inherits spacing ??? FIXME really?
page_vlay
->
addLayout
(
hlay
);
auto
mFromFileBtn
=
new
QPushButton
(
i18n
(
"Select File..."
),
page
);
mFromFileBtn
->
setWhatsThis
(
i18n
(
"Use this to select an image file to create the picture from. "
"The image should be of high contrast and nearly quadratic shape. "
"A light background helps improve the result."
));
mFromFileBtn
->
setAutoDefault
(
false
);
page_vlay
->
addWidget
(
mFromFileBtn
,
1
);
connect
(
mFromFileBtn
,
&
QPushButton
::
released
,
this
,
&
XFaceConfigurator
::
slotSelectFile
);
auto
mFromAddrbkBtn
=
new
QPushButton
(
i18n
(
"Set From Address Book"
),
page
);
mFromAddrbkBtn
->
setWhatsThis
(
i18n
(
"You can use a scaled-down version of the picture "
"you have set in your address book entry."
));
mFromAddrbkBtn
->
setAutoDefault
(
false
);
page_vlay
->
addWidget
(
mFromAddrbkBtn
,
1
);
connect
(
mFromAddrbkBtn
,
&
QPushButton
::
released
,
this
,
&
XFaceConfigurator
::
slotSelectFromAddressbook
);
auto
label1
=
new
QLabel
(
i18n
(
"<qt>KMail can send a small (48x48 pixels), low-quality, "
"monochrome picture with every message. "
"For example, this could be a picture of you or a glyph. "
"It is shown in the recipient's mail client (if supported).</qt>"
),
page
);
label1
->
setAlignment
(
Qt
::
AlignVCenter
);
label1
->
setWordWrap
(
true
);
page_vlay
->
addWidget
(
label1
);
page_vlay
->
addStretch
();
widgetStack
->
setCurrentIndex
(
0
);
// since sourceCombo->currentItem() == 0
// page 1: input field for direct entering
++
pageno
;
page
=
new
QWidget
(
widgetStack
);
widgetStack
->
insertWidget
(
pageno
,
page
);
page_vlay
=
new
QVBoxLayout
(
page
);
page_vlay
->
setContentsMargins
({});
mTextEdit
=
new
KPIMTextEdit
::
PlainTextEditorWidget
(
page
);
mTextEdit
->
editor
()
->
setSpellCheckingSupport
(
false
);
page_vlay
->
addWidget
(
mTextEdit
);
mTextEdit
->
editor
()
->
setWhatsThis
(
i18n
(
"Use this field to enter an arbitrary X-Face string."
));
mTextEdit
->
editor
()
->
setFont
(
QFontDatabase
::
systemFont
(
QFontDatabase
::
FixedFont
));
mTextEdit
->
editor
()
->
setWordWrapMode
(
QTextOption
::
WrapAnywhere
);
mTextEdit
->
editor
()
->
setSearchSupport
(
false
);
auto
label2
=
new
QLabel
(
i18n
(
"Examples are available at <a "
"href=
\"
https://ace.home.xs4all.nl/X-Faces/
\"
>"
"https://ace.home.xs4all.nl/X-Faces/</a>."
),
page
);
label2
->
setOpenExternalLinks
(
true
);
label2
->
setTextInteractionFlags
(
Qt
::
TextBrowserInteraction
);
page_vlay
->
addWidget
(
label2
);
connect
(
mTextEdit
->
editor
(),
&
KPIMTextEdit
::
PlainTextEditor
::
textChanged
,
this
,
&
XFaceConfigurator
::
slotUpdateXFace
);
mUi
->
setupUi
(
this
);
mPngquantProc
->
setInputChannelMode
(
QProcess
::
ManagedInputChannel
);
mPngquantProc
->
setProgram
(
QLatin1String
(
"pngquant"
));
mPngquantProc
->
setArguments
(
QStringList
()
<<
QLatin1String
(
"--strip"
)
<<
QLatin1String
(
"7"
)
<<
QLatin1String
(
"-"
));
mUi
->
faceConfig
->
setTitle
(
i18n
(
"Face"
));
mUi
->
xFaceConfig
->
setTitle
(
i18n
(
"X-Face"
));
mUi
->
faceConfig
->
setInfo
(
i18n
(
"More information under <a href=
\"
https://quimby.gnus.org/circus/face/
\"
>https://quimby.gnus.org/circus/face/</a>."
));
mUi
->
xFaceConfig
->
setInfo
(
i18n
(
"Examples are available at <a href=
\"
https://ace.home.xs4all.nl/X-Faces/
\"
>https://ace.home.xs4all.nl/X-Faces/</a>."
));
connect
(
mUi
->
enableComboBox
,
&
QComboBox
::
currentIndexChanged
,
this
,
&
XFaceConfigurator
::
modeChanged
);
connect
(
mUi
->
faceConfig
,
&
EncodedImagePicker
::
imageSelected
,
this
,
&
XFaceConfigurator
::
compressFace
);
connect
(
mUi
->
xFaceConfig
,
&
EncodedImagePicker
::
imageSelected
,
this
,
&
XFaceConfigurator
::
compressXFace
);
connect
(
mUi
->
faceConfig
,
&
EncodedImagePicker
::
sourceChanged
,
this
,
&
XFaceConfigurator
::
updateFace
);
connect
(
mUi
->
xFaceConfig
,
&
EncodedImagePicker
::
sourceChanged
,
this
,
&
XFaceConfigurator
::
updateXFace
);
connect
(
mPngquantProc
,
&
QProcess
::
finished
,
this
,
&
XFaceConfigurator
::
pngquantFinished
);
// set initial state
modeChanged
(
mUi
->
enableComboBox
->
currentIndex
());
}
XFaceConfigurator
::~
XFaceConfigurator
()
=
default
;
bool
XFaceConfigurator
::
isXFaceEnabled
()
const
{
return
m
E
nableC
heck
->
isChecked
()
;
return
m
Ui
->
e
nableC
omboBox
->
currentIndex
()
&
SendXFace
;
}
void
XFaceConfigurator
::
setXFaceEnabled
(
bool
enable
)
{
mEnableCheck
->
setChecked
(
enable
);
const
int
currentIndex
=
mUi
->
enableComboBox
->
currentIndex
();
if
(
enable
)
{
mUi
->
enableComboBox
->
setCurrentIndex
(
currentIndex
|
SendXFace
);
}
else
{
mUi
->
enableComboBox
->
setCurrentIndex
(
currentIndex
&
~
SendXFace
);
}
}
bool
XFaceConfigurator
::
isFaceEnabled
()
const
{
return
mUi
->
enableComboBox
->
currentIndex
()
&
SendFace
;
}
void
XFaceConfigurator
::
setFaceEnabled
(
bool
enable
)
{
const
int
currentIndex
=
mUi
->
enableComboBox
->
currentIndex
();
if
(
enable
)
{
mUi
->
enableComboBox
->
setCurrentIndex
(
currentIndex
|
SendFace
);
}
else
{
mUi
->
enableComboBox
->
setCurrentIndex
(
currentIndex
&
~
SendFace
);
}
}
QString
XFaceConfigurator
::
xface
()
const
{
return
mTextEdit
->
editor
()
->
toPlainText
();
QString
str
=
mUi
->
xFaceConfig
->
source
().
trimmed
();
str
.
remove
(
QStringLiteral
(
"x-face:"
),
Qt
::
CaseInsensitive
);
str
=
str
.
trimmed
();
return
str
;
}
void
XFaceConfigurator
::
setXFace
(
const
QString
&
text
)
{
m
TextEdit
->
editor
()
->
setPlainText
(
text
);
m
Ui
->
xFaceConfig
->
setSource
(
text
);
}
void
XFaceConfigurator
::
setXfaceFromFile
(
const
QUrl
&
url
)
QString
XFaceConfigurator
::
face
()
const
{
auto
job
=
KIO
::
storedGet
(
url
);
KJobWidgets
::
setWindow
(
job
,
this
);
if
(
job
->
exec
())
{
KXFace
xf
;
mTextEdit
->
editor
()
->
setPlainText
(
xf
.
fromImage
(
QImage
::
fromData
(
job
->
data
())));
}
else
{
KMessageBox
::
error
(
this
,
job
->
errorString
());
}
QString
str
=
mUi
->
faceConfig
->
source
().
trimmed
();
str
.
remove
(
QStringLiteral
(
"face:"
),
Qt
::
CaseInsensitive
);
str
=
str
.
trimmed
();
return
str
;
}
void
XFaceConfigurator
::
s
lotSelectFile
(
)
void
XFaceConfigurator
::
s
etFace
(
const
QString
&
text
)
{
QString
filter
;
const
QList
<
QByteArray
>
supportedImage
=
QImageReader
::
supportedImageFormats
();
for
(
const
QByteArray
&
ba
:
supportedImage
)
{
if
(
!
filter
.
isEmpty
())
{
filter
+=
QLatin1Char
(
' '
);
}
filter
+=
QLatin1String
(
"*."
)
+
QString
::
fromLatin1
(
ba
);
}
mUi
->
faceConfig
->
setSource
(
text
);
}
filter
=
QStringLiteral
(
"%1 (%2)"
).
arg
(
i18n
(
"Image"
),
filter
);
const
QUrl
url
=
QFileDialog
::
getOpenFileUrl
(
this
,
QString
(),
QUrl
(),
filter
);
if
(
!
url
.
isEmpty
())
{
setXfaceFromFile
(
url
);
void
XFaceConfigurator
::
modeChanged
(
int
index
)
{
mUi
->
faceConfig
->
setEnabled
(
index
&
SendFace
);
mUi
->
xFaceConfig
->
setEnabled
(
index
&
SendXFace
);
switch
(
index
)
{
case
DontSend
:
mUi
->
modeInfo
->
setText
(
i18n
(
"No image will be sent."
));
break
;
case
SendFace
:
mUi
->
modeInfo
->
setText
(
i18n
(
"KMail will send a colored image through the Face header."
));
break
;