void Plugin::hookEntryStatusChanged (IHookProxy_ptr, QObject *entryObj, QString) { if (!IsGoodEntry (entryObj)) return; ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const QString& id = entry->GetEntryID (); const EntryStatus& status = entry->GetStatus (); if (!LastState_.contains (id)) { LastState_ [id] = status.State_; return; } const State oldState = LastState_ [id]; LastState_ [id] = status.State_; switch (oldState) { case SOffline: case SProbe: case SError: case SInvalid: case SConnecting: return; case SOnline: LastAvailable_ [id] = QDateTime::currentDateTime (); default: LastOnline_ [id] = QDateTime::currentDateTime (); ScheduleSave (); } }
void MetaEntry::handleRealNameChanged (const QString&) { QObject *obj = sender (); ICLEntry *entry = qobject_cast<ICLEntry*> (obj); handleRealVariantsChanged (entry->Variants (), obj); }
void Plugin::RequestLastMessages (QObject *entryObj, int num) { ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry) { qWarning () << Q_FUNC_INFO << entryObj << "doesn't implement ICLEntry"; return; } if (entry->GetEntryType () != ICLEntry::ETChat) return; IAccount *account = qobject_cast<IAccount*> (entry->GetParentAccount ()); if (!account) { qWarning () << Q_FUNC_INFO << entry->GetParentAccount () << "doesn't implement IAccount"; return; } const QString& accId = account->GetAccountID (); const QString& entryId = entry->GetEntryID (); Core::Instance ()->GetChatLogs (accId, entryId, 0, num); RequestedLogs_ [accId] [entryId] = entryObj; }
void MetaEntry::handleRealVariantsChanged (QStringList variants, QObject *passedObj) { QObject *obj = passedObj ? passedObj : sender (); Q_FOREACH (const QString& var, Variant2RealVariant_.keys ()) { const QPair<QObject*, QString>& pair = Variant2RealVariant_ [var]; if (pair.first == obj) Variant2RealVariant_.remove (var); } ICLEntry *entry = qobject_cast<ICLEntry*> (obj); if (!variants.contains (QString ())) variants.prepend (QString ()); Q_FOREACH (const QString& var, variants) Variant2RealVariant_ [entry->GetEntryName () + '/' + var] = qMakePair (obj, var); emit availableVariantsChanged (Variants ()); Q_FOREACH (const QString& var, variants) { const QString& str = entry->GetEntryName () + '/' + var; emit statusChanged (GetStatus (str), str); } }
AcceptRIEXDialog::AcceptRIEXDialog (const QList<RIEXItem>& items, QObject *entryObj, QString message, QWidget *parent) : QDialog (parent) , Model_ (new QStandardItemModel (this)) { Ui_.setupUi (this); Model_->setHorizontalHeaderLabels ({ tr ("Action"), tr ("ID"), tr ("Name"), tr ("Groups") }); for (const RIEXItem& item : items) { QList<QStandardItem*> row; QStandardItem *action = new QStandardItem; action->setCheckState (Qt::Checked); action->setCheckable (true); switch (item.Action_) { case RIEXItem::AAdd: action->setText (tr ("add")); break; case RIEXItem::ADelete: action->setText (tr ("delete")); break; case RIEXItem::AModify: action->setText (tr ("modify")); break; default: action->setText (tr ("(unknown)")); break; } action->setData (QVariant::fromValue<RIEXItem> (item)); row << action; row << new QStandardItem (item.ID_); row << new QStandardItem (item.Nick_); row << new QStandardItem (item.Groups_.join ("; ")); Model_->appendRow (row); } Ui_.ItemsTree_->setModel (Model_); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const QString& id = entry->GetEntryName ().isEmpty () ? entry->GetHumanReadableID () : entry->GetEntryName () + " (" + entry->GetHumanReadableID () + ")"; const QString& text = message.isEmpty () ? tr ("%1 has suggested to modify your contact list:") .arg (id) : tr ("%1 has suggested to modify your contact list:\n%2") .arg (id) .arg (message); Ui_.MessageLabel_->setText (text); }
void Plugin::hookMessageWillCreated (LeechCraft::IHookProxy_ptr proxy, QObject*, QObject *entry, int, QString) { ICLEntry *other = qobject_cast<ICLEntry*> (entry); if (!other) { qWarning () << Q_FUNC_INFO << "unable to cast" << entry << "to ICLEntry"; return; } QString text = proxy->GetValue ("text").toString (); const int maxLines = XmlSettingsManager::Instance () .property ("LineCount").toInt (); if (text.split ('\n').size () < maxLines) return; QByteArray propName; switch (other->GetEntryType ()) { case ICLEntry::ETChat: propName = "EnableForNormalChats"; break; case ICLEntry::ETMUC: propName = "EnableForMUCChats"; break; case ICLEntry::ETPrivateChat: propName = "EnableForPrivateChats"; break; default: return; } if (!XmlSettingsManager::Instance ().property (propName).toBool ()) return; PasteDialog dia; dia.exec (); auto choice = dia.GetChoice (); switch (choice) { case PasteDialog::Cancel: proxy->CancelDefault (); case PasteDialog::No: return; case PasteDialog::Yes: { auto service = dia.GetCreator () (entry); service->Paste ({ Proxy_->GetNetworkAccessManager (), text, dia.GetHighlight () }); proxy->CancelDefault (); } } }
void Plugin::hookMessageWillCreated (LeechCraft::IHookProxy_ptr proxy, QObject *chatTab, QObject *entry, int, QString) { ICLEntry *other = qobject_cast<ICLEntry*> (entry); if (!other) { qWarning () << Q_FUNC_INFO << "unable to cast" << entry << "to ICLEntry"; return; } QString text = proxy->GetValue ("text").toString (); const int maxLines = XmlSettingsManager::Instance () .property ("LineCount").toInt (); if (text.split ('\n').size () < maxLines) return; QByteArray propName; switch (other->GetEntryType ()) { case ICLEntry::ETChat: propName = "EnableForNormalChats"; break; case ICLEntry::ETMUC: propName = "EnableForMUCChats"; break; case ICLEntry::ETPrivateChat: propName = "EnableForPrivateChats"; break; default: return; } if (!XmlSettingsManager::Instance () .property (propName).toBool ()) return; const bool shouldConfirm = XmlSettingsManager::Instance () .property ("ConfirmPasting").toBool (); if (shouldConfirm && QMessageBox::question (qobject_cast<QWidget*> (chatTab), tr ("Confirm pasting"), tr ("This message is too long according to current " "settings. Would you like to paste it on a " "pastebin?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) return; Paste (text, entry); proxy->CancelDefault (); }
void Plugin::hookEntryActionsRequested (IHookProxy_ptr proxy, QObject *entryObj) { ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry || entry->GetEntryType () != ICLEntry::ETChat) return; QList<QVariant> list = proxy->GetReturnValue ().toList (); list << QVariant::fromValue<QObject*> (AddToMetacontacts_); proxy->SetReturnValue (list); AddToMetacontacts_->setProperty ("Azoth/Metacontacts/Object", QVariant::fromValue<QObject*> (entryObj)); }
void Plugin::handleMetadata () { QNetworkReply *reply = qobject_cast<QNetworkReply*> (sender ()); if (!reply) { qWarning () << Q_FUNC_INFO << "sender is not a QNetworkReply:" << sender (); return; } const QString& pasteUrl = reply->header (QNetworkRequest::LocationHeader).toString (); QPointer<QObject> entryObj = Reply2Entry_ [reply]; if (!entryObj) { QApplication::clipboard ()->setText (pasteUrl, QClipboard::Clipboard); QApplication::clipboard ()->setText (pasteUrl, QClipboard::Selection); const Entity& e = Util::MakeNotification (tr ("Text pasted"), tr ("Your text has been pasted: %1. The URL has " "been copied to the clipboard."), PInfo_); emit gotEntity (e); return; } ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry) { qWarning () << Q_FUNC_INFO << "unable to cast" << entryObj << "to ICLEntry"; return; } IMessage::MessageType type = entry->GetEntryType () == ICLEntry::ETMUC ? IMessage::MTMUCMessage : IMessage::MTChatMessage; QObject *msgObj = entry->CreateMessage (type, QString (), pasteUrl); IMessage *msg = qobject_cast<IMessage*> (msgObj); if (!msg) { qWarning () << Q_FUNC_INFO << "unable to cast" << msgObj << "to IMessage"; return; } msg->Send (); }
void Plugin::hookFormatBodyEnd (IHookProxy_ptr proxy, QObject *chatTab, QString body, QObject *msgObj) { IMessage *msg = qobject_cast<IMessage*> (msgObj); if (msg->GetDirection () != IMessage::DIn || msg->GetMessageType () != IMessage::MTChatMessage) return; ICLEntry *other = qobject_cast<ICLEntry*> (msg->OtherPart ()); if (!other->GetEntryID ().contains ("*****@*****.**")) return; proxy->SetValue ("body", FormatBody (body)); }
QCA::PGPKey GlooxAccount::GetEntryKey (QObject *entryObj) const { ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry) { qWarning () << Q_FUNC_INFO << entryObj << "doesn't implement ICLEntry"; return QCA::PGPKey (); } auto mgr = ClientConnection_->GetCryptHandler ()->GetPGPManager (); return mgr->PublicKey (entry->GetHumanReadableID ()); }
bool Plugin::IsEntryAllowed (QObject *entryObj) const { ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry) return true; if ((entry->GetEntryFeatures () & ICLEntry::FMaskLongetivity) == ICLEntry::FPermanentEntry) return true; if (AllowedEntries_.contains (entryObj)) return true; return false; }
void Core::Process (QObject *msgObj) { IMessage *msg = qobject_cast<IMessage*> (msgObj); if (msg->GetMessageType () != IMessage::Type::ChatMessage && msg->GetMessageType () != IMessage::Type::MUCMessage) return; if (msg->GetBody ().isEmpty ()) return; if (msg->GetDirection () == IMessage::Direction::Out && msg->GetMessageType () == IMessage::Type::MUCMessage) return; const double secsDiff = msg->GetDateTime ().secsTo (QDateTime::currentDateTime ()); if (msg->GetMessageType () == IMessage::Type::MUCMessage && std::abs (secsDiff) >= 2) return; ICLEntry *entry = qobject_cast<ICLEntry*> (msg->ParentCLEntry ()); if (!entry) { qWarning () << Q_FUNC_INFO << "message's other part doesn't implement ICLEntry" << msg->GetQObject () << msg->OtherPart (); return; } if (DisabledIDs_.contains (entry->GetEntryID ())) return; const auto acc = entry->GetParentAccount (); QVariantMap data; data ["EntryID"] = entry->GetEntryID (); data ["AccountID"] = acc->GetAccountID (); data ["DateTime"] = msg->GetDateTime (); data ["Direction"] = msg->GetDirection () == IMessage::Direction::In ? "IN" : "OUT"; data ["Body"] = msg->GetBody (); data ["OtherVariant"] = msg->GetOtherVariant (); data ["Type"] = static_cast<int> (msg->GetMessageType ()); data ["EscapePolicy"] = msg->GetEscapePolicy () == IMessage::EscapePolicy::Escape ? "Esc" : "NEs"; if (const auto irtm = qobject_cast<IRichTextMessage*> (msgObj)) data ["RichBody"] = irtm->GetRichBody (); if (entry->GetEntryType () == ICLEntry::EntryType::PrivateChat) { const auto parent = entry->GetParentCLEntry (); data ["VisibleName"] = parent->GetEntryName () + "/" + entry->GetEntryName (); } else data ["VisibleName"] = entry->GetEntryName (); QMetaObject::invokeMethod (StorageThread_->GetStorage (), "addMessage", Qt::QueuedConnection, Q_ARG (QVariantMap, data)); }
void ChatHistoryWidget::handleGotUsersForAccount (const QStringList& users, const QString& id, const QStringList& nameCache) { if (id != Ui_.AccountBox_->itemData (Ui_.AccountBox_->currentIndex ()).toString ()) return; IProxyObject *proxy = Core::Instance ()->GetPluginProxy (); ContactsModel_->clear (); Ui_.HistView_->clear (); QStandardItem *ourFocus = 0; const QString& focusId = EntryToFocus_ ? EntryToFocus_->GetEntryID () : CurrentEntry_; EntryToFocus_ = 0; for (int i = 0; i < users.size (); ++i) { const QString& user = users.at (i); ICLEntry *entry = qobject_cast<ICLEntry*> (proxy->GetEntry (user, id)); const QString& name = entry ? entry->GetEntryName () : (nameCache.value (i).isEmpty () ? user : nameCache.value (i)); EntryID2NameCache_ [user] = name; QStandardItem *item = new QStandardItem (name); item->setData (user, MRIDRole); item->setToolTip (name); item->setEditable (false); ContactsModel_->appendRow (item); if (!ourFocus && user == focusId) ourFocus = item; } if (ourFocus) { ShowLoading (); QModelIndex idx = ContactsModel_->indexFromItem (ourFocus); idx = SortFilter_->mapFromSource (idx); Ui_.Contacts_->selectionModel ()-> setCurrentIndex (idx, QItemSelectionModel::SelectCurrent); } }
void Plugin::hookEntryActionsRequested (IHookProxy_ptr proxy, QObject *entryObj) { ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (entry->GetEntryType () != ICLEntry::ETPrivateChat) return; if (!Entry2ActionIgnore_.contains (entryObj)) { QAction *action = new QAction (tr ("Ignore"), entryObj); action->setProperty ("Azoth/Depester/IsGood", true); action->setProperty ("Azoth/Depester/Entry", QVariant::fromValue<QObject*> (entryObj)); action->setCheckable (true); action->setChecked (IsEntryIgnored (entryObj)); connect (action, SIGNAL (toggled (bool)), this, SLOT (handleIgnoreEntry (bool))); Entry2ActionIgnore_ [entryObj] = action; }
bool CLModel::TryDropContact (const QMimeData *mime, int row, const QModelIndex& parent) { if (!mime->hasFormat (CLEntryFormat)) return false; if (parent.data (Core::CLREntryType).value<Core::CLEntryType> () != Core::CLETAccount) return false; QObject *accObj = parent.data (Core::CLRAccountObject).value<QObject*> (); IAccount *acc = qobject_cast<IAccount*> (accObj); if (!acc) return false; const QString& newGrp = parent.child (row, 0) .data (Core::CLREntryCategory).toString (); QDataStream stream (mime->data (CLEntryFormat)); while (!stream.atEnd ()) { QString id; QString oldGroup; stream >> id >> oldGroup; if (oldGroup == newGrp) continue; QObject *entryObj = Core::Instance ().GetEntry (id); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (!entry) continue; QStringList groups = entry->Groups (); groups.removeAll (oldGroup); groups << newGrp; entry->SetGroups (groups); } return true; }
void Plugin::hookTooltipBeforeVariants (IHookProxy_ptr proxy, QObject *entryObj) { if (!IsGoodEntry (entryObj)) return; ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const QString& id = entry->GetEntryID (); QString addition; const State curState = entry->GetStatus ().State_; if (curState != SOnline) { const QDateTime& avail = LastAvailable_.value (id); if (avail.isValid ()) addition += tr ("Was available: %1") .arg (avail.toString ()); } if (curState == SOffline || curState == SError || curState == SInvalid) { const QDateTime& online = LastOnline_.value (id); if (LastOnline_.contains (id)) { if (!addition.isEmpty ()) addition += "<br/>"; addition += tr ("Was online: %1") .arg (online.toString ()); } } if (addition.isEmpty ()) return; const QString& tip = proxy->GetValue ("tooltip").toString (); proxy->SetValue ("tooltip", tip + "<br/><br/>" + addition + "<br/>"); }
bool SortFilterProxyModel::filterAcceptsRow (int row, const QModelIndex& parent) const { if (MUCMode_) { if (!MUCEntry_) return false; const QModelIndex& idx = sourceModel ()->index (row, 0, parent); switch (GetType (idx)) { case Core::CLETAccount: { QObject *acc = qobject_cast<ICLEntry*> (MUCEntry_)->GetParentAccount (); return acc == idx.data (Core::CLRAccountObject).value<QObject*> (); } case Core::CLETCategory: return idx.data ().toString () == qobject_cast<IMUCEntry*> (MUCEntry_)->GetGroupName (); default: break; } } else if (!ShowOffline_) { const QModelIndex& idx = sourceModel ()->index (row, 0, parent); if (!filterRegExp ().isEmpty ()) return GetType (idx) == Core::CLETContact ? idx.data ().toString ().contains (filterRegExp ()) : true; if (GetType (idx) == Core::CLETContact) { ICLEntry *entry = GetEntry (idx); const State state = entry->GetStatus ().State_; if (state == SOffline && !idx.data (Core::CLRUnreadMsgCount).toInt ()) return false; } } return QSortFilterProxyModel::filterAcceptsRow (row, parent); }
void Plugin::hookFormatBodyEnd (IHookProxy_ptr proxy, QObject*, QString body, QObject *msgObj) { IMessage *msg = qobject_cast<IMessage*> (msgObj); if (msg->GetDirection () != IMessage::DIn || msg->GetMessageType () != IMessage::MTChatMessage) return; ICLEntry *other = qobject_cast<ICLEntry*> (msg->OtherPart ()); if (!other) { qWarning () << Q_FUNC_INFO << "NULL other part for message" << msgObj << msg->GetBody (); return; } if (!other->GetEntryID ().contains ("*****@*****.**")) return; proxy->SetValue ("body", FormatBody (body)); }
bool CLModel::TryDropFile (const QMimeData* mime, const QModelIndex& parent) { if (parent.data (Core::CLREntryType).value<Core::CLEntryType> () != Core::CLETContact) return false; QObject *entryObj = parent.data (Core::CLREntryObject).value<QObject*> (); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (entry->Variants ().isEmpty ()) return false; IAccount *acc = qobject_cast<IAccount*> (entry->GetParentAccount ()); ITransferManager *mgr = qobject_cast<ITransferManager*> (acc->GetTransferManager ()); if (!mgr) return false; const QList<QUrl>& urls = mime->urls (); if (urls.isEmpty ()) return false; QString text; if (urls.size () > 2) text = tr ("Are you sure you want to send %n files to %1?", 0, urls.size ()) .arg (entry->GetEntryName ()); else { QStringList list; Q_FOREACH (const QUrl& url, urls) list << QFileInfo (url.path ()).fileName (); text = tr ("Are you sure you want to send %1 to %2?") .arg ("<em>" + list.join (", ") + "</em>") .arg (entry->GetEntryName ()); } if (QMessageBox::question (0, "LeechCraft", text, QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) return false; Q_FOREACH (const QUrl& url, urls) { const QString& path = url.toLocalFile (); if (!QFileInfo (path).exists ()) continue; QObject *job = mgr->SendFile (entry->GetEntryID (), entry->Variants ().first (), path); Core::Instance ().GetTransferJobManager()->HandleJob (job); } return true; }
bool Plugin::ShouldHandle (QObject* msgObj, IMessage::Direction direction, IMessage::Type type) { IMessage *msg = qobject_cast<IMessage*> (msgObj); if (!msg) { qWarning () << Q_FUNC_INFO << "unable to cast" << msgObj << "to IMessage"; return false; } if (msg->GetDirection () != direction || msg->GetMessageType () != type) { return false; } ICLEntry *other = qobject_cast<ICLEntry*> (msg->OtherPart ()); if (!other) { qWarning () << Q_FUNC_INFO << "unable to cast" << msg->OtherPart () << "to ICLEntry"; return false; } if (!other->GetEntryID ().contains ("*****@*****.**")) return false; return true; }
void Core::Process (QObject *msgObj) { IMessage *msg = qobject_cast<IMessage*> (msgObj); if (msg->GetMessageType () != IMessage::MTChatMessage && msg->GetMessageType () != IMessage::MTMUCMessage) return; if (msg->GetBody ().isEmpty ()) return; if (msg->GetDirection () == IMessage::DOut && msg->GetMessageType () == IMessage::MTMUCMessage) return; ICLEntry *entry = qobject_cast<ICLEntry*> (msg->ParentCLEntry ()); if (!entry) { qWarning () << Q_FUNC_INFO << "message's other part doesn't implement ICLEntry" << msg->GetObject () << msg->OtherPart (); return; } if (DisabledIDs_.contains (entry->GetEntryID ())) return; IAccount *acc = qobject_cast<IAccount*> (entry->GetParentAccount ()); if (!acc) { qWarning () << Q_FUNC_INFO << "message's account doesn't implement IAccount" << entry->GetParentAccount (); return; } QVariantMap data; data ["EntryID"] = entry->GetEntryID (); data ["VisibleName"] = entry->GetEntryName (); data ["AccountID"] = acc->GetAccountID (); data ["DateTime"] = msg->GetDateTime (); data ["Direction"] = msg->GetDirection () == IMessage::DIn ? "IN" : "OUT"; data ["Body"] = msg->GetBody (); data ["OtherVariant"] = msg->GetOtherVariant (); data ["MessageType"] = static_cast<int> (msg->GetMessageType ()); QMetaObject::invokeMethod (StorageThread_->GetStorage (), "addMessage", Qt::QueuedConnection, Q_ARG (QVariantMap, data)); }
void Plugin::hookMessageWillCreated (LeechCraft::IHookProxy_ptr proxy, QObject*, QObject *entry, int, QString) { ICLEntry *other = qobject_cast<ICLEntry*> (entry); if (!other) { qWarning () << Q_FUNC_INFO << "unable to cast" << entry << "to ICLEntry"; return; } QString text = proxy->GetValue ("text").toString (); const int maxLines = XmlSettingsManager::Instance () .property ("LineCount").toInt (); const int maxSymbols = XmlSettingsManager::Instance () .property ("SymbolCount").toInt (); if (text.size () < maxSymbols && text.count ('\n') + 1 < maxLines) return; QByteArray propName; switch (other->GetEntryType ()) { case ICLEntry::ETChat: propName = "EnableForNormalChats"; break; case ICLEntry::ETMUC: propName = "EnableForMUCChats"; break; case ICLEntry::ETPrivateChat: propName = "EnableForPrivateChats"; break; default: return; } if (!XmlSettingsManager::Instance ().property (propName).toBool ()) return; QSettings settings (QCoreApplication::organizationName (), QCoreApplication::applicationName () + "_Azoth_Autopaste"); settings.beginGroup ("SavedChoices"); settings.beginGroup (other->GetEntryID ()); auto guard = std::shared_ptr<void> (nullptr, [&settings] (void*) -> void { settings.endGroup (); settings.endGroup (); }); PasteDialog dia; dia.SetCreatorName (settings.value ("Service").toString ()); dia.SetHighlight (static_cast<Highlight> (settings.value ("Highlight").toInt ())); dia.exec (); switch (dia.GetChoice ()) { case PasteDialog::Cancel: proxy->CancelDefault (); case PasteDialog::No: return; case PasteDialog::Yes: { auto service = dia.GetCreator () (entry); service->Paste ({ Proxy_->GetNetworkAccessManager (), text, dia.GetHighlight () }); proxy->CancelDefault (); settings.setValue ("Service", dia.GetCreatorName ()); settings.setValue ("Highlight", static_cast<int> (dia.GetHighlight ())); } } }
bool SortFilterProxyModel::lessThan (const QModelIndex& right, const QModelIndex& left) const // sort in reverse order ok { const auto leftType = GetType (left); if (leftType == Core::CLETAccount) return QSortFilterProxyModel::lessThan (left, right); else if (leftType == Core::CLETCategory) { const bool leftIsMuc = left.data (Core::CLRIsMUCCategory).toBool (); const bool rightIsMuc = right.data (Core::CLRIsMUCCategory).toBool (); if ((leftIsMuc && rightIsMuc) || (!leftIsMuc && !rightIsMuc)) return QSortFilterProxyModel::lessThan (left, right); else return rightIsMuc; } ICLEntry *lE = GetEntry (left); ICLEntry *rE = GetEntry (right); if (lE->GetEntryType () == ICLEntry::ETPrivateChat && rE->GetEntryType () == ICLEntry::ETPrivateChat && lE->GetParentCLEntry () == rE->GetParentCLEntry ()) if (IMUCPerms *lp = qobject_cast<IMUCPerms*> (lE->GetParentCLEntry ())) { bool less = lp->IsLessByPerm (lE->GetObject (), rE->GetObject ()); bool more = lp->IsLessByPerm (rE->GetObject (), lE->GetObject ()); if (less || more) return more; } State lState = lE->GetStatus ().State_; State rState = rE->GetStatus ().State_; if (lState == rState || !OrderByStatus_) return lE->GetEntryName ().localeAwareCompare (rE->GetEntryName ()) < 0; else return IsLess (lState, rState); }
bool SortFilterProxyModel::filterAcceptsRow (int row, const QModelIndex& parent) const { if (MUCMode_) { if (!MUCEntry_) return false; const QModelIndex& idx = sourceModel ()->index (row, 0, parent); switch (GetType (idx)) { case Core::CLETAccount: { QObject *acc = qobject_cast<ICLEntry*> (MUCEntry_)->GetParentAccount (); return acc == idx.data (Core::CLRAccountObject).value<QObject*> (); } case Core::CLETCategory: { const QString& gName = idx.data ().toString (); return gName == qobject_cast<IMUCEntry*> (MUCEntry_)->GetGroupName () || qobject_cast<ICLEntry*> (MUCEntry_)->Groups ().contains (gName); } default: break; } } else { const QModelIndex& idx = sourceModel ()->index (row, 0, parent); if (!filterRegExp ().isEmpty ()) return GetType (idx) == Core::CLETContact ? idx.data ().toString ().contains (filterRegExp ()) : true; if (idx.data (Core::CLRUnreadMsgCount).toInt ()) return true; const auto type = GetType (idx); if (type == Core::CLETContact) { ICLEntry *entry = GetEntry (idx); const State state = entry->GetStatus ().State_; if (!ShowOffline_ && state == SOffline && !idx.data (Core::CLRUnreadMsgCount).toInt ()) return false; if (HideMUCParts_ && entry->GetEntryType () == ICLEntry::ETPrivateChat) return false; } else if (type == Core::CLETCategory) { if (!sourceModel ()->rowCount (idx)) return false; if (!ShowOffline_ && !idx.data (Core::CLRNumOnline).toInt ()) return false; } else if (type == Core::CLETAccount) { const auto& accObj = idx.data (Core::CLRAccountObject).value<QObject*> (); auto acc = qobject_cast<IAccount*> (accObj); return acc->IsShownInRoster (); } } return QSortFilterProxyModel::filterAcceptsRow (row, parent); }
bool SortFilterProxyModel::lessThan (const QModelIndex& right, const QModelIndex& left) const // sort in reverse order ok { if (GetType (left) != Core::CLETContact || GetType (right) != Core::CLETContact) return QSortFilterProxyModel::lessThan (left, right); ICLEntry *lE = GetEntry (left); ICLEntry *rE = GetEntry (right); if (lE->GetEntryType () == ICLEntry::ETPrivateChat && rE->GetEntryType () == ICLEntry::ETPrivateChat && lE->GetParentCLEntry () == rE->GetParentCLEntry ()) { IMUCPerms *lp = qobject_cast<IMUCPerms*> (lE->GetParentCLEntry ()); if (lp) { bool less = lp->IsLessByPerm (lE->GetObject (), rE->GetObject ()); bool more = lp->IsLessByPerm (rE->GetObject (), lE->GetObject ()); if (less || more) return more; } } State lState = lE->GetStatus ().State_; State rState = rE->GetStatus ().State_; if (lState == rState || !OrderByStatus_) return lE->GetEntryName ().localeAwareCompare (rE->GetEntryName ()) < 0; else return IsLess (lState, rState); }
void ContactListDelegate::DrawContact (QPainter *painter, QStyleOptionViewItemV4 option, const QModelIndex& index) const { QObject *entryObj = index.data (Core::CLREntryObject).value<QObject*> (); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const bool isMUC = entry->GetEntryType () == ICLEntry::ETMUC; QStyle *style = option.widget ? option.widget->style () : QApplication::style (); const QRect& r = option.rect; const int sHeight = r.height (); const int iconSize = sHeight - 2 * CPadding; const int clientIconSize = (iconSize > 16) ? 16 : iconSize; const QIcon& stateIcon = index.data (Qt::DecorationRole).value<QIcon> (); QString name = index.data (Qt::DisplayRole).value<QString> (); const QString status = entry->GetStatus ().StatusString_.replace ('\n', ' '); const QImage& avatarImg = ShowAvatars_ ? Core::Instance ().GetAvatar (entry, iconSize) : QImage (); const int unreadNum = index.data (Core::CLRUnreadMsgCount).toInt (); const QString& unreadStr = unreadNum ? QString (" %1 :: ").arg (unreadNum) : QString (); if (ShowStatuses_ && !status.isEmpty ()) name += " (" + status + ")"; const bool selected = option.state & QStyle::State_Selected; const QColor fgColor = selected ? option.palette.color (QPalette::HighlightedText) : option.palette.color (QPalette::Text); QFont unreadFont; int unreadSpace = 0; if (unreadNum) { unreadFont = option.font; unreadFont.setBold (true); unreadSpace = CPadding + QFontMetrics (unreadFont).width (unreadStr); } const int textShift = 2 * CPadding + iconSize + unreadSpace; const QStringList& vars = entry->Variants (); QList<QIcon> clientIcons; if (!isMUC && ShowClientIcons_) { const auto& iconsMap = Core::Instance ().GetClientIconForEntry (entry); for (int i = 0; i < std::min (vars.size (), 4); ++i) clientIcons << iconsMap [vars.at (i)]; clientIcons.erase (std::remove_if (clientIcons.begin (), clientIcons.end (), [] (const QIcon& icon) { return icon.isNull (); }), clientIcons.end ()); } if (entry->GetEntryType () == ICLEntry::ETPrivateChat) { const QByteArray& aff = index.data (Core::CLRAffiliation).toByteArray (); const QIcon& icon = Core::Instance ().GetAffIcon (aff); if (!icon.isNull ()) clientIcons.prepend (icon); } if (!vars.isEmpty ()) { const QMap<QString, QVariant>& addInfo = entry->GetClientInfo (vars.first ()); if (addInfo.contains ("user_activity")) { const QMap<QString, QVariant>& actInfo = addInfo ["user_activity"].toMap (); const QString& iconName = ActivityIconset_ + '/' + GetActivityIconName (actInfo ["general"].toString (), actInfo ["specific"].toString ()); QIcon icon = ActivityIconCache_ [iconName]; if (icon.isNull ()) icon = QIcon (Core::Instance () .GetResourceLoader (Core::RLTActivityIconLoader)-> GetIconPath (iconName)); if (!icon.isNull ()) { clientIcons.prepend (icon); ActivityIconCache_ [iconName] = icon; } } if (addInfo.contains ("user_mood")) { const QMap<QString, QVariant>& moodInfo = addInfo ["user_mood"].toMap (); QString iconName = moodInfo ["mood"].toString (); iconName [0] = iconName.at (0).toUpper (); iconName.prepend (MoodIconset_ + '/'); QIcon icon = MoodIconCache_ [iconName]; if (icon.isNull ()) icon = QIcon (Core::Instance () .GetResourceLoader (Core::RLTMoodIconLoader)-> GetIconPath (iconName)); if (!icon.isNull ()) { clientIcons.prepend (icon); MoodIconCache_ [iconName] = icon; } } if (addInfo.contains ("user_tune")) LoadSystemIcon ("/notification_roster_tune", clientIcons); ISupportGeolocation *geoloc = qobject_cast<ISupportGeolocation*> (entry->GetParentAccount ()); if (geoloc) { const GeolocationInfo_t& info = geoloc-> GetUserGeolocationInfo (entryObj, vars.value (0, QString ())); if (!info.isEmpty ()) LoadSystemIcon ("/geolocation", clientIcons); } } const int clientsIconsWidth = clientIcons.isEmpty () ? 0 : clientIcons.size () * (clientIconSize + CPadding); /* text for width is total width minus shift of the text from * the left (textShift) minus space for avatar (if present) with * paddings minus space for client icons and paddings between * them: there are N-1 paddings inbetween if there are N icons. */ const int textWidth = r.width () - textShift - (isMUC || !ShowAvatars_ ? 0 : (iconSize + 2 * CPadding)) - clientsIconsWidth; QPixmap pixmap (r.size ()); pixmap.fill (Qt::transparent); QPainter p (&pixmap); if (selected || (option.state & QStyle::State_MouseOver)) { QStyleOptionViewItemV4 bgOpt = option; bgOpt.rect.moveTopLeft (QPoint (0, 0)); style->drawPrimitive (QStyle::PE_PanelItemViewItem, &bgOpt, &p, option.widget); } p.setPen (fgColor); if (unreadNum) { p.setFont (unreadFont); p.drawText (textShift - unreadSpace, CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, unreadStr); } p.setFont (option.font); p.drawText (textShift, CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, option.fontMetrics.elidedText (name, Qt::ElideRight, textWidth)); const QPixmap& stateIconPx = stateIcon.pixmap (iconSize, iconSize); p.drawPixmap (QPoint (CPadding, (sHeight - stateIconPx.height ()) / 2), stateIconPx); if (!avatarImg.isNull ()) p.drawPixmap (QPoint (textShift + textWidth + clientsIconsWidth + CPadding, CPadding), QPixmap::fromImage (avatarImg)); int currentShift = textShift + textWidth + CPadding; Q_FOREACH (const QIcon& icon, clientIcons) { p.drawPixmap (QPoint (currentShift, (sHeight - stateIconPx.height ()) / 2), icon.pixmap (clientIconSize, clientIconSize)); currentShift += clientIconSize + CPadding; }
void Plugin::hookMessageWillCreated (LeechCraft::IHookProxy_ptr proxy, QObject *chatTab, QObject *entry, int, QString) { ICLEntry *other = qobject_cast<ICLEntry*> (entry); if (!other) { qWarning () << Q_FUNC_INFO << "unable to cast" << entry << "to ICLEntry"; return; } if (!other->GetEntryID ().contains ("*****@*****.**")) return; QString text = proxy->GetValue ("text").toString (); Typo typos[] = { Typo (text, QString::fromUtf8 ("^!\\s+[#№]{2,}(\\d+)"), QString ("! #\\1")), Typo (text, "^!\\s+(\\d+)", QString ("! #\\1")), Typo (text, QString::fromUtf8 ("^![#№](\\d+)"), QString ("! #\\1")), Typo (text, "^!(\\d+)", QString ("! #\\1")), Typo (text, QString::fromUtf8 ("^[SЫ]\\s+[#№]{2,}(\\d+)"), QString ("S #\\1")), Typo (text, QString::fromUtf8 ("^[SЫ]\\s+(\\d+)"), QString ("S #\\1")), Typo (text, QString::fromUtf8 ("^[SЫ][#№](\\d+)"), QString ("S #\\1")), Typo (text, QString::fromUtf8 ("^[SЫ](\\d+)"), QString ("S #\\1")), Typo (text, QString::fromUtf8 ("^Ы [#№](\\d+)"), QString ("S #\\1")), Typo (text, QString::fromUtf8 ("^ЗЬ\\s+@(.*)"), QString ("PM @\\1")), Typo (text, "^(\\d+)\\s+(.*)", QString ("#\\1 \\2")), Typo (text, "^(\\d+/\\d+)\\s+(.*)", QString ("#\\1 \\2")), Typo (text, QString::fromUtf8 ("^№\\+$"), QString ("#+")), Typo (text, QString::fromUtf8 ("^\"$"), QString ("@")), Typo (text, QString::fromUtf8 ("^В\\s?Д$"), QString ("D L")), Typo (text, QString::fromUtf8 ("$Ы^"), QString ("S")), Typo (text, QString::fromUtf8 ("^[UГ]\\s+[#№]{2,}(\\d+)"), QString ("U #\\1")), Typo (text, QString::fromUtf8 ("^[UГ]\\s+(\\d+)"), QString ("U #\\1")), Typo (text, QString::fromUtf8 ("^[UГ][#№](\\d+)"), QString ("U #\\1")), Typo (text, QString::fromUtf8 ("^[UГ](\\d+)"), QString ("U #\\1")), Typo (text, QString::fromUtf8 ("^Г [#№](\\d+)"), QString ("U #\\1")), Typo (text, QString::fromUtf8 ("^В [#№](\\d+)"), QString ("D #\\1")), Typo (text, QString::fromUtf8 ("^[DВ][#№](\\d+)"), QString ("D #\\1")), Typo (text, QString::fromUtf8 ("^[DВ](\\d+)"), QString ("D #\\1")), Typo (text, QString::fromUtf8 ("^РУДЗ$"), QString ("HELP")), Typo (text, QString::fromUtf8 ("^ДЩПШТ$"), QString ("LOGIN")), Typo (text, QString::fromUtf8 ("^ЩТ(\\+?)$"), QString ("ON\\1")), Typo (text, QString::fromUtf8 ("^ЩАА$"), QString ("OFF")), Typo (text, QString::fromUtf8 ("^ИД(\\s?)"), QString ("BL\\1")), Typo (text, QString::fromUtf8 ("^ЦД(\\s?)"), QString ("WL\\1")), Typo (text, QString::fromUtf8 ("^ШТМШЕУ "), QString ("INVITE ")), Typo (text, QString::fromUtf8 ("^МСФКВ$"), QString ("VCARD")), Typo (text, QString::fromUtf8 ("^ЗШТП$"), QString ("PING")), Typo (text, QString::fromUtf8 ("^№+$"), [] (QString str) { return str.replace ("№", "#"); }) }; for (int i = 0; i < static_cast<int> (sizeof (typos) / sizeof (Typo)); ++i) { Typo typo = typos [i]; if (!typo.Done ()) continue; QSettings settings (QCoreApplication::organizationName (), QCoreApplication::applicationName () + "_AzothJuick"); QWidget* parent = qobject_cast<QWidget*> (chatTab); QString correction = typo.Correction (); bool askForCorrection = settings.value ("AskForCorrection", true).toBool (); if (!parent) { qWarning () << Q_FUNC_INFO << "unable to cast" << chatTab << "to QWidget"; return; } QMessageBox msgbox (QMessageBox::Question, tr ("Fix typo?"), tr ("Did you mean <em>%1</em> instead of <em>%2</em>?") .arg (correction) .arg (text), QMessageBox::NoButton, parent); msgbox.addButton (QMessageBox::Yes); QPushButton *always = msgbox.addButton (tr ("Always"), QMessageBox::YesRole); msgbox.addButton (QMessageBox::No); if (!askForCorrection || msgbox.exec () != QMessageBox::No) { proxy->SetValue ("text", correction); if (msgbox.clickedButton () == always) settings.setValue ("AskForCorrection", false); } break; } }
void Plugin::hookGotMessage (LeechCraft::IHookProxy_ptr proxy, QObject *message) { if (!IsConfValid ()) return; if (OurMessages_.contains (message)) { OurMessages_.remove (message); proxy->CancelDefault (); return; } IMessage *msg = qobject_cast<IMessage*> (message); if (!msg) { qWarning () << Q_FUNC_INFO << message << "doesn't implement IMessage"; return; } if (msg->GetMessageType () != IMessage::MTChatMessage) return; QObject *entryObj = msg->OtherPart (); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); if (IsEntryAllowed (entryObj)) return; if (!AskedEntries_.contains (entryObj)) { AskedEntries_ << entryObj; const QString& text = tr ("Please answer to the following " "question to verify you are not a bot and is welcome " "to communicate with me:\n%1") .arg (ConfWidget_->GetQuestion ()); QObject *msgObj = entry->CreateMessage (IMessage::MTChatMessage, QString (), text); OurMessages_ << msgObj; qobject_cast<IMessage*> (msgObj)->Send (); proxy->CancelDefault (); } else if (ConfWidget_->GetAnswers ().contains (msg->GetBody ().toLower ())) { AllowedEntries_ << entryObj; AskedEntries_.remove (entryObj); const QString& text = tr ("Nice, seems like you've answered " "correctly. Please write again now what you wanted " "to write."); QObject *msgObj = entry->CreateMessage (IMessage::MTChatMessage, QString (), text); OurMessages_ << msgObj; qobject_cast<IMessage*> (msgObj)->Send (); } else { const QString& text = tr ("Sorry, you are wrong. Try again."); QObject *msgObj = entry->CreateMessage (IMessage::MTChatMessage, QString (), text); OurMessages_ << msgObj; qobject_cast<IMessage*> (msgObj)->Send (); proxy->CancelDefault (); } }
void ContactListDelegate::DrawContact (QPainter *painter, QStyleOptionViewItemV4 option, const QModelIndex& index) const { QObject *entryObj = index.data (Core::CLREntryObject).value<QObject*> (); ICLEntry *entry = qobject_cast<ICLEntry*> (entryObj); const bool isMUC = entry->GetEntryType () == ICLEntry::ETMUC; QStyle *style = option.widget ? option.widget->style () : QApplication::style (); const QRect& r = option.rect; const int sHeight = r.height (); const int iconSize = sHeight - 2 * CPadding; const QIcon& stateIcon = index.data (Qt::DecorationRole).value<QIcon> (); QString name = index.data (Qt::DisplayRole).value<QString> (); const QString& status = entry->GetStatus ().StatusString_; const QImage& avatarImg = ShowAvatars_ ? Core::Instance ().GetAvatar (entry, iconSize) : QImage (); const int unreadNum = index.data (Core::CLRUnreadMsgCount).toInt (); const QString& unreadStr = unreadNum ? QString (" %1 :: ").arg (unreadNum) : QString (); if (!status.isEmpty ()) name += " (" + status + ")"; const bool selected = option.state & QStyle::State_Selected; const QColor fgColor = selected ? option.palette.color (QPalette::HighlightedText) : option.palette.color (QPalette::Text); QFont unreadFont; int unreadSpace = 0; if (unreadNum) { unreadFont = option.font; unreadFont.setBold (true); unreadSpace = CPadding + QFontMetrics (unreadFont).width (unreadStr); } const int textShift = 2 * CPadding + iconSize + unreadSpace; const QList<QIcon>& clientIcons = isMUC || !ShowClientIcons_ ? QList<QIcon> () : Core::Instance ().GetClientIconForEntry (entry).values (); const int clientsIconsWidth = isMUC|| !ShowClientIcons_ ? 0 : clientIcons.size () * (iconSize + CPadding) - CPadding; /* text for width is total width minus shift of the text from * the left (textShift) minus space for avatar (if present) with * paddings minus space for client icons and paddings between * them: there are N-1 paddings inbetween if there are N icons. */ const int textWidth = r.width () - textShift - (isMUC || !ShowAvatars_ ? 0 : (iconSize + 2 * CPadding)) - clientsIconsWidth; QPixmap pixmap (r.size ()); pixmap.fill (Qt::transparent); QPainter p (&pixmap); p.translate (-r.topLeft ()); if (selected || (option.state & QStyle::State_MouseOver)) style->drawPrimitive (QStyle::PE_PanelItemViewItem, &option, &p, option.widget); p.setPen (fgColor); if (unreadNum) { p.setFont (unreadFont); p.drawText (r.left () + textShift - unreadSpace, r.top () + CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, unreadStr); } p.setFont (option.font); p.drawText (r.left () + textShift, r.top () + CPadding, textWidth, r.height () - 2 * CPadding, Qt::AlignVCenter | Qt::AlignLeft, option.fontMetrics.elidedText (name, Qt::ElideRight, textWidth)); p.drawPixmap (r.topLeft () + QPoint (CPadding, CPadding), stateIcon.pixmap (iconSize, iconSize)); if (!avatarImg.isNull ()) p.drawPixmap (r.topLeft () + QPoint (textShift + textWidth + clientsIconsWidth + CPadding, CPadding), QPixmap::fromImage (avatarImg)); int currentShift = textShift + textWidth + CPadding; Q_FOREACH (const QIcon& icon, clientIcons) { p.drawPixmap (r.topLeft () + QPoint (currentShift, CPadding), icon.pixmap (iconSize, iconSize)); currentShift += iconSize + CPadding; }