home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 January / 01_02.iso / software / netscape62win / browser.xpi / bin / chrome / toolkit.jar / content / global / filepicker.js < prev    next >
Encoding:
Text File  |  2001-08-25  |  15.4 KB  |  530 lines

  1. /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is mozilla.org code.
  14.  *
  15.  * The Initial Developer of the Original Code is Netscape Communications
  16.  * Corporation.  Portions created by Netscape are
  17.  * Copyright (C) 2000 Netscape Communications Corporation. All
  18.  * Rights Reserved.
  19.  *
  20.  * Contributor(s): 
  21.  *  Stuart Parmenter <pavlov@netscape.com>
  22.  *  Brian Ryner <bryner@netscape.com>
  23.  *  Jan Varga <varga@utcru.sk>
  24.  *  Peter Annema <disttsc@bart.nl>
  25.  */
  26.  
  27. const nsIFilePicker       = Components.interfaces.nsIFilePicker;
  28. const nsIDirectoryServiceProvider = Components.interfaces.nsIDirectoryServiceProvider;
  29. const nsIDirectoryServiceProvider_CONTRACTID = "@mozilla.org/file/directory_service;1";
  30. const nsIOutlinerBoxObject = Components.interfaces.nsIOutlinerBoxObject;
  31.  
  32. var sfile = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
  33. var retvals;
  34. var filePickerMode;
  35. var homeDir;
  36. var outlinerView;
  37.  
  38. var textInput;
  39. var okButton;
  40.  
  41. var gFilePickerBundle;
  42.  
  43. function filepickerLoad() {
  44.   gFilePickerBundle = document.getElementById("bundle_filepicker");
  45.  
  46.   textInput = document.getElementById("textInput");
  47.   okButton = document.getElementById("ok");
  48.   outlinerView = new nsFileView();
  49.   outlinerView.selectionCallback = onSelect;
  50.  
  51.   if (window.arguments) {
  52.     var o = window.arguments[0];
  53.     retvals = o.retvals; /* set this to a global var so we can set return values */
  54.     const title = o.title;
  55.     filePickerMode = o.mode;
  56.     if (o.displayDirectory) {
  57.       const directory = o.displayDirectory.unicodePath;
  58.     }
  59.     const initialText = o.defaultString;
  60.     const filterTitles = o.filters.titles;
  61.     const filterTypes = o.filters.types;
  62.     const numFilters = filterTitles.length;
  63.  
  64.     window.title = title;
  65.  
  66.     if (initialText) {
  67.       textInput.value = initialText;
  68.     }
  69.   }
  70.  
  71.   if ((filePickerMode == nsIFilePicker.modeOpen) ||
  72.       (filePickerMode == nsIFilePicker.modeSave)) {
  73.  
  74.     outlinerView.setFilter(filterTypes[0]);
  75.  
  76.     /* build filter popup */
  77.     var filterPopup = document.createElement("menupopup");
  78.  
  79.     for (var i = 0; i < numFilters; i++) {
  80.       var menuItem = document.createElement("menuitem");
  81.       menuItem.setAttribute("label", filterTitles[i] + " (" + filterTypes[i] + ")");
  82.       menuItem.setAttribute("filters", filterTypes[i]);
  83.       filterPopup.appendChild(menuItem);
  84.     }
  85.  
  86.     var filterMenuList = document.getElementById("filterMenuList");
  87.     filterMenuList.appendChild(filterPopup);
  88.     if (numFilters > 0)
  89.       filterMenuList.selectedIndex = 0;
  90.     var filterBox = document.getElementById("filterBox");
  91.     filterBox.removeAttribute("hidden");
  92.   } else if (filePickerMode == nsIFilePicker.modeGetFolder) {
  93.     outlinerView.showOnlyDirectories = true;
  94.   }
  95.  
  96.   // start out with a filename sort
  97.   handleColumnClick("FilenameColumn");
  98.  
  99.   try {
  100.     var buttonLabel = getOKAction();
  101.     okButton.setAttribute("label", buttonLabel);
  102.   } catch (exception) {
  103.     // keep it set to "OK"
  104.   }
  105.  
  106.   // setup the dialogOverlay.xul button handlers
  107.   doSetOKCancel(selectOnOK, onCancel);
  108.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  109.  
  110.   var outliner = document.getElementById("directoryOutliner");
  111.   outliner.outlinerBoxObject.view = outlinerView;
  112.  
  113.   // Start out with the ok button disabled since nothing will be
  114.   // selected and nothing will be in the text field.
  115.   okButton.disabled = true;
  116.   textInput.focus();
  117.  
  118.   // This allows the window to show onscreen before we begin
  119.   // loading the file list
  120.  
  121.   setTimeout(setInitialDirectory, 0, directory);
  122. }
  123.  
  124. function setInitialDirectory(directory)
  125. {
  126.   // get the home dir
  127.   var dirServiceProvider = Components.classes[nsIDirectoryServiceProvider_CONTRACTID]
  128.                                      .getService(nsIDirectoryServiceProvider);
  129.   var persistent = new Object();
  130.   homeDir = dirServiceProvider.getFile("Home", persistent);
  131.  
  132.   if (directory) {
  133.     sfile.initWithUnicodePath(directory);
  134.   }
  135.   if (!directory || !(sfile.exists() && sfile.isDirectory())) {
  136.     // Start in the user's home directory
  137.     sfile.initWithUnicodePath(homeDir.unicodePath);
  138.   }
  139.  
  140.   gotoDirectory(sfile);
  141. }
  142.  
  143. function onFilterChanged(target)
  144. {
  145.   // Do this on a timeout callback so the filter list can roll up
  146.   // and we don't keep the mouse grabbed while we are refiltering.
  147.  
  148.   setTimeout(changeFilter, 0, target.getAttribute("filters"));
  149. }
  150.  
  151. function changeFilter(filterTypes)
  152. {
  153.   window.setCursor("wait");
  154.   outlinerView.setFilter(filterTypes);
  155.   window.setCursor("auto");
  156. }
  157.  
  158. function openOnOK()
  159. {
  160.   var dir = outlinerView.getSelectedFile();
  161.   if (dir)
  162.     gotoDirectory(dir);
  163.   retvals.file = dir;
  164.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  165.   doSetOKCancel(selectOnOK, onCancel);
  166.   return false;
  167. }
  168.  
  169. function selectOnOK()
  170. {
  171.   var errorTitle, errorMessage, promptService;
  172.   var ret = nsIFilePicker.returnCancel;
  173.  
  174.   var isDir = false;
  175.   var isFile = false;
  176.  
  177.   var input = textInput.value;
  178.   if (input[0] == '~') // XXX XP?
  179.     input  = homeDir.unicodePath + input.substring(1);
  180.  
  181.   var file = sfile.clone().QueryInterface(nsILocalFile);
  182.   if (!file)
  183.     return false;
  184.  
  185.   /* XXX we need an XP way to test for an absolute path! */
  186.   if (input[0] == '/')   /* an absolute path was entered */
  187.     file.initWithUnicodePath(input);
  188.   else if ((input.indexOf("/../") > 0) ||
  189.            (input.substr(-3) == "/..") ||
  190.            (input.substr(0,3) == "../") ||
  191.            (input == "..")) {
  192.     /* appendRelativePath doesn't allow .. */
  193.     file.initWithUnicodePath(file.unicodePath + "/" + input);
  194.     file.normalize();
  195.   }
  196.   else {
  197.     try {
  198.       file.appendRelativeUnicodePath(input);
  199.     } catch (e) {
  200.       dump("Can't append relative path '"+input+"':\n");
  201.       return false;
  202.     }
  203.   }
  204.  
  205.   if (!file.exists() && (filePickerMode != nsIFilePicker.modeSave)) {
  206.     errorTitle = gFilePickerBundle.getFormattedString("errorOpenFileDoesntExistTitle",
  207.                                                       [file.unicodePath]);
  208.     errorMessage = gFilePickerBundle.getFormattedString("errorOpenFileDoesntExistMessage",
  209.                                                         [file.unicodePath]);
  210.     promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  211.                               .getService(Components.interfaces.nsIPromptService);
  212.     promptService.alert(window, errorTitle, errorMessage);
  213.     return false;
  214.   }
  215.  
  216.   if (file.exists()) {
  217.     isDir = file.isDirectory();
  218.     isFile = file.isFile();
  219.   }
  220.  
  221.   switch(filePickerMode) {
  222.   case nsIFilePicker.modeOpen:
  223.     if (isFile) {
  224.       retvals.directory = file.parent.unicodePath;
  225.       ret = nsIFilePicker.returnOK;
  226.     } else if (isDir) {
  227.       if (!sfile.equals(file)) {
  228.         gotoDirectory(file);
  229.       }
  230.       textInput.value = "";
  231.       doEnabling();
  232.       ret = nsIFilePicker.returnCancel;
  233.     }
  234.     break;
  235.   case nsIFilePicker.modeSave:
  236.     if (isFile) { // can only be true if file.exists()
  237.       // we need to pop up a dialog asking if you want to save
  238.       var message = gFilePickerBundle.getFormattedString("confirmFileReplacing",
  239.                                                          [file.unicodePath]);
  240.       var rv = window.confirm(message);
  241.       if (rv) {
  242.         ret = nsIFilePicker.returnReplace;
  243.         retvals.directory = file.parent.unicodePath;
  244.       } else {
  245.         ret = nsIFilePicker.returnCancel;
  246.       }
  247.     } else if (isDir) {
  248.       if (!sfile.equals(file)) {
  249.         gotoDirectory(file);
  250.       }
  251.       textInput.value = "";
  252.       doEnabling();
  253.       ret = nsIFilePicker.returnCancel;
  254.     } else {
  255.       var parent = file.parent;
  256.       if (parent.exists() && parent.isDirectory()) {
  257.         ret = nsIFilePicker.returnOK;
  258.         retvals.directory = parent.unicodePath;
  259.       } else {
  260.         var oldParent = parent;
  261.         while (!parent.exists()) {
  262.           oldParent = parent;
  263.           parent = parent.parent;
  264.         }
  265.         errorTitle = gFilePickerBundle.getFormattedString("errorSavingFileTitle",
  266.                                                           [file.unicodePath]);
  267.         if (parent.isFile()) {
  268.           errorMessage = gFilePickerBundle.getFormattedString("saveParentIsFileMessage",
  269.                                                               [parent.unicodePath, file.unicodePath]);
  270.         } else {
  271.           errorMessage = gFilePickerBundle.getFormattedString("saveParentDoesntExistMessage",
  272.                                                               [oldParent.unicodePath, file.unicodePath]);
  273.         }
  274.         promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  275.                                   .getService(Components.interfaces.nsIPromptService);
  276.         promptService.alert(window, errorTitle, errorMessage);
  277.         ret = nsIFilePicker.returnCancel;
  278.       }
  279.     }
  280.     break;
  281.   case nsIFilePicker.modeGetFolder:
  282.     if (isDir) {
  283.       retvals.directory = file.parent.unicodePath;
  284.     } else { // if nothing selected, the current directory will be fine
  285.       retvals.directory = sfile.unicodePath;
  286.     }
  287.     ret = nsIFilePicker.returnOK;
  288.     break;
  289.   }
  290.  
  291.   retvals.file = file;
  292.   retvals.buttonStatus = ret;
  293.  
  294.   if (ret == nsIFilePicker.returnCancel)
  295.     return false;
  296.   else
  297.     return true;
  298. }
  299.  
  300. function onCancel()
  301. {
  302.   // Close the window.
  303.   retvals.buttonStatus = nsIFilePicker.returnCancel;
  304.   retvals.file = null;
  305.   return true;
  306. }
  307.  
  308. function onDblClick(e) {
  309.   var t = e.originalTarget;
  310.   if (t.localName != "outlinerbody")
  311.     return;
  312.  
  313.   openSelectedFile();
  314. }
  315.  
  316. function openSelectedFile() {
  317.   var file = outlinerView.getSelectedFile();
  318.   if (!file)
  319.     return;
  320.  
  321.   if (file.isSymlink())
  322.     file.initWithUnicodePath(file.unicodeTarget);
  323.  
  324.   if (file.isDirectory())
  325.     gotoDirectory(file);
  326.   else if (file.isFile())
  327.     doOKButton();
  328. }
  329.  
  330. function onClick(e) {
  331.   var t = e.originalTarget;
  332.   if (t.localName == "outlinercol")
  333.     handleColumnClick(t.id);
  334. }
  335.  
  336. function convertColumnIDtoSortType(columnID) {
  337.   var sortKey;
  338.   
  339.   switch (columnID) {
  340.   case "FilenameColumn":
  341.     sortKey = nsFileView.SORTTYPE_NAME;
  342.     break;
  343.   case "FileSizeColumn":
  344.     sortKey = nsFileView.SORTTYPE_SIZE;
  345.     break;
  346.   case "LastModifiedColumn":
  347.     sortKey = nsFileView.SORTTYPE_DATE;
  348.     break;
  349.   default:
  350.     dump("unsupported sort column: " + columnID + "\n");
  351.     sortKey = 0;
  352.     break;
  353.   }
  354.   
  355.   return sortKey;
  356. }
  357.  
  358. function handleColumnClick(columnID) {
  359.   var sortType = convertColumnIDtoSortType(columnID);
  360.   var sortOrder = (outlinerView.sortType == sortType) ? !outlinerView.reverseSort : false;
  361.   outlinerView.sort(sortType, sortOrder, false);
  362.   
  363.   // set the sort indicator on the column we are sorted by
  364.   var sortedColumn = document.getElementById(columnID);
  365.   if (outlinerView.reverseSort) {
  366.     sortedColumn.setAttribute("sortDirection", "descending");
  367.   } else {
  368.     sortedColumn.setAttribute("sortDirection", "ascending");
  369.   }
  370.   
  371.   // remove the sort indicator from the rest of the columns
  372.   var currCol = document.getElementById("directoryOutliner").firstChild;
  373.   while (currCol) {
  374.     while (currCol && currCol.localName != "outlinercol")
  375.       currCol = currCol.nextSibling;
  376.     if (currCol) {
  377.       if (currCol != sortedColumn) {
  378.         currCol.removeAttribute("sortDirection");
  379.       }
  380.       currCol = currCol.nextSibling;
  381.     }
  382.   }
  383. }
  384.  
  385. function doSort(sortType) {
  386.   outlinerView.sort(sortType, false);
  387. }
  388.  
  389. function onKeypress(e) {
  390.   if (e.keyCode == 8) /* backspace */
  391.     goUp();
  392.   else if (e.keyCode == 13) { /* enter */
  393.     var file = outlinerView.getSelectedFile();
  394.     if (file) {
  395.       if (file.isDirectory()) {
  396.         gotoDirectory(file);
  397.         e.preventDefault();
  398.       }
  399.     }
  400.   }
  401. }
  402.  
  403. function doEnabling() {
  404.   // Maybe add check if textInput.value would resolve to an existing
  405.   // file or directory in .modeOpen. Too costly I think.
  406.   var enable = (textInput.value != "");
  407.  
  408.   okButton.disabled = !enable;
  409. }
  410.  
  411. function onOutlinerFocus(event) {
  412.   // Reset the button label and enabled/disabled state.
  413.   onSelect(outlinerView.getSelectedFile());
  414. }
  415.  
  416. function getOKAction(file) {
  417.   var buttonLabel;
  418.  
  419.   if (file && file.isDirectory() && filePickerMode != nsIFilePicker.modeGetFolder) {
  420.     doSetOKCancel(openOnOK, onCancel);
  421.     buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  422.   }
  423.   else {
  424.     doSetOKCancel(selectOnOK, onCancel);
  425.     switch(filePickerMode) {
  426.     case nsIFilePicker.modeGetFolder:
  427.       buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
  428.       break;
  429.     case nsIFilePicker.modeOpen:
  430.       buttonLabel = gFilePickerBundle.getString("openButtonLabel");
  431.       break;
  432.     case nsIFilePicker.modeSave:
  433.       buttonLabel = gFilePickerBundle.getString("saveButtonLabel");
  434.       break;
  435.     }
  436.   }
  437.  
  438.   return buttonLabel;
  439. }
  440.  
  441. function onSelect(file) {
  442.   if (file) {
  443.     var path = file.unicodeLeafName;
  444.     
  445.     if (path) {
  446.       if ((filePickerMode == nsIFilePicker.modeGetFolder) || !file.isDirectory())
  447.         textInput.value = path;
  448.       
  449.       var buttonLabel = getOKAction(file);
  450.       okButton.setAttribute("label", buttonLabel);
  451.       okButton.disabled = false;
  452.       return;
  453.     }
  454.   }
  455.  
  456.   okButton.disabled = true;
  457. }
  458.  
  459. function onTextFieldFocus() {
  460.   var buttonLabel = getOKAction(null);
  461.   okButton.setAttribute("label", buttonLabel);
  462.   doEnabling();
  463. }
  464.  
  465. function onDirectoryChanged(target)
  466. {
  467.   var path = target.getAttribute("label");
  468.  
  469.   var file = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
  470.   file.initWithUnicodePath(path);
  471.  
  472.   if (!sfile.equals(file)) {
  473.     // Do this on a timeout callback so the directory list can roll up
  474.     // and we don't keep the mouse grabbed while we are loading.
  475.  
  476.     setTimeout(gotoDirectory, 0, file);
  477.   }
  478. }
  479.  
  480. function addToHistory(directoryName) {
  481.   var menu = document.getElementById("lookInMenu");
  482.   var children = menu.childNodes;
  483.  
  484.   var i = 0;
  485.   while (i < children.length) {
  486.     if (children[i].getAttribute("label") == directoryName)
  487.       break;
  488.  
  489.     ++i;
  490.   }
  491.  
  492.   if (i < children.length) {
  493.     if (i != 0) {
  494.       var node = children[i];
  495.       menu.removeChild(node);
  496.       menu.insertBefore(node, children[0]);
  497.     }
  498.   } else {
  499.     var menuItem = document.createElement("menuitem");
  500.     menuItem.setAttribute("label", directoryName);
  501.     menu.insertBefore(menuItem, children[0]);
  502.   }
  503.  
  504.   var menuList = document.getElementById("lookInMenuList");
  505.   menuList.selectedIndex = 0;
  506. }
  507.  
  508. function goUp() {
  509.   try {
  510.     var parent = sfile.parent;
  511.   } catch(ex) { dump("can't get parent directory\n"); }
  512.  
  513.   if (parent) {
  514.     gotoDirectory(parent);
  515.   }
  516. }
  517.  
  518. function gotoDirectory(directory) {
  519.   addToHistory(directory.unicodePath);
  520.  
  521.   window.setCursor("wait");
  522.   outlinerView.setDirectory(directory.unicodePath);
  523.   window.setCursor("auto");
  524.  
  525.   outlinerView.selection.clearSelection();
  526.   textInput.focus();
  527.   sfile = directory;
  528. }
  529.  
  530.