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 +}