Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
PIM
KAddressBook
Commits
4ed28b81
Commit
4ed28b81
authored
Sep 02, 2020
by
Konrad Czapla
Committed by
Laurent Montel
Sep 02, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve the contacts list
Improving appearance of the main contact list by adding style delegate.
parent
84d959ce
Pipeline
#32691
passed with stage
in 17 minutes and 34 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
620 additions
and
1 deletion
+620
-1
src/CMakeLists.txt
src/CMakeLists.txt
+2
-0
src/contactinfoproxymodel.cpp
src/contactinfoproxymodel.cpp
+365
-0
src/contactinfoproxymodel.h
src/contactinfoproxymodel.h
+94
-0
src/mainwidget.cpp
src/mainwidget.cpp
+7
-1
src/stylecontactlistdelegate.cpp
src/stylecontactlistdelegate.cpp
+124
-0
src/stylecontactlistdelegate.h
src/stylecontactlistdelegate.h
+28
-0
No files found.
src/CMakeLists.txt
View file @
4ed28b81
...
...
@@ -59,12 +59,14 @@ set(kaddressbook_LIB_SRCS
aboutdata.cpp
categoryfilterproxymodel.cpp
categoryselectwidget.cpp
contactinfoproxymodel.cpp
contactsorter.cpp
contactswitcher.cpp
globalcontactmodel.cpp
mainwidget.cpp
manageshowcollectionproperties.cpp
modelcolumnmanager.cpp
stylecontactlistdelegate.cpp
widgets/quicksearchwidget.cpp
kaddressbookmigrateapplication.cpp
${
kaddressbook_printing_SRCS
}
...
...
src/contactinfoproxymodel.cpp
0 → 100644
View file @
4ed28b81
/*
This file is part of KAddressBook.
SPDX-FileCopyrightText: 2020 Konrad Czapla <kondzio89dev@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "contactinfoproxymodel.h"
#include "kaddressbook_debug.h"
#include <AkonadiCore/EntityTreeModel>
#include <AkonadiCore/Item>
#include <AkonadiCore/ItemFetchJob>
#include <AkonadiCore/ItemFetchScope>
#include <AkonadiCore/Monitor>
#include <KLocalizedString>
#include <kcontacts/addressee.h>
#include <kcontacts/contactgroup.h>
#include <KJob>
#include <QImage>
#include <QJsonObject>
#include <QRegularExpression>
ContactInfoProxyModel
::
ContactInfoProxyModel
(
QObject
*
parent
)
:
QIdentityProxyModel
(
parent
),
mMonitor
(
new
Akonadi
::
Monitor
(
this
))
{
mMonitor
->
setTypeMonitored
(
Akonadi
::
Monitor
::
Items
);
mMonitor
->
itemFetchScope
().
fetchFullPayload
(
true
);
connect
(
mMonitor
,
&
Akonadi
::
Monitor
::
itemChanged
,
this
,
&
ContactInfoProxyModel
::
slotItemChanged
);
connect
(
mMonitor
,
&
Akonadi
::
Monitor
::
itemRemoved
,
this
,
&
ContactInfoProxyModel
::
slotItemRemoved
);
}
QVariant
ContactInfoProxyModel
::
data
(
const
QModelIndex
&
index
,
int
role
)
const
{
if
(
role
>=
Roles
::
PictureRole
&&
role
<=
Roles
::
DescriptionRole
)
{
const
Akonadi
::
Item
item
=
index
.
data
(
Akonadi
::
EntityTreeModel
::
ItemRole
).
value
<
Akonadi
::
Item
>
();
if
(
item
.
isValid
())
{
if
(
item
.
hasPayload
<
KContacts
::
Addressee
>
())
{
const
KContacts
::
Addressee
contact
=
item
.
payload
<
KContacts
::
Addressee
>
();
switch
(
role
)
{
case
Roles
::
PictureRole
:
return
contact
.
photo
().
data
();
case
Roles
::
InitialsRole
:
return
getInitials
(
contact
);
case
Roles
::
DescriptionRole
:
return
getDescription
(
contact
);
}
}
else
if
(
item
.
hasPayload
<
KContacts
::
ContactGroup
>
())
{
const
KContacts
::
ContactGroup
groupContacts
=
item
.
payload
<
KContacts
::
ContactGroup
>
();
if
(
!
mGroupsCache
.
contains
(
index
))
{
mGroupsCache
.
insert
(
index
,
ContactCacheData
::
List
());
}
updateCache
(
index
,
groupContacts
);
if
(
groupFetchDone
(
index
,
groupContacts
))
{
switch
(
role
)
{
case
Roles
::
PictureRole
:
return
QVariant
();
case
Roles
::
InitialsRole
:
return
getInitials
(
index
,
groupContacts
);
case
Roles
::
DescriptionRole
:
return
getDescription
(
index
,
groupContacts
);
}
}
else
if
(
role
==
Roles
::
DescriptionRole
)
{
return
i18n
(
"Loading contacts details ..."
);
}
if
(
!
mPendingGroups
.
contains
(
groupContacts
.
id
()))
{
QMap
<
const
char
*
,
QVariant
>
properties
{
{
"groupPersistentModelIndex"
,
QVariant
::
fromValue
(
index
)},
{
"groupId"
,
QVariant
::
fromValue
(
groupContacts
.
id
())},
};
Akonadi
::
Item
::
List
groupItemsList
;
QList
<
QJsonObject
>
groupRefIdsList
;
for
(
int
idx
=
0
;
idx
<
groupContacts
.
contactReferenceCount
();
++
idx
)
{
const
KContacts
::
ContactGroup
::
ContactReference
contactRef
=
groupContacts
.
contactReference
(
idx
);
if
(
findCacheItem
(
index
,
contactRef
)
==
mGroupsCache
[
index
].
cend
())
{
Akonadi
::
Item
newItem
;
if
(
contactRef
.
gid
().
isEmpty
())
{
newItem
.
setId
(
contactRef
.
uid
().
toLongLong
());
}
else
{
newItem
.
setGid
(
contactRef
.
gid
());
}
if
(
!
mPendingGroups
.
contains
(
groupContacts
.
id
()))
{
mPendingGroups
<<
groupContacts
.
id
();
}
groupItemsList
<<
newItem
;
const
QJsonObject
refId
{
{
QStringLiteral
(
"uid"
),
contactRef
.
uid
()},
{
QStringLiteral
(
"gid"
),
contactRef
.
gid
()}
};
if
(
!
groupRefIdsList
.
contains
(
refId
))
{
groupRefIdsList
<<
refId
;
}
}
}
if
(
groupItemsList
.
size
()
&&
groupRefIdsList
.
size
())
{
properties
.
insert
(
"groupRefIdsList"
,
QVariant
::
fromValue
(
groupRefIdsList
));
fetchItems
(
groupItemsList
,
properties
);
}
}
return
QVariant
();
}
}
}
return
QIdentityProxyModel
::
data
(
index
,
role
);
}
QString
ContactInfoProxyModel
::
getInitials
(
const
KContacts
::
Addressee
&
contact
)
const
{
QString
initials
;
QString
names
=
contact
.
realName
();
names
.
remove
(
contact
.
prefix
());
names
.
remove
(
contact
.
suffix
());
names
.
remove
(
contact
.
additionalName
());
const
QStringList
contactListNames
=
names
.
split
(
QRegularExpression
(
QStringLiteral
(
"
\\
s+"
)));
for
(
const
QString
&
name
:
contactListNames
)
{
if
(
!
name
.
isEmpty
())
{
initials
.
append
(
name
.
front
());
}
}
return
initials
.
toUpper
();
}
QString
ContactInfoProxyModel
::
getInitials
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
{
QString
initials
;
for
(
int
idx
=
0
;
idx
<
groupContacts
.
dataCount
();
idx
++
)
{
if
(
!
groupContacts
.
data
(
idx
).
name
().
isEmpty
())
{
initials
.
append
(
groupContacts
.
data
(
idx
).
name
().
front
());
}
}
for
(
const
ContactCacheData
&
cacheContact
:
mGroupsCache
[
index
])
{
if
(
!
cacheContact
.
name
.
isEmpty
())
{
initials
.
append
(
cacheContact
.
name
.
front
());
}
}
return
initials
.
toUpper
();
}
QString
ContactInfoProxyModel
::
getDescription
(
const
KContacts
::
Addressee
&
contact
)
const
{
QString
dataSeparator
;
QString
emailAddress
;
QString
phone
;
if
(
!
contact
.
preferredEmail
().
isEmpty
())
{
emailAddress
=
i18n
(
"Email: %1"
,
contact
.
preferredEmail
());
}
const
QList
<
KContacts
::
PhoneNumber
>
phoneList
=
contact
.
phoneNumbers
().
toList
();
QList
<
KContacts
::
PhoneNumber
>::
const_reverse_iterator
itPhone
=
std
::
find_if
(
phoneList
.
rbegin
(),
phoneList
.
rend
(),
[
&
phoneList
](
const
KContacts
::
PhoneNumber
&
phone
)
{
return
phone
.
isPreferred
()
||
phoneList
.
at
(
0
)
==
phone
;
});
if
(
itPhone
!=
phoneList
.
rend
())
{
phone
=
i18n
(
"Phone: %1"
,
(
*
itPhone
).
number
());
}
if
(
!
emailAddress
.
isEmpty
()
&&
!
phone
.
isEmpty
())
{
dataSeparator
=
QStringLiteral
(
","
);
}
return
i18n
(
"%1%2 %3"
,
emailAddress
,
dataSeparator
,
phone
).
trimmed
();
}
QString
ContactInfoProxyModel
::
getDescription
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
{
QStringList
groupDescription
;
QString
contactDescription
;
for
(
int
idx
=
0
;
idx
<
groupContacts
.
dataCount
();
idx
++
)
{
QString
dataSeparator
;
if
(
!
groupContacts
.
data
(
idx
).
name
().
isEmpty
()
&&
!
groupContacts
.
data
(
idx
).
email
().
isEmpty
())
{
dataSeparator
=
QStringLiteral
(
"-"
);
}
contactDescription
=
i18n
(
"%1 %2 %3"
,
groupContacts
.
data
(
idx
).
name
(),
dataSeparator
,
groupContacts
.
data
(
idx
).
email
());
groupDescription
<<
contactDescription
.
trimmed
();
contactDescription
.
clear
();
}
for
(
int
idx
=
0
;
idx
<
groupContacts
.
contactReferenceCount
();
++
idx
)
{
const
KContacts
::
ContactGroup
::
ContactReference
contactRef
=
groupContacts
.
contactReference
(
idx
);
ContactCacheData
::
ConstListIterator
it
=
findCacheItem
(
index
,
contactRef
);
if
(
it
!=
mGroupsCache
[
index
].
end
())
{
QString
cacheSeparator
,
email
;
email
=
contactRef
.
preferredEmail
().
isEmpty
()
?
it
->
email
:
contactRef
.
preferredEmail
();
if
(
it
->
name
.
isEmpty
()
&&
email
.
isEmpty
())
{
continue
;
}
else
if
(
!
it
->
name
.
isEmpty
()
&&
!
email
.
isEmpty
())
{
cacheSeparator
=
QStringLiteral
(
"-"
);
}
contactDescription
=
i18n
(
"%1 %2 %3"
,
it
->
name
,
cacheSeparator
,
email
);
groupDescription
<<
contactDescription
.
trimmed
();
contactDescription
.
clear
();
}
}
return
groupDescription
.
join
(
QStringLiteral
(
", "
));
}
void
ContactInfoProxyModel
::
updateCache
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
{
mGroupsCache
[
index
].
erase
(
std
::
remove_if
(
mGroupsCache
[
index
].
begin
(),
mGroupsCache
[
index
].
end
(),
[
&
groupContacts
](
const
ContactCacheData
&
cacheContact
)
->
bool
{
for
(
int
idx
=
0
;
idx
<
groupContacts
.
contactReferenceCount
();
++
idx
)
{
const
KContacts
::
ContactGroup
::
ContactReference
&
reference
=
groupContacts
.
contactReference
(
idx
);
if
(
cacheContact
==
reference
)
{
return
false
;
}
}
return
true
;
}),
mGroupsCache
[
index
].
end
());
}
bool
ContactInfoProxyModel
::
groupFetchDone
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
{
QStringList
contactRefIds
;
QStringList
contactCacheIds
;
auto
sortFunc
=
[](
const
QString
&
lhs
,
const
QString
&
rhs
)
->
bool
{
return
lhs
.
toLongLong
()
<
rhs
.
toLongLong
();
};
for
(
int
idx
=
0
;
idx
<
groupContacts
.
contactReferenceCount
();
++
idx
)
{
const
KContacts
::
ContactGroup
::
ContactReference
&
reference
=
groupContacts
.
contactReference
(
idx
);
contactRefIds
+=
reference
.
gid
().
isEmpty
()
?
reference
.
uid
()
:
reference
.
gid
();
}
std
::
sort
(
contactRefIds
.
begin
(),
contactRefIds
.
end
(),
sortFunc
);
contactRefIds
.
erase
(
std
::
unique
(
contactRefIds
.
begin
(),
contactRefIds
.
end
()),
contactRefIds
.
end
());
for
(
const
auto
&
cacheContact
:
mGroupsCache
[
index
])
{
contactCacheIds
+=
cacheContact
.
gid
.
isEmpty
()
?
cacheContact
.
uid
:
cacheContact
.
gid
;
}
std
::
sort
(
contactCacheIds
.
begin
(),
contactCacheIds
.
end
(),
sortFunc
);
return
std
::
equal
(
contactRefIds
.
begin
(),
contactRefIds
.
end
(),
contactCacheIds
.
begin
(),
contactCacheIds
.
end
());
}
ContactInfoProxyModel
::
ContactCacheData
::
ListIterator
ContactInfoProxyModel
::
findCacheItem
(
const
QModelIndex
&
index
,
const
ContactInfoProxyModel
::
ContactCacheData
&
cacheContact
)
{
ContactCacheData
::
ListIterator
it
=
std
::
find_if
(
mGroupsCache
[
index
].
begin
(),
mGroupsCache
[
index
].
end
(),
[
&
cacheContact
](
const
ContactCacheData
&
contact
)
->
bool
{
return
contact
==
cacheContact
;
});
return
it
;
}
ContactInfoProxyModel
::
ContactCacheData
::
ConstListIterator
ContactInfoProxyModel
::
findCacheItem
(
const
QModelIndex
&
index
,
const
ContactInfoProxyModel
::
ContactCacheData
&
cacheContact
)
const
{
ContactCacheData
::
ConstListIterator
it
=
std
::
find_if
(
mGroupsCache
[
index
].
cbegin
(),
mGroupsCache
[
index
].
cend
(),
[
&
cacheContact
](
const
ContactCacheData
&
contact
)
->
bool
{
return
contact
==
cacheContact
;
});
return
it
;
}
void
ContactInfoProxyModel
::
fetchItems
(
const
Akonadi
::
Item
::
List
&
items
,
const
QMap
<
const
char
*
,
QVariant
>
&
properties
)
const
{
Akonadi
::
ItemFetchJob
*
job
=
new
Akonadi
::
ItemFetchJob
(
items
);
job
->
fetchScope
().
fetchFullPayload
();
job
->
fetchScope
().
setIgnoreRetrievalErrors
(
true
);
for
(
const
auto
&
property
:
properties
.
toStdMap
())
{
job
->
setProperty
(
property
.
first
,
property
.
second
);
}
connect
(
job
,
&
Akonadi
::
ItemFetchJob
::
result
,
this
,
&
ContactInfoProxyModel
::
slotFetchJobFinished
);
}
void
ContactInfoProxyModel
::
slotFetchJobFinished
(
KJob
*
job
)
{
if
(
job
->
error
())
{
qCWarning
(
KADDRESSBOOK_LOG
)
<<
" error during fetching items"
<<
job
->
errorString
();
return
;
}
Akonadi
::
ItemFetchJob
*
fetchJob
=
qobject_cast
<
Akonadi
::
ItemFetchJob
*>
(
job
);
const
QPersistentModelIndex
index
=
job
->
property
(
"groupPersistentModelIndex"
).
value
<
QPersistentModelIndex
>
();
const
QString
groupId
=
job
->
property
(
"groupId"
).
value
<
QString
>
();
const
QList
<
QJsonObject
>
groupRefIdsList
=
job
->
property
(
"groupRefIdsList"
).
value
<
QList
<
QJsonObject
>>
();
for
(
const
QJsonObject
&
refId
:
groupRefIdsList
)
{
ContactCacheData
cacheContact
;
cacheContact
.
gid
=
refId
[
QStringLiteral
(
"gid"
)].
toString
();
cacheContact
.
uid
=
refId
[
QStringLiteral
(
"uid"
)].
toString
();
for
(
const
Akonadi
::
Item
&
item
:
fetchJob
->
items
())
{
if
(
item
.
isValid
())
{
if
((
!
item
.
gid
().
isEmpty
()
&&
refId
[
QStringLiteral
(
"gid"
)].
toString
()
==
item
.
gid
())
||
QString
::
number
(
item
.
id
())
==
refId
[
QStringLiteral
(
"uid"
)].
toString
())
{
if
(
item
.
hasPayload
<
KContacts
::
Addressee
>
())
{
mMonitor
->
setItemMonitored
(
item
);
const
KContacts
::
Addressee
contact
=
item
.
payload
<
KContacts
::
Addressee
>
();
cacheContact
.
name
=
contact
.
realName
();
cacheContact
.
email
=
contact
.
preferredEmail
();
}
}
}
}
if
(
mGroupsCache
.
contains
(
index
))
{
mGroupsCache
[
index
].
append
(
cacheContact
);
}
}
Q_EMIT
dataChanged
(
index
,
index
,
mKrole
);
if
(
mPendingGroups
.
contains
(
groupId
))
{
mPendingGroups
.
removeOne
(
groupId
);
}
}
void
ContactInfoProxyModel
::
slotItemChanged
(
const
Akonadi
::
Item
&
item
,
const
QSet
<
QByteArray
>
&
partIdentifiers
)
{
Q_UNUSED
(
partIdentifiers
)
for
(
const
QPersistentModelIndex
&
index
:
mGroupsCache
.
keys
())
{
ContactCacheData
::
ListIterator
it
=
findCacheItem
(
index
,
item
);
if
(
it
!=
mGroupsCache
[
index
].
end
())
{
if
(
item
.
isValid
())
{
if
(
item
.
hasPayload
<
KContacts
::
Addressee
>
())
{
const
KContacts
::
Addressee
contact
=
item
.
payload
<
KContacts
::
Addressee
>
();
it
->
uid
=
QString
::
number
(
item
.
id
());
it
->
gid
=
item
.
gid
();
it
->
name
=
contact
.
realName
();
it
->
email
=
contact
.
preferredEmail
();
Q_EMIT
dataChanged
(
index
,
index
,
mKrole
);
}
}
}
}
}
void
ContactInfoProxyModel
::
slotItemRemoved
(
const
Akonadi
::
Item
&
item
)
{
if
(
item
.
isValid
())
{
for
(
const
QPersistentModelIndex
&
index
:
mGroupsCache
.
keys
())
{
ContactCacheData
::
List
::
iterator
it
=
findCacheItem
(
index
,
item
);
if
(
it
!=
mGroupsCache
[
index
].
end
())
{
mGroupsCache
[
index
].
erase
(
it
);
Q_EMIT
dataChanged
(
index
,
index
,
mKrole
);
}
}
}
}
bool
operator
==
(
const
ContactInfoProxyModel
::
ContactCacheData
&
lhs
,
const
ContactInfoProxyModel
::
ContactCacheData
&
rhs
)
{
return
!
lhs
.
gid
.
isEmpty
()
?
lhs
.
gid
==
rhs
.
gid
:
!
lhs
.
uid
.
isEmpty
()
?
lhs
.
uid
==
rhs
.
uid
:
false
;
}
src/contactinfoproxymodel.h
0 → 100644
View file @
4ed28b81
/*
This file is part of KAddressBook.
SPDX-FileCopyrightText: 2020 Konrad Czapla <kondzio89dev@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef CONTACTINFOPROXYMODEL_H
#define CONTACTINFOPROXYMODEL_H
#include <AkonadiCore/EntityTreeModel>
#include <kcontacts/contactgroup.h>
#include <QObject>
#include <QIdentityProxyModel>
#include <QPersistentModelIndex>
namespace
Akonadi
{
class
Item
;
class
Monitor
;
}
namespace
KContacts
{
class
Addressee
;
class
ContactGroup
;
}
class
ContactInfoProxyModel
:
public
QIdentityProxyModel
{
Q_OBJECT
public:
enum
Roles
{
PictureRole
=
Akonadi
::
EntityTreeModel
::
UserRole
,
InitialsRole
,
DescriptionRole
,
};
explicit
ContactInfoProxyModel
(
QObject
*
parent
=
nullptr
);
QVariant
data
(
const
QModelIndex
&
index
,
int
role
)
const
override
;
private:
class
ContactCacheData
{
public:
ContactCacheData
()
=
default
;
~
ContactCacheData
()
=
default
;
ContactCacheData
(
const
ContactCacheData
&
)
=
default
;
ContactCacheData
(
const
KContacts
::
ContactGroup
::
ContactReference
&
other
)
:
uid
(
other
.
uid
()),
gid
(
other
.
gid
())
{
}
ContactCacheData
(
const
Akonadi
::
Item
&
other
)
{
uid
=
QString
::
number
(
other
.
id
());
gid
=
other
.
gid
();
}
friend
bool
operator
==
(
const
ContactCacheData
&
lhs
,
const
ContactCacheData
&
rhs
);
using
List
=
QVector
<
ContactCacheData
>
;
using
ListIterator
=
ContactCacheData
::
List
::
iterator
;
using
ConstListIterator
=
ContactCacheData
::
List
::
ConstIterator
;
QString
uid
;
QString
gid
;
QString
name
;
QString
email
;
};
Q_REQUIRED_RESULT
QString
getInitials
(
const
KContacts
::
Addressee
&
contact
)
const
;
Q_REQUIRED_RESULT
QString
getInitials
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
;
Q_REQUIRED_RESULT
QString
getDescription
(
const
KContacts
::
Addressee
&
contact
)
const
;
Q_REQUIRED_RESULT
QString
getDescription
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
;
void
updateCache
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
;
Q_REQUIRED_RESULT
bool
groupFetchDone
(
const
QModelIndex
&
index
,
const
KContacts
::
ContactGroup
&
groupContacts
)
const
;
Q_REQUIRED_RESULT
ContactCacheData
::
ListIterator
findCacheItem
(
const
QModelIndex
&
index
,
const
ContactCacheData
&
cacheContact
);
Q_REQUIRED_RESULT
ContactCacheData
::
ConstListIterator
findCacheItem
(
const
QModelIndex
&
index
,
const
ContactCacheData
&
cacheContact
)
const
;
void
fetchItems
(
const
Akonadi
::
Item
::
List
&
items
,
const
QMap
<
const
char
*
,
QVariant
>
&
properties
)
const
;
void
slotFetchJobFinished
(
KJob
*
job
);
void
slotItemChanged
(
const
Akonadi
::
Item
&
item
,
const
QSet
<
QByteArray
>
&
partIdentifiers
);
void
slotItemRemoved
(
const
Akonadi
::
Item
&
item
);
friend
bool
operator
==
(
const
ContactCacheData
&
lhs
,
const
ContactCacheData
&
rhs
);
using
Cache
=
QMap
<
QPersistentModelIndex
,
ContactCacheData
::
List
>
;
mutable
Cache
mGroupsCache
;
mutable
QStringList
mPendingGroups
;
const
QVector
<
int
>
mKrole
{
PictureRole
,
InitialsRole
,
DescriptionRole
};
Akonadi
::
Monitor
*
mMonitor
=
nullptr
;
};
#endif // CONTACTINFOPROXYMODEL_H
src/mainwidget.cpp
View file @
4ed28b81
...
...
@@ -8,6 +8,8 @@
#include "mainwidget.h"
#include "stylecontactlistdelegate.h"
#include "contactinfoproxymodel.h"
#include "contactswitcher.h"
#include "globalcontactmodel.h"
#include "modelcolumnmanager.h"
...
...
@@ -243,6 +245,9 @@ MainWidget::MainWidget(KXMLGUIClient *guiClient, QWidget *parent)
mContactsFilterModel
=
new
Akonadi
::
ContactsFilterProxyModel
(
this
);
mContactsFilterModel
->
setSourceModel
(
mCategoryFilterModel
);
ContactInfoProxyModel
*
contactInfoProxyModel
=
new
ContactInfoProxyModel
(
this
);
contactInfoProxyModel
->
setSourceModel
(
mContactsFilterModel
);
connect
(
mQuickSearchWidget
,
&
QuickSearchWidget
::
filterStringChanged
,
mContactsFilterModel
,
&
Akonadi
::
ContactsFilterProxyModel
::
setFilterString
);
...
...
@@ -250,7 +255,8 @@ MainWidget::MainWidget(KXMLGUIClient *guiClient, QWidget *parent)
this
,
&
MainWidget
::
selectFirstItem
);
connect
(
mQuickSearchWidget
,
&
QuickSearchWidget
::
arrowDownKeyPressed
,
this
,
&
MainWidget
::
setFocusToTreeView
);
mItemView
->
setModel
(
mContactsFilterModel
);
mItemView
->
setModel
(
contactInfoProxyModel
);
mItemView
->
setItemDelegate
(
new
StyleContactListDelegate
(
this
));
mItemView
->
setXmlGuiClient
(
guiClient
);
mItemView
->
setSelectionMode
(
QAbstractItemView
::
ExtendedSelection
);
mItemView
->
setRootIsDecorated
(
false
);
...
...
src/stylecontactlistdelegate.cpp
0 → 100644
View file @
4ed28b81
/*
This file is part of KAddressBook.
SPDX-FileCopyrightText: 2020 Konrad Czapla <kondzio89dev@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "stylecontactlistdelegate.h"
#include "contactinfoproxymodel.h"
#include <Akonadi/Contact/ContactsTreeModel>
#include <KLocalizedString>
#include <QApplication>
#include <QPainter>
#include <QPainterPath>
#include <QImage>
StyleContactListDelegate
::
StyleContactListDelegate
(
QObject
*
parent
)
:
QStyledItemDelegate
(
parent
),
mKImageSize
(
50
,
50
)
{
}
void
StyleContactListDelegate
::
paint
(
QPainter
*
painter
,
const
QStyleOptionViewItem
&
option
,
const
QModelIndex
&
index
)
const
{
Q_ASSERT
(
index
.
isValid
());
if
(
Akonadi
::
ContactsTreeModel
::
Column
::
FullName
==
index
.
column
())
{
QApplication
::
style
()
->
drawPrimitive
(
QStyle
::
PE_PanelItemViewItem
,
&
option
,
painter
);
const
QRectF
optionRect
=
option
.
rect
.
marginsRemoved
(
QMargins
()
+
static_cast
<
int
>
(
mKMargin
));
QRectF
pictureRect
=
QRectF
(
optionRect
.
topLeft
(),
mKImageSize
);
if
(
mKImageSize
.
width
()
>
optionRect
.
size
().
width
())
{
const
qreal
width
=
option
.
rect
.
size
().
width
();
const
qreal
height
=
option
.
rect
.
size
().
height
();
const
QMargins
fitMargins
(
0
,
(
qMax
(
width
,
height
)
-
qMin
(
width
,
height
))
/
qreal
(
2
),
0
,
(
qMax
(
width
,
height
)
-
qMin
(
width
,
height
))
/
qreal
(
2
));
pictureRect
=
optionRect
.
marginsRemoved
(
fitMargins
);
}
QRectF
nameTextRect
(
optionRect
.
topLeft
(),
QSize
(
optionRect
.
width
(),
optionRect
.
height
()
/
qreal
(
2
)));
QRectF
descriptionTextRect
=
nameTextRect
;
descriptionTextRect
.
moveBottomLeft
(
optionRect
.
bottomLeft
());
QMargins
textMargin
;
switch
(
static_cast
<
int
>
(
option
.
widget
->
layoutDirection
()))
{
case
Qt
::
LayoutDirection
::
LeftToRight
:
{
textMargin
.
setLeft
(
mKMargin
);
nameTextRect
.
setLeft
(
pictureRect
.
bottomRight
().
x
());
nameTextRect
=
nameTextRect
.
marginsRemoved
(
textMargin
);
descriptionTextRect
.
setLeft
(
pictureRect
.
bottomRight
().
x
());
descriptionTextRect
=
descriptionTextRect
.
marginsRemoved
(
textMargin
);
}
break
;
case
Qt
::
LayoutDirection
::
RightToLeft
:
{
pictureRect
.
moveRight
(
optionRect
.
bottomRight
().
x
());
textMargin
.
setRight
(
mKMargin
);
nameTextRect
.
setRight
(
pictureRect
.
bottomLeft
().
x
());
nameTextRect
=
nameTextRect
.
marginsRemoved
(
textMargin
);
descriptionTextRect
.
setRight
(
pictureRect
.
bottomLeft
().
x
());
descriptionTextRect
=
descriptionTextRect
.
marginsRemoved
(
textMargin
);
}
break
;
}
QPainterPath
path
;
path
.
addEllipse
(
pictureRect
);
painter
->
save
();
painter
->
setClipPath
(
path
);
painter
->
setPen
(
QPen
(
Qt
::
darkGray
,
qreal
(
4
)));
painter
->
setRenderHint
(
QPainter
::
Antialiasing
);
painter
->
drawPath
(
path
);
painter
->
setFont
(
QFont
(
option
.
font
.
family
(),
12
,
QFont
::
Bold
,
true
));
if
(
index
.
data
(
ContactInfoProxyModel
::
Roles
::
PictureRole
).
value
<
QImage
>
().
isNull
())
{
const
QString
initials
=
index
.
data
(
ContactInfoProxyModel
::
Roles
::
InitialsRole
).
value
<
QString
>
();
painter
->
drawText
(
pictureRect
,
Qt
::
AlignCenter
,
painter
->
fontMetrics
().
elidedText
(
initials
,
Qt
::
ElideRight
,
pictureRect
.
width
()
-
qreal
(
10
)));