33 #include <config-kleopatra.h>
38 #ifdef KLEO_MODEL_TEST
44 #include <kleo/keyfiltermanager.h>
45 #include <kleo/keyfilter.h>
53 #include <QApplication>
56 #include <gpgme++/key.h>
60 #define BOOST_ALL_NO_LIB
63 #ifndef Q_MOC_RUN // QTBUG-22829
64 #include <boost/bind.hpp>
65 #include <boost/graph/topological_sort.hpp>
66 #include <boost/graph/adjacency_list.hpp>
77 #include <ext/algorithm>
80 using namespace GpgME;
129 static uint
hash(
const uchar *p)
136 if ((g = (h & 0xf0000000)) != 0)
147 static inline uint
qHash(
const char * data ) {
153 class AbstractKeyListModel::Private {
155 Private() : m_toolTipOptions( Formatting::
Validity ) {}
156 int m_toolTipOptions;
157 mutable QHash<const char*,QVariant> prettyEMailCache;
159 AbstractKeyListModel::AbstractKeyListModel( QObject * p )
169 d->m_toolTipOptions = opts;
174 return d->m_toolTipOptions;
179 return doMapToKey( idx );
185 std::vector<Key> result;
186 result.reserve( indexes.size() );
187 std::transform( indexes.begin(), indexes.end(),
188 std::back_inserter( result ),
190 result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
195 if ( key.isNull() || col < 0 || col >=
NumColumns )
196 return QModelIndex();
198 return doMapFromKey( key, col );
203 std::transform( keys.begin(), keys.end(),
204 std::back_inserter( result ),
217 const std::vector<Key> vec( 1, key );
219 return l.empty() ? QModelIndex() : l.front() ;
226 d->prettyEMailCache.remove( key.primaryFingerprint() );
230 std::vector<Key> sorted;
231 sorted.reserve( keys.size() );
232 std::remove_copy_if( keys.begin(), keys.end(),
233 std::back_inserter( sorted ),
234 boost::bind( &Key::isNull, _1 ) );
235 std::sort( sorted.begin(), sorted.end(), _detail::ByFingerprint<std::less>() );
236 return doAddKeys( sorted );
241 d->prettyEMailCache.clear();
250 if ( o == Qt::Horizontal )
251 if ( role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole )
254 #ifndef KDEPIM_MOBILE_UI
256 case ValidFrom:
return i18n(
"Valid From" );
257 case ValidUntil:
return i18n(
"Valid Until" );
281 const Key key = this->
key( index );
285 const int column = index.column();
287 if ( role == Qt::DisplayRole || role == Qt::EditRole )
290 #ifdef KDEPIM_MOBILE_UI
295 if (
const char *
const fpr = key.primaryFingerprint() ) {
296 const QHash<const char*,QVariant>::const_iterator it = d->prettyEMailCache.constFind( fpr );
297 if ( it != d->prettyEMailCache.constEnd() )
305 if ( role == Qt::EditRole )
310 if ( role == Qt::EditRole )
317 return QString::fromLatin1( key.shortKeyID() );
318 #endif // KDEPIM_MOBILE_UI
322 #ifndef KDEPIM_MOBILE_UI
323 else if ( role == Qt::ToolTipRole )
325 else if ( role == Qt::FontRole )
326 return KeyFilterManager::instance()->font( key, ( column ==
ShortKeyID ) ? QFont( QLatin1String(
"courier") ) : QFont() );
328 else if ( role == Qt::DecorationRole )
329 return column ==
Icon ?
returnIfValid( KeyFilterManager::instance()->icon( key ) ) : QVariant() ;
330 else if ( role == Qt::BackgroundRole )
331 return returnIfValid( KeyFilterManager::instance()->bgColor( key ) );
332 else if ( role == Qt::ForegroundRole )
333 return returnIfValid( KeyFilterManager::instance()->fgColor( key ) );
335 return QString::fromLatin1( key.primaryFingerprint() );
341 template <
typename Base>
342 class TableModelMixin :
public Base {
344 explicit TableModelMixin( QObject * p=0 ) : Base( p ) {}
345 ~TableModelMixin() {}
348 QModelIndex index(
int row,
int column,
const QModelIndex & pidx=QModelIndex() )
const {
349 return this->hasIndex( row, column, pidx ) ? this->createIndex( row, column, 0 ) : QModelIndex() ;
353 QModelIndex parent(
const QModelIndex & )
const {
return QModelIndex(); }
354 bool hasChildren(
const QModelIndex & pidx )
const {
355 return ( pidx.model() ==
this || !pidx.isValid() ) && this->rowCount( pidx ) > 0 && this->columnCount( pidx ) > 0 ;
359 class FlatKeyListModel
361 :
public TableModelMixin<AbstractKeyListModel>
368 explicit FlatKeyListModel( QObject * parent=0 );
371 int rowCount(
const QModelIndex & pidx )
const {
return pidx.isValid() ? 0 : mKeysByFingerprint.size() ; }
374 Key doMapToKey(
const QModelIndex & index )
const;
375 QModelIndex doMapFromKey(
const Key & key,
int col )
const;
377 void doRemoveKey(
const Key & key );
379 mKeysByFingerprint.clear();
383 std::vector<Key> mKeysByFingerprint;
389 explicit HierarchicalKeyListModel( QObject * parent=0 );
390 ~HierarchicalKeyListModel();
392 int rowCount(
const QModelIndex & pidx )
const;
394 QModelIndex index(
int row,
int col,
const QModelIndex & pidx )
const;
395 QModelIndex parent(
const QModelIndex & idx )
const;
397 bool hasChildren(
const QModelIndex & pidx )
const {
return rowCount( pidx ) > 0 ; }
400 Key doMapToKey(
const QModelIndex & index )
const;
401 QModelIndex doMapFromKey(
const Key & key,
int col )
const;
403 void doRemoveKey(
const Key & key );
406 mKeysByFingerprint.clear();
407 mKeysByExistingParent.clear();
408 mKeysByNonExistingParent.clear();
412 void addTopLevelKey(
const Key & key );
413 void addKeyWithParent(
const char * issuer_fpr,
const Key & key );
414 void addKeyWithoutParent(
const char * issuer_fpr,
const Key & key );
417 typedef std::map< std::string, std::vector<Key> > Map;
418 std::vector<Key> mKeysByFingerprint;
419 Map mKeysByExistingParent, mKeysByNonExistingParent;
420 std::vector<Key> mTopLevels;
423 static const char * cleanChainID(
const Key & key ) {
426 if (
const char * chid = key.chainID() )
434 FlatKeyListModel::FlatKeyListModel( QObject * p )
441 FlatKeyListModel::~FlatKeyListModel() {}
443 Key FlatKeyListModel::doMapToKey(
const QModelIndex & idx )
const {
444 assert( idx.isValid() );
445 if ( static_cast<unsigned>( idx.row() ) < mKeysByFingerprint.size() && idx.column() < NumColumns )
446 return mKeysByFingerprint[ idx.row() ];
451 QModelIndex FlatKeyListModel::doMapFromKey(
const Key & key,
int col )
const {
452 assert( !key.isNull() );
453 const std::vector<Key>::const_iterator it
454 = std::lower_bound( mKeysByFingerprint.begin(), mKeysByFingerprint.end(),
455 key, _detail::ByFingerprint<std::less>() );
456 if ( it == mKeysByFingerprint.end() || !_detail::ByFingerprint<std::equal_to>()( *it, key ) )
457 return QModelIndex();
459 return createIndex( it - mKeysByFingerprint.begin(), col );
464 assert( __gnu_cxx::is_sorted( keys.begin(), keys.end(), _detail::ByFingerprint<std::less>() ) );
469 for ( std::vector<Key>::const_iterator it = keys.begin(), end = keys.end() ; it != end ; ++it ) {
472 const std::vector<Key>::iterator pos = std::upper_bound( mKeysByFingerprint.begin(), mKeysByFingerprint.end(), *it, _detail::ByFingerprint<std::less>() );
473 const unsigned int idx = std::distance( mKeysByFingerprint.begin(), pos );
475 if ( idx > 0 && qstrcmp( mKeysByFingerprint[idx-1].primaryFingerprint(), it->primaryFingerprint() ) == 0 ) {
477 mKeysByFingerprint[idx-1] = *it;
478 emit dataChanged( createIndex( idx-1, 0 ), createIndex( idx-1, NumColumns-1 ) );
481 beginInsertRows( QModelIndex(), idx, idx );
482 mKeysByFingerprint.insert( pos, *it );
487 return indexes( keys );
491 void FlatKeyListModel::doRemoveKey(
const Key & key ) {
492 const std::vector<Key>::iterator it
493 = qBinaryFind( mKeysByFingerprint.begin(), mKeysByFingerprint.end(),
494 key, _detail::ByFingerprint<std::less>() );
495 if ( it == mKeysByFingerprint.end() )
498 const unsigned int row = std::distance( mKeysByFingerprint.begin(), it );
499 beginRemoveRows( QModelIndex(), row, row );
500 mKeysByFingerprint.erase( it );
511 HierarchicalKeyListModel::HierarchicalKeyListModel( QObject * p )
513 mKeysByFingerprint(),
514 mKeysByExistingParent(),
515 mKeysByNonExistingParent(),
521 HierarchicalKeyListModel::~HierarchicalKeyListModel() {}
523 int HierarchicalKeyListModel::rowCount(
const QModelIndex & pidx )
const {
526 if ( !pidx.isValid() )
527 return mTopLevels.size();
529 if ( pidx.column() != 0 )
533 const Key issuer = this->key( pidx );
534 const char *
const fpr = issuer.primaryFingerprint();
537 const Map::const_iterator it = mKeysByExistingParent.find( fpr );
538 if ( it == mKeysByExistingParent.end() )
540 return it->second.size();
543 QModelIndex HierarchicalKeyListModel::index(
int row,
int col,
const QModelIndex & pidx )
const {
545 if ( row < 0 || col < 0 || col >= NumColumns )
546 return QModelIndex();
549 if ( !pidx.isValid() ) {
550 if ( static_cast<unsigned>( row ) < mTopLevels.size() )
551 return index( mTopLevels[row], col );
553 return QModelIndex();
557 const Key issuer = this->key( pidx );
558 const char *
const fpr = issuer.primaryFingerprint();
560 return QModelIndex();
561 const Map::const_iterator it = mKeysByExistingParent.find( fpr );
562 if ( it == mKeysByExistingParent.end() ||
static_cast<unsigned>( row ) >= it->second.size() )
563 return QModelIndex();
564 return index( it->second[row], col );
567 QModelIndex HierarchicalKeyListModel::parent(
const QModelIndex & idx )
const {
568 const Key key = this->key( idx );
569 if ( key.isNull() || key.isRoot() )
570 return QModelIndex();
571 const std::vector<Key>::const_iterator it
572 = qBinaryFind( mKeysByFingerprint.begin(), mKeysByFingerprint.end(),
573 cleanChainID( key ), _detail::ByFingerprint<std::less>() );
574 return it != mKeysByFingerprint.end() ? index( *it ) : QModelIndex();
577 Key HierarchicalKeyListModel::doMapToKey(
const QModelIndex & idx )
const {
579 if ( !idx.isValid() )
582 const char *
const issuer_fpr =
static_cast<const char*
>( idx.internalPointer() );
583 if ( !issuer_fpr || !*issuer_fpr ) {
585 if ( static_cast<unsigned>( idx.row() ) >= mTopLevels.size() )
588 return mTopLevels[idx.row()];
592 const Map::const_iterator it
593 = mKeysByExistingParent.find( issuer_fpr );
594 if ( it == mKeysByExistingParent.end() ||
static_cast<unsigned>( idx.row() ) >= it->second.size() )
596 return it->second[idx.row()];
599 QModelIndex HierarchicalKeyListModel::doMapFromKey(
const Key & key,
int col )
const {
602 return QModelIndex();
604 const char * issuer_fpr = cleanChainID( key );
607 const std::vector<Key> * v = &mTopLevels;
608 if ( issuer_fpr && *issuer_fpr ) {
609 const std::map< std::string, std::vector<Key> >::const_iterator it
610 = mKeysByExistingParent.find( issuer_fpr );
612 if ( it != mKeysByExistingParent.end() )
618 const std::vector<Key>::const_iterator it
619 = std::lower_bound( v->begin(), v->end(), key, _detail::ByFingerprint<std::less>() );
620 if ( it == v->end() || !_detail::ByFingerprint<std::equal_to>()( *it, key ) )
621 return QModelIndex();
623 const unsigned int row = std::distance( v->begin(), it );
624 return createIndex( row, col, const_cast<char* /* thanks, Trolls :/ */ >( issuer_fpr ) );
627 void HierarchicalKeyListModel::addKeyWithParent(
const char * issuer_fpr,
const Key & key ) {
629 assert( issuer_fpr ); assert( *issuer_fpr ); assert( !key.isNull() );
631 std::vector<Key> & subjects = mKeysByExistingParent[issuer_fpr];
634 const std::vector<Key>::iterator it = std::lower_bound( subjects.begin(), subjects.end(), key, _detail::ByFingerprint<std::less>() );
635 const int row = std::distance( subjects.begin(), it );
637 if ( it != subjects.end() && qstricmp( it->primaryFingerprint(), key.primaryFingerprint() ) == 0 ) {
640 emit dataChanged( createIndex( row, 0, const_cast<char*>( issuer_fpr ) ), createIndex( row, NumColumns-1, const_cast<char*>( issuer_fpr ) ) );
643 const std::vector<Key>::const_iterator pos = qBinaryFind( mKeysByFingerprint.begin(), mKeysByFingerprint.end(), issuer_fpr, _detail::ByFingerprint<std::less>() );
644 assert( pos != mKeysByFingerprint.end() );
645 beginInsertRows( index( *pos ), row, row );
646 subjects.insert( it, key );
651 void HierarchicalKeyListModel::addKeyWithoutParent(
const char * issuer_fpr,
const Key & key ) {
653 assert( issuer_fpr ); assert( *issuer_fpr ); assert( !key.isNull() );
655 std::vector<Key> & subjects = mKeysByNonExistingParent[issuer_fpr];
658 const std::vector<Key>::iterator it = std::lower_bound( subjects.begin(), subjects.end(), key, _detail::ByFingerprint<std::less>() );
660 if ( it != subjects.end() && qstricmp( it->primaryFingerprint(), key.primaryFingerprint() ) == 0 )
665 subjects.insert( it, key );
667 addTopLevelKey( key );
670 void HierarchicalKeyListModel::addTopLevelKey(
const Key & key ) {
673 const std::vector<Key>::iterator it = std::lower_bound( mTopLevels.begin(), mTopLevels.end(), key, _detail::ByFingerprint<std::less>() );
674 const int row = std::distance( mTopLevels.begin(), it );
676 if ( it != mTopLevels.end() && qstricmp( it->primaryFingerprint(), key.primaryFingerprint() ) == 0 ) {
679 emit dataChanged( createIndex( row, 0 ), createIndex( row, NumColumns-1 ) );
682 beginInsertRows( QModelIndex(), row, row );
683 mTopLevels.insert( it, key );
692 boost::adjacency_list<> graph( keys.size() );
695 for (
unsigned int i = 0, end = keys.size() ; i != end ; ++i ) {
696 const char *
const issuer_fpr = cleanChainID( keys[i] );
697 if ( !issuer_fpr || !*issuer_fpr )
699 const std::vector<Key>::const_iterator it
700 = qBinaryFind( keys.begin(), keys.end(), issuer_fpr, _detail::ByFingerprint<std::less>() );
701 if ( it == keys.end() )
703 add_edge( i, std::distance( keys.begin(), it ), graph );
706 std::vector<int> order;
707 order.reserve( keys.size() );
710 assert( order.size() == keys.size() );
712 std::vector<Key> result;
713 result.reserve( keys.size() );
714 Q_FOREACH(
int i, order )
715 result.push_back( keys[i] );
719 QList<QModelIndex> HierarchicalKeyListModel::doAddKeys(
const std::vector<Key> & keys ) {
721 assert( __gnu_cxx::is_sorted( keys.begin(), keys.end(), _detail::ByFingerprint<std::less>() ) );
727 const std::vector<Key> oldKeys = mKeysByFingerprint;
729 std::vector<Key> merged;
730 merged.reserve( keys.size() + mKeysByFingerprint.size() );
731 std::set_union( keys.begin(), keys.end(),
732 mKeysByFingerprint.begin(), mKeysByFingerprint.end(),
733 std::back_inserter( merged ), _detail::ByFingerprint<std::less>() );
735 mKeysByFingerprint = merged;
737 std::set<Key, _detail::ByFingerprint<std::less> > changedParents;
742 const char *
const fpr = key.primaryFingerprint();
746 const bool keyAlreadyExisted = qBinaryFind( oldKeys.begin(), oldKeys.end(), key, _detail::ByFingerprint<std::less>() ) != oldKeys.end();
748 const Map::iterator it = mKeysByNonExistingParent.find( fpr );
749 const std::vector<Key> children = it != mKeysByNonExistingParent.end() ? it->second : std::vector<Key>();
750 if ( it != mKeysByNonExistingParent.end() )
751 mKeysByNonExistingParent.erase( it );
755 if ( !keyAlreadyExisted ) {
756 std::vector<Key>::iterator last = mTopLevels.begin();
757 std::vector<Key>::iterator lastFP = mKeysByFingerprint.begin();
759 Q_FOREACH(
const Key & k, children ) {
760 last = qBinaryFind( last, mTopLevels.end(), k, _detail::ByFingerprint<std::less>() );
761 assert( last != mTopLevels.end() );
762 const int row = std::distance( mTopLevels.begin(), last );
764 lastFP = qBinaryFind( lastFP, mKeysByFingerprint.end(), k, _detail::ByFingerprint<std::less>() );
765 assert( lastFP != mKeysByFingerprint.end() );
767 emit rowAboutToBeMoved( QModelIndex(), row );
768 beginRemoveRows( QModelIndex(), row, row );
769 last = mTopLevels.erase( last );
770 lastFP = mKeysByFingerprint.erase( lastFP );
776 const char *
const issuer_fpr = cleanChainID( key );
777 if ( !issuer_fpr || !*issuer_fpr )
779 addTopLevelKey( key );
780 else if ( std::binary_search( mKeysByFingerprint.begin(), mKeysByFingerprint.end(), issuer_fpr, _detail::ByFingerprint<std::less>() ) )
782 addKeyWithParent( issuer_fpr, key );
785 addKeyWithoutParent( issuer_fpr, key );
787 const QModelIndex key_idx = index( key );
788 QModelIndex key_parent = key_idx.parent();
789 while ( key_parent.isValid() ) {
790 changedParents.insert( doMapToKey( key_parent ) );
791 key_parent = key_parent.parent();
796 if ( !keyAlreadyExisted && !children.empty() ) {
798 const QModelIndex new_parent = index( key );
801 for (
int i = children.size() - 1 ; i >= 0 ; --i )
802 emit rowMoved( new_parent, i );
807 Q_FOREACH(
const Key & i, changedParents ) {
808 const QModelIndex idx = index( i );
810 emit dataChanged( idx.sibling( idx.row(), 0 ), idx.sibling( idx.row(), NumColumns - 1 ) );
812 return indexes( keys );
815 void HierarchicalKeyListModel::doRemoveKey(
const Key & key ) {
816 const QModelIndex idx = index( key );
817 if ( !idx.isValid() )
820 const char *
const fpr = key.primaryFingerprint();
821 if ( mKeysByExistingParent.find( fpr ) != mKeysByExistingParent.end() ) {
823 std::vector<Key> keys = mKeysByFingerprint;
824 const std::vector<Key>::iterator it = qBinaryFind( keys.begin(), keys.end(),
825 key, _detail::ByFingerprint<std::less>() );
826 if ( it == keys.end() )
838 const std::vector<Key>::iterator it = qBinaryFind( mKeysByFingerprint.begin(), mKeysByFingerprint.end(),
839 key, _detail::ByFingerprint<std::less>() );
841 assert( it != mKeysByFingerprint.end() );
842 assert( mKeysByNonExistingParent.find( fpr ) == mKeysByNonExistingParent.end() );
843 assert( mKeysByExistingParent.find( fpr ) == mKeysByExistingParent.end() );
845 beginRemoveRows( parent( idx ), idx.row(), idx.row() );
846 mKeysByFingerprint.erase( it );
848 const char *
const issuer_fpr = cleanChainID( key );
850 const std::vector<Key>::iterator tlIt = qBinaryFind( mTopLevels.begin(), mTopLevels.end(), key, _detail::ByFingerprint<std::less>() );
851 if( tlIt != mTopLevels.end() )
852 mTopLevels.erase( tlIt );
854 if ( issuer_fpr && *issuer_fpr ) {
855 const Map::iterator nexIt = mKeysByNonExistingParent.find( issuer_fpr );
856 if ( nexIt != mKeysByNonExistingParent.end() ) {
857 const std::vector<Key>::iterator eit = qBinaryFind( nexIt->second.begin(), nexIt->second.end(), key, _detail::ByFingerprint<std::less>() );
858 if ( eit != nexIt->second.end() )
859 nexIt->second.erase( eit );
860 if ( nexIt->second.empty() )
861 mKeysByNonExistingParent.erase( nexIt );
864 const Map::iterator exIt = mKeysByExistingParent.find( issuer_fpr );
865 if ( exIt != mKeysByExistingParent.end() ) {
866 const std::vector<Key>::iterator eit = qBinaryFind( exIt->second.begin(), exIt->second.end(), key, _detail::ByFingerprint<std::less>() );
867 if ( eit != exIt->second.end() )
868 exIt->second.erase( eit );
869 if ( exIt->second.empty() )
870 mKeysByExistingParent.erase( exIt );
879 #ifdef KLEO_MODEL_TEST
888 #ifdef KLEO_MODEL_TEST
894 #include "moc_keylistmodel.cpp"
895 #include "keylistmodel.moc"
static uint qHash(const char *data)
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
QModelIndex addKey(const GpgME::Key &key)
int columnCount(const QModelIndex &pidx) const
QList< QModelIndex > indexes(const std::vector< GpgME::Key > &keys) const
void setToolTipOptions(int opts)
static AbstractKeyListModel * createHierarchicalKeyListModel(QObject *parent=0)
static uint hash(const uchar *p)
QModelIndex index(const GpgME::Key &key) const
static std::vector< Key > topological_sort(const std::vector< Key > &keys)
static QVariant returnIfValid(const QColor &t)
QList< QModelIndex > addKeys(const std::vector< GpgME::Key > &keys)
int toolTipOptions() const
defines which information is displayed in tooltips see Kleo::Formatting::ToolTipOption ...
QVariant headerData(int section, Qt::Orientation o, int role=Qt::DisplayRole) const
GpgME::Key key(const QModelIndex &idx) const
std::vector< GpgME::Key > keys(const QList< QModelIndex > &indexes) const
static AbstractKeyListModel * createFlatKeyListModel(QObject *parent=0)
static const int FingerprintRole
void removeKey(const GpgME::Key &key)
void setKeys(const std::vector< GpgME::Key > &keys)