From 114e5ca0839bace7f247a6eadb6e06a28597501d Mon Sep 17 00:00:00 2001 From: Loren Shih Date: Mon, 29 Mar 2010 16:33:35 -0400 Subject: EXT-5940 : Typedef all vector's Superficial cleanup to change all typedef std::vector to use a common typedef uuid_vec_t instead. --- indra/llui/llflatlistview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 2e5aeec41d..bc34012267 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -243,7 +243,7 @@ LLUUID LLFlatListView::getSelectedUUID() const } } -void LLFlatListView::getSelectedUUIDs(std::vector& selected_uuids) const +void LLFlatListView::getSelectedUUIDs(uuid_vec_t& selected_uuids) const { if (mSelectedItemPairs.empty()) return; -- cgit v1.3 From 7f38ea147466b6d045c90d710402b2ac321dbfd9 Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Thu, 1 Apr 2010 11:32:51 +0300 Subject: Fixed normal bug EXT-6659("Ctrl+A" combination allows selecting of several picks) - added check that multiple selection is allowed Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/146/ --HG-- branch : product-engine --- indra/llui/llflatlistview.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index bc34012267..d8084fd9aa 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -562,8 +562,7 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) { if(MASK_CONTROL & mask) { - selectAll(); - handled = TRUE; + handled = (BOOL)selectAll(); } break; } @@ -793,7 +792,7 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti bool LLFlatListView::selectAll() { - if (!mAllowSelection) + if (!mAllowSelection || !mMultipleSelection) return false; mSelectedItemPairs.clear(); -- cgit v1.3 From 7b4046df83e4353bdade8fbc39387a7bbb3f498d Mon Sep 17 00:00:00 2001 From: Richard Nelson Date: Thu, 1 Apr 2010 11:47:21 -0700 Subject: EXT-3531 - Ctrl-P does not work reliably on login --- indra/llui/llcombobox.cpp | 1 - indra/llui/llflatlistview.cpp | 37 ++++-- indra/llui/llflatlistview.h | 7 +- indra/llui/lllineeditor.cpp | 112 +++------------- indra/llui/lllineeditor.h | 4 - indra/llui/llmenugl.cpp | 2 +- indra/llui/llmultifloater.cpp | 2 +- indra/llui/lltextbase.cpp | 7 + indra/llui/lltextbase.h | 1 + indra/llui/lltexteditor.cpp | 237 +++++----------------------------- indra/llui/lltexteditor.h | 12 +- indra/llui/llui.cpp | 7 +- indra/llui/llui.h | 2 + indra/llwindow/llwindowwin32.cpp | 73 ----------- indra/newview/lllocationinputctrl.cpp | 1 - indra/newview/lltoastalertpanel.cpp | 3 - indra/newview/llurllineeditorctrl.cpp | 7 +- indra/newview/llurllineeditorctrl.h | 2 - indra/newview/llviewercontrol.cpp | 8 ++ indra/newview/llviewermenu.cpp | 7 +- indra/newview/llviewermenu.h | 1 + indra/newview/llviewerwindow.cpp | 129 ++++++------------ 22 files changed, 141 insertions(+), 521 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 3a8efadaa4..cc107c972d 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -495,7 +495,6 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p) params.max_length_bytes(mMaxChars); params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.handle_edit_keys_directly(true); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); params.label(mLabel); diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index bc34012267..d499e08ecb 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -53,6 +53,17 @@ LLFlatListView::Params::Params() no_items_text("no_items_text") {}; +LLFlatListView::~LLFlatListView() +{ + clear(); + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } +}; + + void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { LLScrollContainer::reshape(width, height, called_from_parent); @@ -558,15 +569,6 @@ BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) } break; } - case 'A': - { - if(MASK_CONTROL & mask) - { - selectAll(); - handled = TRUE; - } - break; - } default: break; } @@ -791,10 +793,15 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti return false; } -bool LLFlatListView::selectAll() +BOOL LLFlatListView::canSelectAll() const +{ + return !mItemPairs.empty() && mAllowSelection; +} + +void LLFlatListView::selectAll() { if (!mAllowSelection) - return false; + return; mSelectedItemPairs.clear(); @@ -814,8 +821,6 @@ bool LLFlatListView::selectAll() // Stretch selected item rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); - - return true; } bool LLFlatListView::isSelected(item_pair_t* item_pair) const @@ -953,11 +958,17 @@ void LLFlatListView::getValues(std::vector& values) const void LLFlatListView::onFocusReceived() { mSelectedItemsBorder->setVisible(TRUE); + gEditMenuHandler = this; } // virtual void LLFlatListView::onFocusLost() { mSelectedItemsBorder->setVisible(FALSE); + // Route menu back to the default + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } } //virtual diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 837fbb36b7..3a2ab54658 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -58,7 +58,7 @@ * - Order of returned selected items are not guaranteed * - The control assumes that all items being added are unique. */ -class LLFlatListView : public LLScrollContainer +class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler { public: @@ -114,7 +114,7 @@ public: Params(); }; - virtual ~LLFlatListView() { clear(); }; + virtual ~LLFlatListView(); /** * Connects callback to signal called when Return key is pressed. @@ -344,7 +344,8 @@ protected: virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection); - virtual bool selectAll(); + virtual BOOL canSelectAll() const; + virtual void selectAll(); virtual bool isSelected(item_pair_t* item_pair) const; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 483a394bbd..ce0c0befe0 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -91,7 +91,6 @@ LLLineEditor::Params::Params() background_image_disabled("background_image_disabled"), background_image_focused("background_image_focused"), select_on_focus("select_on_focus", false), - handle_edit_keys_directly("handle_edit_keys_directly", false), revert_on_esc("revert_on_esc", true), commit_on_focus_lost("commit_on_focus_lost", true), ignore_tab("ignore_tab", true), @@ -136,7 +135,6 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mIgnoreArrowKeys( FALSE ), mIgnoreTab( p.ignore_tab ), mDrawAsterixes( FALSE ), - mHandleEditKeysDirectly(p.handle_edit_keys_directly), mSelectAllonFocusReceived( p.select_on_focus ), mPassDelete(FALSE), mReadOnly(FALSE), @@ -497,6 +495,7 @@ void LLLineEditor::selectAll() setCursor(mSelectionEnd); //mScrollHPos = 0; mIsSelecting = TRUE; + updatePrimary(); } @@ -788,7 +787,7 @@ void LLLineEditor::removeChar() } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } } @@ -827,7 +826,7 @@ void LLLineEditor::addChar(const llwchar uni_char) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } getWindow()->hideCursorUntilMouseMove(); @@ -916,7 +915,7 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } break; @@ -932,7 +931,7 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } break; @@ -958,22 +957,6 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) } } - if (!handled && mHandleEditKeysDirectly) - { - if( (MASK_CONTROL & mask) && ('A' == key) ) - { - if( canSelectAll() ) - { - selectAll(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - } - if(handled) { // take selection to 'primary' clipboard @@ -1020,7 +1003,7 @@ void LLLineEditor::cut() if( need_to_rollback ) { rollback.doRollback( this ); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } else if( mKeystrokeCallback ) @@ -1129,7 +1112,7 @@ void LLLineEditor::pasteHelper(bool is_primary) } // Truncate the clean string at the limit of what will fit clean_string = clean_string.substr(0, wchars_that_fit); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } mText.insert(getCursor(), clean_string); @@ -1141,7 +1124,7 @@ void LLLineEditor::pasteHelper(bool is_primary) if( need_to_rollback ) { rollback.doRollback( this ); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } else if( mKeystrokeCallback ) @@ -1206,7 +1189,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } } handled = TRUE; @@ -1255,7 +1238,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } handled = TRUE; } @@ -1282,7 +1265,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } handled = TRUE; } @@ -1299,7 +1282,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } handled = TRUE; } @@ -1316,7 +1299,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } handled = TRUE; } @@ -1339,64 +1322,6 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) break; } - if( !handled && mHandleEditKeysDirectly ) - { - // Standard edit keys (Ctrl-X, Delete, etc,) are handled here instead of routed by the menu system. - if( KEY_DELETE == key ) - { - if( canDoDelete() ) - { - doDelete(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - else - if( MASK_CONTROL & mask ) - { - if( 'C' == key ) - { - if( canCopy() ) - { - copy(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - else - if( 'V' == key ) - { - if( canPaste() ) - { - paste(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - else - if( 'X' == key ) - { - if( canCut() ) - { - cut(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - } - } return handled; } @@ -1451,7 +1376,7 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) { rollback.doRollback(this); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } // Notify owner if requested @@ -1499,7 +1424,7 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) { rollback.doRollback( this ); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } // Notify owner if requested @@ -1544,7 +1469,7 @@ void LLLineEditor::doDelete() if( need_to_rollback ) { rollback.doRollback( this ); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } else { @@ -1879,11 +1804,6 @@ S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) const return result; } -void LLLineEditor::reportBadKeystroke() -{ - make_ui_sound("UISndBadKeystroke"); -} - //virtual void LLLineEditor::clear() { diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index b62138426b..9489e723e3 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -81,7 +81,6 @@ public: background_image_focused; Optional select_on_focus, - handle_edit_keys_directly, revert_on_esc, commit_on_focus_lost, ignore_tab; @@ -215,7 +214,6 @@ public: void extendSelection(S32 new_cursor_pos); void deleteSelection(); - void setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; } void setSelectAllonFocusReceived(BOOL b); typedef boost::function callback_t; @@ -247,7 +245,6 @@ private: void addChar(const llwchar c); void setCursorAtLocalPos(S32 local_mouse_x); S32 findPixelNearestPos(S32 cursor_offset = 0) const; - void reportBadKeystroke(); BOOL handleSpecialKey(KEY key, MASK mask); BOOL handleSelectionKey(KEY key, MASK mask); BOOL handleControlKey(KEY key, MASK mask); @@ -325,7 +322,6 @@ protected: BOOL mIgnoreTab; BOOL mDrawAsterixes; - BOOL mHandleEditKeysDirectly; // If true, the standard edit keys (Ctrl-X, Delete, etc,) are handled here instead of routed by the menu system BOOL mSelectAllonFocusReceived; BOOL mPassDelete; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index fb4a9d032d..e0e86ae228 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3345,7 +3345,7 @@ void LLMenuHolderGL::draw() LLView::draw(); // now draw last selected item as overlay LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get(); - if (selecteditem && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) + if (selecteditem && selecteditem->getVisible() && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) { // make sure toggle items, for example, show the proper state when fading out selecteditem->buildDrawLabel(); diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index 4af9108329..3aea648562 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -345,7 +345,7 @@ void LLMultiFloater::setVisible(BOOL visible) BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask) { - if (key == 'W' && mask == MASK_CONTROL) + if (key == 'W' && mask == (MASK_CONTROL|MASK_SHIFT)) { LLFloater* floater = getActiveFloater(); // is user closeable and is system closeable diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 5f4b16ec9e..fb8cb1c93b 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1047,6 +1047,13 @@ void LLTextBase::setValue(const LLSD& value ) setText(value.asString()); } +//virtual +BOOL LLTextBase::canDeselect() const +{ + return hasSelection(); +} + + //virtual void LLTextBase::deselect() { diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 5b24c63557..8ed0680df9 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -132,6 +132,7 @@ public: /*virtual*/ LLTextViewModel* getViewModel() const; // LLEditMenuHandler interface + /*virtual*/ BOOL canDeselect() const; /*virtual*/ void deselect(); // used by LLTextSegment layout code diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 7d230f7d42..0f943831eb 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -240,7 +240,6 @@ LLTextEditor::Params::Params() prevalidate_callback("prevalidate_callback"), embedded_items("embedded_items", false), ignore_tab("ignore_tab", true), - handle_edit_keys_directly("handle_edit_keys_directly", false), show_line_numbers("show_line_numbers", false), default_color("default_color"), commit_on_focus_lost("commit_on_focus_lost", false), @@ -258,7 +257,6 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : mShowLineNumbers ( p.show_line_numbers ), mCommitOnFocusLost( p.commit_on_focus_lost), mAllowEmbeddedItems( p.embedded_items ), - mHandleEditKeysDirectly( p.handle_edit_keys_directly ), mMouseDownX(0), mMouseDownY(0), mTabsToNextField(p.ignore_tab), @@ -507,21 +505,6 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, } } -// virtual -BOOL LLTextEditor::canDeselect() const -{ - return hasSelection(); -} - - -void LLTextEditor::deselect() -{ - mSelectionStart = 0; - mSelectionEnd = 0; - mIsSelecting = FALSE; -} - - BOOL LLTextEditor::selectionContainsLineBreaks() { if (hasSelection()) @@ -668,6 +651,7 @@ void LLTextEditor::selectAll() mSelectionStart = getLength(); mSelectionEnd = 0; setCursorPos(mSelectionEnd); + updatePrimary(); } BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) @@ -1025,7 +1009,7 @@ void LLTextEditor::removeCharOrTab() } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } } @@ -1048,7 +1032,7 @@ void LLTextEditor::removeChar() } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } } @@ -1198,22 +1182,6 @@ BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) } } - if( !handled && mHandleEditKeysDirectly ) - { - if( (MASK_CONTROL & mask) && ('A' == key) ) - { - if( canSelectAll() ) - { - selectAll(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - } - if( handled ) { // take selection to 'primary' clipboard @@ -1247,6 +1215,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) case KEY_DOWN: changeLine( 1 ); + deselect(); break; case KEY_PAGE_DOWN: @@ -1260,7 +1229,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) case KEY_LEFT: if( hasSelection() ) { - setCursorPos(llmin( mCursorPos - 1, mSelectionStart, mSelectionEnd )); + setCursorPos(llmin( mSelectionStart, mSelectionEnd )); } else { @@ -1270,7 +1239,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } } break; @@ -1278,7 +1247,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) case KEY_RIGHT: if( hasSelection() ) { - setCursorPos(llmax( mCursorPos + 1, mSelectionStart, mSelectionEnd )); + setCursorPos(llmax( mSelectionStart, mSelectionEnd )); } else { @@ -1288,7 +1257,7 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } } break; @@ -1298,6 +1267,11 @@ BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask) break; } } + + if (handled) + { + deselect(); + } return handled; } @@ -1551,75 +1525,13 @@ BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) return handled; } -BOOL LLTextEditor::handleEditKey(const KEY key, const MASK mask) -{ - BOOL handled = FALSE; - - // Standard edit keys (Ctrl-X, Delete, etc,) are handled here instead of routed by the menu system. - if( KEY_DELETE == key ) - { - if( canDoDelete() ) - { - doDelete(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - else - if( MASK_CONTROL & mask ) - { - if( 'C' == key ) - { - if( canCopy() ) - { - copy(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - else - if( 'V' == key ) - { - if( canPaste() ) - { - paste(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - else - if( 'X' == key ) - { - if( canCut() ) - { - cut(); - } - else - { - reportBadKeystroke(); - } - handled = TRUE; - } - } - - return handled; -} - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return_key_hit) +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) { - *return_key_hit = FALSE; BOOL handled = TRUE; + if (mReadOnly) return FALSE; + switch( key ) { case KEY_INSERT: @@ -1641,7 +1553,7 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return } else { - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } break; @@ -1694,6 +1606,10 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return break; } + if (handled) + { + onKeyStroke(); + } return handled; } @@ -1714,9 +1630,6 @@ void LLTextEditor::unindentLineBeforeCloseBrace() BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { BOOL handled = FALSE; - BOOL selection_modified = FALSE; - BOOL return_key_hit = FALSE; - BOOL text_may_have_changed = TRUE; // Special case for TAB. If want to move to next field, report // not handled and let the parent take care of field movement. @@ -1724,116 +1637,24 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask ) { return FALSE; } - /* - if (KEY_F10 == key) - { - LLComboBox::Params cp; - cp.name = "combo box"; - cp.label = "my combo"; - cp.rect.width = 100; - cp.rect.height = 20; - cp.items.add().label = "item 1"; - cp.items.add().label = "item 2"; - cp.items.add().label = "item 3"; - - appendWidget(LLUICtrlFactory::create(cp), "combo", true, false); - } - if (KEY_F11 == key) - { - LLButton::Params bp; - bp.name = "text button"; - bp.label = "Click me"; - bp.rect.width = 100; - bp.rect.height = 20; - appendWidget(LLUICtrlFactory::create(bp), "button", true, false); - } - */ - if (mReadOnly) + if (mReadOnly && mScroller) { - if(mScroller) - { - handled = mScroller->handleKeyHere( key, mask ); - } - else - { - handled = handleNavigationKey( key, mask ); - } - + handled = (mScroller && mScroller->handleKeyHere( key, mask )) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask); } else { - // handle navigation keys ourself - handled = handleNavigationKey( key, mask ); - } - - - if( handled ) - { - text_may_have_changed = FALSE; - } - - if( !handled ) - { - handled = handleSelectionKey( key, mask ); - if( handled ) - { - selection_modified = TRUE; - } - } - - if( !handled ) - { - handled = handleControlKey( key, mask ); - if( handled ) - { - selection_modified = TRUE; - } - } - - if( !handled && mHandleEditKeysDirectly ) - { - handled = handleEditKey( key, mask ); - if( handled ) - { - selection_modified = TRUE; - text_may_have_changed = TRUE; - } - } - - // Handle most keys only if the text editor is writeable. - if( !mReadOnly ) - { - if( !handled ) - { - handled = handleSpecialKey( key, mask, &return_key_hit ); - if( handled ) - { - selection_modified = TRUE; - text_may_have_changed = TRUE; - } - } - + handled = handleNavigationKey( key, mask ) + || handleSelectionKey(key, mask) + || handleControlKey(key, mask) + || handleSpecialKey(key, mask); } if( handled ) { resetCursorBlink(); - - // Most keystrokes will make the selection box go away, but not all will. - if( !selection_modified && - KEY_SHIFT != key && - KEY_CONTROL != key && - KEY_ALT != key && - KEY_CAPSLOCK ) - { - deselect(); - } - - if(text_may_have_changed) - { - onKeyStroke(); - } needsScroll(); } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 71d937b2c4..9b3ab9414c 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -68,7 +68,6 @@ public: Optional embedded_items, ignore_tab, - handle_edit_keys_directly, show_line_numbers, commit_on_focus_lost, show_context_menu; @@ -146,8 +145,6 @@ public: virtual BOOL canDoDelete() const; virtual void selectAll(); virtual BOOL canSelectAll() const; - virtual void deselect(); - virtual BOOL canDeselect() const; void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); @@ -218,13 +215,10 @@ protected: S32 indentLine( S32 pos, S32 spaces ); void unindentLineBeforeCloseBrace(); - void reportBadKeystroke() { make_ui_sound("UISndBadKeystroke"); } - BOOL handleNavigationKey(const KEY key, const MASK mask); - BOOL handleSpecialKey(const KEY key, const MASK mask, BOOL* return_key_hit); + BOOL handleSpecialKey(const KEY key, const MASK mask); BOOL handleSelectionKey(const KEY key, const MASK mask); BOOL handleControlKey(const KEY key, const MASK mask); - BOOL handleEditKey(const KEY key, const MASK mask); BOOL selectionContainsLineBreaks(); void deleteSelection(BOOL transient_operation); @@ -329,10 +323,6 @@ private: LLUUID mSourceID; - // If true, the standard edit keys (Ctrl-X, Delete, etc,) are handled here - //instead of routed by the menu system - BOOL mHandleEditKeysDirectly; - LLCoordGL mLastIMEPosition; // Last position of the IME editor keystroke_signal_t mKeystrokeSignal; diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index b049895526..f9a4ed7285 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -1914,7 +1914,12 @@ void LLUI::clearPopups() } } - +//static +void LLUI::reportBadKeystroke() +{ + make_ui_sound("UISndBadKeystroke"); +} + //static // spawn_x and spawn_y are top left corner of view in screen GL coordinates void LLUI::positionViewNearMouse(LLView* view, S32 spawn_x, S32 spawn_y) diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 30f3623ded..c18262ef76 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -217,6 +217,8 @@ public: static void removePopup(LLView*); static void clearPopups(); + static void reportBadKeystroke(); + // Ensures view does not overlap mouse cursor, but is inside // the view's parent rectangle. Used for tooltips, inspectors. // Optionally override the view's default X/Y, which are relative to the diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d726c60018..95c1980dd6 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2999,79 +2999,6 @@ void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) sei.lpVerb = L"open"; sei.lpFile = url_utf16.c_str(); ShellExecuteEx( &sei ); - - //// TODO: LEAVING OLD CODE HERE SO I DON'T BONE OTHER MERGES - //// DELETE THIS ONCE THE MERGES ARE DONE - - // Figure out the user's default web browser - // HKEY_CLASSES_ROOT\http\shell\open\command - /* - std::string reg_path_str = gURLProtocolWhitelistHandler[i] + "\\shell\\open\\command"; - WCHAR reg_path_wstr[256]; - mbstowcs( reg_path_wstr, reg_path_str.c_str(), LL_ARRAY_SIZE(reg_path_wstr) ); - - HKEY key; - WCHAR browser_open_wstr[1024]; - DWORD buffer_length = 1024; - RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key); - RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length); - RegCloseKey(key); - - // Convert to STL string - LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr); - - if (browser_open_wstring.length() < 2) - { - LL_WARNS("Window") << "Invalid browser executable in registry " << browser_open_wstring << LL_ENDL; - return; - } - - // Extract the process that's supposed to be launched - LLWString browser_executable; - if (browser_open_wstring[0] == '"') - { - // executable is quoted, find the matching quote - size_t quote_pos = browser_open_wstring.find('"', 1); - // copy out the string including both quotes - browser_executable = browser_open_wstring.substr(0, quote_pos+1); - } - else - { - // executable not quoted, find a space - size_t space_pos = browser_open_wstring.find(' ', 1); - browser_executable = browser_open_wstring.substr(0, space_pos); - } - - LL_DEBUGS("Window") << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << LL_ENDL; - LL_INFOS("Window") << "Browser executable: " << wstring_to_utf8str(browser_executable) << LL_ENDL; - - // Convert URL to wide string for Windows API - // Assume URL is UTF8, as can come from scripts - LLWString url_wstring = utf8str_to_wstring(escaped_url); - llutf16string url_utf16 = wstring_to_utf16str(url_wstring); - - // Convert executable and path to wide string for Windows API - llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable); - - // ShellExecute returns HINSTANCE for backwards compatiblity. - // MS docs say to cast to int and compare to 32. - HWND our_window = NULL; - LPCWSTR directory_wstr = NULL; - int retval = (int) ShellExecute(our_window, // Flawfinder: ignore - L"open", - browser_exec_utf16.c_str(), - url_utf16.c_str(), - directory_wstr, - SW_SHOWNORMAL); - if (retval > 32) - { - LL_DEBUGS("Window") << "load_url success with " << retval << LL_ENDL; - } - else - { - LL_INFOS("Window") << "load_url failure with " << retval << LL_ENDL; - } - */ } /* diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index ba50287ebd..ad2e594b49 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -227,7 +227,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) params.default_text(LLStringUtil::null); params.max_length_bytes(p.max_chars); params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); - params.handle_edit_keys_directly(true); params.commit_on_focus_lost(false); params.follows.flags(FOLLOWS_ALL); mTextEntry = LLUICtrlFactory::create(params); diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp index c3ccb9380b..986ccdf19b 100644 --- a/indra/newview/lltoastalertpanel.cpp +++ b/indra/newview/lltoastalertpanel.cpp @@ -281,9 +281,6 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal mLineEditor->setText(edit_text_contents); mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1); - // make sure all edit keys get handled properly (DEV-22396) - mLineEditor->setHandleEditKeysDirectly(TRUE); - LLToastPanel::addChild(mLineEditor); mLineEditor->setDrawAsterixes(is_password); diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp index 258c3ddd75..1d2687a8c2 100644 --- a/indra/newview/llurllineeditorctrl.cpp +++ b/indra/newview/llurllineeditorctrl.cpp @@ -72,7 +72,7 @@ void LLURLLineEditor::cut() if( need_to_rollback ) { rollback.doRollback( this ); - reportBadKeystroke(); + LLUI::reportBadKeystroke(); } else if( mKeystrokeCallback ) @@ -96,8 +96,3 @@ void LLURLLineEditor::copyEscapedURLToClipboard() gClipboard.copyFromString( text_to_copy ); } -// Makes UISndBadKeystroke sound -void LLURLLineEditor::reportBadKeystroke() -{ - make_ui_sound("UISndBadKeystroke"); -} diff --git a/indra/newview/llurllineeditorctrl.h b/indra/newview/llurllineeditorctrl.h index 618f29dfbf..ebe417e855 100644 --- a/indra/newview/llurllineeditorctrl.h +++ b/indra/newview/llurllineeditorctrl.h @@ -55,8 +55,6 @@ protected: private: // util function to escape selected text and copy it to clipboard void copyEscapedURLToClipboard(); - // send a beep signal if keystroke is bad. As it is private at LLLineEditor we need own function - void reportBadKeystroke(); // Helper class to do rollback if needed class LLURLLineEditorRollback diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 23349ab916..b2b7e653e4 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -74,6 +74,7 @@ #include "llnavigationbar.h" #include "llfloatertools.h" #include "llpaneloutfitsinventory.h" +#include "llpanellogin.h" #ifdef TOGGLE_HACKED_GODLIKE_VIEWER BOOL gHackGodmode = FALSE; @@ -443,6 +444,12 @@ bool handleVelocityInterpolate(const LLSD& newvalue) return true; } +bool handleForceShowGrid(const LLSD& newvalue) +{ + LLPanelLogin::refreshLocation( false ); + return true; +} + bool toggle_agent_pause(const LLSD& newvalue) { if ( newvalue.asBoolean() ) @@ -648,6 +655,7 @@ void settings_setup_listeners() gSavedSettings.getControl("ShowNavbarFavoritesPanel")->getSignal()->connect(boost::bind(&toggle_show_favorites_panel, _2)); gSavedSettings.getControl("ShowDebugAppearanceEditor")->getSignal()->connect(boost::bind(&toggle_show_appearance_editor, _2)); gSavedSettings.getControl("ShowObjectRenderingCost")->getSignal()->connect(boost::bind(&toggle_show_object_render_cost, _2)); + gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 3a6aed01ce..eae60b4d85 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -136,6 +136,7 @@ extern BOOL gDebugWindowProc; LLMenuBarGL *gMenuBarView = NULL; LLViewerMenuHolderGL *gMenuHolder = NULL; LLMenuGL *gPopupMenuView = NULL; +LLMenuGL *gEditMenu = NULL; LLMenuBarGL *gLoginMenuBarView = NULL; // Pie menus @@ -383,8 +384,10 @@ void init_menus() /// /// Context menus /// + const widget_registry_t& registry = LLViewerMenuHolderGL::child_registry_t::instance(); + gEditMenu = LLUICtrlFactory::createFromFile("menu_edit.xml", gMenuHolder, registry); gMenuAvatarSelf = LLUICtrlFactory::createFromFile( "menu_avatar_self.xml", gMenuHolder, registry); gMenuAvatarOther = LLUICtrlFactory::createFromFile( @@ -5182,10 +5185,6 @@ void toggle_debug_menus(void*) { BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); gSavedSettings.setBOOL("UseDebugMenus", visible); - if(visible) - { - //LLFirstUse::useDebugMenus(); - } show_debug_menus(); } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index d3c34f0de4..d72ea00077 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -157,6 +157,7 @@ extern const std::string SAVE_INTO_INVENTORY; extern LLMenuBarGL* gMenuBarView; //extern LLView* gMenuBarHolder; +extern LLMenuGL* gEditMenu; extern LLMenuGL* gPopupMenuView; extern LLViewerMenuHolderGL* gMenuHolder; extern LLMenuBarGL* gLoginMenuBarView; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 85c961f34a..6fb1a054ed 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2145,12 +2145,14 @@ void LLViewerWindow::draw() // Takes a single keydown event, usually when UI is visible BOOL LLViewerWindow::handleKey(KEY key, MASK mask) { + // hide tooltips on keypress + LLToolTipMgr::instance().blockToolTips(); + if (gFocusMgr.getKeyboardFocus() && !(mask & (MASK_CONTROL | MASK_ALT)) && !gFocusMgr.getKeystrokesOnly()) { // We have keyboard focus, and it's not an accelerator - if (key < 0x80) { // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first. @@ -2158,68 +2160,49 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } } - // hide tooltips on keypress - LLToolTipMgr::instance().blockToolTips(); - - // Explicit hack for debug menu. - if ((MASK_ALT & mask) && - (MASK_CONTROL & mask) && - ('D' == key || 'd' == key)) + // let menus handle navigation keys for navigation + if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE)) + ||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE))) { - toggle_debug_menus(NULL); + return TRUE; } - // Explicit hack for debug menu. - if ((mask == (MASK_SHIFT | MASK_CONTROL)) && - ('G' == key || 'g' == key)) + // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus + // as long as focus isn't locked + if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked()) { - if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) { - BOOL visible = ! gSavedSettings.getBOOL("ForceShowGrid"); - gSavedSettings.setBOOL("ForceShowGrid", visible); - - // Initialize visibility (and don't force visibility - use prefs) - LLPanelLogin::refreshLocation( false ); + return TRUE; } } - // Debugging view for unified notifications: CTRL-SHIFT-5 - // *FIXME: Having this special-cased right here (just so this can be invoked from the login screen) sucks. - if ((MASK_SHIFT & mask) - && (!(MASK_ALT & mask)) - && (MASK_CONTROL & mask) - && ('5' == key)) + // give floaters first chance to handle TAB key + // so frontmost floater gets focus + // if nothing has focus, go to first or last UI element as appropriate + if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL)) { - //LLFloaterNotificationConsole::showInstance(); - LLFloaterReg::showInstance("notifications_console"); - return TRUE; - } + if (gMenuHolder) gMenuHolder->hideMenus(); - // handle escape key - //if (key == KEY_ESCAPE && mask == MASK_NONE) - //{ + // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode + gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0); - // *TODO: get this to play well with mouselook and hidden - // cursor modes, etc, and re-enable. - //if (gFocusMgr.getMouseCapture()) - //{ - // gFocusMgr.setMouseCapture(NULL); - // return TRUE; - //} - //} - - // let menus handle navigation keys - if (gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) - { - return TRUE; - } - // let menus handle navigation keys - if (gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE)) - { + // do CTRL-TAB and CTRL-SHIFT-TAB logic + if (mask & MASK_SHIFT) + { + mRootView->focusPrevRoot(); + } + else + { + mRootView->focusNextRoot(); + } return TRUE; } - //some of context menus use this container, let context menu handle navigation keys - if(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)) + + // hidden edit menu for cut/copy/paste + if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask)) { return TRUE; } @@ -2284,50 +2267,10 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) return TRUE; } - // Topmost view gets a chance before the hierarchy - // *FIX: get rid of this? - //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - //if (top_ctrl) - //{ - // if( top_ctrl->handleKey( key, mask, TRUE ) ) - // { - // return TRUE; - // } - //} - - // give floaters first chance to handle TAB key - // so frontmost floater gets focus - if (key == KEY_TAB) - { - // if nothing has focus, go to first or last UI element as appropriate - if (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL) - { - if (gMenuHolder) gMenuHolder->hideMenus(); - - // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode - gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0); - // do CTRL-TAB and CTRL-SHIFT-TAB logic - if (mask & MASK_SHIFT) - { - mRootView->focusPrevRoot(); - } - else - { - mRootView->focusNextRoot(); - } - return TRUE; - } - } - - // give menus a chance to handle keys - if (gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) - { - return TRUE; - } - - // give menus a chance to handle keys - if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)) + // give menus a chance to handle unmodified accelerator keys + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) { return TRUE; } -- cgit v1.3 From a9b806071ac0b60b9c4c36cc98564846c677dbd4 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Thu, 1 Apr 2010 16:41:45 -0700 Subject: fix for bad merge --- indra/llui/llflatlistview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 0fd7e7ed55..35f5a6bbb9 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -790,7 +790,7 @@ BOOL LLFlatListView::canSelectAll() const void LLFlatListView::selectAll() { if (!mAllowSelection || !mMultipleSelection) - return false; + return; mSelectedItemPairs.clear(); -- cgit v1.3 From 4e4dd52753523afcedc4af357a280defd1cb9070 Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Fri, 16 Apr 2010 13:18:11 +0300 Subject: Fixed low bug EXT-6823 (Implement a possibility to select several residents by "Shift" button) - improved the selection of list items by mouse. Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/238/ --HG-- branch : product-engine --- indra/llui/llflatlistview.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 35f5a6bbb9..82f054c4b7 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -504,7 +504,68 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) //*TODO find a better place for that enforcing stuff if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; - + + if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) + && mMultipleSelection && !mSelectedItemPairs.empty() ) + { + item_pair_t* last_selected_pair = mSelectedItemPairs.back(); + + // If item_pair is already selected - do nothing + if (last_selected_pair == item_pair) + return; + + bool grab_items = false; + pairs_list_t pairs_to_select; + + // Pick out items from list between last selected and current clicked item_pair. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* cur = *iter; + if (cur == last_selected_pair || cur == item_pair) + { + grab_items = !grab_items; + // Skip last selected and current clicked item pairs. + continue; + } + if (!cur->first->getVisible()) + { + // Skip invisible item pairs. + continue; + } + if (grab_items) + { + pairs_to_select.push_back(cur); + } + } + + if (select_item) + { + pairs_to_select.push_back(item_pair); + } + + for (pairs_iterator_t + iter = pairs_to_select.begin(), + iter_end = pairs_to_select.end(); + iter != iter_end; ++iter) + { + item_pair_t* pair_to_select = *iter; + selectItemPair(pair_to_select, true); + } + + if (!select_item) + { + // Item was already selected but there is a need to update last selected item and its border. + // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). + mSelectedItemPairs.remove(item_pair); + mSelectedItemPairs.push_back(item_pair); + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + } + return; + } + if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(); selectItemPair(item_pair, select_item); } -- cgit v1.3 From 4395d8e9f1302e8efcda4b35da3b0e3ea6c36928 Mon Sep 17 00:00:00 2001 From: Mike Antipov Date: Wed, 21 Apr 2010 10:17:09 +0300 Subject: WIP: critical bug EXT-4837 ([NUX] When filter results in null state, provide a message suggesting the user try global search.) Partial implementation of help text in case of empty list when filtered for Nearby and Recent lists of People panel: * Extracted support implementation of several messages for empty list depend of filtering from LLGroupList to LLFlatListEx * change inheritence of LLGroupList and LLAvatarList from LLFlatListView to LLFlatListViewEx * updated panel people to init Nearby & Recent lists with appropriate messages. --HG-- branch : product-engine --- indra/llui/llflatlistview.cpp | 38 ++++++++++++++- indra/llui/llflatlistview.h | 54 +++++++++++++++++++++- indra/newview/llavatarlist.cpp | 12 +++-- indra/newview/llavatarlist.h | 4 +- indra/newview/llgrouplist.cpp | 21 +-------- indra/newview/llgrouplist.h | 22 +-------- indra/newview/llpanelpeople.cpp | 10 ++-- .../newview/skins/default/xui/en/panel_people.xml | 10 +++- 8 files changed, 116 insertions(+), 55 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 82f054c4b7..990bf5cd22 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1,10 +1,10 @@ /** * @file llflatlistview.cpp - * @brief LLFlatListView base class + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2009, Linden Research, Inc. + * Copyright (c) 2009-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -1122,4 +1122,38 @@ void LLFlatListView::detachItems(std::vector& detached_items) } } + +/************************************************************************/ +/* LLFlatListViewEx implementation */ +/************************************************************************/ +LLFlatListViewEx::Params::Params() +: no_items_msg("no_items_msg") +, no_filtered_items_msg("no_filtered_items_msg") +{ + +} + +LLFlatListViewEx::LLFlatListViewEx(const Params& p) +: LLFlatListView(p) +, mNoFilteredItemsMsg(p.no_filtered_items_msg) +, mNoItemsMsg(p.no_items_msg) +{ + +} + +void LLFlatListViewEx::updateNoItemsMessage(bool items_filtered) +{ + if (items_filtered) + { + // items were filtered + setNoItemsCommentText(mNoFilteredItemsMsg); + } + else + { + // list does not contain any items at all + setNoItemsCommentText(mNoItemsMsg); + } + +} + //EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index e3c07e811f..f7d094f7e7 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -1,10 +1,10 @@ /** * @file llflatlistview.h - * @brief LLFlatListView base class + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2009, Linden Research, Inc. + * Copyright (c) 2009-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -430,4 +430,54 @@ private: commit_signal_t mOnReturnSignal; }; +/** + * Extends LLFlatListView functionality to show different messages when there are no items in the + * list depend on whether they are filtered or not. + * + * Class provides one message per case of empty list. + * It also provides protected updateNoItemsMessage() method to be called each time when derived list + * is changed to update base mNoItemsCommentTextbox value. + * + * It is implemented to avoid duplication of this functionality in concrete implementations of the + * lists. It is intended to be used as a base class for lists which should support two different + * messages for empty state. Can be improved to support more than two messages via state-to-message map. + */ +class LLFlatListViewEx : public LLFlatListView +{ +public: + struct Params : public LLInitParam::Block + { + /** + * Contains a message for empty list when it does not contain any items at all. + */ + Optional no_items_msg; + + /** + * Contains a message for empty list when its items are removed by filtering. + */ + Optional no_filtered_items_msg; + Params(); + }; + + // *WORKAROUND: two methods to overload appropriate Params due to localization issue: + // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 + void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } + void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + +protected: + LLFlatListViewEx(const Params& p); + + /** + * Applies a message for empty list depend on passed argument. + * + * @param items_filtered - if true message for filtered items will be set, otherwise for + * completely empty list. + */ + void updateNoItemsMessage(bool items_filtered); + +private: + std::string mNoFilteredItemsMsg; + std::string mNoItemsMsg; +}; + #endif diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index c7a5691d70..8ba47b5198 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -113,7 +113,7 @@ LLAvatarList::Params::Params() } LLAvatarList::LLAvatarList(const Params& p) -: LLFlatListView(p) +: LLFlatListViewEx(p) , mIgnoreOnlineStatus(p.ignore_online_status) , mShowLastInteractionTime(p.show_last_interaction_time) , mContextMenu(NULL) @@ -154,7 +154,7 @@ void LLAvatarList::draw() // *NOTE dzaporozhan // Call refresh() after draw() to avoid flickering of avatar list items. - LLFlatListView::draw(); + LLFlatListViewEx::draw(); if (mDirty) refresh(); @@ -171,7 +171,7 @@ void LLAvatarList::clear() { getIDs().clear(); setDirty(true); - LLFlatListView::clear(); + LLFlatListViewEx::clear(); } void LLAvatarList::setNameFilter(const std::string& filter) @@ -179,6 +179,10 @@ void LLAvatarList::setNameFilter(const std::string& filter) if (mNameFilter != filter) { mNameFilter = filter; + + // update message for empty state here instead of refresh() to avoid blinking when switch + // between tabs. + updateNoItemsMessage(!mNameFilter.empty()); setDirty(); } } @@ -360,7 +364,7 @@ S32 LLAvatarList::notifyParent(const LLSD& info) sort(); return 1; } - return LLFlatListView::notifyParent(info); + return LLFlatListViewEx::notifyParent(info); } void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is_online, EAddPosition pos) diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 528f796b8b..ff090f3a34 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -49,11 +49,11 @@ class LLTimer; * @see setDirty() * @see setNameFilter() */ -class LLAvatarList : public LLFlatListView +class LLAvatarList : public LLFlatListViewEx { LOG_CLASS(LLAvatarList); public: - struct Params : public LLInitParam::Block + struct Params : public LLInitParam::Block { Optional ignore_online_status, // show all items as online show_last_interaction_time, // show most recent interaction time. *HACK: move this to a derived class diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 8a056f836f..f21b6e1085 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -71,18 +71,10 @@ public: static const LLGroupComparator GROUP_COMPARATOR; -LLGroupList::Params::Params() -: no_groups_msg("no_groups_msg") -, no_filtered_groups_msg("no_filtered_groups_msg") -{ - -} LLGroupList::LLGroupList(const Params& p) -: LLFlatListView(p) +: LLFlatListViewEx(p) , mDirty(true) // to force initial update - , mNoFilteredGroupsMsg(p.no_filtered_groups_msg) - , mNoGroupsMsg(p.no_groups_msg) { // Listen for agent group changes. gAgent.addListener(this, "new group"); @@ -160,16 +152,7 @@ void LLGroupList::refresh() bool have_filter = !mNameFilter.empty(); // set no items message depend on filter state & total count of groups - if (have_filter) - { - // groups were filtered - setNoItemsCommentText(mNoFilteredGroupsMsg); - } - else if (0 == count) - { - // user is not a member of any group - setNoItemsCommentText(mNoGroupsMsg); - } + updateNoItemsMessage(have_filter); clear(); diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 0e9da25c58..16f3fc05a3 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -47,23 +47,10 @@ * * @see setNameFilter() */ -class LLGroupList: public LLFlatListView, public LLOldEvents::LLSimpleListener +class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener { LOG_CLASS(LLGroupList); public: - struct Params : public LLInitParam::Block - { - /** - * Contains a message for empty list when user is not a member of any group - */ - Optional no_groups_msg; - - /** - * Contains a message for empty list when all groups don't match passed filter - */ - Optional no_filtered_groups_msg; - Params(); - }; LLGroupList(const Params& p); virtual ~LLGroupList(); @@ -75,11 +62,6 @@ public: void toggleIcons(); bool getIconsVisible() const { return mShowIcons; } - // *WORKAROUND: two methods to overload appropriate Params due to localization issue: - // no_groups_msg & no_filtered_groups_msg attributes are not defined as translatable in VLT. See EXT-5931 - void setNoGroupsMsg(const std::string& msg) { mNoGroupsMsg = msg; } - void setNoFilteredGroupsMsg(const std::string& msg) { mNoFilteredGroupsMsg = msg; } - private: void setDirty(bool val = true) { mDirty = val; } void refresh(); @@ -94,8 +76,6 @@ private: bool mShowIcons; bool mDirty; std::string mNameFilter; - std::string mNoFilteredGroupsMsg; - std::string mNoGroupsMsg; }; class LLButton; diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 5802d53cd1..daa2a04f65 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -512,15 +512,19 @@ BOOL LLPanelPeople::postBuild() mNearbyList = getChild(NEARBY_TAB_NAME)->getChild("avatar_list"); mNearbyList->setNoItemsCommentText(getString("no_one_near")); + mNearbyList->setNoItemsMsg(getString("no_one_near")); + mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near")); mNearbyList->setShowIcons("NearbyListShowIcons"); mRecentList = getChild(RECENT_TAB_NAME)->getChild("avatar_list"); - mRecentList->setNoItemsCommentText(getString("no_people")); + mRecentList->setNoItemsCommentText(getString("no_recent_people")); + mRecentList->setNoItemsMsg(getString("no_recent_people")); + mRecentList->setNoFilteredItemsMsg(getString("no_filtered_recent_people")); mRecentList->setShowIcons("RecentListShowIcons"); mGroupList = getChild("group_list"); - mGroupList->setNoGroupsMsg(getString("no_groups_msg")); - mGroupList->setNoFilteredGroupsMsg(getString("no_filtered_groups_msg")); + mGroupList->setNoItemsMsg(getString("no_groups_msg")); + mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg")); mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu); diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 8a4a28e188..61784fede4 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -12,11 +12,17 @@ top="0" width="333"> + + @@ -30,7 +36,7 @@ name="groups_filter_label" value="Filter Groups" /> Date: Mon, 26 Apr 2010 17:19:43 +0300 Subject: Fixed major bug EXT-6092 [crashhunters] Crash in LLFlatListView::selectItemPair Reason: A) incorrect UP arrow handling in accordion control: invisible accordion tab was selected to handle selection. B) invalid std::map item (in empty map) was used to make selection in Flat List Fix: added checks against empty map before use front/back item pair before selecting first/last items. Also updated processing of the UP key in accordion control to not select invisible accordion tab. Reviewed by Vadim Savchuk at https://codereview.productengine.com/secondlife/r/318/ --HG-- branch : product-engine --- indra/llui/llaccordionctrl.cpp | 16 ++++++++++++---- indra/llui/llflatlistview.cpp | 6 ++++++ 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp index 136fd2a9ac..dca43c5784 100644 --- a/indra/llui/llaccordionctrl.cpp +++ b/indra/llui/llaccordionctrl.cpp @@ -668,15 +668,23 @@ S32 LLAccordionCtrl::notifyParent(const LLSD& info) LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[i]); if(accordion_tab->hasFocus() && i>0) { + bool prev_visible_tab_found = false; while(i>0) { if(mAccordionTabs[--i]->getVisible()) + { + prev_visible_tab_found = true; break; + } } - - accordion_tab = dynamic_cast(mAccordionTabs[i]); - accordion_tab->notify(LLSD().with("action","select_last")); - return 1; + + if (prev_visible_tab_found) + { + accordion_tab = dynamic_cast(mAccordionTabs[i]); + accordion_tab->notify(LLSD().with("action","select_last")); + return 1; + } + break; } } return 0; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 990bf5cd22..e0b2244654 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -744,12 +744,18 @@ LLRect LLFlatListView::getLastSelectedItemRect() void LLFlatListView::selectFirstItem () { + // No items - no actions! + if (mItemPairs.empty()) return; + selectItemPair(mItemPairs.front(), true); ensureSelectedVisible(); } void LLFlatListView::selectLastItem () { + // No items - no actions! + if (mItemPairs.empty()) return; + selectItemPair(mItemPairs.back(), true); ensureSelectedVisible(); } -- cgit v1.3 From 872b4d7ed0bd532e349d3c177a63d48e17d0bdb3 Mon Sep 17 00:00:00 2001 From: Mike Antipov Date: Wed, 28 Apr 2010 11:00:53 +0300 Subject: Fixed critical bug EXT-4837 ( [NUX] When filter results in null state, provide a message suggesting the user try global search.) Implemented passing of entered filter substring without head spaces to search URI in help message for null filtered results. * Updated setting "no item message" to use search term from filter editor for avatar & group lists and for inventory panels. * Updated appropriate translatable strings to get [SEARCH_TERM] substitution. * Updated processing of filter substring to pass original string to methods applied new filter. Additional necessary changes * Changed place to set "no item message" for group list from refresh to where filter is updated (like in avatar lists) * Removed converting of filter substring to upper case in Places & My Appearance sidepanels (this conversion has already been implemented in where filter is applied) * Added a separate message for Landmarks to set search URI to secondlife:///app/search/places for Lanmarks panel; other inventory related panels have URL to all searched categories (secondlife:///app/search/all) Reviewed by Vadim Savchuk at https://codereview.productengine.com/secondlife/r/326/ --HG-- branch : product-engine --- indra/llui/llflatlistview.cpp | 9 +++++++-- indra/llui/llflatlistview.h | 6 +++--- indra/newview/llavatarlist.cpp | 8 +++++--- indra/newview/llfolderview.cpp | 4 +++- indra/newview/llgrouplist.cpp | 13 ++++++++----- indra/newview/llinventoryfilter.cpp | 5 +++-- indra/newview/llinventoryfilter.h | 2 ++ indra/newview/llpanellandmarks.cpp | 1 + indra/newview/llpanelpeople.cpp | 20 ++++++++++++-------- indra/newview/llpanelpeople.h | 1 + indra/newview/llpanelplaces.cpp | 3 +-- indra/newview/llsidepanelappearance.cpp | 3 +-- indra/newview/skins/default/xui/en/panel_people.xml | 8 ++++---- indra/newview/skins/default/xui/en/strings.xml | 3 ++- 14 files changed, 53 insertions(+), 33 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index e0b2244654..ec247b25c3 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -1147,12 +1147,17 @@ LLFlatListViewEx::LLFlatListViewEx(const Params& p) } -void LLFlatListViewEx::updateNoItemsMessage(bool items_filtered) +void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) { + bool items_filtered = !filter_string.empty(); if (items_filtered) { // items were filtered - setNoItemsCommentText(mNoFilteredItemsMsg); + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter_string); + std::string text = mNoFilteredItemsMsg; + LLStringUtil::format(text, args); + setNoItemsCommentText(text); } else { diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index f7d094f7e7..4f718ab0dc 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -470,10 +470,10 @@ protected: /** * Applies a message for empty list depend on passed argument. * - * @param items_filtered - if true message for filtered items will be set, otherwise for - * completely empty list. + * @param filter_string - if is not empty, message for filtered items will be set, otherwise for + * completely empty list. Value of filter string will be passed as search_term in SLURL. */ - void updateNoItemsMessage(bool items_filtered); + void updateNoItemsMessage(const std::string& filter_string); private: std::string mNoFilteredItemsMsg; diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 8ba47b5198..e32daf55ca 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -176,13 +176,15 @@ void LLAvatarList::clear() void LLAvatarList::setNameFilter(const std::string& filter) { - if (mNameFilter != filter) + std::string filter_upper = filter; + LLStringUtil::toUpper(filter_upper); + if (mNameFilter != filter_upper) { - mNameFilter = filter; + mNameFilter = filter_upper; // update message for empty state here instead of refresh() to avoid blinking when switch // between tabs. - updateNoItemsMessage(!mNameFilter.empty()); + updateNoItemsMessage(filter); setDirty(); } } diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index c492bfcef1..eba4cdfa31 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -946,7 +946,9 @@ void LLFolderView::draw() } else { - mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage()); + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(getFilter()->getFilterSubStringOrig()); + mStatusText = LLTrans::getString(getFilter()->getEmptyLookupMessage(), args); //font->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } mStatusTextBox->setValue(mStatusText); diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index f21b6e1085..252c34cf9c 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -131,9 +131,15 @@ BOOL LLGroupList::handleRightMouseDown(S32 x, S32 y, MASK mask) void LLGroupList::setNameFilter(const std::string& filter) { - if (mNameFilter != filter) + std::string filter_upper = filter; + LLStringUtil::toUpper(filter_upper); + if (mNameFilter != filter_upper) { - mNameFilter = filter; + mNameFilter = filter_upper; + + // set no items message depend on filter state + updateNoItemsMessage(filter); + setDirty(); } } @@ -151,9 +157,6 @@ void LLGroupList::refresh() LLUUID id; bool have_filter = !mNameFilter.empty(); - // set no items message depend on filter state & total count of groups - updateNoItemsMessage(have_filter); - clear(); for(S32 i = 0; i < count; ++i) diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 1a488175ac..901a570487 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -329,9 +329,10 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) // appending new characters const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString); - mFilterSubString = string; + mFilterSubStringOrig = string; + LLStringUtil::trimHead(mFilterSubStringOrig); + mFilterSubString = mFilterSubStringOrig; LLStringUtil::toUpper(mFilterSubString); - LLStringUtil::trimHead(mFilterSubString); if (less_restrictive) { setModified(FILTER_LESS_RESTRICTIVE); diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index b01554edc8..2376ba5d22 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -84,6 +84,7 @@ public: void setFilterSubString(const std::string& string); const std::string& getFilterSubString(BOOL trim = FALSE) const; + const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; } BOOL hasFilterString() const; void setFilterPermissions(PermissionMask perms); @@ -181,6 +182,7 @@ private: std::string::size_type mSubStringMatchOffset; std::string mFilterSubString; + std::string mFilterSubStringOrig; const std::string mName; S32 mFilterGeneration; diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 67d40a39b1..0a978d1b26 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -583,6 +583,7 @@ void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list if (!inventory_list->getFilter()) return; + inventory_list->getFilter()->setEmptyLookupMessage("PlacesNoMatchingItems"); inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK); inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2)); diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index f60951ca66..f2c0f92f9b 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -443,6 +443,7 @@ public: LLPanelPeople::LLPanelPeople() : LLPanel(), mFilterSubString(LLStringUtil::null), + mFilterSubStringOrig(LLStringUtil::null), mFilterEditor(NULL), mTabContainer(NULL), mOnlineFriendList(NULL), @@ -658,7 +659,9 @@ void LLPanelPeople::updateFriendListHelpText() { //update help text for empty lists std::string message_name = mFilterSubString.empty() ? "no_friends_msg" : "no_filtered_friends_msg"; - no_friends_text->setText(getString(message_name)); + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(mFilterSubStringOrig); + no_friends_text->setText(getString(message_name, args)); } } @@ -981,10 +984,11 @@ bool LLPanelPeople::isRealGroup() void LLPanelPeople::onFilterEdit(const std::string& search_string) { - std::string search_upper = search_string; + mFilterSubStringOrig = search_string; + LLStringUtil::trimHead(mFilterSubStringOrig); // Searches are case-insensitive + std::string search_upper = mFilterSubStringOrig; LLStringUtil::toUpper(search_upper); - LLStringUtil::trimHead(search_upper); if (mFilterSubString == search_upper) return; @@ -999,11 +1003,11 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) // Apply new filter. - mNearbyList->setNameFilter(mFilterSubString); - mOnlineFriendList->setNameFilter(mFilterSubString); - mAllFriendList->setNameFilter(mFilterSubString); - mRecentList->setNameFilter(mFilterSubString); - mGroupList->setNameFilter(mFilterSubString); + mNearbyList->setNameFilter(mFilterSubStringOrig); + mOnlineFriendList->setNameFilter(mFilterSubStringOrig); + mAllFriendList->setNameFilter(mFilterSubStringOrig); + mRecentList->setNameFilter(mFilterSubStringOrig); + mGroupList->setNameFilter(mFilterSubStringOrig); setAccordionCollapsedByUser("tab_online", false); setAccordionCollapsedByUser("tab_all", false); diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h index 1bd3ea471c..17c45a034b 100644 --- a/indra/newview/llpanelpeople.h +++ b/indra/newview/llpanelpeople.h @@ -169,6 +169,7 @@ private: Updater* mRecentListUpdater; std::string mFilterSubString; + std::string mFilterSubStringOrig; }; #endif //LL_LLPANELPEOPLE_H diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 89293d0e50..51a11e97e4 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -528,8 +528,7 @@ void LLPanelPlaces::onFilterEdit(const std::string& search_string, bool force_fi std::string string = search_string; // Searches are case-insensitive - LLStringUtil::toUpper(string); - LLStringUtil::trimHead(string); + // but we don't convert the typed string to upper-case so that it can be fed to the web search as-is. mActivePanel->onSearchEdit(string); } diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index 87494daaa9..f38df19de0 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -197,8 +197,7 @@ void LLSidepanelAppearance::onFilterEdit(const std::string& search_string) mFilterSubString = search_string; // Searches are case-insensitive - LLStringUtil::toUpper(mFilterSubString); - LLStringUtil::trimHead(mFilterSubString); + // but we don't convert the typed string to upper-case so that it can be fed to the web search as-is. mPanelOutfitsInventory->onSearchEdit(mFilterSubString); } diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index fa4213667b..066ea3be6e 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -16,13 +16,13 @@ value="No recent people. Looking for people to hang out with? Try [secondlife:///app/search/people Search] or the [secondlife:///app/worldmap World Map]." /> + value="Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search]." /> + value="Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search]." /> @@ -36,7 +36,7 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M - Didn't find what you're looking for? Try [secondlife:///app/search/people Search]. + Didn't find what you're looking for? Try [secondlife:///app/search/people/[SEARCH_TERM] Search]. + value="Didn't find what you're looking for? Try [secondlife:///app/search/groups/[SEARCH_TERM] Search]." /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index bf30e89a59..b0e43e72ed 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1842,7 +1842,8 @@ Clears (deletes) the media and all params from the given face. Press ESC to return to World View - Didn't find what you're looking for? Try [secondlife:///app/search/all Search]. + Didn't find what you're looking for? Try [secondlife:///app/search/all/[SEARCH_TERM] Search]. + Didn't find what you're looking for? Try [secondlife:///app/search/places/[SEARCH_TERM] Search]. Drag a landmark here to add it to your favorites. You do not have a copy of this texture in your inventory -- cgit v1.3 From d6edc4cd12c015003cd665028b69a7b34b3aa54f Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Fri, 30 Apr 2010 18:27:24 +0300 Subject: Implemented normal EXT-7002 (Inventory flat list needs optimization.): - changed the LLInventoryItemsList::addNewItem() to add item to the list without immediately rearranging - implemented LLFlatListViewEx::setFilterSubString(), sets up new filter string and filters the list. - implemented LLFlatListViewEx::filterItems(), filters the list, rearranges and notifies parent about shape changes. The list items are filtered using the notify() functionality, without need in adding/removing them on each filter call. It sends 'match_filter' request to items and interprets the returned zero as sign of matched filter string, i.e. we don't hide items that don't support 'match_filter' action(separators etc). - filtring of LLOutfitsList. Reviewed by Mike Antipov at https://codereview.productengine.com/secondlife/r/342/ --HG-- branch : product-engine --- indra/llui/llflatlistview.cpp | 160 ++++++++++++++++++++++++++------- indra/llui/llflatlistview.h | 17 +++- indra/newview/llinventoryitemslist.cpp | 58 ++++++++++-- indra/newview/llinventoryitemslist.h | 26 ++++-- indra/newview/lloutfitslist.cpp | 28 ++++++ 5 files changed, 240 insertions(+), 49 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index ec247b25c3..bea2572ff8 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -297,6 +297,27 @@ void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) mNoItemsCommentTextbox->setValue(comment_text); } +U32 LLFlatListView::size(const bool only_visible_items) const +{ + if (only_visible_items) + { + U32 size = 0; + for (pairs_const_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + if ((*iter)->first->getVisible()) + ++size; + } + return size; + } + else + { + return mItemPairs.size(); + } +} + void LLFlatListView::clear() { // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. @@ -426,7 +447,7 @@ void LLFlatListView::rearrangeItems() { static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - setNoItemsCommentVisible(mItemPairs.empty()); + setNoItemsCommentVisible(0==size()); if (mItemPairs.empty()) return; @@ -745,19 +766,43 @@ LLRect LLFlatListView::getLastSelectedItemRect() void LLFlatListView::selectFirstItem () { // No items - no actions! - if (mItemPairs.empty()) return; + if (0 == size()) return; - selectItemPair(mItemPairs.front(), true); - ensureSelectedVisible(); + // Select first visible item + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + // skip invisible items + if ( (*iter)->first->getVisible() ) + { + selectItemPair(*iter, true); + ensureSelectedVisible(); + break; + } + } } void LLFlatListView::selectLastItem () { // No items - no actions! - if (mItemPairs.empty()) return; + if (0 == size()) return; - selectItemPair(mItemPairs.back(), true); - ensureSelectedVisible(); + // Select last visible item + for (pairs_list_t::reverse_iterator + r_iter = mItemPairs.rbegin(), + r_iter_end = mItemPairs.rend(); + r_iter != r_iter_end; ++r_iter) + { + // skip invisible items + if ( (*r_iter)->first->getVisible() ) + { + selectItemPair(*r_iter, true); + ensureSelectedVisible(); + break; + } + } } void LLFlatListView::ensureSelectedVisible() @@ -775,14 +820,14 @@ void LLFlatListView::ensureSelectedVisible() bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection) { // No items - no actions! - if ( !mItemPairs.size() ) + if ( 0 == size() ) return false; - - item_pair_t* to_sel_pair = NULL; - item_pair_t* cur_sel_pair = NULL; if ( mSelectedItemPairs.size() ) { + item_pair_t* to_sel_pair = NULL; + item_pair_t* cur_sel_pair = NULL; + // Take the last selected pair cur_sel_pair = mSelectedItemPairs.back(); // Bases on given direction choose next item to select @@ -816,42 +861,42 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti } } } + + if ( to_sel_pair ) + { + bool select = true; + if ( reset_selection ) + { + // Reset current selection if we were asked about it + resetSelection(); + } + else + { + // If item already selected and no reset request than we should deselect last selected item. + select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); + } + // Select/Deselect next item + selectItemPair(select ? to_sel_pair : cur_sel_pair, select); + return true; + } } else { // If there weren't selected items then choose the first one bases on given direction - cur_sel_pair = (is_up_direction) ? mItemPairs.back() : mItemPairs.front(); // Force selection to first item - to_sel_pair = cur_sel_pair; - } - - - if ( to_sel_pair ) - { - bool select = true; - - if ( reset_selection ) - { - // Reset current selection if we were asked about it - resetSelection(); - } + if (is_up_direction) + selectLastItem(); else - { - // If item already selected and no reset request than we should deselect last selected item. - select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); - } - - // Select/Deselect next item - selectItemPair(select ? to_sel_pair : cur_sel_pair, select); - + selectFirstItem(); return true; } + return false; } BOOL LLFlatListView::canSelectAll() const { - return !mItemPairs.empty() && mAllowSelection && mMultipleSelection; + return 0 != size() && mAllowSelection && mMultipleSelection; } void LLFlatListView::selectAll() @@ -1167,4 +1212,51 @@ void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) } +void LLFlatListViewEx::setFilterSubString(const std::string& filter_str) +{ + if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) + { + mFilterSubString = filter_str; + updateNoItemsMessage(mFilterSubString); + filterItems(); + } +} + +void LLFlatListViewEx::filterItems() +{ + typedef std::vector item_panel_list_t; + + std::string cur_filter = mFilterSubString; + LLStringUtil::toUpper(cur_filter); + + LLSD action; + action.with("match_filter", cur_filter); + + item_panel_list_t items; + getItems(items); + + for (item_panel_list_t::iterator + iter = items.begin(), + iter_end = items.end(); + iter != iter_end; ++iter) + { + LLPanel* pItem = (*iter); + // 0 signifies that filter is matched, + // i.e. we don't hide items that don't support 'match_filter' action, separators etc. + if (0 == pItem->notify(action)) + { + pItem->setVisible(true); + } + else + { + // TODO: implement (re)storing of current selection. + selectItem(pItem, false); + pItem->setVisible(false); + } + } + + rearrangeItems(); + notifyParentItemsRectChanged(); +} + //EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 4f718ab0dc..6395805aab 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -264,9 +264,8 @@ public: /** Get number of selected items in the list */ U32 numSelected() const {return mSelectedItemPairs.size(); } - /** Get number of items in the list */ - U32 size() const { return mItemPairs.size(); } - + /** Get number of (visible) items in the list */ + U32 size(const bool only_visible_items = true) const; /** Removes all items from the list */ virtual void clear(); @@ -464,6 +463,17 @@ public: void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + /** + * Sets up new filter string and filters the list. + */ + void setFilterSubString(const std::string& filter_str); + + /** + * Filters the list, rearranges and notifies parent about shape changes. + * Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration. + */ + void filterItems(); + protected: LLFlatListViewEx(const Params& p); @@ -478,6 +488,7 @@ protected: private: std::string mNoFilteredItemsMsg; std::string mNoItemsMsg; + std::string mFilterSubString; }; #endif diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp index 8dfdb0788a..9719de4650 100644 --- a/indra/newview/llinventoryitemslist.cpp +++ b/indra/newview/llinventoryitemslist.cpp @@ -45,6 +45,7 @@ #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "lltextutil.h" +#include "lltrans.h" //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -63,6 +64,16 @@ LLPanelInventoryListItemBase* LLPanelInventoryListItemBase::create(LLViewerInven return list_item; } +void LLPanelInventoryListItemBase::draw() +{ + if (getNeedsRefresh()) + { + updateItem(); + setNeedsRefresh(false); + } + LLPanel::draw(); +} + void LLPanelInventoryListItemBase::updateItem() { setIconImage(mIconImage); @@ -121,7 +132,7 @@ BOOL LLPanelInventoryListItemBase::postBuild() mIconImage = get_item_icon(mItem->getType(), mItem->getInventoryType(), mItem->getFlags(), FALSE); - updateItem(); + setNeedsRefresh(true); setWidgetsVisible(false); reshapeWidgets(); @@ -148,6 +159,34 @@ void LLPanelInventoryListItemBase::onMouseLeave(S32 x, S32 y, MASK mask) LLPanel::onMouseLeave(x, y, mask); } +S32 LLPanelInventoryListItemBase::notify(const LLSD& info) +{ + S32 rv = 0; + if(info.has("match_filter")) + { + mHighlightedText = info["match_filter"].asString(); + + std::string test(mItem->getName()); + LLStringUtil::toUpper(test); + + if(mHighlightedText.empty() || std::string::npos != test.find(mHighlightedText)) + { + rv = 0; // substring is found + } + else + { + rv = -1; + } + + setNeedsRefresh(true); + } + else + { + rv = LLPanel::notify(info); + } + return rv; +} + LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem* item) : LLPanel() , mItem(item) @@ -156,6 +195,7 @@ LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem , mWidgetSpacing(WIDGET_SPACING) , mLeftWidgetsWidth(0) , mRightWidgetsWidth(0) +, mNeedsRefresh(false) { } @@ -278,13 +318,15 @@ LLInventoryItemsList::Params::Params() {} LLInventoryItemsList::LLInventoryItemsList(const LLInventoryItemsList::Params& p) -: LLFlatListView(p) +: LLFlatListViewEx(p) , mNeedsRefresh(false) { // TODO: mCommitOnSelectionChange is set to "false" in LLFlatListView // but reset to true in all derived classes. This settings might need to // be added to LLFlatListView::Params() and/or set to "true" by default. setCommitOnSelectionChange(true); + + setNoFilteredItemsMsg(LLTrans::getString("InventoryNoMatchingItems")); } // virtual @@ -304,7 +346,7 @@ void LLInventoryItemsList::refreshList(const LLInventoryModel::item_array_t item void LLInventoryItemsList::draw() { - LLFlatListView::draw(); + LLFlatListViewEx::draw(); if(mNeedsRefresh) { refresh(); @@ -332,7 +374,8 @@ void LLInventoryItemsList::refresh() break; } LLViewerInventoryItem* item = gInventory.getItem(*it); - addNewItem(item); + // Do not rearrange items on each adding, let's do that on filter call + addNewItem(item, false); ++nadded; } @@ -342,6 +385,9 @@ void LLInventoryItemsList::refresh() removeItemByUUID(*it); } + // Filter, rearrange and notify parent about shape changes + filterItems(); + bool needs_refresh = add_limit_exceeded; setNeedsRefresh(needs_refresh); } @@ -363,7 +409,7 @@ void LLInventoryItemsList::computeDifference( LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved); } -void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item) +void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item, bool rearrange /*= true*/) { if (!item) { @@ -375,7 +421,7 @@ void LLInventoryItemsList::addNewItem(LLViewerInventoryItem* item) if (!list_item) return; - bool is_item_added = addItem(list_item, item->getUUID()); + bool is_item_added = addItem(list_item, item->getUUID(), ADD_BOTTOM, rearrange); if (!is_item_added) { llwarns << "Couldn't add flat list item." << llendl; diff --git a/indra/newview/llinventoryitemslist.h b/indra/newview/llinventoryitemslist.h index 152aafbd7e..bc04eb6f5b 100644 --- a/indra/newview/llinventoryitemslist.h +++ b/indra/newview/llinventoryitemslist.h @@ -64,13 +64,16 @@ class LLViewerInventoryItem; class LLPanelInventoryListItemBase : public LLPanel { public: - static LLPanelInventoryListItemBase* create(LLViewerInventoryItem* item); + virtual void draw(); + /** - * Called after inventory item was updated, update panel widgets to reflect inventory changes. + * Let item know it need to be refreshed in next draw() */ - virtual void updateItem(); + void setNeedsRefresh(bool needs_refresh){ mNeedsRefresh = needs_refresh; } + + bool getNeedsRefresh(){ return mNeedsRefresh; } /** * Add widget to left side @@ -107,6 +110,11 @@ public: */ /*virtual*/ void setValue(const LLSD& value); + /** + * Handles filter request + */ + /*virtual*/ S32 notify(const LLSD& info); + /* Highlights item */ /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); /* Removes item highlight */ @@ -125,6 +133,11 @@ protected: */ virtual void init(); + /** + * Called after inventory item was updated, update panel widgets to reflect inventory changes. + */ + virtual void updateItem(); + /** setter for mIconCtrl */ void setIconCtrl(LLIconCtrl* icon) { mIconCtrl = icon; } /** setter for MTitleCtrl */ @@ -178,14 +191,15 @@ private: S32 mLeftWidgetsWidth; S32 mRightWidgetsWidth; + bool mNeedsRefresh; }; ////////////////////////////////////////////////////////////////////////// -class LLInventoryItemsList : public LLFlatListView +class LLInventoryItemsList : public LLFlatListViewEx { public: - struct Params : public LLInitParam::Block + struct Params : public LLInitParam::Block { Params(); }; @@ -225,7 +239,7 @@ protected: /** * Add an item to the list */ - virtual void addNewItem(LLViewerInventoryItem* item); + virtual void addNewItem(LLViewerInventoryItem* item, bool rearrange = true); private: uuid_vec_t mIDs; // IDs of items that were added in refreshList(). diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index b103ec45d0..18bd610dd9 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -245,6 +245,34 @@ void LLOutfitsList::performAction(std::string action) void LLOutfitsList::setFilterSubString(const std::string& string) { mFilterSubString = string; + + for (outfits_map_t::iterator + iter = mOutfitsMap.begin(), + iter_end = mOutfitsMap.end(); + iter != iter_end; ++iter) + { + LLAccordionCtrlTab* tab = iter->second; + if (tab) + { + LLWearableItemsList* list = dynamic_cast (tab->getAccordionView()); + if (list) + { + list->setFilterSubString(mFilterSubString); + } + + if(!mFilterSubString.empty()) + { + //store accordion tab state when filter is not empty + tab->notifyChildren(LLSD().with("action","store_state")); + tab->setDisplayChildren(true); + } + else + { + //restore accordion state after all those accodrion tab manipulations + tab->notifyChildren(LLSD().with("action","restore_state")); + } + } + } } ////////////////////////////////////////////////////////////////////////// -- cgit v1.3 From 582f6502ff755d3c86c1daa854425e29ae2654ba Mon Sep 17 00:00:00 2001 From: Eugene Mutavchi Date: Wed, 5 May 2010 14:23:22 +0300 Subject: Related to low EXT-6823 (Implement a possibility to select several residents by "Shift" button) - fix improved to keep order of multiple selection and to reset the inconsecutive selection. Reviewed by Richard Nelson at https://codereview.productengine.com/secondlife/r/238/ --HG-- branch : product-engine --- indra/llui/llflatlistview.cpp | 44 ++++++++++++++++++++++++++++++++++++------- indra/llui/llflatlistview.h | 2 ++ 2 files changed, 39 insertions(+), 7 deletions(-) (limited to 'indra/llui/llflatlistview.cpp') diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index bea2572ff8..6bd16c9ee6 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -379,6 +379,7 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p) , mCommitOnSelectionChange(false) , mPrevNotifyParentRect(LLRect()) , mNoItemsCommentTextbox(NULL) + , mIsConsecutiveSelection(false) { mBorderThickness = getBorderWidth(); @@ -536,6 +537,7 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) return; bool grab_items = false; + bool reverse = false; pairs_list_t pairs_to_select; // Pick out items from list between last selected and current clicked item_pair. @@ -547,6 +549,8 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) item_pair_t* cur = *iter; if (cur == last_selected_pair || cur == item_pair) { + // We've got reverse selection if last grabed item isn't a new selection. + reverse = grab_items && (cur != item_pair); grab_items = !grab_items; // Skip last selected and current clicked item pairs. continue; @@ -562,26 +566,35 @@ void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) } } - if (select_item) + if (reverse) { - pairs_to_select.push_back(item_pair); + pairs_to_select.reverse(); } + pairs_to_select.push_back(item_pair); + for (pairs_iterator_t iter = pairs_to_select.begin(), iter_end = pairs_to_select.end(); iter != iter_end; ++iter) { item_pair_t* pair_to_select = *iter; - selectItemPair(pair_to_select, true); + if (isSelected(pair_to_select)) + { + // Item was already selected but there is a need to keep order from last selected pair to new selection. + // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). + mSelectedItemPairs.remove(pair_to_select); + mSelectedItemPairs.push_back(pair_to_select); + } + else + { + selectItemPair(pair_to_select, true); + } } if (!select_item) { - // Item was already selected but there is a need to update last selected item and its border. - // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). - mSelectedItemPairs.remove(item_pair); - mSelectedItemPairs.push_back(item_pair); + // Update last selected item border. mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); } return; @@ -749,6 +762,8 @@ bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) // Stretch selected item rect to ensure it won't be clipped mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + // By default mark it as not consecutive selection + mIsConsecutiveSelection = false; return true; } @@ -823,6 +838,17 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti if ( 0 == size() ) return false; + if (!mIsConsecutiveSelection) + { + // Leave only one item selected if list has not consecutive selection + if (mSelectedItemPairs.size() && !reset_selection) + { + item_pair_t* cur_sel_pair = mSelectedItemPairs.back(); + resetSelection(); + selectItemPair (cur_sel_pair, true); + } + } + if ( mSelectedItemPairs.size() ) { item_pair_t* to_sel_pair = NULL; @@ -877,6 +903,8 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti } // Select/Deselect next item selectItemPair(select ? to_sel_pair : cur_sel_pair, select); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; return true; } } @@ -888,6 +916,8 @@ bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selecti selectLastItem(); else selectFirstItem(); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; return true; } diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 6395805aab..f4e0426f15 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -410,6 +410,8 @@ private: bool mKeepOneItemSelected; + bool mIsConsecutiveSelection; + /** All pairs of the list */ pairs_list_t mItemPairs; -- cgit v1.3