toolkit/components/filepicker/nsFileView.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsIFileView.h"
     7 #include "nsITreeView.h"
     8 #include "mozilla/ModuleUtils.h"
     9 #include "nsITreeSelection.h"
    10 #include "nsITreeColumns.h"
    11 #include "nsITreeBoxObject.h"
    12 #include "nsIFile.h"
    13 #include "nsString.h"
    14 #include "nsReadableUtils.h"
    15 #include "nsCRT.h"
    16 #include "nsPrintfCString.h"
    17 #include "nsIDateTimeFormat.h"
    18 #include "nsDateTimeFormatCID.h"
    19 #include "nsQuickSort.h"
    20 #include "nsIAtom.h"
    21 #include "nsIAutoCompleteResult.h"
    22 #include "nsIAutoCompleteSearch.h"
    23 #include "nsISimpleEnumerator.h"
    24 #include "nsAutoPtr.h"
    25 #include "nsIMutableArray.h"
    26 #include "nsTArray.h"
    27 #include "mozilla/Attributes.h"
    29 #include "nsWildCard.h"
    31 class nsIDOMDataTransfer;
    33 #define NS_FILECOMPLETE_CID { 0xcb60980e, 0x18a5, 0x4a77, \
    34                             { 0x91, 0x10, 0x81, 0x46, 0x61, 0x4c, 0xa7, 0xf0 } }
    35 #define NS_FILECOMPLETE_CONTRACTID "@mozilla.org/autocomplete/search;1?name=file"
    37 class nsFileResult MOZ_FINAL : public nsIAutoCompleteResult
    38 {
    39 public:
    40   // aSearchString is the text typed into the autocomplete widget
    41   // aSearchParam is the picker's currently displayed directory
    42   nsFileResult(const nsAString& aSearchString, const nsAString& aSearchParam);
    44   NS_DECL_ISUPPORTS
    45   NS_DECL_NSIAUTOCOMPLETERESULT
    47   nsTArray<nsString> mValues;
    48   nsAutoString mSearchString;
    49   uint16_t mSearchResult;
    50 };
    52 NS_IMPL_ISUPPORTS(nsFileResult, nsIAutoCompleteResult)
    54 nsFileResult::nsFileResult(const nsAString& aSearchString,
    55                            const nsAString& aSearchParam):
    56   mSearchString(aSearchString)
    57 {
    58   if (aSearchString.IsEmpty())
    59     mSearchResult = RESULT_IGNORED;
    60   else {
    61     int32_t slashPos = mSearchString.RFindChar('/');
    62     mSearchResult = RESULT_FAILURE;
    63     nsCOMPtr<nsIFile> directory;
    64     nsDependentSubstring parent(Substring(mSearchString, 0, slashPos + 1));
    65     if (!parent.IsEmpty() && parent.First() == '/')
    66       NS_NewLocalFile(parent, true, getter_AddRefs(directory));
    67     if (!directory) {
    68       if (NS_FAILED(NS_NewLocalFile(aSearchParam, true, getter_AddRefs(directory))))
    69         return;
    70       if (slashPos > 0)
    71         directory->AppendRelativePath(Substring(mSearchString, 0, slashPos));
    72     }
    73     nsCOMPtr<nsISimpleEnumerator> dirEntries;
    74     if (NS_FAILED(directory->GetDirectoryEntries(getter_AddRefs(dirEntries))))
    75       return;
    76     mSearchResult = RESULT_NOMATCH;
    77     bool hasMore = false;
    78     nsDependentSubstring prefix(Substring(mSearchString, slashPos + 1));
    79     while (NS_SUCCEEDED(dirEntries->HasMoreElements(&hasMore)) && hasMore) {
    80       nsCOMPtr<nsISupports> nextItem;
    81       dirEntries->GetNext(getter_AddRefs(nextItem));
    82       nsCOMPtr<nsIFile> nextFile(do_QueryInterface(nextItem));
    83       nsAutoString fileName;
    84       nextFile->GetLeafName(fileName);
    85       if (StringBeginsWith(fileName, prefix)) {
    86         fileName.Insert(parent, 0);
    87         if (mSearchResult == RESULT_NOMATCH && fileName.Equals(mSearchString))
    88           mSearchResult = RESULT_IGNORED;
    89         else
    90           mSearchResult = RESULT_SUCCESS;
    91         bool isDirectory = false;
    92         nextFile->IsDirectory(&isDirectory);
    93         if (isDirectory)
    94           fileName.Append('/');
    95         mValues.AppendElement(fileName);
    96       }
    97     }
    98     mValues.Sort();
    99   }
   100 }
   102 NS_IMETHODIMP nsFileResult::GetSearchString(nsAString & aSearchString)
   103 {
   104   aSearchString.Assign(mSearchString);
   105   return NS_OK;
   106 }
   108 NS_IMETHODIMP nsFileResult::GetSearchResult(uint16_t *aSearchResult)
   109 {
   110   NS_ENSURE_ARG_POINTER(aSearchResult);
   111   *aSearchResult = mSearchResult;
   112   return NS_OK;
   113 }
   115 NS_IMETHODIMP nsFileResult::GetDefaultIndex(int32_t *aDefaultIndex)
   116 {
   117   NS_ENSURE_ARG_POINTER(aDefaultIndex);
   118   *aDefaultIndex = -1;
   119   return NS_OK;
   120 }
   122 NS_IMETHODIMP nsFileResult::GetErrorDescription(nsAString & aErrorDescription)
   123 {
   124   aErrorDescription.Truncate();
   125   return NS_OK;
   126 }
   128 NS_IMETHODIMP nsFileResult::GetMatchCount(uint32_t *aMatchCount)
   129 {
   130   NS_ENSURE_ARG_POINTER(aMatchCount);
   131   *aMatchCount = mValues.Length();
   132   return NS_OK;
   133 }
   135 NS_IMETHODIMP nsFileResult::GetTypeAheadResult(bool *aTypeAheadResult)
   136 {
   137   NS_ENSURE_ARG_POINTER(aTypeAheadResult);
   138   *aTypeAheadResult = false;
   139   return NS_OK;
   140 }
   142 NS_IMETHODIMP nsFileResult::GetValueAt(int32_t index, nsAString & aValue)
   143 {
   144   aValue = mValues[index];
   145   if (aValue.Last() == '/')
   146     aValue.Truncate(aValue.Length() - 1);
   147   return NS_OK;
   148 }
   150 NS_IMETHODIMP nsFileResult::GetLabelAt(int32_t index, nsAString & aValue)
   151 {
   152   return GetValueAt(index, aValue);
   153 }
   155 NS_IMETHODIMP nsFileResult::GetCommentAt(int32_t index, nsAString & aComment)
   156 {
   157   aComment.Truncate();
   158   return NS_OK;
   159 }
   161 NS_IMETHODIMP nsFileResult::GetStyleAt(int32_t index, nsAString & aStyle)
   162 {
   163   if (mValues[index].Last() == '/')
   164     aStyle.AssignLiteral("directory");
   165   else
   166     aStyle.AssignLiteral("file");
   167   return NS_OK;
   168 }
   170 NS_IMETHODIMP nsFileResult::GetImageAt(int32_t index, nsAString & aImage)
   171 {
   172   aImage.Truncate();
   173   return NS_OK;
   174 }
   175 NS_IMETHODIMP nsFileResult::GetFinalCompleteValueAt(int32_t index,
   176                                                     nsAString & aValue)
   177 {
   178   return GetValueAt(index, aValue);
   179 }
   181 NS_IMETHODIMP nsFileResult::RemoveValueAt(int32_t rowIndex, bool removeFromDb)
   182 {
   183   return NS_OK;
   184 }
   186 class nsFileComplete MOZ_FINAL : public nsIAutoCompleteSearch
   187 {
   188 public:
   189   NS_DECL_ISUPPORTS
   190   NS_DECL_NSIAUTOCOMPLETESEARCH
   191 };
   193 NS_IMPL_ISUPPORTS(nsFileComplete, nsIAutoCompleteSearch)
   195 NS_IMETHODIMP
   196 nsFileComplete::StartSearch(const nsAString& aSearchString,
   197                             const nsAString& aSearchParam,
   198                             nsIAutoCompleteResult *aPreviousResult,
   199                             nsIAutoCompleteObserver *aListener)
   200 {
   201   NS_ENSURE_ARG_POINTER(aListener);
   202   nsRefPtr<nsFileResult> result = new nsFileResult(aSearchString, aSearchParam);
   203   NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
   204   return aListener->OnSearchResult(this, result);
   205 }
   207 NS_IMETHODIMP
   208 nsFileComplete::StopSearch()
   209 {
   210   return NS_OK;
   211 }
   213 #define NS_FILEVIEW_CID { 0xa5570462, 0x1dd1, 0x11b2, \
   214                          { 0x9d, 0x19, 0xdf, 0x30, 0xa2, 0x7f, 0xbd, 0xc4 } }
   216 class nsFileView : public nsIFileView,
   217                    public nsITreeView
   218 {
   219 public:
   220   nsFileView();
   221   nsresult Init();
   223   NS_DECL_ISUPPORTS
   224   NS_DECL_NSIFILEVIEW
   225   NS_DECL_NSITREEVIEW
   227 protected:
   228   virtual ~nsFileView();
   230   void FilterFiles();
   231   void ReverseArray(nsTArray<nsCOMPtr<nsIFile> >& aArray);
   232   void SortArray(nsTArray<nsCOMPtr<nsIFile> >& aArray);
   233   void SortInternal();
   235   nsTArray<nsCOMPtr<nsIFile> > mFileList;
   236   nsTArray<nsCOMPtr<nsIFile> > mDirList;
   237   nsTArray<nsCOMPtr<nsIFile> > mFilteredFiles;
   239   nsCOMPtr<nsIFile> mDirectoryPath;
   240   nsCOMPtr<nsITreeBoxObject> mTree;
   241   nsCOMPtr<nsITreeSelection> mSelection;
   242   nsCOMPtr<nsIDateTimeFormat> mDateFormatter;
   244   int16_t mSortType;
   245   int32_t mTotalRows;
   247   nsTArray<char16_t*> mCurrentFilters;
   249   bool mShowHiddenFiles;
   250   bool mDirectoryFilter;
   251   bool mReverseSort;
   252 };
   254 // Factory constructor
   255 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFileComplete)
   256 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFileView, Init)
   257 NS_DEFINE_NAMED_CID(NS_FILECOMPLETE_CID);
   258 NS_DEFINE_NAMED_CID(NS_FILEVIEW_CID);
   260 static const mozilla::Module::CIDEntry kFileViewCIDs[] = {
   261   { &kNS_FILECOMPLETE_CID, false, nullptr, nsFileCompleteConstructor },
   262   { &kNS_FILEVIEW_CID, false, nullptr, nsFileViewConstructor },
   263   { nullptr }
   264 };
   266 static const mozilla::Module::ContractIDEntry kFileViewContracts[] = {
   267   { NS_FILECOMPLETE_CONTRACTID, &kNS_FILECOMPLETE_CID },
   268   { NS_FILEVIEW_CONTRACTID, &kNS_FILEVIEW_CID },
   269   { nullptr }
   270 };
   272 static const mozilla::Module kFileViewModule = {
   273   mozilla::Module::kVersion,
   274   kFileViewCIDs,
   275   kFileViewContracts
   276 };
   278 NSMODULE_DEFN(nsFileViewModule) = &kFileViewModule;
   280 nsFileView::nsFileView() :
   281   mSortType(-1),
   282   mTotalRows(0),
   283   mShowHiddenFiles(false),
   284   mDirectoryFilter(false),
   285   mReverseSort(false)
   286 {
   287 }
   289 nsFileView::~nsFileView()
   290 {
   291   uint32_t count = mCurrentFilters.Length();
   292   for (uint32_t i = 0; i < count; ++i)
   293     NS_Free(mCurrentFilters[i]);
   294 }
   296 nsresult
   297 nsFileView::Init()
   298 {
   299   mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID);
   300   if (!mDateFormatter)
   301     return NS_ERROR_OUT_OF_MEMORY;
   303   return NS_OK;
   304 }
   306 // nsISupports implementation
   308 NS_IMPL_ISUPPORTS(nsFileView, nsITreeView, nsIFileView)
   310 // nsIFileView implementation
   312 NS_IMETHODIMP
   313 nsFileView::SetShowHiddenFiles(bool aShowHidden)
   314 {
   315   if (aShowHidden != mShowHiddenFiles) {
   316     mShowHiddenFiles = aShowHidden;
   318     // This could be better optimized, but since the hidden
   319     // file functionality is not currently used, this will be fine.
   320     SetDirectory(mDirectoryPath);
   321   }
   323   return NS_OK;
   324 }
   326 NS_IMETHODIMP
   327 nsFileView::GetShowHiddenFiles(bool* aShowHidden)
   328 {
   329   *aShowHidden = mShowHiddenFiles;
   330   return NS_OK;
   331 }
   333 NS_IMETHODIMP
   334 nsFileView::SetShowOnlyDirectories(bool aOnlyDirs)
   335 {
   336   if (aOnlyDirs == mDirectoryFilter)
   337     return NS_OK;
   339   mDirectoryFilter = aOnlyDirs;
   340   uint32_t dirCount = mDirList.Length();
   341   if (mDirectoryFilter) {
   342     int32_t rowDiff = mTotalRows - dirCount;
   344     mFilteredFiles.Clear();
   345     mTotalRows = dirCount;
   346     if (mTree)
   347       mTree->RowCountChanged(mTotalRows, -rowDiff);
   348   } else {
   349     // Run the filter again to get the file list back
   350     FilterFiles();
   352     SortArray(mFilteredFiles);
   353     if (mReverseSort)
   354       ReverseArray(mFilteredFiles);
   356     if (mTree)
   357       mTree->RowCountChanged(dirCount, mTotalRows - dirCount);
   358   }
   360   return NS_OK;
   361 }
   363 NS_IMETHODIMP
   364 nsFileView::GetShowOnlyDirectories(bool* aOnlyDirs)
   365 {
   366   *aOnlyDirs = mDirectoryFilter;
   367   return NS_OK;
   368 }
   370 NS_IMETHODIMP
   371 nsFileView::GetSortType(int16_t* aSortType)
   372 {
   373   *aSortType = mSortType;
   374   return NS_OK;
   375 }
   377 NS_IMETHODIMP
   378 nsFileView::GetReverseSort(bool* aReverseSort)
   379 {
   380   *aReverseSort = mReverseSort;
   381   return NS_OK;
   382 }
   384 NS_IMETHODIMP
   385 nsFileView::Sort(int16_t aSortType, bool aReverseSort)
   386 {
   387   if (aSortType == mSortType) {
   388     if (aReverseSort == mReverseSort)
   389       return NS_OK;
   391     mReverseSort = aReverseSort;
   392     ReverseArray(mDirList);
   393     ReverseArray(mFilteredFiles);
   394   } else {
   395     mSortType = aSortType;
   396     mReverseSort = aReverseSort;
   397     SortInternal();
   398   }
   400   if (mTree)
   401     mTree->Invalidate();
   403   return NS_OK;
   404 }
   406 NS_IMETHODIMP
   407 nsFileView::SetDirectory(nsIFile* aDirectory)
   408 {
   409   NS_ENSURE_ARG_POINTER(aDirectory);
   411   nsCOMPtr<nsISimpleEnumerator> dirEntries;
   412   aDirectory->GetDirectoryEntries(getter_AddRefs(dirEntries));
   414   if (!dirEntries) {
   415     // Couldn't read in the directory, this can happen if the user does not
   416     // have permission to list it.
   417     return NS_ERROR_FAILURE;
   418   }
   420   mDirectoryPath = aDirectory;
   421   mFileList.Clear();
   422   mDirList.Clear();
   424   bool hasMore = false;
   426   while (NS_SUCCEEDED(dirEntries->HasMoreElements(&hasMore)) && hasMore) {
   427     nsCOMPtr<nsISupports> nextItem;
   428     dirEntries->GetNext(getter_AddRefs(nextItem));
   429     nsCOMPtr<nsIFile> theFile = do_QueryInterface(nextItem);
   431     bool isDirectory = false;
   432     if (theFile) {
   433       theFile->IsDirectory(&isDirectory);
   435       if (isDirectory) {
   436         bool isHidden;
   437         theFile->IsHidden(&isHidden);
   438         if (mShowHiddenFiles || !isHidden) {
   439           mDirList.AppendElement(theFile);
   440         }
   441       }
   442       else {
   443         mFileList.AppendElement(theFile);
   444       }
   445     }
   446   }
   448   if (mTree) {
   449     mTree->BeginUpdateBatch();
   450     mTree->RowCountChanged(0, -mTotalRows);
   451   }
   453   FilterFiles();
   454   SortInternal();
   456   if (mTree) {
   457     mTree->EndUpdateBatch();
   458     mTree->ScrollToRow(0);
   459   }
   461   return NS_OK;
   462 }
   464 NS_IMETHODIMP
   465 nsFileView::SetFilter(const nsAString& aFilterString)
   466 {
   467   uint32_t filterCount = mCurrentFilters.Length();
   468   for (uint32_t i = 0; i < filterCount; ++i)
   469     NS_Free(mCurrentFilters[i]);
   470   mCurrentFilters.Clear();
   472   nsAString::const_iterator start, iter, end;
   473   aFilterString.BeginReading(iter);
   474   aFilterString.EndReading(end);
   476   while (true) {
   477     // skip over delimiters
   478     while (iter != end && (*iter == ';' || *iter == ' '))
   479       ++iter;
   481     if (iter == end)
   482       break;
   484     start = iter; // start of a filter
   486     // we know this is neither ';' nor ' ', skip to next char
   487     ++iter;
   489     // find next delimiter or end of string
   490     while (iter != end && (*iter != ';' && *iter != ' '))
   491       ++iter;
   493     char16_t* filter = ToNewUnicode(Substring(start, iter));
   494     if (!filter)
   495       return NS_ERROR_OUT_OF_MEMORY;
   497     if (!mCurrentFilters.AppendElement(filter)) {
   498       NS_Free(filter);
   499       return NS_ERROR_OUT_OF_MEMORY;
   500     }
   502     if (iter == end)
   503       break;
   505     ++iter; // we know this is either ';' or ' ', skip to next char
   506   }
   508   if (mTree) {
   509     mTree->BeginUpdateBatch();
   510     uint32_t count = mDirList.Length();
   511     mTree->RowCountChanged(count, count - mTotalRows);
   512   }
   514   mFilteredFiles.Clear();
   516   FilterFiles();
   518   SortArray(mFilteredFiles);
   519   if (mReverseSort)
   520     ReverseArray(mFilteredFiles);
   522   if (mTree)
   523     mTree->EndUpdateBatch();
   525   return NS_OK;
   526 }
   528 NS_IMETHODIMP
   529 nsFileView::GetSelectedFiles(nsIArray** aFiles)
   530 {
   531   *aFiles = nullptr;
   532   if (!mSelection)
   533     return NS_OK;
   535   int32_t numRanges;
   536   mSelection->GetRangeCount(&numRanges);
   538   uint32_t dirCount = mDirList.Length();
   539   nsCOMPtr<nsIMutableArray> fileArray =
   540     do_CreateInstance(NS_ARRAY_CONTRACTID);
   541   NS_ENSURE_STATE(fileArray);
   543   for (int32_t range = 0; range < numRanges; ++range) {
   544     int32_t rangeBegin, rangeEnd;
   545     mSelection->GetRangeAt(range, &rangeBegin, &rangeEnd);
   547     for (int32_t itemIndex = rangeBegin; itemIndex <= rangeEnd; ++itemIndex) {
   548       nsIFile* curFile = nullptr;
   550       if (itemIndex < (int32_t) dirCount)
   551         curFile = mDirList[itemIndex];
   552       else {
   553         if (itemIndex < mTotalRows)
   554           curFile = mFilteredFiles[itemIndex - dirCount];
   555       }
   557       if (curFile)
   558         fileArray->AppendElement(curFile, false);
   559     }
   560   }
   562   NS_ADDREF(*aFiles = fileArray);
   563   return NS_OK;
   564 }
   567 // nsITreeView implementation
   569 NS_IMETHODIMP
   570 nsFileView::GetRowCount(int32_t* aRowCount)
   571 {
   572   *aRowCount = mTotalRows;
   573   return NS_OK;
   574 }
   576 NS_IMETHODIMP
   577 nsFileView::GetSelection(nsITreeSelection** aSelection)
   578 {
   579   *aSelection = mSelection;
   580   NS_IF_ADDREF(*aSelection);
   581   return NS_OK;
   582 }
   584 NS_IMETHODIMP
   585 nsFileView::SetSelection(nsITreeSelection* aSelection)
   586 {
   587   mSelection = aSelection;
   588   return NS_OK;
   589 }
   591 NS_IMETHODIMP
   592 nsFileView::GetRowProperties(int32_t aIndex, nsAString& aProps)
   593 {
   594   return NS_OK;
   595 }
   597 NS_IMETHODIMP
   598 nsFileView::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
   599                               nsAString& aProps)
   600 {
   601   uint32_t dirCount = mDirList.Length();
   603   if (aRow < (int32_t) dirCount)
   604     aProps.AppendLiteral("directory");
   605   else if (aRow < mTotalRows)
   606     aProps.AppendLiteral("file");
   608   return NS_OK;
   609 }
   611 NS_IMETHODIMP
   612 nsFileView::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
   613 {
   614   return NS_OK;
   615 }
   617 NS_IMETHODIMP
   618 nsFileView::IsContainer(int32_t aIndex, bool* aIsContainer)
   619 {
   620   *aIsContainer = false;
   621   return NS_OK;
   622 }
   624 NS_IMETHODIMP
   625 nsFileView::IsContainerOpen(int32_t aIndex, bool* aIsOpen)
   626 {
   627   *aIsOpen = false;
   628   return NS_OK;
   629 }
   631 NS_IMETHODIMP
   632 nsFileView::IsContainerEmpty(int32_t aIndex, bool* aIsEmpty)
   633 {
   634   *aIsEmpty = false;
   635   return NS_OK;
   636 }
   638 NS_IMETHODIMP
   639 nsFileView::IsSeparator(int32_t aIndex, bool* aIsSeparator)
   640 {
   641   *aIsSeparator = false;
   642   return NS_OK;
   643 }
   645 NS_IMETHODIMP
   646 nsFileView::IsSorted(bool* aIsSorted)
   647 {
   648   *aIsSorted = (mSortType >= 0);
   649   return NS_OK;
   650 }
   652 NS_IMETHODIMP
   653 nsFileView::CanDrop(int32_t aIndex, int32_t aOrientation,
   654                     nsIDOMDataTransfer* dataTransfer, bool* aCanDrop)
   655 {
   656   *aCanDrop = false;
   657   return NS_OK;
   658 }
   660 NS_IMETHODIMP
   661 nsFileView::Drop(int32_t aRow, int32_t aOrientation, nsIDOMDataTransfer* dataTransfer)
   662 {
   663   return NS_OK;
   664 }
   666 NS_IMETHODIMP
   667 nsFileView::GetParentIndex(int32_t aRowIndex, int32_t* aParentIndex)
   668 {
   669   *aParentIndex = -1;
   670   return NS_OK;
   671 }
   673 NS_IMETHODIMP
   674 nsFileView::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, 
   675                            bool* aHasSibling)
   676 {
   677   *aHasSibling = (aAfterIndex < (mTotalRows - 1));
   678   return NS_OK;
   679 }
   681 NS_IMETHODIMP
   682 nsFileView::GetLevel(int32_t aIndex, int32_t* aLevel)
   683 {
   684   *aLevel = 0;
   685   return NS_OK;
   686 }
   688 NS_IMETHODIMP
   689 nsFileView::GetImageSrc(int32_t aRow, nsITreeColumn* aCol,
   690                         nsAString& aImageSrc)
   691 {
   692   return NS_OK;
   693 }
   695 NS_IMETHODIMP
   696 nsFileView::GetProgressMode(int32_t aRow, nsITreeColumn* aCol,
   697                             int32_t* aProgressMode)
   698 {
   699   return NS_OK;
   700 }
   702 NS_IMETHODIMP
   703 nsFileView::GetCellValue(int32_t aRow, nsITreeColumn* aCol,
   704                          nsAString& aCellValue)
   705 {
   706   return NS_OK;
   707 }
   709 NS_IMETHODIMP
   710 nsFileView::GetCellText(int32_t aRow, nsITreeColumn* aCol,
   711                         nsAString& aCellText)
   712 {
   713   uint32_t dirCount = mDirList.Length();
   714   bool isDirectory;
   715   nsIFile* curFile = nullptr;
   717   if (aRow < (int32_t) dirCount) {
   718     isDirectory = true;
   719     curFile = mDirList[aRow];
   720   } else if (aRow < mTotalRows) {
   721     isDirectory = false;
   722     curFile = mFilteredFiles[aRow - dirCount];
   723   } else {
   724     // invalid row
   725     aCellText.SetCapacity(0);
   726     return NS_OK;
   727   }
   729   const char16_t* colID;
   730   aCol->GetIdConst(&colID);
   731   if (NS_LITERAL_STRING("FilenameColumn").Equals(colID)) {
   732     curFile->GetLeafName(aCellText);
   733   } else if (NS_LITERAL_STRING("LastModifiedColumn").Equals(colID)) {
   734     PRTime lastModTime;
   735     curFile->GetLastModifiedTime(&lastModTime);
   736     // XXX FormatPRTime could take an nsAString&
   737     nsAutoString temp;
   738     mDateFormatter->FormatPRTime(nullptr, kDateFormatShort, kTimeFormatSeconds,
   739                                  lastModTime * 1000, temp);
   740     aCellText = temp;
   741   } else {
   742     // file size
   743     if (isDirectory)
   744       aCellText.SetCapacity(0);
   745     else {
   746       int64_t fileSize;
   747       curFile->GetFileSize(&fileSize);
   748       CopyUTF8toUTF16(nsPrintfCString("%lld", fileSize), aCellText);
   749     }
   750   }
   752   return NS_OK;
   753 }
   755 NS_IMETHODIMP
   756 nsFileView::SetTree(nsITreeBoxObject* aTree)
   757 {
   758   mTree = aTree;
   759   return NS_OK;
   760 }
   762 NS_IMETHODIMP
   763 nsFileView::ToggleOpenState(int32_t aIndex)
   764 {
   765   return NS_OK;
   766 }
   768 NS_IMETHODIMP
   769 nsFileView::CycleHeader(nsITreeColumn* aCol)
   770 {
   771   return NS_OK;
   772 }
   774 NS_IMETHODIMP
   775 nsFileView::SelectionChanged()
   776 {
   777   return NS_OK;
   778 }
   780 NS_IMETHODIMP
   781 nsFileView::CycleCell(int32_t aRow, nsITreeColumn* aCol)
   782 {
   783   return NS_OK;
   784 }
   786 NS_IMETHODIMP
   787 nsFileView::IsEditable(int32_t aRow, nsITreeColumn* aCol,
   788                        bool* aIsEditable)
   789 {
   790   *aIsEditable = false;
   791   return NS_OK;
   792 }
   794 NS_IMETHODIMP
   795 nsFileView::IsSelectable(int32_t aRow, nsITreeColumn* aCol,
   796                          bool* aIsSelectable)
   797 {
   798   *aIsSelectable = false;
   799   return NS_OK;
   800 }
   802 NS_IMETHODIMP
   803 nsFileView::SetCellValue(int32_t aRow, nsITreeColumn* aCol,
   804                          const nsAString& aValue)
   805 {
   806   return NS_OK;
   807 }
   809 NS_IMETHODIMP
   810 nsFileView::SetCellText(int32_t aRow, nsITreeColumn* aCol,
   811                         const nsAString& aValue)
   812 {
   813   return NS_OK;
   814 }
   816 NS_IMETHODIMP
   817 nsFileView::PerformAction(const char16_t* aAction)
   818 {
   819   return NS_OK;
   820 }
   822 NS_IMETHODIMP
   823 nsFileView::PerformActionOnRow(const char16_t* aAction, int32_t aRow)
   824 {
   825   return NS_OK;
   826 }
   828 NS_IMETHODIMP
   829 nsFileView::PerformActionOnCell(const char16_t* aAction, int32_t aRow,
   830                                 nsITreeColumn* aCol)
   831 {
   832   return NS_OK;
   833 }
   835 // Private methods
   837 void
   838 nsFileView::FilterFiles()
   839 {
   840   uint32_t count = mDirList.Length();
   841   mTotalRows = count;
   842   count = mFileList.Length();
   843   mFilteredFiles.Clear();
   844   uint32_t filterCount = mCurrentFilters.Length();
   846   for (uint32_t i = 0; i < count; ++i) {
   847     nsIFile* file = mFileList[i];
   848     bool isHidden = false;
   849     if (!mShowHiddenFiles)
   850       file->IsHidden(&isHidden);
   852     nsAutoString ucsLeafName;
   853     if(NS_FAILED(file->GetLeafName(ucsLeafName))) {
   854       // need to check return value for GetLeafName()
   855       continue;
   856     }
   858     if (!isHidden) {
   859       for (uint32_t j = 0; j < filterCount; ++j) {
   860         bool matched = false;
   861         if (!nsCRT::strcmp(mCurrentFilters.ElementAt(j),
   862                            MOZ_UTF16("..apps")))
   863         {
   864           file->IsExecutable(&matched);
   865         } else
   866           matched = (NS_WildCardMatch(ucsLeafName.get(),
   867                                       mCurrentFilters.ElementAt(j),
   868                                       true) == MATCH);
   870         if (matched) {
   871           mFilteredFiles.AppendElement(file);
   872           ++mTotalRows;
   873           break;
   874         }
   875       }
   876     }
   877   }
   878 }
   880 void
   881 nsFileView::ReverseArray(nsTArray<nsCOMPtr<nsIFile> >& aArray)
   882 {
   883   uint32_t count = aArray.Length();
   884   for (uint32_t i = 0; i < count/2; ++i) {
   885     // If we get references to the COMPtrs in the array, and then .swap() them
   886     // we avoid AdRef() / Release() calls.
   887     nsCOMPtr<nsIFile>& element = aArray[i];
   888     nsCOMPtr<nsIFile>& element2 = aArray[count - i - 1];
   889     element.swap(element2);
   890   }
   891 }
   893 static int
   894 SortNameCallback(const void* aElement1, const void* aElement2, void* aContext)
   895 {
   896   nsIFile* file1 = *static_cast<nsIFile* const *>(aElement1);
   897   nsIFile* file2 = *static_cast<nsIFile* const *>(aElement2);
   899   nsAutoString leafName1, leafName2;
   900   file1->GetLeafName(leafName1);
   901   file2->GetLeafName(leafName2);
   903   return Compare(leafName1, leafName2);
   904 }
   906 static int
   907 SortSizeCallback(const void* aElement1, const void* aElement2, void* aContext)
   908 {
   909   nsIFile* file1 = *static_cast<nsIFile* const *>(aElement1);
   910   nsIFile* file2 = *static_cast<nsIFile* const *>(aElement2);
   912   int64_t size1, size2;
   913   file1->GetFileSize(&size1);
   914   file2->GetFileSize(&size2);
   916   if (size1 == size2)
   917     return 0;
   919   return size1 < size2 ? -1 : 1;
   920 }
   922 static int
   923 SortDateCallback(const void* aElement1, const void* aElement2, void* aContext)
   924 {
   925   nsIFile* file1 = *static_cast<nsIFile* const *>(aElement1);
   926   nsIFile* file2 = *static_cast<nsIFile* const *>(aElement2);
   928   PRTime time1, time2;
   929   file1->GetLastModifiedTime(&time1);
   930   file2->GetLastModifiedTime(&time2);
   932   if (time1 == time2)
   933     return 0;
   935   return time1 < time2 ? -1 : 1;
   936 }
   938 void
   939 nsFileView::SortArray(nsTArray<nsCOMPtr<nsIFile> >& aArray)
   940 {
   941   // We assume the array to be in filesystem order, which
   942   // for our purposes, is completely unordered.
   944   int (*compareFunc)(const void*, const void*, void*);
   946   switch (mSortType) {
   947   case sortName:
   948     compareFunc = SortNameCallback;
   949     break;
   950   case sortSize:
   951     compareFunc = SortSizeCallback;
   952     break;
   953   case sortDate:
   954     compareFunc = SortDateCallback;
   955     break;
   956   default:
   957     return;
   958   }
   960   uint32_t count = aArray.Length();
   962   nsIFile** array = new nsIFile*[count];
   963   for (uint32_t i = 0; i < count; ++i) {
   964     array[i] = aArray[i];
   965   }
   967   NS_QuickSort(array, count, sizeof(nsIFile*), compareFunc, nullptr);
   969   for (uint32_t i = 0; i < count; ++i) {
   970     // Use swap() to avoid refcounting.
   971     aArray[i].swap(array[i]);
   972   }
   974   delete[] array;
   975 }
   977 void
   978 nsFileView::SortInternal()
   979 {
   980   SortArray(mDirList);
   981   SortArray(mFilteredFiles);
   983   if (mReverseSort) {
   984     ReverseArray(mDirList);
   985     ReverseArray(mFilteredFiles);
   986   }
   987 }

mercurial