/* Copyright (C) 2003-2005 George Staikos Copyright (C) 2005 Isaac Clerencia This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "allyourbase.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /**************** * KWalletFolderItem - ListView items to represent kwallet folders */ KWalletFolderItem::KWalletFolderItem(KWallet::Wallet *w, QTreeWidget *parent, const QString &name, int entries) : QTreeWidgetItem(parent, KWalletFolderItemClass), _wallet(w), _name(name), _entries(entries) { setText(0, QStringLiteral("%1 (%2)").arg(_name).arg(_entries)); setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled); setIcon(0, getFolderIcon(KIconLoader::Small)); } QPixmap KWalletFolderItem::getFolderIcon(KIconLoader::Group group) { QPixmap pix = QIcon::fromTheme(_name).pixmap(IconSize(group), IconSize(group)); if (pix.isNull()) pix = QIcon::fromTheme(_name.toLower()).pixmap(IconSize(group), IconSize(group)); if (pix.isNull()) pix = QIcon::fromTheme(QStringLiteral("folder-red")).pixmap(IconSize(group), IconSize(group)); return pix; } void KWalletFolderItem::refresh() { const QString saveFolder = _wallet->currentFolder(); _wallet->setFolder(_name); setText(0, QStringLiteral("%1 (%2)").arg(_name).arg(_wallet->entryList().count())); _wallet->setFolder(saveFolder); } void KWalletFolderItem::refreshItemsCount() { int visibleLeafCount = 0; for (int i = 0; i < childCount(); i++) { QTreeWidgetItem *wi = child(i); if (wi->childCount()) { for (int l = 0; l < wi->childCount(); l++) { QTreeWidgetItem *li = wi->child(l); if (!li->isHidden()) { visibleLeafCount++; } } } } setText(0, QStringLiteral("%1 (%2)").arg(_name).arg(visibleLeafCount)); } KWalletContainerItem *KWalletFolderItem::getContainer(KWallet::Wallet::EntryType type) { for (int i = 0; i < childCount(); ++i) { KWalletContainerItem *ci = dynamic_cast(child(i)); if (!ci) { continue; } if (ci->entryType() == type) { return ci; } } return 0; } bool KWalletFolderItem::contains(const QString &key) { return (getItem(key) != 0); } QTreeWidgetItem *KWalletFolderItem::getItem(const QString &key) { for (int i = 0; i < childCount(); ++i) { KWalletContainerItem *ci = dynamic_cast(child(i)); if (!ci) { continue; } QTreeWidgetItem *tmp = ci->getItem(key); if (tmp) { return tmp; } } return 0; } bool KWalletFolderItem::acceptDrop(const QMimeData *mime) const { return mime->hasFormat(QStringLiteral("application/x-kwallet-entry")) || mime->hasFormat(QStringLiteral("text/uri-list")); } QString KWalletFolderItem::name() const { return _name; } KWalletFolderItem::~KWalletFolderItem() { } /**************** * KWalletContainerItem - ListView items to represent kwallet containers, i.e. * passwords, maps, ... */ KWalletContainerItem::KWalletContainerItem(QTreeWidgetItem *parent, const QString &name, KWallet::Wallet::EntryType entryType) : QTreeWidgetItem(parent, QStringList() << name, KWalletContainerItemClass), _type(entryType) { setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); } KWalletContainerItem::~KWalletContainerItem() { } KWallet::Wallet::EntryType KWalletContainerItem::entryType() { return _type; } bool KWalletContainerItem::contains(const QString &key) { return getItem(key) != 0; } QTreeWidgetItem *KWalletContainerItem::getItem(const QString &key) { for (int i = 0; i < childCount(); ++i) { KWalletEntryItem *entryItem = dynamic_cast(child(i)); if (entryItem && entryItem->name() == key) { return entryItem; } } return 0; } /**************** * KWalletEntryItem - ListView items to represent kwallet entries */ KWalletEntryItem::KWalletEntryItem(KWallet::Wallet *w, QTreeWidgetItem *parent, const QString &ename) : QTreeWidgetItem(parent, QStringList() << ename, KWalletEntryItemClass), _wallet(w), m_name(ename) { setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); } KWalletEntryItem::~KWalletEntryItem() { } void KWalletEntryItem::setName(const QString &n) { m_name = n; QTreeWidgetItem::setText(0, n); } void KWalletEntryItem::restoreName() { QTreeWidgetItem::setText(0, m_name); } /**************** * KWalletItem - IconView items to represent wallets */ KWalletItem::KWalletItem(QListWidget *parent, const QString &walletName) : QListWidgetItem(DesktopIcon(QLatin1String("wallet-closed")), walletName, parent), _open(false) { setFlags(flags() | Qt::ItemIsDropEnabled); } KWalletItem::~KWalletItem() { } void KWalletItem::setOpen(bool state) { if (_open != state) { _open = state; if (_open) { setIcon(DesktopIcon(QLatin1String("wallet-open"))); } else { setIcon(DesktopIcon(QLatin1String("wallet-closed"))); } } } static bool decodeEntry(KWallet::Wallet *_wallet, QDataStream &ds) { quint32 magic; ds >> magic; if (magic != KWALLETENTRYMAGIC) { qDebug() << "bad magic" ; return false; } QString name; QByteArray value; KWallet::Wallet::EntryType et; ds >> name; if (_wallet->hasEntry(name)) { int rc = KMessageBox::warningContinueCancel(0L, i18n("An entry by the name '%1' already exists. Would you like to continue?", name)); if (rc == KMessageBox::Cancel) { return false; } } qint32 l; ds >> l; et = KWallet::Wallet::EntryType(l); ds >> value; _wallet->writeEntry(name, value, et); return true; } static bool decodeFolder(KWallet::Wallet *_wallet, QDataStream &ds) { quint32 magic; ds >> magic; if (magic != KWALLETFOLDERMAGIC) { qDebug() << "bad magic" ; return false; } QString folder; ds >> folder; if (_wallet->hasFolder(folder)) { int rc = KMessageBox::warningYesNoCancel(0L, i18n("A folder by the name '%1' already exists. What would you like to do?", folder), QString(), KStandardGuiItem::cont(), KGuiItem(i18n("Replace"))); if (rc == KMessageBox::Cancel) { return false; } if (rc == KMessageBox::No) { _wallet->removeFolder(folder); _wallet->createFolder(folder); } } else { _wallet->createFolder(folder); } _wallet->setFolder(folder); while (!ds.atEnd()) { QString name; QByteArray value; KWallet::Wallet::EntryType et; ds >> name; qint32 l; ds >> l; et = KWallet::Wallet::EntryType(l); ds >> value; _wallet->writeEntry(name, value, et); } return true; } void KWalletItem::processDropEvent(QDropEvent *e) { // We fetch this here at the beginning because we run an event loop further // down which might lead to the event data getting deleted KWalletEntryList *el = nullptr; Qt::DropAction proposedAction = e->proposedAction(); if (e->source() && e->source()->parent() && !strcmp(e->source()->parent()->metaObject()->className(), "KWalletEntryList") && (proposedAction != Qt::CopyAction)) { el = dynamic_cast(e->source()->parent()); } if (e->mimeData()->hasFormat(QStringLiteral("application/x-kwallet-folder")) || e->mimeData()->hasFormat(QStringLiteral("text/uri-list"))) { // FIXME: don't allow the drop if the wallet name is the same KWallet::Wallet *_wallet = KWallet::Wallet::openWallet(text(), listWidget()->topLevelWidget()->winId()); if (!_wallet) { e->ignore(); return; } const QString saveFolder = _wallet->currentFolder(); QByteArray data; if (e->mimeData()->hasFormat(QStringLiteral("application/x-kwallet-folder"))) { data = e->mimeData()->data(QStringLiteral("application/x-kwallet-folder")); e->accept(); } else { // text/uri-list const QList urls = e->mimeData()->urls(); if (urls.isEmpty()) { e->ignore(); return; } QUrl u(urls.first()); if (u.fileName().isEmpty()) { e->ignore(); return; } KIO::StoredTransferJob *job = KIO::storedGet(u); KJobWidgets::setWindow(job, listWidget()); e->accept(); if (job->exec()) { data = job->data(); } else { KMessageBox::error(listWidget(), job->errorString()); } } if (!data.isEmpty()) { QDataStream ds(data); decodeFolder(_wallet, ds); } _wallet->setFolder(saveFolder); delete _wallet; //delete the folder from the source if we were moving if (el) { KWalletFolderItem *fi = dynamic_cast(el->currentItem()); if (fi) { el->_wallet->removeFolder(fi->name()); } } } else { e->ignore(); return; } } /**************** * KWalletEntryList - A listview to store wallet entries */ KWalletEntryList::KWalletEntryList(QWidget *parent, const char *name) : QTreeWidget(parent), _wallet(0) { setObjectName(QLatin1String(name)); setColumnCount(1); setHeaderLabel(i18n("Folders")); setRootIsDecorated(true); setDragEnabled(true); setAcceptDrops(true); setDragDropMode(DragDrop); setSelectionMode(SingleSelection); } KWalletEntryList::~KWalletEntryList() { } //returns true if the item has been dropped successfully void KWalletEntryList::itemDropped(QDropEvent *e, QTreeWidgetItem *item) { bool ok = true; bool isEntry; QByteArray data; KWalletEntryList *el = 0L; QTreeWidgetItem *sel = 0L; // We fetch this here because we run an event loop further down which might invalidate this Qt::DropAction proposedAction = e->proposedAction(); if (!item) { e->ignore(); return; } //detect if we are dragging from kwallet itself qDebug() << e->source() << e->source()->metaObject()->className(); if (e->source() && !strcmp(e->source()->metaObject()->className(), "KWalletEntryList")) { el = dynamic_cast(e->source()); if (!el) { KMessageBox::error(this, i18n("An unexpected error occurred trying to drop the item")); } else { sel = el->currentItem(); } } if (e->mimeData()->hasFormat(QStringLiteral("application/x-kwallet-entry"))) { //do nothing if we are in the same folder if (sel && sel->parent()->parent() == KWalletEntryList::getItemFolder(item)) { e->ignore(); return; } isEntry = true; data = e->mimeData()->data(QStringLiteral("application/x-kwallet-entry")); if (data.isEmpty()) { e->ignore(); return; } e->accept(); } else if (e->mimeData()->hasFormat(QStringLiteral("application/x-kwallet-folder"))) { //do nothing if we are in the same wallet if (this == el) { e->ignore(); return; } isEntry = false; data = e->mimeData()->data(QStringLiteral("application/x-kwallet-folder")); if (data.isEmpty()) { e->ignore(); return; } e->accept(); } else if (e->mimeData()->hasFormat(QStringLiteral("text/uri-list"))) { const QList urls = e->mimeData()->urls(); if (urls.isEmpty()) { e->ignore(); return; } QUrl u(urls.first()); if (u.fileName().isEmpty()) { e->ignore(); return; } e->accept(); KIO::StoredTransferJob *job = KIO::storedGet(u); KJobWidgets::setWindow(job, this); if (!job->exec()) { KMessageBox::error(this, job->errorString()); return; } data = job->data(); QByteArray entryMagic(QByteArray::number(KWALLETENTRYMAGIC)); QByteArray folderMagic(QByteArray::number(KWALLETFOLDERMAGIC)); if (data.startsWith(entryMagic)) { isEntry = true; } else if (data.startsWith(folderMagic)) { isEntry = false; } else { qDebug() << "bad magic" ; return; } } else { e->ignore(); return; } QDataStream ds(data); if (isEntry) { KWalletFolderItem *fi = KWalletEntryList::getItemFolder(item); if (!fi) { KMessageBox::error(this, i18n("An unexpected error occurred trying to drop the entry")); return; } QString saveFolder = _wallet->currentFolder(); _wallet->setFolder(fi->name()); ok = decodeEntry(_wallet, ds); _wallet->setFolder(saveFolder); fi->refresh(); //delete source if we were moving, i.e., we are dragging //from kwalletmanager and Control is not pressed if (ok && el && proposedAction != Qt::CopyAction && sel) { el->_wallet->removeEntry(sel->text(0)); delete sel; } } else { ok = decodeFolder(_wallet, ds); //delete source if we were moving, i.e., we are dragging //from kwalletmanager and Control is not pressed if (ok && el && proposedAction != Qt::CopyAction && sel) { KWalletFolderItem *fi = dynamic_cast(sel); if (fi) { el->_wallet->removeFolder(fi->name()); delete sel; } else { KMessageBox::error(this, i18n("An unexpected error occurred trying to delete the original folder, but the folder has been copied successfully")); } } } } void KWalletEntryList::setWallet(KWallet::Wallet *w) { _wallet = w; } bool KWalletEntryList::existsFolder(const QString &name) { for (int i = 0; i < topLevelItemCount(); ++i) { KWalletFolderItem *fi = dynamic_cast(topLevelItem(i)); if (!fi) { continue; } if (name == fi->name()) { return true; } } return false; } QMimeData *KWalletEntryList::itemMimeData(const QTreeWidgetItem *i) const { QMimeData *sd = 0L; if (i->type() == KWalletEntryItemClass) { const KWalletEntryItem *ei = dynamic_cast(i); if (!ei) { return 0L; } KWalletContainerItem *ci = dynamic_cast(ei->parent()); if (!ci) { return 0L; } sd = new QMimeData(); QByteArray a; QDataStream ds(&a, QIODevice::WriteOnly); ds.setVersion(QDataStream::Qt_3_1); ds << KWALLETENTRYMAGIC; ds << ei->text(0); ds << ci->entryType(); QByteArray value; ei->_wallet->readEntry(i->text(0), value); ds << value; sd->setData(QStringLiteral("application/x-kwallet-entry"), a); } else if (i->type() == KWalletFolderItemClass) { const KWalletFolderItem *fi = dynamic_cast(i); if (!fi) { return 0L; } sd = new QMimeData(); QByteArray a; QDataStream ds(&a, QIODevice::WriteOnly); ds.setVersion(QDataStream::Qt_3_1); ds << KWALLETFOLDERMAGIC; ds << *fi; sd->setData(QStringLiteral("application/x-kwallet-folder"), a); } return sd; } void KWalletEntryList::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { _mousePos = e->pos(); } QTreeWidget::mousePressEvent(e); } void KWalletEntryList::mouseMoveEvent(QMouseEvent *e) { if (!(e->buttons() & Qt::LeftButton)) { return; } if ((e->pos() - _mousePos).manhattanLength() < QApplication::startDragDistance()) { return; } const QTreeWidgetItem *item = itemAt(_mousePos); if (!item || !item->isSelected()) { return; } QMimeData *mimeData = itemMimeData(item); if (mimeData) { QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->setHotSpot(QPoint(0, 0)); drag->exec(); } } void KWalletEntryList::dropEvent(QDropEvent *e) { QTreeWidgetItem *i = itemAt(e->pos()); itemDropped(e, i); } void KWalletEntryList::dragEnterEvent(QDragEnterEvent *e) { e->accept(); } void KWalletEntryList::dragMoveEvent(QDragMoveEvent *e) { QTreeWidgetItem *i = itemAt(e->pos()); e->ignore(); if (i) { if (e->mimeData()->hasFormat(QStringLiteral("application/x-kwallet-entry")) || e->mimeData()->hasFormat(QStringLiteral("text/uri-list"))) { e->accept(); } } if ((e->mimeData()->hasFormat(QStringLiteral("application/x-kwallet-folder")) && e->source() != viewport()) || e->mimeData()->hasFormat(QStringLiteral("text/uri-list"))) { e->accept(); } } KWalletFolderItem *KWalletEntryList::getFolder(const QString &name) { for (int i = 0; i < topLevelItemCount(); ++i) { KWalletFolderItem *fi = dynamic_cast(topLevelItem(i)); if (!fi) { continue; } if (name == fi->name()) { return fi; } } return 0; } KWalletFolderItem *KWalletEntryList::getItemFolder(QTreeWidgetItem *item) { switch (item->type()) { case KWalletFolderItemClass: return dynamic_cast(item); case KWalletContainerItemClass: return dynamic_cast(item->parent()); case KWalletEntryItemClass: return dynamic_cast(item->parent()->parent()); } return 0; } void KWalletEntryList::selectFirstVisible() { QTreeWidgetItemIterator it(this); while (*it) { QTreeWidgetItem *item = *it++; if (!item->isHidden()) { // if it's a leaf, then select it and quit if (item->childCount() == 0) { // qDebug() << "selecting " << item->text(0); setCurrentItem(item); break; } } } } void KWalletEntryList::refreshItemsCount() { QTreeWidgetItemIterator it(this); while (*it) { QTreeWidgetItem *item = *it++; KWalletFolderItem *fi = dynamic_cast< KWalletFolderItem * >(item); if (fi) { fi->refreshItemsCount(); } } } class ReturnPressedFilter : public QObject { public: ReturnPressedFilter(QListWidget *parent) : QObject(parent) { parent->installEventFilter(this); } bool eventFilter(QObject * /*watched*/, QEvent *event) Q_DECL_OVERRIDE { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) { QListWidget *p = static_cast(parent()); QMetaObject::invokeMethod(p, "executed", Q_ARG(QListWidgetItem *, p->currentItem())); return true; } } return false; } };