ContactListModelSelection::ContactListModelSelection(QList<ContactListItemProxy*> items) : QMimeData() , mimeData_(0) { QDomDocument doc; QDomElement root = doc.createElement("items"); root.setAttribute("version", "2.0"); doc.appendChild(root); // TODO: maybe also embed a random instance-specific token to // prevent drag'n'drop with other running Psi instances? QStringList jids; foreach(ContactListItemProxy* itemProxy, items) { Q_ASSERT(itemProxy); PsiContact* contact = 0; ContactListNestedGroup* group = 0; ContactListAccountGroup* account = 0; if ((contact = dynamic_cast<PsiContact*>(itemProxy->item()))) { QDomElement tag = textTag(&doc, "contact", contact->jid().full()); tag.setAttribute("account", contact->account()->id()); tag.setAttribute("group", itemProxy->parent() ? itemProxy->parent()->fullName() : ""); root.appendChild(tag); jids << contact->jid().full(); } else if ((account = dynamic_cast<ContactListAccountGroup*>(itemProxy->item()))) { QDomElement tag = doc.createElement("account"); tag.setAttribute("id", account->account()->id()); root.appendChild(tag); jids << account->displayName(); } else if ((group = dynamic_cast<ContactListNestedGroup*>(itemProxy->item()))) { // if group->fullName() consists only of whitespace when we'll try // to read it back we'll get an empty string, so we're using CDATA // QDomElement tag = textTag(&doc, "group", group->fullName()); QDomElement tag = doc.createElement("group"); QDomText text = doc.createCDATASection(TextUtil::escape(group->fullName())); tag.appendChild(text); root.appendChild(tag); jids << group->fullName(); } else { qWarning("ContactListModelSelection::ContactListModelSelection(): Unable to serialize %d, unsupported type", itemProxy->item()->type()); } }
bool ContactListModel::setData(const QModelIndex &index, const QVariant &data, int role) { if (!index.isValid()) return false; ContactListItem *item = toItem(index); if (!item) return false; PsiContact *contact = item->isContact() ? item->contact() : nullptr; if (role == ActivateRole) { if (!contact) return false; contact->activate(); return true; } else if (role == Qt::EditRole) { QString name = data.toString(); if (contact) { item->setName(name); emit dataChanged(index, index); } else if (item->isGroup() && !name.isEmpty()) { QString oldName = item->name(); QList<PsiContact*> contacts; for (int i = 0; i < item->childCount(); ++i) { if (item->child(i)->isContact()) contacts << item->child(i)->contact(); } for (PsiContact *contact: contacts) { QStringList groups = contact->groups(); groups.removeOne(oldName); groups << name; contact->setGroups(groups); } } return true; } else if (role == ExpandedRole) { if (!item->isContact()) { item->setExpanded(data.toBool()); } } return true; }
/** * TODO */ bool PsiContactListModel::setData(const QModelIndex& index, const QVariant& data, int role) { if (role == ActivateRole) { if (!index.isValid()) return false; ContactListItem* item = static_cast<ContactListItem*>(index.internalPointer()); PsiContact* contact = dynamic_cast<PsiContact*>(item); if (!contact) return false; contact->activate(); return true; } else if (role == Qt::EditRole) { ContactListItem* item = static_cast<ContactListItem*>(index.internalPointer()); PsiContactGroup* group = 0; PsiContact* contact = 0; QString name = data.toString(); if ((contact = dynamic_cast<PsiContact*>(item))) { if (name.isEmpty()) { QMessageBox::information(0, tr("Error"), tr("You can't set a blank name.")); return false; } else { contact->setName(name); } } else if ((group = dynamic_cast<PsiContactGroup*>(item))) { if (name.isEmpty()) { QMessageBox::information(0, tr("Error"), tr("You can't set a blank group name.")); return false; } else { // make sure we don't have it already if (group->account()->groupList().contains(name)) { QMessageBox::information(0, tr("Error"), tr("You already have a group with that name.")); return false; } group->setName(name); } } emit dataChanged(index, index); return true; } return ContactListModel::setData(index, data, role); }
void ContactListModel::Private::contactUpdated() { PsiContact *contact = qobject_cast<PsiContact*>(sender()); Q_ASSERT(monitoredContacts.contains(contact)); if (!monitoredContacts.contains(contact)) return; // Check for groups changing // Maybe very difficult and should be simplified? QList<ContactListItem*> groupItems; for (const QPersistentModelIndex &index: monitoredContacts.values(contact)) { ContactListItem *item = q->toItem(index); ContactListItem *parent = item->parent(); if (parent && parent->isGroup()) { groupItems << parent; } } Operation operation = Operation::UpdateContact; ContactListItem::SpecialGroupType specialGroupType = specialGroupFor(contact); if (specialGroupType == ContactListItem::SpecialGroupType::NoneSpecialGroupType) { QStringList groups1; for (ContactListItem *item: groupItems) { groups1 << item->name(); } groups1.sort(); QStringList groups2 = contact->groups(); groups2.sort(); if (groups1 != groups2) { operation = Operation::ContactGroupsChanged; } } else if (groupItems.size() > 1 || (!groupItems.isEmpty() && groupItems.first()->specialGroupType() != specialGroupType)) { operation = Operation::ContactGroupsChanged; } addOperation(contact, operation); }
bool YaPopupNotification::notify(int id, PsiEvent* event, int soundType) { Q_ASSERT(event); #ifndef YAPSI_ACTIVEX_SERVER // FIXME: should use PsiAccount::Private::noPopup() if (!event->account() || event->account()->status().type() != XMPP::Status::Online) return false; #endif if (event->type() == PsiEvent::Message || event->type() == PsiEvent::Mood) { ChatDlg* chatDlg = event->account()->findChatDialog(event->from()); if (!chatDlg) chatDlg = event->account()->findChatDialog(event->jid()); if (chatDlg && chatDlg->isActiveTab()) return false; } if (event->type() == PsiEvent::Message) { #ifndef YAPSI_ACTIVEX_SERVER if (!PsiOptions::instance()->getOption("options.ya.popups.message.enable").toBool()) { return false; } #endif } if (event->type() == PsiEvent::Mood) { MoodEvent* moodEvent = static_cast<MoodEvent*>(event); if (!event->account()->psi()->yaToasterCentral()->showToaster(YaToasterCentral::MoodChange, event->from(), moodEvent->mood())) { // qWarning("YaToasterCentral blocked mood change: %s %s", qPrintable(contact->jid().full()), qPrintable(mood)); return false; } // qWarning("%s Changed mood to: %s", qPrintable(contact->jid().full()), qPrintable(mood)); #ifndef YAPSI_ACTIVEX_SERVER if (!PsiOptions::instance()->getOption("options.ya.popups.moods.enable").toBool()) { return false; } #endif #if defined(Q_WS_MAC) && defined(HAVE_GROWL) PsiContact* contact = event->account()->findContact(event->from()); if (contact) { QString contactName = Ya::contactName(contact->name(), contact->jid().bare()); PsiGrowlNotifier::instance()->moodChanged(event->account(), contact->jid(), contactName, moodEvent->mood()); } return true; #endif } #ifdef YAPSI_ACTIVEX_SERVER if (event->account()->psi()->yaOnline()) { event->account()->psi()->yaOnline()->notify(id, event, soundType); return true; } #endif #if defined(Q_WS_MAC) && defined(HAVE_GROWL) // nasty-nasty YaToster steals focus on Mac OS X return true; #endif YaPopupNotification* notification = new YaPopupNotification(id, event); int height = notification->sizeHint().height(); notification->setMinimumSize(QSize(16, height)); YaToster* toster = new YaToster(notification); toster->setStayForever(Ya::isSubscriptionRequest(event)); toster->setTimes(1000, 5000, 500); toster->setSize(QSize(280, height)); toster->start(); return true; }
bool ContactListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); if (!index.isValid()) return false; ContactListItemProxy* itemProxy = static_cast<ContactListItemProxy*>(index.internalPointer()); ContactListItem* item = itemProxy ? itemProxy->item() : 0; if (!item) { Q_ASSERT(false); return false; } if (item->editing()) { return true; } switch (ContactListModel::indexType(index)) { case ContactListModel::ContactType: { PsiContact* psiContact = dynamic_cast<PsiContact*>(item); if (psiContact->isHidden()) { return false; } if (psiContact->isSelf()) { return showSelf(); } else if (psiContact->isAgent()) { return showTransports(); } if (!showOffline()) { return psiContact->isOnline(); } else { return true; } } case ContactListModel::GroupType: { ContactListGroup::SpecialType specialGroupType = static_cast<ContactListGroup::SpecialType>(index.data(ContactListModel::SpecialGroupTypeRole).toInt()); if (specialGroupType != ContactListGroup::SpecialType_None) { if (specialGroupType == ContactListGroup::SpecialType_Transports) return showTransports(); } if (!showOffline()) { ContactListGroup* group = dynamic_cast<ContactListGroup*>(item); return group->haveOnlineContacts(); } else { return true; } } case ContactListModel::AccountType: return true; case ContactListModel::InvalidType: return true; default: Q_ASSERT(false); } return true; }
void ContactListUtil::removeContact(PsiContact* contact, QMimeData* _selection, ContactListDragModel* model, QWidget* widget, QObject* obj) { Q_ASSERT(model); QModelIndexList indexes = model ? model->indexesFor(contact, _selection) : QModelIndexList(); if (model && !indexes.isEmpty()) { QMimeData* selection = model->mimeData(indexes); QString selectionData = confirmationData(contact, _selection, model); // WARNING: selection could also contain groups. and when there are groups, // all groups' contacts are marked for deletion too QList<PsiContact*> contactsLost = model->contactsLostByRemove(selection); bool removeConfirmed = contactsLost.isEmpty(); bool confirmWithoutPrompt = false; if (!removeConfirmed) { QStringList contactNames = contactNamesFor(contactsLost); QString destructiveActionName; QString msg; bool doPrompt = true; // don't prompt when removing single muc or not-in-list contacts if(contactsLost.count() == 1 && (contactsLost[0]->isPrivate() || !contactsLost[0]->inList())) { doPrompt = false; } if (!contactNames.isEmpty()) { msg = tr("This will permanently remove<br>" "%1" "<br>from your contact list." ).arg(contactNames.join(", ").replace("\\40","@")); } #ifdef YAPSI QString complimentaryActionName; const char* complimentaryActionSlot = 0; ContactListModelSelection contactListSelection(selection); if (contactNames.count() > 1 || contactListSelection.groups().count()) { QStringList tmp; QStringList tmpContactNames = contactNames; while (!tmpContactNames.isEmpty()) { if (tmp.count() >= 10) break; tmp << QString("%1. %2").arg(tmp.count() + 1).arg(tmpContactNames.takeFirst()); } QString andNContacts; if (!tmpContactNames.isEmpty()) { andNContacts = tr("and %n contacts ", 0, tmpContactNames.count()); } if (contactListSelection.groups().count() > 1) { msg = tr("This will permanently remove:<br>" "%1" "<br>%2and %n groups from your contact list.", 0, contactListSelection.groups().count() ).arg(tmp.join("<br>")) .arg(andNContacts); } else if (contactListSelection.groups().count() == 1) { msg = tr("This will permanently remove:<br>" "%1" "<br>%2and \"%3\" group from your contact list." ).arg(tmp.join("<br>")) .arg(andNContacts) .arg(contactListSelection.groups().first().fullName); } else { msg = tr("This will permanently remove:<br>" "%1" "<br>%2from your contact list." ).arg(tmp.join("<br>")) .arg(andNContacts); } } if (indexes.count() == 1 && model->indexType(indexes.first()) == ContactListModel::GroupType) { if (YaContactListContactsModel::virtualUnremovableGroups().contains(contactListSelection.groups().first().fullName)) { msg = tr("This is a system group and can't be removed. " "Permanently remove all its contacts from your contact list?"); destructiveActionName = tr("Clear Group"); } else { msg = tr("This will permanently remove<br>" "%1" "<br>group and all its contacts from your contact list.").arg(TextUtil::escape(indexes.first().data().toString())); } } else if (indexes.count() == 1 && model->indexType(indexes.first()) == ContactListModel::ContactType) { Q_ASSERT(contactListSelection.contacts().count() == 1); ContactListModelSelection::Contact c = contactListSelection.contacts().first(); PsiAccount* account = contactList()->getAccount(c.account); PsiContact* psiContact = account ? account->findContact(c.jid) : 0; QStringList contactGroupsLostByRemove; if (psiContact) { contactGroupsLostByRemove = model->contactGroupsLostByRemove(psiContact, selection); } if (psiContact && !psiContact->inList() && psiContact->blockAvailable()) { msg = tr("This will permanently remove %1 from your contact list. " "You could block it in order to avoid further messages.") .arg(contactNames.join(", ").replace("\\40","@")); destructiveActionName = tr("Delete"); complimentaryActionName = tr("Block"); complimentaryActionSlot = "blockContactConfirmation"; } else if (psiContact && psiContact->groups().count() > 1 && contactGroupsLostByRemove.count() == 1) { // TODO: needs to be translated msg = tr("This will remove %1 from \"%2\" group. " "You could also remove it from all groups.") .arg(contactNames.join(", ")) .arg(contactGroupsLostByRemove.first()); destructiveActionName = tr("Delete"); complimentaryActionName = tr("Delete From All Groups"); // TODO: needs to be implemented complimentaryActionSlot = "removeContactFullyConfirmation"; } } #endif if (!msg.isEmpty()) { if (doPrompt) { #ifdef YAPSI if (complimentaryActionSlot) { RemoveConfirmationMessageBoxManager::instance()-> removeConfirmation(selectionData, obj, "removeContactConfirmation", obj, complimentaryActionSlot, tr("Deleting contacts"), msg, widget, destructiveActionName, complimentaryActionName); } #else if (false) { } #endif else { RemoveConfirmationMessageBoxManager::instance()-> removeConfirmation(selectionData, obj, "removeContactConfirmation", tr("Deleting contacts"), msg, widget, destructiveActionName); } removeConfirmed = false; } else { confirmWithoutPrompt = true; } } } QMetaObject::invokeMethod(obj, "removeContactConfirmation", Qt::DirectConnection, QGenericReturnArgument(), Q_ARG(QString, selectionData), Q_ARG(bool, removeConfirmed)); if(confirmWithoutPrompt) { QMetaObject::invokeMethod(obj, "removeContactConfirmation", Qt::QueuedConnection, QGenericReturnArgument(), Q_ARG(QString, selectionData), Q_ARG(bool, true)); } delete selection; }