diff options
Diffstat (limited to 'indra/newview')
40 files changed, 648 insertions, 374 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b98fea7032..593381cb29 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10105,7 +10105,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>2</integer> + <integer>1</integer> </map> <key>SortFriendsFirst</key> <map> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index be6901c36a..bb0dbc7ff0 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1911,7 +1911,8 @@ void LLAgent::startTyping() { sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START); } - (LLNearbyChat::instance()).sendChatFromViewer("", CHAT_TYPE_START, FALSE); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))-> + sendChatFromViewer("", CHAT_TYPE_START, FALSE); } //----------------------------------------------------------------------------- @@ -1923,7 +1924,8 @@ void LLAgent::stopTyping() { clearRenderState(AGENT_STATE_TYPING); sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP); - (LLNearbyChat::instance()).sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))-> + sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); } } diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index e3d57ab7ae..3636f9e9d2 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -585,7 +585,8 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p) mBottomSeparatorPad(p.bottom_separator_pad), mTopHeaderPad(p.top_header_pad), mBottomHeaderPad(p.bottom_header_pad), - mIsLastMessageFromLog(false) + mIsLastMessageFromLog(false), + mNotifyAboutUnreadMsg(p.notify_unread_msg) { LLTextEditor::Params editor_params(p); editor_params.rect = getLocalRect(); @@ -707,7 +708,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL bool from_me = chat.mFromID == gAgent.getID(); mEditor->setPlainText(use_plain_text_chat_history); - if (!mEditor->scrolledToEnd() && !from_me && !chat.mFromName.empty()) + if (mNotifyAboutUnreadMsg && !mEditor->scrolledToEnd() && !from_me && !chat.mFromName.empty()) { mUnreadChatSources.insert(chat.mFromName); mMoreChatPanel->setVisible(TRUE); diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index 28344e6a10..990c52f31b 100644 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -60,6 +60,8 @@ class LLChatHistory : public LLUICtrl Optional<LLTextBox::Params> more_chat_text; + Optional<bool> notify_unread_msg; + Params() : message_header("message_header"), message_separator("message_separator"), @@ -71,7 +73,8 @@ class LLChatHistory : public LLUICtrl bottom_separator_pad("bottom_separator_pad"), top_header_pad("top_header_pad"), bottom_header_pad("bottom_header_pad"), - more_chat_text("more_chat_text") + more_chat_text("more_chat_text"), + notify_unread_msg("notify_unread_msg", true) {} }; @@ -122,6 +125,7 @@ class LLChatHistory : public LLUICtrl LLUUID mLastFromID; LLDate mLastMessageTime; bool mIsLastMessageFromLog; + bool mNotifyAboutUnreadMsg; //std::string mLastMessageTimeStr; std::string mMessageHeaderFilename; diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index e6340e0fa3..f1b5c42ef3 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -323,12 +323,12 @@ BOOL LLNearbyChatToastPanel::handleMouseUp (S32 x, S32 y, MASK mask) return TRUE; else { - LLNearbyChat::instance().showHistory(); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))->showHistory(); return FALSE; } } - LLNearbyChat::instance().showHistory(); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))->showHistory(); return LLPanel::handleMouseUp(x,y,mask); } diff --git a/indra/newview/llconversationlog.cpp b/indra/newview/llconversationlog.cpp index 7db6a93709..239a89015f 100644 --- a/indra/newview/llconversationlog.cpp +++ b/indra/newview/llconversationlog.cpp @@ -26,15 +26,18 @@ #include "llviewerprecompiledheaders.h" #include "llagent.h" +#include "llavatarnamecache.h" #include "llconversationlog.h" #include "lltrans.h" +const int CONVERSATION_LIFETIME = 30; // lifetime of LLConversation is 30 days by spec + struct Conversation_params { Conversation_params(time_t time) : mTime(time), mTimestamp(LLConversation::createTimestamp(time)), - mIsConversationPast(true) + mIsVoice(false) {} time_t mTime; @@ -45,7 +48,6 @@ struct Conversation_params LLUUID mSessionID; LLUUID mParticipantID; bool mIsVoice; - bool mIsConversationPast; bool mHasOfflineIMs; }; @@ -62,7 +64,6 @@ LLConversation::LLConversation(const Conversation_params& params) mSessionID(params.mSessionID), mParticipantID(params.mParticipantID), mIsVoice(params.mIsVoice), - mIsConversationPast(params.mIsConversationPast), mHasOfflineIMs(params.mHasOfflineIMs) { setListenIMFloaterOpened(); @@ -77,7 +78,6 @@ LLConversation::LLConversation(const LLIMModel::LLIMSession& session) mSessionID(session.mSessionID), mParticipantID(session.mOtherParticipantID), mIsVoice(session.mStartedAsIMCall), - mIsConversationPast(false), mHasOfflineIMs(session.mHasOfflineMessage) { setListenIMFloaterOpened(); @@ -93,7 +93,6 @@ LLConversation::LLConversation(const LLConversation& conversation) mSessionID = conversation.getSessionID(); mParticipantID = conversation.getParticipantID(); mIsVoice = conversation.isVoice(); - mIsConversationPast = conversation.isConversationPast(); mHasOfflineIMs = conversation.hasOfflineMessages(); setListenIMFloaterOpened(); @@ -104,12 +103,10 @@ LLConversation::~LLConversation() mIMFloaterShowedConnection.disconnect(); } -void LLConversation::setIsVoice(bool is_voice) +void LLConversation::updateTimestamp() { - if (mIsConversationPast) - return; - - mIsVoice = is_voice; + mTime = time_corrected(); + mTimestamp = createTimestamp(mTime); } void LLConversation::onIMFloaterShown(const LLUUID& session_id) @@ -138,20 +135,33 @@ const std::string LLConversation::createTimestamp(const time_t& utc_time) return timeStr; } +bool LLConversation::isOlderThan(U32 days) const +{ + time_t now = time_corrected(); + U32 age = (U32)((now - mTime) / SEC_PER_DAY); // age of conversation in days + + return age > days; +} + void LLConversation::setListenIMFloaterOpened() { LLIMFloater* floater = LLIMFloater::findInstance(mSessionID); bool has_offline_ims = !mIsVoice && mHasOfflineIMs; - bool ims_are_read = LLIMFloater::isVisible(floater) && floater->hasFocus(); + bool offline_ims_visible = LLIMFloater::isVisible(floater) && floater->hasFocus(); // we don't need to listen for im floater with this conversation is opened // if floater is already opened or this conversation doesn't have unread offline messages - if (has_offline_ims && !ims_are_read) + if (has_offline_ims && !offline_ims_visible) { mIMFloaterShowedConnection = LLIMFloater::setIMFloaterShowedCallback(boost::bind(&LLConversation::onIMFloaterShown, this, _1)); } + else + { + mHasOfflineIMs = false; + } } + /************************************************************************/ /* LLConversationLogFriendObserver implementation */ /************************************************************************/ @@ -193,6 +203,7 @@ LLConversationLog::LLConversationLog() if (ctrl->getValue().asBoolean()) { LLIMMgr::instance().addSessionObserver(this); + newMessageSignalConnection = LLIMModel::instance().addNewMsgCallback(boost::bind(&LLConversationLog::onNewMessageReceived, this, _1)); } } @@ -206,17 +217,80 @@ void LLConversationLog::observeIMSession() if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) { LLIMMgr::instance().addSessionObserver(this); + LLIMModel::instance().addNewMsgCallback(boost::bind(&LLConversationLog::onNewMessageReceived, this, _1)); } else { LLIMMgr::instance().removeSessionObserver(this); + newMessageSignalConnection.disconnect(); } } -void LLConversationLog::logConversation(const LLConversation& conversation) +void LLConversationLog::logConversation(const LLUUID& session_id) { - mConversations.push_back(conversation); - notifyObservers(); + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); + LLConversation* conversation = findConversation(session_id); + + if (session && conversation) + { + updateConversationTimestamp(conversation); + } + else if (session && !conversation) + { + createConversation(session_id); + } +} + +void LLConversationLog::createConversation(const LLUUID& session_id) +{ + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); + + if (session) + { + LLConversation conversation(*session); + mConversations.push_back(conversation); + + if (LLIMModel::LLIMSession::P2P_SESSION == session->mSessionType) + { + LLAvatarNameCache::get(session->mOtherParticipantID, boost::bind(&LLConversationLog::onAvatarNameCache, this, _1, _2, session)); + } + + notifyObservers(); + } +} + +void LLConversationLog::updateConversationName(const LLUUID& session_id, const std::string& name) +{ + LLConversation* conversation = findConversation(session_id); + + if (conversation) + { + conversation->setConverstionName(name); + notifyPrticularConversationObservers(session_id, LLConversationLogObserver::CHANGED_NAME); + } +} + +void LLConversationLog::updateConversationTimestamp(LLConversation* conversation) +{ + if (conversation) + { + conversation->updateTimestamp(); + notifyPrticularConversationObservers(conversation->getSessionID(), LLConversationLogObserver::CHANGED_TIME); + } +} + +LLConversation* LLConversationLog::findConversation(const LLUUID& session_id) +{ + conversations_vec_t::iterator conv_it = mConversations.begin(); + for(; conv_it != mConversations.end(); ++conv_it) + { + if (conv_it->getSessionID() == session_id) + { + return &*conv_it; + } + } + + return NULL; } void LLConversationLog::removeConversation(const LLConversation& conversation) @@ -259,27 +333,7 @@ void LLConversationLog::removeObserver(LLConversationLogObserver* observer) void LLConversationLog::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) { - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id); - if (session) - { - LLConversation conversation(*session); - LLConversationLog::instance().logConversation(conversation); - session->mVoiceChannel->setStateChangedCallback(boost::bind(&LLConversationLog::onVoiceChannelConnected, this, _5, _2)); - } -} - -void LLConversationLog::sessionRemoved(const LLUUID& session_id) -{ - conversations_vec_t::reverse_iterator rev_iter = mConversations.rbegin(); - - for (; rev_iter != mConversations.rend(); ++rev_iter) - { - if (rev_iter->getSessionID() == session_id && !rev_iter->isConversationPast()) - { - rev_iter->setIsPast(true); - return; // return here because only one session with session_id may be active - } - } + logConversation(session_id); } void LLConversationLog::cache() @@ -385,10 +439,22 @@ bool LLConversationLog::loadFromFile(const std::string& filename) params.mHistoryFileName = std::string(history_file_name); LLConversation conversation(params); + + // CHUI-325 + // The conversation log should be capped to the last 30 days. Conversations with the last utterance + // being over 30 days old should be purged from the conversation log text file on login. + if (conversation.isOlderThan(CONVERSATION_LIFETIME)) + { + continue; + } + mConversations.push_back(conversation); } fclose(fp); + LLFile::remove(filename); + cache(); + notifyObservers(); return true; } @@ -411,17 +477,13 @@ void LLConversationLog::notifyPrticularConversationObservers(const LLUUID& sessi } } -void LLConversationLog::onVoiceChannelConnected(const LLUUID& session_id, const LLVoiceChannel::EState& state) +void LLConversationLog::onNewMessageReceived(const LLSD& data) { - conversations_vec_t::reverse_iterator rev_iter = mConversations.rbegin(); + const LLUUID session_id = data["session_id"].asUUID(); + logConversation(session_id); +} - for (; rev_iter != mConversations.rend(); ++rev_iter) - { - if (rev_iter->getSessionID() == session_id && !rev_iter->isConversationPast() && LLVoiceChannel::STATE_CALL_STARTED == state) - { - rev_iter->setIsVoice(true); - notifyPrticularConversationObservers(session_id, LLConversationLogObserver::VOICE_STATE); - return; // return here because only one session with session_id may be active - } - } +void LLConversationLog::onAvatarNameCache(const LLUUID& participant_id, const LLAvatarName& av_name, LLIMModel::LLIMSession* session) +{ + updateConversationName(session->mSessionID, av_name.getCompleteName()); } diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index 9fd54c61c9..ffd27f7e20 100644 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -57,11 +57,17 @@ public: const std::string& getTimestamp() const { return mTimestamp; } const time_t& getTime() const { return mTime; } bool isVoice() const { return mIsVoice; } - bool isConversationPast() const { return mIsConversationPast; } bool hasOfflineMessages() const { return mHasOfflineIMs; } void setIsVoice(bool is_voice); - void setIsPast (bool is_past) { mIsConversationPast = is_past; } + void setConverstionName(std::string conv_name) { mConversationName = conv_name; } + + bool isOlderThan(U32 days) const; + + /* + * updates last interaction time + */ + void updateTimestamp(); /* * Resets flag of unread offline message to false when im floater with this conversation is opened. @@ -83,7 +89,7 @@ private: boost::signals2::connection mIMFloaterShowedConnection; - time_t mTime; // start time of conversation + time_t mTime; // last interaction time SessionType mConversationType; std::string mConversationName; std::string mHistoryFileName; @@ -91,8 +97,7 @@ private: LLUUID mParticipantID; bool mIsVoice; bool mHasOfflineIMs; - bool mIsConversationPast; // once session is finished conversation became past forever - std::string mTimestamp; // conversation start time in form of: mm/dd/yyyy hh:mm + std::string mTimestamp; // last interaction time in form of: mm/dd/yyyy hh:mm }; /** @@ -109,32 +114,26 @@ class LLConversationLog : public LLSingleton<LLConversationLog>, LLIMSessionObse friend class LLSingleton<LLConversationLog>; public: - /** - * adds conversation to the conversation list and notifies observers - */ - void logConversation(const LLConversation& conversation); void removeConversation(const LLConversation& conversation); /** * Returns first conversation with matched session_id */ - const LLConversation* getConversation(const LLUUID& session_id); + const LLConversation* getConversation(const LLUUID& session_id); + const std::vector<LLConversation>& getConversations() { return mConversations; } void addObserver(LLConversationLogObserver* observer); void removeObserver(LLConversationLogObserver* observer); - const std::vector<LLConversation>& getConversations() { return mConversations; } - // LLIMSessionObserver triggers virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); - virtual void sessionRemoved(const LLUUID& session_id); + virtual void sessionRemoved(const LLUUID& session_id){} // Stub virtual void sessionVoiceOrIMStarted(const LLUUID& session_id){}; // Stub virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id){}; // Stub void notifyObservers(); - void notifyPrticularConversationObservers(const LLUUID& session_id, U32 mask); - void onVoiceChannelConnected(const LLUUID& session_id, const LLVoiceChannel::EState& state); + void onNewMessageReceived(const LLSD& data); /** * public method which is called on viewer exit to save conversation log @@ -145,6 +144,13 @@ private: LLConversationLog(); + /** + * adds conversation to the conversation list and notifies observers + */ + void logConversation(const LLUUID& session_id); + + void notifyPrticularConversationObservers(const LLUUID& session_id, U32 mask); + void observeIMSession(); /** @@ -156,11 +162,21 @@ private: bool saveToFile(const std::string& filename); bool loadFromFile(const std::string& filename); + void onAvatarNameCache(const LLUUID& participant_id, const LLAvatarName& av_name, LLIMModel::LLIMSession* session); + + void createConversation(const LLUUID& session_id); + void updateConversationTimestamp(LLConversation* conversation); + void updateConversationName(const LLUUID& session_id, const std::string& name); + + LLConversation* findConversation(const LLUUID& session_id); + typedef std::vector<LLConversation> conversations_vec_t; std::vector<LLConversation> mConversations; std::set<LLConversationLogObserver*> mObservers; LLFriendObserver* mFriendObserver; // Observer of the LLAvatarTracker instance + + boost::signals2::connection newMessageSignalConnection; }; class LLConversationLogObserver @@ -169,7 +185,8 @@ public: enum EConversationChange { - VOICE_STATE = 1 + CHANGED_TIME = 1, // last interaction time changed + CHANGED_NAME = 2 // conversation name changed }; virtual ~LLConversationLogObserver(){} diff --git a/indra/newview/llconversationloglist.cpp b/indra/newview/llconversationloglist.cpp index d39e090c22..429e99f7ad 100644 --- a/indra/newview/llconversationloglist.cpp +++ b/indra/newview/llconversationloglist.cpp @@ -143,22 +143,32 @@ void LLConversationLogList::changed() void LLConversationLogList::changed(const LLUUID& session_id, U32 mask) { - if (mask & LLConversationLogObserver::VOICE_STATE) + LLConversationLogListItem* item = getConversationLogListItem(session_id); + + if (!item) { - std::vector<LLPanel*> panels; - LLFlatListViewEx::getItems(panels); + return; + } - std::vector<LLPanel*>::iterator iter = panels.begin(); + if (mask & LLConversationLogObserver::CHANGED_TIME) + { + item->updateTimestamp(); - for (; iter != panels.end(); ++iter) + // 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()) { - LLConversationLogListItem* item = dynamic_cast<LLConversationLogListItem*>(*iter); - - if (item && session_id == item->getConversation()->getSessionID() && !item->getConversation()->isConversationPast()) - { - item->initIcons(); - return; - } + 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; } } } @@ -401,6 +411,29 @@ const LLConversation* LLConversationLogList::getSelectedConversation() return NULL; } +LLConversationLogListItem* LLConversationLogList::getConversationLogListItem(const LLUUID& session_id) +{ + std::vector<LLPanel*> panels; + LLFlatListViewEx::getItems(panels); + std::vector<LLPanel*>::iterator iter = panels.begin(); + + for (; iter != panels.end(); ++iter) + { + LLConversationLogListItem* item = dynamic_cast<LLConversationLogListItem*>(*iter); + if (item && session_id == item->getConversation()->getSessionID()) + { + return item; + } + } + + return NULL; +} + +LLConversationLogList::ESortOrder LLConversationLogList::getSortOrder() +{ + return static_cast<ESortOrder>(gSavedSettings.getU32("CallLogSortOrder")); +} + bool LLConversationLogListItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const { const LLConversationLogListItem* conversation_item1 = dynamic_cast<const LLConversationLogListItem*>(item1); diff --git a/indra/newview/llconversationloglist.h b/indra/newview/llconversationloglist.h index 5e7fc0a9fb..62ec57e09e 100644 --- a/indra/newview/llconversationloglist.h +++ b/indra/newview/llconversationloglist.h @@ -43,6 +43,12 @@ class LLConversationLogList: public LLFlatListViewEx, public LLConversationLogOb { LOG_CLASS(LLConversationLogList); public: + + typedef enum e_sort_oder{ + E_SORT_BY_NAME = 0, + E_SORT_BY_DATE = 1, + } ESortOrder; + struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params> { Params(){}; @@ -90,6 +96,9 @@ private: LLIMModel::LLIMSession::SType getSelectedSessionType(); const LLConversationLogListItem* getSelectedConversationPanel(); const LLConversation* getSelectedConversation(); + LLConversationLogListItem* getConversationLogListItem(const LLUUID& session_id); + + ESortOrder getSortOrder(); LLHandle<LLToggleableMenu> mContextMenu; bool mIsDirty; diff --git a/indra/newview/llconversationloglistitem.cpp b/indra/newview/llconversationloglistitem.cpp index dddf216592..fac6130371 100644 --- a/indra/newview/llconversationloglistitem.cpp +++ b/indra/newview/llconversationloglistitem.cpp @@ -117,6 +117,16 @@ void LLConversationLogListItem::initIcons() } } +void LLConversationLogListItem::updateTimestamp() +{ + mConversationDate->setValue(mConversation->getTimestamp()); +} + +void LLConversationLogListItem::updateName() +{ + mConversationName->setValue(mConversation->getConversationName()); +} + void LLConversationLogListItem::onMouseEnter(S32 x, S32 y, MASK mask) { getChildView("hovered_icon")->setVisible(true); diff --git a/indra/newview/llconversationloglistitem.h b/indra/newview/llconversationloglistitem.h index 2aaafa0fba..1bf7a0ed93 100644 --- a/indra/newview/llconversationloglistitem.h +++ b/indra/newview/llconversationloglistitem.h @@ -64,10 +64,16 @@ public: void onDoubleClick(); - void initIcons(); + /** + * updates string value of last interaction time from conversation + */ + void updateTimestamp(); + void updateName(); private: + void initIcons(); + const LLConversation* mConversation; LLTextBox* mConversationName; diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index d7f9093a4a..e810bac1d9 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -36,21 +36,24 @@ LLConversationItem::LLConversationItem(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) : LLFolderViewModelItemCommon(root_view_model), mName(display_name), - mUUID(uuid) + mUUID(uuid), + mNeedsRefresh(true) { } LLConversationItem::LLConversationItem(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) : LLFolderViewModelItemCommon(root_view_model), mName(""), - mUUID(uuid) + mUUID(uuid), + mNeedsRefresh(true) { } LLConversationItem::LLConversationItem(LLFolderViewModelInterface& root_view_model) : LLFolderViewModelItemCommon(root_view_model), mName(""), - mUUID() + mUUID(), + mNeedsRefresh(true) { } @@ -75,14 +78,6 @@ void LLConversationItem::showProperties(void) { } -bool LLConversationSort::operator()(const LLConversationItem* const& a, const LLConversationItem* const& b) const -{ - // We compare only by name for the moment - // *TODO : Implement the sorting by date - S32 compare = LLStringUtil::compareDict(a->getDisplayName(), b->getDisplayName()); - return (compare < 0); -} - // // LLConversationItemSession // @@ -102,11 +97,13 @@ void LLConversationItemSession::addParticipant(LLConversationItemParticipant* pa { addChild(participant); mIsLoaded = true; + mNeedsRefresh = true; } void LLConversationItemSession::removeParticipant(LLConversationItemParticipant* participant) { removeChild(participant); + mNeedsRefresh = true; } void LLConversationItemSession::removeParticipant(const LLUUID& participant_id) @@ -122,6 +119,7 @@ void LLConversationItemSession::clearParticipants() { clearChildren(); mIsLoaded = false; + mNeedsRefresh = true; } LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id) @@ -187,8 +185,42 @@ LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid, { } +void LLConversationItemParticipant::onAvatarNameCache(const LLAvatarName& av_name) +{ + mName = av_name.mDisplayName; + // *TODO : we should also store that one, to be used in the tooltip : av_name.mUsername + mNeedsRefresh = true; + if (mParent) + { + mParent->requestSort(); + } +} + void LLConversationItemParticipant::dumpDebugData() { llinfos << "Merov debug : participant, uuid = " << mUUID << ", name = " << mName << ", muted = " << mIsMuted << ", moderator = " << mIsModerator << llendl; -} +} + +// +// LLConversationSort +// + +bool LLConversationSort::operator()(const LLConversationItem* const& a, const LLConversationItem* const& b) const +{ + // For the moment, we sort only by name + // *TODO : Implement the sorting by date as well (most recent first) + // *TODO : Check the type of item (session/participants) as order should be different for both (eventually) + S32 compare = LLStringUtil::compareDict(a->getDisplayName(), b->getDisplayName()); + return (compare < 0); +} + +// +// LLConversationViewModel +// + +void LLConversationViewModel::sort(LLFolderViewFolder* folder) +{ + base_t::sort(folder); +} + // EOF diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 7baabf7f76..4f13d3d3a1 100755 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -29,6 +29,7 @@ #include "llfolderviewitem.h" #include "llfolderviewmodel.h" +#include "llavatarname.h" #include "llviewerfoldertype.h" // Implementation of conversations list @@ -61,7 +62,7 @@ public: virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } virtual std::string getLabelSuffix() const { return LLStringUtil::null; } virtual BOOL isItemRenameable() const { return TRUE; } - virtual BOOL renameItem(const std::string& new_name) { mName = new_name; return TRUE; } + virtual BOOL renameItem(const std::string& new_name) { mName = new_name; mNeedsRefresh = true; return TRUE; } virtual BOOL isItemMovable( void ) const { return FALSE; } virtual BOOL isItemRemovable( void ) const { return FALSE; } virtual BOOL isItemInTrash( void) const { return FALSE; } @@ -104,9 +105,13 @@ public: // bool hasSameValues(std::string name, const LLUUID& uuid) { return ((name == mName) && (uuid == mUUID)); } bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); } + void resetRefresh() { mNeedsRefresh = false; } + bool needsRefresh() { return mNeedsRefresh; } + protected: std::string mName; // Name of the session or the participant LLUUID mUUID; // UUID of the session or the participant + bool mNeedsRefresh; // Flag signaling to the view that something changed for this item }; class LLConversationItemSession : public LLConversationItem @@ -117,7 +122,7 @@ public: virtual ~LLConversationItemSession() {} LLPointer<LLUIImage> getIcon() const { return NULL; } - void setSessionID(const LLUUID& session_id) { mUUID = session_id; } + void setSessionID(const LLUUID& session_id) { mUUID = session_id; mNeedsRefresh = true; } void addParticipant(LLConversationItemParticipant* participant); void removeParticipant(LLConversationItemParticipant* participant); void removeParticipant(const LLUUID& participant_id); @@ -144,8 +149,10 @@ public: bool isMuted() { return mIsMuted; } bool isModerator() {return mIsModerator; } - void setIsMuted(bool is_muted) { mIsMuted = is_muted; } - void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; } + void setIsMuted(bool is_muted) { mIsMuted = is_muted; mNeedsRefresh = true; } + void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; } + + void onAvatarNameCache(const LLAvatarName& av_name); void dumpDebugData(); @@ -203,23 +210,14 @@ private: class LLConversationSort { public: - LLConversationSort(U32 order = 0) - : mSortOrder(order), - mByDate(false), - mByName(false) - { - mByDate = (order & LLConversationFilter::SO_DATE); - mByName = (order & LLConversationFilter::SO_NAME); - } + LLConversationSort(U32 order = 0) : mSortOrder(order) { } - bool isByDate() const { return mByDate; } + bool isByDate() const { return (mSortOrder & LLConversationFilter::SO_DATE); } U32 getSortOrder() const { return mSortOrder; } bool operator()(const LLConversationItem* const& a, const LLConversationItem* const& b) const; private: U32 mSortOrder; - bool mByDate; - bool mByName; }; class LLConversationViewModel @@ -228,7 +226,7 @@ class LLConversationViewModel public: typedef LLFolderViewModel<LLConversationSort, LLConversationItem, LLConversationItem, LLConversationFilter> base_t; - void sort(LLFolderViewFolder* folder) { } // *TODO : implement conversation sort + void sort(LLFolderViewFolder* folder); bool contentsReady() { return true; } // *TODO : we need to check that participants names are available somewhat bool startDrag(std::vector<LLFolderViewModelItem*>& items) { return false; } // We do not allow drag of conversation items diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 9c1c9aa225..1d1c774874 100755 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -39,7 +39,7 @@ // // Implementation of conversations list session widgets // - + LLConversationViewSession::Params::Params() : @@ -85,6 +85,36 @@ void LLConversationViewSession::setVisibleIfDetached(BOOL visible) } } +LLConversationViewParticipant* LLConversationViewSession::findParticipant(const LLUUID& participant_id) +{ + // This is *not* a general tree parsing algorithm. We search only in the mItems list + // assuming there is no mFolders which makes sense for sessions (sessions don't contain + // sessions). + LLConversationViewParticipant* participant = NULL; + items_t::const_iterator iter; + for (iter = getItemsBegin(); iter != getItemsEnd(); iter++) + { + participant = dynamic_cast<LLConversationViewParticipant*>(*iter); + if (participant->hasSameValue(participant_id)) + { + break; + } + } + return (iter == getItemsEnd() ? NULL : participant); +} + +void LLConversationViewSession::refresh() +{ + // Refresh the session view from its model data + LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem()); + vmi->resetRefresh(); + + // Note: for the moment, all that needs to be done is done by LLFolderViewItem::refresh() + + // Do the regular upstream refresh + LLFolderViewFolder::refresh(); +} + // // Implementation of conversations list participant (avatar) widgets // @@ -93,13 +123,15 @@ static LLDefaultChildRegistry::Register<LLConversationViewParticipant> r("conver LLConversationViewParticipant::Params::Params() : container(), +participant_id(), info_button("info_button"), output_monitor("output_monitor") {} LLConversationViewParticipant::LLConversationViewParticipant( const LLConversationViewParticipant::Params& p ): - LLFolderViewItem(p) -{ + LLFolderViewItem(p), + mUUID(p.participant_id) +{ } @@ -124,6 +156,18 @@ BOOL LLConversationViewParticipant::postBuild() return TRUE; } +void LLConversationViewParticipant::refresh() +{ + // Refresh the participant view from its model data + LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(getViewModelItem()); + vmi->resetRefresh(); + + // Note: for the moment, all that needs to be done is done by LLFolderViewItem::refresh() + + // Do the regular upstream refresh + LLFolderViewItem::refresh(); +} + void LLConversationViewParticipant::onInfoBtnClick() { @@ -189,3 +233,4 @@ void LLConversationViewParticipant::draw() } // EOF + diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 98eb32d44e..a7946f4d06 100755 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -39,6 +39,8 @@ #include "lloutputmonitorctrl.h" class LLIMFloaterContainer; +class LLConversationViewSession; +class LLConversationViewParticipant; // Implementation of conversations list session widgets @@ -62,6 +64,9 @@ public: virtual ~LLConversationViewSession( void ) { } virtual void selectItem(); void setVisibleIfDetached(BOOL visible); + LLConversationViewParticipant* findParticipant(const LLUUID& participant_id); + + virtual void refresh(); }; // Implementation of conversations list participant (avatar) widgets @@ -76,6 +81,7 @@ public: struct Params : public LLInitParam::Block<Params, LLFolderViewItem::Params> { Optional<LLIMFloaterContainer*> container; + Optional<LLUUID> participant_id; Optional<LLButton::Params> info_button; Optional<LLOutputMonitorCtrl::Params> output_monitor; @@ -84,9 +90,11 @@ public: virtual ~LLConversationViewParticipant( void ) { } virtual void draw(); + bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); } + virtual void refresh(); protected: - friend class LLUICtrlFactory; + friend class LLUICtrlFactory; LLConversationViewParticipant( const Params& p ); void initFromParams(const Params& params); BOOL postBuild(); @@ -96,8 +104,7 @@ protected: private: LLButton* createProfileButton(); LLButton * mInfoBtn; - - + LLUUID mUUID; // UUID of the participant }; #endif // LL_LLCONVERSATIONVIEW_H diff --git a/indra/newview/llfloaterconversationlog.cpp b/indra/newview/llfloaterconversationlog.cpp index 4375ce5726..7b4c999e52 100644 --- a/indra/newview/llfloaterconversationlog.cpp +++ b/indra/newview/llfloaterconversationlog.cpp @@ -45,11 +45,11 @@ BOOL LLFloaterConversationLog::postBuild() switch (gSavedSettings.getU32("CallLogSortOrder")) { - case E_SORT_BY_NAME: + case LLConversationLogList::E_SORT_BY_NAME: mConversationLogList->sortByName(); break; - case E_SORT_BY_DATE: + case LLConversationLogList::E_SORT_BY_DATE: mConversationLogList->sortByDate(); break; } @@ -87,12 +87,12 @@ void LLFloaterConversationLog::onCustomAction (const LLSD& userdata) if ("sort_by_name" == command_name) { mConversationLogList->sortByName(); - gSavedSettings.setU32("CallLogSortOrder", E_SORT_BY_NAME); + gSavedSettings.setU32("CallLogSortOrder", LLConversationLogList::E_SORT_BY_NAME); } else if ("sort_by_date" == command_name) { mConversationLogList->sortByDate(); - gSavedSettings.setU32("CallLogSortOrder", E_SORT_BY_DATE); + gSavedSettings.setU32("CallLogSortOrder", LLConversationLogList::E_SORT_BY_DATE); } else if ("sort_friends_on_top" == command_name) { @@ -117,11 +117,11 @@ bool LLFloaterConversationLog::isActionChecked(const LLSD& userdata) if ("sort_by_name" == command_name) { - return sort_order == E_SORT_BY_NAME; + return sort_order == LLConversationLogList::E_SORT_BY_NAME; } else if ("sort_by_date" == command_name) { - return sort_order == E_SORT_BY_DATE; + return sort_order == LLConversationLogList::E_SORT_BY_DATE; } else if ("sort_friends_on_top" == command_name) { diff --git a/indra/newview/llfloaterconversationlog.h b/indra/newview/llfloaterconversationlog.h index 7d788c0290..e971330f3d 100644 --- a/indra/newview/llfloaterconversationlog.h +++ b/indra/newview/llfloaterconversationlog.h @@ -34,11 +34,6 @@ class LLFloaterConversationLog : public LLFloater { public: - typedef enum e_sort_oder{ - E_SORT_BY_NAME = 0, - E_SORT_BY_DATE = 1, - } ESortOrder; - LLFloaterConversationLog(const LLSD& key); virtual ~LLFloaterConversationLog(){}; diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index 7083fb987d..dbcf154ef2 100644 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -29,6 +29,7 @@ #include "llfloaterconversationpreview.h" #include "llimview.h" #include "lllineeditor.h" +#include "llspinctrl.h" #include "lltrans.h" LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_id) @@ -64,11 +65,18 @@ BOOL LLFloaterConversationPreview::postBuild() std::string title = getString("Title", args); setTitle(title); - getChild<LLLineEditor>("description")->setValue(name); - LLLogChat::loadChatHistory(file, mMessages, true); mCurrentPage = mMessages.size() / mPageSize; + mPageSpinner = getChild<LLSpinCtrl>("history_page_spin"); + mPageSpinner->setCommitCallback(boost::bind(&LLFloaterConversationPreview::onMoreHistoryBtnClick, this)); + mPageSpinner->setMinValue(1); + mPageSpinner->setMaxValue(mCurrentPage + 1); + mPageSpinner->set(mCurrentPage + 1); + + std::string total_page_num = llformat("/ %d", mCurrentPage + 1); + getChild<LLTextBox>("page_num_label")->setValue(total_page_num); + return LLFloater::postBuild(); } @@ -128,6 +136,7 @@ void LLFloaterConversationPreview::showHistory() void LLFloaterConversationPreview::onMoreHistoryBtnClick() { + mCurrentPage = (int)(mPageSpinner->getValueF32()); if (--mCurrentPage < 0) { return; diff --git a/indra/newview/llfloaterconversationpreview.h b/indra/newview/llfloaterconversationpreview.h index 2246a44761..0341e5d2a0 100644 --- a/indra/newview/llfloaterconversationpreview.h +++ b/indra/newview/llfloaterconversationpreview.h @@ -29,6 +29,8 @@ #include "llchathistory.h" #include "llfloater.h" +class LLSpinCtrl; + class LLFloaterConversationPreview : public LLFloater { public: @@ -45,6 +47,7 @@ private: void onMoreHistoryBtnClick(); void showHistory(); + LLSpinCtrl* mPageSpinner; LLChatHistory* mChatHistory; LLUUID mSessionID; int mCurrentPage; diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp index b5b86dadc2..29d7732a68 100644 --- a/indra/newview/llfloatertranslationsettings.cpp +++ b/indra/newview/llfloatertranslationsettings.cpp @@ -293,6 +293,7 @@ void LLFloaterTranslationSettings::onBtnOK() gSavedSettings.setString("TranslationService", getSelectedService()); gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey()); gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey()); - LLNearbyChat::instance().showTranslationCheckbox(LLTranslate::isTranslationConfigured()); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))-> + showTranslationCheckbox(LLTranslate::isTranslationConfigured()); closeFloater(false); } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 0377337af6..0996af6125 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -35,6 +35,7 @@ // library #include "llaudioengine.h" #include "lldatapacker.h" +#include "llfloaterreg.h" #include "llinventory.h" #include "llkeyframemotion.h" #include "llmultigesture.h" @@ -997,7 +998,8 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) const BOOL animate = FALSE; - LLNearbyChat::instance().sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))-> + sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); gesture->mCurrentStep++; break; diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp index 7bb29be27b..216c5bbd70 100644 --- a/indra/newview/llimconversation.cpp +++ b/indra/newview/llimconversation.cpp @@ -31,6 +31,8 @@ #include "llchatentry.h" #include "llchathistory.h" +#include "llchiclet.h" +#include "llchicletbar.h" #include "lldraghandle.h" #include "llfloaterreg.h" #include "llimfloater.h" @@ -53,6 +55,8 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id) , mInputEditorTopPad(0) , mRefreshTimer(new LLTimer()) { + mSession = LLIMModel::getInstance()->findIMSession(mSessionID); + mCommitCallbackRegistrar.add("IMSession.Menu.Action", boost::bind(&LLIMConversation::onIMSessionMenuItemClicked, this, _2)); mEnableCallbackRegistrar.add("IMSession.Menu.CompactExpandedModes.CheckItem", @@ -182,6 +186,84 @@ void LLIMConversation::draw() } } +void LLIMConversation::enableDisableCallBtn() +{ + getChildView("voice_call_btn")->setEnabled( + mSessionID.notNull() + && mSession + && mSession->mSessionInitialized + && LLVoiceClient::getInstance()->voiceEnabled() + && LLVoiceClient::getInstance()->isVoiceWorking() + && mSession->mCallBackEnabled); +} + + +void LLIMConversation::onFocusReceived() +{ + setBackgroundOpaque(true); + + if (mSessionID.notNull()) + { + LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, true); + + if (getVisible()) + { + // suppress corresponding toast only if this floater is visible and have focus + LLIMModel::getInstance()->setActiveSessionID(mSessionID); + LLIMModel::instance().sendNoUnreadMessages(mSessionID); + } + } + + LLTransientDockableFloater::onFocusReceived(); +} + +void LLIMConversation::onFocusLost() +{ + setBackgroundOpaque(false); + LLTransientDockableFloater::onFocusLost(); +} + +std::string LLIMConversation::appendTime() +{ + time_t utc_time; + utc_time = time_corrected(); + std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" + +LLTrans::getString("TimeMin")+"]"; + + LLSD substitution; + + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + + return timeStr; +} + +void LLIMConversation::appendMessage(const LLChat& chat, const LLSD &args) +{ + LLChat& tmp_chat = const_cast<LLChat&>(chat); + + if(tmp_chat.mTimeStr.empty()) + tmp_chat.mTimeStr = appendTime(); + + if (!chat.mMuted) + { + tmp_chat.mFromName = chat.mFromName; + LLSD chat_args; + if (args) chat_args = args; + chat_args["use_plain_text_chat_history"] = + gSavedSettings.getBOOL("PlainTextChatHistory"); + chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime"); + chat_args["show_names_for_p2p_conv"] = + !mIsP2PChat || gSavedSettings.getBOOL("IMShowNamesForP2PConv"); + + if (mChatHistory) + { + mChatHistory->appendMessage(chat, chat_args); + } + } +} + + void LLIMConversation::buildParticipantList() { if (mIsNearbyChat) @@ -358,9 +440,10 @@ void LLIMConversation::processChatHistoryStyleUpdate() } } - if (LLNearbyChat::instanceExists()) + LLNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat) { - LLNearbyChat::instance().reloadMessages(); + nearby_chat->reloadMessages(); } } diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h index 26151ad1be..41a76c206e 100644 --- a/indra/newview/llimconversation.h +++ b/indra/newview/llimconversation.h @@ -33,6 +33,7 @@ #include "lltransientdockablefloater.h" #include "llviewercontrol.h" #include "lleventtimer.h" +#include "llimview.h" #include "llconversationmodel.h" class LLPanelChatControlPanel; @@ -87,9 +88,6 @@ protected: // refresh a visual state of the Call button void updateCallBtnState(bool callIsActive); - // set the enable/disable state for the Call button - virtual void enableDisableCallBtn() = 0; - void buildParticipantList(); void onSortMenuItemClicked(const LLSD& userdata); @@ -99,9 +97,23 @@ protected: /// Update floater header and toolbar buttons when hosted/torn off state is toggled. void updateHeaderAndToolbar(); + // set the enable/disable state for the Call button + virtual void enableDisableCallBtn(); + + // process focus events to set a currently active session + /* virtual */ void onFocusLost(); + /* virtual */ void onFocusReceived(); + + // prepare chat's params and out one message to chatHistory + void appendMessage(const LLChat& chat, const LLSD &args = 0); + + std::string appendTime(); + bool mIsNearbyChat; bool mIsP2PChat; + LLIMModel::LLIMSession* mSession; + LLLayoutPanel* mParticipantListPanel; LLParticipantList* mParticipantList; LLUUID mSessionID; @@ -119,7 +131,6 @@ private: /// Refreshes the floater at a constant rate. virtual void refresh() = 0; - /** * Adjusts chat history height to fit vertically with input chat field * and avoid overlapping, since input chat field can be vertically expanded. diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index a601561c62..2474fe0891 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -92,24 +92,6 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id) setDocked(true); } -void LLIMFloater::onFocusLost() -{ - LLIMModel::getInstance()->resetActiveSessionID(); - - LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, false); -} - -void LLIMFloater::onFocusReceived() -{ - LLChicletBar::getInstance()->getChicletPanel()->setChicletToggleState(mSessionID, true); - - if (getVisible()) - { - // suppress corresponding toast only if this floater is visible and have focus - LLIMModel::getInstance()->setActiveSessionID(mSessionID); - LLIMModel::instance().sendNoUnreadMessages(mSessionID); - } -} // virtual void LLIMFloater::refresh() @@ -513,27 +495,6 @@ void LLIMFloater::boundVoiceChannel() } } -void LLIMFloater::enableDisableCallBtn() -{ - bool voice_enabled = LLVoiceClient::getInstance()->voiceEnabled() - && LLVoiceClient::getInstance()->isVoiceWorking(); - - if (mSession) - { - bool session_initialized = mSession->mSessionInitialized; - bool callback_enabled = mSession->mCallBackEnabled; - - BOOL enable_connect = - session_initialized && voice_enabled && callback_enabled; - getChildView("voice_call_btn")->setEnabled(enable_connect); - } - else - { - getChildView("voice_call_btn")->setEnabled(false); - } -} - - void LLIMFloater::onCallButtonClicked() { LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); @@ -887,25 +848,6 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id) } } -void LLIMFloater::appendMessage(const LLChat& chat, const LLSD &args) -{ - LLChat& tmp_chat = const_cast<LLChat&>(chat); - - if (!chat.mMuted) - { - tmp_chat.mFromName = chat.mFromName; - LLSD chat_args; - if (args) chat_args = args; - chat_args["use_plain_text_chat_history"] = - gSavedSettings.getBOOL("PlainTextChatHistory"); - chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime"); - chat_args["show_names_for_p2p_conv"] = !mIsP2PChat - || gSavedSettings.getBOOL("IMShowNamesForP2PConv"); - - mChatHistory->appendMessage(chat, chat_args); - } -} - void LLIMFloater::updateMessages() { std::list<LLSD> messages; diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 24a8f17feb..e4a67a3d56 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -134,10 +134,6 @@ public: private: - // process focus events to set a currently active session - /* virtual */ void onFocusLost(); - /* virtual */ void onFocusReceived(); - /*virtual*/ void refresh(); /*virtual*/ void onClickCloseBtn(); @@ -156,7 +152,6 @@ private: BOOL isInviteAllowed() const; BOOL inviteToSession(const uuid_vec_t& agent_ids); - void appendMessage(const LLChat& chat, const LLSD &args = 0); static void onInputEditorFocusReceived( LLFocusableElement* caller,void* userdata ); static void onInputEditorFocusLost(LLFocusableElement* caller, void* userdata); static void onInputEditorKeystroke(LLTextEditor* caller, void* userdata); @@ -169,9 +164,6 @@ private: void onCallButtonClicked(); - // set the enable/disable state for the Call button - virtual void enableDisableCallBtn(); - void boundVoiceChannel(); // Add the "User is typing..." indicator. @@ -184,8 +176,6 @@ private: static void confirmLeaveCallCallback(const LLSD& notification, const LLSD& response); - - LLIMModel::LLIMSession* mSession; S32 mLastMessageIndex; EInstantMessage mDialog; diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp index 9758f5a93e..faca92e662 100755 --- a/indra/newview/llimfloatercontainer.cpp +++ b/indra/newview/llimfloatercontainer.cpp @@ -45,6 +45,7 @@ #include "lltransientfloatermgr.h" #include "llviewercontrol.h" #include "llconversationview.h" +#include "llcallbacklist.h" // // LLIMFloaterContainer @@ -52,7 +53,8 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed) : LLMultiFloater(seed), mExpandCollapseBtn(NULL), - mConversationsRoot(NULL) + mConversationsRoot(NULL), + mInitialized(false) { mCommitCallbackRegistrar.add("IMFloaterContainer.Action", boost::bind(&LLIMFloaterContainer::onCustomAction, this, _2)); @@ -65,6 +67,8 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed) LLIMFloaterContainer::~LLIMFloaterContainer() { + gIdleCallbacks.deleteFunction(idle, this); + mNewMessageConnection.disconnect(); LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this); @@ -139,6 +143,20 @@ BOOL LLIMFloaterContainer::postBuild() LLAvatarNameCache::addUseDisplayNamesCallback( boost::bind(&LLIMConversation::processChatHistoryStyleUpdate)); + if (! mMessagesPane->isCollapsed()) + { + S32 list_width = gSavedPerAccountSettings.getS32("ConversationsListPaneWidth"); + LLRect list_size = mConversationsPane->getRect(); + S32 left_pad = mConversationsListPanel->getRect().mLeft; + list_size.mRight = list_size.mLeft + list_width - left_pad; + + mConversationsPane->handleReshape(list_size, TRUE); + } + mInitialized = true; + + // Add callback: we'll take care of view updates on idle + gIdleCallbacks.addFunction(idle, this); + return TRUE; } @@ -290,8 +308,70 @@ void LLIMFloaterContainer::setMinimized(BOOL b) } } +//static +void LLIMFloaterContainer::idle(void* user_data) +{ + LLIMFloaterContainer* panel = (LLIMFloaterContainer*)user_data; + panel->mConversationsRoot->update(); +} + void LLIMFloaterContainer::draw() { + // CHUI Notes + // Currently, the model is not responsible for creating the view which is a good thing. This means that + // the model could change substantially and the view could decide to echo only a portion of this model. + // Consequently, the participant views need to be created either by the session view or by the container panel. + // For the moment, we create them here (which makes for complicated code...) to conform to the pattern + // implemented in llinventorypanel.cpp (see LLInventoryPanel::buildNewViews()). + // The best however would be to have an observer on the model so that we would not pool on each draw to know + // if the view needs refresh. The current implementation (testing for change on draw) is less + // efficient perf wise than a listener/observer scheme. We will implement that shortly. + + // On each session in mConversationsItems + for (conversations_items_map::iterator it_session = mConversationsItems.begin(); it_session != mConversationsItems.end(); it_session++) + { + // Get the current session descriptors + LLConversationItem* session_model = it_session->second; + LLUUID session_id = it_session->first; + LLConversationViewSession* session_view = dynamic_cast<LLConversationViewSession*>(mConversationsWidgets[session_id]); + // If the session model has been changed, refresh the corresponding view + if (session_model->needsRefresh()) + { + session_view->refresh(); + } + // Iterate through each model participant child + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = session_model->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = session_model->getChildrenEnd(); + while (current_participant_model != end_participant_model) + { + LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); + LLUUID participant_id = participant_model->getUUID(); + LLConversationViewParticipant* participant_view = session_view->findParticipant(participant_id); + // Is there a corresponding view? If not create it + if (!participant_view) + { + participant_view = createConversationViewParticipant(participant_model); + participant_view->addToFolder(session_view); + mConversationsListPanel->addChild(participant_view); + participant_view->setVisible(TRUE); + } + else + // Else, see if it needs refresh + { + if (participant_model->needsRefresh()) + { + participant_view->refresh(); + } + } + // Reset the need for refresh + session_model->resetRefresh(); + // Next participant + current_participant_model++; + } + } + + repositioningWidgets(); + if (mTabContainer->getTabCount() == 0) { // Do not close the container when every conversation is torn off because the user @@ -299,8 +379,6 @@ void LLIMFloaterContainer::draw() collapseMessagesPane(true); } LLFloater::draw(); - - repositioningWidgets(); } void LLIMFloaterContainer::tabClose() @@ -461,6 +539,16 @@ void LLIMFloaterContainer::onCustomAction(const LLSD& userdata) void LLIMFloaterContainer::repositioningWidgets() { + if (!mInitialized) + { + return; + } + + if (!mConversationsPane->isCollapsed()) + { + S32 list_width = (mConversationsPane->getRect()).getWidth(); + gSavedPerAccountSettings.setS32("ConversationsListPaneWidth", list_width); + } LLRect panel_rect = mConversationsListPanel->getRect(); S32 item_height = 16; int index = 0; @@ -499,7 +587,6 @@ void LLIMFloaterContainer::repositioningWidgets() } } -// CHUI-137 : Temporary implementation of conversations list void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid) { bool is_nearby_chat = uuid.isNull(); @@ -527,7 +614,7 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid) } if (!item) { - llinfos << "Merov debug : Couldn't create conversation session item : " << display_name << llendl; + llwarns << "Couldn't create conversation session item : " << display_name << llendl; return; } // *TODO: Should we flag LLConversationItemSession with a mIsNearbyChat? @@ -550,7 +637,6 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid) // Note: usually, we do not get an updated avatar list at that point LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin(); LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); - llinfos << "Merov debug : create participant, children size = " << item->getChildrenCount() << llendl; while (current_participant_model != end_participant_model) { LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); @@ -560,24 +646,6 @@ void LLIMFloaterContainer::addConversationListItem(const LLUUID& uuid) participant_view->setVisible(TRUE); current_participant_model++; } - // Debugging hack : uncomment to force the creation of a dummy participant - // This hack is to be eventually deleted - if (item->getChildrenCount() == 0) - { - llinfos << "Merov debug : create dummy participant" << llendl; - // Create a dummy participant : we let that leak but that's just for debugging... - std::string name("Debug Test : "); - name += display_name; - LLUUID test_id; - test_id.generate(name); - LLConversationItemParticipant* participant_model = new LLConversationItemParticipant(name, test_id, getRootViewModel()); - // Create the dummy widget - LLConversationViewParticipant* participant_view = createConversationViewParticipant(participant_model); - participant_view->addToFolder(widget); - mConversationsListPanel->addChild(participant_view); - participant_view->setVisible(TRUE); - } - // End debugging hack repositioningWidgets(); @@ -644,7 +712,7 @@ LLConversationViewParticipant* LLIMFloaterContainer::createConversationViewParti params.listener = item; params.rect = LLRect (0, 0, 0, 0); params.tool_tip = params.name; - params.container = this; + params.participant_id = item->getUUID(); return LLUICtrlFactory::create<LLConversationViewParticipant>(params); } diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h index a72a3e2221..324adfcc11 100644 --- a/indra/newview/llimfloatercontainer.h +++ b/indra/newview/llimfloatercontainer.h @@ -75,6 +75,8 @@ public: void collapseMessagesPane(bool collapse); + // Callbacks + static void idle(void* user_data); // LLIMSessionObserver observe triggers /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); @@ -110,6 +112,8 @@ private: LLLayoutPanel* mConversationsPane; LLLayoutStack* mConversationsStack; + bool mInitialized; + // Conversation list implementation public: void removeConversationListItem(const LLUUID& uuid, bool change_focus = true); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index effcc9a826..f5392b442a 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -2486,9 +2486,11 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess LLChat chat(message); chat.mSourceType = CHAT_SOURCE_SYSTEM; - if (LLNearbyChat::instanceExists()) + + LLNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat) { - LLNearbyChat::instance().addMessage(chat); + nearby_chat->addMessage(chat); } } else // going to IM session diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index f1518fe825..ddd271e23f 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -69,7 +69,7 @@ S32 LLNearbyChat::sLastSpecialChatChannel = 0; -// --- 2 functions in the global namespace :( --- +// --- function in the global namespace :( --- bool isWordsName(const std::string& name) { // checking to see if it's display name plus username in parentheses @@ -89,22 +89,6 @@ bool isWordsName(const std::string& name) } } -std::string appendTime() -{ - time_t utc_time; - utc_time = time_corrected(); - std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" - +LLTrans::getString("TimeMin")+"]"; - - LLSD substitution; - - substitution["datetime"] = (S32) utc_time; - LLStringUtil::format (timeStr, substitution); - - return timeStr; -} - - const S32 EXPANDED_HEIGHT = 266; const S32 COLLAPSED_HEIGHT = 60; const S32 EXPANDED_MIN_HEIGHT = 150; @@ -129,11 +113,14 @@ LLNearbyChat::LLNearbyChat(const LLSD& llsd) mSpeakerMgr(NULL), mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT) { + mIsP2PChat = false; mIsNearbyChat = true; setIsChrome(TRUE); mKey = LLSD(); mSpeakerMgr = LLLocalSpeakerMgr::getInstance(); + mSessionID = LLUUID(); setName("nearby_chat"); + setIsSingleInstance(TRUE); } //virtual @@ -215,21 +202,6 @@ bool LLNearbyChat::onNearbyChatCheckContextMenuItem(const LLSD& userdata) return false; } -//////////////////////////////////////////////////////////////////////////////// -// -void LLNearbyChat::onFocusReceived() -{ - setBackgroundOpaque(true); - LLIMConversation::onFocusReceived(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLNearbyChat::onFocusLost() -{ - setBackgroundOpaque(false); - LLIMConversation::onFocusLost(); -} BOOL LLNearbyChat::handleMouseDown(S32 x, S32 y, MASK mask) { @@ -325,13 +297,6 @@ void LLNearbyChat::setVisible(BOOL visible) } -void LLNearbyChat::enableDisableCallBtn() -{ - // bool btn_enabled = LLAgent::isActionAllowed("speak"); - - getChildView("voice_call_btn")->setEnabled(false /*btn_enabled*/); -} - void LLNearbyChat::onTearOffClicked() { LLIMConversation::onTearOffClicked(); @@ -624,31 +589,6 @@ void LLNearbyChat::sendChat( EChatType type ) } } - -void LLNearbyChat::appendMessage(const LLChat& chat, const LLSD &args) -{ - LLChat& tmp_chat = const_cast<LLChat&>(chat); - - if(tmp_chat.mTimeStr.empty()) - tmp_chat.mTimeStr = appendTime(); - - if (!chat.mMuted) - { - tmp_chat.mFromName = chat.mFromName; - LLSD chat_args; - if (args) chat_args = args; - chat_args["use_plain_text_chat_history"] = - gSavedSettings.getBOOL("PlainTextChatHistory"); - chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime"); - chat_args["show_names_for_p2p_conv"] = true; - - if (mChatHistory) - { - mChatHistory->appendMessage(chat, chat_args); - } - } -} - void LLNearbyChat::addMessage(const LLChat& chat,bool archive,const LLSD &args) { appendMessage(chat, args); @@ -780,20 +720,21 @@ void LLNearbyChat::sendChatFromViewer(const LLWString &wtext, EChatType type, BO // static void LLNearbyChat::startChat(const char* line) { - if (LLNearbyChat::instanceExists()) + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat) { - (LLNearbyChat::instance()).show(); - (LLNearbyChat::instance()).setVisible(TRUE); - (LLNearbyChat::instance()).setFocus(TRUE); - (LLNearbyChat::instance().mInputEditor)->setFocus(TRUE); + nearby_chat->show(); + nearby_chat->setVisible(TRUE); + nearby_chat->setFocus(TRUE); + nearby_chat->mInputEditor->setFocus(TRUE); if (line) { std::string line_string(line); - (LLNearbyChat::instance().mInputEditor)->setText(line_string); + nearby_chat->mInputEditor->setText(line_string); } - (LLNearbyChat::instance().mInputEditor)->endOfDoc(); + nearby_chat->mInputEditor->endOfDoc(); } } @@ -801,9 +742,10 @@ void LLNearbyChat::startChat(const char* line) // static void LLNearbyChat::stopChat() { - if (LLNearbyChat::instanceExists()) + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat) { - (LLNearbyChat::instance().mInputEditor)->setFocus(FALSE); + nearby_chat->mInputEditor->setFocus(FALSE); gAgent.stopTyping(); } } diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h index 379bfbee4b..2cbafbfa62 100644 --- a/indra/newview/llnearbychat.h +++ b/indra/newview/llnearbychat.h @@ -35,15 +35,13 @@ #include "lloutputmonitorctrl.h" #include "llspeakers.h" #include "llscrollbar.h" -#include "llsingleton.h" #include "llviewerchat.h" #include "llpanel.h" class LLResizeBar; class LLNearbyChat - : public LLIMConversation, - public LLSingleton<LLNearbyChat> + : public LLIMConversation { public: // constructor for inline chat-bars (e.g. hosted in chat history window) @@ -53,10 +51,6 @@ public: /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); - // focus overrides - /*virtual*/ void onFocusLost(); - /*virtual*/ void onFocusReceived(); - /*virtual*/ void setVisible(BOOL visible); void loadHistory(); @@ -104,9 +98,6 @@ protected: void displaySpeakingIndicator(); - // set the enable/disable state for the Call button - virtual void enableDisableCallBtn(); - // Which non-zero channel did we last chat on? static S32 sLastSpecialChatChannel; @@ -117,8 +108,6 @@ protected: private: - // prepare chat's params and out one message to chatHistory - void appendMessage(const LLChat& chat, const LLSD &args = 0); void onNearbySpeakers (); /*virtual*/ void refresh(); diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp index 37f4cc4c19..f3e17ea61b 100644 --- a/indra/newview/llnearbychathandler.cpp +++ b/indra/newview/llnearbychathandler.cpp @@ -487,6 +487,8 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, if(chat_msg.mText.empty()) return;//don't process empty messages + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"); + // Build notification data LLSD chat; chat["message"] = chat_msg.mText; @@ -537,7 +539,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, } } - LLNearbyChat::instance().addMessage(chat_msg, true, args); + nearby_chat->addMessage(chat_msg, true, args); if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull() @@ -553,7 +555,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, // Send event on to LLEventStream sChatWatcher->post(chat); - if( LLNearbyChat::instance().isInVisibleChain() + if( nearby_chat->isInVisibleChain() || ( chat_msg.mSourceType == CHAT_SOURCE_AGENT && gSavedSettings.getBOOL("UseChatBubbles") ) || mChannel.isDead() diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index db8e917435..9fd73746e8 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -181,13 +181,14 @@ void LLHandlerUtil::logGroupNoticeToIMGroup( // static void LLHandlerUtil::logToNearbyChat(const LLNotificationPtr& notification, EChatSourceType type) { - if (LLNearbyChat::instanceExists()) + LLNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat) { LLChat chat_msg(notification->getMessage()); chat_msg.mSourceType = type; chat_msg.mFromName = SYSTEM_FROM; chat_msg.mFromID = LLUUID::null; - LLNearbyChat::instance().addMessage(chat_msg); + nearby_chat->addMessage(chat_msg); } } diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 67fc9b27dc..a293e6acb6 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -85,7 +85,8 @@ bool LLTipHandler::processNotification(const LLNotificationPtr& notification) LLHandlerUtil::logToNearbyChat(notification, CHAT_SOURCE_SYSTEM); // don't show toast if Nearby Chat is opened - if (LLNearbyChat::instance().isChatVisible()) + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat->isChatVisible()) { return false; } diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index fa3432fc89..0d1a37c835 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -652,6 +652,8 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) LLAvatarName avatar_name; bool has_name = LLAvatarNameCache::get(avatar_id, &avatar_name); participant = new LLConversationItemParticipant(!has_name ? LLTrans::getString("AvatarNameWaiting") : avatar_name.mDisplayName , avatar_id, mRootViewModel); + // Binds avatar's name update callback + LLAvatarNameCache::get(avatar_id, boost::bind(&LLConversationItemParticipant::onAvatarNameCache, participant, _2)); if (mAvatarList) { mAvatarList->getIDs().push_back(avatar_id); @@ -670,14 +672,9 @@ void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) mAvalineUpdater->watchAvalineCaller(avatar_id); } - // *TODO : Merov : need to declare and bind a name update callback on that "participant" instance. See LLAvatarListItem::updateAvatarName() for pattern. - // For the moment, we'll get the correct name only if it's already in the name cache (see call to LLAvatarNameCache::get() here above) - // *TODO : Merov : need to update the online/offline status of the participant. // Hack for this: LLAvatarTracker::instance().isBuddyOnline(avatar_id)) - llinfos << "Merov debug : added participant, name = " << participant->getName() << llendl; - // Add the participant model to the session's children list addParticipant(participant); diff --git a/indra/newview/llviewergesture.cpp b/indra/newview/llviewergesture.cpp index a2dea31d9b..71608b5280 100644 --- a/indra/newview/llviewergesture.cpp +++ b/indra/newview/llviewergesture.cpp @@ -33,6 +33,7 @@ #include "llviewerinventory.h" #include "sound_ids.h" // for testing +#include "llfloaterreg.h" #include "llkeyboard.h" // for key shortcuts for testing #include "llinventorymodel.h" #include "llvoavatar.h" @@ -130,7 +131,8 @@ void LLViewerGesture::doTrigger( BOOL send_chat ) { // Don't play nodding animation, since that might not blend // with the gesture animation. - LLNearbyChat::instance().sendChatFromViewer(mOutputString, CHAT_TYPE_NORMAL, FALSE); + (LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))-> + sendChatFromViewer(mOutputString, CHAT_TYPE_NORMAL, FALSE); } } diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index 7105720eb4..f8e988bc0c 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llappviewer.h" +#include "llfloaterreg.h" #include "llviewerkeyboard.h" #include "llmath.h" #include "llagent.h" @@ -543,7 +544,7 @@ void start_gesture( EKeystate s ) if (KEYSTATE_UP == s && ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) { - if (LLNearbyChat::instance().getCurrentChat().empty()) + if ((LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"))->getCurrentChat().empty()) { // No existing chat in chat editor, insert '/' LLNearbyChat::startChat("/"); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 9abd269f0f..81cbc3b6c3 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2297,9 +2297,10 @@ void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string m // Treat like a system message and put in chat history. chat.mText = av_name.getCompleteName() + ": " + message; - if (LLNearbyChat::instanceExists()) + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"); + if (nearby_chat) { - LLNearbyChat::instance().addMessage(chat); + nearby_chat->addMessage(chat); } } @@ -2895,7 +2896,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Note: lie to Nearby Chat, pretending that this is NOT an IM, because // IMs from obejcts don't open IM sessions. - if(!chat_from_system && LLNearbyChat::instanceExists()) + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat"); + if(!chat_from_system && nearby_chat) { chat.mOwnerID = from_id; LLSD args; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 23d2b1633d..403288b2fd 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2493,12 +2493,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) return TRUE; } + LLNearbyChat* nearby_chat = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat"); + // Traverses up the hierarchy if( keyboard_focus ) { - if (LLNearbyChat::instanceExists()) + if (nearby_chat) { - LLChatEntry* chat_editor = LLNearbyChat::instance().getChatBox(); + LLChatEntry* chat_editor = nearby_chat->getChatBox(); // arrow keys move avatar while chatting hack if (chat_editor && chat_editor->hasFocus()) @@ -2559,14 +2561,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, // no view has keyboard focus, this is a printable character key (and no modifier key is // pressed except shift), then give focus to nearby chat (STORM-560) - if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && + if ( nearby_chat && gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) { - LLChatEntry* chat_editor = LLNearbyChat::instance().getChatBox(); + LLChatEntry* chat_editor = LLFloaterReg::findTypedInstance<LLNearbyChat>("nearby_chat")->getChatBox(); if (chat_editor) { // passing NULL here, character will be added later when it is handled by character handler. - LLNearbyChat::instance().startChat(NULL); + nearby_chat->startChat(NULL); return TRUE; } } diff --git a/indra/newview/skins/default/xui/en/floater_conversation_preview.xml b/indra/newview/skins/default/xui/en/floater_conversation_preview.xml index c837a0ee57..825a88e4e1 100644 --- a/indra/newview/skins/default/xui/en/floater_conversation_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_conversation_preview.xml @@ -14,50 +14,49 @@ name="Title"> CONVERSATION: [NAME] </floater.string> - <text - type="string" - length="1" - follows="left|top" - font="SansSerif" - height="19" - layout="topleft" - left="10" - name="desc txt" - top="22" - width="90"> - Description: - </text> - <line_editor - border_style="line" - border_thickness="1" - enabled="false" - follows="left|top|right" - font="SansSerif" - height="22" - layout="topleft" - left_pad="0" - max_length_bytes="127" - name="description" - width="296" /> <chat_history font="SansSerifSmall" follows="all" visible="true" - height="310" + height="330" name="chat_history" + notify_unread_msg="false" parse_highlights="true" parse_urls="true" left="5" + top_pad="25" width="390"> </chat_history> - <button + <text follows="bottom|right" + font="SansSerif" height="22" layout="topleft" - name="more_history" - label="More history..." - right="-15" - top_pad="5" - width="100"> - </button> + name="page_label" + right="-110" + top_pad="7" + value="Page" + width="35"> + </text> + <spinner + decimal_digits="0" + follows="bottom|right" + height="23" + increment="1" + label_width="40" + layout="topleft" + left_pad="0" + name="history_page_spin" + top_delta="-3" + width="50"/> + <text + follows="bottom|right" + font="SandSerif" + height="22" + layout="topleft" + name="page_num_label" + left_pad="5" + top_delta="4" + width="40"> + </text> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_im_container.xml b/indra/newview/skins/default/xui/en/floater_im_container.xml index e439fc9005..1583add857 100644 --- a/indra/newview/skins/default/xui/en/floater_im_container.xml +++ b/indra/newview/skins/default/xui/en/floater_im_container.xml @@ -36,7 +36,7 @@ name="conversations_layout_panel" min_dim="38" width="268" - expanded_min_dim="120"> + expanded_min_dim="165"> <layout_stack animate="false" follows="left|top|right" @@ -113,7 +113,7 @@ height="430" name="messages_layout_panel" width="412" - expanded_min_dim="205"> + expanded_min_dim="225"> <panel_container follows="all" height="430" |