summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/CMakeLists.txt2
-rw-r--r--indra/llui/llaccordionctrltab.cpp2
-rw-r--r--indra/llui/llchatentry.cpp199
-rw-r--r--indra/llui/llchatentry.h98
-rw-r--r--indra/llui/llmultifloater.cpp2
-rw-r--r--indra/llui/llmultifloater.h4
-rw-r--r--indra/llui/lltextbase.cpp122
-rw-r--r--indra/llui/lltextbase.h52
-rw-r--r--indra/llui/lltexteditor.cpp32
-rw-r--r--indra/llui/lltexteditor.h9
-rw-r--r--indra/newview/CMakeLists.txt4
-rw-r--r--indra/newview/app_settings/commands.xml6
-rw-r--r--indra/newview/app_settings/settings.xml24
-rwxr-xr-xindra/newview/llavataractions.cpp35
-rw-r--r--indra/newview/llavataractions.h9
-rw-r--r--indra/newview/llblockedlistitem.cpp114
-rw-r--r--indra/newview/llblockedlistitem.h73
-rw-r--r--indra/newview/llblocklist.cpp276
-rw-r--r--indra/newview/llblocklist.h138
-rw-r--r--indra/newview/llchatitemscontainerctrl.cpp13
-rw-r--r--indra/newview/llchiclet.h7
-rw-r--r--indra/newview/llchicletbar.cpp17
-rw-r--r--indra/newview/llchicletbar.h7
-rw-r--r--indra/newview/llexpandabletextbox.cpp4
-rwxr-xr-xindra/newview/llfloaterpreference.cpp6
-rw-r--r--indra/newview/llfolderviewitem.cpp148
-rw-r--r--indra/newview/llgrouplist.cpp2
-rw-r--r--indra/newview/llgrouplist.h4
-rw-r--r--indra/newview/llimconversation.cpp123
-rw-r--r--indra/newview/llimconversation.h26
-rw-r--r--indra/newview/llimfloater.cpp195
-rw-r--r--indra/newview/llimfloater.h20
-rw-r--r--indra/newview/llimfloatercontainer.cpp263
-rw-r--r--indra/newview/llimfloatercontainer.h110
-rw-r--r--indra/newview/llimview.cpp13
-rw-r--r--indra/newview/llimview.h2
-rw-r--r--indra/newview/llnearbychat.cpp83
-rw-r--r--indra/newview/llnearbychat.h14
-rw-r--r--indra/newview/llnearbychathandler.cpp1
-rw-r--r--indra/newview/llpanelblockedlist.cpp134
-rw-r--r--indra/newview/llpanelblockedlist.h35
-rw-r--r--indra/newview/llpaneltopinfobar.cpp2
-rw-r--r--indra/newview/llparticipantlist.cpp1
-rw-r--r--indra/newview/llsyswellwindow.h1
-rw-r--r--indra/newview/lltoastgroupnotifypanel.cpp2
-rw-r--r--indra/newview/lltoastpanel.cpp2
-rw-r--r--indra/newview/lltoastscripttextbox.cpp2
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rwxr-xr-xindra/newview/llviewerwindow.cpp5
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_add_person.pngbin0 -> 322 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.pngbin0 -> 301 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.pngbin0 -> 293 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_call_log.pngbin0 -> 546 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_close.pngbin0 -> 262 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_collapse.pngbin0 -> 663 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_expand.pngbin0 -> 662 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.pngbin0 -> 460 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_open_call.pngbin0 -> 485 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_plus.pngbin0 -> 195 bytes
-rwxr-xr-xindra/newview/skins/default/textures/icons/Conv_toolbar_sort.pngbin0 -> 196 bytes
-rw-r--r--indra/newview/skins/default/textures/textures.xml14
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_container.xml10
-rw-r--r--indra/newview/skins/default/xui/en/floater_im_session.xml72
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml26
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml20
-rw-r--r--indra/newview/skins/default/xui/en/menu_people_blocked_view.xml26
-rw-r--r--indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml160
-rw-r--r--indra/newview/skins/default/xui/en/panel_blocked_list_item.xml72
-rw-r--r--indra/newview/skins/default/xui/en/panel_people.xml9
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_chat.xml58
-rw-r--r--indra/newview/skins/default/xui/en/strings.xml2
-rw-r--r--indra/newview/skins/default/xui/en/widgets/chat_editor.xml4
-rw-r--r--indra/newview/skins/default/xui/en/widgets/text.xml1
73 files changed, 2316 insertions, 603 deletions
diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt
index 772f173f17..b50ed2342d 100644
--- a/indra/llui/CMakeLists.txt
+++ b/indra/llui/CMakeLists.txt
@@ -34,6 +34,7 @@ set(llui_SOURCE_FILES
llbadgeholder.cpp
llbadgeowner.cpp
llbutton.cpp
+ llchatentry.cpp
llcheckboxctrl.cpp
llclipboard.cpp
llcombobox.cpp
@@ -133,6 +134,7 @@ set(llui_HEADER_FILES
llbadgeowner.h
llbutton.h
llcallbackmap.h
+ llchatentry.h
llcheckboxctrl.h
llclipboard.h
llcombobox.h
diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp
index c025cd7939..43462bd244 100644
--- a/indra/llui/llaccordionctrltab.cpp
+++ b/indra/llui/llaccordionctrltab.cpp
@@ -184,7 +184,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string
if (mHeaderTextbox)
{
std::string text = mHeaderTextbox->getText();
- mStyleParams.font(mHeaderTextbox->getDefaultFont());
+ mStyleParams.font(mHeaderTextbox->getFont());
mStyleParams.font.style(style);
mHeaderTextbox->setText(text, mStyleParams);
}
diff --git a/indra/llui/llchatentry.cpp b/indra/llui/llchatentry.cpp
new file mode 100644
index 0000000000..2a6ccc3dc9
--- /dev/null
+++ b/indra/llui/llchatentry.cpp
@@ -0,0 +1,199 @@
+/**
+ * @file llchatentry.cpp
+ * @brief LLChatEntry implementation
+ *
+ * $LicenseInfo:firstyear=2001&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 "linden_common.h"
+
+#include "llchatentry.h"
+
+static LLDefaultChildRegistry::Register<LLChatEntry> r("chat_editor");
+
+LLChatEntry::Params::Params()
+: has_history("has_history", true),
+ is_expandable("is_expandable", false),
+ expand_lines_count("expand_lines_count", 1)
+{}
+
+LLChatEntry::LLChatEntry(const Params& p)
+: LLTextEditor(p),
+ mTextExpandedSignal(NULL),
+ mHasHistory(p.has_history),
+ mIsExpandable(p.is_expandable),
+ mExpandLinesCount(p.expand_lines_count),
+ mPrevLinesCount(0)
+{
+ // Initialize current history line iterator
+ mCurrentHistoryLine = mLineHistory.begin();
+
+ mAutoIndent = false;
+}
+
+LLChatEntry::~LLChatEntry()
+{
+ delete mTextExpandedSignal;
+}
+
+void LLChatEntry::draw()
+{
+ if(mIsExpandable)
+ {
+ expandText();
+ }
+
+ LLTextEditor::draw();
+}
+
+void LLChatEntry::onCommit()
+{
+ updateHistory();
+ LLTextEditor::onCommit();
+}
+
+boost::signals2::connection LLChatEntry::setTextExpandedCallback(const commit_signal_t::slot_type& cb)
+{
+ if (!mTextExpandedSignal)
+ {
+ mTextExpandedSignal = new commit_signal_t();
+ }
+ return mTextExpandedSignal->connect(cb);
+}
+
+void LLChatEntry::expandText()
+{
+ int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second);
+ bool can_expand = getLineCount() <= mExpandLinesCount;
+
+ // true if pasted text has more lines than expand height limit and expand limit is not reached yet
+ bool text_pasted = (getLineCount() > mExpandLinesCount) && (visible_lines_count < mExpandLinesCount);
+
+ if (mIsExpandable && (can_expand || text_pasted) && getLineCount() != mPrevLinesCount)
+ {
+ int lines_height = 0;
+ if (text_pasted)
+ {
+ // text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty,
+ // so lines_height is the sum of the last 'mExpandLinesCount' lines height
+ lines_height = (mLineInfoList.end() - mExpandLinesCount)->mRect.mTop - mLineInfoList.back().mRect.mBottom;
+ }
+ else
+ {
+ lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom;
+ }
+
+ int height = mVPad * 2 + lines_height;
+
+ LLRect doc_rect = getRect();
+ doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height);
+ setShape(doc_rect);
+
+ mPrevLinesCount = getLineCount();
+
+ if (mTextExpandedSignal)
+ {
+ (*mTextExpandedSignal)(this, LLSD() );
+ }
+ }
+}
+
+// line history support
+void LLChatEntry::updateHistory()
+{
+ // On history enabled, remember committed line and
+ // reset current history line number.
+ // Be sure only to remember lines that are not empty and that are
+ // different from the last on the list.
+ if (mHasHistory && getLength())
+ {
+ // Add text to history, ignoring duplicates
+ if (mLineHistory.empty() || getText() != mLineHistory.back())
+ {
+ mLineHistory.push_back(getText());
+ }
+
+ mCurrentHistoryLine = mLineHistory.end();
+ }
+}
+
+BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask)
+{
+ BOOL handled = FALSE;
+
+ LLTextEditor::handleSpecialKey(key, mask);
+
+ switch(key)
+ {
+ case KEY_RETURN:
+ if (MASK_NONE == mask)
+ {
+ needsReflow();
+ }
+ break;
+
+ case KEY_UP:
+ if (mHasHistory && MASK_CONTROL == mask)
+ {
+ if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin())
+ {
+ setText(*(--mCurrentHistoryLine));
+ endOfDoc();
+ }
+ else
+ {
+ LLUI::reportBadKeystroke();
+ }
+ handled = TRUE;
+ }
+ break;
+
+ case KEY_DOWN:
+ if (mHasHistory && MASK_CONTROL == mask)
+ {
+ if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) )
+ {
+ setText(*(++mCurrentHistoryLine));
+ endOfDoc();
+ }
+ else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) )
+ {
+ mCurrentHistoryLine++;
+ std::string empty("");
+ setText(empty);
+ needsReflow();
+ endOfDoc();
+ }
+ else
+ {
+ LLUI::reportBadKeystroke();
+ }
+ handled = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return handled;
+}
diff --git a/indra/llui/llchatentry.h b/indra/llui/llchatentry.h
new file mode 100644
index 0000000000..10a4594e83
--- /dev/null
+++ b/indra/llui/llchatentry.h
@@ -0,0 +1,98 @@
+/**
+ * @file llchatentry.h
+ * @author Paul Guslisty
+ * @brief Text editor widget which is used for user input
+ *
+ * Features:
+ * Optional line history so previous entries can be recalled by CTRL UP/DOWN
+ * Optional auto-resize behavior on input chat field
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#ifndef LLCHATENTRY_H_
+#define LLCHATENTRY_H_
+
+#include "lltexteditor.h"
+
+class LLChatEntry : public LLTextEditor
+{
+public:
+
+ struct Params : public LLInitParam::Block<Params, LLTextEditor::Params>
+ {
+ Optional<bool> has_history,
+ is_expandable;
+
+ Optional<int> expand_lines_count;
+
+ Params();
+ };
+
+ virtual ~LLChatEntry();
+
+protected:
+
+ friend class LLUICtrlFactory;
+ LLChatEntry(const Params& p);
+
+public:
+
+ virtual void draw();
+ virtual void onCommit();
+
+ boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb);
+
+private:
+
+ /**
+ * Implements auto-resize behavior.
+ * When user's typing reaches the right edge of the chat field
+ * the chat field expands vertically by one line. The bottom of
+ * the chat field remains bottom-justified. The chat field does
+ * not expand beyond mExpandLinesCount.
+ */
+ void expandText();
+
+ /**
+ * Implements line history so previous entries can be recalled by CTRL UP/DOWN
+ */
+ void updateHistory();
+
+ BOOL handleSpecialKey(const KEY key, const MASK mask);
+
+
+ // Fired when text height expanded to mExpandLinesCount
+ commit_signal_t* mTextExpandedSignal;
+
+ // line history support:
+ typedef std::vector<std::string> line_history_t;
+ line_history_t::iterator mCurrentHistoryLine; // currently browsed history line
+ line_history_t mLineHistory; // line history storage
+ bool mHasHistory; // flag for enabled/disabled line history
+ bool mIsExpandable;
+
+ int mExpandLinesCount;
+ int mPrevLinesCount;
+};
+
+#endif /* LLCHATENTRY_H_ */
diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp
index 540ac74aee..6f0e691f10 100644
--- a/indra/llui/llmultifloater.cpp
+++ b/indra/llui/llmultifloater.cpp
@@ -173,7 +173,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
else if (floaterp->getHost())
{
// floaterp is hosted by somebody else and
- // this is adding it, so remove it from it's old host
+ // this is adding it, so remove it from its old host
floaterp->getHost()->removeFloater(floaterp);
}
else if (floaterp->getParent() == gFloaterView)
diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h
index f299ae5dd3..44514a6246 100644
--- a/indra/llui/llmultifloater.h
+++ b/indra/llui/llmultifloater.h
@@ -45,8 +45,8 @@ public:
virtual BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
- /*virtual*/ void draw();
- /*virtual*/ void setVisible(BOOL visible);
+ virtual void draw();
+ virtual void setVisible(BOOL visible);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 7aeeae298f..3b3bc64c5b 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -144,6 +144,7 @@ LLTextBase::Params::Params()
: cursor_color("cursor_color"),
text_color("text_color"),
text_readonly_color("text_readonly_color"),
+ text_tentative_color("text_tentative_color"),
bg_visible("bg_visible", false),
border_visible("border_visible", false),
bg_readonly_color("bg_readonly_color"),
@@ -177,7 +178,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
: LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
mURLClickSignal(NULL),
mMaxTextByteLength( p.max_text_length ),
- mDefaultFont(p.font),
+ mFont(p.font),
mFontShadow(p.font_shadow),
mPopupMenu(NULL),
mReadOnly(p.read_only),
@@ -185,6 +186,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mFgColor(p.text_color),
mBorderVisible( p.border_visible ),
mReadOnlyFgColor(p.text_readonly_color),
+ mTentativeFgColor(p.text_tentative_color()),
mWriteableBgColor(p.bg_writeable_color),
mReadOnlyBgColor(p.bg_readonly_color),
mFocusBgColor(p.bg_focus_color),
@@ -297,21 +299,21 @@ bool LLTextBase::truncate()
return did_truncate;
}
-const LLStyle::Params& LLTextBase::getDefaultStyleParams()
+const LLStyle::Params& LLTextBase::getStyleParams()
{
//FIXME: convert mDefaultStyle to a flyweight http://www.boost.org/doc/libs/1_40_0/libs/flyweight/doc/index.html
//and eliminate color member values
if (mStyleDirty)
{
- mDefaultStyle
+ mStyle
.color(LLUIColor(&mFgColor)) // pass linked color instead of copy of mFGColor
.readonly_color(LLUIColor(&mReadOnlyFgColor))
.selected_color(LLUIColor(&mTextSelectedColor))
- .font(mDefaultFont)
+ .font(mFont)
.drop_shadow(mFontShadow);
mStyleDirty = false;
}
- return mDefaultStyle;
+ return mStyle;
}
void LLTextBase::onValueChange(S32 start, S32 end)
@@ -500,11 +502,17 @@ void LLTextBase::drawCursor()
void LLTextBase::drawText()
{
- const S32 text_len = getLength();
- if( text_len <= 0 )
+ S32 text_len = getLength();
+
+ if (text_len <= 0 && mLabel.empty())
{
return;
}
+ else if (text_len <= 0 && !mLabel.empty() && !hasFocus())
+ {
+ text_len = mLabel.length();
+ }
+
S32 selection_left = -1;
S32 selection_right = -1;
// Draw selection even if we don't have keyboard focus for search/replace
@@ -624,7 +632,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
else
{
// create default editable segment to hold new text
- LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
+ LLStyleConstSP sp(new LLStyle(getStyleParams()));
default_segment = new LLNormalTextSegment( sp, pos, pos + insert_len, *this);
}
@@ -749,7 +757,7 @@ void LLTextBase::createDefaultSegment()
// ensures that there is always at least one segment
if (mSegments.empty())
{
- LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
+ LLStyleConstSP sp(new LLStyle(getStyleParams()));
LLTextSegmentPtr default_segment = new LLNormalTextSegment( sp, 0, getLength() + 1, *this);
mSegments.insert(default_segment);
default_segment->linkToDocument(this);
@@ -1103,6 +1111,22 @@ void LLTextBase::deselect()
mIsSelecting = FALSE;
}
+void LLTextBase::onFocusReceived()
+{
+ if (!getLength() && !mLabel.empty())
+ {
+ // delete label which is LLLabelTextSegment
+ clearSegments();
+ }
+}
+
+void LLTextBase::onFocusLost()
+{
+ if (!getLength() && !mLabel.empty())
+ {
+ resetLabel();
+ }
+}
// Sets the scrollbar from the cursor position
void LLTextBase::updateScrollFromCursor()
@@ -1688,7 +1712,7 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
LLStyle::Params style_params(input_params);
- style_params.fillFrom(getDefaultStyleParams());
+ style_params.fillFrom(getStyleParams());
S32 part = (S32)LLTextParser::WHOLE;
if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
@@ -1770,6 +1794,39 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c
appendTextImpl(new_text,input_params);
}
+void LLTextBase::setLabel(const LLStringExplicit& label)
+{
+ mLabel = label;
+ resetLabel();
+}
+
+BOOL LLTextBase::setLabelArg(const std::string& key, const LLStringExplicit& text )
+{
+ mLabel.setArg(key, text);
+ return TRUE;
+}
+
+void LLTextBase::resetLabel()
+{
+ if (!getLength() && !mLabel.empty() && !hasFocus())
+ {
+ clearSegments();
+
+ LLStyle* style = new LLStyle(getStyleParams());
+ style->setColor(mTentativeFgColor);
+ LLStyleConstSP sp(style);
+
+ LLTextSegmentPtr label = new LLLabelTextSegment(sp, 0, getLabel().length() + 1, *this);
+ insertSegment(label);
+ }
+}
+
+void LLTextBase::setFont(const LLFontGL* font)
+{
+ mFont = font;
+ mStyleDirty = true;
+}
+
void LLTextBase::needsReflow(S32 index)
{
lldebugs << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << llendl;
@@ -2160,7 +2217,7 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
{
// return default height rect in upper left
local_rect = content_window_rect;
- local_rect.mBottom = local_rect.mTop - mDefaultFont->getLineHeight();
+ local_rect.mBottom = local_rect.mTop - mFont->getLineHeight();
return local_rect;
}
@@ -2665,7 +2722,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
{
F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha;
- const LLWString &text = mEditor.getWText();
+ const LLWString &text = getWText();
F32 right_x = rect.mLeft;
if (!mStyle->isVisible())
@@ -2828,7 +2885,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
if (num_chars > 0)
{
height = mFontHeight;
- const LLWString &text = mEditor.getWText();
+ const LLWString &text = getWText();
// if last character is a newline, then return true, forcing line break
width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
}
@@ -2837,7 +2894,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const
{
- const LLWString &text = mEditor.getWText();
+ const LLWString &text = getWText();
return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset,
(F32)segment_local_x_coord,
F32_MAX,
@@ -2847,7 +2904,7 @@ S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset,
S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
{
- const LLWString &text = mEditor.getWText();
+ const LLWString &text = getWText();
LLUIImagePtr image = mStyle->getImage();
if( image.notNull())
@@ -2883,7 +2940,7 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
S32 last_char_in_run = mStart + segment_offset + num_chars;
// check length first to avoid indexing off end of string
if (last_char_in_run < mEnd
- && (last_char_in_run >= mEditor.getLength() ))
+ && (last_char_in_run >= getLength()))
{
num_chars++;
}
@@ -2901,6 +2958,39 @@ void LLNormalTextSegment::dump() const
llendl;
}
+/*virtual*/
+const LLWString& LLNormalTextSegment::getWText() const
+{
+ return mEditor.getWText();
+}
+
+/*virtual*/
+const S32 LLNormalTextSegment::getLength() const
+{
+ return mEditor.getLength();
+}
+
+LLLabelTextSegment::LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor )
+: LLNormalTextSegment(style, start, end, editor)
+{
+}
+
+LLLabelTextSegment::LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible)
+: LLNormalTextSegment(color, start, end, editor, is_visible)
+{
+}
+
+/*virtual*/
+const LLWString& LLLabelTextSegment::getWText() const
+{
+ return mEditor.getWlabel();
+}
+/*virtual*/
+const S32 LLLabelTextSegment::getLength() const
+{
+ return mEditor.getLabel().length();
+}
+
//
// LLOnHoverChangeableTextSegment
//
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 0549141b72..412272b352 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -105,7 +105,7 @@ class LLNormalTextSegment : public LLTextSegment
public:
LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
- ~LLNormalTextSegment();
+ virtual ~LLNormalTextSegment();
/*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
@@ -130,6 +130,9 @@ public:
protected:
F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect);
+ virtual const LLWString& getWText() const;
+ virtual const S32 getLength() const;
+
protected:
class LLTextBase& mEditor;
LLStyleConstSP mStyle;
@@ -139,6 +142,21 @@ protected:
boost::signals2::connection mImageLoadedConnection;
};
+// This text segment is the same as LLNormalTextSegment, the only difference
+// is that LLNormalTextSegment draws value of LLTextBase (LLTextBase::getWText()),
+// but LLLabelTextSegment draws label of the LLTextBase (LLTextBase::mLabel)
+class LLLabelTextSegment : public LLNormalTextSegment
+{
+public:
+ LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
+ LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
+
+protected:
+
+ /*virtual*/ const LLWString& getWText() const;
+ /*virtual*/ const S32 getLength() const;
+};
+
// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)
class LLOnHoverChangeableTextSegment : public LLNormalTextSegment
{
@@ -249,6 +267,7 @@ public:
Optional<LLUIColor> cursor_color,
text_color,
text_readonly_color,
+ text_tentative_color,
bg_readonly_color,
bg_writeable_color,
bg_focus_color,
@@ -311,6 +330,9 @@ public:
/*virtual*/ BOOL canDeselect() const;
/*virtual*/ void deselect();
+ virtual void onFocusReceived();
+ virtual void onFocusLost();
+
// used by LLTextSegment layout code
bool getWordWrap() { return mWordWrap; }
bool getUseEllipses() { return mUseEllipses; }
@@ -330,6 +352,21 @@ public:
const LLWString& getWText() const;
void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params());
+
+ void setLabel(const LLStringExplicit& label);
+ virtual BOOL setLabelArg(const std::string& key, const LLStringExplicit& text );
+
+ const std::string& getLabel() { return mLabel.getString(); }
+ const LLWString& getWlabel() { return mLabel.getWString();}
+
+ /**
+ * If label is set, draws text label (which is LLLabelTextSegment)
+ * that is visible when no user text provided and has no focus
+ */
+ void resetLabel();
+
+ void setFont(const LLFontGL* font);
+
// force reflow of text
void needsReflow(S32 index = 0);
@@ -369,7 +406,7 @@ public:
bool scrolledToStart();
bool scrolledToEnd();
- const LLFontGL* getDefaultFont() const { return mDefaultFont; }
+ const LLFontGL* getFont() const { return mFont; }
virtual void appendLineBreakSegment(const LLStyle::Params& style_params);
virtual void appendImageSegment(const LLStyle::Params& style_params);
@@ -469,7 +506,7 @@ protected:
void createDefaultSegment();
virtual void updateSegments();
void insertSegment(LLTextSegmentPtr segment_to_insert);
- const LLStyle::Params& getDefaultStyleParams();
+ const LLStyle::Params& getStyleParams();
// manage lines
S32 getLineStart( S32 line ) const;
@@ -514,15 +551,16 @@ protected:
LLRect mTextBoundingRect;
// default text style
- LLStyle::Params mDefaultStyle;
+ LLStyle::Params mStyle;
bool mStyleDirty;
- const LLFontGL* const mDefaultFont; // font that is used when none specified, can only be set by constructor
- const LLFontGL::ShadowType mFontShadow; // shadow style, can only be set by constructor
+ const LLFontGL* mFont;
+ const LLFontGL::ShadowType mFontShadow;
// colors
LLUIColor mCursorColor;
LLUIColor mFgColor;
LLUIColor mReadOnlyFgColor;
+ LLUIColor mTentativeFgColor;
LLUIColor mWriteableBgColor;
LLUIColor mReadOnlyBgColor;
LLUIColor mFocusBgColor;
@@ -558,6 +596,7 @@ protected:
bool mClip; // clip text to widget rect
bool mClipPartial; // false if we show lines that are partially inside bounding rect
bool mPlainText; // didn't use Image or Icon segments
+ bool mAutoIndent;
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
// support widgets
@@ -573,6 +612,7 @@ protected:
// Fired when a URL link is clicked
commit_signal_t* mURLClickSignal;
+ LLUIString mLabel; // text label that is visible when no user text provided
};
#endif
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 9720dded6c..4fa6ea085e 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -235,6 +235,7 @@ LLTextEditor::Params::Params()
embedded_items("embedded_items", false),
ignore_tab("ignore_tab", true),
show_line_numbers("show_line_numbers", false),
+ auto_indent("auto_indent", true),
default_color("default_color"),
commit_on_focus_lost("commit_on_focus_lost", false),
show_context_menu("show_context_menu")
@@ -249,6 +250,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mLastCmd( NULL ),
mDefaultColor( p.default_color() ),
mShowLineNumbers ( p.show_line_numbers ),
+ mAutoIndent(p.auto_indent),
mCommitOnFocusLost( p.commit_on_focus_lost),
mAllowEmbeddedItems( p.embedded_items ),
mMouseDownX(0),
@@ -256,7 +258,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mTabsToNextField(p.ignore_tab),
mPrevalidateFunc(p.prevalidate_callback()),
mContextMenu(NULL),
- mShowContextMenu(p.show_context_menu)
+ mShowContextMenu(p.show_context_menu),
+ mPassDelete(FALSE)
{
mSourceID.generate();
@@ -1606,7 +1609,10 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask)
{
deleteSelection(FALSE);
}
- autoIndent(); // TODO: make this optional
+ if (mAutoIndent)
+ {
+ autoIndent();
+ }
}
else
{
@@ -1746,7 +1752,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)
// virtual
BOOL LLTextEditor::canDoDelete() const
{
- return !mReadOnly && ( hasSelection() || (mCursorPos < getLength()) );
+ return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) );
}
void LLTextEditor::doDelete()
@@ -1984,7 +1990,7 @@ void LLTextEditor::drawPreeditMarker()
return;
}
- const S32 line_height = mDefaultFont->getLineHeight();
+ const S32 line_height = mFont->getLineHeight();
S32 line_start = getLineStart(cur_line);
S32 line_y = mVisibleTextRect.mTop - line_height;
@@ -2023,16 +2029,16 @@ void LLTextEditor::drawPreeditMarker()
S32 preedit_left = mVisibleTextRect.mLeft;
if (left > line_start)
{
- preedit_left += mDefaultFont->getWidth(text, line_start, left - line_start);
+ preedit_left += mFont->getWidth(text, line_start, left - line_start);
}
S32 preedit_right = mVisibleTextRect.mLeft;
if (right < line_end)
{
- preedit_right += mDefaultFont->getWidth(text, line_start, right - line_start);
+ preedit_right += mFont->getWidth(text, line_start, right - line_start);
}
else
{
- preedit_right += mDefaultFont->getWidth(text, line_start, line_end - line_start);
+ preedit_right += mFont->getWidth(text, line_start, line_end - line_start);
}
if (mPreeditStandouts[i])
@@ -2707,11 +2713,11 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
const LLWString textString(getWText());
const llwchar * const text = textString.c_str();
- const S32 line_height = mDefaultFont->getLineHeight();
+ const S32 line_height = mFont->getLineHeight();
if (coord)
{
- const S32 query_x = mVisibleTextRect.mLeft + mDefaultFont->getWidth(text, current_line_start, query - current_line_start);
+ const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start);
const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2;
S32 query_screen_x, query_screen_y;
localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y);
@@ -2723,17 +2729,17 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
S32 preedit_left = mVisibleTextRect.mLeft;
if (preedit_left_position > current_line_start)
{
- preedit_left += mDefaultFont->getWidth(text, current_line_start, preedit_left_position - current_line_start);
+ preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start);
}
S32 preedit_right = mVisibleTextRect.mLeft;
if (preedit_right_position < current_line_end)
{
- preedit_right += mDefaultFont->getWidth(text, current_line_start, preedit_right_position - current_line_start);
+ preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start);
}
else
{
- preedit_right += mDefaultFont->getWidth(text, current_line_start, current_line_end - current_line_start);
+ preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start);
}
const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height;
@@ -2810,7 +2816,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length)
S32 LLTextEditor::getPreeditFontSize() const
{
- return llround((F32)mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
+ return llround((F32)mFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
}
BOOL LLTextEditor::isDirty() const
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 40821ae9fb..f8f636b876 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -64,7 +64,8 @@ public:
ignore_tab,
show_line_numbers,
commit_on_focus_lost,
- show_context_menu;
+ show_context_menu,
+ auto_indent;
//colors
Optional<LLUIColor> default_color;
@@ -202,6 +203,8 @@ public:
void setShowContextMenu(bool show) { mShowContextMenu = show; }
bool getShowContextMenu() const { return mShowContextMenu; }
+ void setPassDelete(BOOL b) { mPassDelete = b; }
+
protected:
void showContextMenu(S32 x, S32 y);
void drawPreeditMarker();
@@ -214,8 +217,8 @@ protected:
S32 indentLine( S32 pos, S32 spaces );
void unindentLineBeforeCloseBrace();
+ virtual BOOL handleSpecialKey(const KEY key, const MASK mask);
BOOL handleNavigationKey(const KEY key, const MASK mask);
- BOOL handleSpecialKey(const KEY key, const MASK mask);
BOOL handleSelectionKey(const KEY key, const MASK mask);
BOOL handleControlKey(const KEY key, const MASK mask);
@@ -279,6 +282,7 @@ protected:
LLUIColor mDefaultColor;
BOOL mShowLineNumbers;
+ bool mAutoIndent;
/*virtual*/ void updateSegments();
void updateLinkSegments();
@@ -321,6 +325,7 @@ private:
BOOL mAllowEmbeddedItems;
bool mShowContextMenu;
bool mParseOnTheFly;
+ bool mPassDelete;
LLUUID mSourceID;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index dee37bd5e8..64bc70da58 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -103,6 +103,8 @@ set(viewer_SOURCE_FILES
llavatarlist.cpp
llavatarlistitem.cpp
llavatarpropertiesprocessor.cpp
+ llblockedlistitem.cpp
+ llblocklist.cpp
llbox.cpp
llbreadcrumbview.cpp
llbrowsernotification.cpp
@@ -661,6 +663,8 @@ set(viewer_HEADER_FILES
llavatarlist.h
llavatarlistitem.h
llavatarpropertiesprocessor.h
+ llblockedlistitem.h
+ llblocklist.h
llbox.h
llbreadcrumbview.h
llbuycurrencyhtml.h
diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml
index 73df064ab2..51211a8ce5 100644
--- a/indra/newview/app_settings/commands.xml
+++ b/indra/newview/app_settings/commands.xml
@@ -46,11 +46,11 @@
available_in_toybox="true"
icon="Command_Chat_Icon"
label_ref="Command_Chat_Label"
- tooltip_ref="Command_Chat_Tooltip"
+ tooltip_ref="Command_Conversations_Tooltip"
execute_function="Floater.ToggleOrBringToFront"
- execute_parameters="chat_bar"
+ execute_parameters="im_container"
is_running_function="Floater.IsOpen"
- is_running_parameters="chat_bar"
+ is_running_parameters="im_container"
/>
<command name="compass"
available_in_toybox="false"
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 46c29e32e2..4a586b02af 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1617,17 +1617,6 @@
<key>Value</key>
<integer>1</integer>
</map>
- <key>ChatWindow</key>
- <map>
- <key>Comment</key>
- <string>Show chat in multiple windows(by default) or in one multi-tabbed window(requires restart)</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>0</integer>
- </map>
<key>CheesyBeacon</key>
<map>
<key>Comment</key>
@@ -9809,7 +9798,7 @@
<key>ShowScriptErrorsLocation</key>
<map>
<key>Comment</key>
- <string>Show script error in chat or window</string>
+ <string>Show script error in chat (0) or window (1).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -9993,6 +9982,17 @@
<key>Value</key>
<integer>2</integer>
</map>
+ <key>BlockPeopleSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>Specifies sort order for recent people (0 = by name, 1 = by type)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
<key>ShowPGSearchAll</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index b154dd458c..fb32bcbd60 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -529,23 +529,6 @@ namespace action_give_inventory
return acceptable;
}
- static void build_residents_string(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
- {
- llassert(avatar_names.size() > 0);
-
- const std::string& separator = LLTrans::getString("words_separator");
- for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
- {
- LLAvatarName av_name = *it;
- residents_string.append(av_name.mDisplayName);
- if (++it == avatar_names.end())
- {
- break;
- }
- residents_string.append(separator);
- }
- }
-
static void build_items_string(const std::set<LLUUID>& inventory_selected_uuids , std::string& items_string)
{
llassert(inventory_selected_uuids.size() > 0);
@@ -675,7 +658,7 @@ namespace action_give_inventory
}
std::string residents;
- build_residents_string(avatar_names, residents);
+ LLAvatarActions::buildResidentsString(avatar_names, residents);
std::string items;
build_items_string(inventory_selected_uuids, items);
@@ -706,7 +689,23 @@ namespace action_give_inventory
}
}
+// static
+void LLAvatarActions::buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string)
+{
+ llassert(avatar_names.size() > 0);
+ const std::string& separator = LLTrans::getString("words_separator");
+ for (std::vector<LLAvatarName>::const_iterator it = avatar_names.begin(); ; )
+ {
+ LLAvatarName av_name = *it;
+ residents_string.append(av_name.mDisplayName);
+ if (++it == avatar_names.end())
+ {
+ break;
+ }
+ residents_string.append(separator);
+ }
+}
//static
std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs()
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 0a69ad86a3..46830eb22c 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -34,6 +34,7 @@
#include <string>
#include <vector>
+class LLAvatarName;
class LLInventoryPanel;
class LLFloater;
@@ -208,6 +209,14 @@ public:
*/
static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL);
+ /**
+ * Builds a string of residents' display names separated by "words_separator" string.
+ *
+ * @param avatar_names - a vector of given avatar names from which resulting string is built
+ * @param residents_string - the resulting string
+ */
+ static void buildResidentsString(const std::vector<LLAvatarName> avatar_names, std::string& residents_string);
+
static std::set<LLUUID> getInventorySelectedUUIDs();
private:
diff --git a/indra/newview/llblockedlistitem.cpp b/indra/newview/llblockedlistitem.cpp
new file mode 100644
index 0000000000..d9afd2b629
--- /dev/null
+++ b/indra/newview/llblockedlistitem.cpp
@@ -0,0 +1,114 @@
+/**
+ * @file llviewerobjectlistitem.cpp
+ * @brief viewer object list item implementation
+ *
+ * Class LLPanelInventoryListItemBase displays inventory item as an element
+ * of LLInventoryItemsList.
+ *
+ * $LicenseInfo:firstyear=2012&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 "llblockedlistitem.h"
+
+// llui
+#include "lliconctrl.h"
+#include "lltextbox.h"
+#include "lltextutil.h"
+
+// newview
+#include "llavatariconctrl.h"
+#include "llgroupiconctrl.h"
+#include "llinventoryicon.h"
+#include "llviewerobject.h"
+
+LLBlockedListItem::LLBlockedListItem(const LLMute* item)
+: LLPanel(),
+ mItemID(item->mID),
+ mItemName(item->mName),
+ mMuteType(item->mType)
+{
+ buildFromFile("panel_blocked_list_item.xml");
+}
+
+BOOL LLBlockedListItem::postBuild()
+{
+ mTitleCtrl = getChild<LLTextBox>("item_name");
+ mTitleCtrl->setValue(mItemName);
+
+ switch (mMuteType)
+ {
+ case LLMute::AGENT:
+ case LLMute::EXTERNAL:
+ {
+ LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon");
+ avatar_icon->setVisible(TRUE);
+ avatar_icon->setValue(mItemID);
+ }
+ break;
+ case LLMute::GROUP:
+ {
+ LLGroupIconCtrl* group_icon = getChild<LLGroupIconCtrl>("group_icon");
+ group_icon->setVisible(TRUE);
+ group_icon->setValue(mItemID);
+ }
+ break;
+ case LLMute::OBJECT:
+ case LLMute::BY_NAME:
+ getChild<LLUICtrl>("object_icon")->setVisible(TRUE);
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+void LLBlockedListItem::onMouseEnter(S32 x, S32 y, MASK mask)
+{
+ getChildView("hovered_icon")->setVisible(true);
+ LLPanel::onMouseEnter(x, y, mask);
+}
+
+void LLBlockedListItem::onMouseLeave(S32 x, S32 y, MASK mask)
+{
+ getChildView("hovered_icon")->setVisible(false);
+ LLPanel::onMouseLeave(x, y, mask);
+}
+
+void LLBlockedListItem::setValue(const LLSD& value)
+{
+ if (!value.isMap() || !value.has("selected"))
+ {
+ return;
+ }
+
+ getChildView("selected_icon")->setVisible(value["selected"]);
+}
+
+void LLBlockedListItem::highlightName(const std::string& highlited_text)
+{
+ LLStyle::Params params;
+ LLTextUtil::textboxSetHighlightedVal(mTitleCtrl, params, mItemName, highlited_text);
+}
diff --git a/indra/newview/llblockedlistitem.h b/indra/newview/llblockedlistitem.h
new file mode 100644
index 0000000000..05409e8a3b
--- /dev/null
+++ b/indra/newview/llblockedlistitem.h
@@ -0,0 +1,73 @@
+/**
+ * @file llviewerobjectlistitem.h
+ * @brief viewer object list item header file
+ *
+ * $LicenseInfo:firstyear=2012&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$
+ */
+#ifndef LLVIEWEROBJECTLISTITEM_H_
+#define LLVIEWEROBJECTLISTITEM_H_
+
+#include "llmutelist.h"
+#include "llpanel.h"
+#include "llstyle.h"
+#include "lltextbox.h"
+#include "lliconctrl.h"
+
+/**
+ * This class represents items of LLBlockList, which represents
+ * contents of LLMuteList. LLMuteList "consists" of LLMute items.
+ * Each LLMute represents either blocked avatar or object and
+ * stores info about mute type (avatar or object)
+ *
+ * Each item consists if object/avatar icon and object/avatar name
+ *
+ * To create a blocked list item just need to pass LLMute pointer
+ * and appropriate block list item will be created depending on
+ * LLMute type (LLMute::EType) and other LLMute's info
+ */
+class LLBlockedListItem : public LLPanel
+{
+public:
+
+ LLBlockedListItem(const LLMute* item);
+ virtual BOOL postBuild();
+
+ void onMouseEnter(S32 x, S32 y, MASK mask);
+ void onMouseLeave(S32 x, S32 y, MASK mask);
+
+ virtual void setValue(const LLSD& value);
+
+ void highlightName(const std::string& highlited_text);
+ const std::string& getName() const { return mItemName; }
+ const LLMute::EType& getType() const { return mMuteType; }
+ const LLUUID& getUUID() const { return mItemID; }
+
+private:
+
+ LLTextBox* mTitleCtrl;
+ const LLUUID mItemID;
+ std::string mItemName;
+ LLMute::EType mMuteType;
+
+};
+
+#endif /* LLVIEWEROBJECTLISTITEM_H_ */
diff --git a/indra/newview/llblocklist.cpp b/indra/newview/llblocklist.cpp
new file mode 100644
index 0000000000..cb68f677eb
--- /dev/null
+++ b/indra/newview/llblocklist.cpp
@@ -0,0 +1,276 @@
+/**
+ * @file llblocklist.cpp
+ * @brief List of the blocked avatars and objects.
+ *
+ * $LicenseInfo:firstyear=2012&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 "llblocklist.h"
+
+#include "llavataractions.h"
+#include "llblockedlistitem.h"
+#include "llfloatersidepanelcontainer.h"
+#include "llviewermenu.h"
+
+static LLDefaultChildRegistry::Register<LLBlockList> r("block_list");
+
+static const LLBlockListNameComparator NAME_COMPARATOR;
+static const LLBlockListNameTypeComparator NAME_TYPE_COMPARATOR;
+
+LLBlockList::LLBlockList(const Params& p)
+: LLFlatListViewEx(p),
+ mSelectedItem(NULL),
+ mDirty(true)
+{
+
+ LLMuteList::getInstance()->addObserver(this);
+
+ // Set up context menu.
+ LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+ LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
+
+ registrar.add ("Block.Action", boost::bind(&LLBlockList::onCustomAction, this, _2));
+ enable_registrar.add("Block.Enable", boost::bind(&LLBlockList::isActionEnabled, this, _2));
+
+ LLToggleableMenu* context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
+ "menu_people_blocked_gear.xml",
+ gMenuHolder,
+ LLViewerMenuHolderGL::child_registry_t::instance());
+ if(context_menu)
+ {
+ mContextMenu = context_menu->getHandle();
+ }
+}
+
+LLBlockList::~LLBlockList()
+{
+ if (mContextMenu.get())
+ {
+ mContextMenu.get()->die();
+ }
+
+ LLMuteList::getInstance()->removeObserver(this);
+}
+
+BOOL LLBlockList::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 LLBlockList::setNameFilter(const std::string& filter)
+{
+ std::string filter_upper = filter;
+ LLStringUtil::toUpper(filter_upper);
+ if (mNameFilter != filter_upper)
+ {
+ mNameFilter = filter_upper;
+ setDirty();
+ }
+}
+
+void LLBlockList::sortByName()
+{
+ setComparator(&NAME_COMPARATOR);
+ sort();
+}
+
+void LLBlockList::sortByType()
+{
+ setComparator(&NAME_TYPE_COMPARATOR);
+ sort();
+}
+
+void LLBlockList::draw()
+{
+ if (mDirty)
+ {
+ refresh();
+ }
+
+ LLFlatListView::draw();
+}
+
+void LLBlockList::addNewItem(const LLMute* mute)
+{
+ LLBlockedListItem* item = new LLBlockedListItem(mute);
+ if (!mNameFilter.empty())
+ {
+ item->highlightName(mNameFilter);
+ }
+ addItem(item, item->getUUID(), ADD_BOTTOM);
+}
+
+void LLBlockList::refresh()
+{
+ bool have_filter = !mNameFilter.empty();
+
+ // save selection to restore it after list rebuilt
+ LLUUID selected = getSelectedUUID();
+
+ // calling refresh may be initiated by removing currently selected item
+ // so select next item and save the selection to restore it after list rebuilt
+ if (!selectNextItemPair(false, true))
+ {
+ selectNextItemPair(true, true);
+ }
+ LLUUID next_selected = getSelectedUUID();
+
+ clear();
+
+ std::vector<LLMute> mutes = LLMuteList::instance().getMutes();
+ std::vector<LLMute>::const_iterator mute_it = mutes.begin();
+
+ for (; mute_it != mutes.end(); ++mute_it)
+ {
+ if (have_filter && !findInsensitive(mute_it->mName, mNameFilter))
+ continue;
+
+ addNewItem(&*mute_it);
+ }
+
+ if (getItemPair(selected))
+ {
+ // restore previously selected item
+ selectItemPair(getItemPair(selected), true);
+ }
+ else if (getItemPair(next_selected))
+ {
+ // previously selected item was removed, so select next item
+ selectItemPair(getItemPair(next_selected), true);
+ }
+
+ // Sort the list.
+ sort();
+
+ setDirty(false);
+}
+
+bool LLBlockList::findInsensitive(std::string haystack, const std::string& needle_upper)
+{
+ LLStringUtil::toUpper(haystack);
+ return haystack.find(needle_upper) != std::string::npos;
+}
+
+LLBlockedListItem* LLBlockList::getBlockedItem() const
+{
+ LLPanel* panel = LLFlatListView::getSelectedItem();
+ LLBlockedListItem* item = dynamic_cast<LLBlockedListItem*>(panel);
+ return item;
+}
+
+bool LLBlockList::isActionEnabled(const LLSD& userdata)
+{
+ bool action_enabled = true;
+
+ const std::string command_name = userdata.asString();
+
+ if ("unblock_item" == command_name || "profile_item" == command_name)
+ {
+ action_enabled = getSelectedItem() != NULL;
+ }
+
+ return action_enabled;
+}
+
+void LLBlockList::onCustomAction(const LLSD& userdata)
+{
+ if (!isActionEnabled(userdata))
+ {
+ return;
+ }
+
+ LLBlockedListItem* item = getBlockedItem();
+ const std::string command_name = userdata.asString();
+
+ if ("unblock_item" == command_name)
+ {
+ LLMute mute(item->getUUID(), item->getName());
+ LLMuteList::getInstance()->remove(mute);
+ }
+ else if ("profile_item" == command_name)
+ {
+ switch(item->getType())
+ {
+
+ case LLMute::AGENT:
+ LLAvatarActions::showProfile(item->getUUID());
+ break;
+
+ case LLMute::OBJECT:
+ LLFloaterSidePanelContainer::showPanel("inventory", LLSD().with("id", item->getUUID()));
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+bool LLBlockListItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const
+{
+ const LLBlockedListItem* blocked_item1 = dynamic_cast<const LLBlockedListItem*>(item1);
+ const LLBlockedListItem* blocked_item2 = dynamic_cast<const LLBlockedListItem*>(item2);
+
+ if (!blocked_item1 || !blocked_item2)
+ {
+ llerror("blocked_item1 and blocked_item2 cannot be null", 0);
+ return true;
+ }
+
+ return doCompare(blocked_item1, blocked_item2);
+}
+
+bool LLBlockListNameComparator::doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const
+{
+ std::string name1 = blocked_item1->getName();
+ std::string name2 = blocked_item2->getName();
+
+ LLStringUtil::toUpper(name1);
+ LLStringUtil::toUpper(name2);
+
+ return name1 < name2;
+}
+
+bool LLBlockListNameTypeComparator::doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const
+{
+ LLMute::EType type1 = blocked_item1->getType();
+ LLMute::EType type2 = blocked_item2->getType();
+
+ if (type1 != type2)
+ {
+ return type1 > type2;
+ }
+
+ return NAME_COMPARATOR.compare(blocked_item1, blocked_item2);
+}
diff --git a/indra/newview/llblocklist.h b/indra/newview/llblocklist.h
new file mode 100644
index 0000000000..1a215710f4
--- /dev/null
+++ b/indra/newview/llblocklist.h
@@ -0,0 +1,138 @@
+/**
+ * @file llblocklist.h
+ * @brief List of the blocked avatars and objects.
+ *
+ * $LicenseInfo:firstyear=2012&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$
+ */
+#ifndef LLBLOCKLIST_H_
+#define LLBLOCKLIST_H_
+
+#include "llflatlistview.h"
+#include "lllistcontextmenu.h"
+#include "llmutelist.h"
+#include "lltoggleablemenu.h"
+
+class LLBlockedListItem;
+class LLMute;
+
+/**
+ * List of blocked avatars and objects.
+ * This list represents contents of the LLMuteList.
+ * Each change in LLMuteList leads to rebuilding this list, so
+ * it's always in actual state.
+ */
+class LLBlockList: public LLFlatListViewEx, public LLMuteListObserver
+{
+ LOG_CLASS(LLBlockList);
+public:
+ struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
+ {
+ Params(){};
+ };
+
+ LLBlockList(const Params& p);
+ virtual ~LLBlockList();
+
+ virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
+ LLToggleableMenu* getContextMenu() const { return mContextMenu.get(); }
+ LLBlockedListItem* getBlockedItem() const;
+
+ virtual void onChange() { refresh(); }
+ virtual void draw();
+
+ void setNameFilter(const std::string& filter);
+ void sortByName();
+ void sortByType();
+ void refresh();
+
+private:
+
+ void addNewItem(const LLMute* mute);
+ void setDirty(bool dirty = true) { mDirty = dirty; }
+ bool findInsensitive(std::string haystack, const std::string& needle_upper);
+
+ bool isActionEnabled(const LLSD& userdata);
+ void onCustomAction (const LLSD& userdata);
+
+
+ LLHandle<LLToggleableMenu> mContextMenu;
+
+ LLBlockedListItem* mSelectedItem;
+ std::string mNameFilter;
+ bool mDirty;
+
+};
+
+
+/*
+ * Abstract comparator for blocked items
+ */
+class LLBlockListItemComparator : public LLFlatListView::ItemComparator
+{
+ LOG_CLASS(LLBlockListItemComparator);
+
+public:
+ LLBlockListItemComparator() {};
+ virtual ~LLBlockListItemComparator() {};
+
+ virtual bool compare(const LLPanel* item1, const LLPanel* item2) const;
+
+protected:
+
+ virtual bool doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const = 0;
+};
+
+
+/*
+ * Compares items by name
+ */
+class LLBlockListNameComparator : public LLBlockListItemComparator
+{
+ LOG_CLASS(LLBlockListNameComparator);
+
+public:
+ LLBlockListNameComparator() {};
+ virtual ~LLBlockListNameComparator() {};
+
+protected:
+
+ virtual bool doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const;
+};
+
+/*
+ * Compares items by type and then by name within type
+ * Objects come first then avatars
+ */
+class LLBlockListNameTypeComparator : public LLBlockListItemComparator
+{
+ LOG_CLASS(LLBlockListNameTypeComparator);
+
+public:
+ LLBlockListNameTypeComparator() {};
+ virtual ~LLBlockListNameTypeComparator() {};
+
+protected:
+
+ virtual bool doCompare(const LLBlockedListItem* blocked_item1, const LLBlockedListItem* blocked_item2) const;
+};
+
+#endif /* LLBLOCKLIST_H_ */
diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp
index 477bdb3967..61772b4bb7 100644
--- a/indra/newview/llchatitemscontainerctrl.cpp
+++ b/indra/newview/llchatitemscontainerctrl.cpp
@@ -96,8 +96,15 @@ void LLNearbyChatToastPanel::reshape (S32 width, S32 height, BOOL called_from_p
{
LLPanel::reshape(width, height,called_from_parent);
- LLUICtrl* msg_text = getChild<LLUICtrl>("msg_text", false);
- LLUICtrl* icon = getChild<LLUICtrl>("avatar_icon", false);
+ // reshape() may be called from LLView::initFromParams() before the children are created.
+ // We call findChild() instead of getChild() here to avoid creating dummy controls.
+ LLUICtrl* msg_text = findChild<LLUICtrl>("msg_text", false);
+ LLUICtrl* icon = findChild<LLUICtrl>("avatar_icon", false);
+
+ if (!msg_text || !icon)
+ {
+ return;
+ }
LLRect msg_text_rect = msg_text->getRect();
LLRect avatar_rect = icon->getRect();
@@ -355,6 +362,8 @@ BOOL LLNearbyChatToastPanel::handleRightMouseDown(S32 x, S32 y, MASK mask)
}
void LLNearbyChatToastPanel::draw()
{
+ LLPanel::draw();
+
if(mIsDirty)
{
LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon", false);
diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h
index 3973b6547a..f51d7b622c 100644
--- a/indra/newview/llchiclet.h
+++ b/indra/newview/llchiclet.h
@@ -873,9 +873,10 @@ class LLIMWellChiclet : public LLSysWellChiclet, LLIMSessionObserver
{
friend class LLUICtrlFactory;
public:
- virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}
- virtual void sessionRemoved(const LLUUID& session_id) { messageCountChanged(LLSD()); }
- virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {}
+ /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}
+ /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {};
+ /*virtual*/ void sessionRemoved(const LLUUID& session_id) { messageCountChanged(LLSD()); }
+ /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {}
~LLIMWellChiclet();
protected:
diff --git a/indra/newview/llchicletbar.cpp b/indra/newview/llchicletbar.cpp
index 8701b602ce..39f5d0b8f6 100644
--- a/indra/newview/llchicletbar.cpp
+++ b/indra/newview/llchicletbar.cpp
@@ -57,19 +57,11 @@ LLChicletBar::LLChicletBar(const LLSD&)
: mChicletPanel(NULL),
mToolbarStack(NULL)
{
- // Firstly add our self to IMSession observers, so we catch session events
- // before chiclets do that.
- LLIMMgr::getInstance()->addSessionObserver(this);
-
buildFromFile("panel_chiclet_bar.xml");
}
LLChicletBar::~LLChicletBar()
{
- if (!LLSingleton<LLIMMgr>::destroyed())
- {
- LLIMMgr::getInstance()->removeSessionObserver(this);
- }
}
LLIMChiclet* LLChicletBar::createIMChiclet(const LLUUID& session_id)
@@ -102,6 +94,13 @@ void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& nam
// no need to spawn chiclets for participants in P2P calls called through Avaline
if (session->isP2P() && session->isOtherParticipantAvaline()) return;
+ // Do not spawn chiclet when using the new multitab conversation UI
+ if (LLIMConversation::isChatMultiTab())
+ {
+ LLIMFloater::addToHost(session_id);
+ return;
+ }
+
if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;
LLIMChiclet* chiclet = createIMChiclet(session_id);
@@ -109,7 +108,7 @@ void LLChicletBar::sessionAdded(const LLUUID& session_id, const std::string& nam
{
chiclet->setIMSessionName(name);
chiclet->setOtherParticipantId(other_participant_id);
-
+
LLIMFloater::onIMChicletCreated(session_id);
}
diff --git a/indra/newview/llchicletbar.h b/indra/newview/llchicletbar.h
index 1427bf95e0..7d0d904810 100644
--- a/indra/newview/llchicletbar.h
+++ b/indra/newview/llchicletbar.h
@@ -50,9 +50,10 @@ public:
LLChicletPanel* getChicletPanel() { return mChicletPanel; }
// LLIMSessionObserver observe triggers
- virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
- virtual void sessionRemoved(const LLUUID& session_id);
- void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
+ /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {};
+ /*virtual*/ void sessionRemoved(const LLUUID& session_id);
+ /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
S32 getTotalUnreadIMCount();
diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp
index 935dcb74b0..a50184460b 100644
--- a/indra/newview/llexpandabletextbox.cpp
+++ b/indra/newview/llexpandabletextbox.cpp
@@ -150,7 +150,7 @@ void LLExpandableTextBox::LLTextBoxEx::showExpandText()
std::pair<S32, S32> visible_lines = getVisibleLines(true);
S32 last_line = visible_lines.second - 1;
- LLStyle::Params expander_style(getDefaultStyleParams());
+ LLStyle::Params expander_style(getStyleParams());
expander_style.font.style = "UNDERLINE";
expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this);
@@ -166,7 +166,7 @@ void LLExpandableTextBox::LLTextBoxEx::hideExpandText()
if (mExpanderVisible)
{
// this will overwrite the expander segment and all text styling with a single style
- LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
+ LLStyleConstSP sp(new LLStyle(getStyleParams()));
LLNormalTextSegment* segmentp = new LLNormalTextSegment(sp, 0, getLength() + 1, *this);
insertSegment(segmentp);
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 18ab9dc264..996cf1e212 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -423,8 +423,6 @@ void LLFloaterPreference::saveAvatarProperties( void )
BOOL LLFloaterPreference::postBuild()
{
-// gSavedSettings.getControl("PlainTextChatHistory")->getSignal()->connect(boost::bind(&LLIMConversation::processChatHistoryStyleUpdate));
-
gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLIMConversation::processChatHistoryStyleUpdate));
gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&LLViewerChat::signalChatFontChanged));
@@ -542,8 +540,6 @@ void LLFloaterPreference::apply()
// LLWString busy_response = utf8str_to_wstring(getChild<LLUICtrl>("busy_response")->getValue().asString());
// LLWStringUtil::replaceTabsWithSpaces(busy_response, 4);
-
- gSavedSettings.setBOOL("PlainTextChatHistory", getChild<LLUICtrl>("plain_text_chat_history")->getValue().asBoolean());
if (mGotPersonalInfo)
{
@@ -1412,8 +1408,6 @@ void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im
getChild<LLUICtrl>("online_visibility")->setLabelArg("[DIR_VIS]", mDirectoryVisibility);
getChildView("send_im_to_email")->setEnabled(TRUE);
getChild<LLUICtrl>("send_im_to_email")->setValue(im_via_email);
- getChildView("plain_text_chat_history")->setEnabled(TRUE);
- getChild<LLUICtrl>("plain_text_chat_history")->setValue(gSavedSettings.getBOOL("PlainTextChatHistory"));
getChildView("log_instant_messages")->setEnabled(TRUE);
// getChildView("log_chat")->setEnabled(TRUE);
// getChildView("busy_response")->setEnabled(TRUE);
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index ac389c9189..80893c3037 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -218,7 +218,7 @@ BOOL LLFolderViewItem::passedFilter(S32 filter_generation)
}
void LLFolderViewItem::refresh()
-{
+{
LLFolderViewModelItem& vmi = *getViewModelItem();
mLabel = vmi.getDisplayName();
@@ -422,12 +422,12 @@ void LLFolderViewItem::rename(const std::string& new_name)
{
getViewModelItem()->renameItem(new_name);
- if(mParentFolder)
- {
- mParentFolder->requestSort();
+ if(mParentFolder)
+ {
+ mParentFolder->requestSort();
+ }
}
}
-}
const std::string& LLFolderViewItem::getName( void ) const
{
@@ -539,7 +539,10 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
}
else
{
+ if (getRoot())
+ {
getRoot()->setShowSelectionContext(FALSE);
+ }
gViewerWindow->setCursor(UI_CURSOR_ARROW);
// let parent handle this then...
return FALSE;
@@ -582,7 +585,10 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )
if( hasMouseCapture() )
{
+ if (getRoot())
+ {
getRoot()->setShowSelectionContext(FALSE);
+ }
gFocusMgr.setMouseCapture( NULL );
}
return TRUE;
@@ -601,16 +607,16 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
{
BOOL handled = FALSE;
BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg);
- handled = accepted;
- if (accepted)
- {
- mDragAndDropTarget = TRUE;
- *accept = ACCEPT_YES_MULTI;
- }
- else
- {
- *accept = ACCEPT_NO;
- }
+ handled = accepted;
+ if (accepted)
+ {
+ mDragAndDropTarget = TRUE;
+ *accept = ACCEPT_YES_MULTI;
+ }
+ else
+ {
+ *accept = ACCEPT_NO;
+ }
if(mParentFolder && !handled)
{
// store this item to get it in LLFolderBridge::dragItemIntoFolder on drop event.
@@ -628,17 +634,17 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
void LLFolderViewItem::draw()
{
- static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
- static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
- static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
+ static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
+ static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
static LLUIColor sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
- static LLUIColor sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
- static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
- static LLUIColor sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
- static LLUIColor sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
- static LLUIColor sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
+ static LLUIColor sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
+ static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
+ static LLUIColor sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
+ static LLUIColor sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
+ static LLUIColor sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
- static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
+ static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
const S32 TOP_PAD = default_params.item_top_pad;
@@ -662,8 +668,8 @@ void LLFolderViewItem::draw()
//--------------------------------------------------------------------------------//
// Draw highlight for selected items
//
- const BOOL show_context = getRoot()->getShowSelectionContext();
- const BOOL filled = show_context || (getRoot()->getParentPanel()->hasFocus()); // If we have keyboard focus, draw selection filled
+ const BOOL show_context = (getRoot() ? getRoot()->getShowSelectionContext() : FALSE);
+ const BOOL filled = show_context || (getRoot() ? getRoot()->getParentPanel()->hasFocus() : FALSE); // If we have keyboard focus, draw selection filled
const S32 focus_top = getRect().getHeight();
const S32 focus_bottom = getRect().getHeight() - mItemHeight;
const bool folder_open = (getRect().getHeight() > mItemHeight + 4);
@@ -674,8 +680,8 @@ void LLFolderViewItem::draw()
if (!mIsCurSelection)
{
// do time-based fade of extra objects
- F32 fade_time = getRoot()->getSelectionFadeElapsedTime();
- if (getRoot()->getShowSingleSelection())
+ F32 fade_time = (getRoot() ? getRoot()->getSelectionFadeElapsedTime() : 0.0f);
+ if (getRoot() && getRoot()->getShowSingleSelection())
{
// fading out
bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, bg_color.mV[VALPHA], 0.f);
@@ -777,7 +783,7 @@ void LLFolderViewItem::draw()
//TODO RN: implement this in terms of getColor()
//if (highlight_link) color = sLinkColor;
//if (gInventory.isObjectDescendentOf(getViewModelItem()->getUUID(), gInventory.getLibraryRootFolderID())) color = sLibraryColor;
-
+
F32 right_x = 0;
F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD;
F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation);
@@ -828,12 +834,12 @@ void LLFolderViewItem::draw()
}
const LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) const
-{
+ {
return getRoot()->getFolderViewModel();
}
LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void )
-{
+ {
return getRoot()->getFolderViewModel();
}
@@ -864,7 +870,7 @@ LLFolderViewFolder::~LLFolderViewFolder( void )
// addToFolder() returns TRUE if it succeeds. FALSE otherwise
BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder)
-{
+ {
return folder->addFolder(this);
}
@@ -1450,29 +1456,29 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item )
BOOL LLFolderViewFolder::isMovable()
{
if( !(getViewModelItem()->isItemMovable()) )
- {
- return FALSE;
- }
-
- for (items_t::iterator iter = mItems.begin();
- iter != mItems.end();)
- {
- items_t::iterator iit = iter++;
- if(!(*iit)->isMovable())
{
return FALSE;
}
- }
- for (folders_t::iterator iter = mFolders.begin();
- iter != mFolders.end();)
- {
- folders_t::iterator fit = iter++;
- if(!(*fit)->isMovable())
+ for (items_t::iterator iter = mItems.begin();
+ iter != mItems.end();)
{
- return FALSE;
+ items_t::iterator iit = iter++;
+ if(!(*iit)->isMovable())
+ {
+ return FALSE;
+ }
+ }
+
+ for (folders_t::iterator iter = mFolders.begin();
+ iter != mFolders.end();)
+ {
+ folders_t::iterator fit = iter++;
+ if(!(*fit)->isMovable())
+ {
+ return FALSE;
+ }
}
- }
return TRUE;
}
@@ -1480,29 +1486,29 @@ BOOL LLFolderViewFolder::isMovable()
BOOL LLFolderViewFolder::isRemovable()
{
if( !(getViewModelItem()->isItemRemovable()) )
- {
- return FALSE;
- }
-
- for (items_t::iterator iter = mItems.begin();
- iter != mItems.end();)
- {
- items_t::iterator iit = iter++;
- if(!(*iit)->isRemovable())
{
return FALSE;
}
- }
- for (folders_t::iterator iter = mFolders.begin();
- iter != mFolders.end();)
- {
- folders_t::iterator fit = iter++;
- if(!(*fit)->isRemovable())
+ for (items_t::iterator iter = mItems.begin();
+ iter != mItems.end();)
{
- return FALSE;
+ items_t::iterator iit = iter++;
+ if(!(*iit)->isRemovable())
+ {
+ return FALSE;
+ }
+ }
+
+ for (folders_t::iterator iter = mFolders.begin();
+ iter != mFolders.end();)
+ {
+ folders_t::iterator fit = iter++;
+ if(!(*fit)->isRemovable())
+ {
+ return FALSE;
+ }
}
- }
return TRUE;
}
@@ -1595,12 +1601,12 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r
{
BOOL was_open = isOpen();
mIsOpen = openitem;
- if(!was_open && openitem)
- {
+ if(!was_open && openitem)
+ {
getViewModelItem()->openItem();
- }
- else if(was_open && !openitem)
- {
+ }
+ else if(was_open && !openitem)
+ {
getViewModelItem()->closeItem();
}
diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp
index 2de891565c..aba3d74d87 100644
--- a/indra/newview/llgrouplist.cpp
+++ b/indra/newview/llgrouplist.cpp
@@ -406,7 +406,7 @@ void LLGroupListItem::setActive(bool active)
// *BUG: setName() overrides the style params.
// Active group should be bold.
- LLFontDescriptor new_desc(mGroupNameBox->getDefaultFont()->getFontDesc());
+ LLFontDescriptor new_desc(mGroupNameBox->getFont()->getFontDesc());
// *NOTE dzaporozhan
// On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font
diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h
index 6c8f4406ab..e96a720886 100644
--- a/indra/newview/llgrouplist.h
+++ b/indra/newview/llgrouplist.h
@@ -48,6 +48,10 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener
{
LOG_CLASS(LLGroupList);
public:
+ struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
+ {
+ Params(){};
+ };
LLGroupList(const Params& p);
virtual ~LLGroupList();
diff --git a/indra/newview/llimconversation.cpp b/indra/newview/llimconversation.cpp
index b45fc63825..acdd7ba46a 100644
--- a/indra/newview/llimconversation.cpp
+++ b/indra/newview/llimconversation.cpp
@@ -29,25 +29,29 @@
#include "llimconversation.h"
+#include "llchatentry.h"
+#include "llchathistory.h"
#include "lldraghandle.h"
#include "llfloaterreg.h"
#include "llimfloater.h"
#include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container
#include "lllayoutstack.h"
#include "llnearbychat.h"
-#include "llnearbychat.h"
const F32 REFRESH_INTERVAL = 0.2f;
LLIMConversation::LLIMConversation(const LLUUID& session_id)
: LLTransientDockableFloater(NULL, true, session_id)
- , LLEventTimer(REFRESH_INTERVAL)
, mIsP2PChat(false)
, mExpandCollapseBtn(NULL)
, mTearOffBtn(NULL)
, mCloseBtn(NULL)
, mSessionID(session_id)
, mParticipantList(NULL)
+ , mChatHistory(NULL)
+ , mInputEditor(NULL)
+ , mInputEditorTopPad(0)
+ , mRefreshTimer(new LLTimer())
{
mCommitCallbackRegistrar.add("IMSession.Menu.Action",
boost::bind(&LLIMConversation::onIMSessionMenuItemClicked, this, _2));
@@ -63,6 +67,10 @@ LLIMConversation::LLIMConversation(const LLUUID& session_id)
boost::bind(&LLIMConversation::onIMShowModesMenuItemCheck, this, _2));
mEnableCallbackRegistrar.add("IMSession.Menu.ShowModes.Enable",
boost::bind(&LLIMConversation::onIMShowModesMenuItemEnable, this, _2));
+
+ // Zero expiry time is set only once to allow initial update.
+ mRefreshTimer->setTimerExpirySec(0);
+ mRefreshTimer->start();
}
LLIMConversation::~LLIMConversation()
@@ -72,6 +80,8 @@ LLIMConversation::~LLIMConversation()
delete mParticipantList;
mParticipantList = NULL;
}
+
+ delete mRefreshTimer;
}
BOOL LLIMConversation::postBuild()
@@ -84,25 +94,29 @@ BOOL LLIMConversation::postBuild()
mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel");
- // Show the participants list in torn off floaters only.
-// mParticipantListPanel->setVisible(gSavedSettings.getBOOL("IMShowControlPanel")
-// && !mIsNearbyChat); // *TODO: temporarily disabled for Nearby chat
-// mExpandCollapseBtn->setImageOverlay(
-// getString(mParticipantListPanel->getVisible() ? "collapse_icon" : "expand_icon"));
-// mExpandCollapseBtn->setEnabled(!mIsP2PChat);
-
mTearOffBtn = getChild<LLButton>("tear_off_btn");
mTearOffBtn->setCommitCallback(boost::bind(&LLIMConversation::onTearOffClicked, this));
+ mChatHistory = getChild<LLChatHistory>("chat_history");
+ mInputEditor = getChild<LLChatEntry>("chat_editor");
+
+ mInputEditor->setTextExpandedCallback(boost::bind(&LLIMConversation::reshapeChatHistory, this));
+ mInputEditorTopPad = mChatHistory->getRect().mBottom - mInputEditor->getRect().mTop;
+
if (!getTornOff())
{
setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE);
}
buildParticipantList();
+ updateHeaderAndToolbar();
if (isChatMultiTab())
{
+ if (mIsNearbyChat)
+ {
+ setCanClose(FALSE);
+ }
return LLFloater::postBuild();
}
else
@@ -112,31 +126,38 @@ BOOL LLIMConversation::postBuild()
}
-BOOL LLIMConversation::tick()
+void LLIMConversation::draw()
{
- // This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
- // via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
- if (isDead()) return false;
+ LLTransientDockableFloater::draw();
- // Need to resort the participant list if it's in sort by recent speaker order.
- if (mParticipantList)
+ if (mRefreshTimer->hasExpired())
{
- mParticipantList->update();
- }
+ if (mParticipantList)
+ {
+ mParticipantList->update();
+ }
- return false;
+ refresh();
+
+ // Restart the refresh timer
+ mRefreshTimer->setTimerExpirySec(REFRESH_INTERVAL);
+ }
}
void LLIMConversation::buildParticipantList()
-{ if (mIsNearbyChat)
+{
+ if (mIsNearbyChat)
{
+ LLLocalSpeakerMgr* speaker_manager = LLLocalSpeakerMgr::getInstance();
+ mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true, false);
}
else
{
+ LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
// for group and ad-hoc chat we need to include agent into list
- if(!mIsP2PChat && !mParticipantList && mSessionID.notNull())
+ if(!mIsP2PChat && mSessionID.notNull() && speaker_manager)
{
- LLSpeakerMgr* speaker_manager = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ delete mParticipantList; // remove the old list and create a new one if the session id has changed
mParticipantList = new LLParticipantList(speaker_manager, getChild<LLAvatarList>("speakers_list"), true, false);
}
}
@@ -144,9 +165,11 @@ void LLIMConversation::buildParticipantList()
void LLIMConversation::onSortMenuItemClicked(const LLSD& userdata)
{
- // TODO: Check this code when when sort order menu will be added. (EM)
- if (true || !mParticipantList)
+ // TODO: Check this code when sort order menu will be added. (EM)
+ if (!mParticipantList)
+ {
return;
+ }
std::string chosen_item = userdata.asString();
@@ -218,8 +241,7 @@ void LLIMConversation::updateHeaderAndToolbar()
bool is_participant_list_visible =
!is_hosted
&& gSavedSettings.getBOOL("IMShowControlPanel")
- && !mIsP2PChat
- && !mIsNearbyChat; // *TODO: temporarily disabled for Nearby chat
+ && !mIsP2PChat;
mParticipantListPanel->setVisible(is_participant_list_visible);
@@ -228,20 +250,40 @@ void LLIMConversation::updateHeaderAndToolbar()
bool is_expanded = is_hosted || is_participant_list_visible;
mExpandCollapseBtn->setImageOverlay(getString(is_expanded ? "collapse_icon" : "expand_icon"));
- // The button (>>) should be disabled for torn off P2P conversations.
- mExpandCollapseBtn->setEnabled(is_hosted || !mIsP2PChat && !mIsNearbyChat);
-
+ // toggle floater's drag handle and title visibility
if (mDragHandle)
{
- // toggle floater's drag handle and title visibility
- mDragHandle->setVisible(!is_hosted);
+ mDragHandle->setTitleVisible(!is_hosted);
+ setCanDrag(!is_hosted);
}
+ setCanResize(!is_hosted);
+
+ // The button (>>) should be disabled for torn off P2P conversations.
+ mExpandCollapseBtn->setEnabled(is_hosted || !mIsP2PChat);
mTearOffBtn->setImageOverlay(getString(is_hosted ? "tear_off_icon" : "return_icon"));
- mCloseBtn->setVisible(is_hosted);
+ mCloseBtn->setVisible(is_hosted && !mIsNearbyChat);
enableDisableCallBtn();
+
+ showTranslationCheckbox();
+}
+
+void LLIMConversation::reshapeChatHistory()
+{
+ LLRect chat_rect = mChatHistory->getRect();
+ LLRect input_rect = mInputEditor->getRect();
+
+ int delta_height = chat_rect.mBottom - (input_rect.mTop + mInputEditorTopPad);
+
+ chat_rect.setLeftTopAndSize(chat_rect.mLeft, chat_rect.mTop, chat_rect.getWidth(), chat_rect.getHeight() + delta_height);
+ mChatHistory->setShape(chat_rect);
+}
+
+void LLIMConversation::showTranslationCheckbox(BOOL show)
+{
+ getChild<LLUICtrl>("translate_chat_checkbox_lp")->setVisible(mIsNearbyChat? show : FALSE);
}
// static
@@ -307,9 +349,25 @@ void LLIMConversation::onOpen(const LLSD& key)
host_floater->collapseMessagesPane(false);
}
+ setCanResize(TRUE);
+
updateHeaderAndToolbar();
}
+// virtual
+void LLIMConversation::onClose(bool app_quitting)
+{
+ // Always suppress the IM from the conversations list on close if present for any reason
+ if (LLIMConversation::isChatMultiTab())
+ {
+ LLIMFloaterContainer* im_box = LLIMFloaterContainer::findInstance();
+ if (im_box)
+ {
+ im_box->removeConversationListItem(this);
+ }
+ }
+}
+
void LLIMConversation::onTearOffClicked()
{
onClickTearOff(this);
@@ -320,6 +378,5 @@ void LLIMConversation::onTearOffClicked()
bool LLIMConversation::isChatMultiTab()
{
// Restart is required in order to change chat window type.
- static bool is_single_window = gSavedSettings.getS32("ChatWindow") == 1;
- return is_single_window;
+ return true;
}
diff --git a/indra/newview/llimconversation.h b/indra/newview/llimconversation.h
index d31ae0808a..50663137ac 100644
--- a/indra/newview/llimconversation.h
+++ b/indra/newview/llimconversation.h
@@ -35,10 +35,11 @@
#include "lleventtimer.h"
class LLPanelChatControlPanel;
+class LLChatEntry;
+class LLChatHistory;
class LLIMConversation
: public LLTransientDockableFloater
- , public LLEventTimer
{
public:
@@ -56,9 +57,14 @@ public:
*/
static bool isChatMultiTab();
+ // show/hide the translation check box
+ void showTranslationCheckbox(const BOOL visible = FALSE);
+
// LLFloater overrides
/*virtual*/ void onOpen(const LLSD& key);
+ /*virtual*/ void onClose(bool app_quitting);
/*virtual*/ BOOL postBuild();
+ /*virtual*/ void draw();
protected:
@@ -83,8 +89,6 @@ protected:
void buildParticipantList();
void onSortMenuItemClicked(const LLSD& userdata);
- /*virtual*/ BOOL tick();
-
bool mIsNearbyChat;
bool mIsP2PChat;
@@ -97,8 +101,24 @@ protected:
LLButton* mCloseBtn;
private:
+ /// Refreshes the floater at a constant rate.
+ virtual void refresh() = 0;
+
/// Update floater header and toolbar buttons when hosted/torn off state is toggled.
void updateHeaderAndToolbar();
+
+ /**
+ * Adjusts chat history height to fit vertically with input chat field
+ * and avoid overlapping, since input chat field can be vertically expanded.
+ * Implementation: chat history bottom "follows" top+top_pad of input chat field
+ */
+ void reshapeChatHistory();
+
+ LLChatHistory* mChatHistory;
+ LLChatEntry* mInputEditor;
+ int mInputEditorTopPad; // padding between input field and chat history
+
+ LLTimer* mRefreshTimer; ///< Defines the rate at which refresh() is called.
};
diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp
index 7c6de01c96..9d3c0f98ce 100644
--- a/indra/newview/llimfloater.cpp
+++ b/indra/newview/llimfloater.cpp
@@ -44,7 +44,7 @@
#include "llimfloatercontainer.h" // to replace separate IM Floaters with multifloater container
#include "llinventoryfunctions.h"
//#include "lllayoutstack.h"
-#include "lllineeditor.h"
+#include "llchatentry.h"
#include "lllogchat.h"
#include "llscreenchannel.h"
#include "llsyswellwindow.h"
@@ -106,39 +106,16 @@ void LLIMFloater::onFocusReceived()
}
// virtual
-void LLIMFloater::onClose(bool app_quitting)
+void LLIMFloater::refresh()
{
- LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
- mSessionID);
-
- if (session == NULL)
+ if (mMeTyping)
{
- llwarns << "Empty session." << llendl;
- return;
- }
-
- bool is_call_with_chat = session->isGroupSessionType()
- || session->isAdHocSessionType() || session->isP2PSessionType();
-
- LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
-
- if (is_call_with_chat && voice_channel != NULL
- && voice_channel->isActive())
- {
- LLSD payload;
- payload["session_id"] = mSessionID;
- LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
- return;
+ // Time out if user hasn't typed for a while.
+ if (mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS)
+ {
+ setTyping(false);
+ }
}
-
- setTyping(false);
-
- // The source of much argument and design thrashing
- // Should the window hide or the session close when the X is clicked?
- //
- // Last change:
- // EXT-3516 X Button should end IM session, _ button should hide
- gIMMgr->leaveSession(mSessionID);
}
/* static */
@@ -190,7 +167,9 @@ void LLIMFloater::sendMsg()
{
if (mInputEditor)
{
- LLWString text = mInputEditor->getConvertedText();
+ LLWString text = mInputEditor->getWText();
+ LLWStringUtil::trim(text);
+ LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
if(!text.empty())
{
// Truncate and convert to UTF8 for transport
@@ -221,6 +200,7 @@ void LLIMFloater::sendMsg()
LLIMFloater::~LLIMFloater()
{
+ mParticipantsListRefreshConnection.disconnect();
mVoiceChannelStateChangeConnection.disconnect();
if(LLVoiceClient::instanceExists())
{
@@ -258,6 +238,8 @@ void LLIMFloater::initIMFloater()
boundVoiceChannel();
+ mTypingStart = LLTrans::getString("IM_typing_start_string");
+
// Show control panel in torn off floaters only.
mParticipantListPanel->setVisible(!getHost() && gSavedSettings.getBOOL("IMShowControlPanel"));
@@ -279,6 +261,20 @@ void LLIMFloater::initIMFloater()
{
std::string session_name(LLIMModel::instance().getName(mSessionID));
updateSessionName(session_name, session_name);
+
+ // For ad hoc conferences we should update the title with participants names.
+ if ((IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID))
+ || mDialog == IM_SESSION_CONFERENCE_START)
+ {
+ if (mParticipantsListRefreshConnection.connected())
+ {
+ mParticipantsListRefreshConnection.disconnect();
+ }
+
+ LLAvatarList* avatar_list = getChild<LLAvatarList>("speakers_list");
+ mParticipantsListRefreshConnection = avatar_list->setRefreshCompleteCallback(
+ boost::bind(&LLIMFloater::onParticipantsListChanged, this, _1));
+ }
}
}
@@ -287,30 +283,25 @@ BOOL LLIMFloater::postBuild()
{
LLIMConversation::postBuild();
- mInputEditor = getChild<LLLineEditor>("chat_editor");
+ mInputEditor = getChild<LLChatEntry>("chat_editor");
mInputEditor->setMaxTextLength(1023);
// enable line history support for instant message bar
- mInputEditor->setEnableLineHistory(TRUE);
LLFontGL* font = LLViewerChat::getChatFont();
mInputEditor->setFont(font);
mInputEditor->setFocusReceivedCallback( boost::bind(onInputEditorFocusReceived, _1, this) );
mInputEditor->setFocusLostCallback( boost::bind(onInputEditorFocusLost, _1, this) );
- mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this );
+ mInputEditor->setKeystrokeCallback( boost::bind(onInputEditorKeystroke, _1, this) );
mInputEditor->setCommitOnFocusLost( FALSE );
- mInputEditor->setRevertOnEsc( FALSE );
- mInputEditor->setReplaceNewlinesWithSpaces( FALSE );
mInputEditor->setPassDelete( TRUE );
- childSetCommitCallback("chat_editor", onSendMsg, this);
+ mInputEditor->setCommitCallback(boost::bind(onSendMsg, _1, this));
mChatHistory = getChild<LLChatHistory>("chat_history");
setDocked(true);
- mTypingStart = LLTrans::getString("IM_typing_start_string");
-
LLButton* add_btn = getChild<LLButton>("add_btn");
// Allow to add chat participants depending on the session type
@@ -377,7 +368,9 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids)
for (uuid_vec_t::const_iterator id = uuids.begin();
id != uuids.end(); ++id)
{
- if (*id == mOtherParticipantUUID)
+ // Skip this check for ad hoc conferences,
+ // conference participants should be listed in mSession->mInitialTargetIDs.
+ if (mIsP2PChat && *id == mOtherParticipantUUID)
{
return false;
}
@@ -447,11 +440,6 @@ void LLIMFloater::onCallButtonClicked()
}
}
-/*void LLIMFloater::onOpenVoiceControlsClicked()
-{
- LLFloaterReg::showInstance("voice_controls");
-}*/
-
void LLIMFloater::onChange(EStatusType status, const std::string &channelURI, bool proximal)
{
if(status != STATUS_JOINING && status != STATUS_LEFT_CHANNEL)
@@ -484,25 +472,59 @@ void LLIMFloater::onAvatarNameCache(const LLUUID& agent_id,
mTypingStart.setArg("[NAME]", ui_title);
}
-// virtual
-BOOL LLIMFloater::tick()
+void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl)
{
- // This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
- // via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
- if (isDead()) return false;
+ LLAvatarList* avatar_list = dynamic_cast<LLAvatarList*>(ctrl);
+ if (!avatar_list)
+ {
+ return;
+ }
- BOOL parents_retcode = LLIMConversation::tick();
+ bool all_names_resolved = true;
+ std::vector<LLSD> participants_uuids;
- if ( mMeTyping )
+ avatar_list->getValues(participants_uuids);
+
+ // Check whether we have all participants names in LLAvatarNameCache
+ for (std::vector<LLSD>::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it)
{
- // Time out if user hasn't typed for a while.
- if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS )
+ const LLUUID& id = it->asUUID();
+ LLAvatarName av_name;
+ if (!LLAvatarNameCache::get(id, &av_name))
{
- setTyping(false);
+ all_names_resolved = false;
+
+ // If a name is not found in cache, request it and continue the process recursively
+ // until all ids are resolved into names.
+ LLAvatarNameCache::get(id,
+ boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list));
+ break;
}
}
- return parents_retcode;
+ if (all_names_resolved)
+ {
+ std::vector<LLAvatarName> avatar_names;
+ std::vector<LLSD>::const_iterator it = participants_uuids.begin();
+ for (; it != participants_uuids.end(); ++it)
+ {
+ const LLUUID& id = it->asUUID();
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(id, &av_name))
+ {
+ avatar_names.push_back(av_name);
+ }
+ }
+
+ // We should check whether the vector is not empty to pass the assertion
+ // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString.
+ if (!avatar_names.empty())
+ {
+ std::string ui_title;
+ LLAvatarActions::buildResidentsString(avatar_names, ui_title);
+ updateSessionName(ui_title, ui_title);
+ }
+ }
}
//static
@@ -528,8 +550,10 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
}
}
+ // Test the existence of the floater before we try to create it
bool exist = findInstance(session_id);
+ // Get the floater: this will create the instance if it didn't exist
LLIMFloater* floater = getInstance(session_id);
if (!floater)
return NULL;
@@ -538,18 +562,21 @@ LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
{
LLIMFloaterContainer* floater_container = LLIMFloaterContainer::getInstance();
- // do not add existed floaters to avoid adding torn off instances
+ // Do not add again existing floaters
if (!exist)
{
// LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END;
// TODO: mantipov: use LLTabContainer::RIGHT_OF_CURRENT if it exists
LLTabContainer::eInsertionPoint i_pt = LLTabContainer::END;
-
if (floater_container)
{
floater_container->addFloater(floater, TRUE, i_pt);
}
}
+
+ // Add a conversation list item in the left pane: nothing will be done if already in there
+ // but relevant clean up will be done to ensure consistency of the conversation list
+ floater_container->addConversationListItem(floater->getTitle(), session_id, floater);
floater->openFloater(floater->getKey());
}
@@ -599,6 +626,44 @@ LLIMFloater* LLIMFloater::getInstance(const LLUUID& session_id)
return conversation;
}
+void LLIMFloater::onClose(bool app_quitting)
+{
+ LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
+ mSessionID);
+
+ if (session == NULL)
+ {
+ llwarns << "Empty session." << llendl;
+ return;
+ }
+
+ bool is_call_with_chat = session->isGroupSessionType()
+ || session->isAdHocSessionType() || session->isP2PSessionType();
+
+ LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
+
+ if (is_call_with_chat && voice_channel != NULL
+ && voice_channel->isActive())
+ {
+ LLSD payload;
+ payload["session_id"] = mSessionID;
+ LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
+ return;
+ }
+
+ setTyping(false);
+
+ // The source of much argument and design thrashing
+ // Should the window hide or the session close when the X is clicked?
+ //
+ // Last change:
+ // EXT-3516 X Button should end IM session, _ button should hide
+ gIMMgr->leaveSession(mSessionID);
+
+ // Clean up the conversation *after* the session has been ended
+ LLIMConversation::onClose(app_quitting);
+}
+
void LLIMFloater::setDocked(bool docked, bool pop_on_undock)
{
// update notification channel state
@@ -726,8 +791,6 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)
{
initIMSession(im_session_id);
- boundVoiceChannel();
-
buildParticipantList();
}
@@ -877,7 +940,7 @@ void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userd
}
// static
-void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata)
+void LLIMFloater::onInputEditorKeystroke(LLTextEditor* caller, void* userdata)
{
LLIMFloater* self = (LLIMFloater*) userdata;
std::string text = self->mInputEditor->getText();
@@ -1013,6 +1076,12 @@ BOOL LLIMFloater::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
*accept = ACCEPT_NO;
}
}
+ else if (mDialog == IM_NOTHING_SPECIAL)
+ {
+ LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionID, drop,
+ cargo_type, cargo_data, accept);
+ }
+
return TRUE;
}
@@ -1074,7 +1143,7 @@ private:
BOOL LLIMFloater::inviteToSession(const uuid_vec_t& ids)
{
LLViewerRegion* region = gAgent.getRegion();
- bool is_region_exist = !!region;
+ bool is_region_exist = region != NULL;
if (is_region_exist)
{
diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h
index d74b13b88d..23f9e75e21 100644
--- a/indra/newview/llimfloater.h
+++ b/indra/newview/llimfloater.h
@@ -37,7 +37,9 @@
class LLAvatarName;
class LLButton;
-class LLLineEditor;
+class LLChatEntry;
+class LLTextEditor;
+class LLPanelChatControlPanel;
class LLChatHistory;
class LLInventoryItem;
class LLInventoryCategory;
@@ -64,15 +66,11 @@ public:
/*virtual*/ void setVisible(BOOL visible);
/*virtual*/ BOOL getVisible();
// Check typing timeout timer.
- /*virtual*/ BOOL tick();
static LLIMFloater* findInstance(const LLUUID& session_id);
static LLIMFloater* getInstance(const LLUUID& session_id);
static void addToHost(const LLUUID& session_id);
- static void* createPanelGroupControl(void* userdata);
- static void* createPanelAdHocControl(void* userdata);
-
// LLFloater overrides
/*virtual*/ void onClose(bool app_quitting);
/*virtual*/ void setDocked(bool docked, bool pop_on_undock = true);
@@ -132,12 +130,18 @@ private:
/* virtual */ void onFocusLost();
/* virtual */ void onFocusReceived();
+ /*virtual*/ void refresh();
+
// Update the window title, input field help text, etc.
void updateSessionName(const std::string& ui_title, const std::string& ui_label);
// For display name lookups for IM window titles
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+ /// Updates the list of ad hoc conference participants
+ /// in an IM floater title.
+ void onParticipantsListChanged(LLUICtrl* ctrl);
+
bool dropPerson(LLUUID* person_id, bool drop);
BOOL isInviteAllowed() const;
@@ -145,7 +149,7 @@ private:
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(LLLineEditor* caller, void* userdata);
+ static void onInputEditorKeystroke(LLTextEditor* caller, void* userdata);
void setTyping(bool typing);
void onAddButtonClicked();
void onAvatarPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
@@ -176,7 +180,7 @@ private:
EInstantMessage mDialog;
LLUUID mOtherParticipantUUID;
- LLLineEditor* mInputEditor;
+ LLChatEntry* mInputEditor;
bool mPositioned;
std::string mSavedTitle;
@@ -194,6 +198,8 @@ private:
// connection to voice channel state change signal
boost::signals2::connection mVoiceChannelStateChangeConnection;
+
+ boost::signals2::connection mParticipantsListRefreshConnection;
};
#endif // LL_IMFLOATER_H
diff --git a/indra/newview/llimfloatercontainer.cpp b/indra/newview/llimfloatercontainer.cpp
index 71b69dfbc8..261b5f33a2 100644
--- a/indra/newview/llimfloatercontainer.cpp
+++ b/indra/newview/llimfloatercontainer.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
+#include "llimfloater.h"
#include "llimfloatercontainer.h"
#include "llfloaterreg.h"
@@ -49,6 +50,9 @@ LLIMFloaterContainer::LLIMFloaterContainer(const LLSD& seed)
: LLMultiFloater(seed)
,mExpandCollapseBtn(NULL)
{
+ // Firstly add our self to IMSession observers, so we catch session events
+ LLIMMgr::getInstance()->addSessionObserver(this);
+
mAutoResize = FALSE;
LLTransientFloaterMgr::getInstance()->addControlView(LLTransientFloaterMgr::IM, this);
}
@@ -60,8 +64,18 @@ LLIMFloaterContainer::~LLIMFloaterContainer()
gSavedPerAccountSettings.setBOOL("ConversationsListPaneCollapsed", mConversationsPane->isCollapsed());
gSavedPerAccountSettings.setBOOL("ConversationsMessagePaneCollapsed", mMessagesPane->isCollapsed());
+
+ if (!LLSingleton<LLIMMgr>::destroyed())
+ {
+ LLIMMgr::getInstance()->removeSessionObserver(this);
+ }
}
+void LLIMFloaterContainer::sessionVoiceOrIMStarted(const LLUUID& session_id)
+{
+ LLIMFloater::show(session_id);
+};
+
BOOL LLIMFloaterContainer::postBuild()
{
mNewMessageConnection = LLIMModel::instance().mNewMsgSignal.connect(boost::bind(&LLIMFloaterContainer::onNewMessageReceived, this, _1));
@@ -73,6 +87,8 @@ BOOL LLIMFloaterContainer::postBuild()
mConversationsStack = getChild<LLLayoutStack>("conversations_stack");
mConversationsPane = getChild<LLLayoutPanel>("conversations_layout_panel");
mMessagesPane = getChild<LLLayoutPanel>("messages_layout_panel");
+
+ mConversationsListPanel = getChild<LLPanel>("conversations_list_panel");
mExpandCollapseBtn = getChild<LLButton>("expand_collapse_btn");
mExpandCollapseBtn->setClickedCallback(boost::bind(&LLIMFloaterContainer::onExpandCollapseButtonClicked, this));
@@ -88,16 +104,6 @@ BOOL LLIMFloaterContainer::postBuild()
void LLIMFloaterContainer::onOpen(const LLSD& key)
{
LLMultiFloater::onOpen(key);
-/*
- if (key.isDefined())
- {
- LLIMFloater* im_floater = LLIMFloater::findInstance(key.asUUID());
- if (im_floater)
- {
- im_floater->openFloater();
- }
- }
-*/
}
// virtual
@@ -113,17 +119,24 @@ void LLIMFloaterContainer::addFloater(LLFloater* floaterp,
openFloater(floaterp->getKey());
return;
}
+
+ // Make sure the message panel is open when adding a floater or it stays mysteriously hidden
+ collapseMessagesPane(false);
+ // Add the floater
LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point);
+ LLUUID session_id = floaterp->getKey();
+
+ // Add a conversation list item in the left pane
+ addConversationListItem(floaterp->getTitle(), session_id, floaterp);
+
LLView* floater_contents = floaterp->getChild<LLView>("contents_view");
// we don't show the header when the floater is hosted,
// so reshape floater contents to occupy the header space
floater_contents->setShape(floaterp->getRect());
- LLUUID session_id = floaterp->getKey();
-
LLIconCtrl* icon = 0;
if(gAgent.isInGroup(session_id, TRUE))
@@ -254,6 +267,58 @@ void LLIMFloaterContainer::setMinimized(BOOL b)
}
}
+void LLIMFloaterContainer::draw()
+{
+ if (mTabContainer->getTabCount() == 0)
+ {
+ // Do not close the container when every conversation is torn off because the user
+ // still needs the conversation list. Simply collapse the message pane in that case.
+ collapseMessagesPane(true);
+ }
+ LLFloater::draw();
+}
+
+void LLIMFloaterContainer::tabClose()
+{
+ if (mTabContainer->getTabCount() == 0)
+ {
+ // Do not close the container when every conversation is torn off because the user
+ // still needs the conversation list. Simply collapse the message pane in that case.
+ collapseMessagesPane(true);
+ }
+}
+
+void LLIMFloaterContainer::setVisible(BOOL visible)
+{
+ if (visible)
+ {
+ // Make sure we have the Nearby Chat present when showing the conversation container
+ LLUUID nearbychat_uuid = LLUUID::null; // Hacky but true: the session id for nearby chat is always null
+ LLFloater* floaterp = findConversationItem(nearbychat_uuid);
+ if (floaterp == NULL)
+ {
+ // If not found, force the creation of the nearby chat conversation panel
+ // *TODO: find a way to move this to XML as a default panel or something like that
+ LLSD name("chat_bar");
+ LLFloaterReg::toggleInstanceOrBringToFront(name);
+ }
+ }
+
+ // We need to show/hide all the associated conversations that have been torn off
+ // (and therefore, are not longer managed by the multifloater),
+ // so that they show/hide with the conversations manager.
+ conversations_items_map::iterator item_it = mConversationsItems.begin();
+ for (;item_it != mConversationsItems.end(); ++item_it)
+ {
+ LLConversationItem* item = item_it->second;
+ item->setVisibleIfDetached(visible);
+ }
+
+ // Now, do the normal multifloater show/hide
+ LLMultiFloater::setVisible(visible);
+
+}
+
void LLIMFloaterContainer::collapseMessagesPane(bool collapse)
{
if (mMessagesPane->isCollapsed() == collapse)
@@ -339,4 +404,178 @@ void LLIMFloaterContainer::onAvatarPicked(const uuid_vec_t& ids)
}
}
+// CHUI-137 : Temporary implementation of conversations list
+void LLIMFloaterContainer::addConversationListItem(std::string name, const LLUUID& uuid, LLFloater* floaterp)
+{
+ // Check if the item is not already in the list, exit if it is and has the same name and uuid (nothing to do)
+ // Note: this happens often, when reattaching a torn off conversation for instance
+ conversations_items_map::iterator item_it = mConversationsItems.find(floaterp);
+ if (item_it != mConversationsItems.end())
+ {
+ LLConversationItem* item = item_it->second;
+ // Check if the item has changed
+ if (item->hasSameValues(name,uuid))
+ {
+ // If it hasn't changed, nothing to do -> exit
+ return;
+ }
+ }
+
+ // Remove the conversation item that might exist already: it'll be recreated anew further down anyway
+ // and nothing wrong will happen removing it if it doesn't exist
+ removeConversationListItem(floaterp,false);
+
+ // Create a conversation item
+ LLConversationItem* item = new LLConversationItem(name, uuid, floaterp, this);
+ mConversationsItems[floaterp] = item;
+
+ // Create a widget from it
+ LLFolderViewItem* widget = createConversationItemWidget(item);
+ mConversationsWidgets[floaterp] = widget;
+
+ // Add it to the UI
+ widget->setVisible(TRUE);
+ mConversationsListPanel->addChild(widget);
+ LLRect panel_rect = mConversationsListPanel->getRect();
+ S32 item_height = 16;
+ S32 index = mConversationsWidgets.size() - 1;
+ widget->setRect(LLRect(0,
+ panel_rect.getHeight() - item_height*index,
+ panel_rect.getWidth(),
+ panel_rect.getHeight() - item_height*(index+1)));
+ return;
+}
+
+void LLIMFloaterContainer::removeConversationListItem(LLFloater* floaterp, bool change_focus)
+{
+ // Delete the widget and the associated conversation item
+ // Note : since the mConversationsItems is also the listener to the widget, deleting
+ // the widget will also delete its listener
+ conversations_widgets_map::iterator widget_it = mConversationsWidgets.find(floaterp);
+ if (widget_it != mConversationsWidgets.end())
+ {
+ LLFolderViewItem* widget = widget_it->second;
+ delete widget;
+ }
+
+ // Suppress the conversation items and widgets from their respective maps
+ mConversationsItems.erase(floaterp);
+ mConversationsWidgets.erase(floaterp);
+
+ // Reposition the leftover conversation items
+ LLRect panel_rect = mConversationsListPanel->getRect();
+ S32 item_height = 16;
+ int index = 0;
+ for (widget_it = mConversationsWidgets.begin(); widget_it != mConversationsWidgets.end(); ++widget_it, ++index)
+ {
+ LLFolderViewItem* widget = widget_it->second;
+ widget->setRect(LLRect(0,
+ panel_rect.getHeight() - item_height*index,
+ panel_rect.getWidth(),
+ panel_rect.getHeight() - item_height*(index+1)));
+ }
+
+ // Don't let the focus fall IW, select and refocus on the first conversation in the list
+ if (change_focus)
+ {
+ setFocus(TRUE);
+ conversations_items_map::iterator item_it = mConversationsItems.begin();
+ if (item_it != mConversationsItems.end())
+ {
+ LLConversationItem* item = item_it->second;
+ item->selectItem();
+ }
+ }
+ return;
+}
+
+LLFloater* LLIMFloaterContainer::findConversationItem(LLUUID& uuid)
+{
+ LLFloater* floaterp = NULL;
+ for (conversations_items_map::iterator item_it = mConversationsItems.begin(); item_it != mConversationsItems.end(); ++item_it)
+ {
+ LLConversationItem* item = item_it->second;
+ if (item->hasSameValue(uuid))
+ {
+ floaterp = item_it->first;
+ break;
+ }
+ }
+ return floaterp;
+}
+
+LLFolderViewItem* LLIMFloaterContainer::createConversationItemWidget(LLConversationItem* item)
+{
+ LLFolderViewItem::Params params;
+
+ params.name = item->getDisplayName();
+ //params.icon = bridge->getIcon();
+ //params.icon_open = bridge->getOpenIcon();
+ //params.creation_date = bridge->getCreationDate();
+ //params.root = mFolderRoot;
+ params.listener = item;
+ params.rect = LLRect (0, 0, 0, 0);
+ params.tool_tip = params.name;
+
+ return LLUICtrlFactory::create<LLFolderViewItem>(params);
+}
+
+// Conversation items
+LLConversationItem::LLConversationItem(std::string name, const LLUUID& uuid, LLFloater* floaterp, LLIMFloaterContainer* containerp) :
+ mName(name),
+ mUUID(uuid),
+ mFloater(floaterp),
+ mContainer(containerp)
+{
+ // Hack: the nearby chat has no name so we catch that case and impose one
+ // Of course, we won't be doing this in the final code
+ if (name == "")
+ mName = "Nearby Chat";
+}
+
+// Virtual action callbacks
+void LLConversationItem::selectItem(void)
+{
+ LLMultiFloater* host_floater = mFloater->getHost();
+ if (host_floater == mContainer)
+ {
+ // Always expand the message pane if the panel is hosted by the container
+ mContainer->collapseMessagesPane(false);
+ // Switch to the conversation floater that is being selected
+ mContainer->selectFloater(mFloater);
+ }
+ // Set the focus on the selected floater
+ mFloater->setFocus(TRUE);
+}
+
+void LLConversationItem::setVisibleIfDetached(BOOL visible)
+{
+ // Do this only if the conversation floater has been torn off (i.e. no multi floater host) and is not minimized
+ // Note: minimized dockable floaters are brought to front hence unminimized when made visible and we don't want that here
+ if (!mFloater->getHost() && !mFloater->isMinimized())
+ {
+ mFloater->setVisible(visible);
+ }
+}
+
+void LLConversationItem::performAction(LLInventoryModel* model, std::string action)
+{
+}
+
+void LLConversationItem::openItem( void )
+{
+}
+
+void LLConversationItem::closeItem( void )
+{
+}
+
+void LLConversationItem::previewItem( void )
+{
+}
+
+void LLConversationItem::showProperties(void)
+{
+}
+
// EOF
diff --git a/indra/newview/llimfloatercontainer.h b/indra/newview/llimfloatercontainer.h
index 7b395fb18f..2bbd371e8f 100644
--- a/indra/newview/llimfloatercontainer.h
+++ b/indra/newview/llimfloatercontainer.h
@@ -30,17 +30,102 @@
#include <map>
#include <vector>
+#include "llimview.h"
#include "llfloater.h"
#include "llmultifloater.h"
#include "llavatarpropertiesprocessor.h"
#include "llgroupmgr.h"
+#include "llfolderviewitem.h"
+#include "llfoldervieweventlistener.h"
+
class LLButton;
class LLLayoutPanel;
class LLLayoutStack;
class LLTabContainer;
+class LLIMFloaterContainer;
+
+// CHUI-137 : Temporary implementation of conversations list
+class LLConversationItem;
+
+typedef std::map<LLFloater*, LLConversationItem*> conversations_items_map;
+typedef std::map<LLFloater*, LLFolderViewItem*> conversations_widgets_map;
-class LLIMFloaterContainer : public LLMultiFloater
+// Conversation items: we hold a list of those and create an LLFolderViewItem widget for each
+// that we tuck into the mConversationsListPanel.
+class LLConversationItem : public LLFolderViewEventListener
+{
+public:
+ LLConversationItem(std::string name, const LLUUID& uuid, LLFloater* floaterp, LLIMFloaterContainer* containerp);
+ virtual ~LLConversationItem() {}
+
+ // Stub those things we won't really be using in this conversation context
+ virtual const std::string& getName() const { return mName; }
+ virtual const std::string& getDisplayName() const { return mName; }
+ virtual const LLUUID& getUUID() const { return mUUID; }
+ virtual time_t getCreationDate() const { return 0; }
+ virtual PermissionMask getPermissionMask() const { return PERM_ALL; }
+ virtual LLFolderType::EType getPreferredType() const { return LLFolderType::FT_NONE; }
+ virtual LLPointer<LLUIImage> getIcon() const { return NULL; }
+ virtual LLPointer<LLUIImage> getOpenIcon() const { return getIcon(); }
+ virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; }
+ virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
+ virtual BOOL isItemRenameable() const { return FALSE; }
+ virtual BOOL renameItem(const std::string& new_name) { return FALSE; }
+ virtual BOOL isItemMovable( void ) const { return FALSE; }
+ virtual BOOL isItemRemovable( void ) const { return FALSE; }
+ virtual BOOL isItemInTrash( void) const { return FALSE; }
+ virtual BOOL removeItem() { return FALSE; }
+ virtual void removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch) { }
+ virtual void move( LLFolderViewEventListener* parent_listener ) { }
+ virtual BOOL isItemCopyable() const { return FALSE; }
+ virtual BOOL copyToClipboard() const { return FALSE; }
+ virtual BOOL cutToClipboard() const { return FALSE; }
+ virtual BOOL isClipboardPasteable() const { return FALSE; }
+ virtual void pasteFromClipboard() { }
+ virtual void pasteLinkFromClipboard() { }
+ virtual void buildContextMenu(LLMenuGL& menu, U32 flags) { }
+ virtual BOOL isUpToDate() const { return TRUE; }
+ virtual BOOL hasChildren() const { return FALSE; }
+ virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; }
+ virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; }
+
+ // The action callbacks
+ virtual void performAction(LLInventoryModel* model, std::string action);
+ virtual void openItem( void );
+ virtual void closeItem( void );
+ virtual void previewItem( void );
+ virtual void selectItem(void);
+ virtual void showProperties(void);
+
+ void setVisibleIfDetached(BOOL visible);
+
+ // This method should be called when a drag begins.
+ // Returns TRUE if the drag can begin, FALSE otherwise.
+ virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const { return FALSE; }
+
+ // This method will be called to determine if a drop can be
+ // performed, and will set drop to TRUE if a drop is
+ // requested.
+ // Returns TRUE if a drop is possible/happened, FALSE otherwise.
+ virtual BOOL dragOrDrop(MASK mask, BOOL drop,
+ EDragAndDropType cargo_type,
+ void* cargo_data,
+ std::string& tooltip_msg) { return FALSE; }
+
+ bool hasSameValues(std::string name, const LLUUID& uuid) { return ((name == mName) && (uuid == mUUID)); }
+ bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); }
+private:
+ std::string mName;
+ const LLUUID mUUID;
+ LLFloater* mFloater;
+ LLIMFloaterContainer* mContainer;
+};
+// CHUI-137 : End
+
+class LLIMFloaterContainer
+ : public LLMultiFloater
+ , public LLIMSessionObserver
{
public:
LLIMFloaterContainer(const LLSD& seed);
@@ -48,6 +133,8 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
+ /*virtual*/ void draw();
+ /*virtual*/ void setVisible(BOOL visible);
void onCloseFloater(LLUUID& id);
/*virtual*/ void addFloater(LLFloater* floaterp,
@@ -55,6 +142,8 @@ public:
LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
/*virtual*/ void removeFloater(LLFloater* floaterp);
+ /*virtual*/ void tabClose();
+
static LLFloater* getCurrentVoiceFloater();
static LLIMFloaterContainer* findInstance();
@@ -64,6 +153,13 @@ public:
virtual void setMinimized(BOOL b);
void collapseMessagesPane(bool collapse);
+
+
+ // LLIMSessionObserver observe triggers
+ /*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {};
+ /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id);
+ /*virtual*/ void sessionRemoved(const LLUUID& session_id) {};
+ /*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) {};
private:
typedef std::map<LLUUID,LLFloater*> avatarID_panel_map_t;
@@ -87,6 +183,18 @@ private:
LLLayoutPanel* mMessagesPane;
LLLayoutPanel* mConversationsPane;
LLLayoutStack* mConversationsStack;
+
+ // CHUI-137 : Temporary implementation of conversations list
+public:
+ void removeConversationListItem(LLFloater* floaterp, bool change_focus = true);
+ void addConversationListItem(std::string name, const LLUUID& uuid, LLFloater* floaterp);
+ LLFloater* findConversationItem(LLUUID& uuid);
+private:
+ LLFolderViewItem* createConversationItemWidget(LLConversationItem* item);
+ // Conversation list data
+ LLPanel* mConversationsListPanel; // This is the widget we add items to (i.e. clickable title for each conversation)
+ conversations_items_map mConversationsItems;
+ conversations_widgets_map mConversationsWidgets;
};
#endif // LL_LLIMFLOATERCONTAINER_H
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 0d2b1f06b5..79018ec366 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -2582,7 +2582,9 @@ LLUUID LLIMMgr::addSession(
{
LLDynamicArray<LLUUID> ids;
ids.put(other_participant_id);
- return addSession(name, dialog, other_participant_id, ids, voice);
+ LLUUID session_id = addSession(name, dialog, other_participant_id, ids, voice);
+ notifyObserverSessionVoiceOrIMStarted(session_id);
+ return session_id;
}
// Adds a session using the given session_id. If the session already exists
@@ -2610,6 +2612,7 @@ LLUUID LLIMMgr::addSession(
if (floater_id.notNull())
{
LLIMFloater* im_floater = LLIMFloater::findInstance(floater_id);
+
if (im_floater && im_floater->getStartConferenceInSameFloater())
{
// The IM floater should be initialized with a new session_id
@@ -2936,6 +2939,14 @@ void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::st
}
}
+void LLIMMgr::notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id)
+{
+ for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++)
+ {
+ (*it)->sessionVoiceOrIMStarted(session_id);
+ }
+}
+
void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id)
{
for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++)
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index 58a2ac5162..80bf315aa8 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -298,6 +298,7 @@ class LLIMSessionObserver
public:
virtual ~LLIMSessionObserver() {}
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0;
+ virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) = 0;
virtual void sessionRemoved(const LLUUID& session_id) = 0;
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) = 0;
};
@@ -462,6 +463,7 @@ private:
static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& name, bool is_group);
void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ void notifyObserverSessionVoiceOrIMStarted(const LLUUID& session_id);
void notifyObserverSessionRemoved(const LLUUID& session_id);
void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp
index cd181ce865..a81d6b4025 100644
--- a/indra/newview/llnearbychat.cpp
+++ b/indra/newview/llnearbychat.cpp
@@ -30,6 +30,7 @@
#include "lliconctrl.h"
#include "llappviewer.h"
+#include "llchatentry.h"
#include "llfloaterreg.h"
#include "lltrans.h"
#include "llimfloatercontainer.h"
@@ -130,6 +131,8 @@ LLNearbyChat::LLNearbyChat(const LLSD& key)
mSpeakerMgr(NULL),
mExpandedHeight(COLLAPSED_HEIGHT + EXPANDED_HEIGHT)
{
+ setIsChrome(TRUE);
+ mKey = LLSD();
mIsNearbyChat = true;
mSpeakerMgr = LLLocalSpeakerMgr::getInstance();
}
@@ -137,19 +140,14 @@ LLNearbyChat::LLNearbyChat(const LLSD& key)
//virtual
BOOL LLNearbyChat::postBuild()
{
- mChatBox = getChild<LLLineEditor>("chat_editor");
+ mChatBox = getChild<LLChatEntry>("chat_editor");
mChatBox->setCommitCallback(boost::bind(&LLNearbyChat::onChatBoxCommit, this));
- mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this);
+ mChatBox->setKeystrokeCallback(boost::bind(&onChatBoxKeystroke, _1, this));
mChatBox->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this));
mChatBox->setFocusReceivedCallback(boost::bind(&LLNearbyChat::onChatBoxFocusReceived, this));
- mChatBox->setIgnoreArrowKeys( FALSE );
mChatBox->setCommitOnFocusLost( FALSE );
- mChatBox->setRevertOnEsc( FALSE );
- mChatBox->setIgnoreTab(TRUE);
mChatBox->setPassDelete(TRUE);
- mChatBox->setReplaceNewlinesWithSpaces(FALSE);
- mChatBox->setEnableLineHistory(TRUE);
mChatBox->setFont(LLViewerChat::getChatFont());
// mOutputMonitor = getChild<LLOutputMonitorCtrl>("chat_zone_indicator");
@@ -189,6 +187,21 @@ BOOL LLNearbyChat::postBuild()
return LLIMConversation::postBuild();
}
+// virtual
+void LLNearbyChat::refresh()
+{
+ displaySpeakingIndicator();
+ updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState());
+
+ // *HACK: Update transparency type depending on whether our children have focus.
+ // This is needed because this floater is chrome and thus cannot accept focus, so
+ // the transparency type setting code from LLFloater::setFocus() isn't reached.
+ if (getTransparencyType() != TT_DEFAULT)
+ {
+ setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
+ }
+}
+
void LLNearbyChat::onNearbySpeakers()
{
LLSD param;
@@ -382,11 +395,14 @@ LLNearbyChat* LLNearbyChat::getInstance()
return LLFloaterReg::getTypedInstance<LLNearbyChat>("chat_bar");
}
-//static
-//LLNearbyChat* LLNearbyChat::findInstance()
-//{
-// return LLFloaterReg::findTypedInstance<LLNearbyChat>("chat_bar");
-//}
+void LLNearbyChat::show()
+{
+ if (isChatMultiTab())
+ {
+ openFloater(getKey());
+ }
+ setVisible(TRUE);
+}
void LLNearbyChat::showHistory()
{
@@ -397,33 +413,6 @@ void LLNearbyChat::showHistory()
storeRectControl();
}
-void LLNearbyChat::showTranslationCheckbox(BOOL show)
-{
- getChild<LLUICtrl>("translate_chat_checkbox_lp")->setVisible(show);
-}
-
-BOOL LLNearbyChat::tick()
-{
- // This check is needed until LLFloaterReg::removeInstance() is synchronized with deleting the floater
- // via LLMortician::updateClass(), to avoid calling dead instances. See LLFloater::destroy().
- if (isDead()) return false;
-
- BOOL parents_retcode = LLIMConversation::tick();
-
- displaySpeakingIndicator();
- updateCallBtnState(LLVoiceClient::getInstance()->getUserPTTState());
-
- // *HACK: Update transparency type depending on whether our children have focus.
- // This is needed because this floater is chrome and thus cannot accept focus, so
- // the transparency type setting code from LLFloater::setFocus() isn't reached.
- if (getTransparencyType() != TT_DEFAULT)
- {
- setTransparencyType(hasFocus() ? TT_ACTIVE : TT_INACTIVE);
- }
-
- return parents_retcode;
-}
-
std::string LLNearbyChat::getCurrentChat()
{
return mChatBox ? mChatBox->getText() : LLStringUtil::null;
@@ -469,7 +458,7 @@ BOOL LLNearbyChat::matchChatTypeTrigger(const std::string& in_str, std::string*
return string_was_found;
}
-void LLNearbyChat::onChatBoxKeystroke(LLLineEditor* caller, void* userdata)
+void LLNearbyChat::onChatBoxKeystroke(LLTextEditor* caller, void* userdata)
{
LLFirstUse::otherAvatarChatFirst(false);
@@ -523,17 +512,16 @@ void LLNearbyChat::onChatBoxKeystroke(LLLineEditor* caller, void* userdata)
{
std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
self->mChatBox->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part
- S32 outlength = self->mChatBox->getLength(); // in characters
// Select to end of line, starting from the character
// after the last one the user typed.
- self->mChatBox->setSelection(length, outlength);
+ self->mChatBox->selectNext(rest_of_match, false);
}
else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str))
{
std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size());
self->mChatBox->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part
- self->mChatBox->setCursorToEnd();
+ self->mChatBox->endOfDoc();
}
//llinfos << "GESTUREDEBUG " << trigger
@@ -591,11 +579,11 @@ void LLNearbyChat::sendChat( EChatType type )
{
if (mChatBox)
{
- LLWString text = mChatBox->getConvertedText();
+ LLWString text = mChatBox->getWText();
+ LLWStringUtil::trim(text);
+ LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines.
if (!text.empty())
{
- // store sent line in history, duplicates will get filtered
- mChatBox->updateHistory();
// Check if this is destined for another channel
S32 channel = 0;
stripChannelNumber(text, &channel);
@@ -794,6 +782,7 @@ void LLNearbyChat::startChat(const char* line)
if (cb )
{
+ cb->show();
cb->setVisible(TRUE);
cb->setFocus(TRUE);
cb->mChatBox->setFocus(TRUE);
@@ -804,7 +793,7 @@ void LLNearbyChat::startChat(const char* line)
cb->mChatBox->setText(line_string);
}
- cb->mChatBox->setCursorToEnd();
+ cb->mChatBox->endOfDoc();
}
}
diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h
index bc0e54de15..61404df942 100644
--- a/indra/newview/llnearbychat.h
+++ b/indra/newview/llnearbychat.h
@@ -65,15 +65,14 @@ public:
static LLNearbyChat* getInstance();
void addToHost();
+ void show();
/** @param archive true - to save a message to the chat history log */
void addMessage (const LLChat& message,bool archive = true, const LLSD &args = LLSD());
void onNearbyChatContextMenuItemClicked(const LLSD& userdata);
bool onNearbyChatCheckContextMenuItem(const LLSD& userdata);
- LLLineEditor* getChatBox() { return mChatBox; }
-
- //virtual void draw();
+ LLChatEntry* getChatBox() { return mChatBox; }
std::string getCurrentChat();
@@ -87,11 +86,10 @@ public:
static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate);
void showHistory();
- void showTranslationCheckbox(BOOL show);
protected:
static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str);
- static void onChatBoxKeystroke(LLLineEditor* caller, void* userdata);
+ static void onChatBoxKeystroke(LLTextEditor* caller, void* userdata);
static void onChatBoxFocusLost(LLFocusableElement* caller, void* userdata);
void onChatBoxFocusReceived();
@@ -114,14 +112,12 @@ protected:
// Which non-zero channel did we last chat on?
static S32 sLastSpecialChatChannel;
- LLLineEditor* mChatBox;
+ LLChatEntry* mChatBox;
LLOutputMonitorCtrl* mOutputMonitor;
LLLocalSpeakerMgr* mSpeakerMgr;
S32 mExpandedHeight;
- /*virtual*/ BOOL tick();
-
private:
void getAllowedRect (LLRect& rect);
@@ -129,6 +125,8 @@ private:
void appendMessage(const LLChat& chat, const LLSD &args = 0);
void onNearbySpeakers ();
+ /*virtual*/ void refresh();
+
LLHandle<LLView> mPopupMenuHandle;
std::vector<LLChat> mMessageArchive;
LLChatHistory* mChatHistory;
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index e91a3fc334..c97e3585e1 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -555,7 +555,6 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg,
// Send event on to LLEventStream
sChatWatcher->post(chat);
-
if( nearby_chat->isInVisibleChain()
|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
&& gSavedSettings.getBOOL("UseChatBubbles") )
diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp
index d2dff63948..35cda14f8d 100644
--- a/indra/newview/llpanelblockedlist.cpp
+++ b/indra/newview/llpanelblockedlist.cpp
@@ -30,15 +30,23 @@
// library include
#include "llavatarname.h"
+#include "llfiltereditor.h"
#include "llfloater.h"
#include "llfloaterreg.h"
#include "llnotificationsutil.h"
#include "llscrolllistctrl.h"
+#include "llmenubutton.h"
// project include
+#include "llavatarlistitem.h"
+#include "llblocklist.h"
+#include "llblockedlistitem.h"
#include "llfloateravatarpicker.h"
#include "llfloatersidepanelcontainer.h"
+#include "llinventorylistitem.h"
+#include "llinventorymodel.h"
#include "llsidetraypanelcontainer.h"
+#include "llviewercontrol.h"
static LLRegisterPanelClassWrapper<LLPanelBlockedList> t_panel_blocked_list("panel_block_list_sidetray");
@@ -54,24 +62,35 @@ const std::string BLOCKED_PARAM_NAME = "blocked_to_select";
LLPanelBlockedList::LLPanelBlockedList()
: LLPanel()
{
- mCommitCallbackRegistrar.add("Block.ClickPick", boost::bind(&LLPanelBlockedList::onPickBtnClick, this));
- mCommitCallbackRegistrar.add("Block.ClickBlockByName", boost::bind(&LLPanelBlockedList::onBlockByNameClick, this));
- mCommitCallbackRegistrar.add("Block.ClickRemove", boost::bind(&LLPanelBlockedList::onRemoveBtnClick, this));
-}
-
-LLPanelBlockedList::~LLPanelBlockedList()
-{
- LLMuteList::getInstance()->removeObserver(this);
+ mCommitCallbackRegistrar.add("Block.Action", boost::bind(&LLPanelBlockedList::onCustomAction, this, _2));
+ mEnableCallbackRegistrar.add("Block.Check", boost::bind(&LLPanelBlockedList::isActionChecked, this, _2));
}
BOOL LLPanelBlockedList::postBuild()
{
- mBlockedList = getChild<LLScrollListCtrl>("blocked");
+ mBlockedList = getChild<LLBlockList>("blocked");
mBlockedList->setCommitOnSelectionChange(TRUE);
- LLMuteList::getInstance()->addObserver(this);
-
- refreshBlockedList();
+ switch (gSavedSettings.getU32("BlockPeopleSortOrder"))
+ {
+ case E_SORT_BY_NAME:
+ mBlockedList->sortByName();
+ break;
+
+ case E_SORT_BY_TYPE:
+ mBlockedList->sortByType();
+ break;
+ }
+
+ // Use the context menu of the Block list for the Block tab gear menu.
+ LLToggleableMenu* blocked_gear_menu = mBlockedList->getContextMenu();
+ if (blocked_gear_menu)
+ {
+ getChild<LLMenuButton>("blocked_gear_btn")->setMenu(blocked_gear_menu, LLMenuButton::MP_BOTTOM_LEFT);
+ }
+
+ getChild<LLButton>("unblock_btn")->setCommitCallback(boost::bind(&LLPanelBlockedList::unblockItem, this));
+ getChild<LLFilterEditor>("blocked_filter_input")->setCommitCallback(boost::bind(&LLPanelBlockedList::onFilterEdit, this, _2));
return LLPanel::postBuild();
}
@@ -92,7 +111,7 @@ void LLPanelBlockedList::onOpen(const LLSD& key)
void LLPanelBlockedList::selectBlocked(const LLUUID& mute_id)
{
- mBlockedList->selectByID(mute_id);
+ mBlockedList->selectItemByUUID(mute_id);
}
void LLPanelBlockedList::showPanelAndSelect(const LLUUID& idToSelect)
@@ -105,55 +124,64 @@ void LLPanelBlockedList::showPanelAndSelect(const LLUUID& idToSelect)
//////////////////////////////////////////////////////////////////////////
// Private Section
//////////////////////////////////////////////////////////////////////////
-void LLPanelBlockedList::refreshBlockedList()
+void LLPanelBlockedList::updateButtons()
{
- mBlockedList->deleteAllItems();
+ bool hasSelected = NULL != mBlockedList->getSelectedItem();
+ getChildView("unblock_btn")->setEnabled(hasSelected);
+}
- std::vector<LLMute> mutes = LLMuteList::getInstance()->getMutes();
- std::vector<LLMute>::iterator it;
- for (it = mutes.begin(); it != mutes.end(); ++it)
+void LLPanelBlockedList::unblockItem()
+{
+ LLBlockedListItem* item = mBlockedList->getBlockedItem();
+ if (item)
{
- LLScrollListItem::Params item_p;
- item_p.enabled(TRUE);
- item_p.value(it->mID); // link UUID of blocked item with ScrollListItem
- item_p.columns.add().column("item_name").value(it->mName);//.type("text");
- item_p.columns.add().column("item_type").value(it->getDisplayType());//.type("text").width(111);
-
- mBlockedList->addRow(item_p, ADD_BOTTOM);
+ LLMute mute(item->getUUID(), item->getName());
+ LLMuteList::instance().remove(mute);
}
}
-void LLPanelBlockedList::updateButtons()
+void LLPanelBlockedList::onCustomAction(const LLSD& userdata)
{
- bool hasSelected = NULL != mBlockedList->getFirstSelected();
- getChildView("Unblock")->setEnabled(hasSelected);
+ const std::string command_name = userdata.asString();
+
+ if ("block_obj_by_name" == command_name)
+ {
+ blockObjectByName();
+ }
+ else if ("block_res_by_name" == command_name)
+ {
+ blockResidentByName();
+ }
+ else if ("sort_by_name" == command_name)
+ {
+ mBlockedList->sortByName();
+ gSavedSettings.setU32("BlockPeopleSortOrder", E_SORT_BY_NAME);
+ }
+ else if ("sort_by_type" == command_name)
+ {
+ mBlockedList->sortByType();
+ gSavedSettings.setU32("BlockPeopleSortOrder", E_SORT_BY_TYPE);
+ }
}
-void LLPanelBlockedList::onRemoveBtnClick()
+BOOL LLPanelBlockedList::isActionChecked(const LLSD& userdata)
{
- std::string name = mBlockedList->getSelectedItemLabel();
- LLUUID id = mBlockedList->getStringUUIDSelectedItem();
- LLMute mute(id, name);
-
- S32 last_selected = mBlockedList->getFirstSelectedIndex();
- if (LLMuteList::getInstance()->remove(mute))
+ std::string item = userdata.asString();
+ U32 sort_order = gSavedSettings.getU32("BlockPeopleSortOrder");
+
+ if ("sort_by_name" == item)
+ {
+ return E_SORT_BY_NAME == sort_order;
+ }
+ else if ("sort_by_type" == item)
{
- // Above removals may rebuild this dialog.
-
- if (last_selected == mBlockedList->getItemCount())
- {
- // we were on the last item, so select the last item again
- mBlockedList->selectNthItem(last_selected - 1);
- }
- else
- {
- // else select the item after the last item previously selected
- mBlockedList->selectNthItem(last_selected);
- }
+ return E_SORT_BY_TYPE == sort_order;
}
+
+ return false;
}
-void LLPanelBlockedList::onPickBtnClick()
+void LLPanelBlockedList::blockResidentByName()
{
const BOOL allow_multiple = FALSE;
const BOOL close_on_select = TRUE;
@@ -164,11 +192,19 @@ void LLPanelBlockedList::onPickBtnClick()
// addDependentFloater(picker);
}
-void LLPanelBlockedList::onBlockByNameClick()
+void LLPanelBlockedList::blockObjectByName()
{
LLFloaterGetBlockedObjectName::show(&LLPanelBlockedList::callbackBlockByName);
}
+void LLPanelBlockedList::onFilterEdit(const std::string& search_string)
+{
+ std::string filter = search_string;
+ LLStringUtil::trimHead(filter);
+
+ mBlockedList->setNameFilter(filter);
+}
+
void LLPanelBlockedList::callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
{
if (names.empty() || ids.empty()) return;
diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h
index 97236ecdbf..332349dfc0 100644
--- a/indra/newview/llpanelblockedlist.h
+++ b/indra/newview/llpanelblockedlist.h
@@ -30,21 +30,15 @@
#include "llpanel.h"
#include "llmutelist.h"
#include "llfloater.h"
-// #include <vector>
-// class LLButton;
-// class LLLineEditor;
-// class LLMessageSystem;
-// class LLUUID;
class LLAvatarName;
-class LLScrollListCtrl;
+class LLBlockList;
-class LLPanelBlockedList
- : public LLPanel, public LLMuteListObserver
+class LLPanelBlockedList : public LLPanel
{
public:
LLPanelBlockedList();
- ~LLPanelBlockedList();
+ ~LLPanelBlockedList(){};
virtual BOOL postBuild();
virtual void draw();
@@ -59,24 +53,31 @@ public:
* If it is LLUUID::null, nothing will be selected.
*/
static void showPanelAndSelect(const LLUUID& idToSelect);
-
- // LLMuteListObserver callback interface implementation.
- /* virtual */ void onChange() { refreshBlockedList();}
private:
- void refreshBlockedList();
+
+ typedef enum e_sort_oder{
+ E_SORT_BY_NAME = 0,
+ E_SORT_BY_TYPE = 1,
+ } ESortOrder;
+
void updateButtons();
// UI callbacks
- void onRemoveBtnClick();
- void onPickBtnClick();
- void onBlockByNameClick();
+ void unblockItem();
+ void blockResidentByName();
+ void blockObjectByName();
+ void onFilterEdit(const std::string& search_string);
+
+ // List commnads
+ void onCustomAction(const LLSD& userdata);
+ BOOL isActionChecked(const LLSD& userdata);
void callbackBlockPicked(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
static void callbackBlockByName(const std::string& text);
private:
- LLScrollListCtrl* mBlockedList;
+ LLBlockList* mBlockedList;
};
//-----------------------------------------------------------------------------
diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index 280cc11179..854deb00d0 100644
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -230,7 +230,7 @@ void LLPanelTopInfoBar::buildLocationString(std::string& loc_str, bool show_coor
void LLPanelTopInfoBar::setParcelInfoText(const std::string& new_text)
{
LLRect old_rect = getRect();
- const LLFontGL* font = mParcelInfoText->getDefaultFont();
+ const LLFontGL* font = mParcelInfoText->getFont();
S32 new_text_width = font->getWidth(new_text);
mParcelInfoText->setText(new_text);
diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp
index 59d26edff2..47518a365f 100644
--- a/indra/newview/llparticipantlist.cpp
+++ b/indra/newview/llparticipantlist.cpp
@@ -475,6 +475,7 @@ void LLParticipantList::update()
{
mSpeakerMgr->update(true);
+ // Need to resort the participant list if it's in sort by recent speaker order.
if (E_SORT_BY_RECENT_SPEAKERS == getSortOrder() && !isHovered())
{
// Resort avatar list
diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h
index f497f546aa..8758c8c4e5 100644
--- a/indra/newview/llsyswellwindow.h
+++ b/indra/newview/llsyswellwindow.h
@@ -169,6 +169,7 @@ public:
// LLIMSessionObserver observe triggers
/*virtual*/ void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
+ /*virtual*/ void sessionVoiceOrIMStarted(const LLUUID& session_id) {};
/*virtual*/ void sessionRemoved(const LLUUID& session_id);
/*virtual*/ void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index 707d2d9765..ed350ea144 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -112,7 +112,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi
style.font = date_font;
pMessageText->appendText(timeStr + "\n", TRUE, style);
- style.font = pMessageText->getDefaultFont();
+ style.font = pMessageText->getFont();
pMessageText->appendText(message, TRUE, style);
//attachment
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index e20d516392..09f8dcf83c 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -68,7 +68,7 @@ void LLToastPanel::snapToMessageHeight(LLTextBase* message, S32 maxLineCount)
if (message->getVisible())
{
S32 heightDelta = 0;
- S32 maxTextHeight = message->getDefaultFont()->getLineHeight() * maxLineCount;
+ S32 maxTextHeight = message->getFont()->getLineHeight() * maxLineCount;
LLRect messageRect = message->getRect();
S32 oldTextHeight = messageRect.getHeight();
diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp
index 2529ec865a..45fbabad59 100644
--- a/indra/newview/lltoastscripttextbox.cpp
+++ b/indra/newview/lltoastscripttextbox.cpp
@@ -65,7 +65,7 @@ LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification
pMessageText->clear();
LLStyle::Params style;
- style.font = pMessageText->getDefaultFont();
+ style.font = pMessageText->getFont();
pMessageText->appendText(message, TRUE, style);
//submit button
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index df1962f5fe..bf12b08321 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -186,6 +186,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterBump>);
LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);
+ LLFloaterReg::add("chat_bar", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>);
LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>);
@@ -208,7 +209,6 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("help_browser", "floater_help_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHelpBrowser>);
LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>);
- LLFloaterReg::add("chat_bar", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>);
LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>);
LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>);
LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 7f14e021fd..258bc5b698 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -56,6 +56,7 @@
// linden library includes
#include "llaudioengine.h" // mute on minimize
+#include "llchatentry.h"
#include "indra_constants.h"
#include "llassetstorage.h"
#include "llerrorcontrol.h"
@@ -2492,7 +2493,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
if (nearby_chat)
{
- LLLineEditor* chat_editor = nearby_chat->getChatBox();
+ LLChatEntry* chat_editor = nearby_chat->getChatBox();
// arrow keys move avatar while chatting hack
if (chat_editor && chat_editor->hasFocus())
@@ -2555,7 +2556,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
!keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
{
- LLLineEditor* chat_editor = LLFloaterReg::getTypedInstance<LLNearbyChat>("chat_bar")->getChatBox();
+ LLChatEntry* chat_editor = LLNearbyChat::getInstance()->getChatBox();
if (chat_editor)
{
// passing NULL here, character will be added later when it is handled by character handler.
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_add_person.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_add_person.png
new file mode 100755
index 0000000000..f024c733f3
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_add_person.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.png
new file mode 100755
index 0000000000..a19e720d42
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_ne.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.png
new file mode 100755
index 0000000000..7f3f42639d
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_arrow_sw.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_call_log.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_call_log.png
new file mode 100755
index 0000000000..2880eb766a
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_call_log.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_close.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_close.png
new file mode 100755
index 0000000000..25a939d7f5
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_close.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_collapse.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_collapse.png
new file mode 100755
index 0000000000..82baabde47
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_collapse.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_expand.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_expand.png
new file mode 100755
index 0000000000..7d64abb042
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_expand.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.png
new file mode 100755
index 0000000000..f0da962c2d
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_hang_up.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_open_call.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_open_call.png
new file mode 100755
index 0000000000..0db001dcdb
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_open_call.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_plus.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_plus.png
new file mode 100755
index 0000000000..0cf7edc2d4
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_plus.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/icons/Conv_toolbar_sort.png b/indra/newview/skins/default/textures/icons/Conv_toolbar_sort.png
new file mode 100755
index 0000000000..a0c15a6d3e
--- /dev/null
+++ b/indra/newview/skins/default/textures/icons/Conv_toolbar_sort.png
Binary files differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index eabcc68916..ce9474d5e5 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -160,7 +160,21 @@ with the same filename but different name
<texture name="ComboButton_On" file_name="widgets/ComboButton_On.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
<texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
+
<texture name="Container" file_name="containers/Container.png" preload="false" />
+
+ <texture name="Conv_toolbar_add_person" file_name="icons/Conv_toolbar_add_person.png" preload="false" />
+ <texture name="Conv_toolbar_arrow_ne" file_name="icons/Conv_toolbar_arrow_ne.png" preload="false" />
+ <texture name="Conv_toolbar_arrow_sw" file_name="icons/Conv_toolbar_arrow_sw.png" preload="false" />
+ <texture name="Conv_toolbar_call_log" file_name="icons/Conv_toolbar_call_log.png" preload="false" />
+ <texture name="Conv_toolbar_close" file_name="icons/Conv_toolbar_close.png" preload="false" />
+ <texture name="Conv_toolbar_collapse" file_name="icons/Conv_toolbar_collapse.png" preload="false" />
+ <texture name="Conv_toolbar_expand" file_name="icons/Conv_toolbar_expand.png" preload="false" />
+ <texture name="Conv_toolbar_hang_up" file_name="icons/Conv_toolbar_hang_up.png" preload="false" />
+ <texture name="Conv_toolbar_open_call" file_name="icons/Conv_toolbar_open_call.png" preload="false" />
+ <texture name="Conv_toolbar_plus" file_name="icons/Conv_toolbar_plus.png" preload="false" />
+ <texture name="Conv_toolbar_sort" file_name="icons/Conv_toolbar_sort.png" preload="false" />
+
<texture name="Copy" file_name="icons/Copy.png" preload="false" />
<texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />
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 ce40f44a64..8e434b5848 100644
--- a/indra/newview/skins/default/xui/en/floater_im_container.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_container.xml
@@ -15,10 +15,10 @@
width="680">
<string
name="collapse_icon"
- value="TabIcon_Open_Off"/>
+ value="Conv_toolbar_collapse"/>
<string
name="expand_icon"
- value="TabIcon_Close_Off"/>
+ value="Conv_toolbar_expand"/>
<layout_stack
animate="true"
follows="all"
@@ -53,7 +53,7 @@
follows="top|left"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="OptionsMenu_Off"
+ image_overlay="Conv_toolbar_sort"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -65,7 +65,7 @@
follows="top|left"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="AddItem_Off"
+ image_overlay="Conv_toolbar_plus"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -84,7 +84,7 @@
follows="right|top"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="TabIcon_Open_Off"
+ image_overlay="Conv_toolbar_collapse"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml
index a4695b8c09..32eb4ebdae 100644
--- a/indra/newview/skins/default/xui/en/floater_im_session.xml
+++ b/indra/newview/skins/default/xui/en/floater_im_session.xml
@@ -18,20 +18,20 @@
<floater.string
name="NearbyChatTitle"
value="Nearby Chat"/>
- <floater.string name="call_btn_start">VoicePTT_Off</floater.string>
- <floater.string name="call_btn_stop">VoicePTT_On</floater.string>
+ <floater.string name="call_btn_start">Conv_toolbar_open_call</floater.string>
+ <floater.string name="call_btn_stop">Conv_toolbar_hang_up</floater.string>
<floater.string
name="collapse_icon"
- value="TabIcon_Open_Off"/>
+ value="Conv_toolbar_collapse"/>
<floater.string
name="expand_icon"
- value="TabIcon_Close_Off"/>
+ value="Conv_toolbar_expand"/>
<floater.string
name="tear_off_icon"
- value="tearoffbox.tga"/>
+ value="Conv_toolbar_arrow_ne"/>
<floater.string
name="return_icon"
- value="Icon_Dock_Foreground"/>
+ value="Conv_toolbar_arrow_sw"/>
<view
follows="all"
layout="topleft"
@@ -52,10 +52,10 @@
menu_filename="menu_im_session_showmodes.xml"
follows="top|left"
height="25"
- image_hover_unselected="Toolbar_Left_Over"
- image_overlay="OptionsMenu_Off"
- image_selected="Toolbar_Left_Selected"
- image_unselected="Toolbar_Left_Off"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
layout="topleft"
left="5"
name="view_options_btn"
@@ -66,7 +66,7 @@
follows="top|left"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="AddItem_Off"
+ image_overlay="Conv_toolbar_add_person"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -77,10 +77,10 @@
<button
follows="top|left"
height="25"
- image_hover_unselected="Toolbar_Right_Over"
- image_overlay="VoicePTT_Off"
- image_selected="Toolbar_Right_Selected"
- image_unselected="Toolbar_Right_Off"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_open_call"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
layout="topleft"
top="5"
left_pad="4"
@@ -90,7 +90,7 @@
follows="right|top"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Icon_Close_Foreground"
+ image_overlay="Conv_toolbar_close"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -102,7 +102,7 @@
follows="right|top"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="TabIcon_Open_Off"
+ image_overlay="Conv_toolbar_collapse"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -114,7 +114,7 @@
follows="right|top"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="tearoffbox.tga"
+ image_overlay="Conv_toolbar_arrow_ne"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -235,26 +235,22 @@
</layout_panel>
</layout_stack>
</panel>
- <panel width="225"
- height="31"
- left="4"
- name="bottom_panel"
- bottom="-1"
- follows="left|right|bottom"
- tab_group="1">
- <line_editor
- bottom="0"
- follows="left|right|bottom"
- font="SansSerifSmall"
- visible="true"
- height="20"
- label="To"
- layout="bottomleft"
- name="chat_editor"
- tab_group="3"
- width="220">
- </line_editor>
- </panel>
+ <chat_editor
+ bottom="0"
+ expand_lines_count="5"
+ follows="left|right|bottom"
+ font="SansSerifSmall"
+ visible="true"
+ height="20"
+ is_expandable="true"
+ label="To"
+ layout="bottomleft"
+ name="chat_editor"
+ max_length="1023"
+ tab_group="3"
+ width="240"
+ wrap="true">
+ </chat_editor>
</layout_panel>
</layout_stack>
</view>
diff --git a/indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml b/indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml
new file mode 100644
index 0000000000..63295ea27b
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_people_blocked_gear.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ name="menu_blocked_gear"
+ left="0" bottom="0" visible="false"
+ mouse_opaque="false">
+ <menu_item_call
+ label="Unblock"
+ name="unblock">
+ <on_click
+ function="Block.Action"
+ parameter="unblock_item" />
+ <on_enable
+ function="Block.Enable"
+ parameter="unblock_item" />
+ </menu_item_call>
+ <menu_item_call
+ label="Profile..."
+ name="profile">
+ <on_click
+ function="Block.Action"
+ parameter="profile_item"/>
+ <on_enable
+ function="Block.Enable"
+ parameter="profile_item" />
+ </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml b/indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml
new file mode 100644
index 0000000000..0c7155667e
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_people_blocked_plus.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ name="menu_blocked_plus"
+ left="0" bottom="0" visible="false"
+ mouse_opaque="false">
+ <menu_item_call
+ label="Block Resident by name..."
+ name="block_resident_by_name">
+ <on_click
+ function="Block.Action"
+ parameter="block_res_by_name"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Block object by name"
+ name="block_object_by_name">
+ <on_click
+ function="Block.Action"
+ parameter="block_obj_by_name"/>
+ </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_people_blocked_view.xml b/indra/newview/skins/default/xui/en/menu_people_blocked_view.xml
new file mode 100644
index 0000000000..2efb70ee37
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/menu_people_blocked_view.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ name="menu_blocked_view"
+ left="0" bottom="0" visible="false"
+ mouse_opaque="false">
+ <menu_item_check
+ label="Sort by name"
+ name="sort_by_name">
+ <on_click
+ function="Block.Action"
+ parameter="sort_by_name"/>
+ <on_check
+ function="Block.Check"
+ parameter="sort_by_name"/>
+ </menu_item_check>
+ <menu_item_check
+ label="Sort by type"
+ name="sort_by_type">
+ <on_click
+ function="Block.Action"
+ parameter="sort_by_type" />
+ <on_check
+ function="Block.Check"
+ parameter="sort_by_type" />
+ </menu_item_check>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
index 3577d2f457..24f7d44cce 100644
--- a/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
+++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml
@@ -5,90 +5,94 @@
height="305"
layout="topleft"
left="0"
- right="-1"
name="block_list_panel"
help_topic="blocked_list"
min_height="350"
min_width="240"
- width="280">
- <button
- follows="top|left"
- height="24"
- image_hover_unselected="BackButton_Over"
- image_pressed="BackButton_Press"
- image_unselected="BackButton_Off"
- layout="topleft"
- name="back"
- left="4"
- tab_stop="false"
- top="1"
- width="30"/>
- <text
- follows="top|left|right"
- font="SansSerifLargeBold"
- height="20"
- layout="topleft"
- left_pad="10"
- name="title_text"
- text_color="white"
- top="5"
- width="250">
- Block List
- </text>
- <scroll_list
+ width="323">
+ <panel
+ follows="left|top|right"
+ height="27"
+ label="bottom_panel"
+ layout="topleft"
+ left="0"
+ name="blocked_buttons_panel"
+ right="-1"
+ top="0">
+ <filter_editor
+ follows="left|top|right"
+ height="23"
+ layout="topleft"
+ left="6"
+ label="Filter"
+ max_length_chars="300"
+ name="blocked_filter_input"
+ text_color="Black"
+ text_pad_left="10"
+ top="4"
+ width="177" />
+ <menu_button
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="8"
+ menu_filename="menu_people_blocked_gear.xml"
+ menu_position="bottomleft"
+ name="blocked_gear_btn"
+ top="3"
+ width="31" />
+ <menu_button
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="Conv_toolbar_sort"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="2"
+ menu_filename="menu_people_blocked_view.xml"
+ menu_position="bottomleft"
+ name="view_btn"
+ top_delta="0"
+ width="31" />
+ <menu_button
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="2"
+ menu_filename="menu_people_blocked_plus.xml"
+ menu_position="bottomleft"
+ name="plus_btn"
+ top_delta="0"
+ width="31"/>
+ <button
+ follows="right"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ left_pad="2"
+ layout="topleft"
+ name="unblock_btn"
+ top_delta="0"
+ width="31"/>
+ </panel>
+ <block_list
follows="all"
- height="190"
+ height="273"
layout="topleft"
- left="5"
+ left="3"
name="blocked"
tool_tip="List of currently blocked Residents"
- top="30"
- right="-1"
- width="270">
- <scroll_list.columns
- name="item_name" />
- <scroll_list.columns
- name="item_type"
- width="96" />
- </scroll_list>
- <button
- follows="left|bottom"
- height="23"
- label="Block person"
- layout="topleft"
- left_delta="0"
- name="Block resident..."
- tool_tip="Pick a Resident to block"
- top_pad="4"
- width="210">
- <button.commit_callback
- function="Block.ClickPick" />
- </button>
- <button
- follows="left|bottom"
- height="23"
- label="Block object by name"
- layout="topleft"
- left_delta="0"
- name="Block object by name..."
- tool_tip="Pick an object to block by name"
- top_pad="4"
- width="210" >
- <button.commit_callback
- function="Block.ClickBlockByName" />
- </button>
- <button
- enabled="false"
- follows="left|bottom"
- height="23"
- label="Unblock"
- layout="topleft"
- left_delta="0"
- name="Unblock"
- tool_tip="Remove Resident or object from blocked list"
- top_pad="4"
- width="210" >
- <button.commit_callback
- function="Block.ClickRemove" />
- </button>
+ top="31"
+ right="-1"/>
</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml b/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml
new file mode 100644
index 0000000000..84e7e467b1
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_blocked_list_item.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="23"
+ layout="topleft"
+ left="0"
+ name="blocked_list_item"
+ top="0"
+ width="380">
+ <icon
+ height="24"
+ follows="top|right|left"
+ image_name="ListItem_Select"
+ layout="topleft"
+ left="0"
+ name="selected_icon"
+ top="0"
+ visible="false"
+ width="380" />
+ <icon
+ follows="top|right|left"
+ height="24"
+ image_name="ListItem_Over"
+ layout="topleft"
+ left="0"
+ name="hovered_icon"
+ top="0"
+ visible="false"
+ width="380" />
+ <avatar_icon
+ default_icon_name="Generic_Person"
+ follows="top|left"
+ height="20"
+ layout="topleft"
+ left="5"
+ mouse_opaque="true"
+ top="2"
+ visible="false"
+ width="20" />
+ <group_icon
+ default_icon_name="Generic_Group"
+ follows="top|left"
+ height="20"
+ layout="topleft"
+ left="5"
+ mouse_opaque="true"
+ top="2"
+ visible="false"
+ width="20" />
+ <icon
+ follows="top|left"
+ height="16"
+ image_name="Inv_Object"
+ layout="topleft"
+ left="7"
+ name="object_icon"
+ top="4"
+ visible="false"
+ width="16" />
+ <text
+ follows="left|right"
+ font="SansSerifSmall"
+ font.color="DkGray"
+ height="15"
+ layout="topleft"
+ left_pad="5"
+ name="item_name"
+ parse_urls="false"
+ top="6"
+ use_ellipses="true"
+ width="180" />
+</panel> \ No newline at end of file
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index ceb03d03a9..09156b41b5 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -122,7 +122,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
follows="right"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Inv_Underpants"
+ image_overlay="Conv_toolbar_sort"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -270,7 +270,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
follows="right"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Inv_Underpants"
+ image_overlay="Conv_toolbar_sort"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -425,7 +425,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
follows="right"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Inv_Underpants"
+ image_overlay="Conv_toolbar_sort"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -533,7 +533,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
follows="right"
height="25"
image_hover_unselected="Toolbar_Middle_Over"
- image_overlay="Inv_Underpants"
+ image_overlay="Conv_toolbar_sort"
image_selected="Toolbar_Middle_Selected"
image_unselected="Toolbar_Middle_Off"
layout="topleft"
@@ -611,6 +611,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
filename="panel_block_list_sidetray.xml"
follows="all"
label="Blocked Residents &amp; Objects"
+ layout="topleft"
left="0"
font="SansSerifBold"
top="0"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
index caf7fc85f5..d7a7f7d735 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml
@@ -76,15 +76,6 @@
top_pad="5"
width="400" />
<check_box
- enabled="false"
- height="16"
- label="Enable plain text IM and chat history"
- layout="topleft"
- left_delta="0"
- name="plain_text_chat_history"
- top_pad="5"
- width="400" />
- <check_box
control_name="UseChatBubbles"
follows="left|top"
height="16"
@@ -95,55 +86,6 @@
name="bubble_text_chat"
width="150" />
<text
- name="show_ims_in_label"
- follows="left|top"
- layout="topleft"
- left="30"
- height="20"
- width="170"
- top_pad="15">
- Show IMs in:
- </text>
- <text
- name="requires_restart_label"
- follows="left|top"
- layout="topleft"
- top_delta="0"
- left="170"
- height="20"
- width="130"
- text_color="White_25">
- (requires restart)
- </text>
- <radio_group
- follows="left|top"
- height="30"
- left="40"
- control_name="ChatWindow"
- name="chat_window"
- top_pad="0"
- tool_tip="Show your Instant Messages in separate floaters, or in one floater with many tabs (Requires restart)"
- width="150">
- <radio_item
- height="16"
- label="Separate Windows"
- layout="topleft"
- left="0"
- name="radio"
- value="0"
- top="0"
- width="150" />
- <radio_item
- height="16"
- label="Tabs"
- layout="topleft"
- left_delta="0"
- name="radio2"
- value="1"
- top_pad="5"
- width="150" />
- </radio_group>
- <text
name="disable_toast_label"
follows="left|top"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 0a2fc13aff..7790a382d9 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3692,6 +3692,7 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Avatar_Label">Avatar</string>
<string name="Command_Build_Label">Build</string>
<string name="Command_Chat_Label">Chat</string>
+ <string name="Command_Conversations_Label">Conversations</string>
<string name="Command_Compass_Label">Compass</string>
<string name="Command_Destinations_Label">Destinations</string>
<string name="Command_Gestures_Label">Gestures</string>
@@ -3718,6 +3719,7 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Avatar_Tooltip">Choose a complete avatar</string>
<string name="Command_Build_Tooltip">Building objects and reshaping terrain</string>
<string name="Command_Chat_Tooltip">Chat with people nearby using text</string>
+ <string name="Command_Conversations_Tooltip">Converse with everyone</string>
<string name="Command_Compass_Tooltip">Compass</string>
<string name="Command_Destinations_Tooltip">Destinations of interest</string>
<string name="Command_Gestures_Tooltip">Gestures for your avatar</string>
diff --git a/indra/newview/skins/default/xui/en/widgets/chat_editor.xml b/indra/newview/skins/default/xui/en/widgets/chat_editor.xml
new file mode 100644
index 0000000000..f9facb593a
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/chat_editor.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<chat_editor
+ name="chat_editor"
+ show_context_menu="true"/>
diff --git a/indra/newview/skins/default/xui/en/widgets/text.xml b/indra/newview/skins/default/xui/en/widgets/text.xml
index 134f2d7522..2102074674 100644
--- a/indra/newview/skins/default/xui/en/widgets/text.xml
+++ b/indra/newview/skins/default/xui/en/widgets/text.xml
@@ -9,6 +9,7 @@
h_pad="0"
allow_scroll="false"
text_readonly_color="LabelTextColor"
+ text_tentative_color="TextFgTentativeColor"
bg_writeable_color="FloaterDefaultBackgroundColor"
use_ellipses="false"
bg_visible="false"