diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llfolderview.cpp | 668 |
1 files changed, 355 insertions, 313 deletions
diff --git a/linden/indra/newview/llfolderview.cpp b/linden/indra/newview/llfolderview.cpp index 7bc9cd8..ff0ad3f 100644 --- a/linden/indra/newview/llfolderview.cpp +++ b/linden/indra/newview/llfolderview.cpp | |||
@@ -229,6 +229,16 @@ LLFolderViewItem* LLFolderViewItem::getPreviousOpenNode(BOOL include_children) | |||
229 | return itemp; | 229 | return itemp; |
230 | } | 230 | } |
231 | 231 | ||
232 | // is this item something we think we should be showing? | ||
233 | // for example, if we haven't gotten around to filtering it yet, then the answer is yes | ||
234 | // until we find out otherwise | ||
235 | BOOL LLFolderViewItem::potentiallyVisible() | ||
236 | { | ||
237 | // we haven't been checked against min required filter | ||
238 | // or we have and we passed | ||
239 | return getLastFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration() || getFiltered(); | ||
240 | } | ||
241 | |||
232 | BOOL LLFolderViewItem::getFiltered() | 242 | BOOL LLFolderViewItem::getFiltered() |
233 | { | 243 | { |
234 | return mFiltered && mLastFilterGeneration >= mRoot->getFilter()->getMinRequiredGeneration(); | 244 | return mFiltered && mLastFilterGeneration >= mRoot->getFilter()->getMinRequiredGeneration(); |
@@ -335,8 +345,7 @@ void LLFolderViewItem::setSelectionFromRoot(LLFolderViewItem* selection, | |||
335 | } | 345 | } |
336 | 346 | ||
337 | // helper function to change the selection from the root. | 347 | // helper function to change the selection from the root. |
338 | void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, | 348 | void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected) |
339 | BOOL selected) | ||
340 | { | 349 | { |
341 | getRoot()->changeSelection(selection, selected); | 350 | getRoot()->changeSelection(selection, selected); |
342 | } | 351 | } |
@@ -358,6 +367,11 @@ LLString LLFolderViewItem::getWidgetTag() const | |||
358 | return LL_FOLDER_VIEW_ITEM_TAG; | 367 | return LL_FOLDER_VIEW_ITEM_TAG; |
359 | } | 368 | } |
360 | 369 | ||
370 | EInventorySortGroup LLFolderViewItem::getSortGroup() | ||
371 | { | ||
372 | return SG_ITEM; | ||
373 | } | ||
374 | |||
361 | // addToFolder() returns TRUE if it succeeds. FALSE otherwise | 375 | // addToFolder() returns TRUE if it succeeds. FALSE otherwise |
362 | BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) | 376 | BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) |
363 | { | 377 | { |
@@ -427,8 +441,7 @@ void LLFolderViewItem::dirtyFilter() | |||
427 | // means 'deselect' for a leaf item. Do this optimization after | 441 | // means 'deselect' for a leaf item. Do this optimization after |
428 | // multiple selection is implemented to make sure it all plays nice | 442 | // multiple selection is implemented to make sure it all plays nice |
429 | // together. | 443 | // together. |
430 | BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL open, | 444 | BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL open, BOOL take_keyboard_focus) |
431 | BOOL take_keyboard_focus) | ||
432 | { | 445 | { |
433 | if( selection == this ) | 446 | if( selection == this ) |
434 | { | 447 | { |
@@ -445,8 +458,7 @@ BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL open, | |||
445 | return mIsSelected; | 458 | return mIsSelected; |
446 | } | 459 | } |
447 | 460 | ||
448 | BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, | 461 | BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selected) |
449 | BOOL selected) | ||
450 | { | 462 | { |
451 | if(selection == this && mIsSelected != selected) | 463 | if(selection == this && mIsSelected != selected) |
452 | { | 464 | { |
@@ -788,182 +800,174 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, | |||
788 | 800 | ||
789 | void LLFolderViewItem::draw() | 801 | void LLFolderViewItem::draw() |
790 | { | 802 | { |
791 | if( getVisible() ) | 803 | bool possibly_has_children = false; |
804 | bool up_to_date = mListener && mListener->isUpToDate(); | ||
805 | if((up_to_date && hasVisibleChildren() ) || // we fetched our children and some of them have passed the filter... | ||
806 | (!up_to_date && mListener && mListener->hasChildren())) // ...or we know we have children but haven't fetched them (doesn't obey filter) | ||
792 | { | 807 | { |
793 | bool possibly_has_children = false; | 808 | possibly_has_children = true; |
794 | bool up_to_date = mListener && mListener->isUpToDate(); | 809 | } |
795 | if((up_to_date && hasVisibleChildren() ) || // we fetched our children and some of them have passed the filter... | 810 | if(/*mControlLabel[0] != '\0' && */possibly_has_children) |
796 | (!up_to_date && mListener && mListener->hasChildren())) // ...or we know we have children but haven't fetched them (doesn't obey filter) | 811 | { |
797 | { | 812 | LLGLSTexture gls_texture; |
798 | possibly_has_children = true; | 813 | if (mArrowImage) |
799 | } | ||
800 | if(/*mControlLabel[0] != '\0' && */possibly_has_children) | ||
801 | { | 814 | { |
802 | LLGLSTexture gls_texture; | 815 | gl_draw_scaled_rotated_image(mIndentation, mRect.getHeight() - ARROW_SIZE - TEXT_PAD, |
803 | if (mArrowImage) | 816 | ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, mArrowImage, sFgColor); |
804 | { | ||
805 | gl_draw_scaled_rotated_image(mIndentation, mRect.getHeight() - ARROW_SIZE - TEXT_PAD, | ||
806 | ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, mArrowImage, sFgColor); | ||
807 | } | ||
808 | } | 817 | } |
818 | } | ||
809 | 819 | ||
810 | F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); | 820 | F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); |
811 | 821 | ||
812 | // If we have keyboard focus, draw selection filled | 822 | // If we have keyboard focus, draw selection filled |
813 | BOOL show_context = getRoot()->getShowSelectionContext(); | 823 | BOOL show_context = getRoot()->getShowSelectionContext(); |
814 | BOOL filled = show_context || (gFocusMgr.getKeyboardFocus() == getRoot()); | 824 | BOOL filled = show_context || (gFocusMgr.getKeyboardFocus() == getRoot()); |
815 | 825 | ||
816 | // always render "current" item, only render other selected items if | 826 | // always render "current" item, only render other selected items if |
817 | // mShowSingleSelection is FALSE | 827 | // mShowSingleSelection is FALSE |
818 | if( mIsSelected ) | 828 | if( mIsSelected ) |
829 | { | ||
830 | LLGLSNoTexture gls_no_texture; | ||
831 | LLColor4 bg_color = sHighlightBgColor; | ||
832 | //const S32 TRAILING_PAD = 5; // It just looks better with this. | ||
833 | if (!mIsCurSelection) | ||
819 | { | 834 | { |
820 | LLGLSNoTexture gls_no_texture; | 835 | // do time-based fade of extra objects |
821 | LLColor4 bg_color = sHighlightBgColor; | 836 | F32 fade_time = getRoot()->getSelectionFadeElapsedTime(); |
822 | //const S32 TRAILING_PAD = 5; // It just looks better with this. | 837 | if (getRoot()->getShowSingleSelection()) |
823 | if (!mIsCurSelection) | ||
824 | { | 838 | { |
825 | // do time-based fade of extra objects | 839 | // fading out |
826 | F32 fade_time = getRoot()->getSelectionFadeElapsedTime(); | 840 | bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, bg_color.mV[VALPHA], 0.f); |
827 | if (getRoot()->getShowSingleSelection()) | ||
828 | { | ||
829 | // fading out | ||
830 | bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, bg_color.mV[VALPHA], 0.f); | ||
831 | } | ||
832 | else | ||
833 | { | ||
834 | // fading in | ||
835 | bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]); | ||
836 | } | ||
837 | } | 841 | } |
842 | else | ||
843 | { | ||
844 | // fading in | ||
845 | bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]); | ||
846 | } | ||
847 | } | ||
838 | 848 | ||
849 | gl_rect_2d( | ||
850 | 0, | ||
851 | mRect.getHeight(), | ||
852 | mRect.getWidth() - 2, | ||
853 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD), | ||
854 | bg_color, filled); | ||
855 | if (mIsCurSelection) | ||
856 | { | ||
839 | gl_rect_2d( | 857 | gl_rect_2d( |
840 | 0, | 858 | 0, |
841 | mRect.getHeight(), | 859 | mRect.getHeight(), |
842 | mRect.getWidth() - 2, | 860 | mRect.getWidth() - 2, |
843 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD), | 861 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD), |
844 | bg_color, filled); | 862 | sHighlightFgColor, FALSE); |
845 | if (mIsCurSelection) | ||
846 | { | ||
847 | gl_rect_2d( | ||
848 | 0, | ||
849 | mRect.getHeight(), | ||
850 | mRect.getWidth() - 2, | ||
851 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD), | ||
852 | sHighlightFgColor, FALSE); | ||
853 | } | ||
854 | if (mRect.getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) | ||
855 | { | ||
856 | gl_rect_2d( | ||
857 | 0, | ||
858 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, | ||
859 | mRect.getWidth() - 2, | ||
860 | 2, | ||
861 | sHighlightFgColor, FALSE); | ||
862 | if (show_context) | ||
863 | { | ||
864 | gl_rect_2d( | ||
865 | 0, | ||
866 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, | ||
867 | mRect.getWidth() - 2, | ||
868 | 2, | ||
869 | sHighlightBgColor, TRUE); | ||
870 | } | ||
871 | } | ||
872 | } | 863 | } |
873 | if (mDragAndDropTarget) | 864 | if (mRect.getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) |
874 | { | 865 | { |
875 | LLGLSNoTexture gls_no_texture; | ||
876 | gl_rect_2d( | 866 | gl_rect_2d( |
877 | 0, | 867 | 0, |
878 | mRect.getHeight(), | 868 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, |
879 | mRect.getWidth() - 2, | 869 | mRect.getWidth() - 2, |
880 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD), | 870 | 2, |
881 | sHighlightBgColor, FALSE); | 871 | sHighlightFgColor, FALSE); |
882 | 872 | if (show_context) | |
883 | if (mRect.getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) | ||
884 | { | 873 | { |
885 | gl_rect_2d( | 874 | gl_rect_2d( |
886 | 0, | 875 | 0, |
887 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, | 876 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, |
888 | mRect.getWidth() - 2, | 877 | mRect.getWidth() - 2, |
889 | 2, | 878 | 2, |
890 | sHighlightBgColor, FALSE); | 879 | sHighlightBgColor, TRUE); |
891 | } | 880 | } |
892 | mDragAndDropTarget = FALSE; | ||
893 | } | 881 | } |
882 | } | ||
883 | if (mDragAndDropTarget) | ||
884 | { | ||
885 | LLGLSNoTexture gls_no_texture; | ||
886 | gl_rect_2d( | ||
887 | 0, | ||
888 | mRect.getHeight(), | ||
889 | mRect.getWidth() - 2, | ||
890 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD), | ||
891 | sHighlightBgColor, FALSE); | ||
894 | 892 | ||
895 | 893 | if (mRect.getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) | |
896 | if(mIcon) | ||
897 | { | 894 | { |
898 | gl_draw_image(mIndentation + ARROW_SIZE + TEXT_PAD, mRect.getHeight() - mIcon->getHeight(), mIcon); | 895 | gl_rect_2d( |
899 | mIcon->addTextureStats( (F32)(mIcon->getWidth() * mIcon->getHeight())); | 896 | 0, |
897 | llfloor(mRect.getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, | ||
898 | mRect.getWidth() - 2, | ||
899 | 2, | ||
900 | sHighlightBgColor, FALSE); | ||
900 | } | 901 | } |
902 | mDragAndDropTarget = FALSE; | ||
903 | } | ||
901 | 904 | ||
902 | if (!mLabel.empty()) | ||
903 | { | ||
904 | // highlight filtered text | ||
905 | BOOL debug_filters = getRoot()->getDebugFilters(); | ||
906 | LLColor4 color = ( (mIsSelected && filled) ? sHighlightFgColor : sFgColor ); | ||
907 | F32 right_x; | ||
908 | F32 y = (F32)mRect.getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; | ||
909 | 905 | ||
910 | if (debug_filters) | 906 | if(mIcon) |
911 | { | 907 | { |
912 | if (!getFiltered() && !possibly_has_children) | 908 | gl_draw_image(mIndentation + ARROW_SIZE + TEXT_PAD, mRect.getHeight() - mIcon->getHeight(), mIcon); |
913 | { | 909 | mIcon->addTextureStats( (F32)(mIcon->getWidth() * mIcon->getHeight())); |
914 | color.mV[VALPHA] *= 0.5f; | 910 | } |
915 | } | ||
916 | |||
917 | LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); | ||
918 | sSmallFont->renderUTF8(mStatusText, 0, text_left, y, filter_color, | ||
919 | LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, | ||
920 | S32_MAX, S32_MAX, &right_x, FALSE ); | ||
921 | text_left = right_x; | ||
922 | } | ||
923 | 911 | ||
924 | sFont->renderUTF8( mLabel, 0, text_left, y, color, | 912 | if (!mLabel.empty()) |
925 | LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, | 913 | { |
926 | S32_MAX, S32_MAX, &right_x, FALSE ); | 914 | // highlight filtered text |
927 | if (!mLabelSuffix.empty()) | 915 | BOOL debug_filters = getRoot()->getDebugFilters(); |
928 | { | 916 | LLColor4 color = ( (mIsSelected && filled) ? sHighlightFgColor : sFgColor ); |
929 | sFont->renderUTF8( mLabelSuffix, 0, right_x, y, LLColor4(0.75f, 0.85f, 0.85f, 1.f), | 917 | F32 right_x; |
930 | LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, | 918 | F32 y = (F32)mRect.getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; |
931 | S32_MAX, S32_MAX, &right_x, FALSE ); | ||
932 | } | ||
933 | 919 | ||
934 | if (mBoxImage.notNull() && mStringMatchOffset != LLString::npos) | 920 | if (debug_filters) |
921 | { | ||
922 | if (!getFiltered() && !possibly_has_children) | ||
935 | { | 923 | { |
936 | // don't draw backgrounds for zero-length strings | 924 | color.mV[VALPHA] *= 0.5f; |
937 | S32 filter_string_length = mRoot->getFilterSubString().size(); | ||
938 | if (filter_string_length > 0) | ||
939 | { | ||
940 | LLString combined_string = mLabel + mLabelSuffix; | ||
941 | S32 left = llround(text_left) + sFont->getWidth(combined_string, 0, mStringMatchOffset) - 1; | ||
942 | S32 right = left + sFont->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; | ||
943 | S32 bottom = llfloor(mRect.getHeight() - sFont->getLineHeight() - 3); | ||
944 | S32 top = mRect.getHeight(); | ||
945 | |||
946 | LLViewerImage::bindTexture(mBoxImage); | ||
947 | glColor4fv(sFilterBGColor.mV); | ||
948 | gl_segmented_rect_2d_tex(left, top, right, bottom, mBoxImage->getWidth(), mBoxImage->getHeight(), 16); | ||
949 | F32 match_string_left = text_left + sFont->getWidthF32(combined_string, 0, mStringMatchOffset); | ||
950 | F32 y = (F32)mRect.getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; | ||
951 | sFont->renderUTF8( combined_string, mStringMatchOffset, match_string_left, y, | ||
952 | sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, | ||
953 | filter_string_length, S32_MAX, &right_x, FALSE ); | ||
954 | } | ||
955 | } | 925 | } |
926 | |||
927 | LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); | ||
928 | sSmallFont->renderUTF8(mStatusText, 0, text_left, y, filter_color, | ||
929 | LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, | ||
930 | S32_MAX, S32_MAX, &right_x, FALSE ); | ||
931 | text_left = right_x; | ||
956 | } | 932 | } |
957 | 933 | ||
958 | if( sDebugRects ) | 934 | sFont->renderUTF8( mLabel, 0, text_left, y, color, |
935 | LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, | ||
936 | S32_MAX, S32_MAX, &right_x, FALSE ); | ||
937 | if (!mLabelSuffix.empty()) | ||
959 | { | 938 | { |
960 | drawDebugRect(); | 939 | sFont->renderUTF8( mLabelSuffix, 0, right_x, y, LLColor4(0.75f, 0.85f, 0.85f, 1.f), |
940 | LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, | ||
941 | S32_MAX, S32_MAX, &right_x, FALSE ); | ||
942 | } | ||
943 | |||
944 | if (mBoxImage.notNull() && mStringMatchOffset != LLString::npos) | ||
945 | { | ||
946 | // don't draw backgrounds for zero-length strings | ||
947 | S32 filter_string_length = mRoot->getFilterSubString().size(); | ||
948 | if (filter_string_length > 0) | ||
949 | { | ||
950 | LLString combined_string = mLabel + mLabelSuffix; | ||
951 | S32 left = llround(text_left) + sFont->getWidth(combined_string, 0, mStringMatchOffset) - 1; | ||
952 | S32 right = left + sFont->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; | ||
953 | S32 bottom = llfloor(mRect.getHeight() - sFont->getLineHeight() - 3); | ||
954 | S32 top = mRect.getHeight(); | ||
955 | |||
956 | LLViewerImage::bindTexture(mBoxImage); | ||
957 | glColor4fv(sFilterBGColor.mV); | ||
958 | gl_segmented_rect_2d_tex(left, top, right, bottom, mBoxImage->getWidth(), mBoxImage->getHeight(), 16); | ||
959 | F32 match_string_left = text_left + sFont->getWidthF32(combined_string, 0, mStringMatchOffset); | ||
960 | F32 y = (F32)mRect.getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; | ||
961 | sFont->renderUTF8( combined_string, mStringMatchOffset, match_string_left, y, | ||
962 | sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, | ||
963 | filter_string_length, S32_MAX, &right_x, FALSE ); | ||
964 | } | ||
961 | } | 965 | } |
962 | } | 966 | } |
963 | else if (mStatusText.size()) | 967 | |
968 | if( sDebugRects ) | ||
964 | { | 969 | { |
965 | // just draw status text | 970 | drawDebugRect(); |
966 | sFont->renderUTF8( mStatusText, 0, 0, 1, sFgColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, S32_MAX, S32_MAX, NULL, FALSE ); | ||
967 | } | 971 | } |
968 | } | 972 | } |
969 | 973 | ||
@@ -977,7 +981,6 @@ LLFolderViewFolder::LLFolderViewFolder( const LLString& name, LLViewerImage* ico | |||
977 | LLFolderView* root, | 981 | LLFolderView* root, |
978 | LLFolderViewEventListener* listener ): | 982 | LLFolderViewEventListener* listener ): |
979 | LLFolderViewItem( name, icon, 0, root, listener ), // 0 = no create time | 983 | LLFolderViewItem( name, icon, 0, root, listener ), // 0 = no create time |
980 | mSortFunction(sort_item_name), | ||
981 | mIsOpen(FALSE), | 984 | mIsOpen(FALSE), |
982 | mExpanderHighlighted(FALSE), | 985 | mExpanderHighlighted(FALSE), |
983 | mCurHeight(0.f), | 986 | mCurHeight(0.f), |
@@ -1246,7 +1249,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) | |||
1246 | } | 1249 | } |
1247 | 1250 | ||
1248 | // when applying a filter, matching folders get their contents downloaded first | 1251 | // when applying a filter, matching folders get their contents downloaded first |
1249 | if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && !gInventory.isCategoryComplete(mListener->getUUID())) | 1252 | if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) |
1250 | { | 1253 | { |
1251 | gInventory.startBackgroundFetch(mListener->getUUID()); | 1254 | gInventory.startBackgroundFetch(mListener->getUUID()); |
1252 | } | 1255 | } |
@@ -1667,7 +1670,8 @@ BOOL LLFolderViewFolder::removeItem(LLFolderViewItem* item) | |||
1667 | { | 1670 | { |
1668 | if(item->remove()) | 1671 | if(item->remove()) |
1669 | { | 1672 | { |
1670 | removeView(item); | 1673 | //RN: this seem unneccessary as remove() moves to trash |
1674 | //removeView(item); | ||
1671 | return TRUE; | 1675 | return TRUE; |
1672 | } | 1676 | } |
1673 | return FALSE; | 1677 | return FALSE; |
@@ -1677,7 +1681,7 @@ BOOL LLFolderViewFolder::removeItem(LLFolderViewItem* item) | |||
1677 | // listeners. | 1681 | // listeners. |
1678 | void LLFolderViewFolder::removeView(LLFolderViewItem* item) | 1682 | void LLFolderViewFolder::removeView(LLFolderViewItem* item) |
1679 | { | 1683 | { |
1680 | if (!item) | 1684 | if (!item || item->getParentFolder() != this) |
1681 | { | 1685 | { |
1682 | return; | 1686 | return; |
1683 | } | 1687 | } |
@@ -1722,23 +1726,8 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) | |||
1722 | // This is only called for renaming an object because it won't work for date | 1726 | // This is only called for renaming an object because it won't work for date |
1723 | void LLFolderViewFolder::resort(LLFolderViewItem* item) | 1727 | void LLFolderViewFolder::resort(LLFolderViewItem* item) |
1724 | { | 1728 | { |
1725 | std::sort(mItems.begin(), mItems.end(), *mSortFunction); | 1729 | std::sort(mItems.begin(), mItems.end(), mSortFunction); |
1726 | std::sort(mFolders.begin(), mFolders.end(), *mSortFunction); | 1730 | std::sort(mFolders.begin(), mFolders.end(), mSortFunction); |
1727 | //if(mItems.removeData(item)) | ||
1728 | //{ | ||
1729 | // mItems.addDataSorted(item); | ||
1730 | //} | ||
1731 | //else | ||
1732 | //{ | ||
1733 | // // This is an evil downcast. However, it's only doing | ||
1734 | // // pointer comparison to find if (which it should be ) the | ||
1735 | // // item is in the container, so it's pretty safe. | ||
1736 | // LLFolderViewFolder* f = reinterpret_cast<LLFolderViewFolder*>(item); | ||
1737 | // if(mFolders.removeData(f)) | ||
1738 | // { | ||
1739 | // mFolders.addDataSorted(f); | ||
1740 | // } | ||
1741 | //} | ||
1742 | } | 1731 | } |
1743 | 1732 | ||
1744 | bool LLFolderViewFolder::isTrash() | 1733 | bool LLFolderViewFolder::isTrash() |
@@ -1752,65 +1741,22 @@ bool LLFolderViewFolder::isTrash() | |||
1752 | 1741 | ||
1753 | void LLFolderViewFolder::sortBy(U32 order) | 1742 | void LLFolderViewFolder::sortBy(U32 order) |
1754 | { | 1743 | { |
1755 | BOOL sort_order_changed = FALSE; | 1744 | if (!mSortFunction.updateSort(order)) |
1756 | if (!(order & LLInventoryFilter::SO_DATE)) | ||
1757 | { | ||
1758 | if (mSortFunction != sort_item_name) | ||
1759 | { | ||
1760 | mSortFunction = sort_item_name; | ||
1761 | sort_order_changed = TRUE; | ||
1762 | } | ||
1763 | } | ||
1764 | else | ||
1765 | { | 1745 | { |
1766 | if (mSortFunction != sort_item_date) | 1746 | // No changes. |
1767 | { | 1747 | return; |
1768 | mSortFunction = sort_item_date; | ||
1769 | sort_order_changed = TRUE; | ||
1770 | } | ||
1771 | } | 1748 | } |
1772 | 1749 | ||
1750 | // Propegate this change to sub folders | ||
1773 | for (folders_t::iterator iter = mFolders.begin(); | 1751 | for (folders_t::iterator iter = mFolders.begin(); |
1774 | iter != mFolders.end();) | 1752 | iter != mFolders.end();) |
1775 | { | 1753 | { |
1776 | folders_t::iterator fit = iter++; | 1754 | folders_t::iterator fit = iter++; |
1777 | (*fit)->sortBy(order); | 1755 | (*fit)->sortBy(order); |
1778 | } | 1756 | } |
1779 | if (order & LLInventoryFilter::SO_FOLDERS_BY_NAME) | ||
1780 | { | ||
1781 | // sort folders by name if always by name | ||
1782 | std::sort(mFolders.begin(), mFolders.end(), sort_item_name); | ||
1783 | } | ||
1784 | else | ||
1785 | { | ||
1786 | // sort folders by the default sort ordering | ||
1787 | std::sort(mFolders.begin(), mFolders.end(), *mSortFunction); | ||
1788 | 1757 | ||
1789 | // however, if we are at the root of the inventory and we are sorting by date | 1758 | std::sort(mFolders.begin(), mFolders.end(), mSortFunction); |
1790 | if (mListener->getUUID() == gAgent.getInventoryRootID() && order & LLInventoryFilter::SO_DATE) | 1759 | std::sort(mItems.begin(), mItems.end(), mSortFunction); |
1791 | { | ||
1792 | // pull the trash folder and stick it on the end of the list | ||
1793 | LLFolderViewFolder *t = NULL; | ||
1794 | for (folders_t::iterator fit = mFolders.begin(); | ||
1795 | fit != mFolders.end(); ++fit) | ||
1796 | { | ||
1797 | if ((*fit)->isTrash()) | ||
1798 | { | ||
1799 | t = *fit; | ||
1800 | mFolders.erase(fit); | ||
1801 | break; | ||
1802 | } | ||
1803 | } | ||
1804 | if (t) | ||
1805 | { | ||
1806 | mFolders.push_back(t); | ||
1807 | } | ||
1808 | } | ||
1809 | } | ||
1810 | if (sort_order_changed) | ||
1811 | { | ||
1812 | std::sort(mItems.begin(), mItems.end(), *mSortFunction); | ||
1813 | } | ||
1814 | 1760 | ||
1815 | if (order & LLInventoryFilter::SO_DATE) | 1761 | if (order & LLInventoryFilter::SO_DATE) |
1816 | { | 1762 | { |
@@ -1834,19 +1780,39 @@ void LLFolderViewFolder::sortBy(U32 order) | |||
1834 | } | 1780 | } |
1835 | } | 1781 | } |
1836 | 1782 | ||
1837 | void LLFolderViewFolder::setItemSortFunction(sort_order_f ordering) | 1783 | void LLFolderViewFolder::setItemSortOrder(U32 ordering) |
1838 | { | 1784 | { |
1839 | mSortFunction = ordering; | 1785 | if (mSortFunction.updateSort(ordering)) |
1786 | { | ||
1787 | for (folders_t::iterator iter = mFolders.begin(); | ||
1788 | iter != mFolders.end();) | ||
1789 | { | ||
1790 | folders_t::iterator fit = iter++; | ||
1791 | (*fit)->setItemSortOrder(ordering); | ||
1792 | } | ||
1840 | 1793 | ||
1841 | for (folders_t::iterator iter = mFolders.begin(); | 1794 | std::sort(mFolders.begin(), mFolders.end(), mSortFunction); |
1842 | iter != mFolders.end();) | 1795 | std::sort(mItems.begin(), mItems.end(), mSortFunction); |
1796 | } | ||
1797 | } | ||
1798 | |||
1799 | EInventorySortGroup LLFolderViewFolder::getSortGroup() | ||
1800 | { | ||
1801 | if (isTrash()) | ||
1843 | { | 1802 | { |
1844 | folders_t::iterator fit = iter++; | 1803 | return SG_TRASH_FOLDER; |
1845 | (*fit)->setItemSortFunction(ordering); | ||
1846 | } | 1804 | } |
1847 | 1805 | ||
1848 | std::sort(mFolders.begin(), mFolders.end(), *mSortFunction); | 1806 | // Folders that can't be moved are 'system' folders. |
1849 | std::sort(mItems.begin(), mItems.end(), *mSortFunction); | 1807 | if( mListener ) |
1808 | { | ||
1809 | if( !(mListener->isItemMovable()) ) | ||
1810 | { | ||
1811 | return SG_SYSTEM_FOLDER; | ||
1812 | } | ||
1813 | } | ||
1814 | |||
1815 | return SG_NORMAL_FOLDER; | ||
1850 | } | 1816 | } |
1851 | 1817 | ||
1852 | BOOL LLFolderViewFolder::isMovable() | 1818 | BOOL LLFolderViewFolder::isMovable() |
@@ -1917,6 +1883,7 @@ BOOL LLFolderViewFolder::isRemovable() | |||
1917 | // this is an internal method used for adding items to folders. | 1883 | // this is an internal method used for adding items to folders. |
1918 | BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) | 1884 | BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) |
1919 | { | 1885 | { |
1886 | |||
1920 | items_t::iterator it = std::lower_bound( | 1887 | items_t::iterator it = std::lower_bound( |
1921 | mItems.begin(), | 1888 | mItems.begin(), |
1922 | mItems.end(), | 1889 | mItems.end(), |
@@ -1945,18 +1912,29 @@ BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) | |||
1945 | folder->setVisible(FALSE); | 1912 | folder->setVisible(FALSE); |
1946 | addChild( folder ); | 1913 | addChild( folder ); |
1947 | folder->dirtyFilter(); | 1914 | folder->dirtyFilter(); |
1948 | requestArrange(); | 1915 | // rearrange all descendants too, as our indentation level might have changed |
1916 | folder->requestArrange(TRUE); | ||
1949 | return TRUE; | 1917 | return TRUE; |
1950 | } | 1918 | } |
1951 | 1919 | ||
1952 | void LLFolderViewFolder::requestArrange() | 1920 | void LLFolderViewFolder::requestArrange(BOOL include_descendants) |
1953 | { | 1921 | { |
1954 | mLastArrangeGeneration = -1; | 1922 | mLastArrangeGeneration = -1; |
1955 | // flag all items up to root | 1923 | // flag all items up to root |
1956 | if (mParentFolder) | 1924 | if (mParentFolder && !mParentFolder->needsArrange()) |
1957 | { | 1925 | { |
1958 | mParentFolder->requestArrange(); | 1926 | mParentFolder->requestArrange(); |
1959 | } | 1927 | } |
1928 | |||
1929 | if (include_descendants) | ||
1930 | { | ||
1931 | for (folders_t::iterator iter = mFolders.begin(); | ||
1932 | iter != mFolders.end(); | ||
1933 | ++iter) | ||
1934 | { | ||
1935 | (*iter)->requestArrange(TRUE); | ||
1936 | } | ||
1937 | } | ||
1960 | } | 1938 | } |
1961 | 1939 | ||
1962 | void LLFolderViewFolder::toggleOpen() | 1940 | void LLFolderViewFolder::toggleOpen() |
@@ -2002,11 +1980,11 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL open, ERecurseType recur | |||
2002 | } | 1980 | } |
2003 | 1981 | ||
2004 | BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask, | 1982 | BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask, |
2005 | BOOL drop, | 1983 | BOOL drop, |
2006 | EDragAndDropType c_type, | 1984 | EDragAndDropType c_type, |
2007 | void* cargo_data, | 1985 | void* cargo_data, |
2008 | EAcceptance* accept, | 1986 | EAcceptance* accept, |
2009 | LLString& tooltip_msg) | 1987 | LLString& tooltip_msg) |
2010 | { | 1988 | { |
2011 | BOOL accepted = mListener && mListener->dragOrDrop(mask,drop,c_type,cargo_data); | 1989 | BOOL accepted = mListener && mListener->dragOrDrop(mask,drop,c_type,cargo_data); |
2012 | if (accepted) | 1990 | if (accepted) |
@@ -2218,16 +2196,13 @@ void LLFolderViewFolder::draw() | |||
2218 | } | 2196 | } |
2219 | 2197 | ||
2220 | LLFolderViewItem::draw(); | 2198 | LLFolderViewItem::draw(); |
2221 | if( mIsOpen ) | 2199 | |
2200 | // draw children if root folder, or any other folder that is open or animating to closed state | ||
2201 | if( getRoot() == this || (mIsOpen || mCurHeight != mTargetHeight )) | ||
2222 | { | 2202 | { |
2223 | LLView::draw(); | 2203 | LLView::draw(); |
2224 | } | 2204 | } |
2225 | 2205 | ||
2226 | // if (mExpanderHighlighted) | ||
2227 | // { | ||
2228 | // gl_rect_2d(mIndentation - TEXT_PAD, llfloor(mRect.getHeight() - TEXT_PAD), mIndentation + sFont->getWidth(mControlLabel) + TEXT_PAD, llfloor(mRect.getHeight() - sFont->getLineHeight() - TEXT_PAD), sFgColor, FALSE); | ||
2229 | // //sFont->renderUTF8( mControlLabel, 0, mIndentation, llfloor(mRect.getHeight() - sFont->getLineHeight() - TEXT_PAD), sFgColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, S32_MAX, S32_MAX, NULL, FALSE ); | ||
2230 | // } | ||
2231 | mExpanderHighlighted = FALSE; | 2206 | mExpanderHighlighted = FALSE; |
2232 | } | 2207 | } |
2233 | 2208 | ||
@@ -2237,6 +2212,16 @@ U32 LLFolderViewFolder::getCreationDate() const | |||
2237 | } | 2212 | } |
2238 | 2213 | ||
2239 | 2214 | ||
2215 | BOOL LLFolderViewFolder::potentiallyVisible() | ||
2216 | { | ||
2217 | // folder should be visible by it's own filter status | ||
2218 | return LLFolderViewItem::potentiallyVisible() | ||
2219 | // or one or more of its descendants have passed the minimum filter requirement | ||
2220 | || hasFilteredDescendants(mRoot->getFilter()->getMinRequiredGeneration()) | ||
2221 | // or not all of its descendants have been checked against minimum filter requirement | ||
2222 | || getCompletedFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration(); | ||
2223 | } | ||
2224 | |||
2240 | // this does prefix traversal, as folders are listed above their contents | 2225 | // this does prefix traversal, as folders are listed above their contents |
2241 | LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children ) | 2226 | LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children ) |
2242 | { | 2227 | { |
@@ -2456,20 +2441,20 @@ LLFolderViewItem* LLFolderViewFolder::getPreviousFromChild( LLFolderViewItem* it | |||
2456 | class LLSetItemSortFunction : public LLFolderViewFunctor | 2441 | class LLSetItemSortFunction : public LLFolderViewFunctor |
2457 | { | 2442 | { |
2458 | public: | 2443 | public: |
2459 | LLSetItemSortFunction(sort_order_f ordering) | 2444 | LLSetItemSortFunction(U32 ordering) |
2460 | : mSortFunction(ordering) {} | 2445 | : mSortOrder(ordering) {} |
2461 | virtual ~LLSetItemSortFunction() {} | 2446 | virtual ~LLSetItemSortFunction() {} |
2462 | virtual void doFolder(LLFolderViewFolder* folder); | 2447 | virtual void doFolder(LLFolderViewFolder* folder); |
2463 | virtual void doItem(LLFolderViewItem* item); | 2448 | virtual void doItem(LLFolderViewItem* item); |
2464 | 2449 | ||
2465 | sort_order_f mSortFunction; | 2450 | U32 mSortOrder; |
2466 | }; | 2451 | }; |
2467 | 2452 | ||
2468 | 2453 | ||
2469 | // Set the sort order. | 2454 | // Set the sort order. |
2470 | void LLSetItemSortFunction::doFolder(LLFolderViewFolder* folder) | 2455 | void LLSetItemSortFunction::doFolder(LLFolderViewFolder* folder) |
2471 | { | 2456 | { |
2472 | folder->setItemSortFunction(mSortFunction); | 2457 | folder->setItemSortOrder(mSortOrder); |
2473 | } | 2458 | } |
2474 | 2459 | ||
2475 | // Do nothing. | 2460 | // Do nothing. |
@@ -2696,6 +2681,7 @@ BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) | |||
2696 | folder->setVisible(FALSE); | 2681 | folder->setVisible(FALSE); |
2697 | addChild( folder ); | 2682 | addChild( folder ); |
2698 | folder->dirtyFilter(); | 2683 | folder->dirtyFilter(); |
2684 | folder->requestArrange(); | ||
2699 | return TRUE; | 2685 | return TRUE; |
2700 | } | 2686 | } |
2701 | 2687 | ||
@@ -2916,8 +2902,8 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL open, /* Flaw | |||
2916 | addToSelectionList(selection); | 2902 | addToSelectionList(selection); |
2917 | } | 2903 | } |
2918 | 2904 | ||
2919 | BOOL rv = LLFolderViewFolder::setSelection(selection, open, take_keyboard_focus); /* Flawfinder: ignore */ | 2905 | BOOL rv = LLFolderViewFolder::setSelection(selection, open, take_keyboard_focus); |
2920 | if(open) /* Flawfinder: ignore */ | 2906 | if(open && selection) |
2921 | { | 2907 | { |
2922 | selection->getParentFolder()->requestArrange(); | 2908 | selection->getParentFolder()->requestArrange(); |
2923 | } | 2909 | } |
@@ -2954,11 +2940,6 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) | |||
2954 | } | 2940 | } |
2955 | 2941 | ||
2956 | BOOL on_list = (item_iter != mSelectedItems.end()); | 2942 | BOOL on_list = (item_iter != mSelectedItems.end()); |
2957 | if (on_list && mSelectedItems.size() == 1) | ||
2958 | { | ||
2959 | // we are trying to select/deselect the only selected item | ||
2960 | return FALSE; | ||
2961 | } | ||
2962 | 2943 | ||
2963 | if(selected && !on_list) | 2944 | if(selected && !on_list) |
2964 | { | 2945 | { |
@@ -3005,48 +2986,46 @@ S32 LLFolderView::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* | |||
3005 | 2986 | ||
3006 | void LLFolderView::sanitizeSelection() | 2987 | void LLFolderView::sanitizeSelection() |
3007 | { | 2988 | { |
2989 | // store off current item in case it is automatically deselected | ||
2990 | // and we want to preserve context | ||
2991 | LLFolderViewItem* original_selected_item = getCurSelectedItem(); | ||
2992 | |||
3008 | std::vector<LLFolderViewItem*> items_to_remove; | 2993 | std::vector<LLFolderViewItem*> items_to_remove; |
3009 | selected_items_t::iterator item_iter; | 2994 | selected_items_t::iterator item_iter; |
3010 | for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) | 2995 | for (item_iter = mSelectedItems.begin(); item_iter != mSelectedItems.end(); ++item_iter) |
3011 | { | 2996 | { |
3012 | LLFolderViewItem* item = *item_iter; | 2997 | LLFolderViewItem* item = *item_iter; |
3013 | 2998 | ||
3014 | BOOL visible = item->getVisible(); | 2999 | // ensure that each ancestor is open and potentially passes filtering |
3000 | BOOL visible = item->potentiallyVisible(); // initialize from filter state for this item | ||
3001 | // modify with parent open and filters states | ||
3015 | LLFolderViewFolder* parent_folder = item->getParentFolder(); | 3002 | LLFolderViewFolder* parent_folder = item->getParentFolder(); |
3016 | while(visible && parent_folder) | 3003 | while(parent_folder) |
3017 | { | 3004 | { |
3018 | visible = visible && parent_folder->isOpen() && parent_folder->getVisible(); | 3005 | visible = visible && parent_folder->isOpen() && parent_folder->potentiallyVisible(); |
3019 | parent_folder = parent_folder->getParentFolder(); | 3006 | parent_folder = parent_folder->getParentFolder(); |
3020 | } | 3007 | } |
3021 | if (!visible || item->getNumSelectedDescendants() > 0) | 3008 | |
3009 | // deselect item if any ancestor is closed or didn't pass filter requirements. | ||
3010 | if (!visible) | ||
3022 | { | 3011 | { |
3023 | // only deselect self if not visible | 3012 | items_to_remove.push_back(item); |
3024 | // check to see if item failed the filter but was checked against most recent generation | 3013 | } |
3025 | if ((!item->getFiltered() && item->getLastFilterGeneration() >= getFilter()->getMinRequiredGeneration()) | ||
3026 | || (item->getParentFolder() && !item->getParentFolder()->isOpen())) | ||
3027 | { | ||
3028 | item->recursiveDeselect(TRUE); | ||
3029 | items_to_remove.push_back(item); | ||
3030 | } | ||
3031 | else | ||
3032 | { | ||
3033 | item->recursiveDeselect(FALSE); | ||
3034 | } | ||
3035 | 3014 | ||
3036 | selected_items_t::iterator other_item_iter; | 3015 | // disallow nested selections (i.e. folder items plus one or more ancestors) |
3037 | for (other_item_iter = mSelectedItems.begin(); other_item_iter != mSelectedItems.end(); ++other_item_iter) | 3016 | // could check cached mum selections count and only iterate if there are any |
3017 | // but that may be a premature optimization. | ||
3018 | selected_items_t::iterator other_item_iter; | ||
3019 | for (other_item_iter = mSelectedItems.begin(); other_item_iter != mSelectedItems.end(); ++other_item_iter) | ||
3020 | { | ||
3021 | LLFolderViewItem* other_item = *other_item_iter; | ||
3022 | for(LLFolderViewFolder* parent_folder = other_item->getParentFolder(); parent_folder; parent_folder = parent_folder->getParentFolder()) | ||
3038 | { | 3023 | { |
3039 | LLFolderViewItem* other_item = *other_item_iter; | 3024 | if (parent_folder == item) |
3040 | LLFolderViewFolder* parent_folder = other_item->getParentFolder(); | ||
3041 | while (parent_folder) | ||
3042 | { | 3025 | { |
3043 | if (parent_folder == item) | 3026 | // this is a descendent of the current folder, remove from list |
3044 | { | 3027 | items_to_remove.push_back(other_item); |
3045 | // this is a descendent of the current folder, remove from list | 3028 | break; |
3046 | items_to_remove.push_back(other_item); | ||
3047 | break; | ||
3048 | } | ||
3049 | parent_folder = parent_folder->getParentFolder(); | ||
3050 | } | 3029 | } |
3051 | } | 3030 | } |
3052 | } | 3031 | } |
@@ -3055,7 +3034,47 @@ void LLFolderView::sanitizeSelection() | |||
3055 | std::vector<LLFolderViewItem*>::iterator item_it; | 3034 | std::vector<LLFolderViewItem*>::iterator item_it; |
3056 | for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it ) | 3035 | for (item_it = items_to_remove.begin(); item_it != items_to_remove.end(); ++item_it ) |
3057 | { | 3036 | { |
3058 | removeFromSelectionList(*item_it); | 3037 | changeSelection(*item_it, FALSE); // toggle selection (also removes from list) |
3038 | } | ||
3039 | |||
3040 | // if nothing selected after prior constraints... | ||
3041 | if (mSelectedItems.empty()) | ||
3042 | { | ||
3043 | // ...select first available parent of original selection, or "My Inventory" otherwise | ||
3044 | LLFolderViewItem* new_selection = NULL; | ||
3045 | if (original_selected_item) | ||
3046 | { | ||
3047 | for(LLFolderViewFolder* parent_folder = original_selected_item->getParentFolder(); | ||
3048 | parent_folder; | ||
3049 | parent_folder = parent_folder->getParentFolder()) | ||
3050 | { | ||
3051 | if (parent_folder->potentiallyVisible()) | ||
3052 | { | ||
3053 | // give initial selection to first ancestor folder that potentially passes the filter | ||
3054 | if (!new_selection) | ||
3055 | { | ||
3056 | new_selection = parent_folder; | ||
3057 | } | ||
3058 | |||
3059 | // if any ancestor folder of original item is closed, move the selection up | ||
3060 | // to the highest closed | ||
3061 | if (!parent_folder->isOpen()) | ||
3062 | { | ||
3063 | new_selection = parent_folder; | ||
3064 | } | ||
3065 | } | ||
3066 | } | ||
3067 | } | ||
3068 | else | ||
3069 | { | ||
3070 | // nothing selected to start with, so pick "My Inventory" as best guess | ||
3071 | new_selection = getItemByID(gAgent.getInventoryRootID()); | ||
3072 | } | ||
3073 | |||
3074 | if (new_selection) | ||
3075 | { | ||
3076 | setSelection(new_selection, FALSE, FALSE); | ||
3077 | } | ||
3059 | } | 3078 | } |
3060 | } | 3079 | } |
3061 | 3080 | ||
@@ -3232,7 +3251,7 @@ void LLFolderView::removeSelectedItems( void ) | |||
3232 | // create a temporary structure which we will use to remove | 3251 | // create a temporary structure which we will use to remove |
3233 | // items, since the removal will futz with internal data | 3252 | // items, since the removal will futz with internal data |
3234 | // structures. | 3253 | // structures. |
3235 | LLDynamicArray<LLFolderViewItem*> items; | 3254 | std::vector<LLFolderViewItem*> items; |
3236 | S32 count = mSelectedItems.size(); | 3255 | S32 count = mSelectedItems.size(); |
3237 | if(count == 0) return; | 3256 | if(count == 0) return; |
3238 | LLFolderViewItem* item = NULL; | 3257 | LLFolderViewItem* item = NULL; |
@@ -3242,7 +3261,7 @@ void LLFolderView::removeSelectedItems( void ) | |||
3242 | item = *item_it; | 3261 | item = *item_it; |
3243 | if(item->isRemovable()) | 3262 | if(item->isRemovable()) |
3244 | { | 3263 | { |
3245 | items.put(item); | 3264 | items.push_back(item); |
3246 | } | 3265 | } |
3247 | else | 3266 | else |
3248 | { | 3267 | { |
@@ -3252,11 +3271,11 @@ void LLFolderView::removeSelectedItems( void ) | |||
3252 | } | 3271 | } |
3253 | 3272 | ||
3254 | // iterate through the new container. | 3273 | // iterate through the new container. |
3255 | count = items.count(); | 3274 | count = items.size(); |
3256 | LLUUID new_selection_id; | 3275 | LLUUID new_selection_id; |
3257 | if(count == 1) | 3276 | if(count == 1) |
3258 | { | 3277 | { |
3259 | LLFolderViewItem* item_to_delete = items.get(0); | 3278 | LLFolderViewItem* item_to_delete = items[0]; |
3260 | LLFolderViewFolder* parent = item_to_delete->getParentFolder(); | 3279 | LLFolderViewFolder* parent = item_to_delete->getParentFolder(); |
3261 | LLFolderViewItem* new_selection = item_to_delete->getNextOpenNode(FALSE); | 3280 | LLFolderViewItem* new_selection = item_to_delete->getNextOpenNode(FALSE); |
3262 | if (!new_selection) | 3281 | if (!new_selection) |
@@ -3284,7 +3303,7 @@ void LLFolderView::removeSelectedItems( void ) | |||
3284 | { | 3303 | { |
3285 | LLDynamicArray<LLFolderViewEventListener*> listeners; | 3304 | LLDynamicArray<LLFolderViewEventListener*> listeners; |
3286 | LLFolderViewEventListener* listener; | 3305 | LLFolderViewEventListener* listener; |
3287 | LLFolderViewItem* last_item = items.get(count - 1); | 3306 | LLFolderViewItem* last_item = items[count - 1]; |
3288 | LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); | 3307 | LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); |
3289 | while(new_selection && new_selection->isSelected()) | 3308 | while(new_selection && new_selection->isSelected()) |
3290 | { | 3309 | { |
@@ -3309,7 +3328,7 @@ void LLFolderView::removeSelectedItems( void ) | |||
3309 | 3328 | ||
3310 | for(S32 i = 0; i < count; ++i) | 3329 | for(S32 i = 0; i < count; ++i) |
3311 | { | 3330 | { |
3312 | listener = items.get(i)->getListener(); | 3331 | listener = items[i]->getListener(); |
3313 | if(listener && (listeners.find(listener) == LLDynamicArray<LLFolderViewEventListener*>::FAIL)) | 3332 | if(listener && (listeners.find(listener) == LLDynamicArray<LLFolderViewEventListener*>::FAIL)) |
3314 | { | 3333 | { |
3315 | listeners.put(listener); | 3334 | listeners.put(listener); |
@@ -3620,21 +3639,6 @@ void LLFolderView::setFocus(BOOL focus) | |||
3620 | { | 3639 | { |
3621 | if (focus) | 3640 | if (focus) |
3622 | { | 3641 | { |
3623 | // select "My Inventory" if nothing selected | ||
3624 | if (!getCurSelectedItem()) | ||
3625 | { | ||
3626 | LLFolderViewItem* itemp = getItemByID(gAgent.getInventoryRootID()); | ||
3627 | if (itemp) | ||
3628 | { | ||
3629 | setSelection(itemp, FALSE, FALSE); | ||
3630 | } | ||
3631 | } | ||
3632 | |||
3633 | if (mRenamer->getVisible()) | ||
3634 | { | ||
3635 | //RN: commit rename changes when focus is moved, only revert on ESC | ||
3636 | finishRenamingItem(); | ||
3637 | } | ||
3638 | if(!hasFocus()) | 3642 | if(!hasFocus()) |
3639 | { | 3643 | { |
3640 | gEditMenuHandler = this; | 3644 | gEditMenuHandler = this; |
@@ -3954,10 +3958,10 @@ BOOL LLFolderView::search(LLFolderViewItem* first_item, const LLString &search_s | |||
3954 | LLString::toUpper(upper_case_string); | 3958 | LLString::toUpper(upper_case_string); |
3955 | 3959 | ||
3956 | // if nothing selected, select first item in folder | 3960 | // if nothing selected, select first item in folder |
3957 | if (!first_item) | 3961 | if (!search_item) |
3958 | { | 3962 | { |
3959 | // start from first item | 3963 | // start from first item |
3960 | first_item = getNextFromChild(NULL); | 3964 | search_item = getNextFromChild(NULL); |
3961 | } | 3965 | } |
3962 | 3966 | ||
3963 | // search over all open nodes for first substring match (with wrapping) | 3967 | // search over all open nodes for first substring match (with wrapping) |
@@ -4248,8 +4252,6 @@ void LLFolderView::idle(void* user_data) | |||
4248 | // filter to determine visiblity before arranging | 4252 | // filter to determine visiblity before arranging |
4249 | self->filterFromRoot(); | 4253 | self->filterFromRoot(); |
4250 | 4254 | ||
4251 | self->sanitizeSelection(); | ||
4252 | |||
4253 | // automatically show matching items, and select first one | 4255 | // automatically show matching items, and select first one |
4254 | // do this every frame until user puts keyboard focus into the inventory window | 4256 | // do this every frame until user puts keyboard focus into the inventory window |
4255 | // signaling the end of the automatic update | 4257 | // signaling the end of the automatic update |
@@ -4269,6 +4271,8 @@ void LLFolderView::idle(void* user_data) | |||
4269 | self->scrollToShowSelection(); | 4271 | self->scrollToShowSelection(); |
4270 | } | 4272 | } |
4271 | 4273 | ||
4274 | self->sanitizeSelection(); | ||
4275 | |||
4272 | if( self->needsArrange() && self->isInVisibleChain()) | 4276 | if( self->needsArrange() && self->isInVisibleChain()) |
4273 | { | 4277 | { |
4274 | self->arrangeFromRoot(); | 4278 | self->arrangeFromRoot(); |
@@ -4307,33 +4311,71 @@ void LLFolderView::dumpSelectionInformation() | |||
4307 | ///---------------------------------------------------------------------------- | 4311 | ///---------------------------------------------------------------------------- |
4308 | /// Local function definitions | 4312 | /// Local function definitions |
4309 | ///---------------------------------------------------------------------------- | 4313 | ///---------------------------------------------------------------------------- |
4310 | 4314 | bool LLInventorySort::updateSort(U32 order) | |
4311 | bool sort_item_name(LLFolderViewItem* a, LLFolderViewItem* b) | ||
4312 | { | 4315 | { |
4313 | S32 compare = LLString::compareDict(a->getLabel(), b->getLabel()); | 4316 | if (order != mSortOrder) |
4314 | if (0 == compare) | ||
4315 | { | ||
4316 | return (a->getCreationDate() > b->getCreationDate()); | ||
4317 | } | ||
4318 | else | ||
4319 | { | 4317 | { |
4320 | return (compare < 0); | 4318 | mSortOrder = order; |
4319 | mByDate = (order & LLInventoryFilter::SO_DATE); | ||
4320 | mSystemToTop = (order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP); | ||
4321 | mFoldersByName = (order & LLInventoryFilter::SO_FOLDERS_BY_NAME); | ||
4322 | return true; | ||
4321 | } | 4323 | } |
4324 | return false; | ||
4322 | } | 4325 | } |
4323 | 4326 | ||
4324 | // BUG: This is very very slow. The getCreationDate() is log n in number | 4327 | bool LLInventorySort::operator()(LLFolderViewItem* a, LLFolderViewItem* b) |
4325 | // of inventory items. | ||
4326 | bool sort_item_date(LLFolderViewItem* a, LLFolderViewItem* b) | ||
4327 | { | 4328 | { |
4328 | U32 first_create = a->getCreationDate(); | 4329 | // We sort by name if we aren't sorting by date |
4329 | U32 second_create = b->getCreationDate(); | 4330 | // OR if these are folders and we are sorting folders by name. |
4330 | if (first_create == second_create) | 4331 | bool by_name = (!mByDate |
4332 | || (mFoldersByName | ||
4333 | && (a->getSortGroup() != SG_ITEM))); | ||
4334 | |||
4335 | if (a->getSortGroup() != b->getSortGroup()) | ||
4336 | { | ||
4337 | if (mSystemToTop) | ||
4338 | { | ||
4339 | // Group order is System Folders, Trash, Normal Folders, Items | ||
4340 | return (a->getSortGroup() < b->getSortGroup()); | ||
4341 | } | ||
4342 | else if (mByDate) | ||
4343 | { | ||
4344 | // Trash needs to go to the bottom if we are sorting by date | ||
4345 | if ( (a->getSortGroup() == SG_TRASH_FOLDER) | ||
4346 | || (b->getSortGroup() == SG_TRASH_FOLDER)) | ||
4347 | { | ||
4348 | return (b->getSortGroup() == SG_TRASH_FOLDER); | ||
4349 | } | ||
4350 | } | ||
4351 | } | ||
4352 | |||
4353 | if (by_name) | ||
4331 | { | 4354 | { |
4332 | return (LLString::compareDict(a->getLabel(), b->getLabel()) < 0); | 4355 | S32 compare = LLString::compareDict(a->getLabel(), b->getLabel()); |
4356 | if (0 == compare) | ||
4357 | { | ||
4358 | return (a->getCreationDate() > b->getCreationDate()); | ||
4359 | } | ||
4360 | else | ||
4361 | { | ||
4362 | return (compare < 0); | ||
4363 | } | ||
4333 | } | 4364 | } |
4334 | else | 4365 | else |
4335 | { | 4366 | { |
4336 | return (first_create > second_create); | 4367 | // BUG: This is very very slow. The getCreationDate() is log n in number |
4368 | // of inventory items. | ||
4369 | U32 first_create = a->getCreationDate(); | ||
4370 | U32 second_create = b->getCreationDate(); | ||
4371 | if (first_create == second_create) | ||
4372 | { | ||
4373 | return (LLString::compareDict(a->getLabel(), b->getLabel()) < 0); | ||
4374 | } | ||
4375 | else | ||
4376 | { | ||
4377 | return (first_create > second_create); | ||
4378 | } | ||
4337 | } | 4379 | } |
4338 | } | 4380 | } |
4339 | 4381 | ||