toolkit/components/filepicker/content/filepicker.js

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: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 const nsIFilePicker = Components.interfaces.nsIFilePicker;
michael@0 8 const nsIProperties = Components.interfaces.nsIProperties;
michael@0 9 const NS_DIRECTORYSERVICE_CONTRACTID = "@mozilla.org/file/directory_service;1";
michael@0 10 const NS_IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
michael@0 11 const nsITreeBoxObject = Components.interfaces.nsITreeBoxObject;
michael@0 12 const nsIFileView = Components.interfaces.nsIFileView;
michael@0 13 const NS_FILEVIEW_CONTRACTID = "@mozilla.org/filepicker/fileview;1";
michael@0 14 const nsITreeView = Components.interfaces.nsITreeView;
michael@0 15 const nsILocalFile = Components.interfaces.nsILocalFile;
michael@0 16 const nsIFile = Components.interfaces.nsIFile;
michael@0 17 const NS_LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
michael@0 18 const NS_PROMPTSERVICE_CONTRACTID = "@mozilla.org/embedcomp/prompt-service;1";
michael@0 19
michael@0 20 var sfile = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
michael@0 21 var retvals;
michael@0 22 var filePickerMode;
michael@0 23 var homeDir;
michael@0 24 var treeView;
michael@0 25 var allowURLs;
michael@0 26
michael@0 27 var textInput;
michael@0 28 var okButton;
michael@0 29
michael@0 30 var gFilePickerBundle;
michael@0 31
michael@0 32 // name of new directory entered by the user to be remembered
michael@0 33 // for next call of newDir() in case something goes wrong with creation
michael@0 34 var gNewDirName = { value: "" };
michael@0 35
michael@0 36 function filepickerLoad() {
michael@0 37 gFilePickerBundle = document.getElementById("bundle_filepicker");
michael@0 38
michael@0 39 textInput = document.getElementById("textInput");
michael@0 40 okButton = document.documentElement.getButton("accept");
michael@0 41 treeView = Components.classes[NS_FILEVIEW_CONTRACTID].createInstance(nsIFileView);
michael@0 42
michael@0 43 if (window.arguments) {
michael@0 44 var o = window.arguments[0];
michael@0 45 retvals = o.retvals; /* set this to a global var so we can set return values */
michael@0 46 const title = o.title;
michael@0 47 filePickerMode = o.mode;
michael@0 48 if (o.displayDirectory) {
michael@0 49 const directory = o.displayDirectory.path;
michael@0 50 }
michael@0 51
michael@0 52 const initialText = o.defaultString;
michael@0 53 const filterTitles = o.filters.titles;
michael@0 54 const filterTypes = o.filters.types;
michael@0 55 const numFilters = filterTitles.length;
michael@0 56
michael@0 57 document.title = title;
michael@0 58 allowURLs = o.allowURLs;
michael@0 59
michael@0 60 if (initialText) {
michael@0 61 textInput.value = initialText;
michael@0 62 }
michael@0 63 }
michael@0 64
michael@0 65 if (filePickerMode != nsIFilePicker.modeOpen && filePickerMode != nsIFilePicker.modeOpenMultiple) {
michael@0 66 var newDirButton = document.getElementById("newDirButton");
michael@0 67 newDirButton.removeAttribute("hidden");
michael@0 68 }
michael@0 69
michael@0 70 if (filePickerMode == nsIFilePicker.modeGetFolder) {
michael@0 71 var textInputLabel = document.getElementById("textInputLabel");
michael@0 72 textInputLabel.value = gFilePickerBundle.getString("dirTextInputLabel");
michael@0 73 textInputLabel.accessKey = gFilePickerBundle.getString("dirTextInputAccesskey");
michael@0 74 }
michael@0 75
michael@0 76 if ((filePickerMode == nsIFilePicker.modeOpen) ||
michael@0 77 (filePickerMode == nsIFilePicker.modeOpenMultiple) ||
michael@0 78 (filePickerMode == nsIFilePicker.modeSave)) {
michael@0 79
michael@0 80 /* build filter popup */
michael@0 81 var filterPopup = document.createElement("menupopup");
michael@0 82
michael@0 83 for (var i = 0; i < numFilters; i++) {
michael@0 84 var menuItem = document.createElement("menuitem");
michael@0 85 if (filterTypes[i] == "..apps")
michael@0 86 menuItem.setAttribute("label", filterTitles[i]);
michael@0 87 else
michael@0 88 menuItem.setAttribute("label", filterTitles[i] + " (" + filterTypes[i] + ")");
michael@0 89 menuItem.setAttribute("filters", filterTypes[i]);
michael@0 90 filterPopup.appendChild(menuItem);
michael@0 91 }
michael@0 92
michael@0 93 var filterMenuList = document.getElementById("filterMenuList");
michael@0 94 filterMenuList.appendChild(filterPopup);
michael@0 95 if (numFilters > 0)
michael@0 96 filterMenuList.selectedIndex = 0;
michael@0 97 var filterBox = document.getElementById("filterBox");
michael@0 98 filterBox.removeAttribute("hidden");
michael@0 99
michael@0 100 filterMenuList.selectedIndex = o.filterIndex;
michael@0 101
michael@0 102 treeView.setFilter(filterTypes[o.filterIndex]);
michael@0 103
michael@0 104 } else if (filePickerMode == nsIFilePicker.modeGetFolder) {
michael@0 105 treeView.showOnlyDirectories = true;
michael@0 106 }
michael@0 107
michael@0 108 // The dialog defaults to an "open" icon, change it to "save" if applicable
michael@0 109 if (filePickerMode == nsIFilePicker.modeSave)
michael@0 110 okButton.setAttribute("icon", "save");
michael@0 111
michael@0 112 // start out with a filename sort
michael@0 113 handleColumnClick("FilenameColumn");
michael@0 114
michael@0 115 try {
michael@0 116 setOKAction();
michael@0 117 } catch (exception) {
michael@0 118 // keep it set to "OK"
michael@0 119 }
michael@0 120
michael@0 121 // setup the dialogOverlay.xul button handlers
michael@0 122 retvals.buttonStatus = nsIFilePicker.returnCancel;
michael@0 123
michael@0 124 var tree = document.getElementById("directoryTree");
michael@0 125 if (filePickerMode == nsIFilePicker.modeOpenMultiple)
michael@0 126 tree.removeAttribute("seltype");
michael@0 127
michael@0 128 tree.treeBoxObject.view = treeView;
michael@0 129
michael@0 130 // Start out with the ok button disabled since nothing will be
michael@0 131 // selected and nothing will be in the text field.
michael@0 132 okButton.disabled = filePickerMode != nsIFilePicker.modeGetFolder;
michael@0 133
michael@0 134 // This allows the window to show onscreen before we begin
michael@0 135 // loading the file list
michael@0 136
michael@0 137 setTimeout(setInitialDirectory, 0, directory);
michael@0 138 }
michael@0 139
michael@0 140 function setInitialDirectory(directory)
michael@0 141 {
michael@0 142 // Start in the user's home directory
michael@0 143 var dirService = Components.classes[NS_DIRECTORYSERVICE_CONTRACTID]
michael@0 144 .getService(nsIProperties);
michael@0 145 homeDir = dirService.get("Home", Components.interfaces.nsIFile);
michael@0 146
michael@0 147 if (directory) {
michael@0 148 sfile.initWithPath(directory);
michael@0 149 if (!sfile.exists() || !sfile.isDirectory())
michael@0 150 directory = false;
michael@0 151 }
michael@0 152 if (!directory) {
michael@0 153 sfile.initWithPath(homeDir.path);
michael@0 154 }
michael@0 155
michael@0 156 gotoDirectory(sfile);
michael@0 157 }
michael@0 158
michael@0 159 function onFilterChanged(target)
michael@0 160 {
michael@0 161 // Do this on a timeout callback so the filter list can roll up
michael@0 162 // and we don't keep the mouse grabbed while we are refiltering.
michael@0 163
michael@0 164 setTimeout(changeFilter, 0, target.getAttribute("filters"));
michael@0 165 }
michael@0 166
michael@0 167 function changeFilter(filterTypes)
michael@0 168 {
michael@0 169 window.setCursor("wait");
michael@0 170 treeView.setFilter(filterTypes);
michael@0 171 window.setCursor("auto");
michael@0 172 }
michael@0 173
michael@0 174 function showErrorDialog(titleStrName, messageStrName, file)
michael@0 175 {
michael@0 176 var errorTitle =
michael@0 177 gFilePickerBundle.getFormattedString(titleStrName, [file.path]);
michael@0 178 var errorMessage =
michael@0 179 gFilePickerBundle.getFormattedString(messageStrName, [file.path]);
michael@0 180 var promptService =
michael@0 181 Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
michael@0 182
michael@0 183 promptService.alert(window, errorTitle, errorMessage);
michael@0 184 }
michael@0 185
michael@0 186 function openOnOK()
michael@0 187 {
michael@0 188 var dir = treeView.selectedFiles.queryElementAt(0, nsIFile);
michael@0 189 if (dir)
michael@0 190 gotoDirectory(dir);
michael@0 191
michael@0 192 return false;
michael@0 193 }
michael@0 194
michael@0 195 function selectOnOK()
michael@0 196 {
michael@0 197 var errorTitle, errorMessage, promptService;
michael@0 198 var ret = nsIFilePicker.returnOK;
michael@0 199
michael@0 200 var isDir = false;
michael@0 201 var isFile = false;
michael@0 202
michael@0 203 retvals.filterIndex = document.getElementById("filterMenuList").selectedIndex;
michael@0 204 retvals.fileURL = null;
michael@0 205
michael@0 206 if (allowURLs) {
michael@0 207 try {
michael@0 208 var ios = Components.classes[NS_IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
michael@0 209 retvals.fileURL = ios.newURI(textInput.value, null, null);
michael@0 210 var fileList = [];
michael@0 211 if (retvals.fileURL instanceof Components.interfaces.nsIFileURL)
michael@0 212 fileList.push(retvals.fileURL.file);
michael@0 213 gFilesEnumerator.mFiles = fileList;
michael@0 214 retvals.files = gFilesEnumerator;
michael@0 215 retvals.buttonStatus = ret;
michael@0 216
michael@0 217 return true;
michael@0 218 } catch (e) {
michael@0 219 }
michael@0 220 }
michael@0 221
michael@0 222 var fileList = processPath(textInput.value);
michael@0 223 if (!fileList) {
michael@0 224 // generic error message, should probably never happen
michael@0 225 showErrorDialog("errorPathProblemTitle",
michael@0 226 "errorPathProblemMessage",
michael@0 227 textInput.value);
michael@0 228 return false;
michael@0 229 }
michael@0 230
michael@0 231 var curFileIndex;
michael@0 232 for (curFileIndex = 0; curFileIndex < fileList.length &&
michael@0 233 ret != nsIFilePicker.returnCancel; ++curFileIndex) {
michael@0 234 var file = fileList[curFileIndex].QueryInterface(nsIFile);
michael@0 235
michael@0 236 // try to normalize - if this fails we will ignore the error
michael@0 237 // because we will notice the
michael@0 238 // error later and show a fitting error alert.
michael@0 239 try{
michael@0 240 file.normalize();
michael@0 241 } catch(e) {
michael@0 242 //promptService.alert(window, "Problem", "normalize failed, continuing");
michael@0 243 }
michael@0 244
michael@0 245 var fileExists = file.exists();
michael@0 246
michael@0 247 if (!fileExists && (filePickerMode == nsIFilePicker.modeOpen ||
michael@0 248 filePickerMode == nsIFilePicker.modeOpenMultiple)) {
michael@0 249 showErrorDialog("errorOpenFileDoesntExistTitle",
michael@0 250 "errorOpenFileDoesntExistMessage",
michael@0 251 file);
michael@0 252 return false;
michael@0 253 }
michael@0 254
michael@0 255 if (!fileExists && filePickerMode == nsIFilePicker.modeGetFolder) {
michael@0 256 showErrorDialog("errorDirDoesntExistTitle",
michael@0 257 "errorDirDoesntExistMessage",
michael@0 258 file);
michael@0 259 return false;
michael@0 260 }
michael@0 261
michael@0 262 if (fileExists) {
michael@0 263 isDir = file.isDirectory();
michael@0 264 isFile = file.isFile();
michael@0 265 }
michael@0 266
michael@0 267 switch(filePickerMode) {
michael@0 268 case nsIFilePicker.modeOpen:
michael@0 269 case nsIFilePicker.modeOpenMultiple:
michael@0 270 if (isFile) {
michael@0 271 if (file.isReadable()) {
michael@0 272 retvals.directory = file.parent.path;
michael@0 273 } else {
michael@0 274 showErrorDialog("errorOpeningFileTitle",
michael@0 275 "openWithoutPermissionMessage_file",
michael@0 276 file);
michael@0 277 ret = nsIFilePicker.returnCancel;
michael@0 278 }
michael@0 279 } else if (isDir) {
michael@0 280 if (!sfile.equals(file)) {
michael@0 281 gotoDirectory(file);
michael@0 282 }
michael@0 283 textInput.value = "";
michael@0 284 doEnabling();
michael@0 285 ret = nsIFilePicker.returnCancel;
michael@0 286 }
michael@0 287 break;
michael@0 288 case nsIFilePicker.modeSave:
michael@0 289 if (isFile) { // can only be true if file.exists()
michael@0 290 if (!file.isWritable()) {
michael@0 291 showErrorDialog("errorSavingFileTitle",
michael@0 292 "saveWithoutPermissionMessage_file",
michael@0 293 file);
michael@0 294 ret = nsIFilePicker.returnCancel;
michael@0 295 } else {
michael@0 296 // we need to pop up a dialog asking if you want to save
michael@0 297 var confirmTitle = gFilePickerBundle.getString("confirmTitle");
michael@0 298 var message =
michael@0 299 gFilePickerBundle.getFormattedString("confirmFileReplacing",
michael@0 300 [file.path]);
michael@0 301
michael@0 302 promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
michael@0 303 var rv = promptService.confirm(window, confirmTitle, message);
michael@0 304 if (rv) {
michael@0 305 ret = nsIFilePicker.returnReplace;
michael@0 306 retvals.directory = file.parent.path;
michael@0 307 } else {
michael@0 308 ret = nsIFilePicker.returnCancel;
michael@0 309 }
michael@0 310 }
michael@0 311 } else if (isDir) {
michael@0 312 if (!sfile.equals(file)) {
michael@0 313 gotoDirectory(file);
michael@0 314 }
michael@0 315 textInput.value = "";
michael@0 316 doEnabling();
michael@0 317 ret = nsIFilePicker.returnCancel;
michael@0 318 } else {
michael@0 319 var parent = file.parent;
michael@0 320 if (parent.exists() && parent.isDirectory() && parent.isWritable()) {
michael@0 321 retvals.directory = parent.path;
michael@0 322 } else {
michael@0 323 var oldParent = parent;
michael@0 324 while (!parent.exists()) {
michael@0 325 oldParent = parent;
michael@0 326 parent = parent.parent;
michael@0 327 }
michael@0 328 errorTitle =
michael@0 329 gFilePickerBundle.getFormattedString("errorSavingFileTitle",
michael@0 330 [file.path]);
michael@0 331 if (parent.isFile()) {
michael@0 332 errorMessage =
michael@0 333 gFilePickerBundle.getFormattedString("saveParentIsFileMessage",
michael@0 334 [parent.path, file.path]);
michael@0 335 } else {
michael@0 336 errorMessage =
michael@0 337 gFilePickerBundle.getFormattedString("saveParentDoesntExistMessage",
michael@0 338 [oldParent.path, file.path]);
michael@0 339 }
michael@0 340 if (!parent.isWritable()) {
michael@0 341 errorMessage =
michael@0 342 gFilePickerBundle.getFormattedString("saveWithoutPermissionMessage_dir", [parent.path]);
michael@0 343 }
michael@0 344 promptService = Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
michael@0 345 promptService.alert(window, errorTitle, errorMessage);
michael@0 346 ret = nsIFilePicker.returnCancel;
michael@0 347 }
michael@0 348 }
michael@0 349 break;
michael@0 350 case nsIFilePicker.modeGetFolder:
michael@0 351 if (isDir) {
michael@0 352 retvals.directory = file.parent.path;
michael@0 353 } else { // if nothing selected, the current directory will be fine
michael@0 354 retvals.directory = sfile.path;
michael@0 355 }
michael@0 356 break;
michael@0 357 }
michael@0 358 }
michael@0 359
michael@0 360 gFilesEnumerator.mFiles = fileList;
michael@0 361
michael@0 362 retvals.files = gFilesEnumerator;
michael@0 363 retvals.buttonStatus = ret;
michael@0 364
michael@0 365 return (ret != nsIFilePicker.returnCancel);
michael@0 366 }
michael@0 367
michael@0 368 var gFilesEnumerator = {
michael@0 369 mFiles: null,
michael@0 370 mIndex: 0,
michael@0 371
michael@0 372 hasMoreElements: function()
michael@0 373 {
michael@0 374 return (this.mIndex < this.mFiles.length);
michael@0 375 },
michael@0 376 getNext: function()
michael@0 377 {
michael@0 378 if (this.mIndex >= this.mFiles.length)
michael@0 379 throw Components.results.NS_ERROR_FAILURE;
michael@0 380 return this.mFiles[this.mIndex++];
michael@0 381 }
michael@0 382 };
michael@0 383
michael@0 384 function onCancel()
michael@0 385 {
michael@0 386 // Close the window.
michael@0 387 retvals.buttonStatus = nsIFilePicker.returnCancel;
michael@0 388 retvals.file = null;
michael@0 389 retvals.files = null;
michael@0 390 return true;
michael@0 391 }
michael@0 392
michael@0 393 function onDblClick(e) {
michael@0 394 // we only care about button 0 (left click) events
michael@0 395 if (e.button != 0) return;
michael@0 396
michael@0 397 var t = e.originalTarget;
michael@0 398 if (t.localName != "treechildren")
michael@0 399 return;
michael@0 400
michael@0 401 openSelectedFile();
michael@0 402 }
michael@0 403
michael@0 404 function openSelectedFile() {
michael@0 405 var fileList = treeView.selectedFiles;
michael@0 406 if (fileList.length == 0)
michael@0 407 return;
michael@0 408
michael@0 409 var file = fileList.queryElementAt(0, nsIFile);
michael@0 410 if (file.isDirectory())
michael@0 411 gotoDirectory(file);
michael@0 412 else if (file.isFile())
michael@0 413 document.documentElement.acceptDialog();
michael@0 414 }
michael@0 415
michael@0 416 function onClick(e) {
michael@0 417 var t = e.originalTarget;
michael@0 418 if (t.localName == "treecol")
michael@0 419 handleColumnClick(t.id);
michael@0 420 }
michael@0 421
michael@0 422 function convertColumnIDtoSortType(columnID) {
michael@0 423 var sortKey;
michael@0 424
michael@0 425 switch (columnID) {
michael@0 426 case "FilenameColumn":
michael@0 427 sortKey = nsIFileView.sortName;
michael@0 428 break;
michael@0 429 case "FileSizeColumn":
michael@0 430 sortKey = nsIFileView.sortSize;
michael@0 431 break;
michael@0 432 case "LastModifiedColumn":
michael@0 433 sortKey = nsIFileView.sortDate;
michael@0 434 break;
michael@0 435 default:
michael@0 436 dump("unsupported sort column: " + columnID + "\n");
michael@0 437 sortKey = 0;
michael@0 438 break;
michael@0 439 }
michael@0 440
michael@0 441 return sortKey;
michael@0 442 }
michael@0 443
michael@0 444 function handleColumnClick(columnID) {
michael@0 445 var sortType = convertColumnIDtoSortType(columnID);
michael@0 446 var sortOrder = (treeView.sortType == sortType) ? !treeView.reverseSort : false;
michael@0 447 treeView.sort(sortType, sortOrder);
michael@0 448
michael@0 449 // set the sort indicator on the column we are sorted by
michael@0 450 var sortedColumn = document.getElementById(columnID);
michael@0 451 if (treeView.reverseSort) {
michael@0 452 sortedColumn.setAttribute("sortDirection", "descending");
michael@0 453 } else {
michael@0 454 sortedColumn.setAttribute("sortDirection", "ascending");
michael@0 455 }
michael@0 456
michael@0 457 // remove the sort indicator from the rest of the columns
michael@0 458 var currCol = sortedColumn.parentNode.firstChild;
michael@0 459 while (currCol) {
michael@0 460 if (currCol != sortedColumn && currCol.localName == "treecol")
michael@0 461 currCol.removeAttribute("sortDirection");
michael@0 462 currCol = currCol.nextSibling;
michael@0 463 }
michael@0 464 }
michael@0 465
michael@0 466 function onKeypress(e) {
michael@0 467 if (e.keyCode == 8) /* backspace */
michael@0 468 goUp();
michael@0 469
michael@0 470 /* enter is handled by the ondialogaccept handler */
michael@0 471 }
michael@0 472
michael@0 473 function doEnabling() {
michael@0 474 if (filePickerMode != nsIFilePicker.modeGetFolder)
michael@0 475 // Maybe add check if textInput.value would resolve to an existing
michael@0 476 // file or directory in .modeOpen. Too costly I think.
michael@0 477 okButton.disabled = (textInput.value == "")
michael@0 478 }
michael@0 479
michael@0 480 function onTreeFocus(event) {
michael@0 481 // Reset the button label and enabled/disabled state.
michael@0 482 onFileSelected(treeView.selectedFiles);
michael@0 483 }
michael@0 484
michael@0 485 function setOKAction(file) {
michael@0 486 var buttonLabel;
michael@0 487 var buttonIcon = "open"; // used in all but one case
michael@0 488
michael@0 489 if (file && file.isDirectory()) {
michael@0 490 document.documentElement.setAttribute("ondialogaccept", "return openOnOK();");
michael@0 491 buttonLabel = gFilePickerBundle.getString("openButtonLabel");
michael@0 492 }
michael@0 493 else {
michael@0 494 document.documentElement.setAttribute("ondialogaccept", "return selectOnOK();");
michael@0 495 switch(filePickerMode) {
michael@0 496 case nsIFilePicker.modeGetFolder:
michael@0 497 buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
michael@0 498 break;
michael@0 499 case nsIFilePicker.modeOpen:
michael@0 500 case nsIFilePicker.modeOpenMultiple:
michael@0 501 buttonLabel = gFilePickerBundle.getString("openButtonLabel");
michael@0 502 break;
michael@0 503 case nsIFilePicker.modeSave:
michael@0 504 buttonLabel = gFilePickerBundle.getString("saveButtonLabel");
michael@0 505 buttonIcon = "save";
michael@0 506 break;
michael@0 507 }
michael@0 508 }
michael@0 509 okButton.setAttribute("label", buttonLabel);
michael@0 510 okButton.setAttribute("icon", buttonIcon);
michael@0 511 }
michael@0 512
michael@0 513 function onSelect(event) {
michael@0 514 onFileSelected(treeView.selectedFiles);
michael@0 515 }
michael@0 516
michael@0 517 function onFileSelected(/* nsIArray */ selectedFileList) {
michael@0 518 var validFileSelected = false;
michael@0 519 var invalidSelection = false;
michael@0 520 var file;
michael@0 521 var fileCount = selectedFileList.length;
michael@0 522
michael@0 523 for (var index = 0; index < fileCount; ++index) {
michael@0 524 file = selectedFileList.queryElementAt(index, nsIFile);
michael@0 525 if (file) {
michael@0 526 var path = file.leafName;
michael@0 527
michael@0 528 if (path) {
michael@0 529 var isDir = file.isDirectory();
michael@0 530 if ((filePickerMode == nsIFilePicker.modeGetFolder) || !isDir) {
michael@0 531 if (!validFileSelected)
michael@0 532 textInput.value = "";
michael@0 533 addToTextFieldValue(path);
michael@0 534 }
michael@0 535
michael@0 536 if (isDir && fileCount > 1) {
michael@0 537 // The user has selected multiple items, and one of them is
michael@0 538 // a directory. This is not a valid state, so we'll disable
michael@0 539 // the ok button.
michael@0 540 invalidSelection = true;
michael@0 541 }
michael@0 542
michael@0 543 validFileSelected = true;
michael@0 544 }
michael@0 545 }
michael@0 546 }
michael@0 547
michael@0 548 if (validFileSelected) {
michael@0 549 setOKAction(file);
michael@0 550 okButton.disabled = invalidSelection;
michael@0 551 } else if (filePickerMode != nsIFilePicker.modeGetFolder)
michael@0 552 okButton.disabled = (textInput.value == "");
michael@0 553 }
michael@0 554
michael@0 555 function addToTextFieldValue(path)
michael@0 556 {
michael@0 557 var newValue = "";
michael@0 558
michael@0 559 if (textInput.value == "")
michael@0 560 newValue = path.replace(/\"/g, "\\\"");
michael@0 561 else {
michael@0 562 // Quote the existing text if needed,
michael@0 563 // then append the new filename (quoted and escaped)
michael@0 564 if (textInput.value[0] != '"')
michael@0 565 newValue = '"' + textInput.value.replace(/\"/g, "\\\"") + '"';
michael@0 566 else
michael@0 567 newValue = textInput.value;
michael@0 568
michael@0 569 newValue = newValue + ' "' + path.replace(/\"/g, "\\\"") + '"';
michael@0 570 }
michael@0 571
michael@0 572 textInput.value = newValue;
michael@0 573 }
michael@0 574
michael@0 575 function onTextFieldFocus() {
michael@0 576 setOKAction(null);
michael@0 577 doEnabling();
michael@0 578 }
michael@0 579
michael@0 580 function onDirectoryChanged(target)
michael@0 581 {
michael@0 582 var path = target.getAttribute("label");
michael@0 583
michael@0 584 var file = Components.classes[NS_LOCAL_FILE_CONTRACTID].createInstance(nsILocalFile);
michael@0 585 file.initWithPath(path);
michael@0 586
michael@0 587 if (!sfile.equals(file)) {
michael@0 588 // Do this on a timeout callback so the directory list can roll up
michael@0 589 // and we don't keep the mouse grabbed while we are loading.
michael@0 590
michael@0 591 setTimeout(gotoDirectory, 0, file);
michael@0 592 }
michael@0 593 }
michael@0 594
michael@0 595 function populateAncestorList(directory) {
michael@0 596 var menu = document.getElementById("lookInMenu");
michael@0 597
michael@0 598 while (menu.hasChildNodes()) {
michael@0 599 menu.removeChild(menu.firstChild);
michael@0 600 }
michael@0 601
michael@0 602 var menuItem = document.createElement("menuitem");
michael@0 603 menuItem.setAttribute("label", directory.path);
michael@0 604 menuItem.setAttribute("crop", "start");
michael@0 605 menu.appendChild(menuItem);
michael@0 606
michael@0 607 // .parent is _sometimes_ null, see bug 121489. Do a dance around that.
michael@0 608 var parent = directory.parent;
michael@0 609 while (parent && !parent.equals(directory)) {
michael@0 610 menuItem = document.createElement("menuitem");
michael@0 611 menuItem.setAttribute("label", parent.path);
michael@0 612 menuItem.setAttribute("crop", "start");
michael@0 613 menu.appendChild(menuItem);
michael@0 614 directory = parent;
michael@0 615 parent = directory.parent;
michael@0 616 }
michael@0 617
michael@0 618 var menuList = document.getElementById("lookInMenuList");
michael@0 619 menuList.selectedIndex = 0;
michael@0 620 }
michael@0 621
michael@0 622 function goUp() {
michael@0 623 try {
michael@0 624 var parent = sfile.parent;
michael@0 625 } catch(ex) { dump("can't get parent directory\n"); }
michael@0 626
michael@0 627 if (parent) {
michael@0 628 gotoDirectory(parent);
michael@0 629 }
michael@0 630 }
michael@0 631
michael@0 632 function goHome() {
michael@0 633 gotoDirectory(homeDir);
michael@0 634 }
michael@0 635
michael@0 636 function newDir() {
michael@0 637 var file;
michael@0 638 var promptService =
michael@0 639 Components.classes[NS_PROMPTSERVICE_CONTRACTID].getService(Components.interfaces.nsIPromptService);
michael@0 640 var dialogTitle =
michael@0 641 gFilePickerBundle.getString("promptNewDirTitle");
michael@0 642 var dialogMsg =
michael@0 643 gFilePickerBundle.getString("promptNewDirMessage");
michael@0 644 var ret = promptService.prompt(window, dialogTitle, dialogMsg, gNewDirName, null, {value:0});
michael@0 645
michael@0 646 if (ret) {
michael@0 647 file = processPath(gNewDirName.value);
michael@0 648 if (!file) {
michael@0 649 showErrorDialog("errorCreateNewDirTitle",
michael@0 650 "errorCreateNewDirMessage",
michael@0 651 file);
michael@0 652 return false;
michael@0 653 }
michael@0 654
michael@0 655 file = file[0].QueryInterface(nsIFile);
michael@0 656 if (file.exists()) {
michael@0 657 showErrorDialog("errorNewDirDoesExistTitle",
michael@0 658 "errorNewDirDoesExistMessage",
michael@0 659 file);
michael@0 660 return false;
michael@0 661 }
michael@0 662
michael@0 663 var parent = file.parent;
michael@0 664 if (!(parent.exists() && parent.isDirectory() && parent.isWritable())) {
michael@0 665 var oldParent = parent;
michael@0 666 while (!parent.exists()) {
michael@0 667 oldParent = parent;
michael@0 668 parent = parent.parent;
michael@0 669 }
michael@0 670 if (parent.isFile()) {
michael@0 671 showErrorDialog("errorCreateNewDirTitle",
michael@0 672 "errorCreateNewDirIsFileMessage",
michael@0 673 parent);
michael@0 674 return false;
michael@0 675 }
michael@0 676 if (!parent.isWritable()) {
michael@0 677 showErrorDialog("errorCreateNewDirTitle",
michael@0 678 "errorCreateNewDirPermissionMessage",
michael@0 679 parent);
michael@0 680 return false;
michael@0 681 }
michael@0 682 }
michael@0 683
michael@0 684 try {
michael@0 685 file.create(nsIFile.DIRECTORY_TYPE, 0755);
michael@0 686 } catch (e) {
michael@0 687 showErrorDialog("errorCreateNewDirTitle",
michael@0 688 "errorCreateNewDirMessage",
michael@0 689 file);
michael@0 690 return false;
michael@0 691 }
michael@0 692 file.normalize(); // ... in case ".." was used in the path
michael@0 693 gotoDirectory(file);
michael@0 694 // we remember and reshow a dirname if something goes wrong
michael@0 695 // so that errors can be corrected more easily. If all went well,
michael@0 696 // reset the default value to blank
michael@0 697 gNewDirName = { value: "" };
michael@0 698 }
michael@0 699 return true;
michael@0 700 }
michael@0 701
michael@0 702 function gotoDirectory(directory) {
michael@0 703 window.setCursor("wait");
michael@0 704 try {
michael@0 705 populateAncestorList(directory);
michael@0 706 treeView.setDirectory(directory);
michael@0 707 document.getElementById("errorShower").selectedIndex = 0;
michael@0 708 } catch(ex) {
michael@0 709 document.getElementById("errorShower").selectedIndex = 1;
michael@0 710 }
michael@0 711
michael@0 712 window.setCursor("auto");
michael@0 713
michael@0 714 if (filePickerMode == nsIFilePicker.modeGetFolder) {
michael@0 715 textInput.value = "";
michael@0 716 }
michael@0 717 textInput.focus();
michael@0 718 textInput.setAttribute("autocompletesearchparam", directory.path);
michael@0 719 sfile = directory;
michael@0 720 }
michael@0 721
michael@0 722 function toggleShowHidden(event) {
michael@0 723 treeView.showHiddenFiles = !treeView.showHiddenFiles;
michael@0 724 }
michael@0 725
michael@0 726 // from the current directory and whatever was entered
michael@0 727 // in the entry field, try to make a new path. This
michael@0 728 // uses "/" as the directory separator, "~" as a shortcut
michael@0 729 // for the home directory (but only when seen at the start
michael@0 730 // of a path), and ".." to denote the parent directory.
michael@0 731 // returns an array of the files listed,
michael@0 732 // or false if an error occurred.
michael@0 733 function processPath(path)
michael@0 734 {
michael@0 735 var fileArray = new Array();
michael@0 736 var strLength = path.length;
michael@0 737
michael@0 738 if (path[0] == '"' && filePickerMode == nsIFilePicker.modeOpenMultiple &&
michael@0 739 strLength > 1) {
michael@0 740 // we have a quoted list of filenames, separated by spaces.
michael@0 741 // iterate the list and process each file.
michael@0 742
michael@0 743 var curFileStart = 1;
michael@0 744
michael@0 745 while (1) {
michael@0 746 var nextQuote;
michael@0 747
michael@0 748 // Look for an unescaped quote
michael@0 749 var quoteSearchStart = curFileStart + 1;
michael@0 750 do {
michael@0 751 nextQuote = path.indexOf('"', quoteSearchStart);
michael@0 752 quoteSearchStart = nextQuote + 1;
michael@0 753 } while (nextQuote != -1 && path[nextQuote - 1] == '\\');
michael@0 754
michael@0 755 if (nextQuote == -1) {
michael@0 756 // we have a filename with no trailing quote.
michael@0 757 // just assume that the filename ends at the end of the string.
michael@0 758
michael@0 759 if (!processPathEntry(path.substring(curFileStart), fileArray))
michael@0 760 return false;
michael@0 761 break;
michael@0 762 }
michael@0 763
michael@0 764 if (!processPathEntry(path.substring(curFileStart, nextQuote), fileArray))
michael@0 765 return false;
michael@0 766
michael@0 767 curFileStart = path.indexOf('"', nextQuote + 1);
michael@0 768 if (curFileStart == -1) {
michael@0 769 // no more quotes, but if we're not at the end of the string,
michael@0 770 // go ahead and process the remaining text.
michael@0 771
michael@0 772 if (nextQuote < strLength - 1)
michael@0 773 if (!processPathEntry(path.substring(nextQuote + 1), fileArray))
michael@0 774 return false;
michael@0 775 break;
michael@0 776 }
michael@0 777 ++curFileStart;
michael@0 778 }
michael@0 779 } else {
michael@0 780 // If we didn't start with a quote, assume we just have a single file.
michael@0 781 if (!processPathEntry(path, fileArray))
michael@0 782 return false;
michael@0 783 }
michael@0 784
michael@0 785 return fileArray;
michael@0 786 }
michael@0 787
michael@0 788 function processPathEntry(path, fileArray)
michael@0 789 {
michael@0 790 var filePath;
michael@0 791 var file;
michael@0 792
michael@0 793 try {
michael@0 794 file = sfile.clone().QueryInterface(nsILocalFile);
michael@0 795 } catch(e) {
michael@0 796 dump("Couldn't clone\n"+e);
michael@0 797 return false;
michael@0 798 }
michael@0 799
michael@0 800 var tilde_file = file.clone();
michael@0 801 tilde_file.append("~");
michael@0 802 if (path[0] == '~' && // Expand ~ to $HOME, except:
michael@0 803 !(path == "~" && tilde_file.exists()) && // If ~ was entered and such a file exists, don't expand
michael@0 804 (path.length == 1 || path[1] == "/")) // We don't want to expand ~file to ${HOME}file
michael@0 805 filePath = homeDir.path + path.substring(1);
michael@0 806 else
michael@0 807 filePath = path;
michael@0 808
michael@0 809 // Unescape quotes
michael@0 810 filePath = filePath.replace(/\\\"/g, "\"");
michael@0 811
michael@0 812 if (filePath[0] == '/') /* an absolute path was entered */
michael@0 813 file.initWithPath(filePath);
michael@0 814 else if ((filePath.indexOf("/../") > 0) ||
michael@0 815 (filePath.substr(-3) == "/..") ||
michael@0 816 (filePath.substr(0,3) == "../") ||
michael@0 817 (filePath == "..")) {
michael@0 818 /* appendRelativePath doesn't allow .. */
michael@0 819 try{
michael@0 820 file.initWithPath(file.path + "/" + filePath);
michael@0 821 } catch (e) {
michael@0 822 dump("Couldn't init path\n"+e);
michael@0 823 return false;
michael@0 824 }
michael@0 825 }
michael@0 826 else {
michael@0 827 try {
michael@0 828 file.appendRelativePath(filePath);
michael@0 829 } catch (e) {
michael@0 830 dump("Couldn't append path\n"+e);
michael@0 831 return false;
michael@0 832 }
michael@0 833 }
michael@0 834
michael@0 835 fileArray[fileArray.length] = file;
michael@0 836 return true;
michael@0 837 }

mercurial