From 330840af7c363accc8e12d073ba91b871c578d27 Mon Sep 17 00:00:00 2001 From: Martin Reddy Date: Fri, 4 Sep 2009 12:11:27 +0000 Subject: Merging the SLURLs Everywhere branch (viewer-2.0.0-slurls-3) into Viewer 2.0 (viewer-2.0.0-3). This provides support for clickable Urls in text editors and textboxes, with right-click context menus, tooltips, and alternate link labels. This includes alert boxes, the login progress window, local chat and IM interfaces, etc. As well as context menus for avatars and groups in list widgets. Includes fixes for the following individual JIRAs: DEV-8763 VWR-10636: Hyperlinks in alert dialogs should be selectable (clickable)! DEV-38829 EXT-742: Remove LLLink class DEV-35459 VWR-14679: SLURLs and teleport Links not parsed properly DEV-19842 VWR-8773: Closing parenthesis ")" breaks urls DEV-21577 VWR-9405: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat DEV-37652 SEC-435: Object Chat/IMs are untraceable (VWR-2388) Fix has left flaw DEV-10353: URLs in chat log terminated incorrectly when newline in chat DEV-2925: In chat history, use a teleport hyperlink as source name for object IMs DEV-36192: Need a way to copy Avatar names and Group names DEV-2926: Allow viewer hyperlinks to have different text than the actual url DEV-27253: Add easy way to copy URLs from viewer chat DEV-38274: Make About Second Life window use new Url hyperlinking features DEV-39076: No url support in Text Editors DEV-7476 VWR-2172: Add hyperlinks to chat console for easier access DEV-7475: Add hyperlinks to notecards! DEV-35375 EXT-128: HTTPS urls aren't loaded in the internal browser by click Master JIRA issues: DEV-32819, DEV-323820, DEV-7474 Testing performed against QAR-1789 svn merge -r 131623:131889 svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-slurl-3 svn merge -r 131978:132515 svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-slurl-3 --- indra/llui/lltextbox.cpp | 498 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 413 insertions(+), 85 deletions(-) (limited to 'indra/llui/lltextbox.cpp') diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 96e72487b8..7a92bfb74c 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -32,30 +32,24 @@ #include "linden_common.h" #include "lltextbox.h" -#include "lllink.h" #include "lluictrlfactory.h" #include "llfocusmgr.h" #include "llwindow.h" +#include "llurlregistry.h" +#include "llstyle.h" static LLDefaultChildRegistry::Register r("text"); -//*NOTE -// LLLink is not used in code for now, therefor Visual Studio doesn't build it. -// "link" is registered here to force Visual Studio to build LLLink class. -static LLDefaultChildRegistry::Register register_link("link"); - LLTextBox::Params::Params() : text_color("text_color"), length("length"), type("type"), - highlight_on_hover("hover", false), border_visible("border_visible", false), border_drop_shadow_visible("border_drop_shadow_visible", false), bg_visible("bg_visible", false), use_ellipses("use_ellipses"), word_wrap("word_wrap", false), drop_shadow_visible("drop_shadow_visible"), - hover_color("hover_color"), disabled_color("disabled_color"), background_color("background_color"), border_color("border_color"), @@ -68,9 +62,7 @@ LLTextBox::Params::Params() LLTextBox::LLTextBox(const LLTextBox::Params& p) : LLUICtrl(p), - mFontGL(p.font), - mHoverActive( p.highlight_on_hover ), - mHasHover( FALSE ), + LLTextBase(p), mBackgroundVisible( p.bg_visible ), mBorderVisible( p.border_visible ), mShadowType( p.font_shadow ), @@ -84,12 +76,11 @@ LLTextBox::LLTextBox(const LLTextBox::Params& p) mDisabledColor(p.disabled_color()), mBackgroundColor(p.background_color()), mBorderColor(p.border_color()), - mHoverColor(p.hover_color()), mHAlign(p.font_halign), mLineSpacing(p.line_spacing), - mWordWrap( p.word_wrap ), mDidWordWrap(FALSE) { + mWordWrap = p.word_wrap; setText( p.text() ); } @@ -97,9 +88,9 @@ BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; - // HACK: Only do this if there actually is a click callback, so that + // HACK: Only do this if there actually is something to click, so that // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback) + if (isClickable()) { handled = TRUE; @@ -121,10 +112,9 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) // We only handle the click if the click both started and ended within us - // HACK: Only do this if there actually is a click callback, so that + // HACK: Only do this if there actually is something to click, so that // overly large text boxes in the older UI won't start eating clicks. - if (mClickedCallback - && hasMouseCapture()) + if (isClickable() && hasMouseCapture()) { handled = TRUE; @@ -136,27 +126,44 @@ BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) make_ui_sound("UISndClickRelease"); } - // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. - // If mouseup in the widget, it's been clicked - if (mClickedCallback) + // handle clicks on Urls in the textbox first + if (! handleMouseUpOverUrl(x, y)) { - mClickedCallback(); + // DO THIS AT THE VERY END to allow the button to be destroyed + // as a result of being clicked. If mouseup in the widget, + // it's been clicked + if (mClickedCallback && ! handled) + { + mClickedCallback(); + } } } return handled; } +BOOL LLTextBox::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + // pop up a context menu for any Url under the cursor + return handleRightMouseDownOverUrl(this, x, y); +} + BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = LLView::handleHover(x,y,mask); - if(mHoverActive) + // Check to see if we're over an HTML-style link + if (handleHoverOverUrl(x, y)) { - mHasHover = TRUE; // This should be set every frame during a hover. - getWindow()->setCursor(UI_CURSOR_ARROW); + lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; + getWindow()->setCursor(UI_CURSOR_HAND); + return TRUE; } - return (handled || mHasHover); + return LLView::handleHover(x,y,mask); +} + +BOOL LLTextBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +{ + return handleToolTipForUrl(this, x, y, msg, sticky_rect_screen); } void LLTextBox::setText(const LLStringExplicit& text) @@ -168,7 +175,7 @@ void LLTextBox::setText(const LLStringExplicit& text) else { mText.assign(text); - setLineLengths(); + updateDisplayTextAndSegments(); } } @@ -177,11 +184,11 @@ void LLTextBox::setLineLengths() mLineLengthList.clear(); std::string::size_type cur = 0; - std::string::size_type len = mText.getWString().size(); + std::string::size_type len = mDisplayText.size(); while (cur < len) { - std::string::size_type end = mText.getWString().find('\n', cur); + std::string::size_type end = mDisplayText.find('\n', cur); std::string::size_type runLen; if (end == std::string::npos) @@ -199,20 +206,12 @@ void LLTextBox::setLineLengths() } } -void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width) +LLWString LLTextBox::wrapText(const LLWString &wtext, S32 &hoffset, S32 &line_num, F32 max_width) { - if (max_width < 0.0f) - { - max_width = (F32)getRect().getWidth(); - } - - LLWString wtext = utf8str_to_wstring(in_text); LLWString final_wtext; - LLWString::size_type cur = 0;; - LLWString::size_type len = wtext.size(); - F32 line_height = mFontGL->getLineHeight(); - S32 line_num = 1; + LLWString::size_type cur = 0; + LLWString::size_type len = wtext.size(); while (cur < len) { LLWString::size_type end = wtext.find('\n', cur); @@ -221,41 +220,121 @@ void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width) end = len; } + bool charsRemaining = true; LLWString::size_type runLen = end - cur; if (runLen > 0) { + // work out how many chars can fit onto the current line LLWString run(wtext, cur, runLen); LLWString::size_type useLen = - mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); + mDefaultFont->maxDrawableChars(run.c_str(), max_width-hoffset, runLen, TRUE); + charsRemaining = (cur + useLen < len); + // try to break lines on word boundaries + if (useLen < run.size()) + { + LLWString::size_type prev_use_len = useLen; + while (useLen > 0 && ! isspace(run[useLen-1]) && ! ispunct(run[useLen-1])) + { + --useLen; + } + if (useLen == 0) + { + useLen = prev_use_len; + } + } + + // add the chars that could fit onto one line to our result final_wtext.append(wtext, cur, useLen); cur += useLen; - // not enough room to add any more characters - if (useLen == 0) break; + hoffset += mDefaultFont->getWidth(run.substr(0, useLen).c_str()); + + // abort if not enough room to add any more characters + if (useLen == 0) + { + break; + } } - if (cur < len) + if (charsRemaining) { if (wtext[cur] == '\n') { cur += 1; } - line_num +=1; - // Don't wrap the last line if the text is going to spill off - // the bottom of the rectangle. Assume we prefer to run off - // the right edge. - // *TODO: Is this the right behavior? - if((line_num-1)*line_height <= (F32)getRect().getHeight()) + final_wtext += '\n'; + hoffset = 0; + line_num += 1; + } + } + + return final_wtext; +} + +void LLTextBox::setWrappedText(const LLStringExplicit& in_text, F32 max_width) +{ + mDidWordWrap = TRUE; + setText(wstring_to_utf8str(getWrappedText(in_text, max_width))); +} + +LLWString LLTextBox::getWrappedText(const LLStringExplicit& in_text, F32 max_width) +{ + // + // we don't want to wrap Urls otherwise we won't be able to detect their + // presence for hyperlinking. So we look for all Urls, and then word wrap + // the text before and after, but never break a Url in the middle. We + // also need to consider that the Url will be displayed as a label (not + // necessary the actual Url string). + // + + if (max_width < 0.0f) + { + max_width = (F32)getRect().getWidth(); + } + + LLWString wtext = utf8str_to_wstring(in_text); + LLWString final_wtext; + S32 line_num = 1; + S32 hoffset = 0; + + // find the next Url in the text string + LLUrlMatch match; + while ( LLUrlRegistry::instance().findUrl(wstring_to_utf8str(wtext), match)) + { + S32 start = match.getStart(); + S32 end = match.getEnd() + 1; + + // perform word wrap on the text before the Url + final_wtext += wrapText(wtext.substr(0, start), hoffset, line_num, max_width); + + // add the Url (but compute width based on its label) + S32 label_width = mDefaultFont->getWidth(match.getLabel()); + if (hoffset > 0 && hoffset + label_width > max_width) + { + final_wtext += '\n'; + line_num++; + hoffset = 0; + } + final_wtext += wtext.substr(start, end-start); + hoffset += label_width; + if (hoffset > max_width) + { + final_wtext += '\n'; + line_num++; + hoffset = 0; + // eat any leading whitespace on the next line + while (isspace(wtext[end]) && end < (S32)wtext.size()) { - final_wtext += '\n'; + end++; } } + + // move on to the rest of the text after the Url + wtext = wtext.substr(end, wtext.size() - end + 1); } - - mDidWordWrap = TRUE; - std::string final_text = wstring_to_utf8str(final_wtext); - setText(final_text); + final_wtext += wrapText(wtext, hoffset, line_num, max_width); + return final_wtext; } S32 LLTextBox::getTextPixelWidth() @@ -268,7 +347,7 @@ S32 LLTextBox::getTextPixelWidth() iter != mLineLengthList.end(); ++iter) { S32 line_length = *iter; - S32 line_width = mFontGL->getWidth( mText.getWString().c_str(), cur_pos, line_length ); + S32 line_width = mDefaultFont->getWidth( mDisplayText.c_str(), cur_pos, line_length ); if( line_width > max_line_width ) { max_line_width = line_width; @@ -278,7 +357,7 @@ S32 LLTextBox::getTextPixelWidth() } else { - max_line_width = mFontGL->getWidth(mText.getWString().c_str()); + max_line_width = mDefaultFont->getWidth(mDisplayText.c_str()); } return max_line_width; } @@ -290,7 +369,7 @@ S32 LLTextBox::getTextPixelHeight() { num_lines = 1; } - return (S32)(num_lines * mFontGL->getLineHeight()); + return (S32)(num_lines * mDefaultFont->getLineHeight()); } void LLTextBox::setValue(const LLSD& value ) @@ -302,7 +381,7 @@ void LLTextBox::setValue(const LLSD& value ) BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text ) { mText.setArg(key, text); - setLineLengths(); + updateDisplayTextAndSegments(); return TRUE; } @@ -345,18 +424,11 @@ void LLTextBox::draw() if ( getEnabled() ) { - if(mHasHover) - { - drawText( text_x, text_y, mHoverColor.get() ); - } - else - { - drawText( text_x, text_y, mTextColor.get() ); - } + drawText( text_x, text_y, mDisplayText, mTextColor.get() ); } else { - drawText( text_x, text_y, mDisabledColor.get() ); + drawText( text_x, text_y, mDisplayText, mDisabledColor.get() ); } if (sDebugRects) @@ -370,41 +442,46 @@ void LLTextBox::draw() //{ // drawDebugRect(); //} - - mHasHover = FALSE; // This is reset every frame. } void LLTextBox::reshape(S32 width, S32 height, BOOL called_from_parent) { - // reparse line lengths + // reparse line lengths (don't need to recalculate the display text) setLineLengths(); LLView::reshape(width, height, called_from_parent); } -void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color ) +void LLTextBox::drawText( S32 x, S32 y, const LLWString &text, const LLColor4& color ) { - if( mLineLengthList.empty() ) + if (mSegments.size() > 1) { - mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color, - mHAlign, mVAlign, - 0, - mShadowType, - S32_MAX, getRect().getWidth(), NULL, mUseEllipses); + // we have Urls (or other multi-styled segments) + drawTextSegments(x, y, text); + } + else if( mLineLengthList.empty() ) + { + // simple case of 1 line of text in one style + mDefaultFont->render(text, 0, (F32)x, (F32)y, color, + mHAlign, mVAlign, + 0, + mShadowType, + S32_MAX, getRect().getWidth(), NULL, mUseEllipses); } else { + // simple case of multiple lines of text, all in the same style S32 cur_pos = 0; for (std::vector::iterator iter = mLineLengthList.begin(); iter != mLineLengthList.end(); ++iter) { S32 line_length = *iter; - mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color, - mHAlign, mVAlign, - 0, - mShadowType, - line_length, getRect().getWidth(), NULL, mUseEllipses ); + mDefaultFont->render(text, cur_pos, (F32)x, (F32)y, color, + mHAlign, mVAlign, + 0, + mShadowType, + line_length, getRect().getWidth(), NULL, mUseEllipses ); cur_pos += line_length + 1; - y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing; + y -= llfloor(mDefaultFont->getLineHeight()) + mLineSpacing; } } } @@ -415,3 +492,254 @@ void LLTextBox::reshapeToFitText() S32 height = getTextPixelHeight(); reshape( width + 2 * mHPad, height + 2 * mVPad ); } + +S32 LLTextBox::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const +{ + // Returns the character offset for the character under the local (x, y) coordinate. + // When round is true, if the position is on the right half of a character, the cursor + // will be put to its right. If round is false, the cursor will always be put to the + // character's left. + + LLRect rect = getLocalRect(); + rect.mLeft += mHPad; + rect.mRight -= mHPad; + rect.mTop += mVPad; + rect.mBottom -= mVPad; + + // Figure out which line we're nearest to. + S32 total_lines = getLineCount(); + S32 line_height = llround( mDefaultFont->getLineHeight() ) + mLineSpacing; + S32 line = (rect.mTop - 1 - local_y) / line_height; + if (line >= total_lines) + { + return getLength(); // past the end + } + + line = llclamp( line, 0, total_lines ); + S32 line_start = getLineStart(line); + S32 next_start = getLineStart(line+1); + S32 line_end = (next_start != line_start) ? next_start - 1 : getLength(); + if (line_start == -1) + { + return 0; + } + + S32 line_len = line_end - line_start; + S32 pos = mDefaultFont->charFromPixelOffset(mDisplayText.c_str(), line_start, + (F32)(local_x - rect.mLeft), + (F32)rect.getWidth(), + line_len, round); + + return line_start + pos; +} + +S32 LLTextBox::getLineStart( S32 line ) const +{ + line = llclamp(line, 0, getLineCount()-1); + + S32 result = 0; + for (int i = 0; i < line; i++) + { + result += mLineLengthList[i] + 1 /* add newline */; + } + + return result; +} + +void LLTextBox::updateDisplayTextAndSegments() +{ + // remove any previous segment list + clearSegments(); + + // if URL parsing is turned off, then not much to bo + if (! mParseHTML) + { + mDisplayText = mText.getWString(); + setLineLengths(); + return; + } + + // create unique text segments for Urls + mDisplayText.clear(); + S32 end = 0; + LLUrlMatch match; + LLWString text = mText.getWString(); + + // find the next Url in the text string + while ( LLUrlRegistry::instance().findUrl(wstring_to_utf8str(text), match, + boost::bind(&LLTextBox::onUrlLabelUpdated, this, _1, _2)) ) + { + // work out the char offset for the start/end of the url + S32 seg_start = mDisplayText.size(); + S32 start = seg_start + match.getStart(); + end = start + match.getLabel().size(); + + // create a segment for the text before the Url + mSegments.insert(new LLNormalTextSegment(new LLStyle(), seg_start, start, *this)); + mDisplayText += text.substr(0, match.getStart()); + + // create a segment for the Url text + LLStyleSP html(new LLStyle); + html->setVisible(true); + html->setColor(mLinkColor); + html->mUnderline = TRUE; + html->setLinkHREF(match.getUrl()); + + LLNormalTextSegment *html_seg = new LLNormalTextSegment(html, start, end, *this); + html_seg->setToolTip(match.getTooltip()); + + mSegments.insert(html_seg); + mDisplayText += utf8str_to_wstring(match.getLabel()); + + // move on to the rest of the text after the Url + text = text.substr(match.getEnd()+1, text.size() - match.getEnd()); + } + + // output a segment for the remaining text + if (text.size() > 0) + { + mSegments.insert(new LLNormalTextSegment(new LLStyle(), end, end + text.size(), *this)); + mDisplayText += text; + } + + // strip whitespace from the end of the text + while (mDisplayText.size() > 0 && isspace(mDisplayText[mDisplayText.size()-1])) + { + mDisplayText = mDisplayText.substr(0, mDisplayText.size() - 1); + + segment_set_t::iterator it = getSegIterContaining(mDisplayText.size()); + if (it != mSegments.end()) + { + LLTextSegmentPtr seg = *it; + seg->setEnd(seg->getEnd()-1); + } + } + + // we may have changed the line lengths, so recalculate them + setLineLengths(); +} + +void LLTextBox::onUrlLabelUpdated(const std::string &url, const std::string &label) +{ + if (mDidWordWrap) + { + // re-word wrap as the url label lengths may have changed + setWrappedText(mText.getString()); + } + else + { + // or just update the display text with the latest Url labels + updateDisplayTextAndSegments(); + } +} + +bool LLTextBox::isClickable() const +{ + // return true if we have been given a click callback + if (mClickedCallback) + { + return true; + } + + // also return true if we have a clickable Url in the text + segment_set_t::const_iterator it; + for (it = mSegments.begin(); it != mSegments.end(); ++it) + { + LLTextSegmentPtr segmentp = *it; + if (segmentp) + { + const LLStyleSP style = segmentp->getStyle(); + if (style && style->isLink()) + { + return true; + } + } + } + + // otherwise there is nothing clickable here + return false; +} + +void LLTextBox::drawTextSegments(S32 init_x, S32 init_y, const LLWString &text) +{ + const S32 text_len = text.length(); + if (text_len <= 0) + { + return; + } + + S32 cur_line = 0; + S32 num_lines = getLineCount(); + S32 line_start = getLineStart(cur_line); + S32 line_height = llround( mDefaultFont->getLineHeight() ) + mLineSpacing; + F32 text_y = (F32) init_y; + segment_set_t::iterator cur_seg = mSegments.begin(); + + // render a line of text at a time + const LLRect textRect = getLocalRect(); + while((textRect.mBottom <= text_y) && (cur_line < num_lines)) + { + S32 next_start = -1; + S32 line_end = text_len; + + if ((cur_line + 1) < num_lines) + { + next_start = getLineStart(cur_line + 1); + line_end = next_start; + } + if ( text[line_end-1] == '\n' ) + { + --line_end; + } + + // render all segments on this line + F32 text_x = init_x; + S32 seg_start = line_start; + while (seg_start < line_end && cur_seg != mSegments.end()) + { + // move to the next segment (or continue the previous one) + LLTextSegment *cur_segment = *cur_seg; + while (cur_segment->getEnd() <= seg_start) + { + if (++cur_seg == mSegments.end()) + { + return; + } + cur_segment = *cur_seg; + } + + // Draw a segment within the line + S32 clipped_end = llmin( line_end, cur_segment->getEnd() ); + S32 clipped_len = clipped_end - seg_start; + if( clipped_len > 0 ) + { + LLStyleSP style = cur_segment->getStyle(); + if (style && style->isVisible()) + { + // work out the color for the segment + LLColor4 color ; + if (getEnabled()) + { + color = style->isLink() ? mLinkColor.get() : mTextColor.get(); + } + else + { + color = mDisabledColor.get(); + } + + // render a single line worth for this segment + mDefaultFont->render(text, seg_start, text_x, text_y, color, + mHAlign, mVAlign, 0, mShadowType, clipped_len, + textRect.getWidth(), &text_x, mUseEllipses); + } + + seg_start += clipped_len; + } + } + + // move down one line + text_y -= (F32)line_height; + line_start = next_start; + cur_line++; + } +} -- cgit v1.3 From 79653dfed48105019b8ecca9cf4bfaa2a390e100 Mon Sep 17 00:00:00 2001 From: Steven Bennetts Date: Mon, 7 Sep 2009 22:55:07 +0000 Subject: merge https://svn.aws.productengine.com/secondlife/export-from-ll/viewer-2-0@1566 https://svn.aws.productengine.com/secondlife/pe/stable-2@1580 -> viewer-2.0.0-3 * Bugs: EXT-807 EXT-810 EXT-811 EXT-784 EXT-820 EXT-393 EXT-826 EXT-811 EXT-801 EXT-808 EXT-393 EXT-743 EXT-699 EXT-397 EXT-812 EXT-736 EXT-744 EXT-809 EXT-306 EXT-854 EXT-857 EXT-790 * New Dev: EXT-694 EXT-393 EXT-367 EXT-819 EXT-795 EXT-827 EXT-788 * EXT-272 - Draggable Landmarks * EXT-715 - Block List Panel * EXT-782 - Implement advanced place information accordions --- indra/llinventory/llinventory.h | 2 +- indra/llrender/llfontregistry.cpp | 2 +- indra/llui/CMakeLists.txt | 4 + indra/llui/llbutton.cpp | 19 ++ indra/llui/lldockablefloater.cpp | 86 +++++ indra/llui/lldockablefloater.h | 65 ++++ indra/llui/lldockcontrol.cpp | 126 ++++++++ indra/llui/lldockcontrol.h | 81 +++++ indra/llui/llscrolllistctrl.cpp | 35 ++- indra/llui/llscrolllistctrl.h | 10 +- indra/llui/lltextbox.cpp | 5 +- indra/llui/lltexteditor.cpp | 7 +- indra/llui/llview.cpp | 4 +- indra/llui/llview.h | 2 +- indra/newview/CMakeLists.txt | 8 +- indra/newview/app_settings/settings.xml | 17 +- indra/newview/llagent.cpp | 1 - indra/newview/llavatarlist.cpp | 3 +- indra/newview/llbottomtray.cpp | 54 +++- indra/newview/llbottomtray.h | 13 +- indra/newview/llchiclet.cpp | 6 + indra/newview/llchiclet.h | 1 + indra/newview/llfavoritesbar.cpp | 349 ++++++++++++++++++--- indra/newview/llfavoritesbar.h | 49 ++- indra/newview/llfloaterchat.cpp | 4 +- indra/newview/llfloaterpreference.cpp | 6 + indra/newview/llfriendcard.cpp | 13 +- indra/newview/llfriendcard.h | 5 + indra/newview/llinventorybridge.cpp | 10 +- indra/newview/lllocationhistory.cpp | 78 ++--- indra/newview/lllocationhistory.h | 77 ++++- indra/newview/lllocationinputctrl.cpp | 72 ++++- indra/newview/lllocationinputctrl.h | 2 + indra/newview/llnavigationbar.cpp | 204 +++++++----- indra/newview/llnavigationbar.h | 15 +- indra/newview/llpanelavatar.cpp | 4 +- indra/newview/llpanelavatar.h | 2 +- indra/newview/llpanelblockedlist.cpp | 279 ++++++++++++++++ indra/newview/llpanelblockedlist.h | 115 +++++++ indra/newview/llpanelpeople.cpp | 3 +- indra/newview/llpanelpicks.cpp | 100 +++--- indra/newview/llpanelpicks.h | 5 + indra/newview/llpanelplaceinfo.cpp | 262 ++++++++++++---- indra/newview/llpanelplaceinfo.h | 30 +- indra/newview/llpanelplaces.cpp | 11 +- indra/newview/llpanelteleporthistory.cpp | 26 +- indra/newview/llpanelteleporthistory.h | 4 +- indra/newview/llscreenchannel.cpp | 9 +- indra/newview/llsearchcombobox.cpp | 250 +++++++++++++++ indra/newview/llsearchcombobox.h | 108 +++++++ indra/newview/llsearchhistory.cpp | 154 +++++++++ indra/newview/llsearchhistory.h | 138 ++++++++ indra/newview/llsidetray.cpp | 7 + indra/newview/llstartup.cpp | 4 + indra/newview/llsyswellwindow.cpp | 57 ++-- indra/newview/llsyswellwindow.h | 8 +- indra/newview/llteleporthistorystorage.cpp | 98 +++++- indra/newview/llteleporthistorystorage.h | 35 ++- indra/newview/lltoast.h | 4 + indra/newview/lltoastgroupnotifypanel.cpp | 61 ++-- indra/newview/lltoastgroupnotifypanel.h | 2 + indra/newview/lltoastimpanel.cpp | 28 +- indra/newview/lltoastimpanel.h | 5 +- indra/newview/lltoastpanel.cpp | 31 ++ indra/newview/lltoastpanel.h | 2 + indra/newview/lltoolbar.cpp | 11 +- indra/newview/llviewerfloaterreg.cpp | 5 +- indra/newview/llviewerinventory.cpp | 100 +++++- indra/newview/llviewerinventory.h | 7 + indra/newview/llviewermenu.cpp | 4 +- indra/newview/llviewermessage.cpp | 10 +- indra/newview/llviewerwindow.cpp | 13 +- indra/newview/skins/default/textures/textures.xml | 1 + .../xui/en/menu_people_friends_view_sort.xml | 4 + .../xui/en/menu_people_nearby_view_sort.xml | 4 + .../xui/en/menu_people_recent_view_sort.xml | 4 + .../default/xui/en/panel_block_list_sidetray.xml | 84 +++++ .../skins/default/xui/en/panel_bottomtray.xml | 2 +- .../skins/default/xui/en/panel_edit_profile.xml | 38 ++- .../skins/default/xui/en/panel_group_notify.xml | 80 +++-- .../skins/default/xui/en/panel_instant_message.xml | 6 +- .../skins/default/xui/en/panel_navigation_bar.xml | 13 +- .../skins/default/xui/en/panel_pick_list_item.xml | 20 ++ .../skins/default/xui/en/panel_side_tray.xml | 7 + .../skins/default/xui/en/widgets/accordion_tab.xml | 6 + .../newview/skins/default/xui/en/widgets/list.xml | 1 + .../default/xui/en/widgets/location_input.xml | 2 +- .../default/xui/en/widgets/search_combo_box.xml | 26 ++ 88 files changed, 3184 insertions(+), 541 deletions(-) create mode 100644 indra/llui/lldockablefloater.cpp create mode 100644 indra/llui/lldockablefloater.h create mode 100644 indra/llui/lldockcontrol.cpp create mode 100644 indra/llui/lldockcontrol.h create mode 100644 indra/newview/llpanelblockedlist.cpp create mode 100644 indra/newview/llpanelblockedlist.h create mode 100644 indra/newview/llsearchcombobox.cpp create mode 100644 indra/newview/llsearchcombobox.h create mode 100644 indra/newview/llsearchhistory.cpp create mode 100644 indra/newview/llsearchhistory.h create mode 100644 indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml create mode 100644 indra/newview/skins/default/xui/en/widgets/accordion_tab.xml create mode 100644 indra/newview/skins/default/xui/en/widgets/search_combo_box.xml (limited to 'indra/llui/lltextbox.cpp') diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 2b4d8ed831..64af6c94f5 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -100,7 +100,7 @@ public: BOOL getIsLinkType() const; // mutators - will not call updateServer(); void setUUID(const LLUUID& new_uuid); - void rename(const std::string& new_name); + virtual void rename(const std::string& new_name); void setParent(const LLUUID& new_parent); void setType(LLAssetType::EType type); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 99f364a589..45573cd817 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -105,7 +105,7 @@ bool removeSubString(std::string& str, const std::string& substr) size_t pos = str.find(substr); if (pos != string::npos) { - str.erase(pos); + str.erase(pos, substr.size()); return true; } return false; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 790f2d5729..95d693cdc4 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -34,6 +34,8 @@ set(llui_SOURCE_FILES llconsole.cpp llcontainerview.cpp llctrlselectioninterface.cpp + lldockablefloater.cpp + lldockcontrol.cpp lldraghandle.cpp lleditmenuhandler.cpp llf32uictrl.cpp @@ -113,6 +115,8 @@ set(llui_HEADER_FILES llcontainerview.h llctrlselectioninterface.h lldraghandle.h + lldockablefloater.h + lldockcontrol.h lleditmenuhandler.h llf32uictrl.h llfiltereditor.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 98e8c9a988..bf58e19949 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -355,11 +355,19 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) setFocus(TRUE); } + /* + * ATTENTION! This call fires another mouse down callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseDownSignal(x, y, mask); + */ + LLUICtrl::handleMouseDown(x, y, mask); + mMouseDownSignal(this, LLSD()); mMouseDownTimer.start(); mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); mMouseHeldDownCount = 0; + if (getSoundFlags() & MOUSE_DOWN) { @@ -378,6 +386,13 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) // Always release the mouse gFocusMgr.setMouseCapture( NULL ); + /* + * ATTENTION! This call fires another mouse up callback. + * If you wish to remove this call emit that signal directly + * by calling LLUICtrl::mMouseUpSignal(x, y, mask); + */ + LLUICtrl::handleMouseUp(x, y, mask); + // Regardless of where mouseup occurs, handle callback mMouseUpSignal(this, LLSD()); @@ -460,12 +475,16 @@ BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) void LLButton::onMouseEnter(S32 x, S32 y, MASK mask) { + LLUICtrl::onMouseEnter(x, y, mask); + if (isInEnabledChain()) mNeedsHighlight = TRUE; } void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) { + LLUICtrl::onMouseLeave(x, y, mask); + mNeedsHighlight = FALSE; } diff --git a/indra/llui/lldockablefloater.cpp b/indra/llui/lldockablefloater.cpp new file mode 100644 index 0000000000..d0789d6502 --- /dev/null +++ b/indra/llui/lldockablefloater.cpp @@ -0,0 +1,86 @@ +/** + * @file lldockablefloater.cpp + * @brief Creates a panel of a specific kind for a toast + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldockablefloater.h" + +LLDockableFloater::LLDockableFloater(LLDockControl* dockControl, + const LLSD& key, const Params& params) : + LLFloater(key, params), mDockControl(dockControl) +{ +} + +LLDockableFloater::~LLDockableFloater() +{ +} + +BOOL LLDockableFloater::postBuild() +{ + mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); + LLFloater::setDocked(true); + return LLView::postBuild(); +} + +void LLDockableFloater::setDocked(bool docked, bool pop_on_undock) +{ + if (docked) + { + mDockControl.get()->on(); + } + else + { + mDockControl.get()->off(); + } + LLFloater::setDocked(docked, pop_on_undock); +} + +void LLDockableFloater::draw() +{ + mDockControl.get()->repositionDockable(); + mDockControl.get()->drawToungue(); + LLFloater::draw(); +} + +void LLDockableFloater::setDockControl(LLDockControl* dockControl) +{ + mDockControl.reset(dockControl); +} +const LLUIImagePtr& LLDockableFloater::getDockTongue() +{ + return mDockTongue; +} + +LLDockControl* LLDockableFloater::getDockControl() +{ + return mDockControl.get(); +} diff --git a/indra/llui/lldockablefloater.h b/indra/llui/lldockablefloater.h new file mode 100644 index 0000000000..5ece78a925 --- /dev/null +++ b/indra/llui/lldockablefloater.h @@ -0,0 +1,65 @@ +/** + * @file lldockablefloater.h + * @brief Creates a panel of a specific kind for a toast. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_DOCKABLEFLOATER_H +#define LL_DOCKABLEFLOATER_H + +#include "llerror.h" +#include "llfloater.h" +#include "lldockcontrol.h" + +/** + * Represents floater that can dock. + * In case impossibility deriving from LLDockableFloater use LLDockControl. + */ +class LLDockableFloater : public LLFloater +{ +public: + LOG_CLASS(LLDockableFloater); + LLDockableFloater(LLDockControl* dockControl, const LLSD& key, const Params& params = getDefaultParams()); + virtual ~LLDockableFloater(); + + /* virtula */BOOL postBuild(); + /* virtual */void setDocked(bool docked, bool pop_on_undock = true); + /* virtual */void draw(); + +protected: + void setDockControl(LLDockControl* dockControl); + LLDockControl* getDockControl(); + const LLUIImagePtr& getDockTongue(); + +private: + std::auto_ptr mDockControl; + LLUIImagePtr mDockTongue; +}; + +#endif /* LL_DOCKABLEFLOATER_H */ diff --git a/indra/llui/lldockcontrol.cpp b/indra/llui/lldockcontrol.cpp new file mode 100644 index 0000000000..bec7f04cc0 --- /dev/null +++ b/indra/llui/lldockcontrol.cpp @@ -0,0 +1,126 @@ +/** + * @file lldockcontrol.cpp + * @brief Creates a panel of a specific kind for a toast + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lldockcontrol.h" + +LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, + const LLUIImagePtr& dockTongue, DocAt dockAt, bool enabled) : + mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue( + dockTongue) +{ + mDockAt = dockAt; + if (enabled) + { + on(); + } + else + { + off(); + } +} + +LLDockControl::~LLDockControl() +{ +} + +void LLDockControl::repositionDockable() +{ + if (mEnabled) + { + calculateDockablePosition(); + } +} + +void LLDockControl::calculateDockablePosition() +{ + LLRect dockRect = mDockWidget->calcScreenRect(); + if (mPrevDockRect != dockRect || mRecalculateDocablePosition) + { + LLRect dockableRect = mDockableFloater->calcScreenRect(); + LLRect rootRect = mDockableFloater->getRootView()->getRect(); + + S32 x = 0; + S32 y = 0; + switch (mDockAt) + { + case TOP: + x = dockRect.getCenterX() - dockableRect.getWidth() / 2; + y = dockRect.mTop + mDockTongue->getHeight() + + dockableRect.getHeight(); + if (x < rootRect.mLeft) + { + x = rootRect.mLeft; + } + if (x + dockableRect.getWidth() > rootRect.mRight) + { + x = rootRect.mRight - dockableRect.getWidth(); + } + mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2; + mDockTongueY = dockRect.mTop; + break; + } + dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(), + dockableRect.getHeight()); + LLRect localDocableParentRect; + mDockableFloater->getParent()->screenRectToLocal(dockableRect, + &localDocableParentRect); + mDockableFloater->setRect(localDocableParentRect); + + mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY, + &mDockTongueX, &mDockTongueY); + mPrevDockRect = dockRect; + mRecalculateDocablePosition = false; + } +} + +void LLDockControl::on() +{ + mDockableFloater->setCanDrag(false); + mEnabled = true; + mRecalculateDocablePosition = true; +} + +void LLDockControl::off() +{ + mDockableFloater->setCanDrag(true); + mEnabled = false; +} + +void LLDockControl::drawToungue() +{ + if (mEnabled) + { + mDockTongue->draw(mDockTongueX, mDockTongueY); + } +} diff --git a/indra/llui/lldockcontrol.h b/indra/llui/lldockcontrol.h new file mode 100644 index 0000000000..0e1f4c8e64 --- /dev/null +++ b/indra/llui/lldockcontrol.h @@ -0,0 +1,81 @@ +/** + * @file lldockcontrol.h + * @brief Creates a panel of a specific kind for a toast. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_DOCKCONTROL_H +#define LL_DOCKCONTROL_H + +#include "llerror.h" +#include "llview.h" +#include "llfloater.h" +#include "lluiimage.h" + +/** + * Provides services for docking of specified floater. + * This class should be used in case impossibility deriving from LLDockableFloater. + */ +class LLDockControl +{ +public: + enum DocAt + { + TOP + }; + +public: + LOG_CLASS(LLDockControl); + LLDockControl(LLView* dockWidget, LLFloater* dockableFloater, + const LLUIImagePtr& dockTongue, DocAt dockAt, + bool enabled); + virtual ~LLDockControl(); + +public: + void on(); + void off(); + void setDock(LLView* dockWidget) + { mDockWidget = dockWidget;}; + void repositionDockable(); + void drawToungue(); +protected: + virtual void calculateDockablePosition(); +private: + bool mEnabled; + bool mRecalculateDocablePosition; + DocAt mDockAt; + LLView* mDockWidget; + LLRect mPrevDockRect; + LLFloater* mDockableFloater; + LLUIImagePtr mDockTongue; + S32 mDockTongueX; + S32 mDockTongueY; +}; + +#endif /* LL_DOCKCONTROL_H */ diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index b9a253aac8..36a3b007b6 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -123,6 +123,7 @@ LLScrollListCtrl::Params::Params() sort_ascending("sort_ascending", true), commit_on_keyboard_movement("commit_on_keyboard_movement", true), heading_height("heading_height"), + page_lines("page_lines", 0), background_visible("background_visible"), draw_stripes("draw_stripes"), column_padding("column_padding"), @@ -145,7 +146,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) : LLUICtrl(p), mLineHeight(0), mScrollLines(0), - mPageLines(0), + mPageLines(p.page_lines), mMaxSelectable(0), mAllowKeyboardMovement(TRUE), mCommitOnKeyboardMovement(p.commit_on_keyboard_movement), @@ -196,8 +197,6 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) updateLineHeight(); - mPageLines = mLineHeight? (mItemListRect.getHeight()) / mLineHeight : 0; - // Init the scrollbar static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); @@ -214,7 +213,7 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p) sbparams.orientation(LLScrollbar::VERTICAL); sbparams.doc_size(getItemCount()); sbparams.doc_pos(mScrollLines); - sbparams.page_size(mPageLines); + sbparams.page_size( mPageLines ? mPageLines : getItemCount() ); sbparams.change_callback(boost::bind(&LLScrollListCtrl::onScrollChange, this, _1, _2)); sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); sbparams.visible(false); @@ -469,8 +468,12 @@ void LLScrollListCtrl::updateLayout() getChildView("comment_text")->setShape(mItemListRect); // how many lines of content in a single "page" - mPageLines = mLineHeight? mItemListRect.getHeight() / mLineHeight : 0; - BOOL scrollbar_visible = getItemCount() > mPageLines; + S32 page_lines = mLineHeight? mItemListRect.getHeight() / mLineHeight : getItemCount(); + //if mPageLines is NOT provided display all item + if(mPageLines) + page_lines = mPageLines; + + BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight(); if (scrollbar_visible) { // provide space on the right for scrollbar @@ -479,7 +482,7 @@ void LLScrollListCtrl::updateLayout() mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - scrollbar_size, mItemListRect.mBottom); mScrollbar->reshape(scrollbar_size, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); - mScrollbar->setPageSize( mPageLines ); + mScrollbar->setPageSize(page_lines); mScrollbar->setDocSize( getItemCount() ); mScrollbar->setVisible(scrollbar_visible); @@ -491,6 +494,9 @@ void LLScrollListCtrl::updateLayout() void LLScrollListCtrl::fitContents(S32 max_width, S32 max_height) { S32 height = llmin( getRequiredRect().getHeight(), max_height ); + if(mPageLines) + height = llmin( mPageLines * mLineHeight + (mDisplayColumnHeaders ? mHeadingHeight : 0), height ); + S32 width = getRect().getWidth(); reshape( width, height ); @@ -721,6 +727,12 @@ void LLScrollListCtrl::setHeadingHeight(S32 heading_height) updateLayout(); } +void LLScrollListCtrl::setPageLines(S32 new_page_lines) +{ + mPageLines = new_page_lines; + + updateLayout(); +} BOOL LLScrollListCtrl::selectFirstItem() { @@ -1367,7 +1379,7 @@ void LLScrollListCtrl::drawItems() S32 y = mItemListRect.mTop - mLineHeight; // allow for partial line at bottom - S32 num_page_lines = mPageLines + 1; + S32 num_page_lines = (mPageLines)? mPageLines : getItemCount() + 1; LLRect item_rect; @@ -1856,7 +1868,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) mLineHeight ); // allow for partial line at bottom - S32 num_page_lines = mPageLines + 1; + S32 num_page_lines = (mPageLines)? mPageLines : getItemCount() + 1; S32 line = 0; item_list::iterator iter; @@ -2421,7 +2433,8 @@ void LLScrollListCtrl::scrollToShowSelected() } S32 lowest = mScrollLines; - S32 highest = mScrollLines + mPageLines; + S32 page_lines = (mPageLines)? mPageLines : getItemCount(); + S32 highest = mScrollLines + page_lines; if (index < lowest) { @@ -2430,7 +2443,7 @@ void LLScrollListCtrl::scrollToShowSelected() } else if (highest <= index) { - setScrollPos(index - mPageLines + 1); + setScrollPos(index - page_lines + 1); } } diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 7a7e5be0be..5c18f85160 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -87,6 +87,7 @@ public: // layout Optional column_padding, + page_lines, heading_height; // sort and search behavior @@ -314,6 +315,11 @@ public: S32 getMaxContentWidth() { return mMaxContentWidth; } void setHeadingHeight(S32 heading_height); + /** + * Sets max visible lines without scroolbar, if this value equals to 0, + * then display all items. + */ + void setPageLines(S32 page_lines ); void setCollapseEmptyColumns(BOOL collapse); LLScrollListItem* hitItem(S32 x,S32 y); @@ -368,11 +374,13 @@ protected: typedef std::deque item_list; item_list& getItemList() { return mItemList; } + void updateLineHeight(); + private: void selectPrevItem(BOOL extend_selection); void selectNextItem(BOOL extend_selection); void drawItems(); - void updateLineHeight(); + void updateLineHeightInsert(LLScrollListItem* item); void reportInvalidInput(); BOOL isRepeatedChars(const LLWString& string) const; diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 7a92bfb74c..30bf182deb 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -481,7 +481,10 @@ void LLTextBox::drawText( S32 x, S32 y, const LLWString &text, const LLColor4& c mShadowType, line_length, getRect().getWidth(), NULL, mUseEllipses ); cur_pos += line_length + 1; - y -= llfloor(mDefaultFont->getLineHeight()) + mLineSpacing; + S32 line_height = llfloor(mDefaultFont->getLineHeight()) + mLineSpacing; + y -= line_height; + if(y < line_height) + break; } } } diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 296ccea0e4..51c259ff53 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -3412,11 +3412,8 @@ void LLTextEditor::endOfDoc() // Sets the scrollbar from the cursor position void LLTextEditor::updateScrollFromCursor() { - if (mReadOnly) - { - // no cursor in read only mode - return; - } + // Update scroll position even in read-only mode (when there's no cursor displayed) + // because startOfDoc()/endOfDoc() modify cursor position. See EXT-736. if (!mScrollNeeded) { diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 83d45f0dfa..55d94b325f 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -2741,11 +2741,11 @@ void LLView::notifyParent(const LLSD& info) if(parent) parent->notifyParent(info); } -void LLView::notifyChilds(const LLSD& info) +void LLView::notifyChildren(const LLSD& info) { for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) { - (*child_it)->notifyChilds(info); + (*child_it)->notifyChildren(info); } } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 87298b5292..1d48378081 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -550,7 +550,7 @@ public: virtual void handleReshape(const LLRect& rect, bool by_user); virtual void notifyParent(const LLSD& info); - virtual void notifyChilds(const LLSD& info); + virtual void notifyChildren(const LLSD& info); protected: void drawDebugRect(); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 05459cfcac..f4194ed511 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -180,7 +180,6 @@ set(viewer_SOURCE_FILES llfloaterlandholdings.cpp llfloatermap.cpp llfloatermemleak.cpp - llfloatermute.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloateropenobject.cpp @@ -286,6 +285,7 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelavatarrow.cpp llpanelavatartag.cpp + llpanelblockedlist.cpp llpanelclassified.cpp llpanelcontents.cpp llpaneldirbrowser.cpp @@ -348,6 +348,8 @@ set(viewer_SOURCE_FILES llremoteparcelrequest.cpp llsavedsettingsglue.cpp llscreenchannel.cpp + llsearchcombobox.cpp + llsearchhistory.cpp llselectmgr.cpp llsidetray.cpp llsidetraypanelcontainer.cpp @@ -634,7 +636,6 @@ set(viewer_HEADER_FILES llfloaterlandholdings.h llfloatermap.h llfloatermemleak.h - llfloatermute.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloateropenobject.h @@ -738,6 +739,7 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelavatarrow.h llpanelavatartag.h + llpanelblockedlist.h llpanelclassified.h llpanelcontents.h llpaneldirbrowser.h @@ -802,6 +804,8 @@ set(viewer_HEADER_FILES llrootview.h llscreenchannel.h llsavedsettingsglue.h + llsearchcombobox.h + llsearchhistory.h llselectmgr.h llsidetray.h llsidetraypanelcontainer.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e88bc5a91f..32b1443157 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6866,10 +6866,10 @@ Value 0 - ShowPGSearchAll + ShowCameraAndMoveControls Comment - Show/Hide Navigation Bar Favorites Panel + Show/Hide Camera and Move controls in the bottom tray Persist 1 Type @@ -6880,7 +6880,7 @@ ShowNavbarFavoritesPanel Comment - Show/Hide Navigation Bar Navigation Panel + Show/Hide Navigation Bar Favorites Panel Persist 1 Type @@ -6889,6 +6889,17 @@ 1 ShowNavbarNavigationPanel + + Comment + Show/Hide Navigation Bar Navigation Panel + Persist + 1 + Type + Boolean + Value + 1 + + ShowPGSearchAll Comment Display results of search All that are flagged as PG diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index e1747930b0..08681db6cb 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -47,7 +47,6 @@ #include "llfloaterdirectory.h" #include "llfloaterland.h" -#include "llfloatermute.h" #include "llfloatersnapshot.h" #include "llfloatertools.h" #include "llfloaterworldmap.h" diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index e0322e26b9..a121d327f7 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -223,12 +223,13 @@ BOOL LLAvatarList::update(const std::vector& all_buddies, const std::str #endif setScrollPos(pos); + updateLineHeight(); LLRect rect = getRequiredRect(); LLSD params; params["action"] = "size_changes"; params["width"] = rect.getWidth(); - params["height"] = rect.getHeight(); + params["height"] = llmax(rect.getHeight(),20) + 5; getParent()->notifyParent(params); diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index fe13d4f652..861f23abb7 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -60,7 +60,6 @@ LLBottomTray::LLBottomTray(const LLSD&) mSysWell = getChild("sys_well"); mSysWell->setNotificationChicletWindow(LLFloaterReg::getInstance("syswell_window")); - LLFloaterReg::getTypedInstance("syswell_window")->setSysWell(mSysWell); mChicletPanel->setChicletClickedCallback(boost::bind(&LLBottomTray::onChicletClick,this,_1)); @@ -80,8 +79,16 @@ LLBottomTray::LLBottomTray(const LLSD&) BOOL LLBottomTray::postBuild() { + mCommitCallbackRegistrar.add("ShowCamMoveCtrls.Action", boost::bind(&LLBottomTray::onShowCamMoveCtrlsContextMenuItemClicked, this, _2)); + mEnableCallbackRegistrar.add("ShowCamMoveCtrls.EnableMenuItem", boost::bind(&LLBottomTray::onShowCamMoveCtrlsContextMenuItemEnabled, this, _2)); + + mShowCamMoveCtrlsContextMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_hide_camera_move_controls.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gMenuHolder->addChild(mShowCamMoveCtrlsContextMenu); + mNearbyChatBar = getChild("chat_bar"); mToolbarStack = getChild("toolbar_stack"); + mMovementPanel = getChild("movement_panel"); + mCamPanel = getChild("cam_panel"); return TRUE; } @@ -205,8 +212,9 @@ void LLBottomTray::setVisible(BOOL visible) child_it != mToolbarStack->getChildList()->end(); child_it++) { LLView* viewp = *child_it; + std::string name = viewp->getName(); - if ("chat_bar" == viewp->getName()) + if ("chat_bar" == name || "movement_panel" == name || "cam_panel" == name) continue; else { @@ -216,3 +224,45 @@ void LLBottomTray::setVisible(BOOL visible) } } +BOOL LLBottomTray::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mShowCamMoveCtrlsContextMenu) + { + mShowCamMoveCtrlsContextMenu->buildDrawLabels(); + mShowCamMoveCtrlsContextMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, mShowCamMoveCtrlsContextMenu, x, y); + } + + return TRUE; +} + +bool LLBottomTray::onShowCamMoveCtrlsContextMenuItemEnabled(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == "show_camera_move_controls") + { + return gSavedSettings.getBOOL("ShowCameraAndMoveControls"); + } + + return FALSE; +} + +void LLBottomTray::onShowCamMoveCtrlsContextMenuItemClicked(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == "show_camera_move_controls") + { + BOOL state = !gSavedSettings.getBOOL("ShowCameraAndMoveControls"); + + showCameraAndMoveControls(state); + gSavedSettings.setBOOL("ShowCameraAndMoveControls", state); + } +} + +void LLBottomTray::showCameraAndMoveControls(BOOL visible) +{ + mCamPanel->setVisible(visible); + mMovementPanel->setVisible(visible); +} diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h index a8fe65a9d3..c3c840ede0 100644 --- a/indra/newview/llbottomtray.h +++ b/indra/newview/llbottomtray.h @@ -33,6 +33,8 @@ #ifndef LL_LLBOTTOMPANEL_H #define LL_LLBOTTOMPANEL_H +#include + #include "llpanel.h" #include "llimview.h" @@ -68,6 +70,10 @@ public: virtual void onFocusLost(); virtual void setVisible(BOOL visible); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + void showCameraAndMoveControls(BOOL visible); + private: protected: @@ -76,6 +82,9 @@ protected: void onChicletClick(LLUICtrl* ctrl); + bool onShowCamMoveCtrlsContextMenuItemEnabled(const LLSD& userdata); + void onShowCamMoveCtrlsContextMenuItemClicked(const LLSD& userdata); + static void* createNearbyChatBar(void* userdata); /** @@ -88,7 +97,9 @@ protected: LLTalkButton* mTalkBtn; LLNearbyChatBar* mNearbyChatBar; LLLayoutStack* mToolbarStack; - + LLMenuGL* mShowCamMoveCtrlsContextMenu; + LLPanel* mMovementPanel; + LLPanel* mCamPanel; }; #endif // LL_LLBOTTOMPANEL_H diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 1109d8174f..808fcde312 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -117,6 +117,10 @@ boost::signals2::connection LLNotificationChiclet::setClickCallback( return mButton->setClickedCallback(cb); } +void LLNotificationChiclet::setToggleState(BOOL toggled) { + mButton->setToggleState(toggled); +} + void LLNotificationChiclet::updateUreadIMNotifications() { mUreadIMNotifications = gIMMgr->getNumberOfUnreadIM(); @@ -235,6 +239,7 @@ LLIMP2PChiclet::Params::Params() avatar_icon.name("avatar_icon"); avatar_icon.rect(LLRect(0, 25, 25, 0)); + avatar_icon.mouse_opaque(false); unread_notifications.name("unread"); unread_notifications.rect(LLRect(25, 25, 45, 0)); @@ -242,6 +247,7 @@ LLIMP2PChiclet::Params::Params() unread_notifications.font_halign(LLFontGL::HCENTER); unread_notifications.v_pad(5); unread_notifications.text_color(LLColor4::white); + unread_notifications.mouse_opaque(false); speaker.name("speaker"); speaker.rect(LLRect(45, 25, 65, 0)); diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index ba202515a8..f96dfb69ec 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -537,6 +537,7 @@ public: void incUreadSystemNotifications() { setCounter(++mUreadSystemNotifications + mUreadIMNotifications); } void decUreadSystemNotifications() { setCounter(--mUreadSystemNotifications + mUreadIMNotifications); } void updateUreadIMNotifications(); + void setToggleState(BOOL toggled); protected: LLNotificationChiclet(const Params& p); diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 7ad60232c7..a7f0a8ff9a 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -55,6 +55,7 @@ #include "llviewerinventory.h" #include "llviewermenu.h" #include "llviewermenu.h" +#include "lltooldraganddrop.h" static LLDefaultChildRegistry::Register r("favorites_bar"); @@ -73,6 +74,7 @@ public: , mLoaded(false) {} void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } + const LLUUID& getLandmarkId() const { return mLandmarkID; } const std::string& getSLURL() { @@ -130,8 +132,21 @@ public: msg = mUrlGetter.getSLURL(); return TRUE; } + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) + { + LLFavoritesBarCtrl* fb = dynamic_cast(getParent()); + + if (fb) + { + fb->handleHover(x, y, mask); + } + + return LLButton::handleHover(x, y, mask); + } void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + const LLUUID& getLandmarkId() const { return mUrlGetter.getLandmarkId(); } protected: LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} @@ -141,6 +156,33 @@ private: LLSLURLGetter mUrlGetter; }; +class LLFavoritesToggleableMenu : public LLToggleableMenu +{ +public: + virtual BOOL handleHover(S32 x, S32 y, MASK mask) + { + if (fb) + { + fb->handleHover(x, y, mask); + } + + return LLToggleableMenu::handleHover(x, y, mask); + } + + void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; } + +protected: + LLFavoritesToggleableMenu(const LLToggleableMenu::Params& p): + LLToggleableMenu(p) + { + } + + friend class LLUICtrlFactory; + +private: + LLFavoritesBarCtrl* fb; +}; + /** * This class is needed to override LLMenuItemCallGL default handleToolTip function and * show SLURL as button tooltip. @@ -164,6 +206,18 @@ public: void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) + { + mMouseDownSignal(this, x, y, mask); + return LLMenuItemCallGL::handleMouseDown(x, y, mask); + } + + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) + { + mMouseUpSignal(this, x, y, mask); + return LLMenuItemCallGL::handleMouseUp(x, y, mask); + } + protected: LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {} @@ -181,6 +235,14 @@ struct LLFavoritesSort // TODO - made it customizible using gSavedSettings bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b) { + S32 sortField1 = a->getSortField(); + S32 sortField2 = b->getSortField(); + + if (!(sortField1 < 0 && sortField2 < 0)) + { + return sortField2 > sortField1; + } + time_t first_create = a->getCreationDate(); time_t second_create = b->getCreationDate(); if (first_create == second_create) @@ -239,29 +301,34 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_LANDMARK: { // Copy the item into the favorites folder (if it's not already there). - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); - if (item->getParentUUID() == favorites_id) + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + + // check if we are dragging an existing item from the favorites bar + if (item && mDragItemId == item->getUUID()) { - llwarns << "Attemt to copy a favorite item into the same folder." << llendl; - break; + *accept = ACCEPT_YES_SINGLE; + + if (drop) + { + handleExistingFavoriteDragAndDrop(x, y); + } } + else + { + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + if (item->getParentUUID() == favorites_id) + { + llwarns << "Attemt to copy a favorite item into the same folder." << llendl; + break; + } - *accept = ACCEPT_YES_COPY_SINGLE; + *accept = ACCEPT_YES_COPY_SINGLE; - if (drop) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - favorites_id, - std::string(), - LLPointer(NULL)); - - llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl; + if (drop) + { + handleNewFavoriteDragAndDrop(item, favorites_id, x, y); + } } - } break; default: @@ -271,6 +338,61 @@ BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, return TRUE; } +void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) +{ + LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y)); + + if (dest) + { + updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId()); + } + else + { + mItems.push_back(gInventory.getItem(mDragItemId)); + } + + saveItemsOrder(mItems); + + LLFavoritesToggleableMenu* menu = (LLFavoritesToggleableMenu*) mPopupMenuHandle.get(); + + if (menu && menu->getVisible()) + { + menu->setVisible(FALSE); + showDropDownMenu(); + } + + mDragItemId = LLUUID::null; + getWindow()->setCursor(UI_CURSOR_ARROW); +} + +void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) +{ + LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y)); + + if (dest) + { + insertBeforeItem(mItems, dest->getLandmarkId(), item->getUUID()); + } + else + { + mItems.push_back(gInventory.getItem(item->getUUID())); + } + + saveItemsOrder(mItems); + + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + favorites_id, + std::string(), + LLPointer(NULL)); + + getWindow()->setCursor(UI_CURSOR_ARROW); + + llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl; +} + //virtual void LLFavoritesBarCtrl::changed(U32 mask) { @@ -311,9 +433,9 @@ LLXMLNodePtr LLFavoritesBarCtrl::getButtonXMLNode() void LLFavoritesBarCtrl::updateButtons(U32 bar_width) { - LLInventoryModel::item_array_t items; + mItems.clear(); - if (!collectFavoriteItems(items)) + if (!collectFavoriteItems(mItems)) { return; } @@ -331,7 +453,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) const S32 buttonVGap = 2; - S32 count = items.count(); + S32 count = mItems.count(); const S32 buttonHPad = LLUI::sSettingGroups["config"]->getS32("ButtonHPad"); const S32 chevron_button_width = mFont->getWidth(">>") + buttonHPad * 2; @@ -369,7 +491,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) S32 i; for (i = 0; i < mFirstDropDownItem; ++i) { - if (mItemNamesCache.get(i) != items.get(i)->getName()) + if (mItemNamesCache.get(i) != mItems.get(i)->getName()) { break; } @@ -387,7 +509,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) mItemNamesCache.clear(); for (S32 i = 0; i < mFirstDropDownItem; i++) { - mItemNamesCache.put(items.get(i)->getName()); + mItemNamesCache.put(mItems.get(i)->getName()); } // Rebuild the buttons only @@ -404,7 +526,7 @@ void LLFavoritesBarCtrl::updateButtons(U32 bar_width) } } - createButtons(items, buttonXMLNode, buttonWidth, buttonHGap); + createButtons(mItems, buttonXMLNode, buttonWidth, buttonHGap); } // Chevron button @@ -467,9 +589,9 @@ void LLFavoritesBarCtrl::createButtons(const LLInventoryModel::item_array_t &ite { S32 curr_x = buttonHGap; // Adding buttons - for(S32 i = mFirstDropDownItem -1; i >= 0; i--) + for(S32 i = mFirstDropDownItem -1, j = 0; i >= 0; i--) { - LLInventoryItem* item = items.get(i); + LLViewerInventoryItem* item = items.get(j++); LLFavoriteLandmarkButton* fav_btn = LLUICtrlFactory::defaultBuilder(buttonXMLNode, this, NULL); if (NULL == fav_btn) @@ -488,6 +610,10 @@ void LLFavoritesBarCtrl::createButtons(const LLInventoryModel::item_array_t &ite fav_btn->setToolTip(item->getName()); fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); + + fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + sendChildToBack(fav_btn); curr_x += buttonWidth + buttonHGap; @@ -521,6 +647,15 @@ BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &it std::sort(items.begin(), items.end(), LLFavoritesSort()); + if (needToSaveItemsOrder(items)) + { + S32 sortField = 0; + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + (*i)->setSortField(++sortField); + } + } + return TRUE; } @@ -528,7 +663,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() { if (mPopupMenuHandle.isDead()) { - LLToggleableMenu::Params menu_p; + LLFavoritesToggleableMenu::Params menu_p; menu_p.name("favorites menu"); menu_p.can_tear_off(false); menu_p.visible(false); @@ -536,26 +671,26 @@ void LLFavoritesBarCtrl::showDropDownMenu() menu_p.max_scrollable_items = 10; menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; - LLToggleableMenu* menu = LLUICtrlFactory::create(menu_p); - + LLFavoritesToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + menu->initFavoritesBarPointer(this); mPopupMenuHandle = menu->getHandle(); } - LLToggleableMenu* menu = (LLToggleableMenu*)mPopupMenuHandle.get(); + LLFavoritesToggleableMenu* menu = (LLFavoritesToggleableMenu*)mPopupMenuHandle.get(); if(menu) { if (!menu->toggleVisibility()) return; - LLInventoryModel::item_array_t items; + mItems.clear(); - if (!collectFavoriteItems(items)) + if (!collectFavoriteItems(mItems)) { return; } - S32 count = items.count(); + S32 count = mItems.count(); // Check it there are changed items, since last call if (mItemNamesCache.size() == count) @@ -563,7 +698,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() S32 i; for (i = mFirstDropDownItem; i < count; i++) { - if (mItemNamesCache.get(i) != items.get(i)->getName()) + if (mItemNamesCache.get(i) != mItems.get(i)->getName()) { break; } @@ -587,7 +722,7 @@ void LLFavoritesBarCtrl::showDropDownMenu() { for (S32 i = mFirstDropDownItem; i < count; i++) { - mItemNamesCache.put(items.get(i)->getName()); + mItemNamesCache.put(mItems.get(i)->getName()); } } @@ -598,17 +733,18 @@ void LLFavoritesBarCtrl::showDropDownMenu() for(S32 i = mFirstDropDownItem; i < count; i++) { - LLInventoryItem* item = items.get(i); + LLViewerInventoryItem* item = mItems.get(i); const std::string& item_name = item->getName(); - LLMenuItemCallGL::Params item_params; + LLFavoriteLandmarkMenuItem::Params item_params; item_params.name(item_name); item_params.label(item_name); item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create(item_params); menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this,item->getUUID(),_1,_2,_3,_4)); - menu_item->setLandmarkID(item->getUUID()); + menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); // Check whether item name wider than menu if (menu_item->getNominalWidth() > max_width) @@ -644,13 +780,6 @@ void LLFavoritesBarCtrl::showDropDownMenu() void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) { - LLInventoryModel::item_array_t items; - - if (!collectFavoriteItems(items)) - { - return; - } - // We only have one Inventory, gInventory. Some day this should be better abstracted. LLInvFVBridgeAction::doAction(item_id,&gInventory); } @@ -797,5 +926,135 @@ void LLFavoritesBarCtrl::pastFromClipboard() const } } +void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + mDragItemId = id; + mStartDrag = TRUE; + + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY); +} + +void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + mDragItemId = LLUUID::null; +} + +BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) +{ + if (mDragItemId != LLUUID::null && mStartDrag) + { + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY)) + { + LLToolDragAndDrop::getInstance()->beginDrag( + DAD_LANDMARK, mDragItemId, + LLToolDragAndDrop::SOURCE_LIBRARY); + + mStartDrag = FALSE; + + return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); + } + } + + return TRUE; +} + +LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) +{ + LLUICtrl* ctrl = 0; + S32 screenX, screenY; + const child_list_t* list = getChildList(); + + localPointToScreen(x, y, &screenX, &screenY); + + // look for a child which contains the point (screenX, screenY) in it's rectangle + for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i) + { + LLRect rect; + localRectToScreen((*i)->getRect(), &rect); + + if (rect.pointInRect(screenX, screenY)) + { + ctrl = dynamic_cast(*i); + break; + } + } + + return ctrl; +} + +BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) +{ + BOOL result = FALSE; + + // if there is an item without sort order field set, we need to save items order + for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + if ((*i)->getSortField() < 0) + { + result = TRUE; + break; + } + } + + return result; +} + +void LLFavoritesBarCtrl::saveItemsOrder(LLInventoryModel::item_array_t& items) +{ + int sortField = 0; + + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLViewerInventoryItem* item = *i; + + item->setSortField(++sortField); + item->setComplete(TRUE); + item->updateServer(FALSE); + + gInventory.updateItem(item); + } + + gInventory.notifyObservers(); +} + +LLInventoryModel::item_array_t::iterator LLFavoritesBarCtrl::findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) +{ + LLInventoryModel::item_array_t::iterator result = items.end(); + + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + if ((*i)->getUUID() == id) + { + result = i; + break; + } + } + + return result; +} + +void LLFavoritesBarCtrl::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId) +{ + LLViewerInventoryItem* srcItem = gInventory.getItem(srcItemId); + LLViewerInventoryItem* destItem = gInventory.getItem(destItemId); + + items.erase(findItemByUUID(items, srcItem->getUUID())); + items.insert(findItemByUUID(items, destItem->getUUID()), srcItem); +} + +void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId) +{ + LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId); + LLViewerInventoryItem* insertedItem = gInventory.getItem(insertedItemId); + + items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem); +} // EOF diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 824b396add..4cd92d1a58 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -60,6 +60,8 @@ public: EAcceptance* accept, std::string& tooltip_msg); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + // LLInventoryObserver observer trigger virtual void changed(U32 mask); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); @@ -73,10 +75,12 @@ protected: void onButtonClick(LLUUID id); void onButtonRightClick(LLUUID id,LLView* button,S32 x,S32 y,MASK mask); + void onButtonMouseDown(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask); + void onButtonMouseUp(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask); + void doToSelected(const LLSD& userdata); BOOL isClipboardPasteable() const; void pastFromClipboard() const; - void showDropDownMenu(); @@ -94,8 +98,49 @@ protected: LLRect mChevronRect; std::string mChevronButtonToolTip; + +private: + /* + * Helper function to make code more readable. It handles all drag and drop + * operations of the existing favorites items on the favorites bar. + */ + void handleExistingFavoriteDragAndDrop(S32 x, S32 y); + + /* + * Helper function to make code more readable. It handles all drag and drop + * operations of the new landmark to the favorites bar. + */ + void handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y); + + // finds a control under the specified LOCAL point + LLUICtrl* findChildByLocalCoords(S32 x, S32 y); + + // checks if the current order of the favorites items must be saved + BOOL needToSaveItemsOrder(const LLInventoryModel::item_array_t& items); + + // saves current order of the favorites items + void saveItemsOrder(LLInventoryModel::item_array_t& items); + + /* + * changes favorites items order by insertion of the item identified by srcItemId + * BEFORE the item identified by destItemId. both items must exist in items array. + */ + void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId); + + /* + * inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId. + * this function assumes that an item identified by insertedItemId doesn't exist in items array. + */ + void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId); + + // finds an item by it's UUID in the items array + LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); + + BOOL mSkipUpdate; + BOOL mStartDrag; + LLUUID mDragItemId; + LLInventoryModel::item_array_t mItems; }; #endif // LL_LLFAVORITESBARCTRL_H - diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 0dee3a1e83..14fb93df61 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -47,7 +47,6 @@ #include "llconsole.h" #include "llfloateractivespeakers.h" #include "llfloaterchatterbox.h" -#include "llfloatermute.h" #include "llfloaterreg.h" #include "llfloaterscriptdebug.h" #include "llkeyboard.h" @@ -56,6 +55,7 @@ //#include "llresizehandle.h" #include "llchatbar.h" #include "llrecentpeople.h" +#include "llpanelblockedlist.h" #include "llstatusbar.h" #include "llviewertexteditor.h" #include "llviewergesture.h" // for triggering gestures @@ -280,7 +280,7 @@ void LLFloaterChat::onClickMute(void *data) LLMute mute(id); mute.setFromDisplayName(name); LLMuteList::getInstance()->add(mute); - LLFloaterReg::showInstance("mute"); + LLPanelBlockedList::showPanelAndSelect(mute.mID); } //static diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c47c7b073c..d389cf06ec 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -61,6 +61,7 @@ #include "llnavigationbar.h" #include "llpanellogin.h" #include "llradiogroup.h" +#include "llsearchcombobox.h" #include "llsky.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" @@ -214,6 +215,11 @@ bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response // flag client texture cache for clearing next time the client runs gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); LLNotifications::instance().add("CacheWillClear"); + + LLSearchHistory::getInstance()->clearHistory(); + LLSearchHistory::getInstance()->save(); + LLSearchComboBox* search_ctrl = LLNavigationBar::getInstance()->getChild("search_combo_box"); + search_ctrl->clearHistory(); } return false; diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp index bef5f094e3..97b7f3e9ad 100644 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -173,6 +173,15 @@ bool LLFriendCardsManager::isCategoryInFriendFolder(const LLViewerInventoryCateg return TRUE == gInventory.isObjectDescendentOf(cat->getUUID(), findFriendFolderUUIDImpl()); } +bool LLFriendCardsManager::isAnyFriendCategory(const LLUUID& catID) const +{ + const LLUUID& friendFolderID = findFriendFolderUUIDImpl(); + if (catID == friendFolderID) + return true; + + return TRUE == gInventory.isObjectDescendentOf(catID, friendFolderID); +} + void LLFriendCardsManager::syncFriendsFolder() { //lets create "Friends" and "Friends/All" in the Inventory "Calling Cards" if they are absent @@ -305,10 +314,12 @@ void LLFriendCardsManager::findMatchedFriendCards(const LLUUID& avatarID, LLInve LLInventoryModel::cat_array_t cats; LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); - LLParticularBuddyCollector matchFunctor(avatarID); LLViewerInventoryCategory* friendFolder = gInventory.getCategory(friendFolderUUID); + if (NULL == friendFolder) + return; + LLParticularBuddyCollector matchFunctor(avatarID); LLInventoryModel::cat_array_t subFolders; subFolders.push_back(friendFolder); diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h index 18a6d0ab69..aa391ce2c1 100644 --- a/indra/newview/llfriendcard.h +++ b/indra/newview/llfriendcard.h @@ -76,6 +76,11 @@ public: */ bool isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const; + /** + * Checks is the specified category is a Friend folder or any its subfolder + */ + bool isAnyFriendCategory(const LLUUID& catID) const; + /** * Synchronizes content of the Calling Card/Friends/All Global Inventory folder with Agent's Friend List */ diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 789e628b67..adc73111e0 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2420,8 +2420,14 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, drop); break; case DAD_CATEGORY: - accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, - drop); + if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID)) + { + accept = FALSE; + } + else + { + accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop); + } break; default: break; diff --git a/indra/newview/lllocationhistory.cpp b/indra/newview/lllocationhistory.cpp index c83cde9d83..d910dbf718 100644 --- a/indra/newview/lllocationhistory.cpp +++ b/indra/newview/lllocationhistory.cpp @@ -37,59 +37,41 @@ #include // for std::setw() #include "llui.h" - -const char LLLocationHistory::delimiter = '\t'; +#include "llsd.h" +#include "llsdserialize.h" LLLocationHistory::LLLocationHistory() : mFilename("typed_locations.txt") { } -void LLLocationHistory::addItem(const std::string & item, const std::string & tooltip) { +void LLLocationHistory::addItem(const LLLocationHistoryItem& item) { static LLUICachedControl max_items("LocationHistoryMaxSize", 100); // check if this item doesn't duplicate any existing one - std::vector::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), - boost::bind(&LLLocationHistory::equalByRegionParcel,this,_1,item)); + location_list_t::iterator item_iter = std::find(mItems.begin(), mItems.end(),item); if(item_iter != mItems.end()){ - /*replace duplicate. - * If an item's region and item's parcel are equal. - */ - mToolTips.erase(*item_iter); mItems.erase(item_iter); - } mItems.push_back(item); - mToolTips[item] = tooltip; - + // If the vector size exceeds the maximum, purge the oldest items. if ((S32)mItems.size() > max_items) { - for(std::vector::iterator i = mItems.begin(); i != mItems.end()-max_items; ++i) { - mToolTips.erase(*i); - mItems.erase(i); + for(location_list_t::iterator i = mItems.begin(); i != mItems.end()-max_items; ++i) { + mItems.erase(i); } } } -/** - * check if the history item is equal. - * @return true - if region name and parcel is equal. +/* + * @brief Try to find item in history. + * If item has been founded, it will be places into end of history. + * @return true - item has founded */ -bool LLLocationHistory::equalByRegionParcel(const std::string& item, const std::string& newItem){ - - - S32 itemIndex = item.find('('); - S32 newItemIndex = newItem.find('('); - - std::string region_parcel = item.substr(0,itemIndex); - std::string new_region_parcel = newItem.substr(0,newItemIndex); - - return region_parcel == new_region_parcel; -} -bool LLLocationHistory::touchItem(const std::string & item) { +bool LLLocationHistory::touchItem(const LLLocationHistoryItem& item) { bool result = false; - std::vector::iterator item_iter = std::find(mItems.begin(), mItems.end(), item); + location_list_t::iterator item_iter = std::find(mItems.begin(), mItems.end(), item); // the last used item should be the first in the history if (item_iter != mItems.end()) { @@ -104,13 +86,6 @@ bool LLLocationHistory::touchItem(const std::string & item) { void LLLocationHistory::removeItems() { mItems.clear(); - mToolTips.clear(); -} - -std::string LLLocationHistory::getToolTip(const std::string & item) const { - std::map::const_iterator i = mToolTips.find(item); - - return i != mToolTips.end() ? i->second : ""; } bool LLLocationHistory::getMatchingItems(std::string substring, location_list_t& result) const @@ -123,7 +98,7 @@ bool LLLocationHistory::getMatchingItems(std::string substring, location_list_t& for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it) { - std::string haystack = *it; + std::string haystack = it->getLocation(); LLStringUtil::toLower(haystack); if (haystack.find(needle) != std::string::npos) @@ -139,7 +114,7 @@ void LLLocationHistory::dump() const int i = 0; for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it, ++i) { - llinfos << "#" << std::setw(2) << std::setfill('0') << i << ": " << *it << llendl; + llinfos << "#" << std::setw(2) << std::setfill('0') << i << ": " << it->getLocation() << llendl; } } @@ -158,11 +133,7 @@ void LLLocationHistory::save() const for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it) { - std::string tooltip = getToolTip(*it); - if(!tooltip.empty()) - { - file << (*it) << delimiter << tooltip << std::endl; - } + file << LLSDOStreamer((*it).toLLSD()) << std::endl; } file.close(); @@ -186,16 +157,17 @@ void LLLocationHistory::load() // add each line in the file to the list std::string line; - + LLPointer parser = new LLSDNotationParser(); while (std::getline(file, line)) { - size_t dp = line.find(delimiter); - - if (dp != std::string::npos) { - const std::string reg_name = line.substr(0, dp); - const std::string tooltip = line.substr(dp + 1, std::string::npos); - - addItem(reg_name, tooltip); + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + llinfos<< "Parsing saved teleport history failed" << llendl; + break; } + + mItems.push_back(s_item); } file.close(); diff --git a/indra/newview/lllocationhistory.h b/indra/newview/lllocationhistory.h index 060a6b2fe8..5f9976f87a 100644 --- a/indra/newview/lllocationhistory.h +++ b/indra/newview/lllocationhistory.h @@ -40,21 +40,84 @@ #include #include +class LLSD; + +enum ELocationType { + TYPED_REGION_SURL//region name or surl + ,LANDMARK // name of landmark + ,TELEPORT_HISTORY + }; +class LLLocationHistoryItem { + +public: + LLLocationHistoryItem(){} + LLLocationHistoryItem(std::string typed_location, + LLVector3d global_position, std::string tooltip,ELocationType type ): + mLocation(typed_location), + mGlobalPos(global_position), + mToolTip(tooltip), + mType(type) + {} + LLLocationHistoryItem(const LLLocationHistoryItem& item): + mGlobalPos(item.mGlobalPos), + mToolTip(item.mToolTip), + mLocation(item.mLocation), + mType(item.mType) + {} + LLLocationHistoryItem(const LLSD& data): + mLocation(data["location"]), + mGlobalPos(data["global_pos"]), + mToolTip(data["tooltip"]), + mType(ELocationType(data["item_type"].asInteger())) + {} + + bool operator==(const LLLocationHistoryItem& item) + { + // do not compare mGlobalPos, + // because of a rounding off , the history can contain duplicates + return mLocation == item.mLocation && (mType == item.mType); + } + bool operator!=(const LLLocationHistoryItem& item) + { + return ! (*this == item); + } + LLSD toLLSD() const + { + LLSD val; + val["location"]= mLocation; + val["global_pos"] = mGlobalPos.getValue(); + val["tooltip"] = mToolTip; + val["item_type"] = mType; + return val; + } + const std::string& getLocation() const { return mLocation; }; + const std::string& getToolTip() const { return mToolTip; }; + //static bool equalByRegionParcel(const LLLocationHistoryItem& item1, const LLLocationHistoryItem& item2); + static bool equalByLocation(const LLLocationHistoryItem& item1, const std::string& item_location) + { + return item1.getLocation() == item_location; + } + + LLVector3d mGlobalPos; // global position + std::string mToolTip;// SURL + std::string mLocation;// typed_location + ELocationType mType; +}; + class LLLocationHistory: public LLSingleton { LOG_CLASS(LLLocationHistory); public: - typedef std::vector location_list_t; + typedef std::vector location_list_t; typedef boost::function loaded_callback_t; typedef boost::signals2::signal loaded_signal_t; LLLocationHistory(); - void addItem(const std::string & item, const std::string & tooltip); - bool touchItem(const std::string & item); + void addItem(const LLLocationHistoryItem& item); + bool touchItem(const LLLocationHistoryItem& item); void removeItems(); - std::string getToolTip(const std::string & item) const; size_t getItemCount() const { return mItems.size(); } const location_list_t& getItems() const { return mItems; } bool getMatchingItems(std::string substring, location_list_t& result) const; @@ -65,10 +128,8 @@ public: void dump() const; private: - bool equalByRegionParcel(const std::string& item, const std::string& item_to_add); - const static char delimiter; - std::vector mItems; - std::map mToolTips; + + location_list_t mItems; std::string mFilename; /// File to store the history to. loaded_signal_t mLoadedSignal; }; diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index a8ec826e88..f54a614f62 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -48,6 +48,7 @@ #include "lllandmarkactions.h" #include "lllandmarklist.h" #include "lllocationhistory.h" +#include "llteleporthistory.h" #include "llsidetray.h" #include "llslurl.h" #include "lltrans.h" @@ -295,11 +296,19 @@ BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* if (LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen) && !msg.empty()) { if (mList->getRect().pointInRect(x, y)) { - LLLocationHistory* lh = LLLocationHistory::getInstance(); - const std::string tooltip = lh->getToolTip(msg); - - if (!tooltip.empty()) { - msg = tooltip; + S32 loc_x, loc_y; + //x,y - contain coordinates related to the location input control, but without taking the expanded list into account + //So we have to convert it again into local coordinates of mList + localPointToOtherView(x,y,&loc_x,&loc_y,mList); + + LLScrollListItem* item = mList->hitItem(loc_x,loc_y); + if (item) + { + LLSD value = item->getValue(); + if (value.has("tooltip")) + { + msg = value["tooltip"].asString(); + } } } @@ -448,18 +457,58 @@ void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) rebuildLocationHistory(filter); //Let's add landmarks to the top of the list if any - if( filter.size() !=0 ) + if(!filter.empty() ) { LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(filter, TRUE); for(U32 i=0; i < landmark_items.size(); i++) { - mList->addSimpleElement(landmark_items[i]->getName(), ADD_TOP); + LLSD value; + //TODO:: DO we need tooltip for Landmark?? + + value["item_type"] = LANDMARK; + value["AssetUUID"] = landmark_items[i]->getAssetUUID(); + add(landmark_items[i]->getName(), value); + + } + //Let's add teleport history items + LLTeleportHistory* th = LLTeleportHistory::getInstance(); + LLTeleportHistory::slurl_list_t th_items = th->getItems(); + + std::set new_item_titles;// duplicate control + LLTeleportHistory::slurl_list_t::iterator result = std::find_if( + th_items.begin(), th_items.end(), boost::bind( + &LLLocationInputCtrl::findTeleportItemsByTitle, this, + _1, filter)); + + while (result != th_items.end()) + { + //mTitile format - region_name[, parcel_name] + //mFullTitile format - region_name[, parcel_name] (local_x,local_y, local_z) + if (new_item_titles.insert(result->mFullTitle).second) + { + LLSD value; + value["item_type"] = TELEPORT_HISTORY; + value["global_pos"] = result->mGlobalPos.getValue(); + std::string region_name = result->mTitle.substr(0, result->mTitle.find(',')); + //TODO*: add Surl to teleportitem or parse region name from title + value["tooltip"] = LLSLURL::buildSLURLfromPosGlobal(region_name, + result->mGlobalPos, false); + add(result->getTitle(), value); + } + result = std::find_if(result + 1, th_items.end(), boost::bind( + &LLLocationInputCtrl::findTeleportItemsByTitle, this, + _1, filter)); } } + sortByName(); + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. } - +bool LLLocationInputCtrl::findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter) +{ + return item.mTitle.find(filter) != std::string::npos; +} void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) { if (mLocationContextMenu) @@ -519,7 +568,12 @@ void LLLocationInputCtrl::rebuildLocationHistory(std::string filter) removeall(); for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++) { - add(*it); + LLSD value; + value["tooltip"] = it->getToolTip(); + //location history can contain only typed locations + value["item_type"] = TYPED_REGION_SURL; + value["global_pos"] = it->mGlobalPos.getValue(); + add(it->getLocation(), value); } } diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h index d967df8257..3c43e1a321 100644 --- a/indra/newview/lllocationinputctrl.h +++ b/indra/newview/lllocationinputctrl.h @@ -41,6 +41,7 @@ class LLLandmark; class LLAddLandmarkObserver; class LLRemoveLandmarkObserver; class LLMenuGL; +class LLTeleportHistoryItem; /** * Location input control. @@ -103,6 +104,7 @@ private: void refresh(); void refreshLocation(); void rebuildLocationHistory(std::string filter = ""); + bool findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter); void setText(const LLStringExplicit& text); void updateAddLandmarkButton(); void updateContextMenu(); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 28e9c93779..c283b3a05f 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -45,7 +45,7 @@ #include "lllocationhistory.h" #include "lllocationinputctrl.h" #include "llteleporthistory.h" -#include "llsearcheditor.h" +#include "llsearchcombobox.h" #include "llsidetray.h" #include "llslurl.h" #include "llurlsimstring.h" @@ -82,7 +82,6 @@ public: Mandatory item_type; Params() {} - Params(EType type, std::string title); }; /*virtual*/ void draw(); @@ -104,24 +103,21 @@ private: const std::string LLTeleportHistoryMenuItem::ICON_IMG_BACKWARD("teleport_history_backward.tga"); const std::string LLTeleportHistoryMenuItem::ICON_IMG_FORWARD("teleport_history_forward.tga"); -LLTeleportHistoryMenuItem::Params::Params(EType type, std::string title) -{ - item_type(type); - font.name("SANSSERIF"); - - if (type == TYPE_CURRENT) - font.style("BOLD"); - else - title = " " + title; - - name(title); - label(title); -} - LLTeleportHistoryMenuItem::LLTeleportHistoryMenuItem(const Params& p) : LLMenuItemCallGL(p), mArrowIcon(NULL) { + // Set appearance depending on the item type. + if (p.item_type == TYPE_CURRENT) + { + setFont(LLFontGL::getFontSansSerifBold()); + } + else + { + setFont(LLFontGL::getFontSansSerif()); + setLabel(std::string(" ") + std::string(p.label)); + } + LLIconCtrl::Params icon_params; icon_params.name("icon"); icon_params.rect(LLRect(0, ICON_HEIGHT, ICON_WIDTH, 0)); @@ -183,14 +179,11 @@ LLNavigationBar::LLNavigationBar() mBtnForward(NULL), mBtnHome(NULL), mCmbLocation(NULL), - mLeSearch(NULL), + mSearchComboBox(NULL), mPurgeTPHistoryItems(false) { setIsChrome(TRUE); - mParcelMgrConnection = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback( - boost::bind(&LLNavigationBar::onTeleportFinished, this, _1)); - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_navigation_bar.xml"); // set a listener function for LoginComplete event @@ -202,8 +195,10 @@ LLNavigationBar::LLNavigationBar() LLNavigationBar::~LLNavigationBar() { - mParcelMgrConnection.disconnect(); + mTeleportFinishConnection.disconnect(); sInstance = 0; + + LLSearchHistory::getInstance()->save(); } BOOL LLNavigationBar::postBuild() @@ -213,10 +208,12 @@ BOOL LLNavigationBar::postBuild() mBtnHome = getChild("home_btn"); mCmbLocation= getChild("location_combo"); - mLeSearch = getChild("search_input"); + mSearchComboBox = getChild("search_combo_box"); + + fillSearchComboBox(); if (!mBtnBack || !mBtnForward || !mBtnHome || - !mCmbLocation || !mLeSearch) + !mCmbLocation || !mSearchComboBox) { llwarns << "Malformed navigation bar" << llendl; return FALSE; @@ -234,7 +231,7 @@ BOOL LLNavigationBar::postBuild() mCmbLocation->setSelectionCallback(boost::bind(&LLNavigationBar::onLocationSelection, this)); - mLeSearch->setCommitCallback(boost::bind(&LLNavigationBar::onSearchCommit, this)); + mSearchComboBox->setCommitCallback(boost::bind(&LLNavigationBar::onSearchCommit, this)); mDefaultNbRect = getRect(); mDefaultFpRect = getChild("favorite")->getRect(); @@ -246,6 +243,25 @@ BOOL LLNavigationBar::postBuild() return TRUE; } +void LLNavigationBar::fillSearchComboBox() +{ + if(!mSearchComboBox) + { + return; + } + + LLSearchHistory::getInstance()->load(); + + LLSearchHistory::search_history_list_t search_list = + LLSearchHistory::getInstance()->getSearchHistoryList(); + LLSearchHistory::search_history_list_t::const_iterator it = search_list.begin(); + for( ; search_list.end() != it; ++it) + { + LLSearchHistory::LLSearchHistoryItem item = *it; + mSearchComboBox->add(item.search_query); + } +} + void LLNavigationBar::draw() { if(mPurgeTPHistoryItems) @@ -280,7 +296,12 @@ void LLNavigationBar::onHomeButtonClicked() void LLNavigationBar::onSearchCommit() { - invokeSearch(mLeSearch->getValue().asString()); + std::string search_query = mSearchComboBox->getValue().asString(); + if(!search_query.empty()) + { + LLSearchHistory::getInstance()->addEntry(search_query); + invokeSearch(mSearchComboBox->getValue().asString()); + } } void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) @@ -299,69 +320,107 @@ void LLNavigationBar::onLocationSelection() if (typed_location.empty()) return; + LLSD value = mCmbLocation->getSelectedValue(); + + if(value.has("item_type")) + { + + switch(value["item_type"].asInteger()) + { + case LANDMARK: + + if(value.has("AssetUUID")) + { + + gAgent.teleportViaLandmark( LLUUID(value["AssetUUID"].asString())); + return; + } + else + { + LLInventoryModel::item_array_t landmark_items = + LLLandmarkActions::fetchLandmarksByName(typed_location, + FALSE); + if (!landmark_items.empty()) + { + gAgent.teleportViaLandmark( landmark_items[0]->getAssetUUID()); + return; + } + } + break; + + case TELEPORT_HISTORY: + //in case of teleport item was selected, teleport by position too. + case TYPED_REGION_SURL: + if(value.has("global_pos")) + { + gAgent.teleportViaLocation(LLVector3d(value["global_pos"])); + return; + } + break; + + default: + break; + } + } + //Let's parse surl or region name + std::string region_name; LLVector3 local_coords(128, 128, 0); S32 x = 0, y = 0, z = 0; - // Is the typed location a SLURL? if (LLSLURL::isSLURL(typed_location)) { // Yes. Extract region name and local coordinates from it. if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), ®ion_name, &x, &y, &z)) - local_coords.set(x, y, z); + local_coords.set(x, y, z); else return; - } - else + }else { - //If it is not slurl let's look for landmarks - LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(typed_location, FALSE); - if ( !landmark_items.empty() ) - { - gAgent.teleportViaLandmark(landmark_items[0]->getAssetUUID()); - return; - } - //No landmark match, check if it is a region name - region_name = parseLocation(typed_location, &x, &y, &z); - if (region_name != typed_location) - local_coords.set(x, y, z); - - // Treat it as region name. - // region_name = typed_location; + // assume that an user has typed the {region name} or possible {region_name, parcel} + region_name = typed_location.substr(0,typed_location.find(',')); } - + // Resolve the region name to its global coordinates. // If resolution succeeds we'll teleport. LLWorldMap::url_callback_t cb = boost::bind( &LLNavigationBar::onRegionNameResponse, this, typed_location, region_name, local_coords, _1, _2, _3, _4); + // connect the callback each time, when user enter new location to get real location of agent after teleport + mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1,typed_location)); + LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false); } -void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos) +void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location) { // Location is valid. Add it to the typed locations history. LLLocationHistory* lh = LLLocationHistory::getInstance(); + //TODO*: do we need convert surl into readable format? std::string location; /*NOTE: * We can't use gAgent.getPositionAgent() in case of local teleport to build location. * At this moment gAgent.getPositionAgent() contains previous coordinates. * according to EXT-65 agent position is being reseted on each frame. */ - LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM, - gAgent.getPosAgentFromGlobal(global_agent_pos)); + LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM, + gAgent.getPosAgentFromGlobal(global_agent_pos)); + std::string tooltip (LLSLURL::buildSLURLfromPosGlobal(gAgent.getRegion()->getName(), global_agent_pos, false)); + LLLocationHistoryItem item (location, + global_agent_pos, tooltip,TYPED_REGION_SURL);// we can add into history only TYPED location //Touch it, if it is at list already, add new location otherwise - if ( !lh->touchItem(location) ) { - std::string tooltip = LLSLURL::buildSLURLfromPosGlobal( - gAgent.getRegion()->getName(), global_agent_pos, false); - - lh->addItem(location, tooltip); + if ( !lh->touchItem(item) ) { + lh->addItem(item); } - llinfos << "Saving after on teleport finish" << llendl; - lh->save(); + lh->save(); + + if(mTeleportFinishConnection.connected()) + mTeleportFinishConnection.disconnect(); + } void LLNavigationBar::onTeleportHistoryChanged() @@ -411,7 +470,9 @@ void LLNavigationBar::rebuildTeleportHistoryMenu() else type = LLTeleportHistoryMenuItem::TYPE_CURRENT; - LLTeleportHistoryMenuItem::Params item_params(type, hist_items[i].getTitle()); + LLTeleportHistoryMenuItem::Params item_params; + item_params.label = item_params.name = hist_items[i].getTitle(); + item_params.item_type = type; item_params.on_click.function(boost::bind(&LLNavigationBar::onTeleportHistoryMenuItemClicked, this, i)); LLTeleportHistoryMenuItem* new_itemp = LLUICtrlFactory::create(item_params); //new_itemp->setFont() @@ -435,8 +496,8 @@ void LLNavigationBar::onRegionNameResponse( // Teleport to the location. LLVector3d region_pos = from_region_handle(region_handle); LLVector3d global_pos = region_pos + (LLVector3d) local_coords; - - llinfos << "Teleporting to: " << global_pos << llendl; + + llinfos << "Teleporting to: " << LLSLURL::buildSLURLfromPosGlobal(region_name, global_pos, false) << llendl; gAgent.teleportViaLocation(global_pos); } @@ -474,35 +535,6 @@ void LLNavigationBar::invokeSearch(std::string search_text) LLFloaterReg::showInstance("search", LLSD().insert("panel", "all").insert("id", LLSD(search_text))); } -std::string LLNavigationBar::parseLocation(const std::string & location, S32* x, S32* y, S32* z) { - /* - * This regular expression extracts numbers from the following string - * construct: "(num1, num2, num3)", where num1, num2 and num3 are decimal - * numbers. Leading and trailing spaces are also caught by the expression. - */ - const boost::regex re("\\s*\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)\\s*"); - - boost::smatch m; - if (boost::regex_search(location, m, re)) { - // string representations of parsed by regex++ numbers - std::string xstr(m[1].first, m[1].second); - std::string ystr(m[2].first, m[2].second); - std::string zstr(m[3].first, m[3].second); - - *x = atoi(xstr.c_str()); - *y = atoi(ystr.c_str()); - *z = atoi(zstr.c_str()); - //erase commas in coordinates - std::string region_parcel = boost::regex_replace(location, re, ""); - // cut region name - return region_parcel.substr(0, region_parcel.find_first_of(',')); - } - - *x = *y = *z = 0; - - return location; -} - void LLNavigationBar::clearHistoryCache() { mCmbLocation->removeall(); diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 6932847854..8a65cd24fa 100644 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -41,6 +41,7 @@ class LLButton; class LLLocationInputCtrl; class LLMenuGL; class LLSearchEditor; +class LLSearchComboBox; /** * Web browser-like navigation bar. @@ -69,12 +70,6 @@ private: void rebuildTeleportHistoryMenu(); void showTeleportHistoryMenu(); void invokeSearch(std::string search_text); - - /** - * Get region name and local coordinates from typed location - */ - static std::string parseLocation(const std::string & location, S32* x, S32* y, S32* z); - // callbacks void onTeleportHistoryMenuItemClicked(const LLSD& userdata); void onTeleportHistoryChanged(); @@ -86,7 +81,7 @@ private: void onLocationSelection(); void onLocationPrearrange(const LLSD& data); void onSearchCommit(); - void onTeleportFinished(const LLVector3d& global_agent_pos); + void onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location); void onRegionNameResponse( std::string typed_location, std::string region_name, @@ -94,17 +89,19 @@ private: U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport); + void fillSearchComboBox(); + static LLNavigationBar *sInstance; LLMenuGL* mTeleportHistoryMenu; LLButton* mBtnBack; LLButton* mBtnForward; LLButton* mBtnHome; - LLSearchEditor* mLeSearch; + LLSearchComboBox* mSearchComboBox; LLLocationInputCtrl* mCmbLocation; LLRect mDefaultNbRect; LLRect mDefaultFpRect; - boost::signals2::connection mParcelMgrConnection; + boost::signals2::connection mTeleportFinishConnection; bool mPurgeTPHistoryItems; }; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index b2d606ab4d..fd3519bf4b 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -372,7 +372,6 @@ void LLPanelAvatarProfile::resetControls() childSetVisible("status_me_panel", false); childSetVisible("profile_me_buttons_panel", false); childSetVisible("account_actions_panel", false); - childSetVisible("partner_edit_link", false); } void LLPanelAvatarProfile::resetData() @@ -539,7 +538,7 @@ void LLPanelAvatarProfile::fillAccountStatus(const LLAvatarData* avatar_data) childSetValue("acc_status_text", caption_text); } -void LLPanelAvatarProfile::onUrlTextboxClicked(std::string url) +void LLPanelAvatarProfile::onUrlTextboxClicked(const std::string& url) { LLWeb::loadURL(url); } @@ -675,4 +674,3 @@ void LLPanelAvatarMeProfile::onStatusMessageChanged() { updateData(); } - diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 4ee4cb6e87..1ed5fa4357 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -166,7 +166,7 @@ protected: */ virtual void fillAccountStatus(const LLAvatarData* avatar_data); - void onUrlTextboxClicked(std::string url); + void onUrlTextboxClicked(const std::string& url); void onHomepageTextboxClicked(); void onAddFriendButtonClick(); void onIMButtonClick(); diff --git a/indra/newview/llpanelblockedlist.cpp b/indra/newview/llpanelblockedlist.cpp new file mode 100644 index 0000000000..60d0f07285 --- /dev/null +++ b/indra/newview/llpanelblockedlist.cpp @@ -0,0 +1,279 @@ +/** + * @file llpanelblockedlist.cpp + * @brief Container for blocked Residents & Objects list + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloater.h" +#include "llfloaterreg.h" +#include "llscrolllistctrl.h" + +#include "llpanelblockedlist.h" + +// project include +#include "llfloateravatarpicker.h" +#include "llsidetray.h" +#include "llsidetraypanelcontainer.h" + +static LLRegisterPanelClassWrapper t_panel_blocked_list("panel_block_list_sidetray"); + +// +// Constants +// +const std::string BLOCKED_PARAM_NAME = "blocked_to_select"; + +//----------------------------------------------------------------------------- +// LLPanelBlockedList() +//----------------------------------------------------------------------------- + +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); +} + +BOOL LLPanelBlockedList::postBuild() +{ + mBlockedList = getChild("blocked"); + mBlockedList->setCommitOnSelectionChange(TRUE); + + childSetCommitCallback("back", boost::bind(&LLPanelBlockedList::onBackBtnClick, this), NULL); + + LLMuteList::getInstance()->addObserver(this); + + refreshBlockedList(); + + return LLPanel::postBuild(); +} + +void LLPanelBlockedList::draw() +{ + updateButtons(); + LLPanel::draw(); +} + +void LLPanelBlockedList::onOpen(const LLSD& key) +{ + if (key.has(BLOCKED_PARAM_NAME) && key[BLOCKED_PARAM_NAME].asUUID().notNull()) + { + selectBlocked(key[BLOCKED_PARAM_NAME].asUUID()); + } +} + +void LLPanelBlockedList::selectBlocked(const LLUUID& mute_id) +{ + mBlockedList->selectByID(mute_id); +} + +void LLPanelBlockedList::showPanelAndSelect(const LLUUID& idToSelect) +{ + LLSideTray::getInstance()->showPanel("panel_block_list_sidetray", LLSD().insert(BLOCKED_PARAM_NAME, idToSelect)); +} + + +////////////////////////////////////////////////////////////////////////// +// Private Section +////////////////////////////////////////////////////////////////////////// +void LLPanelBlockedList::refreshBlockedList() +{ + mBlockedList->deleteAllItems(); + + std::vector mutes = LLMuteList::getInstance()->getMutes(); + std::vector::iterator it; + for (it = mutes.begin(); it != mutes.end(); ++it) + { + std::string display_name = it->getDisplayName(); + mBlockedList->addStringUUIDItem(display_name, it->mID, ADD_BOTTOM, TRUE); + } +} + +void LLPanelBlockedList::updateButtons() +{ + bool hasSelected = NULL != mBlockedList->getFirstSelected(); + childSetEnabled("Unblock", hasSelected); +} + + + +void LLPanelBlockedList::onBackBtnClick() +{ + LLSideTrayPanelContainer* parent = dynamic_cast(getParent()); + if(parent) + { + parent->openPreviousPanel(); + } +} + +void LLPanelBlockedList::onRemoveBtnClick() +{ + std::string name = mBlockedList->getSelectedItemLabel(); + LLUUID id = mBlockedList->getStringUUIDSelectedItem(); + LLMute mute(id); + mute.setFromDisplayName(name); + // now mute.mName has the suffix trimmed off + + S32 last_selected = mBlockedList->getFirstSelectedIndex(); + if (LLMuteList::getInstance()->remove(mute)) + { + // 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); + } + } +} + +void LLPanelBlockedList::onPickBtnClick() +{ + const BOOL allow_multiple = FALSE; + const BOOL close_on_select = TRUE; + /*LLFloaterAvatarPicker* picker = */LLFloaterAvatarPicker::show(callbackBlockPicked, this, allow_multiple, close_on_select); + + // *TODO: mantipov: should LLFloaterAvatarPicker be closed when panel is closed? + // old Floater dependency is not enable in panel + // addDependentFloater(picker); +} + +void LLPanelBlockedList::onBlockByNameClick() +{ + LLFloaterGetBlockedObjectName::show(&LLPanelBlockedList::callbackBlockByName); +} + +//static +void LLPanelBlockedList::callbackBlockPicked(const std::vector& names, const std::vector& ids, void* user_data) +{ + if (names.empty() || ids.empty()) return; + LLMute mute(ids[0], names[0], LLMute::AGENT); + LLMuteList::getInstance()->add(mute); + showPanelAndSelect(mute.mID); +} + +//static +void LLPanelBlockedList::callbackBlockByName(const std::string& text) +{ + if (text.empty()) return; + + LLMute mute(LLUUID::null, text, LLMute::BY_NAME); + BOOL success = LLMuteList::getInstance()->add(mute); + if (!success) + { + LLNotifications::instance().add("MuteByNameFailed"); + } +} + +////////////////////////////////////////////////////////////////////////// +// LLFloaterGetBlockedObjectName +////////////////////////////////////////////////////////////////////////// + +// Constructor/Destructor +LLFloaterGetBlockedObjectName::LLFloaterGetBlockedObjectName(const LLSD& key) +: LLFloater(key) +, mGetObjectNameCallback(NULL) +{ +} + +// Destroys the object +LLFloaterGetBlockedObjectName::~LLFloaterGetBlockedObjectName() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +BOOL LLFloaterGetBlockedObjectName::postBuild() +{ + getChild("OK")-> setCommitCallback(boost::bind(&LLFloaterGetBlockedObjectName::applyBlocking, this)); + getChild("Cancel")-> setCommitCallback(boost::bind(&LLFloaterGetBlockedObjectName::cancelBlocking, this)); + center(); + + return LLFloater::postBuild(); +} + +BOOL LLFloaterGetBlockedObjectName::handleKeyHere(KEY key, MASK mask) +{ + if (key == KEY_RETURN && mask == MASK_NONE) + { + applyBlocking(); + return TRUE; + } + else if (key == KEY_ESCAPE && mask == MASK_NONE) + { + cancelBlocking(); + return TRUE; + } + + return LLFloater::handleKeyHere(key, mask); +} + +// static +LLFloaterGetBlockedObjectName* LLFloaterGetBlockedObjectName::show(get_object_name_callback_t callback) +{ + LLFloaterGetBlockedObjectName* floater = LLFloaterReg::showTypedInstance("mute_object_by_name"); + + floater->mGetObjectNameCallback = callback; + + // *TODO: mantipov: should LLFloaterGetBlockedObjectName be closed when panel is closed? + // old Floater dependency is not enable in panel + // addDependentFloater(floater); + + return floater; +} + +////////////////////////////////////////////////////////////////////////// +// Private Section +void LLFloaterGetBlockedObjectName::applyBlocking() +{ + if (mGetObjectNameCallback) + { + const std::string& text = childGetValue("object_name").asString(); + mGetObjectNameCallback(text); + } + closeFloater(); +} + +void LLFloaterGetBlockedObjectName::cancelBlocking() +{ + closeFloater(); +} + +//EOF diff --git a/indra/newview/llpanelblockedlist.h b/indra/newview/llpanelblockedlist.h new file mode 100644 index 0000000000..52b74a184b --- /dev/null +++ b/indra/newview/llpanelblockedlist.h @@ -0,0 +1,115 @@ +/** + * @file llpanelblockedlist.h + * @brief Container for blocked Residents & Objects list + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELBLOCKEDLIST_H +#define LL_LLPANELBLOCKEDLIST_H + +#include "llpanel.h" +#include "llmutelist.h" +// #include + +// class LLButton; +// class LLLineEditor; +// class LLMessageSystem; +// class LLUUID; + class LLScrollListCtrl; + +class LLPanelBlockedList + : public LLPanel, public LLMuteListObserver +{ +public: + LLPanelBlockedList(); + ~LLPanelBlockedList(); + + virtual BOOL postBuild(); + virtual void draw(); + virtual void onOpen(const LLSD& key); + + void selectBlocked(const LLUUID& id); + + /** + * Shows current Panel in side tray and select passed blocked item. + * + * @param idToSelect - LLUUID of blocked Resident or Object to be selected. + * 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(); + void updateButtons(); + + // UI callbacks + void onBackBtnClick(); + void onRemoveBtnClick(); + void onPickBtnClick(); + void onBlockByNameClick(); + + static void callbackBlockPicked(const std::vector& names, const std::vector& ids, void* user_data); + static void callbackBlockByName(const std::string& text); + +private: + LLScrollListCtrl* mBlockedList; +}; + +//----------------------------------------------------------------------------- +// LLFloaterGetBlockedObjectName() +//----------------------------------------------------------------------------- +// Class for handling mute object by name floater. +class LLFloaterGetBlockedObjectName : public LLFloater +{ + friend class LLFloaterReg; +public: + typedef boost::function get_object_name_callback_t; + + virtual BOOL postBuild(); + + virtual BOOL handleKeyHere(KEY key, MASK mask); + + static LLFloaterGetBlockedObjectName* show(get_object_name_callback_t callback); + +private: + LLFloaterGetBlockedObjectName(const LLSD& key); + virtual ~LLFloaterGetBlockedObjectName(); + + // UI Callbacks + void applyBlocking(); + void cancelBlocking(); + + get_object_name_callback_t mGetObjectNameCallback; +}; + + +#endif // LL_LLPANELBLOCKEDLIST_H diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 34d5ef8f86..42aa21c13e 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -43,12 +43,12 @@ // newview #include "llagent.h" +#include "llavataractions.h" #include "llavatarlist.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llfloateravatarpicker.h" //#include "llfloaterminiinspector.h" #include "llfriendcard.h" -#include "llavataractions.h" #include "llgroupactions.h" #include "llgrouplist.h" #include "llrecentpeople.h" @@ -976,7 +976,6 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata) } } - void LLPanelPeople::onCallButtonClicked() { // *TODO: not implemented yet diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index bd6ca4746c..c34038c672 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -54,6 +54,11 @@ static const std::string XML_BTN_INFO = "info_btn"; static const std::string XML_BTN_TELEPORT = "teleport_btn"; static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn"; +static const std::string PICK_ID("pick_id"); +static const std::string PICK_CREATOR_ID("pick_creator_id"); +static const std::string PICK_NAME("pick_name"); + + static LLRegisterPanelClassWrapper t_panel_picks("panel_picks"); //----------------------------------------------------------------------------- @@ -97,19 +102,8 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) gCacheName->getName(getAvatarId(),name,second_name); childSetTextArg("pick_title", "[NAME]",name); - // to restore selection of the same item later - LLUUID pick_id_selected(LLUUID::null); - if (getSelectedPickItem()) pick_id_selected = getSelectedPickItem()->getPickId(); - mPicksList->clear(); - //*TODO move it somewhere else? - childSetEnabled(XML_BTN_NEW, false); - childSetEnabled(XML_BTN_DELETE, false); - childSetEnabled(XML_BTN_INFO, false); - childSetEnabled(XML_BTN_TELEPORT,!avatar_picks->picks_list.empty()); - childSetEnabled(XML_BTN_SHOW_ON_MAP,!avatar_picks->picks_list.empty()); - LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); for(; avatar_picks->picks_list.end() != it; ++it) { @@ -124,12 +118,18 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) LLAvatarPropertiesProcessor::instance().addObserver(getAvatarId(), picture); picture->update(); - mPicksList->addItem(picture); - if (pick_id_selected != LLUUID::null && - pick_id == pick_id_selected) mPicksList->toggleSelection(picture); + + LLSD pick_value = LLSD(); + pick_value.insert(PICK_ID, pick_id); + pick_value.insert(PICK_NAME, pick_name); + pick_value.insert(PICK_CREATOR_ID, getAvatarId()); + + mPicksList->addItem(picture, pick_value); picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickItem, this, _1)); picture->setRightMouseDownCallback(boost::bind(&LLPanelPicks::onRightMouseDownItem, this, _1, _2, _3, _4)); + picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); + picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); } LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); @@ -140,10 +140,10 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) LLPickItem* LLPanelPicks::getSelectedPickItem() { - std::list selected_items = mPicksList->getSelectedItems(); + LLPanel* selected_item = mPicksList->getSelectedItem(); + if (!selected_item) return NULL; - if (selected_items.empty()) return NULL; - return dynamic_cast(selected_items.front()); + return dynamic_cast(selected_item); } BOOL LLPanelPicks::postBuild() @@ -193,6 +193,10 @@ void LLPanelPicks::onOpen(const LLSD& key) { childSetVisible("pick_title", !self); childSetVisible("pick_title_agent", self); + + mPopupMenu->setItemVisible("pick_delete", TRUE); + mPopupMenu->setItemVisible("pick_edit", TRUE); + mPopupMenu->setItemVisible("pick_separator", TRUE); } LLPanelProfileTab::onOpen(key); @@ -201,11 +205,11 @@ void LLPanelPicks::onOpen(const LLSD& key) //static void LLPanelPicks::onClickDelete() { - LLPickItem* pick_item = getSelectedPickItem(); - if (!pick_item) return; + LLSD pick_value = mPicksList->getSelectedValue(); + if (pick_value.isUndefined()) return; LLSD args; - args["PICK"] = pick_item->getPickName(); + args["PICK"] = pick_value[PICK_NAME]; LLNotifications::instance().add("DeleteAvatarPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackDelete, this, _1, _2)); } @@ -213,12 +217,12 @@ bool LLPanelPicks::callbackDelete(const LLSD& notification, const LLSD& response { S32 option = LLNotification::getSelectedOption(notification, response); - LLPickItem* pick_item = getSelectedPickItem(); + LLSD pick_value = mPicksList->getSelectedValue(); if (0 == option) { - LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_item->getPickId()); - mPicksList->removeItem(pick_item); + LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]); + mPicksList->removeItemByValue(pick_value); } updateButtons(); return false; @@ -265,32 +269,30 @@ void LLPanelPicks::onRightMouseDownItem(LLUICtrl* item, S32 x, S32 y, MASK mask) void LLPanelPicks::onDoubleClickItem(LLUICtrl* item) { - LLPickItem* pick_item = dynamic_cast(item); - if (!pick_item) return; + LLSD pick_value = mPicksList->getSelectedValue(); + if (pick_value.isUndefined()) return; + LLSD args; - args["PICK"] = pick_item->getPickName(); + args["PICK"] = pick_value[PICK_NAME]; LLNotifications::instance().add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); } void LLPanelPicks::updateButtons() { int picks_num = mPicksList->size(); - childSetEnabled(XML_BTN_INFO, picks_num > 0); + bool has_selected = mPicksList->numSelected(); + + childSetEnabled(XML_BTN_INFO, has_selected); if (getAvatarId() == gAgentID) { childSetEnabled(XML_BTN_NEW, picks_num < MAX_AVATAR_PICKS); - childSetEnabled(XML_BTN_DELETE, picks_num > 0); - - //*TODO move somewhere this calls - // we'd better set them up earlier when a panel was being constructed - mPopupMenu->setItemVisible("pick_delete", TRUE); - mPopupMenu->setItemVisible("pick_edit", TRUE); - mPopupMenu->setItemVisible("pick_separator", TRUE); + childSetEnabled(XML_BTN_DELETE, has_selected); } - //*TODO update buttons like Show on Map, Teleport etc. - + childSetEnabled(XML_BTN_INFO, has_selected); + childSetEnabled(XML_BTN_TELEPORT, has_selected); + childSetEnabled(XML_BTN_SHOW_ON_MAP, has_selected); } void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) @@ -318,12 +320,12 @@ void LLPanelPicks::onClickNew() void LLPanelPicks::onClickInfo() { - LLPickItem* pick = getSelectedPickItem(); - if (!pick) return; + LLSD selected_value = mPicksList->getSelectedValue(); + if (selected_value.isUndefined()) return; buildPickPanel(); mPickPanel->reset(); - mPickPanel->init(pick->getCreatorId(), pick->getPickId()); + mPickPanel->init(selected_value[PICK_CREATOR_ID], selected_value[PICK_ID]); getProfilePanel()->togglePanel(mPickPanel); } @@ -335,12 +337,12 @@ void LLPanelPicks::onClickBack() void LLPanelPicks::onClickMenuEdit() { //*TODO, refactor - most of that is similar to onClickInfo - LLPickItem* pick = getSelectedPickItem(); - if (!pick) return; + LLSD selected_value = mPicksList->getSelectedValue(); + if (selected_value.isUndefined()) return; buildPickPanel(); mPickPanel->reset(); - mPickPanel->init(pick->getCreatorId(), pick->getPickId()); + mPickPanel->init(selected_value[PICK_CREATOR_ID], selected_value[PICK_ID]); mPickPanel->setEditMode(TRUE); getProfilePanel()->togglePanel(mPickPanel); } @@ -470,3 +472,17 @@ void LLPanelPicks::onClose() getProfilePanel()->togglePanel(mPickPanel); } } + +BOOL LLPickItem::postBuild() +{ + setMouseEnterCallback(boost::bind(&LLPanelPick::childSetVisible, this, "hovered_icon", true)); + setMouseLeaveCallback(boost::bind(&LLPanelPick::childSetVisible, this, "hovered_icon", false)); + return TRUE; +} + +void LLPickItem::setValue(const LLSD& value) +{ + if (!value.isMap()) return;; + if (!value.has("selected")) return; + childSetVisible("selected_icon", value["selected"]); +} diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index 5860354902..97e8e607c8 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -152,6 +152,11 @@ public: ~LLPickItem(); + /*virtual*/ BOOL postBuild(); + + /** setting on/off background icon to indicate selected state */ + /*virtual*/ void setValue(const LLSD& value); + protected: LLUUID mPickID; diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index 73e09a36f9..ec1c10d8c9 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -49,6 +49,7 @@ #include "lltextbox.h" #include "llaccordionctrl.h" +#include "llaccordionctrltab.h" #include "llagent.h" #include "llavatarpropertiesprocessor.h" #include "llfloaterworldmap.h" @@ -81,6 +82,8 @@ LLPanelPlaceInfo::~LLPanelPlaceInfo() { LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelID, this); } + + LLViewerParcelMgr::getInstance()->removeObserver(this); } BOOL LLPanelPlaceInfo::postBuild() @@ -98,26 +101,16 @@ BOOL LLPanelPlaceInfo::postBuild() mParcelName = getChild("parcel_title"); mDescEditor = getChild("description"); - mMaturityRatingIcon = getChild("maturity"); mMaturityRatingText = getChild("maturity_value"); - mParcelOwner = getChild("owner_value"); - mLastVisited = getChild("last_visited_value"); - mRatingIcon = getChild("rating_icon"); mRatingText = getChild("rating_value"); - mVoiceIcon = getChild("voice_icon"); mVoiceText = getChild("voice_value"); - mFlyIcon = getChild("fly_icon"); mFlyText = getChild("fly_value"); - mPushIcon = getChild("push_icon"); mPushText = getChild("push_value"); - mBuildIcon = getChild("build_icon"); mBuildText = getChild("build_value"); - mScriptsIcon = getChild("scripts_icon"); mScriptsText = getChild("scripts_value"); - mDamageIcon = getChild("damage_icon"); mDamageText = getChild("damage_value"); mRegionNameText = getChild("region_name"); @@ -131,6 +124,16 @@ BOOL LLPanelPlaceInfo::postBuild() mEstateOwnerText = getChild("estate_owner"); mCovenantText = getChild("covenant"); + mSalesPriceText = getChild("sales_price"); + mAreaText = getChild("area"); + mTrafficText = getChild("traffic"); + mPrimitivesText = getChild("primitives"); + mParcelScriptsText = getChild("parcel_scripts"); + mTerraformLimitsText = getChild("terraform_limits"); + mSubdivideText = getChild("subdivide"); + mResaleText = getChild("resale"); + mSaleToText = getChild("sale_to"); + mOwner = getChild("owner"); mCreator = getChild("creator"); mCreated = getChild("created"); @@ -253,7 +256,6 @@ void LLPanelPlaceInfo::resetLocation() mLandmarkID.setNull(); mPosRegion.clearVec(); std::string not_available = getString("not_available"); - mMaturityRatingIcon->setValue(not_available); mMaturityRatingText->setValue(not_available); mParcelOwner->setValue(not_available); mLastVisited->setValue(not_available); @@ -268,19 +270,12 @@ void LLPanelPlaceInfo::resetLocation() mSnapshotCtrl->setImageAssetID(LLUUID::null); mSnapshotCtrl->setFallbackImageName("default_land_picture.j2c"); - mRatingIcon->setValue(not_available); mRatingText->setText(not_available); - mVoiceIcon->setValue(not_available); mVoiceText->setText(not_available); - mFlyIcon->setValue(not_available); mFlyText->setText(not_available); - mPushIcon->setValue(not_available); mPushText->setText(not_available); - mBuildIcon->setValue(not_available); mBuildText->setText(not_available); - mScriptsIcon->setValue(not_available); - mScriptsText->setText(not_available); - mDamageIcon->setValue(not_available); + mParcelScriptsText->setText(not_available); mDamageText->setText(not_available); mRegionNameText->setValue(not_available); @@ -293,6 +288,16 @@ void LLPanelPlaceInfo::resetLocation() mEstateRatingText->setValue(not_available); mEstateOwnerText->setValue(not_available); mCovenantText->setValue(not_available); + + mSalesPriceText->setValue(not_available); + mAreaText->setValue(not_available); + mTrafficText->setValue(not_available); + mPrimitivesText->setValue(not_available); + mParcelScriptsText->setValue(not_available); + mTerraformLimitsText->setValue(not_available); + mSubdivideText->setValue(not_available); + mResaleText->setValue(not_available); + mSaleToText->setValue(not_available); } //virtual @@ -312,7 +317,6 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) bool is_info_type_teleport_history = type == TELEPORT_HISTORY; getChild("maturity_label")->setVisible(!is_info_type_agent); - mMaturityRatingIcon->setVisible(!is_info_type_agent); mMaturityRatingText->setVisible(!is_info_type_agent); getChild("owner_label")->setVisible(is_info_type_agent); @@ -326,6 +330,8 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) getChild("advanced_info_accordion")->setVisible(is_info_type_agent); + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); + switch(type) { case CREATE_LANDMARK: @@ -333,6 +339,15 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) break; case AGENT: + if (parcel_mgr) + { + // If information is requested for current agent location + // start using LLViewerParcelMgr for land selection. + parcel_mgr->addObserver(this); + parcel_mgr->selectParcelAt(gAgent.getPositionGlobal()); + } + + // Fall through to PLACE case case PLACE: mCurrentTitle = getString("title_place"); @@ -348,14 +363,22 @@ void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) case TELEPORT_HISTORY: mCurrentTitle = getString("title_teleport_history"); - - // *TODO: Add last visited timestamp. - mLastVisited->setText(getString("unknown")); break; } + if (type != AGENT && parcel_mgr != NULL) + { + if (!parcel_mgr->selectionEmpty()) + { + parcel_mgr->deselectUnused(); + } + parcel_mgr->removeObserver(this); + } + if (type != PLACE) toggleMediaPanel(FALSE); + + mInfoType = type; } BOOL LLPanelPlaceInfo::isMediaPanelVisible() @@ -432,22 +455,16 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) // HACK: Flag 0x2 == adult region, // Flag 0x1 == mature region, otherwise assume PG std::string rating = LLViewerRegion::accessToString(SIM_ACCESS_PG); - std::string rating_icon = "places_rating_pg.tga"; if (parcel_data.flags & 0x2) { rating = LLViewerRegion::accessToString(SIM_ACCESS_ADULT); - rating_icon = "places_rating_adult.tga"; } else if (parcel_data.flags & 0x1) { rating = LLViewerRegion::accessToString(SIM_ACCESS_MATURE); - rating_icon = "places_rating_mature.tga"; } - mMaturityRatingIcon->setValue(rating_icon); mMaturityRatingText->setValue(rating); - - mRatingIcon->setValue(rating_icon); mRatingText->setValue(rating); //update for_sale banner, here we should use DFQ_FOR_SALE instead of PF_FOR_SALE @@ -476,7 +493,7 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) mRegionName->setText(name); } - if (mCurrentTitle != getString("title_landmark")) + if (mInfoType == CREATE_LANDMARK) { mTitleEditor->setText(parcel_data.name); mNotesEditor->setText(LLStringUtil::null); @@ -517,10 +534,10 @@ void LLPanelPlaceInfo::displayParcelInfo(const LLVector3& pos_region, void LLPanelPlaceInfo::displayAgentParcelInfo() { - mPosRegion = gAgent.getPositionAgent(); + mParcel = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection(); - LLViewerRegion* region = gAgent.getRegion(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + LLParcel* parcel = mParcel->getParcel(); + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if (!region || !parcel) return; @@ -547,13 +564,6 @@ void LLPanelPlaceInfo::displayAgentParcelInfo() default: parcel_data.flags = 0; } - - // Adding "For Sale" flag in remote parcel response format. - if (parcel->getForSale()) - { - parcel_data.flags |= DFQ_FOR_SALE; - } - parcel_data.desc = parcel->getDesc(); parcel_data.name = parcel->getName(); parcel_data.sim_name = gAgent.getRegion()->getName(); @@ -563,75 +573,68 @@ void LLPanelPlaceInfo::displayAgentParcelInfo() parcel_data.global_y = global_pos.mdV[1]; parcel_data.global_z = global_pos.mdV[2]; + mPosRegion = gAgent.getPositionAgent(); + processParcelInfo(parcel_data); + std::string on = getString("on"); + std::string off = getString("off"); + // Processing parcel characteristics if (parcel->getParcelFlagAllowVoice()) { - mVoiceIcon->setValue("places_voice_on.tga"); - mVoiceText->setText(getString("on")); + mVoiceText->setText(on); } else { - mVoiceIcon->setValue("places_voice_off.tga"); - mVoiceText->setText(getString("off")); + mVoiceText->setText(off); } if (!region->getBlockFly() && parcel->getAllowFly()) { - mFlyIcon->setValue("places_fly_on.tga"); - mFlyText->setText(getString("on")); + mFlyText->setText(on); } else { - mFlyIcon->setValue("places_fly_off.tga"); - mFlyText->setText(getString("off")); + mFlyText->setText(off); } if (region->getRestrictPushObject() || parcel->getRestrictPushObject()) { - mPushIcon->setValue("places_push_off.tga"); - mPushText->setText(getString("off")); + mPushText->setText(off); } else { - mPushIcon->setValue("places_push_on.tga"); - mPushText->setText(getString("on")); + mPushText->setText(on); } if (parcel->getAllowModify()) { - mBuildIcon->setValue("places_build_on.tga"); - mBuildText->setText(getString("on")); + mBuildText->setText(on); } else { - mBuildIcon->setValue("places_build_off.tga"); - mBuildText->setText(getString("off")); + mBuildText->setText(off); } if((region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS) || (region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS) || !parcel->getAllowOtherScripts()) { - mScriptsIcon->setValue("places_scripts_off.tga"); - mScriptsText->setText(getString("off")); + mScriptsText->setText(off); } else { - mScriptsIcon->setValue("places_scripts_on.tga"); - mScriptsText->setText(getString("on")); + mScriptsText->setText(on); } if (region->getAllowDamage() || parcel->getAllowDamage()) { - mDamageIcon->setValue("places_damage_on.tga"); - mDamageText->setText(getString("on")); + mDamageText->setText(on); } else { - mDamageIcon->setValue("places_damage_off.tga"); - mDamageText->setText(getString("off")); + mDamageText->setText(off); } mRegionNameText->setText(region->getName()); @@ -656,7 +659,8 @@ void LLPanelPlaceInfo::displayAgentParcelInfo() gCacheName->get(parcel->getGroupID(), TRUE, boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mRegionGroupText, _2, _3)); - mParcelOwner->setText(mRegionGroupText->getText()); + gCacheName->get(parcel->getGroupID(), TRUE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mParcelOwner, _2, _3)); } else { @@ -681,6 +685,98 @@ void LLPanelPlaceInfo::displayAgentParcelInfo() } mEstateRatingText->setText(region->getSimAccessString()); + + S32 area; + S32 claim_price; + S32 rent_price; + F32 dwell; + BOOL for_sale = parcel->getForSale(); + LLViewerParcelMgr::getInstance()->getDisplayInfo(&area, + &claim_price, + &rent_price, + &for_sale, + &dwell); + + if (for_sale) + { + // Adding "For Sale" flag in remote parcel response format. + parcel_data.flags |= DFQ_FOR_SALE; + + const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID(); + if(auth_buyer_id.notNull()) + { + gCacheName->get(auth_buyer_id, TRUE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mSaleToText, _2, _3)); + + // Show sales info to a specific person or a group he belongs to. + if (auth_buyer_id != gAgent.getID() && !gAgent.isInGroup(auth_buyer_id)) + { + for_sale = FALSE; + } + } + else + { + mSaleToText->setText(getString("anyone")); + } + + const U8* sign = (U8*)getString("price_text").c_str(); + const U8* sqm = (U8*)getString("area_text").c_str(); + + mSalesPriceText->setText(llformat("%s%d ", sign, parcel->getSalePrice())); + mAreaText->setText(llformat("%d %s", area, sqm)); + mTrafficText->setText(llformat("%.0f", dwell)); + + // Can't have more than region max tasks, regardless of parcel + // object bonus factor. + S32 primitives = llmin(llround(parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus()), + (S32)region->getMaxTasks()); + + const U8* available = (U8*)getString("available").c_str(); + const U8* allocated = (U8*)getString("allocated").c_str(); + + mPrimitivesText->setText(llformat("%d %s, %d %s", primitives, available, parcel->getPrimCount(), allocated)); + + if (parcel->getAllowOtherScripts()) + { + mParcelScriptsText->setText(getString("all_residents_text")); + } + else if (parcel->getAllowGroupScripts()) + { + mParcelScriptsText->setText(getString("group_text")); + } + else + { + mParcelScriptsText->setText(off); + } + + mTerraformLimitsText->setText(parcel->getAllowTerraform() ? on : off); + + if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES) + { + mSubdivideText->setText(getString("can_change")); + } + else + { + mSubdivideText->setText(getString("can_not_change")); + } + if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL) + { + mResaleText->setText(getString("can_not_resell")); + } + else + { + mResaleText->setText(getString("can_resell")); + } + } + + getChild("sales_tab")->setVisible(for_sale); +} + +// virtual +void LLPanelPlaceInfo::changed() +{ + resetLocation(); + displayAgentParcelInfo(); } void LLPanelPlaceInfo::updateEstateName(const std::string& name) @@ -698,6 +794,22 @@ void LLPanelPlaceInfo::updateCovenantText(const std::string &text) mCovenantText->setText(text); } +void LLPanelPlaceInfo::updateLastVisitedText(const LLDate &date) +{ + if (date.isNull()) + { + mLastVisited->setText(getString("unknown")); + } + else + { + std::string timeStr = getString("acquired_date"); + LLSD substitution; + substitution["datetime"] = (S32) date.secondsSinceEpoch(); + LLStringUtil::format (timeStr, substitution); + mLastVisited->setText(timeStr); + } +} + void LLPanelPlaceInfo::onCommitTitleOrNote(LANDMARK_INFO_TYPE type) { LLInventoryItem* item = gInventory.getItem(mLandmarkID); @@ -785,6 +897,7 @@ void LLPanelPlaceInfo::createPick(const LLVector3d& global_pos) LLAvatarPropertiesProcessor::instance().sendDataUpdate(&pick_data, APT_PICK_INFO); } +// virtual void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) { if (mMinHeight > 0 && mScrollingPanel != NULL) @@ -794,3 +907,22 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) LLView::reshape(width, height, called_from_parent); } + +// virtual +void LLPanelPlaceInfo::handleVisibilityChange (BOOL new_visibility) +{ + LLPanel::handleVisibilityChange(new_visibility); + + LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance(); + if (!parcel_mgr) + return; + + // Remove land selection when panel hides. + if (!new_visibility) + { + if (!parcel_mgr->selectionEmpty()) + { + parcel_mgr->deselectLand(); + } + } +} diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 0cdeaab2b7..60f35cd0c1 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -42,15 +42,17 @@ #include "llpanelmedia.h" #include "llremoteparcelrequest.h" +#include "llviewerparcelmgr.h" class LLButton; class LLInventoryItem; class LLLineEditor; +class LLParcelSelection; class LLTextBox; class LLTextEditor; class LLTextureCtrl; -class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver +class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver, LLParcelObserver { public: enum INFO_TYPE @@ -105,9 +107,13 @@ public: // without sending a request to the server. void displayAgentParcelInfo(); + // Called on parcel selection change by LLViewerParcelMgr. + /*virtual*/ void changed(); + void updateEstateName(const std::string& name); void updateEstateOwnerName(const std::string& name); void updateCovenantText(const std::string &text); + void updateLastVisitedText(const LLDate &date); void nameUpdatedCallback(LLTextBox* text, const std::string& first, @@ -115,6 +121,7 @@ public: /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void handleVisibilityChange (BOOL new_visibility); private: enum LANDMARK_INFO_TYPE @@ -131,30 +138,23 @@ private: LLVector3 mPosRegion; std::string mCurrentTitle; S32 mMinHeight; + INFO_TYPE mInfoType; LLTextBox* mTitle; LLTextureCtrl* mSnapshotCtrl; LLTextBox* mRegionName; LLTextBox* mParcelName; LLTextEditor* mDescEditor; - LLIconCtrl* mMaturityRatingIcon; LLTextBox* mMaturityRatingText; LLTextBox* mParcelOwner; LLTextBox* mLastVisited; - LLIconCtrl* mRatingIcon; LLTextBox* mRatingText; - LLIconCtrl* mVoiceIcon; LLTextBox* mVoiceText; - LLIconCtrl* mFlyIcon; LLTextBox* mFlyText; - LLIconCtrl* mPushIcon; LLTextBox* mPushText; - LLIconCtrl* mBuildIcon; LLTextBox* mBuildText; - LLIconCtrl* mScriptsIcon; LLTextBox* mScriptsText; - LLIconCtrl* mDamageIcon; LLTextBox* mDamageText; LLTextBox* mRegionNameText; @@ -168,6 +168,16 @@ private: LLTextBox* mEstateOwnerText; LLTextEditor* mCovenantText; + LLTextBox* mSalesPriceText; + LLTextBox* mAreaText; + LLTextBox* mTrafficText; + LLTextBox* mPrimitivesText; + LLTextBox* mParcelScriptsText; + LLTextBox* mTerraformLimitsText; + LLTextEditor* mSubdivideText; + LLTextEditor* mResaleText; + LLTextBox* mSaleToText; + LLTextBox* mOwner; LLTextBox* mCreator; LLTextBox* mCreated; @@ -176,6 +186,8 @@ private: LLPanel* mScrollingPanel; LLPanel* mInfoPanel; LLMediaPanel* mMediaPanel; + + LLSafeHandle mParcel; }; #endif // LL_LLPANELPLACEINFO_H diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 2aebfdabfa..bc740bd865 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -51,6 +51,7 @@ #include "llpanellandmarks.h" #include "llpanelteleporthistory.h" #include "llsidetray.h" +#include "llteleporthistorystorage.h" #include "lltoggleablemenu.h" #include "llviewerinventory.h" #include "llviewermenu.h" @@ -172,8 +173,7 @@ void LLPanelPlaces::onOpen(const LLSD& key) if (mPlaceInfoType == AGENT_INFO_TYPE) { mPlaceInfo->setInfoType(LLPanelPlaceInfo::AGENT); - mPlaceInfo->displayAgentParcelInfo(); - + mPosGlobal = gAgent.getPositionGlobal(); } else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) @@ -212,14 +212,15 @@ void LLPanelPlaces::onOpen(const LLSD& key) { S32 index = key["id"].asInteger(); - const LLTeleportHistory::slurl_list_t& hist_items = - LLTeleportHistory::getInstance()->getItems(); + const LLTeleportHistoryStorage::slurl_list_t& hist_items = + LLTeleportHistoryStorage::getInstance()->getItems(); mPosGlobal = hist_items[index].mGlobalPos; mPlaceInfo->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY); + mPlaceInfo->updateLastVisitedText(hist_items[index].mDate); mPlaceInfo->displayParcelInfo(get_pos_local_from_global(mPosGlobal), - hist_items[index].mRegionID, + LLUUID(), mPosGlobal); } } diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 8b378c33e3..df48ee5d08 100644 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -37,6 +37,7 @@ #include "llpanelteleporthistory.h" #include "llsidetray.h" #include "llworldmap.h" +#include "llteleporthistorystorage.h" // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper t_teleport_history("panel_teleport_history"); @@ -56,7 +57,7 @@ LLTeleportHistoryPanel::~LLTeleportHistoryPanel() BOOL LLTeleportHistoryPanel::postBuild() { - mTeleportHistory = LLTeleportHistory::getInstance(); + mTeleportHistory = LLTeleportHistoryStorage::getInstance(); if (mTeleportHistory) { mTeleportHistory->setHistoryChangedCallback(boost::bind(&LLTeleportHistoryPanel::showTeleportHistory, this)); @@ -92,9 +93,7 @@ void LLTeleportHistoryPanel::onShowOnMap() S32 index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); - const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); - - LLVector3d global_pos = hist_items[index].mGlobalPos; + LLVector3d global_pos = mTeleportHistory->getItems()[index].mGlobalPos; if (!global_pos.isExactlyZero()) { @@ -153,7 +152,7 @@ void LLTeleportHistoryPanel::updateVerbs() if (itemp) { index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); - cur_item = mTeleportHistory->getCurrentItemIndex(); + cur_item = mTeleportHistory->getItems().size() - 1; } mTeleportBtn->setEnabled(index != cur_item); @@ -162,13 +161,11 @@ void LLTeleportHistoryPanel::updateVerbs() void LLTeleportHistoryPanel::showTeleportHistory() { - const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); + const LLTeleportHistoryStorage::slurl_list_t& hist_items = mTeleportHistory->getItems(); mHistoryItems->deleteAllItems(); - S32 cur_item = mTeleportHistory->getCurrentItemIndex(); - - for (LLTeleportHistory::slurl_list_t::const_iterator iter = hist_items.begin(); + for (LLTeleportHistoryStorage::slurl_list_t::const_iterator iter = hist_items.begin(); iter != hist_items.end(); ++iter) { std::string landmark_title = (*iter).mTitle; @@ -181,7 +178,6 @@ void LLTeleportHistoryPanel::showTeleportHistory() continue; S32 index = iter - hist_items.begin(); - LLSD row; row["id"] = index; @@ -201,14 +197,12 @@ void LLTeleportHistoryPanel::showTeleportHistory() index_column["value"] = index; mHistoryItems->addElement(row, ADD_TOP); - - if (cur_item == index) - { - LLScrollListItem* itemp = mHistoryItems->getItem(index); - ((LLScrollListText*)itemp->getColumn(LIST_ITEM_TITLE))->setFontStyle(LLFontGL::BOLD); - } } + // Consider last item (most recent) as current + LLScrollListItem* itemp = mHistoryItems->getItem((S32)hist_items.size() - 1); + ((LLScrollListText*)itemp->getColumn(LIST_ITEM_TITLE))->setFontStyle(LLFontGL::BOLD); + updateVerbs(); } diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h index 553385b37e..023b04c3fa 100644 --- a/indra/newview/llpanelteleporthistory.h +++ b/indra/newview/llpanelteleporthistory.h @@ -39,6 +39,8 @@ #include "llpanelplacestab.h" #include "llteleporthistory.h" +class LLTeleportHistoryStorage; + class LLTeleportHistoryPanel : public LLPanelPlacesTab { public: @@ -65,7 +67,7 @@ private: LIST_INDEX }; - LLTeleportHistory* mTeleportHistory; + LLTeleportHistoryStorage* mTeleportHistory; LLScrollListCtrl* mHistoryItems; std::string mFilterSubString; }; diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 68996673be..1fbe359295 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -88,9 +88,12 @@ void LLScreenChannel::reshape(S32 width, S32 height, BOOL called_from_parent) //-------------------------------------------------------------------------- void LLScreenChannel::addToast(LLToast::Params p) { - bool store_toast = !mShowToasts && p.can_be_stored && mCanStoreToasts; + bool store_toast = false, show_toast = false; - if(!mShowToasts && !store_toast) + show_toast = mShowToasts || p.force_show; + store_toast = !show_toast && p.can_be_stored && mCanStoreToasts; + + if(!show_toast && !store_toast) { mOnRejectToast(p); return; @@ -106,7 +109,7 @@ void LLScreenChannel::addToast(LLToast::Params p) new_toast_elem.toast->setOnToastHoverCallback(boost::bind(&LLScreenChannel::onToastHover, this, _1, _2)); } - if(mShowToasts) + if(show_toast) { mToastList.push_back(new_toast_elem); showToasts(); diff --git a/indra/newview/llsearchcombobox.cpp b/indra/newview/llsearchcombobox.cpp new file mode 100644 index 0000000000..c903f40f3f --- /dev/null +++ b/indra/newview/llsearchcombobox.cpp @@ -0,0 +1,250 @@ +/** + * @file llsearchcombobox.cpp + * @brief Search Combobox implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsearchcombobox.h" + +#include "llkeyboard.h" +#include "lluictrlfactory.h" + +static LLDefaultChildRegistry::Register r1("search_combo_box"); + +class LLSearchHistoryBuilder +{ +public: + LLSearchHistoryBuilder(LLSearchComboBox* combo_box, const std::string& filter); + + virtual void buildSearchHistory(); + + virtual ~LLSearchHistoryBuilder(){} + +protected: + + virtual bool filterSearchHistory(); + + LLSearchComboBox* mComboBox; + std::string mFilter; + LLSearchHistory::search_history_list_t mFilteredSearchHistory; +}; + +LLSearchComboBox::Params::Params() +: search_button("search_button") +, dropdown_button_visible("dropdown_button_visible", false) +{ +} + +LLSearchComboBox::LLSearchComboBox(const Params&p) +: LLComboBox(p) +{ + S32 btn_top = p.search_button.top_pad + p.search_button.rect.height; + S32 btn_right = p.search_button.rect.width + p.search_button.left_pad; + LLRect search_btn_rect(p.search_button.left_pad, btn_top, btn_right, p.search_button.top_pad); + + LLButton::Params button_params(p.search_button); + button_params.name(std::string("search_btn")); + button_params.rect(search_btn_rect) ; + button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); + button_params.tab_stop(false); + button_params.click_callback.function(boost::bind(&LLSearchComboBox::onSelectionCommit, this)); + mSearchButton = LLUICtrlFactory::create(button_params); + mTextEntry->addChild(mSearchButton); + + setButtonVisible(p.dropdown_button_visible); + mTextEntry->setCommitCallback(boost::bind(&LLComboBox::onTextCommit, this, _2)); + mTextEntry->setKeystrokeCallback(boost::bind(&LLComboBox::onTextEntry, this, _1), NULL); + setSelectionCallback(boost::bind(&LLSearchComboBox::onSelectionCommit, this)); + setPrearrangeCallback(boost::bind(&LLSearchComboBox::onSearchPrearrange, this, _2)); +} + +void LLSearchComboBox::rebuildSearchHistory(const std::string& filter) +{ + LLSearchHistoryBuilder builder(this, filter); + builder.buildSearchHistory(); +} + +void LLSearchComboBox::onSearchPrearrange(const LLSD& data) +{ + std::string filter = data.asString(); + rebuildSearchHistory(filter); + + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. +} + +void LLSearchComboBox::onTextEntry(LLLineEditor* line_editor) +{ + KEY key = gKeyboard->currentKey(); + + if (line_editor->getText().empty()) + { + prearrangeList(); // resets filter + hideList(); + } + // Typing? (moving cursor should not affect showing the list) + else if (key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) + { + prearrangeList(line_editor->getText()); + if (mList->getItemCount() != 0) + { + showList(); + focusTextEntry(); + } + else + { + // Hide the list if it's empty. + hideList(); + } + } + LLComboBox::onTextEntry(line_editor); +} + +void LLSearchComboBox::focusTextEntry() +{ + // We can't use "mTextEntry->setFocus(TRUE)" instead because + // if the "select_on_focus" parameter is true it places the cursor + // at the beginning (after selecting text), thus screwing up updateSelection(). + if (mTextEntry) + { + gFocusMgr.setKeyboardFocus(mTextEntry); + } +} + +void LLSearchComboBox::hideList() +{ + LLComboBox::hideList(); + if (mTextEntry && hasFocus()) + focusTextEntry(); +} + +LLSearchComboBox::~LLSearchComboBox() +{ +} + +void LLSearchComboBox::onSelectionCommit() +{ + std::string search_query = getSimple(); + LLStringUtil::trim(search_query); + if(search_query.empty()) + { + mTextEntry->setText(search_query); + setControlValue(search_query); + + return; + } + + remove(search_query); + add(search_query, ADD_TOP); + mTextEntry->setText(search_query); + setControlValue(search_query); + + LLUICtrl::onCommit(); +} + +BOOL LLSearchComboBox::remove(const std::string& name) +{ + BOOL found = mList->selectItemByLabel(name, FALSE); + + if (found) + { + LLScrollListItem* item = mList->getFirstSelected(); + if (item) + { + LLComboBox::remove(mList->getItemIndex(item)); + } + } + + return found; +} + +void LLSearchComboBox::clearHistory() +{ + removeall(); + setTextEntry(LLStringUtil::null); +} + +LLSearchHistoryBuilder::LLSearchHistoryBuilder(LLSearchComboBox* combo_box, const std::string& filter) +: mComboBox(combo_box) +, mFilter(filter) +{ +} + +bool LLSearchHistoryBuilder::filterSearchHistory() +{ + // *TODO: an STL algorithm would look nicer + mFilteredSearchHistory.clear(); + + std::string filter_copy = mFilter; + LLStringUtil::toLower(filter_copy); + + LLSearchHistory::search_history_list_t history = + LLSearchHistory::getInstance()->getSearchHistoryList(); + + LLSearchHistory::search_history_list_t::const_iterator it = history.begin(); + for ( ; it != history.end(); ++it) + { + std::string search_query = (*it).search_query; + LLStringUtil::toLower(search_query); + + if (search_query.find(filter_copy) != std::string::npos) + mFilteredSearchHistory.push_back(*it); + } + + return mFilteredSearchHistory.size(); +} + +void LLSearchHistoryBuilder::buildSearchHistory() +{ + mFilteredSearchHistory.clear(); + + LLSearchHistory::search_history_list_t filtered_items; + LLSearchHistory::search_history_list_t* itemsp = NULL; + LLSearchHistory* sh = LLSearchHistory::getInstance(); + + if (mFilter.empty()) + { + itemsp = &sh->getSearchHistoryList(); + } + else + { + filterSearchHistory(); + itemsp = &mFilteredSearchHistory; + itemsp->sort(); + } + + mComboBox->removeall(); + + LLSearchHistory::search_history_list_t::const_iterator it = itemsp->begin(); + for ( ; it != itemsp->end(); it++) + { + LLSearchHistory::LLSearchHistoryItem item = *it; + mComboBox->add(item.search_query); + } +} diff --git a/indra/newview/llsearchcombobox.h b/indra/newview/llsearchcombobox.h new file mode 100644 index 0000000000..38f9a5a26b --- /dev/null +++ b/indra/newview/llsearchcombobox.h @@ -0,0 +1,108 @@ +/** + * @file llsearchcombobox.h + * @brief LLSearchComboBox class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSEARCHCOMBOBOX_H +#define LL_LLSEARCHCOMBOBOX_H + +#include "llcombobox.h" +#include "llsearchhistory.h" + +/** + * Search control with text box for search queries and a drop down list + * with recent queries. Supports text auto-complete and filtering of drop down list + * according to typed text. + */ +class LLSearchComboBox : public LLComboBox +{ +public: + + struct Params : public LLInitParam::Block + { + Optional search_button; + Optional dropdown_button_visible; + + Params(); + }; + + /** + * Removes an entry from combo box, case insensitive + */ + BOOL remove(const std::string& name); + + /** + * Clears search history + */ + void clearHistory(); + + ~LLSearchComboBox(); + +protected: + + LLSearchComboBox(const Params&p); + friend class LLUICtrlFactory; + + /** + * Handles typing in text box + */ + void onTextEntry(LLLineEditor* line_editor); + + /** + * Hides drop down list and focuses text box + */ + void hideList(); + + /** + * Rebuilds search history, case insensitive + * If filter is an empty string - whole history will be added to combo box + * if filter is valid string - only matching entries will be added + */ + virtual void rebuildSearchHistory(const std::string& filter); + + /** + * Callback for prearrange event + */ + void onSearchPrearrange(const LLSD& data); + + /** + * Callback for text box or combo box commit + */ + void onSelectionCommit(); + + /** + * Sets focus to text box + */ + void focusTextEntry(); + + LLButton* mSearchButton; +}; + +#endif //LL_LLSEARCHCOMBOBOX_H diff --git a/indra/newview/llsearchhistory.cpp b/indra/newview/llsearchhistory.cpp new file mode 100644 index 0000000000..d45a1efa0e --- /dev/null +++ b/indra/newview/llsearchhistory.cpp @@ -0,0 +1,154 @@ +/** + * @file llsearchhistory.cpp + * @brief Search history container implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsearchhistory.h" + +#include "llfile.h" +#include "llsdserialize.h" +#include "llxmlnode.h" + +std::string LLSearchHistory::SEARCH_QUERY = "search_query"; +std::string LLSearchHistory::SEARCH_HISTORY_FILE_NAME = "search_history.txt"; + +LLSearchHistory::LLSearchHistory() +{ + +} + +bool LLSearchHistory::load() +{ + // build filename for each user + std::string resolved_filename = getHistoryFilePath(); + llifstream file(resolved_filename); + if (!file.is_open()) + { + return false; + } + + clearHistory(); + + // add each line in the file to the list + std::string line; + LLPointer parser = new LLSDNotationParser(); + while (std::getline(file, line)) + { + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + break; + } + + mSearchHistory.push_back(s_item); + } + + file.close(); + + return true; +} + +bool LLSearchHistory::save() +{ + // build filename for each user + std::string resolved_filename = getHistoryFilePath(); + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + return false; + } + + search_history_list_t::const_iterator it = mSearchHistory.begin(); + for (; mSearchHistory.end() != it; ++it) + { + file << LLSDOStreamer((*it).toLLSD()) << std::endl; + } + + file.close(); + return true; +} + +std::string LLSearchHistory::getHistoryFilePath() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SEARCH_HISTORY_FILE_NAME); +} + +void LLSearchHistory::addEntry(const std::string& search_query) +{ + if(search_query.empty()) + { + return; + } + + search_history_list_t::iterator it = + find(mSearchHistory.begin(), mSearchHistory.end(), search_query); + + if(mSearchHistory.end() != it) + { + mSearchHistory.erase(it); + } + + LLSearchHistoryItem item(search_query); + mSearchHistory.push_front(item); +} + +bool LLSearchHistory::LLSearchHistoryItem::operator < (const LLSearchHistory::LLSearchHistoryItem& right) +{ + S32 result = LLStringUtil::compareInsensitive(search_query, right.search_query); + + return result < 0; +} + +bool LLSearchHistory::LLSearchHistoryItem::operator > (const LLSearchHistory::LLSearchHistoryItem& right) +{ + S32 result = LLStringUtil::compareInsensitive(search_query, right.search_query); + + return result > 0; +} + +bool LLSearchHistory::LLSearchHistoryItem::operator==(const LLSearchHistory::LLSearchHistoryItem& right) +{ + return 0 == LLStringUtil::compareInsensitive(search_query, right.search_query); +} + +bool LLSearchHistory::LLSearchHistoryItem::operator==(const std::string& right) +{ + return 0 == LLStringUtil::compareInsensitive(search_query, right); +} + +LLSD LLSearchHistory::LLSearchHistoryItem::toLLSD() const +{ + LLSD ret; + ret[SEARCH_QUERY] = search_query; + return ret; +} diff --git a/indra/newview/llsearchhistory.h b/indra/newview/llsearchhistory.h new file mode 100644 index 0000000000..253ef21e9e --- /dev/null +++ b/indra/newview/llsearchhistory.h @@ -0,0 +1,138 @@ +/** + * @file llsearchhistory.h + * @brief Search history container definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSEARCHHISTORY_H +#define LL_LLSEARCHHISTORY_H + +#include "llsingleton.h" +/** + * Search history container able to save and load history from file. + * History is stored in chronological order, most recent at the beginning. + */ +class LLSearchHistory : public LLSingleton +{ +public: + + // Forward declaration + class LLSearchHistoryItem; + + // Search history container + typedef std::list search_history_list_t; + + /** + * Saves search history to file + */ + bool save(); + + /** + * loads search history from file + */ + bool load(); + + /** + * Returns search history list + */ + search_history_list_t& getSearchHistoryList() { return mSearchHistory; } + + /** + * Deletes all search history queries from list. + */ + void clearHistory() { mSearchHistory.clear(); } + + /** + * Adds unique entry to front of search history list, case insensitive + * If entry is already in list, it will be deleted and added to front. + */ + void addEntry(const std::string& search_text); + + LLSearchHistory(); + + /** + * Class for storing data about single search request. + */ + class LLSearchHistoryItem + { + public: + + LLSearchHistoryItem() + {} + + LLSearchHistoryItem(const std::string& query) + : search_query(query) + {} + + LLSearchHistoryItem(const LLSD& item) + { + if(item.has(SEARCH_QUERY)) + search_query = item[SEARCH_QUERY].asString(); + } + + std::string search_query; + + /** + * Allows std::list sorting + */ + bool operator < (const LLSearchHistory::LLSearchHistoryItem& right); + + /** + * Allows std::list sorting + */ + bool operator > (const LLSearchHistory::LLSearchHistoryItem& right); + + bool operator==(const LLSearchHistoryItem& right); + + bool operator==(const std::string& right); + + /** + * Serializes search history item to LLSD + */ + LLSD toLLSD() const; + }; + +protected: + + /** + * Returns path to search history file. + */ + std::string getHistoryFilePath(); + + static std::string SEARCH_HISTORY_FILE_NAME; + static std::string SEARCH_QUERY; + +private: + + search_history_list_t mSearchHistory; +}; + +class LLSearchComboBox; + +#endif //LL_LLSEARCHHISTORY_H diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp index afa8e5f072..381e63f020 100644 --- a/indra/newview/llsidetray.cpp +++ b/indra/newview/llsidetray.cpp @@ -241,6 +241,13 @@ LLSideTray::LLSideTray(Params& params) ,mMaxBarWidth(params.rect.width) { mCollapsed=params.collapsed; + + + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // register handler function to process data from the xml. + // panel_name should be specified via "parameter" attribute. + commit.add("SideTray.ShowPanel", boost::bind(&LLSideTray::showPanel, this, _2, LLUUID::null)); } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6c0481feaa..8fb0f201cb 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -899,6 +899,10 @@ bool idle_startup() if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) { + // Move the progress view in front of the UI immediately when login is performed + // this allows not to see main menu after Alt+Tab was pressed while login. EXT-744. + gViewerWindow->moveProgressViewToFront(); + //reset the values that could have come in from a slurl if (!gLoginHandler.getWebLoginKey().isNull()) { diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 15d77dbf88..7ddbf0a744 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -38,9 +38,9 @@ #include "llviewercontrol.h" #include "llviewerwindow.h" +#include "llchiclet.h" //--------------------------------------------------------------------------------- -LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLFloater(LLSD()), - mSysWell(NULL), +LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLDockableFloater(NULL, key), mChannel(NULL), mScrollContainer(NULL), mNotificationList(NULL) @@ -57,13 +57,9 @@ BOOL LLSysWellWindow::postBuild() mNotificationList = getChild("notification_list"); mIMRowList = getChild("im_row_panel_list"); - gViewerWindow->setOnBottomTrayWidthChanged(boost::bind(&LLSysWellWindow::adjustWindowPosition, this)); // *TODO: won't be necessary after docking is realized mScrollContainer->setBorderVisible(FALSE); - mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); - - - return TRUE; + return LLDockableFloater::postBuild(); } //--------------------------------------------------------------------------------- @@ -82,7 +78,6 @@ void LLSysWellWindow::addItem(LLSysWellItem::Params p) LLSysWellItem* new_item = new LLSysWellItem(p); mNotificationList->addPanel(dynamic_cast(new_item)); reshapeWindow(); - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); @@ -127,10 +122,6 @@ void LLSysWellWindow::removeItemByID(const LLUUID& id) return; reshapeWindow(); - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized - - // hide chiclet window if there are no items left - setVisible(!isWindowEmpty()); } //--------------------------------------------------------------------------------- @@ -148,11 +139,20 @@ void LLSysWellWindow::onItemClose(LLSysWellItem* item) removeItemByID(id); if(mChannel) mChannel->killToastByNotificationID(id); + + // hide chiclet window if there are no items left + setVisible(!isWindowEmpty()); } //--------------------------------------------------------------------------------- void LLSysWellWindow::toggleWindow() { + if (getDockControl() == NULL) + { + setDockControl(new LLDockControl( + LLBottomTray::getInstance()->getSysWell(), this, + getDockTongue(), LLDockControl::TOP, isDocked())); + } setVisible(!getVisible()); } @@ -162,28 +162,26 @@ void LLSysWellWindow::setVisible(BOOL visible) // on Show adjust position of SysWell chiclet's window if(visible) { + if (LLBottomTray::instanceExists()) + { + LLBottomTray::getInstance()->getSysWell()->setToggleState(TRUE); + } if(mChannel) mChannel->removeAndStoreAllVisibleToasts(); - - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized } - + else + { + if (LLBottomTray::instanceExists()) + { + LLBottomTray::getInstance()->getSysWell()->setToggleState(FALSE); + } + } if(mChannel) mChannel->setShowToasts(!visible); LLFloater::setVisible(visible); } -//--------------------------------------------------------------------------------- -void LLSysWellWindow::adjustWindowPosition() // *TODO: won't be necessary after docking is realized -{ - const S32 WINDOW_MARGIN = 5; - - LLRect btm_rect = LLBottomTray::getInstance()->getRect(); - LLRect this_rect = getRect(); - setOrigin(btm_rect.mRight - this_rect.getWidth() - WINDOW_MARGIN, WINDOW_MARGIN); -} - //--------------------------------------------------------------------------------- void LLSysWellWindow::reshapeWindow() { @@ -272,7 +270,6 @@ void LLSysWellWindow::addIMRow(const LLUUID& sessionId, S32 chicletCounter, { mIMRowList->addPanel(new RowPanel(this, sessionId, chicletCounter, name, otherParticipantId)); - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized } //--------------------------------------------------------------------------------- @@ -286,14 +283,12 @@ void LLSysWellWindow::delIMRow(const LLUUID& sessionId) // hide chiclet window if there are no items left setVisible(!isWindowEmpty()); - - adjustWindowPosition(); // *TODO: won't be necessary after docking is realized } //--------------------------------------------------------------------------------- bool LLSysWellWindow::isWindowEmpty() { - if(mIMRowList->getPanelList().size() == 0 && mNotificationList->getPanelList().size() == 0) + if(mIMRowList->getPanelList().size() == 0 && LLBottomTray::getInstance()->getSysWell()->getCounter() == 0) { return true; } @@ -328,7 +323,7 @@ void LLSysWellWindow::sessionRemoved(const LLUUID& sessionId) { delIMRow(sessionId); reshapeWindow(); - mSysWell->updateUreadIMNotifications(); + LLBottomTray::getInstance()->getSysWell()->updateUreadIMNotifications(); } //--------------------------------------------------------------------------------- @@ -396,5 +391,3 @@ void LLSysWellWindow::RowPanel::updatePanel(BOOL allow_modify) } //--------------------------------------------------------------------------------- - - diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index d9fdf77a04..ef0974b428 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -35,7 +35,7 @@ #include "llsyswellitem.h" -#include "llfloater.h" +#include "lldockablefloater.h" #include "llbutton.h" #include "llscreenchannel.h" #include "llscrollcontainer.h" @@ -46,7 +46,7 @@ -class LLSysWellWindow : public LLFloater, LLIMSessionObserver +class LLSysWellWindow : public LLDockableFloater, LLIMSessionObserver { public: LLSysWellWindow(const LLSD& key); @@ -58,7 +58,6 @@ public: // change attributes void setChannel(LLNotificationsUI::LLScreenChannel* channel) {mChannel = channel;} - void setSysWell(LLNotificationChiclet* sys_well) {mSysWell = sys_well;} // Operating with items void addItem(LLSysWellItem::Params p); @@ -93,9 +92,6 @@ private: // pointer to a corresponding channel's instance LLNotificationsUI::LLScreenChannel* mChannel; - - LLNotificationChiclet* mSysWell; - LLUIImagePtr mDockTongue; LLPanel* mTwinListPanel; LLScrollContainer* mScrollContainer; LLScrollingPanelList* mIMRowList; diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index b31edf1e5d..0bb5a727e0 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -37,8 +37,11 @@ #include "llsd.h" #include "llsdserialize.h" #include "lldir.h" +#include "llteleporthistory.h" +#include "llagent.h" -static LLTeleportHistoryStorage tpstorage; +// Max offset for two global positions to consider them as equal +const F64 MAX_GLOBAL_POS_OFFSET = 5.0f; LLTeleportHistoryPersistentItem::LLTeleportHistoryPersistentItem(const LLSD& val) { @@ -58,15 +61,42 @@ LLSD LLTeleportHistoryPersistentItem::toLLSD() const return val; } +struct LLSortItemsByDate +{ + bool operator()(const LLTeleportHistoryPersistentItem& a, const LLTeleportHistoryPersistentItem& b) + { + return a.mDate < b.mDate; + } +}; + LLTeleportHistoryStorage::LLTeleportHistoryStorage() : mFilename("teleport_history.txt") { + LLTeleportHistory *th = LLTeleportHistory::getInstance(); + if (th) + th->setHistoryChangedCallback(boost::bind(&LLTeleportHistoryStorage::onTeleportHistoryChange, this)); + + load(); } LLTeleportHistoryStorage::~LLTeleportHistoryStorage() { } +void LLTeleportHistoryStorage::onTeleportHistoryChange() +{ + LLTeleportHistory *th = LLTeleportHistory::getInstance(); + if (!th) + return; + + const LLTeleportHistoryItem &item = th->getItems()[th->getCurrentItemIndex()]; + + addItem(item.mTitle, item.mGlobalPos); + save(); + + mHistoryChangedSignal(); +} + void LLTeleportHistoryStorage::purgeItems() { mItems.clear(); @@ -74,12 +104,45 @@ void LLTeleportHistoryStorage::purgeItems() void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos) { - mItems.push_back(LLTeleportHistoryPersistentItem(title, global_pos)); + addItem(title, global_pos, LLDate::now()); +} + + +bool LLTeleportHistoryStorage::compareByTitleAndGlobalPos(const LLTeleportHistoryPersistentItem& a, const LLTeleportHistoryPersistentItem& b) +{ + return a.mTitle == b.mTitle && (a.mGlobalPos - b.mGlobalPos).length() < MAX_GLOBAL_POS_OFFSET; } void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date) { - mItems.push_back(LLTeleportHistoryPersistentItem(title, global_pos, date)); + + LLTeleportHistoryPersistentItem item(title, global_pos, date); + + slurl_list_t::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), + boost::bind(&LLTeleportHistoryStorage::compareByTitleAndGlobalPos, this, _1, item)); + + // If there is such item already, remove it, since new item is more recent + if (item_iter != mItems.end()) + { + mItems.erase(item_iter); + } + + mItems.push_back(item); + + // Check whether sorting is needed + if (mItems.size() > 1) + { + item_iter = mItems.end(); + + item_iter--; + item_iter--; + + // If second to last item is more recent than last, then resort items + if (item_iter->mDate > item.mDate) + { + std::sort(mItems.begin(), mItems.end(), LLSortItemsByDate()); + } + } } void LLTeleportHistoryStorage::removeItem(S32 idx) @@ -145,6 +208,8 @@ void LLTeleportHistoryStorage::load() } file.close(); + + std::sort(mItems.begin(), mItems.end(), LLSortItemsByDate()); } void LLTeleportHistoryStorage::dump() const @@ -162,3 +227,30 @@ void LLTeleportHistoryStorage::dump() const } } +boost::signals2::connection LLTeleportHistoryStorage::setHistoryChangedCallback(history_callback_t cb) +{ + return mHistoryChangedSignal.connect(cb); +} + +void LLTeleportHistoryStorage::goToItem(S32 idx) + +{ + // Validate specified index. + if (idx < 0 || idx >= (S32)mItems.size()) + { + llwarns << "Invalid teleport history index (" << idx << ") specified" << llendl; + dump(); + return; + } + + if (idx == (S32)mItems.size() - 1) + { + llwarns << "Will not teleport to the same location." << llendl; + dump(); + return; + } + + // Attempt to teleport to the requested item. + gAgent.teleportViaLocation(mItems[idx].mGlobalPos); +} + diff --git a/indra/newview/llteleporthistorystorage.h b/indra/newview/llteleporthistorystorage.h index fa836c0326..f67c4e2fb9 100644 --- a/indra/newview/llteleporthistorystorage.h +++ b/indra/newview/llteleporthistorystorage.h @@ -78,7 +78,10 @@ class LLTeleportHistoryStorage: public LLSingleton public: - typedef std::vector item_list_list_t; + typedef std::vector slurl_list_t; + + typedef boost::function history_callback_t; + typedef boost::signals2::signal history_signal_t; LLTeleportHistoryStorage(); ~LLTeleportHistoryStorage(); @@ -86,7 +89,7 @@ public: /** * @return history items. */ - const item_list_list_t& getItems() const { return mItems; } + const slurl_list_t& getItems() const { return mItems; } void purgeItems(); void addItem(const std::string title, const LLVector3d& global_pos); @@ -99,10 +102,34 @@ public: void dump() const; + /** + * Set a callback to be called upon history changes. + * + * Multiple callbacks can be set. + */ + boost::signals2::connection setHistoryChangedCallback(history_callback_t cb); + + /** + * Go to specific item in the history. + * + * The item is specified by its index (starting from 0). + */ + void goToItem(S32 idx); + private: - item_list_list_t mItems; - std::string mFilename; + void onTeleportHistoryChange(); + bool compareByTitleAndGlobalPos(const LLTeleportHistoryPersistentItem& a, const LLTeleportHistoryPersistentItem& b); + + slurl_list_t mItems; + std::string mFilename; + + /** + * Signal emitted when the history gets changed. + * + * Invokes callbacks set with setHistoryChangedCallback(). + */ + history_signal_t mHistoryChangedSignal; }; #endif //LL_LLTELEPORTHISTORYSTORAGE_H diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 969f3fd1cb..05e63a60c5 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -70,12 +70,16 @@ public: bool enable_hide_btn; bool is_modal; bool is_tip; + bool force_show; + bool force_store; Params() : can_fade(true), can_be_stored(true), is_modal(false), is_tip(false), enable_hide_btn(true), + force_show(false), + force_store(false), panel(NULL), timer_period(gSavedSettings.getS32("NotificationToastTime")) diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index 6f26b4077c..6f373a74bd 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -40,7 +40,7 @@ #include "lliconctrl.h" #include "llnotify.h" #include "lltextbox.h" -#include "lltexteditor.h" + #include "lluiconstants.h" #include "llui.h" #include "llviewercontrol.h" @@ -53,6 +53,8 @@ #include "llfloaterinventory.h" #include "llinventorytype.h" +const S32 LLToastGroupNotifyPanel::DEFAULT_MESSAGE_MAX_LINE_COUNT = 4; + LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification) : LLToastPanel(notification), mInventoryOffer(NULL) @@ -65,8 +67,6 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl; } - static const LLUIColor textColor = LLUIColorTable::instance().getColor("GroupNotifyTextColor"); - //group icon LLIconCtrl* pGroupIcon = getChild("group_icon", TRUE); pGroupIcon->setValue(groupData.mInsigniaID); @@ -78,23 +78,16 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLTextBox* pTitleText = getChild("title"); pTitleText->setValue(from.str()); - //message body + //message subject const std::string& subject = payload["subject"].asString(); + //message body const std::string& message = payload["message"].asString(); - LLTextEditor* pMessageText = getChild("message"); - pMessageText->setValue(""); - pMessageText->setEnabled(FALSE); - LLStyle::Params date_style; - date_style.color = textColor; - date_style.font.name = "SANSSERIF"; - - LLStyle::Params header_style_params; - header_style_params.color = textColor; - header_style_params.font = LLFontGL::getFontSansSerifBig(); - pMessageText->appendStyledText(subject + "\n",false,false,header_style_params); + LLTextBox* pSubjectText = getChild("subject"); + pSubjectText->setValue(subject); + LLTextBox* pDateTimeText = getChild("datetime"); std::string timeStr = "["+LLTrans::getString("UTCTimeWeek")+"],[" +LLTrans::getString("UTCTimeDay")+"] [" +LLTrans::getString("UTCTimeMth")+"] [" @@ -108,25 +101,38 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLSD substitution; substitution["datetime"] = (S32) notice_date.secondsSinceEpoch(); LLStringUtil::format(timeStr, substitution); - LLStyle::Params date_style_params; - date_style_params.color = textColor; - date_style_params.font = LLFontGL::getFontMonospace(); - pMessageText->appendStyledText(timeStr, false, false, date_style); - pMessageText->appendColoredText(std::string("\n\n") + message, false, - false, textColor); + pDateTimeText->setValue(timeStr); + + LLTextBox* pMessageText = getChild("message"); + + //If message is empty let it be invisible and not take place at the panel + if(message.size() != 0) + { + pMessageText->setVisible(TRUE); + pMessageText->setValue(message); + } + else + { + pMessageText->setVisible(FALSE); + } //attachment BOOL hasInventory = payload["inventory_offer"].isDefined(); + + //attachment text LLTextBox * pAttachLink = getChild("attachment"); + //attachment icon + LLIconCtrl* pAttachIcon = getChild("attachment_icon", TRUE); + + //If attachment is empty let it be invisible and not take place at the panel pAttachLink->setVisible(hasInventory); + pAttachIcon->setVisible(hasInventory); if (hasInventory) { pAttachLink->setValue(payload["inventory_name"]); mInventoryOffer = new LLOfferInfo(payload["inventory_offer"]); childSetActionTextbox("attachment", boost::bind( &LLToastGroupNotifyPanel::onClickAttachment, this)); - //attachment icon - LLIconCtrl* pAttachIcon = getChild("attachment_icon", TRUE); LLUIImagePtr attachIconImg = get_item_icon(mInventoryOffer->mType, LLInventoryType::IT_TEXTURE, 0, FALSE); @@ -137,8 +143,15 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification LLButton* pOkBtn = getChild("btn_ok"); pOkBtn->setClickedCallback((boost::bind(&LLToastGroupNotifyPanel::onClickOk, this))); setDefaultBtn(pOkBtn); -} + S32 maxLinesCount; + std::istringstream ss( getString("message_max_lines_count") ); + if (!(ss >> maxLinesCount)) + { + maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT; + } + snapToMessageHeight(pMessageText, maxLinesCount); +} // virtual LLToastGroupNotifyPanel::~LLToastGroupNotifyPanel() diff --git a/indra/newview/lltoastgroupnotifypanel.h b/indra/newview/lltoastgroupnotifypanel.h index ba98531251..e3d0ef45cb 100644 --- a/indra/newview/lltoastgroupnotifypanel.h +++ b/indra/newview/lltoastgroupnotifypanel.h @@ -68,6 +68,8 @@ protected: private: static bool isAttachmentOpenable(LLAssetType::EType); + static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT; + LLButton* mSaveInventoryBtn; LLUUID mGroupID; diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index e41181c9e1..913e46e05e 100644 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -34,9 +34,7 @@ #include "lltoastimpanel.h" #include "llimpanel.h" -const S32 LLToastIMPanel::MAX_MESSAGE_HEIGHT = 50; -const S32 LLToastIMPanel::CAPTION_HEIGHT = 30; -const S32 LLToastIMPanel::TOP_PAD = 5; +const S32 LLToastIMPanel::DEFAULT_MESSAGE_MAX_LINE_COUNT = 6; //-------------------------------------------------------------------------- LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notification), @@ -60,7 +58,13 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notif mReplyBtn->setClickedCallback(boost::bind(&LLToastIMPanel::onClickReplyBtn, this)); - snapToMessageHeight(); + S32 maxLinesCount; + std::istringstream ss( getString("message_max_lines_count") ); + if (!(ss >> maxLinesCount)) + { + maxLinesCount = DEFAULT_MESSAGE_MAX_LINE_COUNT; + } + snapToMessageHeight(mMessage, maxLinesCount); } //-------------------------------------------------------------------------- @@ -68,22 +72,6 @@ LLToastIMPanel::~LLToastIMPanel() { } -//-------------------------------------------------------------------------- -void LLToastIMPanel::snapToMessageHeight() -{ - S32 required_text_height = mMessage->getTextPixelHeight(); - S32 text_height = llmin(required_text_height, MAX_MESSAGE_HEIGHT); - LLRect text_rect = mMessage->getRect(); - LLRect btn_rect = mReplyBtn->getRect(); - - - mMessage->reshape( text_rect.getWidth(), text_height, TRUE); - mMessage->setValue(mMessage->getText()); - - S32 panel_height = CAPTION_HEIGHT + text_height + btn_rect.getHeight() + TOP_PAD*5; - reshape( getRect().getWidth(), panel_height, TRUE); -} - //-------------------------------------------------------------------------- void LLToastIMPanel::onClickReplyBtn() { diff --git a/indra/newview/lltoastimpanel.h b/indra/newview/lltoastimpanel.h index 7f5d6eca1d..11f489c12f 100644 --- a/indra/newview/lltoastimpanel.h +++ b/indra/newview/lltoastimpanel.h @@ -59,12 +59,9 @@ public: virtual ~LLToastIMPanel(); private: - static const S32 MAX_MESSAGE_HEIGHT; - static const S32 CAPTION_HEIGHT; - static const S32 TOP_PAD; + static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT; void onClickReplyBtn(); - void snapToMessageHeight(); LLUUID mSessionID; LLAvatarIconCtrl* mAvatar; diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 28052a33be..e884d89ce4 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -49,5 +49,36 @@ std::string LLToastPanel::getTitle() return mNotification->getMessage(); } +//snap to the message height if it is visible +void LLToastPanel::snapToMessageHeight(LLTextBox* message, S32 maxLineCount) +{ + //Add message height if it is visible + if (message->getVisible()) + { + S32 heightDelta = 0; + S32 maxTextHeight = (S32)(message->getFont()->getLineHeight() * maxLineCount); + + LLRect messageRect = message->getRect(); + S32 oldTextHeight = messageRect.getHeight(); + + //Reshape the toast to give the message max height. + //This needed to calculate lines count according to specified text + heightDelta = maxTextHeight - oldTextHeight; + reshape( getRect().getWidth(), getRect().getHeight() + heightDelta); + message->setValue(message->getText()); + + //Knowing the height is set to max allowed, getTextPixelHeight returns needed text height + //Perhaps we need to pass maxLineCount as parameter to getTextPixelHeight to avoid previous reshape. + S32 requiredTextHeight = message->getTextPixelHeight(); + S32 newTextHeight = llmin(requiredTextHeight, maxTextHeight); + //Calculate last delta height deducting previous heightDelta + heightDelta = newTextHeight - oldTextHeight - heightDelta; + + //reshape the panel with new height + reshape( getRect().getWidth(), getRect().getHeight() + heightDelta); + message->setValue(message->getText()); + } + +} diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index 2258eca273..bc9888f4b4 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -34,6 +34,7 @@ #define LL_LLTOASTPANEL_H #include "llpanel.h" +#include "lltextbox.h" #include "llnotifications.h" #include @@ -53,6 +54,7 @@ public: virtual const LLUUID& getID() { return mNotification->id();} protected: LLNotificationPtr mNotification; + void snapToMessageHeight(LLTextBox* message, S32 maxLineCount); }; #endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index acd6856061..c7c9f07504 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -60,6 +60,7 @@ #include "llui.h" #include "llviewermenu.h" #include "llfirstuse.h" +#include "llpanelblockedlist.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llscrolllistcell.h" @@ -69,7 +70,6 @@ #include "lltoolgrab.h" #include "llcombobox.h" #include "llfloaterchat.h" -#include "llfloatermute.h" #include "llimpanel.h" #include "lllayoutstack.h" @@ -297,11 +297,8 @@ void LLToolBar::updateCommunicateList() communicate_button->addSeparator(ADD_TOP); communicate_button->add(getString("Redock Windows"), LLSD("redock"), ADD_TOP); communicate_button->addSeparator(ADD_TOP); - LLFloaterMute* mute_instance = LLFloaterReg::getTypedInstance("mute"); - if(mute_instance) - { - communicate_button->add(mute_instance->getShortTitle(), LLSD("mute list"), ADD_TOP); - } + communicate_button->add(getString("Blocked List"), LLSD("mute list"), ADD_TOP); + std::set >::const_iterator floater_handle_it; if (gIMMgr->getIMFloaterHandles().size() > 0) @@ -379,7 +376,7 @@ void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, const LLSD& user_data) } else if (selected_option.asString() == "mute list") { - LLFloaterReg::showInstance("mute"); + LLPanelBlockedList::showPanelAndSelect(LLUUID::null); } else if (selected_option.isUndefined()) // user just clicked the communicate button, treat as toggle { diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index b85dc30e72..c8f2e03903 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -78,7 +78,6 @@ #include "llfloaterlandholdings.h" #include "llfloatermap.h" #include "llfloatermemleak.h" -#include "llfloatermute.h" #include "llfloaternamedesc.h" #include "llfloaternotificationsconsole.h" #include "llfloateropenobject.h" @@ -110,6 +109,7 @@ #include "llmediaremotectrl.h" #include "llmoveview.h" #include "llnearbychat.h" +#include "llpanelblockedlist.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewnotecard.h" @@ -177,8 +177,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("mute", "floater_mute.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("mute_object", "floater_mute_object.xml", &LLFloaterMute::buildFloaterMuteObjectUI); + LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("syswell_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 95ab40f9bf..ec20af46a1 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -120,6 +120,41 @@ LLViewerInventoryItem::~LLViewerInventoryItem() { } +BOOL LLViewerInventoryItem::extractSortFieldAndDisplayName(S32* sortField, std::string* displayName) const +{ + using std::string; + using std::stringstream; + + const char separator = getSeparator(); + const string::size_type separatorPos = mName.find(separator, 0); + + BOOL result = FALSE; + + if (separatorPos < string::npos) + { + if (sortField) + { + /* + * The conversion from string to S32 is made this way instead of old plain + * atoi() to ensure portability. If on some other platform S32 will not be + * defined to be signed int, this conversion will still work because of + * operators overloading, but atoi() may fail. + */ + stringstream ss(mName.substr(0, separatorPos)); + ss >> *sortField; + } + + if (displayName) + { + *displayName = mName.substr(separatorPos + 1, string::npos); + } + + result = TRUE; + } + + return result; +} + void LLViewerInventoryItem::copyViewerItem(const LLViewerInventoryItem* other) { LLInventoryItem::copyItem(other); @@ -1102,7 +1137,70 @@ const std::string& LLViewerInventoryItem::getName() const return linked_category->getName(); } - return LLInventoryItem::getName(); + return getDisplayName(); +} + +const std::string& LLViewerInventoryItem::getDisplayName() const +{ + std::string result; + BOOL hasSortField = extractSortFieldAndDisplayName(0, &result); + + return mDisplayName = hasSortField ? result : LLInventoryItem::getName(); +} + +S32 LLViewerInventoryItem::getSortField() const +{ + S32 result; + BOOL hasSortField = extractSortFieldAndDisplayName(&result, 0); + + return hasSortField ? result : -1; +} + +void LLViewerInventoryItem::setSortField(S32 sortField) +{ + using std::string; + + std::stringstream ss; + ss << sortField; + + string newSortField = ss.str(); + + const char separator = getSeparator(); + const string::size_type separatorPos = mName.find(separator, 0); + + if (separatorPos < string::npos) + { + // the name of the LLViewerInventoryItem already consists of sort field and display name. + mName = newSortField + separator + mName.substr(separatorPos + 1, string::npos); + } + else + { + // there is no sort field in the name of LLViewerInventoryItem, we should add it + mName = newSortField + separator + mName; + } +} + +void LLViewerInventoryItem::rename(const std::string& n) +{ + using std::string; + + string new_name(n); + LLStringUtil::replaceNonstandardASCII(new_name, ' '); + LLStringUtil::replaceChar(new_name, '|', ' '); + LLStringUtil::trim(new_name); + LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); + + const char separator = getSeparator(); + const string::size_type separatorPos = mName.find(separator, 0); + + if (separatorPos < string::npos) + { + mName.replace(separatorPos + 1, string::npos, new_name); + } + else + { + mName = new_name; + } } const LLPermissions& LLViewerInventoryItem::getPermissions() const diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 0bfb37f7e8..c4ff30bbfc 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -55,11 +55,18 @@ public: protected: ~LLViewerInventoryItem( void ); // ref counted + BOOL extractSortFieldAndDisplayName(S32* sortField, std::string* displayName) const; + static char getSeparator() { return '@'; } + mutable std::string mDisplayName; public: virtual LLAssetType::EType getType() const; virtual const LLUUID& getAssetUUID() const; virtual const std::string& getName() const; + virtual const std::string& getDisplayName() const; + virtual S32 getSortField() const; + virtual void setSortField(S32 sortField); + virtual void rename(const std::string& new_name); virtual const LLPermissions& getPermissions() const; virtual const LLUUID& getCreatorUUID() const; virtual const std::string& getDescription() const; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 8a5928f4e9..5536951ce6 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -113,7 +113,6 @@ #include "llfloaterland.h" #include "llfloaterlandholdings.h" #include "llfloatermap.h" -#include "llfloatermute.h" #include "llfloateropenobject.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -147,6 +146,7 @@ #include "llfloaterinventory.h" #include "llkeyboard.h" #include "llpanellogin.h" +#include "llpanelblockedlist.h" #include "llmenucommands.h" #include "llmenugl.h" #include "llmimetypes.h" @@ -2896,7 +2896,7 @@ class LLObjectMute : public view_listener_t else { LLMuteList::getInstance()->add(mute); - LLFloaterReg::showInstance("mute"); + LLPanelBlockedList::showPanelAndSelect(mute.mID); } return true; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index dfb1c330e5..177c987bc0 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -82,7 +82,6 @@ #include "llfloaterregioninfo.h" #include "llfloaterlandholdings.h" #include "llurldispatcher.h" -#include "llfloatermute.h" #include "llfloaterpostcard.h" #include "llfloaterpreference.h" #include "llfollowcam.h" @@ -138,6 +137,7 @@ #include "llgroupactions.h" #include "llagentui.h" #include "llsidetray.h" +#include "llpanelblockedlist.h" #include "llpanelplaceinfo.h" #include @@ -1001,9 +1001,7 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, LLMute mute(blocked_id, from_name, type); if (LLMuteList::getInstance()->add(mute)) { - LLFloaterReg::showInstance("mute"); - LLFloaterMute* mute_instance = LLFloaterReg::getTypedInstance("mute"); - if(mute_instance) mute_instance->selectMute(blocked_id); + LLPanelBlockedList::showPanelAndSelect(blocked_id); } // purge the message queue of any previously queued inventory offers from the same source. @@ -5576,7 +5574,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLPanelLandCovenant::updateEstateName(estate_name); LLFloaterBuyLand::updateEstateName(estate_name); - LLPanelPlaceInfo* panel = dynamic_cast(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD())); + LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild("panel_place_info"); if (panel) { panel->updateEstateName(estate_name); @@ -5660,7 +5658,7 @@ void callbackCacheEstateOwnerName(const LLUUID& id, LLPanelLandCovenant::updateEstateOwnerName(name); LLFloaterBuyLand::updateEstateOwnerName(name); - LLPanelPlaceInfo* panel = dynamic_cast(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD())); + LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild("panel_place_info"); if (panel) { panel->updateEstateOwnerName(name); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 607c5d9ae8..241c6fd511 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1596,8 +1596,6 @@ void LLViewerWindow::initWorldUI() gFloaterView->setRect(floater_view_rect); gNotifyBoxView->setRect(notify_view_rect); - // *Note: this is where gFloaterMute used to be initialized. - LLWorldMapView::initClass(); // Force gFloaterWorldMap to initialize @@ -1636,6 +1634,11 @@ void LLViewerWindow::initWorldUI() navbar->showFavoritesPanel(FALSE); } + if (!gSavedSettings.getBOOL("ShowCameraAndMoveControls")) + { + LLBottomTray::getInstance()->showCameraAndMoveControls(FALSE); + } + getRootView()->addChild(gStatusBar); getRootView()->addChild(navbar); @@ -1668,6 +1671,9 @@ void LLViewerWindow::initWorldUI() // put behind everything else in the UI getRootView()->addChildInBack(gHUDView); } + + // this allows not to see UI elements created while UI initializing after Alt+Tab was pressed during login. EXT-744. + moveProgressViewToFront(); } // Destroy the UI @@ -4417,8 +4423,7 @@ void LLViewerWindow::moveProgressViewToFront() { if( mProgressView && mRootView ) { - mRootView->removeChild( mProgressView ); - mRootView->addChild( mProgressView ); + mRootView->sendChildToFront(mProgressView); } } diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 0bd5f114ed..e32ea0944e 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -93,6 +93,7 @@ + diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml index bb5a4e51f7..6ef1eb9513 100644 --- a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml @@ -15,4 +15,8 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml index 8c2c5e8c9e..2b0f029016 100644 --- a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml @@ -15,4 +15,8 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml index 00cf443cc6..88b0528e53 100644 --- a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml @@ -12,4 +12,8 @@ + + + + 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 new file mode 100644 index 0000000000..5c8a8ee208 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_block_list_sidetray.xml @@ -0,0 +1,84 @@ + + + + Blocked List + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml index 8fc029bea6..79ca839f28 100644 --- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml @@ -266,7 +266,7 @@ top="2" width="48">