зеркало из https://github.com/mozilla/pjs.git
Landing OUTLINER_FILEPICKER_BRANCH (bug 75838). r=jag, sr=blake.
This commit is contained in:
Родитель
7979b6163f
Коммит
cf9f02ca53
|
@ -1,37 +1,50 @@
|
|||
@import url(chrome://global/skin/global.css);
|
||||
|
||||
treecell.directory {
|
||||
list-style-image: url("chrome://global/skin/dir-closed.gif");
|
||||
}
|
||||
|
||||
treecell.file {
|
||||
list-style-image: url("chrome://global/skin/blank.gif");
|
||||
}
|
||||
|
||||
/*
|
||||
treeitem.hidden > treerow > treecell > .tree-button {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
treeitem.hidden > treerow > treecell > .tree-icon {
|
||||
list-style-image: url("chrome://global/skin/blank.gif");
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* This fixes a bug. As you scroll down in a tree the computed column width
|
||||
* can change. That would make the columns shift durning scrolling.
|
||||
* So we give them inital preferred widths so they aren't computed.
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Joe Hewitt (hewitt@netscape.com)
|
||||
* Brian Ryner (bryner@netscape.com)
|
||||
*/
|
||||
#FilenameColumn {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#ContentLengthColumn {
|
||||
width: 100px;
|
||||
}
|
||||
/* ===== filepicker.css =================================================
|
||||
== Styles used by the File Picker dialog.
|
||||
======================================================================= */
|
||||
|
||||
@import url("chrome://global/skin/");
|
||||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
|
||||
/* ::::: column widths ::::: */
|
||||
|
||||
#FilenameColumn,
|
||||
#ContentLengthColumn,
|
||||
#LastModifiedDateColumn {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
/* ::::: file/directory items ::::: */
|
||||
|
||||
outlinerbody:-moz-outliner-image(FilenameColumn, directory) {
|
||||
list-style-image: url("chrome://global/skin/filepicker/dir-closed.gif");
|
||||
}
|
||||
|
||||
outlinerbody:-moz-outliner-image(FilenameColumn, file) {
|
||||
list-style-image: url("chrome://global/skin/filepicker/blank.gif");
|
||||
}
|
||||
|
||||
|
|
|
@ -14,11 +14,12 @@
|
|||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
* Copyright (C) 1998-2001 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Joe Hewitt (hewitt@netscape.com)
|
||||
* Brian Ryner (bryner@netscape.com)
|
||||
*/
|
||||
|
||||
/* ===== filepicker.css =================================================
|
||||
|
@ -39,11 +40,11 @@
|
|||
|
||||
/* ::::: file/directory items ::::: */
|
||||
|
||||
treecell.directory {
|
||||
outlinerbody:-moz-outliner-image(FilenameColumn, directory) {
|
||||
list-style-image: url("chrome://global/skin/filepicker/dir-closed.gif");
|
||||
}
|
||||
|
||||
treecell.file {
|
||||
outlinerbody:-moz-outliner-image(FilenameColumn, file) {
|
||||
list-style-image: url("chrome://global/skin/filepicker/blank.gif");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
|
@ -24,36 +24,34 @@
|
|||
* Peter Annema <disttsc@bart.nl>
|
||||
*/
|
||||
|
||||
const nsILocalFile = Components.interfaces.nsILocalFile;
|
||||
const nsILocalFile_CONTRACTID = "@mozilla.org/file/local;1";
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
const nsIDirectoryServiceProvider = Components.interfaces.nsIDirectoryServiceProvider;
|
||||
const nsIDirectoryServiceProvider_CONTRACTID = "@mozilla.org/file/directory_service;1";
|
||||
const nsStdURL_CONTRACTID = "@mozilla.org/network/standard-url;1";
|
||||
const nsIFileURL = Components.interfaces.nsIFileURL;
|
||||
const NC_NAMESPACE_URI = "http://home.netscape.com/NC-rdf#";
|
||||
const nsIOutlinerBoxObject = Components.interfaces.nsIOutlinerBoxObject;
|
||||
|
||||
var sfile = Components.classes[nsILocalFile_CONTRACTID].createInstance(nsILocalFile);
|
||||
var sfile = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
|
||||
var retvals;
|
||||
var filePickerMode;
|
||||
var currentFilter;
|
||||
var dirHistory;
|
||||
var homeDir;
|
||||
var outlinerView;
|
||||
|
||||
var directoryTree;
|
||||
var textInput;
|
||||
var okButton;
|
||||
|
||||
var gFilePickerBundle;
|
||||
|
||||
function onLoad() {
|
||||
function filepickerLoad() {
|
||||
gFilePickerBundle = document.getElementById("bundle_filepicker");
|
||||
|
||||
dirHistory = new Array();
|
||||
|
||||
directoryTree = document.getElementById("directoryTree");
|
||||
textInput = document.getElementById("textInput");
|
||||
okButton = document.getElementById("ok");
|
||||
outlinerView = new nsFileView();
|
||||
outlinerView.selectionCallback = onSelect;
|
||||
|
||||
if (window.arguments) {
|
||||
var o = window.arguments[0];
|
||||
|
@ -78,8 +76,9 @@ function onLoad() {
|
|||
if ((filePickerMode == nsIFilePicker.modeOpen) ||
|
||||
(filePickerMode == nsIFilePicker.modeSave)) {
|
||||
|
||||
currentFilter = filterTypes[0];
|
||||
applyFilter();
|
||||
window.setCursor("wait");
|
||||
outlinerView.setFilter(filterTypes[0]);
|
||||
window.setCursor("auto");
|
||||
|
||||
/* build filter popup */
|
||||
var filterPopup = document.createElement("menupopup");
|
||||
|
@ -98,10 +97,12 @@ function onLoad() {
|
|||
var filterBox = document.getElementById("filterBox");
|
||||
filterBox.removeAttribute("hidden");
|
||||
} else if (filePickerMode == nsIFilePicker.modeGetFolder) {
|
||||
// This applies a special filter to only show directories
|
||||
applyDirectoryFilter();
|
||||
outlinerView.showOnlyDirectories = true;
|
||||
}
|
||||
|
||||
// start out with a filename sort
|
||||
handleColumnClick("FilenameColumn");
|
||||
|
||||
try {
|
||||
var buttonLabel;
|
||||
switch (filePickerMode) {
|
||||
|
@ -143,6 +144,9 @@ function onLoad() {
|
|||
retvals.buttonStatus = nsIFilePicker.returnCancel;
|
||||
|
||||
gotoDirectory(sfile);
|
||||
var outliner = document.getElementById("directoryOutliner");
|
||||
outliner.outlinerBoxObject.view = outlinerView;
|
||||
|
||||
doEnabling();
|
||||
textInput.focus();
|
||||
}
|
||||
|
@ -150,61 +154,9 @@ function onLoad() {
|
|||
function onFilterChanged(target)
|
||||
{
|
||||
var filterTypes = target.getAttribute("filters");
|
||||
currentFilter = filterTypes;
|
||||
applyFilter();
|
||||
}
|
||||
|
||||
function applyFilter()
|
||||
{
|
||||
/* This is where we manipulate the DOM to create new <rule>s */
|
||||
var splitFilters = currentFilter.split("; ");
|
||||
var matchAllFiles = false;
|
||||
var ruleNode;
|
||||
|
||||
/* get just the extensions for each of the filters */
|
||||
var extensions = new Array(splitFilters.length);
|
||||
for (var j = 0; j < splitFilters.length; j++) {
|
||||
var tmpStr = splitFilters[j];
|
||||
if (tmpStr == "*") {
|
||||
matchAllFiles = true;
|
||||
break;
|
||||
} else
|
||||
extensions[j] = tmpStr.substring(1); /* chop off the '*' */
|
||||
}
|
||||
|
||||
/* delete all rules except the first one */
|
||||
for (j = 1;; j++) {
|
||||
ruleNode = document.getElementById("matchRule."+j);
|
||||
if (ruleNode) {
|
||||
ruleNode.parentNode.removeChild(ruleNode);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we are matching all files, just clear the extension attribute
|
||||
on the first match rule and we're done */
|
||||
var rule0 = document.getElementById("matchRule.0");
|
||||
if (matchAllFiles) {
|
||||
rule0.removeAttributeNS(NC_NAMESPACE_URI, "extension");
|
||||
directoryTree.builder.rebuild();
|
||||
return;
|
||||
}
|
||||
|
||||
/* rule 0 is special */
|
||||
rule0.setAttributeNS(NC_NAMESPACE_URI, "extension" , extensions[0]);
|
||||
|
||||
/* iterate through the remaining extensions, creating new rules */
|
||||
ruleNode = document.getElementById("fileFilter");
|
||||
|
||||
for (var k=1; k < extensions.length; k++) {
|
||||
var newRule = rule0.cloneNode(true);
|
||||
newRule.setAttribute("id", "matchRule."+k);
|
||||
newRule.setAttributeNS(NC_NAMESPACE_URI, "extension", extensions[k]);
|
||||
ruleNode.appendChild(newRule);
|
||||
}
|
||||
|
||||
directoryTree.builder.rebuild();
|
||||
window.setCursor("wait");
|
||||
outlinerView.setFilter(filterTypes);
|
||||
window.setCursor("auto");
|
||||
}
|
||||
|
||||
function onOK()
|
||||
|
@ -338,24 +290,88 @@ function onCancel()
|
|||
return true;
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
if ( e.detail == 2 ) {
|
||||
var path = e.target.parentNode.getAttribute("path");
|
||||
function onDblClick(e) {
|
||||
var t = e.originalTarget;
|
||||
if (t.localName != "outlinerbody")
|
||||
return;
|
||||
|
||||
if (path) {
|
||||
var file = URLpathToFile(path);
|
||||
if (file) {
|
||||
if (file.isDirectory()) {
|
||||
gotoDirectory(file);
|
||||
}
|
||||
else if (file.isFile()) {
|
||||
doOKButton();
|
||||
}
|
||||
var file = outlinerView.getSelectedFile();
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
if (file.isSymlink()) {
|
||||
var targetFile = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
|
||||
targetFile.initWithUnicodePath(file.unicodeTarget);
|
||||
file = targetFile;
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
gotoDirectory(file);
|
||||
}
|
||||
else if (file.isFile()) {
|
||||
doOKButton();
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
var t = e.originalTarget;
|
||||
if (t.localName == "outlinercol")
|
||||
handleColumnClick(t.id);
|
||||
}
|
||||
|
||||
function convertColumnIDtoSortType(columnID) {
|
||||
var sortKey;
|
||||
|
||||
switch (columnID) {
|
||||
case "FilenameColumn":
|
||||
sortKey = nsFileView.SORTTYPE_NAME;
|
||||
break;
|
||||
case "FileSizeColumn":
|
||||
sortKey = nsFileView.SORTTYPE_SIZE;
|
||||
break;
|
||||
case "LastModifiedColumn":
|
||||
sortKey = nsFileView.SORTTYPE_DATE;
|
||||
break;
|
||||
default:
|
||||
dump("unsupported sort column: " + columnID + "\n");
|
||||
sortKey = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return sortKey;
|
||||
}
|
||||
|
||||
function handleColumnClick(columnID) {
|
||||
var sortType = convertColumnIDtoSortType(columnID);
|
||||
var sortOrder = (outlinerView.sortType == sortType) ? !outlinerView.reverseSort : false;
|
||||
outlinerView.sort(sortType, sortOrder, false);
|
||||
|
||||
// set the sort indicator on the column we are sorted by
|
||||
var sortedColumn = document.getElementById(columnID);
|
||||
if (outlinerView.reverseSort) {
|
||||
sortedColumn.setAttribute("sortDirection", "descending");
|
||||
} else {
|
||||
sortedColumn.setAttribute("sortDirection", "ascending");
|
||||
}
|
||||
|
||||
// remove the sort indicator from the rest of the columns
|
||||
var currCol = document.getElementById("directoryOutliner").firstChild;
|
||||
while (currCol) {
|
||||
while (currCol && currCol.localName != "outlinercol")
|
||||
currCol = currCol.nextSibling;
|
||||
if (currCol) {
|
||||
if (currCol != sortedColumn) {
|
||||
currCol.removeAttribute("sortDirection");
|
||||
}
|
||||
currCol = currCol.nextSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function doSort(sortType) {
|
||||
outlinerView.sort(sortType, false);
|
||||
}
|
||||
|
||||
function onKeypress(e) {
|
||||
if (e.keyCode == 8) /* backspace */
|
||||
goUp();
|
||||
|
@ -369,21 +385,13 @@ function doEnabling() {
|
|||
okButton.disabled = !enable;
|
||||
}
|
||||
|
||||
function onSelect(e) {
|
||||
if (e.target.selectedItems.length != 1)
|
||||
return;
|
||||
var path = e.target.selectedItems[0].firstChild.getAttribute("path");
|
||||
function onSelect(file) {
|
||||
var path = file.unicodeLeafName;
|
||||
|
||||
if (path) {
|
||||
var file = URLpathToFile(path);
|
||||
if (file) {
|
||||
/* Put the leafName of the selected item in the input field if:
|
||||
- GetFolder mode : a directory was selected (only option)
|
||||
- Open or Save mode: a file was selected */
|
||||
if ((filePickerMode == nsIFilePicker.modeGetFolder) || file.isFile()) {
|
||||
textInput.value = file.unicodeLeafName;
|
||||
doEnabling();
|
||||
}
|
||||
if ((filePickerMode == nsIFilePicker.modeGetFolder) || file.isFile()) {
|
||||
textInput.value = path;
|
||||
doEnabling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +400,7 @@ function onDirectoryChanged(target)
|
|||
{
|
||||
var path = target.getAttribute("label");
|
||||
|
||||
var file = Components.classes[nsILocalFile_CONTRACTID].createInstance(nsILocalFile);
|
||||
var file = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
|
||||
file.initWithUnicodePath(path);
|
||||
|
||||
if (!sfile.equals(file)) {
|
||||
|
@ -447,30 +455,9 @@ function goUp() {
|
|||
|
||||
function gotoDirectory(directory) {
|
||||
addToHistory(directory.unicodePath);
|
||||
directoryTree.setAttribute("ref", fileToURL(directory).spec);
|
||||
window.setCursor("wait");
|
||||
outlinerView.setDirectory(directory.unicodePath);
|
||||
window.setCursor("auto");
|
||||
sfile = directory;
|
||||
}
|
||||
|
||||
function fileToURL(aFile) {
|
||||
var newDirectoryURL = Components.classes[nsStdURL_CONTRACTID].createInstance().QueryInterface(nsIFileURL);
|
||||
newDirectoryURL.file = aFile;
|
||||
return newDirectoryURL;
|
||||
}
|
||||
|
||||
function URLpathToFile(aURLstr) {
|
||||
var fileURL = Components.classes[nsStdURL_CONTRACTID].createInstance().QueryInterface(nsIFileURL);
|
||||
fileURL.spec = aURLstr;
|
||||
return fileURL.file;
|
||||
}
|
||||
|
||||
function applyDirectoryFilter() {
|
||||
var ruleNode = document.getElementById("matchRule.0");
|
||||
|
||||
// A file can never have an extension of ".", because the extension is
|
||||
// by definition everything after the last dot. So, this rule will
|
||||
// cause only directories to show up.
|
||||
ruleNode.setAttributeNS(NC_NAMESPACE_URI, "extension", ".");
|
||||
|
||||
directoryTree.builder.rebuild();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
<?xml-stylesheet href="chrome://global/skin/filepicker.css" type="text/css"?>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
|
||||
<?xml-stylesheet href="chrome://global/content/filepicker.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://global/locale/filepicker.dtd" >
|
||||
|
||||
|
@ -37,12 +36,13 @@
|
|||
xmlns:nc="http://home.netscape.com/NC-rdf#"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
orient="vertical"
|
||||
onload="onLoad();"
|
||||
onload="filepickerLoad();"
|
||||
width="426" height="300"
|
||||
class="dialog"
|
||||
persist="screenX screenY">
|
||||
|
||||
<stringbundle id="bundle_filepicker" src="chrome://global/locale/filepicker.properties"/>
|
||||
<script type="application/x-javascript" src="chrome://global/content/nsFileView.js"/>
|
||||
<script type="application/x-javascript" src="chrome://global/content/filepicker.js"/>
|
||||
<keyset id="dialogKeys"/>
|
||||
|
||||
|
@ -51,48 +51,23 @@
|
|||
<menulist id="lookInMenuList" flex="1" oncommand="onDirectoryChanged(event.target);" crop="left">
|
||||
<menupopup id="lookInMenu"/>
|
||||
</menulist>
|
||||
<button label=".." onclick="goUp();"/>
|
||||
<button label=".." oncommand="goUp();"/>
|
||||
</box>
|
||||
|
||||
<box flex="1">
|
||||
<tree id="directoryTree" flex="1" onkeypress="onKeypress(event)"
|
||||
onselect="onSelect(event)" datasources="rdf:files">
|
||||
<template id="fileFilter">
|
||||
<!-- This is the rule for files matching the filter -->
|
||||
<rule id="matchRule.0">
|
||||
<treechildren flex="1">
|
||||
<treeitem uri="..." empty="true"
|
||||
type="rdf:http://home.netscape.com/NC-rdf#File-Type"
|
||||
loading="rdf:http://home.netscape.com/NC-rdf#loading" >
|
||||
<treerow path="rdf:http://home.netscape.com/NC-rdf#URL">
|
||||
<treecell class="treecell-filename treecell-indent"
|
||||
indent="true" type="rdf:http://home.netscape.com/NC-rdf#File-Type"
|
||||
label="rdf:http://home.netscape.com/NC-rdf#Name"/>
|
||||
<treecell label="rdf:http://home.netscape.com/NC-rdf#Content-Length" />
|
||||
<treecell label="rdf:http://home.netscape.com/WEB-rdf#LastModifiedDate" />
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</rule>
|
||||
<outliner id="directoryOutliner" flex="1" onclick="onClick(event);"
|
||||
ondblclick="onDblClick(event);">
|
||||
<outlinercol id="FilenameColumn" label="&name.label;" flex="1"
|
||||
class="outlinercol-header outlinercell-inset-header sortDirectionIndicator"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<outlinercol id="FileSizeColumn" label="&size.label;" flex="1"
|
||||
class="outlinercol-header outlinercell-inset-header sortDirectionIndicator"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<outlinercol id="LastModifiedColumn" label="&lastModified.label;" flex="1"
|
||||
class="outlinercol-header outlinercell-inset-header sortDirectionIndicator"/>
|
||||
|
||||
</template>
|
||||
|
||||
<treecolgroup>
|
||||
<treecol flex="1" id="FilenameColumn" resource="http://home.netscape.com/NC-rdf#Name" sortActive="true" sortDirection="ascending"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol flex="1" id="ContentLengthColumn" resource="http://home.netscape.com/NC-rdf#Content-Length"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol flex="1" id="LastModifiedDateColumn" resource="http//home.netscape.com/WEB-rdf#LastModifiedDate"/>
|
||||
</treecolgroup>
|
||||
<treehead>
|
||||
<treerow>
|
||||
<treecell class="treecell-header" label="&name.label;"/>
|
||||
<treecell class="treecell-header" label="&size.label;"/>
|
||||
<treecell class="treecell-header" label="&lastModified.label;"/>
|
||||
</treerow>
|
||||
</treehead>
|
||||
<treechildren flex="1" onclick="onClick(event)"/>
|
||||
</tree>
|
||||
<outlinerbody flex="1" onselect="this.parentNode.outlinerBoxObject.view.selectionChanged()"/>
|
||||
</outliner>
|
||||
</box>
|
||||
|
||||
<grid style="margin-top: 5px">
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@netscape.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/* This file implements an nsIOutlinerView for the filepicker */
|
||||
|
||||
const nsILocalFile = Components.interfaces.nsILocalFile;
|
||||
const nsLocalFile_CONTRACTID = "@mozilla.org/file/local;1";
|
||||
const nsIFile = Components.interfaces.nsIFile;
|
||||
const nsIScriptableDateFormat = Components.interfaces.nsIScriptableDateFormat;
|
||||
const nsScriptableDateFormat_CONTRACTID = "@mozilla.org/intl/scriptabledateformat;1";
|
||||
const nsIAtomService = Components.interfaces.nsIAtomService;
|
||||
const nsAtomService_CONTRACTID = "@mozilla.org/atom-service;1";
|
||||
|
||||
var gDateService = null;
|
||||
|
||||
function numMatchingChars(str1, str2) {
|
||||
var minLength = Math.min(str1.length, str2.length);
|
||||
for (var i = 0; ((i < minLength) && (str1[i] == str2[i])); i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
function sortFilename(a, b) {
|
||||
if (a.cachedName < b.cachedName) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function sortSize(a, b) {
|
||||
if (a.cachedSize < b.cachedSize) {
|
||||
return -1;
|
||||
} else if (a.cachedSize > b.cachedSize) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function sortDate(a, b) {
|
||||
if (a.cachedDate < b.cachedDate) {
|
||||
return -1;
|
||||
} else if (a.cachedDate > b.cachedDate) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function nsFileView() {
|
||||
this.mShowHiddenFiles = false;
|
||||
this.mDirectoryFilter = false;
|
||||
this.mFileList = [];
|
||||
this.mDirList = [];
|
||||
this.mFilteredFiles = [];
|
||||
this.mCurrentFilter = ".*";
|
||||
this.mSelectionCallback = null;
|
||||
this.mOutliner = null;
|
||||
this.mReverseSort = false;
|
||||
this.mSortType = 0;
|
||||
this.mTotalRows = 0;
|
||||
|
||||
if (!gDateService) {
|
||||
gDateService = Components.classes[nsScriptableDateFormat_CONTRACTID]
|
||||
.getService(nsIScriptableDateFormat);
|
||||
}
|
||||
|
||||
var atomService = Components.classes[nsAtomService_CONTRACTID]
|
||||
.getService(nsIAtomService);
|
||||
this.mDirectoryAtom = atomService.getAtom("directory");
|
||||
this.mFileAtom = atomService.getAtom("file");
|
||||
}
|
||||
|
||||
nsFileView.prototype = {
|
||||
|
||||
SORTTYPE_NAME: 1,
|
||||
SORTTYPE_SIZE: 2,
|
||||
SORTTYPE_DATE: 3,
|
||||
|
||||
/* readonly attribute long rowCount; */
|
||||
set rowCount(c) { throw "readonly property"; },
|
||||
get rowCount() { return this.mTotalRows; },
|
||||
|
||||
/* attribute nsIOutlinerSelection selection; */
|
||||
set selection(s) { this.mSelection = s; },
|
||||
get selection() { return this.mSelection; },
|
||||
|
||||
set selectionCallback(f) { this.mSelectionCallback = f; },
|
||||
get selectionCallback() { return this.mSelectionCallback; },
|
||||
|
||||
/* nsISupports methods */
|
||||
|
||||
/* void QueryInterface(in nsIIDRef uuid,
|
||||
[iid_is(uuid),retval] out nsQIResult result); */
|
||||
QueryInterface: function(iid) {
|
||||
if (!iid.equals(nsIOutlinerView) &&
|
||||
!iid.equals(nsISupports)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/* nsIOutlinerView methods */
|
||||
|
||||
/* void getRowProperties(in long index, in nsISupportsArray properties); */
|
||||
getRowProperties: function(index, properties) { },
|
||||
|
||||
/* void getCellProperties(in long row, in wstring colID, in nsISupportsArray properties); */
|
||||
getCellProperties: function(row, colID, properties) {
|
||||
if (row < this.mDirList.length)
|
||||
properties.AppendElement(this.mDirectoryAtom);
|
||||
else if ((row - this.mDirList.length) < this.mFilteredFiles.length)
|
||||
properties.AppendElement(this.mFileAtom);
|
||||
},
|
||||
|
||||
/* void getColumnProperties(in wstring colID, in nsIDOMElement colElt,
|
||||
in nsISupportsArray properties); */
|
||||
getColumnProperties: function(colID, colElt, properties) { },
|
||||
|
||||
/* boolean isContainer(in long index); */
|
||||
isContainer: function(index) { return false; },
|
||||
|
||||
/* boolean isContainerOpen(in long index); */
|
||||
isContainerOpen: function(index) { return false;},
|
||||
|
||||
/* boolean isContainerEmpty(in long index); */
|
||||
isContainerEmpty: function(index) { return false; },
|
||||
|
||||
/* boolean isSorted (); */
|
||||
isSorted: function() { return (this.mSortType > 0); },
|
||||
|
||||
/* boolean canDropOn (in long index); */
|
||||
canDropOn: function(index) { return false; },
|
||||
|
||||
/* boolean canDropBeforeAfter (in long index, in boolean before); */
|
||||
canDropBeforeAfter: function(index, before) { return false; },
|
||||
|
||||
/* void drop (in long row, in long orientation); */
|
||||
drop: function(row, orientation) { },
|
||||
|
||||
/* long getParentIndex(in long rowIndex); */
|
||||
getParentIndex: function(rowIndex) { return -1; },
|
||||
|
||||
/* boolean hasNextSibling(in long rowIndex, in long afterIndex); */
|
||||
hasNextSibling: function(rowIndex, afterIndex) {
|
||||
return (afterIndex < (this.mTotalRows - 1));
|
||||
},
|
||||
|
||||
/* long getLevel(in long index); */
|
||||
getLevel: function(index) { return 0; },
|
||||
|
||||
/* wstring getCellText(in long row, in wstring colID); */
|
||||
getCellText: function(row, colID) {
|
||||
/* we cache the file size and last modified dates -
|
||||
this function must be very fast since it's called
|
||||
whenever the cell needs repainted */
|
||||
var file, isdir = false;
|
||||
if (row < this.mDirList.length) {
|
||||
isdir = true;
|
||||
file = this.mDirList[row];
|
||||
} else if ((row - this.mDirList.length) < this.mFilteredFiles.length) {
|
||||
file = this.mFilteredFiles[row - this.mDirList.length];
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (colID == "FilenameColumn") {
|
||||
if (!("cachedName" in file)) {
|
||||
file.cachedName = file.file.unicodeLeafName;
|
||||
}
|
||||
return file.cachedName;
|
||||
} else if (colID == "LastModifiedColumn") {
|
||||
if (!("cachedDate" in file)) {
|
||||
// perhaps overkill, but lets get the right locale handling
|
||||
var modDate = new Date(file.file.lastModificationDate);
|
||||
file.cachedDate = gDateService.FormatDateTime("", gDateService.dateFormatShort,
|
||||
gDateService.timeFormatSeconds,
|
||||
modDate.getFullYear(), modDate.getMonth()+1,
|
||||
modDate.getDate(), modDate.getHours(),
|
||||
modDate.getMinutes(), modDate.getSeconds());
|
||||
}
|
||||
return file.cachedDate;
|
||||
} else if (colID == "FileSizeColumn") {
|
||||
if (isdir) {
|
||||
return "";
|
||||
} else {
|
||||
if (!("cachedSize" in file)) {
|
||||
file.cachedSize = String(file.file.fileSize);
|
||||
}
|
||||
}
|
||||
return file.cachedSize;
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
/* void setOutliner(in nsIOutlinerBoxObject outliner); */
|
||||
setOutliner: function(outliner) { this.mOutliner = outliner; },
|
||||
|
||||
/* void toggleOpenState(in long index); */
|
||||
toggleOpenState: function(index) { },
|
||||
|
||||
/* void cycleHeader(in wstring colID, in nsIDOMElement elt); */
|
||||
cycleHeader: function(colID, elt) { },
|
||||
|
||||
/* void selectionChanged(); */
|
||||
selectionChanged: function() {
|
||||
if (this.mSelectionCallback && this.mSelection.currentIndex > 0) {
|
||||
var file;
|
||||
if (this.mSelection.currentIndex < this.mDirList.length) {
|
||||
file = this.mDirList[this.mSelection.currentIndex].file;
|
||||
} else if ((this.mSelection.currentIndex - this.mDirList.length) < this.mFilteredFiles.length) {
|
||||
file = this.mFilteredFiles[this.mSelection.currentIndex - this.mDirList.length].file;
|
||||
}
|
||||
|
||||
if (file) {
|
||||
this.mSelectionCallback(file);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* void cycleCell(in long row, in wstring colID); */
|
||||
cycleCell: function(row, colID) { },
|
||||
|
||||
/* boolean isEditable(in long row, in wstring colID); */
|
||||
isEditable: function(row, colID) { return false; },
|
||||
|
||||
/* void setCellText(in long row, in wstring colID, in wstring value); */
|
||||
setCellText: function(row, colID, value) { },
|
||||
|
||||
/* void performAction(in wstring action); */
|
||||
performAction: function(action) { },
|
||||
|
||||
/* void performActionOnRow(in wstring action, in long row); */
|
||||
performActionOnRow: function(action, row) { },
|
||||
|
||||
/* void performActionOnCell(in wstring action, in long row, in wstring colID); */
|
||||
performActionOnCell: function(action, row, colID) { },
|
||||
|
||||
/* private attributes */
|
||||
|
||||
/* attribute boolean showHiddenFiles */
|
||||
set showHiddenFiles(s) {
|
||||
this.mShowHiddenFiles = s;
|
||||
this.setDirectory(this.mDirectoryPath);
|
||||
},
|
||||
|
||||
get showHiddenFiles() { return this.mShowHiddenFiles; },
|
||||
|
||||
/* attribute boolean showOnlyDirectories */
|
||||
set showOnlyDirectories(s) {
|
||||
this.mDirectoryFilter = s;
|
||||
this.filterFiles();
|
||||
},
|
||||
|
||||
get showOnlyDirectories() { return this.mDirectoryFilter; },
|
||||
|
||||
/* readonly attribute short sortType */
|
||||
set sortType(s) { throw "readonly property"; },
|
||||
get sortType() { return this.mSortType; },
|
||||
|
||||
/* readonly attribute boolean reverseSort */
|
||||
set reverseSort(s) { throw "readonly property"; },
|
||||
get reverseSort() { return this.mReverseSort; },
|
||||
|
||||
/* private methods */
|
||||
sort: function(sortType, reverseSort, forceSort) {
|
||||
if (sortType == this.mSortType && reverseSort != this.mReverseSort && !forceSort) {
|
||||
this.mDirList.reverse();
|
||||
this.mFilteredFiles.reverse();
|
||||
} else {
|
||||
var compareFunc, i;
|
||||
|
||||
/* We pre-fetch all the data we are going to sort on, to avoid
|
||||
calling into C++ on every comparison */
|
||||
|
||||
switch (sortType) {
|
||||
case 0:
|
||||
/* no sort has been set yet */
|
||||
return;
|
||||
case nsFileView.SORTTYPE_NAME:
|
||||
for (i = 0; i < this.mDirList.length; i++) {
|
||||
this.mDirList[i].cachedName = this.mDirList[i].file.unicodeLeafName;
|
||||
}
|
||||
for (i = 0; i < this.mFilteredFiles.length; i++) {
|
||||
this.mFilteredFiles[i].cachedName = this.mFilteredFiles[i].file.unicodeLeafName;
|
||||
}
|
||||
compareFunc = sortFilename;
|
||||
break;
|
||||
case nsFileView.SORTTYPE_SIZE:
|
||||
for (i = 0; i < this.mDirList.length; i++) {
|
||||
this.mDirList[i].cachedSize = this.mDirList[i].file.fileSize;
|
||||
}
|
||||
for (i = 0; i < this.mFilteredFiles.length; i++) {
|
||||
this.mFilteredFiles[i].cachedSize = this.mFilteredFiles[i].file.fileSize;
|
||||
}
|
||||
compareFunc = sortSize;
|
||||
break;
|
||||
case nsFileView.SORTTYPE_DATE:
|
||||
for (i = 0; i < this.mDirList.length; i++) {
|
||||
this.mDirList[i].cachedDate = this.mDirList[i].file.lastModificationDate;
|
||||
}
|
||||
for (i = 0; i < this.mFilteredFiles.length; i++) {
|
||||
this.mFilteredFiles[i].cachedDate = this.mFilteredFiles[i].file.lastModificationDate;
|
||||
}
|
||||
compareFunc = sortDate;
|
||||
break;
|
||||
default:
|
||||
throw("Unsupported sort type " + sortType);
|
||||
break;
|
||||
}
|
||||
this.mDirList.sort(compareFunc);
|
||||
this.mFilteredFiles.sort(compareFunc);
|
||||
}
|
||||
|
||||
this.mSortType = sortType;
|
||||
this.mReverseSort = reverseSort;
|
||||
if (this.mOutliner) {
|
||||
this.mOutliner.invalidate();
|
||||
}
|
||||
},
|
||||
|
||||
setDirectory: function(directory) {
|
||||
this.mDirectoryPath = directory;
|
||||
this.mFileList = [];
|
||||
this.mDirList = [];
|
||||
|
||||
var dir = Components.classes[nsLocalFile_CONTRACTID].createInstance(nsILocalFile);
|
||||
dir.followLinks = false;
|
||||
dir.initWithUnicodePath(directory);
|
||||
var dirEntries = dir.QueryInterface(nsIFile).directoryEntries;
|
||||
var nextFile;
|
||||
var fileobj;
|
||||
//var time = new Date();
|
||||
|
||||
while (dirEntries.hasMoreElements()) {
|
||||
nextFile = dirEntries.getNext().QueryInterface(nsIFile);
|
||||
if (nextFile.isDirectory()) {
|
||||
if (!nextFile.isHidden() || this.mShowHiddenFiles) {
|
||||
fileobj = new Object();
|
||||
fileobj.file = nextFile;
|
||||
this.mDirList[this.mDirList.length] = fileobj;
|
||||
}
|
||||
} else if (!this.mDirectoryFilter) {
|
||||
this.mFileList[this.mFileList.length] = nextFile;
|
||||
}
|
||||
}
|
||||
|
||||
//time = new Date() - time;
|
||||
//dump("load time: " + time/1000 + " seconds\n");
|
||||
|
||||
this.mFilteredFiles = [];
|
||||
|
||||
if (this.mOutliner) {
|
||||
var oldRows = this.mTotalRows;
|
||||
this.mTotalRows = this.mDirList.length;
|
||||
if (this.mDirList.length != oldRows) {
|
||||
this.mOutliner.rowCountChanged(0, this.mDirList.length - oldRows);
|
||||
}
|
||||
this.mOutliner.invalidate();
|
||||
}
|
||||
|
||||
//time = new Date();
|
||||
|
||||
this.filterFiles();
|
||||
|
||||
//time = new Date() - time;
|
||||
//dump("filter time: " + time/1000 + " seconds\n");
|
||||
//time = new Date();
|
||||
|
||||
this.sort(this.mSortType, this.mReverseSort);
|
||||
|
||||
//time = new Date() - time;
|
||||
//dump("sort time: " + time/1000 + " seconds\n");
|
||||
},
|
||||
|
||||
setFilter: function(filter) {
|
||||
// The filter may contain several components, i.e.:
|
||||
// *.html; *.htm
|
||||
// First separate it into its components
|
||||
var filterList = filter.split(/;[ ]*/);
|
||||
|
||||
if (filterList.length == 0) {
|
||||
// this shouldn't happen
|
||||
return;
|
||||
}
|
||||
|
||||
// Transform everything in the array to a regexp
|
||||
var tmp = filterList[0].replace(/\./g, "\\.");
|
||||
filterList[0] = tmp.replace(/\*/g, ".*");
|
||||
var shortestPrefix = filterList[0];
|
||||
|
||||
for (var i = 1; i < filterList.length; i++) {
|
||||
// * becomes .*, and we escape all .'s with \
|
||||
tmp = filterList[i].replace(/\./g, "\\.");
|
||||
filterList[i] = tmp.replace(/\*/g, ".*");
|
||||
shortestPrefix = shortestPrefix.substr(0, numMatchingChars(shortestPrefix, filterList[i]));
|
||||
}
|
||||
|
||||
var filterStr = shortestPrefix+"(";
|
||||
var startpos = shortestPrefix.length;
|
||||
for (i = 0; i < filterList.length; i++) {
|
||||
filterStr += filterList[i].substr(shortestPrefix.length) + "|";
|
||||
}
|
||||
|
||||
this.mCurrentFilter = new RegExp(filterStr.substr(0, (filterStr.length) - 1) + ")");
|
||||
this.mFilteredFiles = [];
|
||||
|
||||
if (this.mOutliner) {
|
||||
var rowDiff = -(this.mTotalRows - this.mDirList.length);
|
||||
this.mTotalRows = this.mDirList.length;
|
||||
this.mOutliner.rowCountChanged(this.mDirList.length, rowDiff);
|
||||
this.mOutliner.invalidate();
|
||||
}
|
||||
this.filterFiles();
|
||||
this.sort(this.mSortType, this.mReverseSort, true);
|
||||
},
|
||||
|
||||
filterFiles: function() {
|
||||
for(var i = 0; i < this.mFileList.length; i++) {
|
||||
var file = this.mFileList[i];
|
||||
|
||||
if ((this.mShowHiddenFiles || !file.isHidden()) &&
|
||||
file.unicodeLeafName.search(this.mCurrentFilter) == 0) {
|
||||
this.mFilteredFiles[this.mFilteredFiles.length] = { file : file };
|
||||
}
|
||||
}
|
||||
|
||||
this.mTotalRows = this.mDirList.length + this.mFilteredFiles.length;
|
||||
|
||||
// Tell the outliner how many rows we just added
|
||||
if (this.mOutliner) {
|
||||
this.mOutliner.rowCountChanged(this.mDirList.length, this.mFilteredFiles.length);
|
||||
}
|
||||
},
|
||||
|
||||
getSelectedFile: function() {
|
||||
if (0 <= this.mSelection.currentIndex) {
|
||||
if (this.mSelection.currentIndex < this.mDirList.length) {
|
||||
return this.mDirList[this.mSelection.currentIndex].file;
|
||||
} else if ((this.mSelection.currentIndex - this.mDirList.length) < this.mFilteredFiles.length) {
|
||||
return this.mFilteredFiles[this.mSelection.currentIndex - this.mDirList.length].file;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -168,4 +168,4 @@ toolkit.jar:
|
|||
content/global/autocomplete.css (autocomplete/resources/content/autocomplete.css)
|
||||
content/global/filepicker.js (filepicker/res/content/filepicker.js)
|
||||
content/global/filepicker.xul (filepicker/res/content/filepicker.xul)
|
||||
content/global/filepicker.css (filepicker/res/content/filepicker.css)
|
||||
content/global/nsFileView.js (filepicker/res/content/nsFileView.js)
|
||||
|
|
Загрузка…
Ссылка в новой задаче