- lots of work on the prefs. work now, with a few ceveats. the pref dialog is a pain when used without prefs.
- bugfixes for transfer
This commit is contained in:
mozilla.BenB%bucksch.org 2003-03-09 19:05:41 +00:00
Родитель 4b52868b34
Коммит c18ddceabf
1 изменённых файлов: 452 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,452 @@
/*
* 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 Session Roaming code.
*
* The Initial Developer of the Original Code is
* Ben Bucksch <http://www.bucksch.org> of
* Beonex <http://www.beonex.com>
* Portions created by Ben Bucksch are Copyright (C) 2002 Ben Bucksch.
* All Rights Reserved.
*
* Contributor(s):
*/
/* The backend needs the settings in the Mozilla app registry
(via nsIRegistry), not in the prefs system (nsIPref;
it is not yet running when needed). This file implements
the saving of the settings (from the dialog) to the registry and reading
it back.
Oh Shit. When the user switches panes, the dialog loses all state. Nothing
restores it. But we can't save it to the registry either, the user might
cancel later. So, we have to store all values in our own, internal data
structure and later save it to the registry, if the user clicked OK.
To unify matters, I share a data structure between top.xul and files.js.
*/
var gData; // for structure, see RegistryToData()
/* While each prefs pane (top and files) has its own |gData| var,
they all point to the same object, gotten from data manager.
I.e. top.js and files.js practically share the same
object. This is important so that files selection can be
disabled, if roaming is disabled, and be enabled as soon
as the user enabled roaming (but didn't save yet). */
// for pane switches
function Unload()
{
UIToData();
parent.roaming.verifyData();
}
/* *sigh*!!! when the user clicks OK in another pane,
all the other functions and even the consts are gone,
so creating an object. */
function RoamingPrefs()
{
// init
this.loaded = false; // already read from registry
this.changed = false; // any of the values changed, so save all
// user data
this.Enabled = false;
this.Method = 0; // int, reall enum: 0=stream, 1=copy
this.Files = new Array(); // of strings, will get another default below
this.Stream = new Object();
this.Stream.BaseURL = "";
this.Stream.Username = "";
this.Stream.SavePW = false;
this.Stream.Password = "";
this.Copy = new Object();
this.Copy.RemoteDir = "";
// caching(have to add that here or it will disappear during pane switches)
this.regkeyProf = undefined;
this.registry = undefined;
this.registryToData();
var me = this;
parent.hPrefWindow.registerOKCallbackFunc(function() { me.okClicked(); });
}
RoamingPrefs.prototype =
{
//from mozSRoaming*.cpp
kRegTreeProfile : "Profiles",
kRegTreeRoaming : "Roaming",
kRegKeyEnabled : "Enabled",
kRegKeyMethod : "Method",
kRegKeyFiles : "Files",
kRegValMethodStream : "stream",
kRegValMethodCopy : "copy",
kRegTreeStream : "Stream",
kRegKeyStreamURL : "BaseURL",
kRegKeyStreamUsername : "Username",
kRegKeyStreamPassword : "Password",
kRegKeyStreamSavePW : "SavePassword",
kRegTreeCopy : "Copy",
kRegKeyCopyDir : "RemoteDir",
// Registry layout:
// (root) (tree)
// + Profile (tree)
// + (current profile) (tree)
// + Roaming (tree)
// + Enabled (int)
// + Method (string, really enum: stream or copy)
// + Files (string, comma-separated list)
// + Stream (tree)
// | + BaseURL (string)
// | + Username (string)
// | + SavePW (int, really bool)
// | + Password (string, encrypted)
// + Copy (tree)
// + RemoteDir (string)
okClicked : function()
{
if ("UIToData" in window) // unless a different pane is selected
{
UIToData();
}
//this.verifyData();
this.dataToRegistry();
},
// Registry
// Read from the Mozilla registry into the internal data structure
registryToData : function()
{
if (this.loaded == true)
// prevent overwriting of user changes after pane switch back/forth
return;
// set default values, matching the hardcoded ones, in case we fail below
// internal logic
try
{
/* Default files
In case roaming was never set up, we will fail below at reg reading
and use the defaults in this. Set the default files list to some
sensible values, which we will get from the default prefs. */
var pref = Components.classes["@mozilla.org/preferences-service;1"]
.getService()
.QueryInterface(Components.interfaces.nsIPrefService)
.getDefaultBranch(null);
var value = pref.getCharPref("roaming.default.files");
this.Files = value.split(",");
} catch (e) {}
try
{
/* to understand the structure of the registry,
see comment at the const defs above */
// get the Roaming reg branch
registry = Components.classes["@mozilla.org/registry;1"]
.createInstance(Components.interfaces.nsIRegistry);
registry.openWellKnownRegistry(registry.ApplicationRegistry);
this.registry = registry;
var profMan = Components.classes["@mozilla.org/profile/manager;1"]
.getService(Components.interfaces.nsIProfile);
var regkey = registry.getKey(registry.Common, this.kRegTreeProfile);
regkey = registry.getKey(regkey, profMan.currentProfile);
this.regkeyProf = regkey;
regkey = registry.getKey(regkey, this.kRegTreeRoaming);
// enabled
value = registry.getInt(regkey, this.kRegKeyEnabled);
this.Enabled = value == 1 ? true : false;
// method (in the sense of the roaming implementation) selection
value = registry.getString(regkey, this.kRegKeyMethod);
if (value == this.kRegValMethodStream)
this.Method = 0;
else if (value == this.kRegValMethodCopy)
this.Method = 1;
// files
value = registry.getString(regkey, this.kRegKeyFiles);
this.Files = value.split(",");
// remove empty entries
for (var i = 0, l = this.Files.length; i < l; i++)
{
if (this.Files[i] == "")
this.Files.splice(i, 1);
}
// stream
var regkeyRoaming = regkey; // save for use in "copy"
regkey = registry.getKey(regkeyRoaming, this.kRegTreeStream);
this.Stream.BaseURL = registry.getString(regkey, this.kRegKeyStreamURL);
this.Stream.Username = registry.getString(regkey,
this.kRegKeyStreamUsername);
this.Stream.Password = registry.getString(regkey,
this.kRegKeyStreamPassword);
value = registry.getInt(regkey, this.kRegKeyStreamSavePW);
this.Stream.SavePW = value == 1 ? true : false;
// copy
regkey = registry.getKey(regkeyRoaming, this.kRegTreeCopy);
this.Copy.RemoteDir = registry.getString(regkey, this.kRegKeyCopyDir);
// Note that read and write all values. We want to remember them,
// even if not used at the moment.
}
catch (e)
{
if (!this.regkeyProf)
this.showError("ErrorRegRead", undefined, e.message);
// later errors are expected, if we never wrote roaming prefs before,
// fatal otherwise, but we don't know the difference.
else
dump("Error, might be expected (roaming not set up yet): " + e + "\n");
}
this.loaded = true;
/* we might have failed above, but in this case, there is probably no
sense trying it again, so treat that the same as loaded.
This is important for the first setup - the first read will fail. */
},
// Saves from the internal data structure into the Mozilla registry
dataToRegistry : function()
{
if (!this.changed)
return;
var registry = this.registry;
if (!registry || !this.regkeyProf)
// arg, we had a fatal error during read, so bail out
return;
try {
var regkey = this.saveRegBranch(this.regkeyProf, this.kRegTreeRoaming);
// enabled
registry.setInt(regkey, this.kRegKeyEnabled,
this.Enabled == true ? 1 : 0);
// method (in the sense of the roaming implementation) selection
var value;
if (this.Method == 0)
value = this.kRegValMethodStream;
else if (this.Method == 1)
value = this.kRegValMethodCopy;
else // huh??
value = this.kRegValMethodStream;
registry.setString(regkey, this.kRegKeyMethod, value);
// files
value = "";
for (var i = 0, l = this.Files.length; i < l; i++)
{
var file = this.Files[i];
if (file && file != "")
value += file + ",";
}
// remove last ","
if (value.length > 0)
value = value.substring(0, value.length - 1);
registry.setString(regkey, this.kRegKeyFiles, value);
// stream
var regkeyRoaming = regkey; // save for use in "copy"
regkey = this.saveRegBranch(regkeyRoaming, this.kRegTreeStream);
registry.setString(regkey, this.kRegKeyStreamURL, this.Stream.BaseURL);
registry.setString(regkey, this.kRegKeyStreamUsername,
this.Stream.Username);
registry.setString(regkey, this.kRegKeyStreamPassword,
this.Stream.SavePW == true ? this.Stream.Password : "");
registry.setInt(regkey, this.kRegKeyStreamSavePW,
this.Stream.SavePW == true ? 1 : 0);
// copy
regkey = this.saveRegBranch(regkeyRoaming, this.kRegTreeCopy);
registry.setString(regkey, this.kRegKeyCopyDir, this.Copy.RemoteDir);
this.changed = false;
} catch (e) {
this.showError("ErrorRegWrite", undefined, e.message);
return;
}
},
// gets or creates registry branch, i.e. drop-in replacement for
// getKey/addKey returns either the regkey for branch or nothing, if failed
saveRegBranch : function(baseregkey, branchname)
{
try {
return this.registry.getKey(baseregkey, branchname);
} catch (e) { // XXX catch selectively
dump("got (expected?) exception " + e + "\n");
return this.registry.addKey(baseregkey, branchname);
// if that fails with an exception, throw it to caller
}
// throw unexpected errors to caller
},
// Logic
// if some (user-entered) value is bad, shows error dialog and returns false
verifyData : function()
{
if (!this.Enabled)
return;
var errorProp; // see showError();
var errorVal; // dito
var errorException;
if (this.Files.length <= 0)
{
errorProp = "NoFilesSelected";
}
if (this.Method == 0) // stream
{
// username
if (!this.Stream.Username || this.Stream.Username == "")
{
errorProp = "NoUsername";
}
// password
/* password may be empty despite savepw, we'll then ask for the password
during the next transfer and store it (by default) then. */
// base url
try
{
var ioserv = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var baseURL = ioserv.newURI(this.Stream.BaseURL, null, null);
}
catch(e)
{
errorProp = "BaseURLMalformed";
errorVal = this.Stream.BaseURL;
//errorException = e;
}
}
else if (this.Method == 1) // copy
{
// remote dir
if (this.Copy.RemoteDir == "")
{
errorProp = "RemoteDirNonExistant";
errorVal = " ";
}
else
{
try
{
var lf = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
lf.initWithPath(this.Copy.RemoteDir);
if (!lf.exists())
{
throw "";
}
}
catch(e)
{
errorProp = "RemoteDirNonExistant";
errorVal = this.Copy.RemoteDir;
errorException = e.message; // will be undefined, if !lf.exist()
}
}
}
if (errorProp)
this.showError(errorProp, errorVal, errorException);
return errorProp ? true : false;
// XXX We should prevent closure and force the user to enter valid data,
// but I don't know how to do it.
},
/**
* Warning: Don't try to show this after pref window disappeared, because
* we then can't display decendant windows (this error dialog) anymore.
*
* @param prop string stringbungle string name
* @param val string text to be replaced in string
* @param tech string internal error message (exception etc.). In English.
*/
showError : function(prop, val, tech)
{
try
{
var promptService = Components
.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService()
.QueryInterface(Components.interfaces.nsIStringBundleService)
.createBundle("chrome://sroaming/locale/prefs.properties");
var dialogTitle = bundle.GetStringFromName("RoamingErrorTitle");
var text = dialogTitle + "\n";
if (val)
text += bundle.formatStringFromName(prop, [val], 1);
else
text += bundle.GetStringFromName(prop);
if (tech) // should we show exceptions to user?
text += "\n" + tech;
promptService.alert(window, dialogTitle, text);
} catch(e) {
dump("Error while trying to display an error: " + e
+ " (original error: " + prop + " " + tech + ")\n");
}
}
}
// UI
function SwitchDeck(page, deckElement)
{
deckElement.setAttribute("selectedIndex", page);
}
function EnableElement(enabled, triggerElement, elementID)
{
var element = document.getElementById(elementID);
if(!enabled)
element.setAttribute("disabled", "true");
else
element.removeAttribute("disabled");
}
function EnableTree(enabled, element)
{
if (!element || !element.setAttribute)
return;
if(!enabled)
element.setAttribute("disabled", "true");
else
element.removeAttribute("disabled");
// EnableTree direct children (recursive)
var children = element.childNodes;
for (var i = 0; i < children.length; i++)
EnableTree(enabled, children.item(i));
}
function InitElement(elementID)
{
var e = document.getElementById(elementID);
eval(e.getAttribute("oncommand").replace(/this/g, "e")); //hackish, but WFM
}
function E(elementID)
{
return document.getElementById(elementID);
}