aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llfolderview.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llfolderview.cpp668
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
235BOOL 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
232BOOL LLFolderViewItem::getFiltered() 242BOOL 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.
338void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, 348void 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
370EInventorySortGroup 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
362BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) 376BOOL 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.
430BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL open, 444BOOL 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
448BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, 461BOOL 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
789void LLFolderViewItem::draw() 801void 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.
1678void LLFolderViewFolder::removeView(LLFolderViewItem* item) 1682void 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
1723void LLFolderViewFolder::resort(LLFolderViewItem* item) 1727void 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
1744bool LLFolderViewFolder::isTrash() 1733bool LLFolderViewFolder::isTrash()
@@ -1752,65 +1741,22 @@ bool LLFolderViewFolder::isTrash()
1752 1741
1753void LLFolderViewFolder::sortBy(U32 order) 1742void 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
1837void LLFolderViewFolder::setItemSortFunction(sort_order_f ordering) 1783void 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
1799EInventorySortGroup 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
1852BOOL LLFolderViewFolder::isMovable() 1818BOOL 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.
1918BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) 1884BOOL 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
1952void LLFolderViewFolder::requestArrange() 1920void 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
1962void LLFolderViewFolder::toggleOpen() 1940void LLFolderViewFolder::toggleOpen()
@@ -2002,11 +1980,11 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL open, ERecurseType recur
2002} 1980}
2003 1981
2004BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask, 1982BOOL 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
2215BOOL 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
2241LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children ) 2226LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children )
2242{ 2227{
@@ -2456,20 +2441,20 @@ LLFolderViewItem* LLFolderViewFolder::getPreviousFromChild( LLFolderViewItem* it
2456class LLSetItemSortFunction : public LLFolderViewFunctor 2441class LLSetItemSortFunction : public LLFolderViewFunctor
2457{ 2442{
2458public: 2443public:
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.
2470void LLSetItemSortFunction::doFolder(LLFolderViewFolder* folder) 2455void 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
3006void LLFolderView::sanitizeSelection() 2987void 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 4314bool LLInventorySort::updateSort(U32 order)
4311bool 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 4327bool LLInventorySort::operator()(LLFolderViewItem* a, LLFolderViewItem* b)
4325// of inventory items.
4326bool 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