• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kleopatra

  • sources
  • kde-4.12
  • kdepim
  • kleopatra
  • models
keylistmodel.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  models/keylistmodel.cpp
3 
4  This file is part of Kleopatra, the KDE keymanager
5  Copyright (c) 2007 Klarälvdalens Datakonsult AB
6 
7  Kleopatra is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  Kleopatra is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  In addition, as a special exception, the copyright holders give
22  permission to link the code of this program with any edition of
23  the Qt library by Trolltech AS, Norway (or with modified versions
24  of Qt that use the same license as Qt), and distribute linked
25  combinations including the two. You must obey the GNU General
26  Public License in all respects for all of the code used other than
27  Qt. If you modify this file, you may extend this exception to
28  your version of the file, but you are not obligated to do so. If
29  you do not wish to do so, delete this exception statement from
30  your version.
31 */
32 
33 #include <config-kleopatra.h>
34 
35 #include "keylistmodel.h"
36 #include "predicates.h"
37 
38 #ifdef KLEO_MODEL_TEST
39 # include "modeltest.h"
40 #endif
41 
42 #include <utils/formatting.h>
43 
44 #include <kleo/keyfiltermanager.h>
45 #include <kleo/keyfilter.h>
46 
47 #include <KLocale>
48 #include <KIcon>
49 
50 #include <QDateTime>
51 #include <QFont>
52 #include <QColor>
53 #include <QApplication>
54 #include <QHash>
55 
56 #include <gpgme++/key.h>
57 
58 
59 #ifdef _WIN32_WCE
60 #define BOOST_ALL_NO_LIB
61 #endif
62 
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>
67 #endif
68 
69 #include <algorithm>
70 #include <vector>
71 #include <map>
72 #include <set>
73 #include <iterator>
74 #include <cassert>
75 
76 #ifdef __GNUC__
77 #include <ext/algorithm> // for is_sorted
78 #endif
79 
80 using namespace GpgME;
81 using namespace Kleo;
82 
83 /****************************************************************************
84 **
85 ** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
86 ** Contact: Qt Software Information (qt-info@nokia.com)
87 **
88 ** This file is part of the QtCore module of the Qt Toolkit.
89 **
90 ** Commercial Usage
91 ** Licensees holding valid Qt Commercial licenses may use this file in
92 ** accordance with the Qt Commercial License Agreement provided with the
93 ** Software or, alternatively, in accordance with the terms contained in
94 ** a written agreement between you and Nokia.
95 **
96 **
97 ** GNU General Public License Usage
98 ** Alternatively, this file may be used under the terms of the GNU
99 ** General Public License versions 2.0 or 3.0 as published by the Free
100 ** Software Foundation and appearing in the file LICENSE.GPL included in
101 ** the packaging of this file. Please review the following information
102 ** to ensure GNU General Public Licensing requirements will be met:
103 ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
104 ** http://www.gnu.org/copyleft/gpl.html. In addition, as a special
105 ** exception, Nokia gives you certain additional rights. These rights
106 ** are described in the Nokia Qt GPL Exception version 1.3, included in
107 ** the file GPL_EXCEPTION.txt in this package.
108 **
109 ** Qt for Windows(R) Licensees
110 ** As a special exception, Nokia, as the sole copyright holder for Qt
111 ** Designer, grants users of the Qt/Eclipse Integration plug-in the
112 ** right for the Qt/Eclipse Integration to link to functionality
113 ** provided by Qt Designer and its related libraries.
114 **
115 ** If you are unsure which license is appropriate for your use, please
116 ** contact the sales department at qt-sales@nokia.com.
117 **
118 ****************************************************************************/
119 
120 /*
121  These functions are based on Peter J. Weinberger's hash function
122  (from the Dragon Book). The constant 24 in the original function
123  was replaced with 23 to produce fewer collisions on input such as
124  "a", "aa", "aaa", "aaaa", ...
125 */
126 
127 // adjustment to null-terminated strings
128 // (c) 2008 Klarälvdalens Datakonsult AB
129 static uint hash(const uchar *p)
130 {
131  uint h = 0;
132  uint g;
133 
134  while (*p) {
135  h = (h << 4) + *p++;
136  if ((g = (h & 0xf0000000)) != 0)
137  h ^= g >> 23;
138  h &= ~g;
139  }
140  return h;
141 }
142 
143 //
144 // end Nokia-copyrighted code
145 //
146 
147 static inline uint qHash( const char * data ) {
148  if ( !data )
149  return 1; // something != 0
150  return ::hash( reinterpret_cast<const uchar*>( data ) );
151 }
152 
153 class AbstractKeyListModel::Private {
154 public:
155  Private() : m_toolTipOptions( Formatting::Validity ) {}
156  int m_toolTipOptions;
157  mutable QHash<const char*,QVariant> prettyEMailCache;
158 };
159 AbstractKeyListModel::AbstractKeyListModel( QObject * p )
160  : QAbstractItemModel( p ), KeyListModelInterface(), d( new Private )
161 {
162 
163 }
164 
165 AbstractKeyListModel::~AbstractKeyListModel() {}
166 
167 void AbstractKeyListModel::setToolTipOptions( int opts )
168 {
169  d->m_toolTipOptions = opts;
170 }
171 
172 int AbstractKeyListModel::toolTipOptions() const
173 {
174  return d->m_toolTipOptions;
175 }
176 
177 Key AbstractKeyListModel::key( const QModelIndex & idx ) const {
178  if ( idx.isValid() )
179  return doMapToKey( idx );
180  else
181  return Key::null;
182 }
183 
184 std::vector<Key> AbstractKeyListModel::keys( const QList<QModelIndex> & indexes ) const {
185  std::vector<Key> result;
186  result.reserve( indexes.size() );
187  std::transform( indexes.begin(), indexes.end(),
188  std::back_inserter( result ),
189  boost::bind( &AbstractKeyListModel::key, this, _1 ) );
190  result.erase( std::unique( result.begin(), result.end(), _detail::ByFingerprint<std::equal_to>() ), result.end() );
191  return result;
192 }
193 
194 QModelIndex AbstractKeyListModel::index( const Key & key, int col ) const {
195  if ( key.isNull() || col < 0 || col >= NumColumns )
196  return QModelIndex();
197  else
198  return doMapFromKey( key, col );
199 }
200 
201 QList<QModelIndex> AbstractKeyListModel::indexes( const std::vector<Key> & keys ) const {
202  QList<QModelIndex> result;
203  std::transform( keys.begin(), keys.end(),
204  std::back_inserter( result ),
205  // if some compilers are complaining about ambigious overloads, use this line instead:
206  //bind( static_cast<QModelIndex(AbstractKeyListModel::*)(const Key&,int)const>( &AbstractKeyListModel::index ), this, _1, 0 ) );
207  boost::bind( &AbstractKeyListModel::index, this, _1, 0 ) );
208  return result;
209 }
210 
211 void AbstractKeyListModel::setKeys( const std::vector<Key> & keys ) {
212  clear();
213  addKeys( keys );
214 }
215 
216 QModelIndex AbstractKeyListModel::addKey( const Key & key ) {
217  const std::vector<Key> vec( 1, key );
218  const QList<QModelIndex> l = doAddKeys( vec );
219  return l.empty() ? QModelIndex() : l.front() ;
220 }
221 
222 void AbstractKeyListModel::removeKey( const Key & key ) {
223  if ( key.isNull() )
224  return;
225  doRemoveKey( key );
226  d->prettyEMailCache.remove( key.primaryFingerprint() );
227 }
228 
229 QList<QModelIndex> AbstractKeyListModel::addKeys( const std::vector<Key> & keys ) {
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 );
237 }
238 
239 void AbstractKeyListModel::clear() {
240  doClear();
241  d->prettyEMailCache.clear();
242  reset();
243 }
244 
245 int AbstractKeyListModel::columnCount( const QModelIndex & ) const {
246  return NumColumns;
247 }
248 
249 QVariant AbstractKeyListModel::headerData( int section, Qt::Orientation o, int role ) const {
250  if ( o == Qt::Horizontal )
251  if ( role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole )
252  switch ( section ) {
253  case PrettyName: return i18n( "Name" );
254 #ifndef KDEPIM_MOBILE_UI
255  case PrettyEMail: return i18n( "E-Mail" );
256  case ValidFrom: return i18n( "Valid From" );
257  case ValidUntil: return i18n( "Valid Until" );
258  case TechnicalDetails: return i18n( "Details" );
259  case ShortKeyID: return i18n( "Key-ID" );
260 #endif
261  case NumColumns: ;
262  }
263  return QVariant();
264 }
265 
266 static QVariant returnIfValid( const QColor & t ) {
267  if ( t.isValid() )
268  return t;
269  else
270  return QVariant();
271 }
272 
273 static QVariant returnIfValid( const QIcon & t ) {
274  if ( !t.isNull() )
275  return t;
276  else
277  return QVariant();
278 }
279 
280 QVariant AbstractKeyListModel::data( const QModelIndex & index, int role ) const {
281  const Key key = this->key( index );
282  if ( key.isNull() )
283  return QVariant();
284 
285  const int column = index.column();
286 
287  if ( role == Qt::DisplayRole || role == Qt::EditRole )
288  switch ( column ) {
289  case PrettyName:
290 #ifdef KDEPIM_MOBILE_UI
291  return Formatting::formatForComboBox( key );
292 #else
293  return Formatting::prettyName( key );
294  case PrettyEMail:
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() )
298  return *it;
299  else
300  return d->prettyEMailCache[fpr] = Formatting::prettyEMail( key );
301  } else {
302  return QVariant();
303  }
304  case ValidFrom:
305  if ( role == Qt::EditRole )
306  return Formatting::creationDate( key );
307  else
308  return Formatting::creationDateString( key );
309  case ValidUntil:
310  if ( role == Qt::EditRole )
311  return Formatting::expirationDate( key );
312  else
313  return Formatting::expirationDateString( key );
314  case TechnicalDetails:
315  return Formatting::type( key );
316  case ShortKeyID:
317  return QString::fromLatin1( key.shortKeyID() );
318 #endif // KDEPIM_MOBILE_UI
319  case NumColumns:
320  break;
321  }
322 #ifndef KDEPIM_MOBILE_UI
323  else if ( role == Qt::ToolTipRole )
324  return Formatting::toolTip( key, toolTipOptions() );
325  else if ( role == Qt::FontRole )
326  return KeyFilterManager::instance()->font( key, ( column == ShortKeyID ) ? QFont( QLatin1String("courier") ) : QFont() );
327 #endif
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 ) );
334  else if ( role == FingerprintRole )
335  return QString::fromLatin1( key.primaryFingerprint() );
336  return QVariant();
337 }
338 
339 
340 namespace {
341  template <typename Base>
342  class TableModelMixin : public Base {
343  public:
344  explicit TableModelMixin( QObject * p=0 ) : Base( p ) {}
345  ~TableModelMixin() {}
346 
347  using Base::index;
348  /* reimp */ QModelIndex index( int row, int column, const QModelIndex & pidx=QModelIndex() ) const {
349  return this->hasIndex( row, column, pidx ) ? this->createIndex( row, column, 0 ) : QModelIndex() ;
350  }
351 
352  private:
353  /* reimp */ QModelIndex parent( const QModelIndex & ) const { return QModelIndex(); }
354  /* reimp */ bool hasChildren( const QModelIndex & pidx ) const {
355  return ( pidx.model() == this || !pidx.isValid() ) && this->rowCount( pidx ) > 0 && this->columnCount( pidx ) > 0 ;
356  }
357  };
358 
359  class FlatKeyListModel
360 #ifndef Q_MOC_RUN
361  : public TableModelMixin<AbstractKeyListModel>
362 #else
363  : public AbstractKeyListModel
364 #endif
365  {
366  Q_OBJECT
367  public:
368  explicit FlatKeyListModel( QObject * parent=0 );
369  ~FlatKeyListModel();
370 
371  /* reimp */ int rowCount( const QModelIndex & pidx ) const { return pidx.isValid() ? 0 : mKeysByFingerprint.size() ; }
372 
373  private:
374  /* reimp */ Key doMapToKey( const QModelIndex & index ) const;
375  /* reimp */ QModelIndex doMapFromKey( const Key & key, int col ) const;
376  /* reimp */ QList<QModelIndex> doAddKeys( const std::vector<Key> & keys );
377  /* reimp */ void doRemoveKey( const Key & key );
378  /* reimp */ void doClear() {
379  mKeysByFingerprint.clear();
380  }
381 
382  private:
383  std::vector<Key> mKeysByFingerprint;
384  };
385 
386  class HierarchicalKeyListModel : public AbstractKeyListModel {
387  Q_OBJECT
388  public:
389  explicit HierarchicalKeyListModel( QObject * parent=0 );
390  ~HierarchicalKeyListModel();
391 
392  /* reimp */ int rowCount( const QModelIndex & pidx ) const;
393  using AbstractKeyListModel::index;
394  /* reimp */ QModelIndex index( int row, int col, const QModelIndex & pidx ) const;
395  /* reimp */ QModelIndex parent( const QModelIndex & idx ) const;
396 
397  bool hasChildren( const QModelIndex & pidx ) const { return rowCount( pidx ) > 0 ; }
398 
399  private:
400  /* reimp */ Key doMapToKey( const QModelIndex & index ) const;
401  /* reimp */ QModelIndex doMapFromKey( const Key & key, int col ) const;
402  /* reimp */ QList<QModelIndex> doAddKeys( const std::vector<Key> & keys );
403  /* reimp */ void doRemoveKey( const Key & key );
404  /* reimp */ void doClear() {
405  mTopLevels.clear();
406  mKeysByFingerprint.clear();
407  mKeysByExistingParent.clear();
408  mKeysByNonExistingParent.clear();
409  }
410 
411  private:
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 );
415 
416  private:
417  typedef std::map< std::string, std::vector<Key> > Map;
418  std::vector<Key> mKeysByFingerprint; // all keys
419  Map mKeysByExistingParent, mKeysByNonExistingParent; // parent->child map
420  std::vector<Key> mTopLevels; // all roots + parent-less
421  };
422 
423  static const char * cleanChainID( const Key & key ) {
424  if ( key.isRoot() )
425  return "";
426  if ( const char * chid = key.chainID() )
427  return chid;
428  return "";
429  }
430 
431 }
432 
433 
434 FlatKeyListModel::FlatKeyListModel( QObject * p )
435  : TableModelMixin<AbstractKeyListModel>( p ),
436  mKeysByFingerprint()
437 {
438 
439 }
440 
441 FlatKeyListModel::~FlatKeyListModel() {}
442 
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() ];
447  else
448  return Key::null;
449 }
450 
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();
458  else
459  return createIndex( it - mKeysByFingerprint.begin(), col );
460 }
461 
462 QList<QModelIndex> FlatKeyListModel::doAddKeys( const std::vector<Key> & keys ) {
463 #ifdef __GNUC__
464  assert( __gnu_cxx::is_sorted( keys.begin(), keys.end(), _detail::ByFingerprint<std::less>() ) );
465 #endif
466  if ( keys.empty() )
467  return QList<QModelIndex>();
468 
469  for ( std::vector<Key>::const_iterator it = keys.begin(), end = keys.end() ; it != end ; ++it ) {
470 
471  // find an insertion point:
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 );
474 
475  if ( idx > 0 && qstrcmp( mKeysByFingerprint[idx-1].primaryFingerprint(), it->primaryFingerprint() ) == 0 ) {
476  // key existed before - replace with new one:
477  mKeysByFingerprint[idx-1] = *it;
478  emit dataChanged( createIndex( idx-1, 0 ), createIndex( idx-1, NumColumns-1 ) );
479  } else {
480  // new key - insert:
481  beginInsertRows( QModelIndex(), idx, idx );
482  mKeysByFingerprint.insert( pos, *it );
483  endInsertRows();
484  }
485  }
486 
487  return indexes( keys );
488 }
489 
490 
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() )
496  return;
497 
498  const unsigned int row = std::distance( mKeysByFingerprint.begin(), it );
499  beginRemoveRows( QModelIndex(), row, row );
500  mKeysByFingerprint.erase( it );
501  endRemoveRows();
502 }
503 
504 
505 
506 
507 
508 
509 
510 
511 HierarchicalKeyListModel::HierarchicalKeyListModel( QObject * p )
512  : AbstractKeyListModel( p ),
513  mKeysByFingerprint(),
514  mKeysByExistingParent(),
515  mKeysByNonExistingParent(),
516  mTopLevels()
517 {
518 
519 }
520 
521 HierarchicalKeyListModel::~HierarchicalKeyListModel() {}
522 
523 int HierarchicalKeyListModel::rowCount( const QModelIndex & pidx ) const {
524 
525  // toplevel item:
526  if ( !pidx.isValid() )
527  return mTopLevels.size();
528 
529  if ( pidx.column() != 0 )
530  return 0;
531 
532  // non-toplevel item - find the number of subjects for this issuer:
533  const Key issuer = this->key( pidx );
534  const char * const fpr = issuer.primaryFingerprint();
535  if ( !fpr || !*fpr )
536  return 0;
537  const Map::const_iterator it = mKeysByExistingParent.find( fpr );
538  if ( it == mKeysByExistingParent.end() )
539  return 0;
540  return it->second.size();
541 }
542 
543 QModelIndex HierarchicalKeyListModel::index( int row, int col, const QModelIndex & pidx ) const {
544 
545  if ( row < 0 || col < 0 || col >= NumColumns )
546  return QModelIndex();
547 
548  // toplevel item:
549  if ( !pidx.isValid() ) {
550  if ( static_cast<unsigned>( row ) < mTopLevels.size() )
551  return index( mTopLevels[row], col );
552  else
553  return QModelIndex();
554  }
555 
556  // non-toplevel item - find the row'th subject of this key:
557  const Key issuer = this->key( pidx );
558  const char * const fpr = issuer.primaryFingerprint();
559  if ( !fpr || !*fpr )
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 );
565 }
566 
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();
575 }
576 
577 Key HierarchicalKeyListModel::doMapToKey( const QModelIndex & idx ) const {
578 
579  if ( !idx.isValid() )
580  return Key::null;
581 
582  const char * const issuer_fpr = static_cast<const char*>( idx.internalPointer() );
583  if ( !issuer_fpr || !*issuer_fpr ) {
584  // top-level:
585  if ( static_cast<unsigned>( idx.row() ) >= mTopLevels.size() )
586  return Key::null;
587  else
588  return mTopLevels[idx.row()];
589  }
590 
591  // non-toplevel:
592  const Map::const_iterator it
593  = mKeysByExistingParent.find( issuer_fpr );
594  if ( it == mKeysByExistingParent.end() || static_cast<unsigned>( idx.row() ) >= it->second.size() )
595  return Key::null;
596  return it->second[idx.row()];
597 }
598 
599 QModelIndex HierarchicalKeyListModel::doMapFromKey( const Key & key, int col ) const {
600 
601  if ( key.isNull() )
602  return QModelIndex();
603 
604  const char * issuer_fpr = cleanChainID( key );
605 
606  // we need to look in the toplevels list,...
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 );
611  // ...unless we find an existing parent:
612  if ( it != mKeysByExistingParent.end() )
613  v = &it->second;
614  else
615  issuer_fpr = 0; // force internalPointer to zero for toplevels
616  }
617 
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();
622 
623  const unsigned int row = std::distance( v->begin(), it );
624  return createIndex( row, col, const_cast<char* /* thanks, Trolls :/ */ >( issuer_fpr ) );
625 }
626 
627 void HierarchicalKeyListModel::addKeyWithParent( const char * issuer_fpr, const Key & key ) {
628 
629  assert( issuer_fpr ); assert( *issuer_fpr ); assert( !key.isNull() );
630 
631  std::vector<Key> & subjects = mKeysByExistingParent[issuer_fpr];
632 
633  // find insertion point:
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 );
636 
637  if ( it != subjects.end() && qstricmp( it->primaryFingerprint(), key.primaryFingerprint() ) == 0 ) {
638  // exists -> replace
639  *it = key;
640  emit dataChanged( createIndex( row, 0, const_cast<char*>( issuer_fpr ) ), createIndex( row, NumColumns-1, const_cast<char*>( issuer_fpr ) ) );
641  } else {
642  // doesn't exist -> insert
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 );
647  endInsertRows();
648  }
649 }
650 
651 void HierarchicalKeyListModel::addKeyWithoutParent( const char * issuer_fpr, const Key & key ) {
652 
653  assert( issuer_fpr ); assert( *issuer_fpr ); assert( !key.isNull() );
654 
655  std::vector<Key> & subjects = mKeysByNonExistingParent[issuer_fpr];
656 
657  // find insertion point:
658  const std::vector<Key>::iterator it = std::lower_bound( subjects.begin(), subjects.end(), key, _detail::ByFingerprint<std::less>() );
659 
660  if ( it != subjects.end() && qstricmp( it->primaryFingerprint(), key.primaryFingerprint() ) == 0 )
661  // exists -> replace
662  *it = key;
663  else
664  // doesn't exist -> insert
665  subjects.insert( it, key );
666 
667  addTopLevelKey( key );
668 }
669 
670 void HierarchicalKeyListModel::addTopLevelKey( const Key & key ) {
671 
672  // find insertion point:
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 );
675 
676  if ( it != mTopLevels.end() && qstricmp( it->primaryFingerprint(), key.primaryFingerprint() ) == 0 ) {
677  // exists -> replace
678  *it = key;
679  emit dataChanged( createIndex( row, 0 ), createIndex( row, NumColumns-1 ) );
680  } else {
681  // doesn't exist -> insert
682  beginInsertRows( QModelIndex(), row, row );
683  mTopLevels.insert( it, key );
684  endInsertRows();
685  }
686 
687 }
688 
689 // sorts 'keys' such that parent always come before their children:
690 static std::vector<Key> topological_sort( const std::vector<Key> & keys ) {
691 
692  boost::adjacency_list<> graph( keys.size() );
693 
694  // add edges from children to parents:
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 )
698  continue;
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() )
702  continue;
703  add_edge( i, std::distance( keys.begin(), it ), graph );
704  }
705 
706  std::vector<int> order;
707  order.reserve( keys.size() );
708  topological_sort( graph, std::back_inserter( order ) );
709 
710  assert( order.size() == keys.size() );
711 
712  std::vector<Key> result;
713  result.reserve( keys.size() );
714  Q_FOREACH( int i, order )
715  result.push_back( keys[i] );
716  return result;
717 }
718 
719 QList<QModelIndex> HierarchicalKeyListModel::doAddKeys( const std::vector<Key> & keys ) {
720 #ifdef __GNUC__
721  assert( __gnu_cxx::is_sorted( keys.begin(), keys.end(), _detail::ByFingerprint<std::less>() ) );
722 #endif
723  if ( keys.empty() )
724  return QList<QModelIndex>();
725 
726 
727  const std::vector<Key> oldKeys = mKeysByFingerprint;
728 
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>() );
734 
735  mKeysByFingerprint = merged;
736 
737  std::set<Key, _detail::ByFingerprint<std::less> > changedParents;
738 
739  Q_FOREACH( const Key & key, topological_sort( keys ) ) {
740 
741  // check to see whether this key is a parent for a previously parent-less group:
742  const char * const fpr = key.primaryFingerprint();
743  if ( !fpr || !*fpr )
744  continue;
745 
746  const bool keyAlreadyExisted = qBinaryFind( oldKeys.begin(), oldKeys.end(), key, _detail::ByFingerprint<std::less>() ) != oldKeys.end();
747 
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 );
752 
753  // Step 1: For new keys, remove children from toplevel:
754 
755  if ( !keyAlreadyExisted ) {
756  std::vector<Key>::iterator last = mTopLevels.begin();
757  std::vector<Key>::iterator lastFP = mKeysByFingerprint.begin();
758 
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 );
763 
764  lastFP = qBinaryFind( lastFP, mKeysByFingerprint.end(), k, _detail::ByFingerprint<std::less>() );
765  assert( lastFP != mKeysByFingerprint.end() );
766 
767  emit rowAboutToBeMoved( QModelIndex(), row );
768  beginRemoveRows( QModelIndex(), row, row );
769  last = mTopLevels.erase( last );
770  lastFP = mKeysByFingerprint.erase( lastFP );
771  endRemoveRows();
772  }
773  }
774  // Step 2: add/update key
775 
776  const char * const issuer_fpr = cleanChainID( key );
777  if ( !issuer_fpr || !*issuer_fpr )
778  // root or something...
779  addTopLevelKey( key );
780  else if ( std::binary_search( mKeysByFingerprint.begin(), mKeysByFingerprint.end(), issuer_fpr, _detail::ByFingerprint<std::less>() ) )
781  // parent exists...
782  addKeyWithParent( issuer_fpr, key );
783  else
784  // parent does't exist yet...
785  addKeyWithoutParent( issuer_fpr, key );
786 
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();
792  }
793 
794  // Step 3: Add children to new parent ( == key )
795 
796  if ( !keyAlreadyExisted && !children.empty() ) {
797  addKeys( children );
798  const QModelIndex new_parent = index( key );
799  // emit the rowMoved() signals in reversed direction, so the
800  // implementation can use a stack for mapping.
801  for ( int i = children.size() - 1 ; i >= 0 ; --i )
802  emit rowMoved( new_parent, i );
803  }
804  }
805  //emit dataChanged for all parents with new children. This triggers KeyListSortFilterProxyModel to
806  //show a parent node if it just got children matching the proxy's filter
807  Q_FOREACH( const Key & i, changedParents ) {
808  const QModelIndex idx = index( i );
809  if ( idx.isValid() )
810  emit dataChanged( idx.sibling( idx.row(), 0 ), idx.sibling( idx.row(), NumColumns - 1 ) );
811  }
812  return indexes( keys );
813 }
814 
815 void HierarchicalKeyListModel::doRemoveKey( const Key & key ) {
816  const QModelIndex idx = index( key );
817  if ( !idx.isValid() )
818  return;
819 
820  const char * const fpr = key.primaryFingerprint();
821  if ( mKeysByExistingParent.find( fpr ) != mKeysByExistingParent.end() ) {
822  //handle non-leave nodes:
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() )
827  return;
828  keys.erase( it );
829  // FIXME for simplicity, we just clear the model and re-add all keys minus the removed one. This is suboptimal,
830  // but acceptable given that deletion of non-leave nodes is rather rare.
831  clear();
832  addKeys( keys );
833  return;
834  }
835 
836  //handle leave nodes:
837 
838  const std::vector<Key>::iterator it = qBinaryFind( mKeysByFingerprint.begin(), mKeysByFingerprint.end(),
839  key, _detail::ByFingerprint<std::less>() );
840 
841  assert( it != mKeysByFingerprint.end() );
842  assert( mKeysByNonExistingParent.find( fpr ) == mKeysByNonExistingParent.end() );
843  assert( mKeysByExistingParent.find( fpr ) == mKeysByExistingParent.end() );
844 
845  beginRemoveRows( parent( idx ), idx.row(), idx.row() );
846  mKeysByFingerprint.erase( it );
847 
848  const char * const issuer_fpr = cleanChainID( key );
849 
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 );
853 
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 );
862  }
863 
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 );
871  }
872  }
873  endRemoveRows();
874 }
875 
876 // static
877 AbstractKeyListModel * AbstractKeyListModel::createFlatKeyListModel( QObject * p ) {
878  AbstractKeyListModel * const m = new FlatKeyListModel( p );
879 #ifdef KLEO_MODEL_TEST
880  new ModelTest( m, p );
881 #endif
882  return m;
883 }
884 
885 // static
886 AbstractKeyListModel * AbstractKeyListModel::createHierarchicalKeyListModel( QObject * p ) {
887  AbstractKeyListModel * const m = new HierarchicalKeyListModel( p );
888 #ifdef KLEO_MODEL_TEST
889  new ModelTest( m, p );
890 #endif
891  return m;
892 }
893 
894 #include "moc_keylistmodel.cpp"
895 #include "keylistmodel.moc"
896 
qHash
static uint qHash(const char *data)
Definition: keylistmodel.cpp:147
Kleo::KeyListModelInterface::PrettyName
Definition: keylistmodelinterface.h:54
Kleo::AbstractKeyListModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Definition: keylistmodel.cpp:280
Kleo::KeyListModelInterface::ValidUntil
Definition: keylistmodelinterface.h:58
Kleo::AbstractKeyListModel::addKey
QModelIndex addKey(const GpgME::Key &key)
Definition: keylistmodel.cpp:216
Kleo::AbstractKeyListModel::columnCount
int columnCount(const QModelIndex &pidx) const
Definition: keylistmodel.cpp:245
Kleo::Formatting::type
QString type(const GpgME::Key &key)
Kleo::KeyListModelInterface::ShortKeyID
Definition: keylistmodelinterface.h:61
Kleo::Formatting::creationDateString
QString creationDateString(const GpgME::Key &key)
Kleo::AbstractKeyListModel::indexes
QList< QModelIndex > indexes(const std::vector< GpgME::Key > &keys) const
Definition: keylistmodel.cpp:201
Kleo::Formatting::toolTip
QString toolTip(const GpgME::Key &key, int opts)
formatting.h
Kleo::AbstractKeyListModel::clear
void clear()
Definition: keylistmodel.cpp:239
Kleo::KeyListModelInterface::PrettyEMail
Definition: keylistmodelinterface.h:56
Kleo::AbstractKeyListModel::setToolTipOptions
void setToolTipOptions(int opts)
Definition: keylistmodel.cpp:167
Kleo::KeyListModelInterface::ValidFrom
Definition: keylistmodelinterface.h:57
Kleo::Formatting::expirationDateString
QString expirationDateString(const GpgME::Key &key)
Kleo::AbstractKeyListModel::~AbstractKeyListModel
~AbstractKeyListModel()
Definition: keylistmodel.cpp:165
Kleo::AbstractKeyListModel::createHierarchicalKeyListModel
static AbstractKeyListModel * createHierarchicalKeyListModel(QObject *parent=0)
Definition: keylistmodel.cpp:886
Kleo::Formatting::formatForComboBox
QString formatForComboBox(const GpgME::Key &key)
Definition: formatting.cpp:497
d
#define d
Definition: adduseridcommand.cpp:90
hash
static uint hash(const uchar *p)
Definition: keylistmodel.cpp:129
Kleo::AbstractKeyListModel::index
QModelIndex index(const GpgME::Key &key) const
Definition: keylistmodel.h:62
modeltest.h
topological_sort
static std::vector< Key > topological_sort(const std::vector< Key > &keys)
Definition: keylistmodel.cpp:690
Kleo::Formatting::expirationDate
QDate expirationDate(const GpgME::Key &key)
returnIfValid
static QVariant returnIfValid(const QColor &t)
Definition: keylistmodel.cpp:266
Kleo::AbstractKeyListModel::addKeys
QList< QModelIndex > addKeys(const std::vector< GpgME::Key > &keys)
Definition: keylistmodel.cpp:229
Kleo::Formatting::prettyEMail
QString prettyEMail(const char *email, const char *id)
Definition: formatting.cpp:184
Kleo::KeyListModelInterface::TechnicalDetails
Definition: keylistmodelinterface.h:59
QAbstractItemModel
Kleo::AbstractKeyListModel
Definition: keylistmodel.h:49
Kleo::KeyListModelInterface::NumColumns
Definition: keylistmodelinterface.h:72
Kleo::KeyListModelInterface
Definition: keylistmodelinterface.h:47
keylistmodel.h
Kleo::AbstractKeyListModel::toolTipOptions
int toolTipOptions() const
defines which information is displayed in tooltips see Kleo::Formatting::ToolTipOption ...
Definition: keylistmodel.cpp:172
Kleo::Formatting::creationDate
QDate creationDate(const GpgME::Key &key)
Kleo::AbstractKeyListModel::headerData
QVariant headerData(int section, Qt::Orientation o, int role=Qt::DisplayRole) const
Definition: keylistmodel.cpp:249
ModelTest
Definition: modeltest.h:31
predicates.h
Kleo::AbstractKeyListModel::key
GpgME::Key key(const QModelIndex &idx) const
Definition: keylistmodel.cpp:177
Kleo::AbstractKeyListModel::keys
std::vector< GpgME::Key > keys(const QList< QModelIndex > &indexes) const
Definition: keylistmodel.cpp:184
Kleo::Formatting::prettyName
QString prettyName(int proto, const char *id, const char *name, const char *comment)
Definition: formatting.cpp:64
Kleo::AbstractKeyListModel::createFlatKeyListModel
static AbstractKeyListModel * createFlatKeyListModel(QObject *parent=0)
Definition: keylistmodel.cpp:877
Kleo::KeyListModelInterface::FingerprintRole
static const int FingerprintRole
Definition: keylistmodelinterface.h:51
Kleo::AbstractKeyListModel::removeKey
void removeKey(const GpgME::Key &key)
Definition: keylistmodel.cpp:222
Kleo::KeyListModelInterface::Icon
Definition: keylistmodelinterface.h:73
Kleo::Formatting::Validity
Definition: formatting.h:69
Kleo::AbstractKeyListModel::setKeys
void setKeys(const std::vector< GpgME::Key > &keys)
Definition: keylistmodel.cpp:211
QList
Definition: commands/command.h:46
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:56:41 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kleopatra

Skip menu "kleopatra"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal