toolkit/components/filepicker/nsFileView.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial