/** * @file llconversationloglist.cpp * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llavataractions.h" #include "llagent.h" #include "llfloaterreg.h" #include "llfloaterconversationpreview.h" #include "llgroupactions.h" #include "llconversationloglist.h" #include "llconversationloglistitem.h" #include "llviewermenu.h" #include "lltrans.h" static LLDefaultChildRegistry::Register r("conversation_log_list"); static LLConversationLogListNameComparator NAME_COMPARATOR; static LLConversationLogListDateComparator DATE_COMPARATOR; LLConversationLogList::LLConversationLogList(const Params& p) : LLFlatListViewEx(p), mIsDirty(true) { LLConversationLog::instance().addObserver(this); // Set up context menu. ScopedRegistrarHelper registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar check_registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; registrar.add ("Calllog.Action", boost::bind(&LLConversationLogList::onCustomAction, this, _2), cb_info::UNTRUSTED_BLOCK); check_registrar.add ("Calllog.Check", boost::bind(&LLConversationLogList::isActionChecked,this, _2)); enable_registrar.add("Calllog.Enable", boost::bind(&LLConversationLogList::isActionEnabled,this, _2)); LLToggleableMenu* context_menu = LLUICtrlFactory::getInstance()->createFromFile( "menu_conversation_log_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); if(context_menu) { mContextMenu = context_menu->getHandle(); } mIsFriendsOnTop = gSavedSettings.getBOOL("SortFriendsFirst"); } LLConversationLogList::~LLConversationLogList() { if (mContextMenu.get()) { mContextMenu.get()->die(); } LLConversationLog::instance().removeObserver(this); } void LLConversationLogList::draw() { if (mIsDirty) { refresh(); } LLFlatListViewEx::draw(); } bool LLConversationLogList::handleRightMouseDown(S32 x, S32 y, MASK mask) { bool handled = LLUICtrl::handleRightMouseDown(x, y, mask); LLToggleableMenu* context_menu = mContextMenu.get(); if (context_menu && size()) { context_menu->buildDrawLabels(); context_menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, context_menu, x, y); } return handled; } void LLConversationLogList::setNameFilter(const std::string& filter) { std::string filter_upper = filter; LLStringUtil::toUpper(filter_upper); if (mNameFilter != filter_upper) { mNameFilter = filter_upper; setDirty(); } } bool LLConversationLogList::findInsensitive(std::string haystack, const std::string& needle_upper) { LLStringUtil::toUpper(haystack); return haystack.find(needle_upper) != std::string::npos; } void LLConversationLogList::sortByName() { setComparator(&NAME_COMPARATOR); sort(); } void LLConversationLogList::sortByDate() { setComparator(&DATE_COMPARATOR); sort(); } void LLConversationLogList::toggleSortFriendsOnTop() { mIsFriendsOnTop = !mIsFriendsOnTop; gSavedSettings.setBOOL("SortFriendsFirst", mIsFriendsOnTop); sort(); } void LLConversationLogList::changed() { refresh(); } void LLConversationLogList::changed(const LLUUID& session_id, U32 mask) { LLConversationLogListItem* item = getConversationLogListItem(session_id); if (!item) { return; } if (mask & LLConversationLogObserver::CHANGED_TIME) { item->updateTimestamp(); // if list is sorted by date and a date of some item has changed, // than the whole list should be rebuilt if (E_SORT_BY_DATE == getSortOrder()) { mIsDirty = true; } } else if (mask & LLConversationLogObserver::CHANGED_NAME) { item->updateName(); // if list is sorted by name and a name of some item has changed, // than the whole list should be rebuilt if (E_SORT_BY_DATE == getSortOrder()) { mIsDirty = true; } } else if (mask & LLConversationLogObserver::CHANGED_OfflineIMs) { item->updateOfflineIMs(); } } void LLConversationLogList::addNewItem(const LLConversation* conversation) { LLConversationLogListItem* item = new LLConversationLogListItem(&*conversation); if (!mNameFilter.empty()) { item->highlightNameDate(mNameFilter); } addItem(item, conversation->getSessionID(), ADD_TOP); } void LLConversationLogList::refresh() { rebuildList(); sort(); mIsDirty = false; } void LLConversationLogList::rebuildList() { const LLConversation * selected_conversationp = getSelectedConversation(); clear(); bool have_filter = !mNameFilter.empty(); LLConversationLog &log_instance = LLConversationLog::instance(); const std::vector& conversations = log_instance.getConversations(); std::vector::const_iterator iter = conversations.begin(); for (; iter != conversations.end(); ++iter) { bool not_found = have_filter && !findInsensitive(iter->getConversationName(), mNameFilter) && !findInsensitive(iter->getTimestamp(), mNameFilter); if (not_found) continue; addNewItem(&*iter); } // try to restore selection of item if (NULL != selected_conversationp) { selectItemByUUID(selected_conversationp->getSessionID()); } bool logging_enabled = log_instance.getIsLoggingEnabled(); bool log_empty = log_instance.isLogEmpty(); if (!logging_enabled && log_empty) { setNoItemsCommentText(LLTrans::getString("logging_calls_disabled_log_empty")); } else if (!logging_enabled && !log_empty) { setNoItemsCommentText(LLTrans::getString("logging_calls_disabled_log_not_empty")); } else if (logging_enabled && log_empty) { setNoItemsCommentText(LLTrans::getString("logging_calls_enabled_log_empty")); } else if (logging_enabled && !log_empty) { setNoItemsCommentText(""); } } void LLConversationLogList::onCustomAction(const LLSD& userdata) { const LLConversation * selected_conversationp = getSelectedConversation(); if (NULL == selected_conversationp) { return; } const std::string command_name = userdata.asString(); const LLUUID& selected_conversation_participant_id = selected_conversationp->getParticipantID(); const LLUUID& selected_conversation_session_id = selected_conversationp->getSessionID(); LLIMModel::LLIMSession::SType stype = getSelectedSessionType(); if ("im" == command_name) { switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: LLAvatarActions::startIM(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: LLGroupActions::startIM(selected_conversation_session_id); break; default: break; } } else if ("call" == command_name) { switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: LLAvatarActions::startCall(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: LLGroupActions::startCall(selected_conversation_session_id); break; default: break; } } else if ("view_profile" == command_name) { switch (stype) { case LLIMModel::LLIMSession::P2P_SESSION: LLAvatarActions::showProfile(selected_conversation_participant_id); break; case LLIMModel::LLIMSession::GROUP_SESSION: LLGroupActions::show(selected_conversation_session_id); break; default: break; } } else if ("chat_history" == command_name) { LLFloaterReg::showInstance("preview_conversation", selected_conversation_session_id, true); } else if ("offer_teleport" == command_name) { LLAvatarActions::offerTeleport(selected_conversation_participant_id); } else if ("request_teleport" == command_name) { LLAvatarActions::teleportRequest(selected_conversation_participant_id); } else if("add_friend" == command_name) { if (!LLAvatarActions::isFriend(selected_conversation_participant_id)) { LLAvatarActions::requestFriendshipDialog(selected_conversation_participant_id); } } else if("remove_friend" == command_name) { if (LLAvatarActions::isFriend(selected_conversation_participant_id)) { LLAvatarActions::removeFriendDialog(selected_conversation_participant_id); } } else if ("invite_to_group" == command_name) { LLAvatarActions::inviteToGroup(selected_conversation_participant_id); } else if ("show_on_map" == command_name) { LLAvatarActions::showOnMap(selected_conversation_participant_id); } else if ("share" == command_name) { LLAvatarActions::share(selected_conversation_participant_id); } else if ("pay" == command_name) { LLAvatarActions::pay(selected_conversation_participant_id); } else if ("block" == command_name) { LLAvatarActions::toggleBlock(selected_conversation_participant_id); } } bool LLConversationLogList::isActionEnabled(const LLSD& userdata) { const LLConversation * selected_conversationp = getSelectedConversation(); if (NULL == selected_conversationp || numSelected() > 1) { return false; } const std::string command_name = userdata.asString(); LLIMModel::LLIMSession::SType stype = getSelectedSessionType(); const LLUUID& selected_id = selected_conversationp->getParticipantID(); bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == stype; bool is_group = LLIMModel::LLIMSession::GROUP_SESSION == stype; bool is_group_member = is_group && gAgent.isInGroup(selected_id, true); if ("can_im" == command_name) { return is_p2p || is_group_member; } else if ("can_view_profile" == command_name) { return is_p2p || is_group; } else if ("can_view_chat_history" == command_name) { return true; } else if ("can_call" == command_name) { return (is_p2p || is_group_member) && LLAvatarActions::canCall(); } else if ("add_rem_friend" == command_name || "can_invite_to_group" == command_name || "can_share" == command_name || "can_block" == command_name || "can_pay" == command_name || "report_abuse" == command_name) { return is_p2p; } else if("can_offer_teleport" == command_name) { return is_p2p && LLAvatarActions::canOfferTeleport(selected_id); } else if ("can_show_on_map" == command_name) { return is_p2p && ((LLAvatarTracker::instance().isBuddyOnline(selected_id) && is_agent_mappable(selected_id)) || gAgent.isGodlike()); } return false; } bool LLConversationLogList::isActionChecked(const LLSD& userdata) { const LLConversation * selected_conversationp = getSelectedConversation(); if (NULL == selected_conversationp) { return false; } const std::string command_name = userdata.asString(); const LLUUID& selected_id = selected_conversationp->getParticipantID(); bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == getSelectedSessionType(); if ("is_blocked" == command_name) { return is_p2p && LLAvatarActions::isBlocked(selected_id); } else if ("is_friend" == command_name) { return is_p2p && LLAvatarActions::isFriend(selected_id); } else if ("is_not_friend" == command_name) { return is_p2p && !LLAvatarActions::isFriend(selected_id); } return false; } LLIMModel::LLIMSession::SType LLConversationLogList::getSelectedSessionType() { const LLConversationLogListItem* item = getSelectedConversationPanel(); if (item) { return item->getConversation()->getConversationType(); } return LLIMModel::LLIMSession::NONE_SESSION; } const LLConversationLogListItem* LLConversationLogList::getSelectedConversationPanel() { LLPanel* panel = LLFlatListViewEx::getSelectedItem(); LLConversationLogListItem* conv_panel = dynamic_cast(panel); return conv_panel; } const LLConversation* LLConversationLogList::getSelectedConversation() { const LLConversationLogListItem* panel = getSelectedConversationPanel(); if (panel) { return panel->getConversation(); } return NULL; } LLConversationLogListItem* LLConversationLogList::getConversationLogListItem(const LLUUID& session_id) { std::vector panels; LLFlatListViewEx::getItems(panels); std::vector::iterator iter = panels.begin(); for (; iter != panels.end(); ++iter) { LLConversationLogListItem* item = dynamic_cast(*iter); if (item && session_id == item->getConversation()->getSessionID()) { return item; } } return NULL; } LLConversationLogList::ESortOrder LLConversationLogList::getSortOrder() { return static_cast(gSavedSettings.getU32("CallLogSortOrder")); } bool LLConversationLogListItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const { const LLConversationLogListItem* conversation_item1 = dynamic_cast(item1); const LLConversationLogListItem* conversation_item2 = dynamic_cast(item2); if (!conversation_item1 || !conversation_item2) { LL_ERRS() << "conversation_item1 and conversation_item2 cannot be null" << LL_ENDL; return true; } return doCompare(conversation_item1, conversation_item2); } bool LLConversationLogListNameComparator::doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const { std::string name1 = conversation1->getConversation()->getConversationName(); std::string name2 = conversation2->getConversation()->getConversationName(); const LLUUID& id1 = conversation1->getConversation()->getParticipantID(); const LLUUID& id2 = conversation2->getConversation()->getParticipantID(); LLStringUtil::toUpper(name1); LLStringUtil::toUpper(name2); bool friends_first = gSavedSettings.getBOOL("SortFriendsFirst"); if (friends_first && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2))) { return LLAvatarActions::isFriend(id1); } return name1 < name2; } bool LLConversationLogListDateComparator::doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const { U64Seconds date1 = conversation1->getConversation()->getTime(); U64Seconds date2 = conversation2->getConversation()->getTime(); const LLUUID& id1 = conversation1->getConversation()->getParticipantID(); const LLUUID& id2 = conversation2->getConversation()->getParticipantID(); bool friends_first = gSavedSettings.getBOOL("SortFriendsFirst"); if (friends_first && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2))) { return LLAvatarActions::isFriend(id1); } return date1 > date2; }