зеркало из https://github.com/mozilla/gecko-dev.git
New files for proper progress dialog component; needed for fix for bugs 27609, et al. NOT BUILT YET
This commit is contained in:
Родитель
4a9f3070a4
Коммит
5daec863cb
|
@ -0,0 +1,106 @@
|
|||
<!-- These strings are used on the download progress dialog.
|
||||
See: http://lxr.mozilla.org/seamonkey/source/embedding/components/ui/progressDlg/nsProgressDialog.xul
|
||||
-->
|
||||
|
||||
<!-- These are used when saving -->
|
||||
<!ENTITY savingTitle "Saving #1 (#2%)">
|
||||
<!ENTITY savingAlertTitle "Saving #1">
|
||||
<!ENTITY savingSource "Saving From:">
|
||||
<!ENTITY savingTarget "To:">
|
||||
|
||||
<!-- These are used when opening (with an application) -->
|
||||
<!ENTITY openingTitle "Opening #1 (#2%)">
|
||||
<!ENTITY openingAlertTitle "Opening #1">
|
||||
<!ENTITY openingSource "Opening From:">
|
||||
<!ENTITY openingTarget "With:">
|
||||
|
||||
<!-- Labels on other fields -->
|
||||
<!ENTITY status "Status:">
|
||||
<!ENTITY timeElapsed "Elapsed Time:">
|
||||
<!ENTITY timeLeft "Time Left:">
|
||||
<!ENTITY progress "Progress:">
|
||||
|
||||
<!-- Label for the "keep dialog" checkbox -->
|
||||
<!ENTITY keep "Keep this window open after the download is complete.">
|
||||
|
||||
<!-- Button labels -->
|
||||
<!ENTITY cancel "Cancel">
|
||||
<!ENTITY pause "Pause">
|
||||
<!ENTITY resume "Resume">
|
||||
<!ENTITY close "Close">
|
||||
<!ENTITY reveal "Reveal Location">
|
||||
<!ENTITY launch "Launch File">
|
||||
|
||||
<!-- LOCALIZATION NOTE (filesFolder):
|
||||
This is the name of the folder that is created parallel to a HTML file
|
||||
when it is saved "With Images". The ^BASE^ section is replaced with the
|
||||
leaf name of the file being saved (minus extension). -->
|
||||
<!ENTITY filesFolder "^BASE^_files">
|
||||
|
||||
<!-- Status/progress messages -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (pausedMsg):
|
||||
This string is used to indicate that the download is paused -->
|
||||
<!ENTITY pausedMsg "Download Paused">
|
||||
|
||||
<!-- LOCALIZATION NOTE (progressMsg):
|
||||
|
||||
This string is used to generate the status message used during
|
||||
file download.
|
||||
|
||||
#1 will be replaced by the number of bytes downloaded thus far
|
||||
#2 will be replaced by the total number of bytes to be downloaded
|
||||
#3 will be replaced by the download rate (in KB per second) -->
|
||||
<!ENTITY progressMsg "#1KB of #2KB (at #3KB/sec)">
|
||||
|
||||
<!-- LOCALIZATION NOTE (unknownTime):
|
||||
|
||||
This string is used when the time remaining is unknown. -->
|
||||
<!ENTITY unknownTime "Unknown">
|
||||
|
||||
<!-- LOCALIZATION NOTE (longTimeFormat):
|
||||
|
||||
This string is used to format elapsed/remaining times when the
|
||||
time exceeds 1 hour in length.
|
||||
|
||||
#1 will be replaced by the number of hours
|
||||
#2 will be replaced by the number of minutes
|
||||
#3 will be replaced by the number of seconds -->
|
||||
<!ENTITY longTimeFormat "#1:#2:#3">
|
||||
|
||||
<!-- LOCALIZATION NOTE (shortTimeFormat):
|
||||
|
||||
This string is used to format elapsed/remaining times when the
|
||||
time is less than 1 hour in length. Note that you can leave
|
||||
"#1" out of this string to omit the leading "00:" if you so choose.
|
||||
|
||||
#1 will be replaced by the number of hours
|
||||
#2 will be replaced by the number of minutes
|
||||
#3 will be replaced by the number of seconds -->
|
||||
<!ENTITY shortTimeFormat "#2:#3">
|
||||
|
||||
<!-- LOCALIZATION NOTE (completeMsg):
|
||||
|
||||
This string is displayed when the download is complete. The insert
|
||||
"#1" is replaced by the elapsed time, formatted according to the
|
||||
xxxTimeFormat strings defined above). You can omit "#1" if you don't
|
||||
want the elapsed time in the message.
|
||||
|
||||
#1 will be replaced by the elapsed time -->
|
||||
<!ENTITY completeMsg "Download complete (elapsed time was #1)">
|
||||
|
||||
<!-- LOCALIZATION NOTE (percentMsg):
|
||||
|
||||
This string is used to format the text to the right of the progress
|
||||
meter.
|
||||
|
||||
#1 will be replaced by the percentage of the file that has been saved -->
|
||||
<!ENTITY percentMsg "#1%">
|
||||
|
||||
<!-- LOCALIZATION NOTE (filesFolder):
|
||||
This is the name of the folder that is created parallel to a HTML file
|
||||
when it is saved "With Images". The ^BASE^ section is replaced with the
|
||||
leaf name of the file being saved (minus extension). -->
|
||||
<!ENTITY filesFolder "^BASE^_files">
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#!nmake
|
||||
#
|
||||
# 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, Inc. Portions created by Netscape are
|
||||
# Copyright (C) 2001, Mozilla. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
DEPTH=..\..\..\..
|
||||
|
||||
MODULE=progressDlg
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsIProgressDialog.idl \
|
||||
$(NULL)
|
||||
|
||||
JSCOMPONENTS = \
|
||||
.\nsProgressDialog.js \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
libs:: $(JSCOMPONENTS)
|
||||
!@$(MAKE_INSTALL) $(JSCOMPONENTS) $(DIST)\bin\components
|
|
@ -0,0 +1,114 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bill Law law@netscape.com
|
||||
*/
|
||||
|
||||
#include "nsIWebProgressListener.idl"
|
||||
|
||||
interface nsIWebBrowserPersist;
|
||||
interface nsIDOMWindow;
|
||||
interface nsILocalFile;
|
||||
|
||||
/* nsIProgressDialog
|
||||
*
|
||||
* These objects are used to display progress notifications to the user.
|
||||
* They are displayed while files are being saved to disk, for example.
|
||||
*
|
||||
* Typical usage is to:
|
||||
* 1. Create an instance, via the component manager CreateInstance()
|
||||
* method.
|
||||
* 2. Set appropriate attributes that control the display and behavior
|
||||
* of the dialog.
|
||||
* 3. Open the dialog.
|
||||
* 4. Send progress notifications to the dialog, via it's
|
||||
* nsIWebProgressListener methods.
|
||||
* 5. Close the dialog when the operation completes, or when the user
|
||||
* closes it manually.
|
||||
* 6. Release the instance. The instance will be referenced by
|
||||
* the dialog itself, so it won't get freed until the dialog closes.
|
||||
*
|
||||
* Important Note: Implementors of this interface must also implement
|
||||
* nsISupportsWeakReference.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(88A478B3-AF65-440a-94DC-ED9B154D2990)]
|
||||
interface nsIProgressDialog : nsIWebProgressListener {
|
||||
/**
|
||||
* Open the dialog
|
||||
*
|
||||
* @param aParent Parent window; optional (if null, then
|
||||
* a top-level window is created)
|
||||
* @param aPersist The stream transfer operation that the dialog is
|
||||
* to show progress for. This is optional. If
|
||||
* specified, then the progress dialog will register
|
||||
* itself as the listener for that object. Otherwise,
|
||||
* it is the caller's responsibility to connect this
|
||||
* object to something that sends out the web progress
|
||||
* notifications.
|
||||
*/
|
||||
void open( in nsIDOMWindow aParent, in nsIWebBrowserPersist aPersist );
|
||||
|
||||
/**
|
||||
* Set starting time to use in elapsed/remaining time calculations;
|
||||
* this is useful in cases where the download might have started
|
||||
* prior to the dialog opening; the time is specified as
|
||||
* milliseconds, according to the convention for the JavaScript Date
|
||||
* object getTime function; if not specified, this value will default
|
||||
* to the time at which the progress dialog object is created.
|
||||
*/
|
||||
attribute long long startTime;
|
||||
|
||||
/**
|
||||
* URL of the source of the stream transfer that the dialog is
|
||||
* displaying the progress of.
|
||||
*/
|
||||
attribute nsIURI source;
|
||||
|
||||
/**
|
||||
* Target of the stream transfer that the dialog is
|
||||
* displaying the progress of.
|
||||
*/
|
||||
attribute nsILocalFile target;
|
||||
|
||||
/**
|
||||
* Set this attribute to indicate that the dialog is being
|
||||
* used to display progress prior to opening a downloaded
|
||||
* file with a helper application. The application string
|
||||
* specified will appear on the dialog, unless the string
|
||||
* is empty. This will also cause the "keep this dialog
|
||||
* open after download" checkbox hidden.
|
||||
*/
|
||||
attribute wstring openingWith;
|
||||
|
||||
/**
|
||||
* The web browser persist object doing the associated I/O.
|
||||
* May be null.
|
||||
*/
|
||||
readonly attribute nsIWebBrowserPersist operation;
|
||||
|
||||
/**
|
||||
* The dialog object itself. This might be null if the dialog isn't
|
||||
* open yet, or has been closed.
|
||||
*/
|
||||
readonly attribute nsIDOMWindow dialog;
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,775 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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 the Mozilla browser.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2001 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributors:
|
||||
* Bill Law <law@netscape.com>
|
||||
*/
|
||||
|
||||
/* This file implements the nsIProgressDialog interface. See nsIProgressDialog.idl
|
||||
*
|
||||
* The implementation consists of a JavaScript "class" named nsProgressDialog,
|
||||
* comprised of:
|
||||
* - a JS constructor function
|
||||
* - a prototype providing all the interface methods and implementation stuff
|
||||
*
|
||||
* In addition, this file implements an nsIModule object that registers the
|
||||
* nsProgressDialog component.
|
||||
*/
|
||||
|
||||
/* NOTE: The current implementation uses the existing "helper app launcher download dialog"
|
||||
* (see http://lxr.mozilla.org/seamonkey/source/xpfe/components/ucth/resources) and
|
||||
* implements only a subset of the capabilities envisioned for this component.
|
||||
*
|
||||
* See the .idl file for details.
|
||||
*/
|
||||
|
||||
/* ctor
|
||||
*/
|
||||
function nsProgressDialog() {
|
||||
// Initialize data properties.
|
||||
this.mParent = null;
|
||||
this.mOperation = null;
|
||||
this.mStartTime = ( new Date() ).getTime();
|
||||
this.mLastUpdate = Number.MIN_VALUE; // To ensure first onProgress causes update.
|
||||
this.mInterval = 750; // Default to .75 seconds.
|
||||
this.mElapsed = 0;
|
||||
this.mLoaded = false;
|
||||
this.fields = new Array;
|
||||
this.strings = new Array;
|
||||
this.mSource = null;
|
||||
this.mTarget = null;
|
||||
this.mApp = null;
|
||||
this.mDialog = null;
|
||||
this.mPaused = null;
|
||||
this.mRequest = null;
|
||||
this.mCompleted = false;
|
||||
this.mMode = "normal";
|
||||
this.mPercent = 0;
|
||||
this.mRate = 0;
|
||||
}
|
||||
|
||||
const nsIProgressDialog = Components.interfaces.nsIProgressDialog;
|
||||
|
||||
nsProgressDialog.prototype = {
|
||||
// Turn this on to get debugging messages.
|
||||
debug: true,
|
||||
|
||||
// Currently, use old helperAppDldProgress.xul.
|
||||
dialogChrome: "chrome://global/content/nsProgressDialog.xul",
|
||||
dialogFeatures: "chrome,titlebar,minimizable=yes",
|
||||
|
||||
// getters/setters
|
||||
get saving() { return this.openingWith == null; },
|
||||
get parent() { return this.mParent; },
|
||||
set parent(newval) { return this.mParent = newval; },
|
||||
get operation() { return this.mOperation; },
|
||||
set operation(newval) { return this.mOperation = newval; },
|
||||
get startTime() { return this.mStartTime; },
|
||||
set startTime(newval) { return this.mStartTime = newval/1000; }, // PR_Now() is in microseconds, so we convert.
|
||||
get lastUpdate() { return this.mLastUpdate; },
|
||||
set lastUpdate(newval) { return this.mLastUpdate = newval; },
|
||||
get interval() { return this.mInterval; },
|
||||
set interval(newval) { return this.mInterval = newval; },
|
||||
get elapsed() { return this.mElapsed; },
|
||||
set elapsed(newval) { return this.mElapsed = newval; },
|
||||
get loaded() { return this.mLoaded; },
|
||||
set loaded(newval) { return this.mLoaded = newval; },
|
||||
get source() { return this.mSource; },
|
||||
set source(newval) { return this.mSource = newval; },
|
||||
get target() { return this.mTarget; },
|
||||
set target(newval) { return this.mTarget = newval; },
|
||||
get openingWith() { return this.mApp; },
|
||||
set openingWith(newval) { return this.mApp = newval; },
|
||||
get dialog() { return this.mDialog; },
|
||||
set dialog(newval) { return this.mDialog = newval; },
|
||||
get paused() { return this.mPaused; },
|
||||
get request() { return this.mRequest; },
|
||||
get completed() { return this.mCompleted; },
|
||||
get mode() { return this.mMode; },
|
||||
get percent() { return this.mPercent; },
|
||||
get rate() { return this.mRate; },
|
||||
get kRate() { return this.mRate / 1024; },
|
||||
|
||||
// These setters use funcitons that update the dialog.
|
||||
set paused(newval) { return this.setPaused(newval); },
|
||||
set request(newval) { return this.setRequest(newval); },
|
||||
set completed(newval) { return this.setCompleted(newval); },
|
||||
set mode(newval) { return this.setMode(newval); },
|
||||
set percent(newval) { return this.setPercent(newval); },
|
||||
set rate(newval) { return this.setRate(newval); },
|
||||
|
||||
// ---------- nsIProgressDialog methods ----------
|
||||
|
||||
// open: Store aParentWindow and open the dialog.
|
||||
open: function( aParentWindow, aPersist ) {
|
||||
// Save parent and "persist" operation.
|
||||
this.parent = aParentWindow;
|
||||
this.operation = aPersist;
|
||||
|
||||
// Open dialog using the WindowWatcher service.
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService( Components.interfaces.nsIWindowWatcher );
|
||||
this.dialog = ww.openWindow( this.parent,
|
||||
this.dialogChrome,
|
||||
null,
|
||||
this.dialogFeatures,
|
||||
this );
|
||||
},
|
||||
|
||||
// ---------- nsIWebProgressListener methods ----------
|
||||
|
||||
// Look for STATE_STOP and update dialog to indicate completion when it happens.
|
||||
onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
|
||||
if ( aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP ) {
|
||||
// we are done downloading...
|
||||
this.completed = true;
|
||||
}
|
||||
},
|
||||
|
||||
// Handle progress notifications.
|
||||
onProgressChange: function( aWebProgress,
|
||||
aRequest,
|
||||
aCurSelfProgress,
|
||||
aMaxSelfProgress,
|
||||
aCurTotalProgress,
|
||||
aMaxTotalProgress ) {
|
||||
// Remember the request; this will also initialize the pause/resume stuff.
|
||||
this.request = aRequest;
|
||||
|
||||
var overallProgress = aCurTotalProgress;
|
||||
|
||||
// Get current time.
|
||||
var now = ( new Date() ).getTime();
|
||||
|
||||
// If interval hasn't elapsed, ignore it.
|
||||
if ( now - this.lastUpdate < this.interval &&
|
||||
aMaxTotalProgress != "-1" &&
|
||||
parseInt( aCurTotalProgress ) < parseInt( aMaxTotalProgress ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update this time.
|
||||
this.lastUpdate = now;
|
||||
|
||||
// Update elapsed time.
|
||||
this.elapsed = now - this.startTime;
|
||||
|
||||
// Calculate percentage.
|
||||
if ( aMaxTotalProgress > 0) {
|
||||
this.percent = Math.floor( ( overallProgress * 100.0 ) / aMaxTotalProgress );
|
||||
} else {
|
||||
this.percent = -1;
|
||||
}
|
||||
|
||||
// If dialog not loaded, then don't bother trying to update display.
|
||||
if ( !this.loaded ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update dialog's display of elapsed time.
|
||||
this.setValue( "timeElapsed", this.formatSeconds( this.elapsed / 1000 ) );
|
||||
|
||||
// Now that we've set the progress and the time, update # bytes downloaded...
|
||||
// Update status (nnK of mmK bytes at xx.xK aCurTotalProgress/sec)
|
||||
var status = this.getString( "progressMsg" );
|
||||
|
||||
// Insert 1 is the number of kilobytes downloaded so far.
|
||||
status = this.replaceInsert( status, 1, parseInt( overallProgress/1024 + .5 ) );
|
||||
|
||||
// Insert 2 is the total number of kilobytes to be downloaded (if known).
|
||||
if ( aMaxTotalProgress != "-1" ) {
|
||||
status = this.replaceInsert( status, 2, parseInt( aMaxTotalProgress/1024 + .5 ) );
|
||||
} else {
|
||||
status = replaceInsert( status, 2, "??" );
|
||||
}
|
||||
|
||||
// Insert 3 is the download rate.
|
||||
if ( this.elapsed ) {
|
||||
this.rate = ( aCurTotalProgress * 1000 ) / this.elapsed;
|
||||
status = this.replaceInsert( status, 3, this.rateToKRate( this.rate ) );
|
||||
} else {
|
||||
// Rate not established, yet.
|
||||
status = this.replaceInsert( status, 3, "??.?" );
|
||||
}
|
||||
|
||||
// All 3 inserts are taken care of, now update status msg.
|
||||
this.setValue( "status", status );
|
||||
|
||||
// Update time remaining.
|
||||
if ( this.rate && ( aMaxTotalProgress > 0 ) ) {
|
||||
// Calculate how much time to download remaining at this rate.
|
||||
var rem = ( aMaxTotalProgress - aCurTotalProgress ) / this.rate;
|
||||
rem = parseInt( rem + .5 );
|
||||
this.setValue( "timeLeft", this.formatSeconds( rem ) );
|
||||
} else {
|
||||
// We don't know how much time remains.
|
||||
this.setValue( "timeLeft", this.getString( "unknownTime" ) );
|
||||
}
|
||||
},
|
||||
|
||||
// Look for error notifications and display alert to user.
|
||||
onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
|
||||
// Check for error condition (only if dialog is still open).
|
||||
if ( this.dialog && aStatus != Components.results.NS_OK ) {
|
||||
// Get prompt service.
|
||||
var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
|
||||
.getService( Components.interfaces.nsIPromptService );
|
||||
// Display error alert (using text supplied by back-end).
|
||||
var title = this.getString( this.saving ? "savingAlertTitle" : "openingAlertTitle" );
|
||||
this.replaceInsert( title, 1, this.fileName );
|
||||
prompter.alert( this.dialog, title, aMessage );
|
||||
|
||||
// Close the dialog.
|
||||
if ( !this.completed ) {
|
||||
this.onCancel();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Ignore onLocationChange and onSecurityChange notifications.
|
||||
onLocationChange: function( aWebProgress, aRequest, aLocation ) {
|
||||
},
|
||||
|
||||
onSecurityChange: function( aWebProgress, aRequest, state ) {
|
||||
},
|
||||
|
||||
// ---------- nsIObserver methods ----------
|
||||
observe: function( anObject, aTopic, aData ) {
|
||||
// Something of interest occured on the dialog.
|
||||
// Dispatch to corresponding implementation method.
|
||||
switch ( aTopic ) {
|
||||
case "onload":
|
||||
this.onLoad();
|
||||
break;
|
||||
case "oncancel":
|
||||
this.onCancel();
|
||||
break;
|
||||
case "onpause":
|
||||
this.onPause();
|
||||
break;
|
||||
case "onlaunch":
|
||||
this.onLaunch();
|
||||
break;
|
||||
case "onreveal":
|
||||
this.onReveal();
|
||||
break;
|
||||
case "onunload":
|
||||
this.onUnload();
|
||||
break;
|
||||
case "oncompleted":
|
||||
// This event comes in when setCompleted needs to be deferred because
|
||||
// the dialog isn't loaded yet.
|
||||
this.completed = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// ---------- nsISupports methods ----------
|
||||
|
||||
// This "class" supports nsIProgressDialog, nsIWebProgressListener (by virtue
|
||||
// of interface inheritance), nsIObserver, and nsISupports.
|
||||
QueryInterface: function (iid) {
|
||||
if (!iid.equals(Components.interfaces.nsIProgressDialog) &&
|
||||
!iid.equals(Components.interfaces.nsIWebProgressListener) &&
|
||||
!iid.equals(Components.interfaces.nsISupportsWeakReference) &&
|
||||
!iid.equals(Components.interfaces.nsIObserver) &&
|
||||
!iid.equals(Components.interfaces.nsISupports)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// ---------- implementation methods ----------
|
||||
|
||||
// Initialize the dialog.
|
||||
onLoad: function() {
|
||||
// Note that onLoad has finished.
|
||||
this.loaded = true;
|
||||
|
||||
// Fill dialog.
|
||||
this.loadDialog();
|
||||
|
||||
// Position dialog.
|
||||
if ( this.dialog.opener ) {
|
||||
this.dialog.moveToAlertPosition();
|
||||
} else {
|
||||
this.dialog.centerWindowOnScreen();
|
||||
}
|
||||
|
||||
// Set initial focus on "keep open" box. If that box is hidden, or, if
|
||||
// the download is already complete, then focus is on the cancel/close
|
||||
// button. The download may be complete if it was really short and the
|
||||
// dialog took longer to open than to download the data.
|
||||
if ( !this.completed && !this.saving ) {
|
||||
this.dialogElement( "keep" ).focus();
|
||||
} else {
|
||||
this.dialogElement( "cancel" ).focus();
|
||||
}
|
||||
},
|
||||
|
||||
// load dialog with initial contents
|
||||
loadDialog: function() {
|
||||
// Check whether we're saving versus opening with a helper app.
|
||||
if ( !this.saving ) {
|
||||
// Put proper label on source field.
|
||||
this.setValue( "sourceLabel", this.getString( "openingSource" ) );
|
||||
|
||||
// Target is the "opening with" application. Hide if empty.
|
||||
if ( this.openingWith.length == 0 ) {
|
||||
this.hide( "targetRow" );
|
||||
} else {
|
||||
// Use the "with:" label.
|
||||
this.setValue( "targetLabel", this.getString( "openingTarget" ) );
|
||||
// Name of application.
|
||||
this.setValue( "target", this.openingWith );
|
||||
}
|
||||
} else {
|
||||
// Target is the destination file.
|
||||
this.setValue( "target", this.target.unicodePath );
|
||||
}
|
||||
|
||||
// Set source field.
|
||||
this.setValue( "source", this.source.spec );
|
||||
|
||||
var now = ( new Date() ).getTime();
|
||||
|
||||
// Intialize the elapsed time.
|
||||
if ( !this.elapsed ) {
|
||||
this.elapsed = now - this.startTime;
|
||||
}
|
||||
|
||||
// Update elapsed time display.
|
||||
this.setValue( "timeElapsed", this.formatSeconds( this.elapsed / 1000 ) );
|
||||
this.setValue( "timeLeft", this.getString( "unknownTime" ) );
|
||||
|
||||
// Initialize the "keep open" box. Hide this if we're opening a helper app.
|
||||
if ( !this.saving ) {
|
||||
// Hide this in this case.
|
||||
this.hide( "keep" );
|
||||
} else {
|
||||
// Initialize using last-set value from prefs.
|
||||
var prefs = Components.classes[ "@mozilla.org/preferences-service;1" ]
|
||||
.getService( Components.interfaces.nsIPrefBranch );
|
||||
if ( prefs ) {
|
||||
this.dialogElement( "keep" ).checked = prefs.getBoolPref( "browser.download.progressDnldDialog.keepAlive" );
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize title.
|
||||
this.setTitle();
|
||||
},
|
||||
|
||||
// Cancel button stops the download (if not completed),
|
||||
// and closes the dialog.
|
||||
onCancel: function() {
|
||||
// Test whether the dialog is already closed.
|
||||
// This will be the case if we've come through onUnload.
|
||||
if ( this.dialog ) {
|
||||
// Close the dialog.
|
||||
this.dialog.close();
|
||||
}
|
||||
// Cancel the download, if not completed.
|
||||
if ( !this.completed && this.operation ) {
|
||||
this.operation.cancelDownload();
|
||||
}
|
||||
},
|
||||
|
||||
// onunload event means the dialog has closed.
|
||||
// We go through our onCancel logic to stop the download if still in progress.
|
||||
onUnload: function() {
|
||||
// Remember "keep dialog open" setting, if visible.
|
||||
if ( this.saving ) {
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService( Components.interfaces.nsIPrefBranch );
|
||||
if ( prefs ) {
|
||||
prefs.setBoolPref( "browser.download.progressDnldDialog.keepAlive", this.dialogElement( "keep" ).checked );
|
||||
}
|
||||
}
|
||||
this.dialog = null; // The dialog is history.
|
||||
this.onCancel();
|
||||
},
|
||||
|
||||
// onpause event means the user pressed the pause/resume button
|
||||
// Toggle the pause/resume state (see the function setPause(), below).i
|
||||
onPause: function() {
|
||||
this.paused = !this.paused;
|
||||
},
|
||||
|
||||
// onlaunch event means the user pressed the launch button
|
||||
// Invoke the launch method of the target file.
|
||||
onLaunch: function() {
|
||||
try {
|
||||
this.target.launch();
|
||||
this.dialog.close();
|
||||
} catch ( exception ) {
|
||||
// XXX Need code here to tell user the launch failed!
|
||||
dump( "nsProgressDialog::onLaunch failed: " + exception + "\n" );
|
||||
}
|
||||
},
|
||||
|
||||
// onreveal event means the user pressed the "reveal location" button
|
||||
// Invoke the reveal method of the target file.
|
||||
onReveal: function() {
|
||||
try {
|
||||
this.target.reveal();
|
||||
this.dialog.close();
|
||||
} catch ( exception ) {
|
||||
}
|
||||
},
|
||||
|
||||
// Set the dialog title.
|
||||
setTitle: function() {
|
||||
// Start with saving/opening template.
|
||||
var title = this.saving ? this.getString( "savingTitle" ) : this.getString( "openingTitle" );
|
||||
|
||||
// Use file name as insert 1.
|
||||
var fname = this.target.unicodePath;
|
||||
var n = this.target.unicodePath.lastIndexOf( "\\" );
|
||||
title = this.replaceInsert( title, 1, fname.substring( n + 1 ) );
|
||||
|
||||
// Use percentage as insert 2.
|
||||
title = this.replaceInsert( title, 2, this.percent );
|
||||
|
||||
// Set <window>'s title attribute.
|
||||
if ( this.dialog ) {
|
||||
this.dialog.title = title;
|
||||
}
|
||||
},
|
||||
|
||||
// Update the dialog to indicate specified percent complete.
|
||||
setPercent: function( percent ) {
|
||||
// Maximum percentage is 100.
|
||||
if ( percent > 100 ) {
|
||||
percent = 100;
|
||||
}
|
||||
// Test if percentage is changing.
|
||||
if ( this.percent != percent ) {
|
||||
this.mPercent = percent;
|
||||
|
||||
// If dialog not opened yet, bail early.
|
||||
if ( !this.loaded ) {
|
||||
return this.mPercent;
|
||||
}
|
||||
|
||||
if ( percent == -1 ) {
|
||||
// Progress meter needs to be in "undetermined" mode.
|
||||
this.mode = "undetermined";
|
||||
|
||||
// Update progress meter percentage text.
|
||||
this.setValue( "progressText", "" );
|
||||
} else {
|
||||
// Progress meter needs to be in normal mode.
|
||||
this.mode = "normal";
|
||||
|
||||
// Set progress meter thermometer.
|
||||
this.setValue( "progress", percent );
|
||||
|
||||
// Update progress meter percentage text.
|
||||
this.setValue( "progressText", this.replaceInsert( this.getString( "percentMsg" ), 1, percent ) );
|
||||
}
|
||||
|
||||
// Update title.
|
||||
this.setTitle();
|
||||
}
|
||||
return this.mPercent;
|
||||
},
|
||||
|
||||
// Update download rate and dialog display.
|
||||
// Note that we don't want the displayed value to quiver
|
||||
// between essentially identical values (e.g., 99.9Kb and
|
||||
// 100.0Kb) so we only update if we see a big change.
|
||||
setRate: function( rate ) {
|
||||
if ( rate ) {
|
||||
// rate is bytes/sec
|
||||
var change = Math.abs( this.rate - rate );
|
||||
// Don't update too often!
|
||||
if ( change > this.rate / 10 ) {
|
||||
// Displayed rate changes.
|
||||
this.mRate = rate;
|
||||
}
|
||||
}
|
||||
return this.mRate;
|
||||
},
|
||||
|
||||
// Handle download completion.
|
||||
setCompleted: function() {
|
||||
// If dialog hasn't loaded yet, defer this.
|
||||
if ( !this.loaded ) {
|
||||
this.dialog.setTimeout( function(obj){obj.setCompleted()}, 100, this );
|
||||
return false;
|
||||
}
|
||||
if ( !this.mCompleted ) {
|
||||
this.mCompleted = true;
|
||||
|
||||
// If the "keep dialog open" box is checked, then update dialog.
|
||||
if ( this.dialog && this.dialogElement( "keep" ).checked ) {
|
||||
// Indicate completion in status area.
|
||||
this.setValue( "status", this.replaceInsert( this.getString( "completeMsg" ),
|
||||
1,
|
||||
this.formatSeconds( this.elapsed/1000 ) ) );
|
||||
|
||||
// Put progress meter at 100%.
|
||||
this.percent = 100;
|
||||
|
||||
// Set time remaining to 00:00.
|
||||
this.setValue( "timeLeft", this.formatSeconds( 0 ) );
|
||||
|
||||
// Change Cancel button to Close, and give it focus.
|
||||
var cancelButton = this.dialogElement( "cancel" );
|
||||
cancelButton.label = this.getString( "close" );
|
||||
cancelButton.focus();
|
||||
|
||||
// Activate reveal/launch buttons.
|
||||
this.enable( "reveal" );
|
||||
if ( this.target && !this.target.isExecutable() ) {
|
||||
this.enable( "launch" );
|
||||
}
|
||||
|
||||
// Disable the Pause/Resume buttons.
|
||||
this.dialogElement( "pause" ).disabled = true;
|
||||
this.dialogElement( "resume" ).disabled = true;
|
||||
|
||||
// Fix up dialog layout (which gets messed up sometimes).
|
||||
this.dialog.sizeToContent();
|
||||
} else if ( this.dialog ) {
|
||||
this.dialog.close();
|
||||
}
|
||||
}
|
||||
return this.mCompleted;
|
||||
},
|
||||
|
||||
// Set progress meter to given mode ("normal" or "undetermined").
|
||||
setMode: function( newMode ) {
|
||||
if ( this.mode != newMode ) {
|
||||
// Need to update progress meter.
|
||||
this.dialogElement( "progress" ).setAttribute( "mode", newMode );
|
||||
}
|
||||
return this.mMode = newMode;
|
||||
},
|
||||
|
||||
// Set pause/resume state.
|
||||
setPaused: function( pausing ) {
|
||||
// If state changing, then update stuff.
|
||||
if ( this.paused != pausing ) {
|
||||
// Set selected index:
|
||||
// Going from active state to paused: 2 -> "resume"
|
||||
// Going from initial or paused state to active: 1 -> "pause"
|
||||
this.dialogElement( "pauseResume" ).selectedIndex = pausing ? 2 : 1;
|
||||
|
||||
// If we have a request, suspend/resume it.
|
||||
if ( this.request ) {
|
||||
if ( pausing ) {
|
||||
this.request.suspend();
|
||||
} else {
|
||||
this.request.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.mPaused = pausing;
|
||||
},
|
||||
|
||||
// Set the saved nsIRequest. The first time, we test it for
|
||||
// ftp and initialize the pause/resume stuff.
|
||||
// XXX This is broken, I think, because if we're doing something
|
||||
// like saving a web-page-complete that has multiple images
|
||||
// accessed via ftp: urls, then it seems like the pause/resume
|
||||
// button should come and go, depending on what's being downloaded
|
||||
// at a given point in time. The old dialog didn't handle that case
|
||||
// either, though, so I'm not sweating it for now.
|
||||
setRequest: function( aRequest ) {
|
||||
if ( this.request == null && this.loaded && aRequest ) {
|
||||
// Right now, all that supports restarting downloads is ftp (rfc959).
|
||||
try {
|
||||
ftpChannel = aRequest.QueryInterface( Components.interfaces.nsIFTPChannel );
|
||||
if ( ftpChannel ) {
|
||||
this.dialogElement("pauseResume").selectedIndex = 1;
|
||||
this.paused = false;
|
||||
}
|
||||
} catch ( e ) {
|
||||
}
|
||||
// This *must* come after the "this.paused = false" above, so that we
|
||||
// don't suspend or resume the first time we call that function!
|
||||
this.mRequest = aRequest;
|
||||
}
|
||||
return this.mRequest;
|
||||
},
|
||||
|
||||
// Convert raw rate (bytes/sec) to Kbytes/sec (to nearest tenth).
|
||||
rateToKRate: function( rate ) {
|
||||
var kRate = rate / 1024; // KBytes/sec
|
||||
var fraction = parseInt( ( kRate - ( kRate = parseInt( kRate ) ) ) * 10 + 0.5 );
|
||||
return kRate + "." + fraction;
|
||||
},
|
||||
|
||||
// Format number of seconds in hh:mm:ss form.
|
||||
formatSeconds: function( secs ) {
|
||||
// Round the number of seconds to remove fractions.
|
||||
secs = parseInt( secs + .5 );
|
||||
var hours = parseInt( secs/3600 );
|
||||
secs -= hours*3600;
|
||||
var mins = parseInt( secs/60 );
|
||||
secs -= mins*60;
|
||||
var result;
|
||||
if ( hours )
|
||||
result = this.getString( "longTimeFormat" );
|
||||
else
|
||||
result = this.getString( "shortTimeFormat" );
|
||||
|
||||
if ( hours < 10 )
|
||||
hours = "0" + hours;
|
||||
if ( mins < 10 )
|
||||
mins = "0" + mins;
|
||||
if ( secs < 10 )
|
||||
secs = "0" + secs;
|
||||
|
||||
// Insert hours, minutes, and seconds into result string.
|
||||
result = this.replaceInsert( result, 1, hours );
|
||||
result = this.replaceInsert( result, 2, mins );
|
||||
result = this.replaceInsert( result, 3, secs );
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
// Get dialog element using argument as id.
|
||||
dialogElement: function( id ) {
|
||||
// Check if we've already fetched it.
|
||||
if ( !( id in this.fields ) ) {
|
||||
// No, then get it from dialog.
|
||||
try {
|
||||
this.fields[ id ] = this.dialog.document.getElementById( id );
|
||||
} catch(e) {
|
||||
this.fields[ id ] = {
|
||||
value: "",
|
||||
setAttribute: function(id,val) {},
|
||||
removeAttribute: function(id) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.fields[ id ];
|
||||
},
|
||||
|
||||
// Set dialog element value for given dialog element.
|
||||
setValue: function( id, val ) {
|
||||
this.dialogElement( id ).value = val;
|
||||
},
|
||||
|
||||
// Enable dialgo element.
|
||||
enable: function( field ) {
|
||||
this.dialogElement( field ).removeAttribute( "disabled" );
|
||||
},
|
||||
|
||||
// Get localizable string (from dialog <data> elements).
|
||||
getString: function ( stringId ) {
|
||||
// Check if we've fetched this string already.
|
||||
if ( !( this.strings && stringId in this.strings ) ) {
|
||||
// Presume the string is empty if we can't get it.
|
||||
this.strings[ stringId ] = "";
|
||||
// Try to get it.
|
||||
try {
|
||||
this.strings[ stringId ] = this.dialog.document.getElementById( "string."+stringId ).childNodes[0].nodeValue;
|
||||
} catch (e) {}
|
||||
}
|
||||
return this.strings[ stringId ];
|
||||
},
|
||||
|
||||
// Replaces insert ("#n") with input text.
|
||||
replaceInsert: function( text, index, value ) {
|
||||
var result = text;
|
||||
var regExp = new RegExp( "#"+index );
|
||||
result = result.replace( regExp, value );
|
||||
return result;
|
||||
},
|
||||
|
||||
// Hide a given dialog field.
|
||||
hide: function( field ) {
|
||||
this.dialogElement( field ).setAttribute( "style", "display: none;" );
|
||||
// Hide the associated separator, too.
|
||||
this.dialogElement( field+"Separator" ).setAttribute( "style", "display: none;" );
|
||||
},
|
||||
|
||||
// Return input in hex, prepended with "0x" and leading zeros (to 8 digits).
|
||||
hex: function( x ) {
|
||||
var hex = Number(x).toString(16);
|
||||
return "0x" + ( "00000000" + hex ).substring( hex.length );
|
||||
},
|
||||
|
||||
// Dump text (if debug is on).
|
||||
dump: function( text ) {
|
||||
if ( this.debug ) {
|
||||
dump( text );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This Component's module implementation. All the code below is used to get this
|
||||
// component registered and accessible via XPCOM.
|
||||
var module = {
|
||||
// registerSelf: Register this component.
|
||||
registerSelf: function (compMgr, fileSpec, location, type) {
|
||||
compMgr = compMgr.QueryInterface( Components.interfaces.nsIComponentManagerObsolete );
|
||||
compMgr.registerComponentWithType( this.cid,
|
||||
"Mozilla Download Progress Dialog",
|
||||
this.contractId,
|
||||
fileSpec,
|
||||
location,
|
||||
true,
|
||||
true,
|
||||
type );
|
||||
},
|
||||
|
||||
// getClassObject: Return this component's factory object.
|
||||
getClassObject: function (compMgr, cid, iid) {
|
||||
if (!cid.equals(this.cid))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
return this.factory;
|
||||
},
|
||||
|
||||
/* CID for this class */
|
||||
cid: Components.ID("{F5D248FD-024C-4f30-B208-F3003B85BC92}"),
|
||||
|
||||
/* Contract ID for this class */
|
||||
contractId: "@mozilla.org/progressdialog;1",
|
||||
|
||||
/* factory object */
|
||||
factory: {
|
||||
// createInstance: Return a new nsProgressDialog object.
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
return (new nsProgressDialog()).QueryInterface(iid);
|
||||
}
|
||||
},
|
||||
|
||||
// canUnload: n/a (returns true)
|
||||
canUnload: function(compMgr) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// NSGetModule: Return the nsIModule object.
|
||||
function NSGetModule(compMgr, fileSpec) {
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- -*- Mode: HTML -*- -->
|
||||
|
||||
<!-- 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-2000 Netscape Communications Corporation. All
|
||||
Rights Reserved.
|
||||
|
||||
Contributor(s):
|
||||
Scott MacGregor <mscott@netscape.com>
|
||||
Bill Law <law@netscape.com>
|
||||
-->
|
||||
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://global/locale/nsProgressDialog.dtd">
|
||||
|
||||
<!-- This dialog can only be opened by creating an instance of the
|
||||
component "@mozilla.org/progressdialog;1". You cannot open it
|
||||
via window.open (or window.openDialog, or any variants thereof).
|
||||
|
||||
That code will pass an nsIObserver interface via window.arguments[0].
|
||||
All "commands" in this dialog simply send notifications via that
|
||||
interface.
|
||||
|
||||
See the implementation of that component in
|
||||
http://lxr.mozilla.org/seamonkey/source/embedding/components/ui/progressDlg/nsProgressDialog.js
|
||||
for details.
|
||||
-->
|
||||
|
||||
<window xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
class="dialog"
|
||||
title="&savingTitle;"
|
||||
onload="notifyObserver('onload')"
|
||||
onunload="notifyObserver('onunload')">
|
||||
|
||||
<!-- This is the only JS code in this file. It simply routes the "command"
|
||||
to the dialog's observer (the implementation in nsProgressDialog.js).
|
||||
-->
|
||||
<script type="application/x-javascript"><![CDATA[
|
||||
function notifyObserver( cmd ) {
|
||||
// Remember observer at onload time.
|
||||
if ( cmd == 'onload' ) {
|
||||
window.observer = window.arguments[0].QueryInterface( Components.interfaces.nsIObserver );
|
||||
}
|
||||
window.observer.observe( null, cmd, '' );
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<!-- This is non-visible content that simply adds translatable string
|
||||
into the document so that it is accessible to JS code.
|
||||
-->
|
||||
|
||||
<data id="string.close">&close;</data>
|
||||
<data id="string.progressMsg">&progressMsg;</data>
|
||||
<data id="string.completeMsg">&completeMsg;</data>
|
||||
<data id="string.percentMsg">&percentMsg;</data>
|
||||
<data id="string.shortTimeFormat">&shortTimeFormat;</data>
|
||||
<data id="string.longTimeFormat">&longTimeFormat;</data>
|
||||
<data id="string.unknownTime">&unknownTime;</data>
|
||||
<data id="string.pausedMsg">&pausedMsg;</data>
|
||||
<data id="string.filesFolder">&filesFolder;</data>
|
||||
<data id="string.savingTitle">&savingTitle;</data>
|
||||
<data id="string.savingAlertTitle">&savingAlertTitle;</data>
|
||||
<data id="string.openingTitle">&openingTitle;</data>
|
||||
<data id="string.openingAlertTitle">&openingAlertTitle;</data>
|
||||
<data id="string.openingSource">&openingSource;</data>
|
||||
<data id="string.openingTarget">&openingTarget;</data>
|
||||
|
||||
<grid flex="1">
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
</columns>
|
||||
|
||||
<rows>
|
||||
<row>
|
||||
<hbox align="center" pack="end">
|
||||
<label id="sourceLabel" value="&savingSource;"/>
|
||||
</hbox>
|
||||
<textbox id="source" class="scrollfield" readonly="" flex="1"/>
|
||||
</row>
|
||||
<separator class="thin"/>
|
||||
<row id="targetRow">
|
||||
<hbox align="center" pack="end">
|
||||
<label id="targetLabel" value="&savingTarget;"/>
|
||||
</hbox>
|
||||
<textbox id="target" class="scrollfield" readonly="" flex="1"/>
|
||||
</row>
|
||||
<separator id="targetRowSeparator" class="thin"/>
|
||||
<row>
|
||||
<hbox align="center" pack="end">
|
||||
<label value="&status;"/>
|
||||
</hbox>
|
||||
<label id="status" value=" " flex="1"/>
|
||||
</row>
|
||||
<separator class="thin"/>
|
||||
<row>
|
||||
<hbox align="center" pack="end">
|
||||
<label value="&timeLeft;"/>
|
||||
</hbox>
|
||||
<label id="timeLeft" value=" "/>
|
||||
</row>
|
||||
<separator class="thin"/>
|
||||
<row>
|
||||
<hbox align="center" pack="end">
|
||||
<label value="&timeElapsed;"/>
|
||||
</hbox>
|
||||
<label id="timeElapsed" value=" "/>
|
||||
</row>
|
||||
<separator class="thin"/>
|
||||
<row>
|
||||
<hbox align="center" pack="end">
|
||||
<label value="&progress;"/>
|
||||
</hbox>
|
||||
<progressmeter id="progress" mode="normal" value="0"/>
|
||||
<hbox align="center" pack="end">
|
||||
<label id="progressText" value=" "/>
|
||||
</hbox>
|
||||
</row>
|
||||
<separator/>
|
||||
</rows>
|
||||
</grid>
|
||||
<hbox align="center">
|
||||
<checkbox id="keep" label="&keep;"/>
|
||||
</hbox>
|
||||
<separator id="keepSeparator"/>
|
||||
<hbox>
|
||||
<button id="cancel" label="&cancel;" oncommand="notifyObserver( 'oncancel' )"/>
|
||||
<deck id="pauseResume">
|
||||
<spacer/>
|
||||
<button id="pause" label="&pause;" oncommand="window.notifyObserver( 'onpause' )"/>
|
||||
<button id="resume" label="&resume;" oncommand="window.notifyObserver( 'onpause' )"/>
|
||||
</deck>
|
||||
<spacer flex="1"/>
|
||||
<button id="launch" label="&launch;" disabled="true" oncommand="window.notifyObserver( 'onlaunch' )"/>
|
||||
<button id="reveal" label="&reveal;" disabled="true" oncommand="window.notifyObserver( 'onreveal' )"/>
|
||||
</hbox>
|
||||
</window>
|
Загрузка…
Ссылка в новой задаче