toolkit/components/filepicker/nsFileView.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/components/filepicker/nsFileView.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,987 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsIFileView.h"
    1.10 +#include "nsITreeView.h"
    1.11 +#include "mozilla/ModuleUtils.h"
    1.12 +#include "nsITreeSelection.h"
    1.13 +#include "nsITreeColumns.h"
    1.14 +#include "nsITreeBoxObject.h"
    1.15 +#include "nsIFile.h"
    1.16 +#include "nsString.h"
    1.17 +#include "nsReadableUtils.h"
    1.18 +#include "nsCRT.h"
    1.19 +#include "nsPrintfCString.h"
    1.20 +#include "nsIDateTimeFormat.h"
    1.21 +#include "nsDateTimeFormatCID.h"
    1.22 +#include "nsQuickSort.h"
    1.23 +#include "nsIAtom.h"
    1.24 +#include "nsIAutoCompleteResult.h"
    1.25 +#include "nsIAutoCompleteSearch.h"
    1.26 +#include "nsISimpleEnumerator.h"
    1.27 +#include "nsAutoPtr.h"
    1.28 +#include "nsIMutableArray.h"
    1.29 +#include "nsTArray.h"
    1.30 +#include "mozilla/Attributes.h"
    1.31 +
    1.32 +#include "nsWildCard.h"
    1.33 +
    1.34 +class nsIDOMDataTransfer;
    1.35 + 
    1.36 +#define NS_FILECOMPLETE_CID { 0xcb60980e, 0x18a5, 0x4a77, \
    1.37 +                            { 0x91, 0x10, 0x81, 0x46, 0x61, 0x4c, 0xa7, 0xf0 } }
    1.38 +#define NS_FILECOMPLETE_CONTRACTID "@mozilla.org/autocomplete/search;1?name=file"
    1.39 +
    1.40 +class nsFileResult MOZ_FINAL : public nsIAutoCompleteResult
    1.41 +{
    1.42 +public:
    1.43 +  // aSearchString is the text typed into the autocomplete widget
    1.44 +  // aSearchParam is the picker's currently displayed directory
    1.45 +  nsFileResult(const nsAString& aSearchString, const nsAString& aSearchParam);
    1.46 +
    1.47 +  NS_DECL_ISUPPORTS
    1.48 +  NS_DECL_NSIAUTOCOMPLETERESULT
    1.49 +
    1.50 +  nsTArray<nsString> mValues;
    1.51 +  nsAutoString mSearchString;
    1.52 +  uint16_t mSearchResult;
    1.53 +};
    1.54 +
    1.55 +NS_IMPL_ISUPPORTS(nsFileResult, nsIAutoCompleteResult)
    1.56 +
    1.57 +nsFileResult::nsFileResult(const nsAString& aSearchString,
    1.58 +                           const nsAString& aSearchParam):
    1.59 +  mSearchString(aSearchString)
    1.60 +{
    1.61 +  if (aSearchString.IsEmpty())
    1.62 +    mSearchResult = RESULT_IGNORED;
    1.63 +  else {
    1.64 +    int32_t slashPos = mSearchString.RFindChar('/');
    1.65 +    mSearchResult = RESULT_FAILURE;
    1.66 +    nsCOMPtr<nsIFile> directory;
    1.67 +    nsDependentSubstring parent(Substring(mSearchString, 0, slashPos + 1));
    1.68 +    if (!parent.IsEmpty() && parent.First() == '/')
    1.69 +      NS_NewLocalFile(parent, true, getter_AddRefs(directory));
    1.70 +    if (!directory) {
    1.71 +      if (NS_FAILED(NS_NewLocalFile(aSearchParam, true, getter_AddRefs(directory))))
    1.72 +        return;
    1.73 +      if (slashPos > 0)
    1.74 +        directory->AppendRelativePath(Substring(mSearchString, 0, slashPos));
    1.75 +    }
    1.76 +    nsCOMPtr<nsISimpleEnumerator> dirEntries;
    1.77 +    if (NS_FAILED(directory->GetDirectoryEntries(getter_AddRefs(dirEntries))))
    1.78 +      return;
    1.79 +    mSearchResult = RESULT_NOMATCH;
    1.80 +    bool hasMore = false;
    1.81 +    nsDependentSubstring prefix(Substring(mSearchString, slashPos + 1));
    1.82 +    while (NS_SUCCEEDED(dirEntries->HasMoreElements(&hasMore)) && hasMore) {
    1.83 +      nsCOMPtr<nsISupports> nextItem;
    1.84 +      dirEntries->GetNext(getter_AddRefs(nextItem));
    1.85 +      nsCOMPtr<nsIFile> nextFile(do_QueryInterface(nextItem));
    1.86 +      nsAutoString fileName;
    1.87 +      nextFile->GetLeafName(fileName);
    1.88 +      if (StringBeginsWith(fileName, prefix)) {
    1.89 +        fileName.Insert(parent, 0);
    1.90 +        if (mSearchResult == RESULT_NOMATCH && fileName.Equals(mSearchString))
    1.91 +          mSearchResult = RESULT_IGNORED;
    1.92 +        else
    1.93 +          mSearchResult = RESULT_SUCCESS;
    1.94 +        bool isDirectory = false;
    1.95 +        nextFile->IsDirectory(&isDirectory);
    1.96 +        if (isDirectory)
    1.97 +          fileName.Append('/');
    1.98 +        mValues.AppendElement(fileName);
    1.99 +      }
   1.100 +    }
   1.101 +    mValues.Sort();
   1.102 +  }
   1.103 +}
   1.104 +
   1.105 +NS_IMETHODIMP nsFileResult::GetSearchString(nsAString & aSearchString)
   1.106 +{
   1.107 +  aSearchString.Assign(mSearchString);
   1.108 +  return NS_OK;
   1.109 +}
   1.110 +
   1.111 +NS_IMETHODIMP nsFileResult::GetSearchResult(uint16_t *aSearchResult)
   1.112 +{
   1.113 +  NS_ENSURE_ARG_POINTER(aSearchResult);
   1.114 +  *aSearchResult = mSearchResult;
   1.115 +  return NS_OK;
   1.116 +}
   1.117 +
   1.118 +NS_IMETHODIMP nsFileResult::GetDefaultIndex(int32_t *aDefaultIndex)
   1.119 +{
   1.120 +  NS_ENSURE_ARG_POINTER(aDefaultIndex);
   1.121 +  *aDefaultIndex = -1;
   1.122 +  return NS_OK;
   1.123 +}
   1.124 +
   1.125 +NS_IMETHODIMP nsFileResult::GetErrorDescription(nsAString & aErrorDescription)
   1.126 +{
   1.127 +  aErrorDescription.Truncate();
   1.128 +  return NS_OK;
   1.129 +}
   1.130 +
   1.131 +NS_IMETHODIMP nsFileResult::GetMatchCount(uint32_t *aMatchCount)
   1.132 +{
   1.133 +  NS_ENSURE_ARG_POINTER(aMatchCount);
   1.134 +  *aMatchCount = mValues.Length();
   1.135 +  return NS_OK;
   1.136 +}
   1.137 +
   1.138 +NS_IMETHODIMP nsFileResult::GetTypeAheadResult(bool *aTypeAheadResult)
   1.139 +{
   1.140 +  NS_ENSURE_ARG_POINTER(aTypeAheadResult);
   1.141 +  *aTypeAheadResult = false;
   1.142 +  return NS_OK;
   1.143 +}
   1.144 +
   1.145 +NS_IMETHODIMP nsFileResult::GetValueAt(int32_t index, nsAString & aValue)
   1.146 +{
   1.147 +  aValue = mValues[index];
   1.148 +  if (aValue.Last() == '/')
   1.149 +    aValue.Truncate(aValue.Length() - 1);
   1.150 +  return NS_OK;
   1.151 +}
   1.152 +
   1.153 +NS_IMETHODIMP nsFileResult::GetLabelAt(int32_t index, nsAString & aValue)
   1.154 +{
   1.155 +  return GetValueAt(index, aValue);
   1.156 +}
   1.157 +
   1.158 +NS_IMETHODIMP nsFileResult::GetCommentAt(int32_t index, nsAString & aComment)
   1.159 +{
   1.160 +  aComment.Truncate();
   1.161 +  return NS_OK;
   1.162 +}
   1.163 +
   1.164 +NS_IMETHODIMP nsFileResult::GetStyleAt(int32_t index, nsAString & aStyle)
   1.165 +{
   1.166 +  if (mValues[index].Last() == '/')
   1.167 +    aStyle.AssignLiteral("directory");
   1.168 +  else
   1.169 +    aStyle.AssignLiteral("file");
   1.170 +  return NS_OK;
   1.171 +}
   1.172 +
   1.173 +NS_IMETHODIMP nsFileResult::GetImageAt(int32_t index, nsAString & aImage)
   1.174 +{
   1.175 +  aImage.Truncate();
   1.176 +  return NS_OK;
   1.177 +}
   1.178 +NS_IMETHODIMP nsFileResult::GetFinalCompleteValueAt(int32_t index,
   1.179 +                                                    nsAString & aValue)
   1.180 +{
   1.181 +  return GetValueAt(index, aValue);
   1.182 +}
   1.183 +
   1.184 +NS_IMETHODIMP nsFileResult::RemoveValueAt(int32_t rowIndex, bool removeFromDb)
   1.185 +{
   1.186 +  return NS_OK;
   1.187 +}
   1.188 +
   1.189 +class nsFileComplete MOZ_FINAL : public nsIAutoCompleteSearch
   1.190 +{
   1.191 +public:
   1.192 +  NS_DECL_ISUPPORTS
   1.193 +  NS_DECL_NSIAUTOCOMPLETESEARCH
   1.194 +};
   1.195 +
   1.196 +NS_IMPL_ISUPPORTS(nsFileComplete, nsIAutoCompleteSearch)
   1.197 +
   1.198 +NS_IMETHODIMP
   1.199 +nsFileComplete::StartSearch(const nsAString& aSearchString,
   1.200 +                            const nsAString& aSearchParam,
   1.201 +                            nsIAutoCompleteResult *aPreviousResult,
   1.202 +                            nsIAutoCompleteObserver *aListener)
   1.203 +{
   1.204 +  NS_ENSURE_ARG_POINTER(aListener);
   1.205 +  nsRefPtr<nsFileResult> result = new nsFileResult(aSearchString, aSearchParam);
   1.206 +  NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
   1.207 +  return aListener->OnSearchResult(this, result);
   1.208 +}
   1.209 +
   1.210 +NS_IMETHODIMP
   1.211 +nsFileComplete::StopSearch()
   1.212 +{
   1.213 +  return NS_OK;
   1.214 +}
   1.215 +
   1.216 +#define NS_FILEVIEW_CID { 0xa5570462, 0x1dd1, 0x11b2, \
   1.217 +                         { 0x9d, 0x19, 0xdf, 0x30, 0xa2, 0x7f, 0xbd, 0xc4 } }
   1.218 +
   1.219 +class nsFileView : public nsIFileView,
   1.220 +                   public nsITreeView
   1.221 +{
   1.222 +public:
   1.223 +  nsFileView();
   1.224 +  nsresult Init();
   1.225 +
   1.226 +  NS_DECL_ISUPPORTS
   1.227 +  NS_DECL_NSIFILEVIEW
   1.228 +  NS_DECL_NSITREEVIEW
   1.229 +  
   1.230 +protected:
   1.231 +  virtual ~nsFileView();
   1.232 +  
   1.233 +  void FilterFiles();
   1.234 +  void ReverseArray(nsTArray<nsCOMPtr<nsIFile> >& aArray);
   1.235 +  void SortArray(nsTArray<nsCOMPtr<nsIFile> >& aArray);
   1.236 +  void SortInternal();
   1.237 +
   1.238 +  nsTArray<nsCOMPtr<nsIFile> > mFileList;
   1.239 +  nsTArray<nsCOMPtr<nsIFile> > mDirList;
   1.240 +  nsTArray<nsCOMPtr<nsIFile> > mFilteredFiles;
   1.241 +
   1.242 +  nsCOMPtr<nsIFile> mDirectoryPath;
   1.243 +  nsCOMPtr<nsITreeBoxObject> mTree;
   1.244 +  nsCOMPtr<nsITreeSelection> mSelection;
   1.245 +  nsCOMPtr<nsIDateTimeFormat> mDateFormatter;
   1.246 +
   1.247 +  int16_t mSortType;
   1.248 +  int32_t mTotalRows;
   1.249 +
   1.250 +  nsTArray<char16_t*> mCurrentFilters;
   1.251 +
   1.252 +  bool mShowHiddenFiles;
   1.253 +  bool mDirectoryFilter;
   1.254 +  bool mReverseSort;
   1.255 +};
   1.256 +
   1.257 +// Factory constructor
   1.258 +NS_GENERIC_FACTORY_CONSTRUCTOR(nsFileComplete)
   1.259 +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsFileView, Init)
   1.260 +NS_DEFINE_NAMED_CID(NS_FILECOMPLETE_CID);
   1.261 +NS_DEFINE_NAMED_CID(NS_FILEVIEW_CID);
   1.262 +
   1.263 +static const mozilla::Module::CIDEntry kFileViewCIDs[] = {
   1.264 +  { &kNS_FILECOMPLETE_CID, false, nullptr, nsFileCompleteConstructor },
   1.265 +  { &kNS_FILEVIEW_CID, false, nullptr, nsFileViewConstructor },
   1.266 +  { nullptr }
   1.267 +};
   1.268 +
   1.269 +static const mozilla::Module::ContractIDEntry kFileViewContracts[] = {
   1.270 +  { NS_FILECOMPLETE_CONTRACTID, &kNS_FILECOMPLETE_CID },
   1.271 +  { NS_FILEVIEW_CONTRACTID, &kNS_FILEVIEW_CID },
   1.272 +  { nullptr }
   1.273 +};
   1.274 +
   1.275 +static const mozilla::Module kFileViewModule = {
   1.276 +  mozilla::Module::kVersion,
   1.277 +  kFileViewCIDs,
   1.278 +  kFileViewContracts
   1.279 +};
   1.280 +
   1.281 +NSMODULE_DEFN(nsFileViewModule) = &kFileViewModule;
   1.282 +
   1.283 +nsFileView::nsFileView() :
   1.284 +  mSortType(-1),
   1.285 +  mTotalRows(0),
   1.286 +  mShowHiddenFiles(false),
   1.287 +  mDirectoryFilter(false),
   1.288 +  mReverseSort(false)
   1.289 +{
   1.290 +}
   1.291 +
   1.292 +nsFileView::~nsFileView()
   1.293 +{
   1.294 +  uint32_t count = mCurrentFilters.Length();
   1.295 +  for (uint32_t i = 0; i < count; ++i)
   1.296 +    NS_Free(mCurrentFilters[i]);
   1.297 +}
   1.298 +
   1.299 +nsresult
   1.300 +nsFileView::Init()
   1.301 +{
   1.302 +  mDateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID);
   1.303 +  if (!mDateFormatter)
   1.304 +    return NS_ERROR_OUT_OF_MEMORY;
   1.305 +
   1.306 +  return NS_OK;
   1.307 +}
   1.308 +
   1.309 +// nsISupports implementation
   1.310 +
   1.311 +NS_IMPL_ISUPPORTS(nsFileView, nsITreeView, nsIFileView)
   1.312 +
   1.313 +// nsIFileView implementation
   1.314 +
   1.315 +NS_IMETHODIMP
   1.316 +nsFileView::SetShowHiddenFiles(bool aShowHidden)
   1.317 +{
   1.318 +  if (aShowHidden != mShowHiddenFiles) {
   1.319 +    mShowHiddenFiles = aShowHidden;
   1.320 +
   1.321 +    // This could be better optimized, but since the hidden
   1.322 +    // file functionality is not currently used, this will be fine.
   1.323 +    SetDirectory(mDirectoryPath);
   1.324 +  }
   1.325 +    
   1.326 +  return NS_OK;
   1.327 +}
   1.328 +
   1.329 +NS_IMETHODIMP
   1.330 +nsFileView::GetShowHiddenFiles(bool* aShowHidden)
   1.331 +{
   1.332 +  *aShowHidden = mShowHiddenFiles;
   1.333 +  return NS_OK;
   1.334 +}
   1.335 +
   1.336 +NS_IMETHODIMP
   1.337 +nsFileView::SetShowOnlyDirectories(bool aOnlyDirs)
   1.338 +{
   1.339 +  if (aOnlyDirs == mDirectoryFilter)
   1.340 +    return NS_OK;
   1.341 +
   1.342 +  mDirectoryFilter = aOnlyDirs;
   1.343 +  uint32_t dirCount = mDirList.Length();
   1.344 +  if (mDirectoryFilter) {
   1.345 +    int32_t rowDiff = mTotalRows - dirCount;
   1.346 +
   1.347 +    mFilteredFiles.Clear();
   1.348 +    mTotalRows = dirCount;
   1.349 +    if (mTree)
   1.350 +      mTree->RowCountChanged(mTotalRows, -rowDiff);
   1.351 +  } else {
   1.352 +    // Run the filter again to get the file list back
   1.353 +    FilterFiles();
   1.354 +
   1.355 +    SortArray(mFilteredFiles);
   1.356 +    if (mReverseSort)
   1.357 +      ReverseArray(mFilteredFiles);
   1.358 +
   1.359 +    if (mTree)
   1.360 +      mTree->RowCountChanged(dirCount, mTotalRows - dirCount);
   1.361 +  }
   1.362 +
   1.363 +  return NS_OK;
   1.364 +}
   1.365 +
   1.366 +NS_IMETHODIMP
   1.367 +nsFileView::GetShowOnlyDirectories(bool* aOnlyDirs)
   1.368 +{
   1.369 +  *aOnlyDirs = mDirectoryFilter;
   1.370 +  return NS_OK;
   1.371 +}
   1.372 +
   1.373 +NS_IMETHODIMP
   1.374 +nsFileView::GetSortType(int16_t* aSortType)
   1.375 +{
   1.376 +  *aSortType = mSortType;
   1.377 +  return NS_OK;
   1.378 +}
   1.379 +
   1.380 +NS_IMETHODIMP
   1.381 +nsFileView::GetReverseSort(bool* aReverseSort)
   1.382 +{
   1.383 +  *aReverseSort = mReverseSort;
   1.384 +  return NS_OK;
   1.385 +}
   1.386 +
   1.387 +NS_IMETHODIMP
   1.388 +nsFileView::Sort(int16_t aSortType, bool aReverseSort)
   1.389 +{
   1.390 +  if (aSortType == mSortType) {
   1.391 +    if (aReverseSort == mReverseSort)
   1.392 +      return NS_OK;
   1.393 +
   1.394 +    mReverseSort = aReverseSort;
   1.395 +    ReverseArray(mDirList);
   1.396 +    ReverseArray(mFilteredFiles);
   1.397 +  } else {
   1.398 +    mSortType = aSortType;
   1.399 +    mReverseSort = aReverseSort;
   1.400 +    SortInternal();
   1.401 +  }
   1.402 +
   1.403 +  if (mTree)
   1.404 +    mTree->Invalidate();
   1.405 +
   1.406 +  return NS_OK;
   1.407 +}
   1.408 +
   1.409 +NS_IMETHODIMP
   1.410 +nsFileView::SetDirectory(nsIFile* aDirectory)
   1.411 +{
   1.412 +  NS_ENSURE_ARG_POINTER(aDirectory);
   1.413 +
   1.414 +  nsCOMPtr<nsISimpleEnumerator> dirEntries;
   1.415 +  aDirectory->GetDirectoryEntries(getter_AddRefs(dirEntries));
   1.416 +
   1.417 +  if (!dirEntries) {
   1.418 +    // Couldn't read in the directory, this can happen if the user does not
   1.419 +    // have permission to list it.
   1.420 +    return NS_ERROR_FAILURE;
   1.421 +  }
   1.422 +
   1.423 +  mDirectoryPath = aDirectory;
   1.424 +  mFileList.Clear();
   1.425 +  mDirList.Clear();
   1.426 +
   1.427 +  bool hasMore = false;
   1.428 +
   1.429 +  while (NS_SUCCEEDED(dirEntries->HasMoreElements(&hasMore)) && hasMore) {
   1.430 +    nsCOMPtr<nsISupports> nextItem;
   1.431 +    dirEntries->GetNext(getter_AddRefs(nextItem));
   1.432 +    nsCOMPtr<nsIFile> theFile = do_QueryInterface(nextItem);
   1.433 +
   1.434 +    bool isDirectory = false;
   1.435 +    if (theFile) {
   1.436 +      theFile->IsDirectory(&isDirectory);
   1.437 +
   1.438 +      if (isDirectory) {
   1.439 +        bool isHidden;
   1.440 +        theFile->IsHidden(&isHidden);
   1.441 +        if (mShowHiddenFiles || !isHidden) {
   1.442 +          mDirList.AppendElement(theFile);
   1.443 +        }
   1.444 +      }
   1.445 +      else {
   1.446 +        mFileList.AppendElement(theFile);
   1.447 +      }
   1.448 +    }
   1.449 +  }
   1.450 +
   1.451 +  if (mTree) {
   1.452 +    mTree->BeginUpdateBatch();
   1.453 +    mTree->RowCountChanged(0, -mTotalRows);
   1.454 +  }
   1.455 +
   1.456 +  FilterFiles();
   1.457 +  SortInternal();
   1.458 +
   1.459 +  if (mTree) {
   1.460 +    mTree->EndUpdateBatch();
   1.461 +    mTree->ScrollToRow(0);
   1.462 +  }
   1.463 +
   1.464 +  return NS_OK;
   1.465 +}
   1.466 +
   1.467 +NS_IMETHODIMP
   1.468 +nsFileView::SetFilter(const nsAString& aFilterString)
   1.469 +{
   1.470 +  uint32_t filterCount = mCurrentFilters.Length();
   1.471 +  for (uint32_t i = 0; i < filterCount; ++i)
   1.472 +    NS_Free(mCurrentFilters[i]);
   1.473 +  mCurrentFilters.Clear();
   1.474 +
   1.475 +  nsAString::const_iterator start, iter, end;
   1.476 +  aFilterString.BeginReading(iter);
   1.477 +  aFilterString.EndReading(end);
   1.478 +
   1.479 +  while (true) {
   1.480 +    // skip over delimiters
   1.481 +    while (iter != end && (*iter == ';' || *iter == ' '))
   1.482 +      ++iter;
   1.483 +
   1.484 +    if (iter == end)
   1.485 +      break;
   1.486 +
   1.487 +    start = iter; // start of a filter
   1.488 +
   1.489 +    // we know this is neither ';' nor ' ', skip to next char
   1.490 +    ++iter;
   1.491 +
   1.492 +    // find next delimiter or end of string
   1.493 +    while (iter != end && (*iter != ';' && *iter != ' '))
   1.494 +      ++iter;
   1.495 +
   1.496 +    char16_t* filter = ToNewUnicode(Substring(start, iter));
   1.497 +    if (!filter)
   1.498 +      return NS_ERROR_OUT_OF_MEMORY;
   1.499 +
   1.500 +    if (!mCurrentFilters.AppendElement(filter)) {
   1.501 +      NS_Free(filter);
   1.502 +      return NS_ERROR_OUT_OF_MEMORY;
   1.503 +    }
   1.504 +
   1.505 +    if (iter == end)
   1.506 +      break;
   1.507 +
   1.508 +    ++iter; // we know this is either ';' or ' ', skip to next char
   1.509 +  }
   1.510 +
   1.511 +  if (mTree) {
   1.512 +    mTree->BeginUpdateBatch();
   1.513 +    uint32_t count = mDirList.Length();
   1.514 +    mTree->RowCountChanged(count, count - mTotalRows);
   1.515 +  }
   1.516 +
   1.517 +  mFilteredFiles.Clear();
   1.518 +
   1.519 +  FilterFiles();
   1.520 +
   1.521 +  SortArray(mFilteredFiles);
   1.522 +  if (mReverseSort)
   1.523 +    ReverseArray(mFilteredFiles);
   1.524 +
   1.525 +  if (mTree)
   1.526 +    mTree->EndUpdateBatch();
   1.527 +
   1.528 +  return NS_OK;
   1.529 +}
   1.530 +
   1.531 +NS_IMETHODIMP
   1.532 +nsFileView::GetSelectedFiles(nsIArray** aFiles)
   1.533 +{
   1.534 +  *aFiles = nullptr;
   1.535 +  if (!mSelection)
   1.536 +    return NS_OK;
   1.537 +
   1.538 +  int32_t numRanges;
   1.539 +  mSelection->GetRangeCount(&numRanges);
   1.540 +
   1.541 +  uint32_t dirCount = mDirList.Length();
   1.542 +  nsCOMPtr<nsIMutableArray> fileArray =
   1.543 +    do_CreateInstance(NS_ARRAY_CONTRACTID);
   1.544 +  NS_ENSURE_STATE(fileArray);
   1.545 +
   1.546 +  for (int32_t range = 0; range < numRanges; ++range) {
   1.547 +    int32_t rangeBegin, rangeEnd;
   1.548 +    mSelection->GetRangeAt(range, &rangeBegin, &rangeEnd);
   1.549 +
   1.550 +    for (int32_t itemIndex = rangeBegin; itemIndex <= rangeEnd; ++itemIndex) {
   1.551 +      nsIFile* curFile = nullptr;
   1.552 +
   1.553 +      if (itemIndex < (int32_t) dirCount)
   1.554 +        curFile = mDirList[itemIndex];
   1.555 +      else {
   1.556 +        if (itemIndex < mTotalRows)
   1.557 +          curFile = mFilteredFiles[itemIndex - dirCount];
   1.558 +      }
   1.559 +
   1.560 +      if (curFile)
   1.561 +        fileArray->AppendElement(curFile, false);
   1.562 +    }
   1.563 +  }
   1.564 +
   1.565 +  NS_ADDREF(*aFiles = fileArray);
   1.566 +  return NS_OK;
   1.567 +}
   1.568 +
   1.569 +
   1.570 +// nsITreeView implementation
   1.571 +
   1.572 +NS_IMETHODIMP
   1.573 +nsFileView::GetRowCount(int32_t* aRowCount)
   1.574 +{
   1.575 +  *aRowCount = mTotalRows;
   1.576 +  return NS_OK;
   1.577 +}
   1.578 +
   1.579 +NS_IMETHODIMP
   1.580 +nsFileView::GetSelection(nsITreeSelection** aSelection)
   1.581 +{
   1.582 +  *aSelection = mSelection;
   1.583 +  NS_IF_ADDREF(*aSelection);
   1.584 +  return NS_OK;
   1.585 +}
   1.586 +
   1.587 +NS_IMETHODIMP
   1.588 +nsFileView::SetSelection(nsITreeSelection* aSelection)
   1.589 +{
   1.590 +  mSelection = aSelection;
   1.591 +  return NS_OK;
   1.592 +}
   1.593 +
   1.594 +NS_IMETHODIMP
   1.595 +nsFileView::GetRowProperties(int32_t aIndex, nsAString& aProps)
   1.596 +{
   1.597 +  return NS_OK;
   1.598 +}
   1.599 +
   1.600 +NS_IMETHODIMP
   1.601 +nsFileView::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
   1.602 +                              nsAString& aProps)
   1.603 +{
   1.604 +  uint32_t dirCount = mDirList.Length();
   1.605 +
   1.606 +  if (aRow < (int32_t) dirCount)
   1.607 +    aProps.AppendLiteral("directory");
   1.608 +  else if (aRow < mTotalRows)
   1.609 +    aProps.AppendLiteral("file");
   1.610 +
   1.611 +  return NS_OK;
   1.612 +}
   1.613 +
   1.614 +NS_IMETHODIMP
   1.615 +nsFileView::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
   1.616 +{
   1.617 +  return NS_OK;
   1.618 +}
   1.619 +
   1.620 +NS_IMETHODIMP
   1.621 +nsFileView::IsContainer(int32_t aIndex, bool* aIsContainer)
   1.622 +{
   1.623 +  *aIsContainer = false;
   1.624 +  return NS_OK;
   1.625 +}
   1.626 +
   1.627 +NS_IMETHODIMP
   1.628 +nsFileView::IsContainerOpen(int32_t aIndex, bool* aIsOpen)
   1.629 +{
   1.630 +  *aIsOpen = false;
   1.631 +  return NS_OK;
   1.632 +}
   1.633 +
   1.634 +NS_IMETHODIMP
   1.635 +nsFileView::IsContainerEmpty(int32_t aIndex, bool* aIsEmpty)
   1.636 +{
   1.637 +  *aIsEmpty = false;
   1.638 +  return NS_OK;
   1.639 +}
   1.640 +
   1.641 +NS_IMETHODIMP
   1.642 +nsFileView::IsSeparator(int32_t aIndex, bool* aIsSeparator)
   1.643 +{
   1.644 +  *aIsSeparator = false;
   1.645 +  return NS_OK;
   1.646 +}
   1.647 +
   1.648 +NS_IMETHODIMP
   1.649 +nsFileView::IsSorted(bool* aIsSorted)
   1.650 +{
   1.651 +  *aIsSorted = (mSortType >= 0);
   1.652 +  return NS_OK;
   1.653 +}
   1.654 +
   1.655 +NS_IMETHODIMP
   1.656 +nsFileView::CanDrop(int32_t aIndex, int32_t aOrientation,
   1.657 +                    nsIDOMDataTransfer* dataTransfer, bool* aCanDrop)
   1.658 +{
   1.659 +  *aCanDrop = false;
   1.660 +  return NS_OK;
   1.661 +}
   1.662 +
   1.663 +NS_IMETHODIMP
   1.664 +nsFileView::Drop(int32_t aRow, int32_t aOrientation, nsIDOMDataTransfer* dataTransfer)
   1.665 +{
   1.666 +  return NS_OK;
   1.667 +}
   1.668 +
   1.669 +NS_IMETHODIMP
   1.670 +nsFileView::GetParentIndex(int32_t aRowIndex, int32_t* aParentIndex)
   1.671 +{
   1.672 +  *aParentIndex = -1;
   1.673 +  return NS_OK;
   1.674 +}
   1.675 +
   1.676 +NS_IMETHODIMP
   1.677 +nsFileView::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, 
   1.678 +                           bool* aHasSibling)
   1.679 +{
   1.680 +  *aHasSibling = (aAfterIndex < (mTotalRows - 1));
   1.681 +  return NS_OK;
   1.682 +}
   1.683 +
   1.684 +NS_IMETHODIMP
   1.685 +nsFileView::GetLevel(int32_t aIndex, int32_t* aLevel)
   1.686 +{
   1.687 +  *aLevel = 0;
   1.688 +  return NS_OK;
   1.689 +}
   1.690 +
   1.691 +NS_IMETHODIMP
   1.692 +nsFileView::GetImageSrc(int32_t aRow, nsITreeColumn* aCol,
   1.693 +                        nsAString& aImageSrc)
   1.694 +{
   1.695 +  return NS_OK;
   1.696 +}
   1.697 +
   1.698 +NS_IMETHODIMP
   1.699 +nsFileView::GetProgressMode(int32_t aRow, nsITreeColumn* aCol,
   1.700 +                            int32_t* aProgressMode)
   1.701 +{
   1.702 +  return NS_OK;
   1.703 +}
   1.704 +
   1.705 +NS_IMETHODIMP
   1.706 +nsFileView::GetCellValue(int32_t aRow, nsITreeColumn* aCol,
   1.707 +                         nsAString& aCellValue)
   1.708 +{
   1.709 +  return NS_OK;
   1.710 +}
   1.711 +
   1.712 +NS_IMETHODIMP
   1.713 +nsFileView::GetCellText(int32_t aRow, nsITreeColumn* aCol,
   1.714 +                        nsAString& aCellText)
   1.715 +{
   1.716 +  uint32_t dirCount = mDirList.Length();
   1.717 +  bool isDirectory;
   1.718 +  nsIFile* curFile = nullptr;
   1.719 +
   1.720 +  if (aRow < (int32_t) dirCount) {
   1.721 +    isDirectory = true;
   1.722 +    curFile = mDirList[aRow];
   1.723 +  } else if (aRow < mTotalRows) {
   1.724 +    isDirectory = false;
   1.725 +    curFile = mFilteredFiles[aRow - dirCount];
   1.726 +  } else {
   1.727 +    // invalid row
   1.728 +    aCellText.SetCapacity(0);
   1.729 +    return NS_OK;
   1.730 +  }
   1.731 +
   1.732 +  const char16_t* colID;
   1.733 +  aCol->GetIdConst(&colID);
   1.734 +  if (NS_LITERAL_STRING("FilenameColumn").Equals(colID)) {
   1.735 +    curFile->GetLeafName(aCellText);
   1.736 +  } else if (NS_LITERAL_STRING("LastModifiedColumn").Equals(colID)) {
   1.737 +    PRTime lastModTime;
   1.738 +    curFile->GetLastModifiedTime(&lastModTime);
   1.739 +    // XXX FormatPRTime could take an nsAString&
   1.740 +    nsAutoString temp;
   1.741 +    mDateFormatter->FormatPRTime(nullptr, kDateFormatShort, kTimeFormatSeconds,
   1.742 +                                 lastModTime * 1000, temp);
   1.743 +    aCellText = temp;
   1.744 +  } else {
   1.745 +    // file size
   1.746 +    if (isDirectory)
   1.747 +      aCellText.SetCapacity(0);
   1.748 +    else {
   1.749 +      int64_t fileSize;
   1.750 +      curFile->GetFileSize(&fileSize);
   1.751 +      CopyUTF8toUTF16(nsPrintfCString("%lld", fileSize), aCellText);
   1.752 +    }
   1.753 +  }
   1.754 +
   1.755 +  return NS_OK;
   1.756 +}
   1.757 +
   1.758 +NS_IMETHODIMP
   1.759 +nsFileView::SetTree(nsITreeBoxObject* aTree)
   1.760 +{
   1.761 +  mTree = aTree;
   1.762 +  return NS_OK;
   1.763 +}
   1.764 +
   1.765 +NS_IMETHODIMP
   1.766 +nsFileView::ToggleOpenState(int32_t aIndex)
   1.767 +{
   1.768 +  return NS_OK;
   1.769 +}
   1.770 +
   1.771 +NS_IMETHODIMP
   1.772 +nsFileView::CycleHeader(nsITreeColumn* aCol)
   1.773 +{
   1.774 +  return NS_OK;
   1.775 +}
   1.776 +
   1.777 +NS_IMETHODIMP
   1.778 +nsFileView::SelectionChanged()
   1.779 +{
   1.780 +  return NS_OK;
   1.781 +}
   1.782 +
   1.783 +NS_IMETHODIMP
   1.784 +nsFileView::CycleCell(int32_t aRow, nsITreeColumn* aCol)
   1.785 +{
   1.786 +  return NS_OK;
   1.787 +}
   1.788 +
   1.789 +NS_IMETHODIMP
   1.790 +nsFileView::IsEditable(int32_t aRow, nsITreeColumn* aCol,
   1.791 +                       bool* aIsEditable)
   1.792 +{
   1.793 +  *aIsEditable = false;
   1.794 +  return NS_OK;
   1.795 +}
   1.796 +
   1.797 +NS_IMETHODIMP
   1.798 +nsFileView::IsSelectable(int32_t aRow, nsITreeColumn* aCol,
   1.799 +                         bool* aIsSelectable)
   1.800 +{
   1.801 +  *aIsSelectable = false;
   1.802 +  return NS_OK;
   1.803 +}
   1.804 +
   1.805 +NS_IMETHODIMP
   1.806 +nsFileView::SetCellValue(int32_t aRow, nsITreeColumn* aCol,
   1.807 +                         const nsAString& aValue)
   1.808 +{
   1.809 +  return NS_OK;
   1.810 +}
   1.811 +
   1.812 +NS_IMETHODIMP
   1.813 +nsFileView::SetCellText(int32_t aRow, nsITreeColumn* aCol,
   1.814 +                        const nsAString& aValue)
   1.815 +{
   1.816 +  return NS_OK;
   1.817 +}
   1.818 +
   1.819 +NS_IMETHODIMP
   1.820 +nsFileView::PerformAction(const char16_t* aAction)
   1.821 +{
   1.822 +  return NS_OK;
   1.823 +}
   1.824 +
   1.825 +NS_IMETHODIMP
   1.826 +nsFileView::PerformActionOnRow(const char16_t* aAction, int32_t aRow)
   1.827 +{
   1.828 +  return NS_OK;
   1.829 +}
   1.830 +
   1.831 +NS_IMETHODIMP
   1.832 +nsFileView::PerformActionOnCell(const char16_t* aAction, int32_t aRow,
   1.833 +                                nsITreeColumn* aCol)
   1.834 +{
   1.835 +  return NS_OK;
   1.836 +}
   1.837 +
   1.838 +// Private methods
   1.839 +
   1.840 +void
   1.841 +nsFileView::FilterFiles()
   1.842 +{
   1.843 +  uint32_t count = mDirList.Length();
   1.844 +  mTotalRows = count;
   1.845 +  count = mFileList.Length();
   1.846 +  mFilteredFiles.Clear();
   1.847 +  uint32_t filterCount = mCurrentFilters.Length();
   1.848 +
   1.849 +  for (uint32_t i = 0; i < count; ++i) {
   1.850 +    nsIFile* file = mFileList[i];
   1.851 +    bool isHidden = false;
   1.852 +    if (!mShowHiddenFiles)
   1.853 +      file->IsHidden(&isHidden);
   1.854 +    
   1.855 +    nsAutoString ucsLeafName;
   1.856 +    if(NS_FAILED(file->GetLeafName(ucsLeafName))) {
   1.857 +      // need to check return value for GetLeafName()
   1.858 +      continue;
   1.859 +    }
   1.860 +    
   1.861 +    if (!isHidden) {
   1.862 +      for (uint32_t j = 0; j < filterCount; ++j) {
   1.863 +        bool matched = false;
   1.864 +        if (!nsCRT::strcmp(mCurrentFilters.ElementAt(j),
   1.865 +                           MOZ_UTF16("..apps")))
   1.866 +        {
   1.867 +          file->IsExecutable(&matched);
   1.868 +        } else
   1.869 +          matched = (NS_WildCardMatch(ucsLeafName.get(),
   1.870 +                                      mCurrentFilters.ElementAt(j),
   1.871 +                                      true) == MATCH);
   1.872 +
   1.873 +        if (matched) {
   1.874 +          mFilteredFiles.AppendElement(file);
   1.875 +          ++mTotalRows;
   1.876 +          break;
   1.877 +        }
   1.878 +      }
   1.879 +    }
   1.880 +  }
   1.881 +}
   1.882 +
   1.883 +void
   1.884 +nsFileView::ReverseArray(nsTArray<nsCOMPtr<nsIFile> >& aArray)
   1.885 +{
   1.886 +  uint32_t count = aArray.Length();
   1.887 +  for (uint32_t i = 0; i < count/2; ++i) {
   1.888 +    // If we get references to the COMPtrs in the array, and then .swap() them
   1.889 +    // we avoid AdRef() / Release() calls.
   1.890 +    nsCOMPtr<nsIFile>& element = aArray[i];
   1.891 +    nsCOMPtr<nsIFile>& element2 = aArray[count - i - 1];
   1.892 +    element.swap(element2);
   1.893 +  }
   1.894 +}
   1.895 +
   1.896 +static int
   1.897 +SortNameCallback(const void* aElement1, const void* aElement2, void* aContext)
   1.898 +{
   1.899 +  nsIFile* file1 = *static_cast<nsIFile* const *>(aElement1);
   1.900 +  nsIFile* file2 = *static_cast<nsIFile* const *>(aElement2);
   1.901 +  
   1.902 +  nsAutoString leafName1, leafName2;
   1.903 +  file1->GetLeafName(leafName1);
   1.904 +  file2->GetLeafName(leafName2);
   1.905 +
   1.906 +  return Compare(leafName1, leafName2);
   1.907 +}
   1.908 +
   1.909 +static int
   1.910 +SortSizeCallback(const void* aElement1, const void* aElement2, void* aContext)
   1.911 +{
   1.912 +  nsIFile* file1 = *static_cast<nsIFile* const *>(aElement1);
   1.913 +  nsIFile* file2 = *static_cast<nsIFile* const *>(aElement2);
   1.914 +
   1.915 +  int64_t size1, size2;
   1.916 +  file1->GetFileSize(&size1);
   1.917 +  file2->GetFileSize(&size2);
   1.918 +
   1.919 +  if (size1 == size2)
   1.920 +    return 0;
   1.921 +
   1.922 +  return size1 < size2 ? -1 : 1;
   1.923 +}
   1.924 +
   1.925 +static int
   1.926 +SortDateCallback(const void* aElement1, const void* aElement2, void* aContext)
   1.927 +{
   1.928 +  nsIFile* file1 = *static_cast<nsIFile* const *>(aElement1);
   1.929 +  nsIFile* file2 = *static_cast<nsIFile* const *>(aElement2);
   1.930 +
   1.931 +  PRTime time1, time2;
   1.932 +  file1->GetLastModifiedTime(&time1);
   1.933 +  file2->GetLastModifiedTime(&time2);
   1.934 +
   1.935 +  if (time1 == time2)
   1.936 +    return 0;
   1.937 +
   1.938 +  return time1 < time2 ? -1 : 1;
   1.939 +}
   1.940 +
   1.941 +void
   1.942 +nsFileView::SortArray(nsTArray<nsCOMPtr<nsIFile> >& aArray)
   1.943 +{
   1.944 +  // We assume the array to be in filesystem order, which
   1.945 +  // for our purposes, is completely unordered.
   1.946 +
   1.947 +  int (*compareFunc)(const void*, const void*, void*);
   1.948 +
   1.949 +  switch (mSortType) {
   1.950 +  case sortName:
   1.951 +    compareFunc = SortNameCallback;
   1.952 +    break;
   1.953 +  case sortSize:
   1.954 +    compareFunc = SortSizeCallback;
   1.955 +    break;
   1.956 +  case sortDate:
   1.957 +    compareFunc = SortDateCallback;
   1.958 +    break;
   1.959 +  default:
   1.960 +    return;
   1.961 +  }
   1.962 +
   1.963 +  uint32_t count = aArray.Length();
   1.964 +
   1.965 +  nsIFile** array = new nsIFile*[count];
   1.966 +  for (uint32_t i = 0; i < count; ++i) {
   1.967 +    array[i] = aArray[i];
   1.968 +  }
   1.969 +
   1.970 +  NS_QuickSort(array, count, sizeof(nsIFile*), compareFunc, nullptr);
   1.971 +
   1.972 +  for (uint32_t i = 0; i < count; ++i) {
   1.973 +    // Use swap() to avoid refcounting.
   1.974 +    aArray[i].swap(array[i]);
   1.975 +  }
   1.976 +
   1.977 +  delete[] array;
   1.978 +}
   1.979 +
   1.980 +void
   1.981 +nsFileView::SortInternal()
   1.982 +{
   1.983 +  SortArray(mDirList);
   1.984 +  SortArray(mFilteredFiles);
   1.985 +
   1.986 +  if (mReverseSort) {
   1.987 +    ReverseArray(mDirList);
   1.988 +    ReverseArray(mFilteredFiles);
   1.989 +  }
   1.990 +}

mercurial