10#include <config-libkleo.h> 
   12#include "keylistview.h" 
   14#include <kleo_ui_debug.h> 
   18#include <QFontMetrics> 
   24#include <gpgme++/key.h> 
   31static const int updateDelayMilliSecs = 500;
 
   33class Q_DECL_HIDDEN KeyListView::KeyListViewPrivate
 
   37        : updateTimer(nullptr)
 
   41    std::vector<GpgME::Key> keyBuffer;
 
   42    QTimer *updateTimer = 
nullptr;
 
   43    std::map<QByteArray, KeyListViewItem *> itemMap;
 
   51} signalReplacements[] = {
 
   57        SIGNAL(itemSelectionChanged()),
 
   58        SLOT(slotEmitSelectionChanged()),
 
   61        SIGNAL(customContextMenuRequested(
QPoint)),
 
   62        SLOT(slotEmitContextMenu(
QPoint)),
 
   65static const int numSignalReplacements = 
sizeof signalReplacements / 
sizeof *signalReplacements;
 
   67KeyListView::KeyListView(
const ColumnStrategy *columnStrategy, 
const DisplayStrategy *displayStrategy, 
QWidget *parent, 
Qt::WindowFlags f)
 
   69    , mColumnStrategy(columnStrategy)
 
   70    , mDisplayStrategy(displayStrategy)
 
   71    , mHierarchical(false)
 
   72    , d(new KeyListViewPrivate())
 
   77    d->updateTimer = 
new QTimer(
this);
 
   78    d->updateTimer->setSingleShot(
true);
 
   80    if (!columnStrategy) {
 
   81        qCWarning(KLEO_UI_LOG) << 
"Kleo::KeyListView: need a column strategy to work with!";
 
   87    for (
int col = 0; !columnStrategy->title(col).isEmpty(); ++col) {
 
   88        headerItem()->setText(col, columnStrategy->title(col));
 
   89        header()->resizeSection(col, columnStrategy->width(col, fm));
 
   90        header()->setSectionResizeMode(col, columnStrategy->resizeMode(col));
 
   93    setAllColumnsShowFocus(
false);
 
   95    for (
int i = 0; i < numSignalReplacements; ++i) {
 
   96        connect(
this, signalReplacements[i].source, signalReplacements[i].target);
 
  100    viewport()->setToolTip(
QString()); 
 
  103KeyListView::~KeyListView()
 
  105    d->updateTimer->stop();
 
  110    Q_ASSERT(d->itemMap.size() == 0);
 
  112    delete mColumnStrategy;
 
  113    mColumnStrategy = 
nullptr;
 
  114    delete mDisplayStrategy;
 
  115    mDisplayStrategy = 
nullptr;
 
  118void KeyListView::takeItem(QTreeWidgetItem *qlvi)
 
  121    if (
auto *item = lvi_cast<KeyListViewItem>(qlvi)) {
 
  122        deregisterItem(item);
 
  127void KeyListView::setHierarchical(
bool hier)
 
  129    if (hier == mHierarchical) {
 
  132    mHierarchical = hier;
 
  136        scatterGathered(firstChild());
 
  140void KeyListView::slotAddKey(
const GpgME::Key &key)
 
  146    d->keyBuffer.push_back(key);
 
  147    if (!d->updateTimer->isActive()) {
 
  148        d->updateTimer->start(updateDelayMilliSecs);
 
  152void KeyListView::slotUpdateTimeout()
 
  154    if (d->keyBuffer.empty()) {
 
  159    if (wasUpdatesEnabled) {
 
  162    qCDebug(KLEO_UI_LOG) << 
"Kleo::KeyListView::slotUpdateTimeout(): processing" << d->keyBuffer.size() << 
"items en block";
 
  163    if (hierarchical()) {
 
  164        for (std::vector<GpgME::Key>::const_iterator it = d->keyBuffer.begin(); it != d->keyBuffer.end(); ++it) {
 
  165            doHierarchicalInsert(*it);
 
  169        for (std::vector<GpgME::Key>::const_iterator it = d->keyBuffer.begin(); it != d->keyBuffer.end(); ++it) {
 
  170            (void)
new KeyListViewItem(
this, *it);
 
  173    if (wasUpdatesEnabled) {
 
  176    d->keyBuffer.clear();
 
  179void KeyListView::clear()
 
  181    d->updateTimer->stop();
 
  182    d->keyBuffer.clear();
 
  189void KeyListView::registerItem(KeyListViewItem *item)
 
  195    const QByteArray fpr = item->key().primaryFingerprint();
 
  197        d->itemMap.insert(std::make_pair(fpr, item));
 
  201void KeyListView::deregisterItem(
const KeyListViewItem *item)
 
  207    auto it = d->itemMap.find(item->key().primaryFingerprint());
 
  208    if (it == d->itemMap.end()) {
 
  214    if (it->second != item) {
 
  215        qCWarning(KLEO_UI_LOG) << 
"deregisterItem:" 
  216                               << 
"item      " << item->key().primaryFingerprint() 
 
  217                               << 
"it->second" << (it->second ? it->second->key().primaryFingerprint() : 
"is null");
 
  220    d->itemMap.erase(it);
 
  223void KeyListView::doHierarchicalInsert(
const GpgME::Key &key)
 
  225    const QByteArray fpr = key.primaryFingerprint();
 
  229    KeyListViewItem *item = 
nullptr;
 
  231        if (KeyListViewItem *
parent = itemByFingerprint(key.chainID())) {
 
  232            item = 
new KeyListViewItem(
parent, key);
 
  233            parent->setExpanded(
true);
 
  237        item = 
new KeyListViewItem(
this, key); 
 
  240    d->itemMap.insert(std::make_pair(fpr, item));
 
  243void KeyListView::gatherScattered()
 
  245    KeyListViewItem *item = firstChild();
 
  247        KeyListViewItem *cur = item;
 
  248        item = item->nextSibling();
 
  249        if (cur->key().isRoot()) {
 
  252        if (KeyListViewItem *
parent = itemByFingerprint(cur->key().chainID())) {
 
  257            parent->setExpanded(
true);
 
  262void KeyListView::scatterGathered(KeyListViewItem *
start)
 
  264    KeyListViewItem *item = 
start;
 
  266        KeyListViewItem *cur = item;
 
  267        item = item->nextSibling();
 
  269        scatterGathered(lvi_cast<KeyListViewItem>(cur->
child(0)));
 
  274            static_cast<KeyListViewItem *
>(cur->
parent())->takeItem(cur);
 
  282KeyListViewItem *KeyListView::itemByFingerprint(
const QByteArray &s)
 const 
  287    const std::map<QByteArray, KeyListViewItem *>::const_iterator it = d->itemMap.find(s);
 
  288    if (it == d->itemMap.end()) {
 
  294void KeyListView::slotRefreshKey(
const GpgME::Key &key)
 
  296    const char *fpr = key.primaryFingerprint();
 
  300    if (KeyListViewItem *item = itemByFingerprint(fpr)) {
 
  310void KeyListView::slotEmitDoubleClicked(QTreeWidgetItem *item, 
int col)
 
  312    if (!item || lvi_cast<KeyListViewItem>(item)) {
 
  313        Q_EMIT doubleClicked(
static_cast<KeyListViewItem *
>(item), col);
 
  317void KeyListView::slotEmitReturnPressed(QTreeWidgetItem *item)
 
  319    if (!item || lvi_cast<KeyListViewItem>(item)) {
 
  320        Q_EMIT returnPressed(
static_cast<KeyListViewItem *
>(item));
 
  324void KeyListView::slotEmitSelectionChanged()
 
  326    Q_EMIT selectionChanged(selectedItem());
 
  329void KeyListView::slotEmitContextMenu(
const QPoint &pos)
 
  332    if (!item || lvi_cast<KeyListViewItem>(item)) {
 
  343KeyListViewItem::KeyListViewItem(KeyListView *parent, 
const GpgME::Key &key)
 
  344    : QTreeWidgetItem(parent, RTTI)
 
  350KeyListViewItem::KeyListViewItem(KeyListView *parent, KeyListViewItem *after, 
const GpgME::Key &key)
 
  357KeyListViewItem::KeyListViewItem(KeyListViewItem *parent, 
const GpgME::Key &key)
 
  360    Q_ASSERT(parent && parent->listView());
 
  364KeyListViewItem::KeyListViewItem(KeyListViewItem *parent, KeyListViewItem *after, 
const GpgME::Key &key)
 
  367    Q_ASSERT(parent && parent->listView());
 
  371KeyListViewItem::~KeyListViewItem()
 
  384    if (KeyListView *lv = listView()) {
 
  385        lv->deregisterItem(
this);
 
  389void KeyListViewItem::setKey(
const GpgME::Key &key)
 
  391    KeyListView *lv = listView();
 
  393        lv->deregisterItem(
this);
 
  397        lv->registerItem(
this);
 
  402    const KeyListView::ColumnStrategy *cs = lv ? lv->columnStrategy() : 
nullptr;
 
  406    const KeyListView::DisplayStrategy *ds = lv->displayStrategy();
 
  408    for (
int i = 0; i < numCols; ++i) {
 
  410        const auto accessibleText = cs->accessibleText(key, i);
 
  411        if (!accessibleText.isEmpty()) {
 
  415        const QIcon 
icon = cs->icon(key, i);
 
  416        if (!
icon.isNull()) {
 
  427QString KeyListViewItem::toolTip(
int col)
 const 
  429    return listView() && listView()->columnStrategy() ? listView()->columnStrategy()->toolTip(key(), col) : QString();
 
  432bool KeyListViewItem::operator<(
const QTreeWidgetItem &other)
 const 
  434    if (other.
type() != RTTI || !listView() || !listView()->columnStrategy()) {
 
  437    const auto that = 
static_cast<const KeyListViewItem *
>(&other);
 
  438    return listView()->columnStrategy()->compare(this->key(), that->key(), 
treeWidget()->sortColumn()) < 0;
 
  441void KeyListViewItem::takeItem(QTreeWidgetItem *qlvi)
 
  444    if (
auto *item = lvi_cast<KeyListViewItem>(qlvi)) {
 
  445        listView()->deregisterItem(item);
 
  456KeyListView::ColumnStrategy::~ColumnStrategy()
 
  460int KeyListView::ColumnStrategy::compare(
const GpgME::Key &key1, 
const GpgME::Key &key2, 
const int col)
 const 
  465int KeyListView::ColumnStrategy::width(
int col, 
const QFontMetrics &fm)
 const 
  470QString KeyListView::ColumnStrategy::toolTip(
const GpgME::Key &key, 
int col)
 const 
  472    return text(key, col);
 
  481KeyListView::DisplayStrategy::~DisplayStrategy()
 
  486QFont KeyListView::DisplayStrategy::keyFont(
const GpgME::Key &, 
const QFont &
font)
 const 
  492QColor KeyListView::DisplayStrategy::keyForeground(
const GpgME::Key &, 
const QColor &fg)
 const 
  498QColor KeyListView::DisplayStrategy::keyBackground(
const GpgME::Key &, 
const QColor &bg)
 const 
  510KeyListView *KeyListViewItem::listView()
 const 
  515KeyListViewItem *KeyListViewItem::nextSibling()
 const 
  518        const int myIndex = 
parent()->indexOfChild(
const_cast<KeyListViewItem *
>(
this));
 
  519        return static_cast<KeyListViewItem *
>(
parent()->child(myIndex + 1));
 
  521    const int myIndex = treeWidget()->indexOfTopLevelItem(
const_cast<KeyListViewItem *
>(
this));
 
  522    return static_cast<KeyListViewItem *
>(treeWidget()->topLevelItem(myIndex + 1));
 
  525KeyListViewItem *KeyListView::firstChild()
 const 
  530KeyListViewItem *KeyListView::selectedItem()
 const 
  532    QList<KeyListViewItem *> selection = selectedItems();
 
  536    return selection.
first();
 
  539QList<KeyListViewItem *> KeyListView::selectedItems()
 const 
  541    QList<KeyListViewItem *> result;
 
  543    for (QTreeWidgetItem *selectedItem : selectedItems) {
 
  544        if (
auto *i = lvi_cast<KeyListViewItem>(selectedItem)) {
 
  551bool KeyListView::isMultiSelection()
 const 
  556void KeyListView::keyPressEvent(QKeyEvent *
event)
 
  559        if (selectedItem()) {
 
  560            slotEmitReturnPressed(selectedItem());
 
  566#include "moc_keylistview.cpp" 
Q_SCRIPTABLE Q_NOREPLY void start()
 
virtual bool event(QEvent *event) override
 
bool isEmpty() const const
 
int horizontalAdvance(QChar ch) const const
 
void append(QList< T > &&value)
 
bool isEmpty() const const
 
QObject * parent() const const
 
int localeAwareCompare(QStringView s1, QStringView s2)
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
 
virtual void keyPressEvent(QKeyEvent *event) override
 
void setText(int column, const QString &text)