/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2006 STZ-IDA, Germany, http://www.stz-ida.de
License:
LGPL: http://www.gnu.org/licenses/lgpl.html
EPL: http://www.eclipse.org/org/documents/epl-v10.php
See the LICENSE file in the project's top-level directory for details.
Authors:
* Til Schneider (til132)
************************************************************************ */
/* ************************************************************************
#module(core)
#module(log)
************************************************************************ */
/**
* An appender that writes all messages to a log window.
*
* This class does not depend on qooxdoo widgets, so it also works when there
* are problems with widgets or when the widgets are not yet initialized.
*
* @param name {String ? "qx_log"} the name of the log window.
*/
qx.OO.defineClass("qx.log.WindowAppender", qx.log.Appender,
function(name) {
qx.log.Appender.call(this);
this._id = qx.log.WindowAppender.register(this);
this._name = (name == null) ? "qx_log" : name;
this._errorsPreventingAutoCloseCount = 0;
this._logWindowOpened = false;
});
/**
* The maximum number of messages to show. If null the number of messages is not
* limited.
*/
qx.OO.addProperty({ name:"maxMessages", type:"number", defaultValue:500 });
/** Whether the window should appear under the main window. */
qx.OO.addProperty({ name:"popUnder", type:"boolean", defaultValue:false, allowNull:false });
/** Whether the window should automatically be closed when its creating page is unloaded and
* errors have been logged. Note that errors that have been logged before this property has been
* turned off will be ignored. Warning: Turning this off may create a memory hole because the disposer
* of this class will auto-close the window, i. e. it may stay open after dispose(), still holding
* memory. However, for diagnostics it is often more important to get information about errors
* than to save memory.
*/
qx.OO.addProperty({ name:"autoCloseWithErrors", type:"boolean", defaultValue:true, allowNull:false });
/**
* Creates and opens the log window if it doesn't alread exist.
*/
qx.Proto.openWindow = function() {
if (this._logWindowOpened) {
// The window is already open -> Nothing to do
return;
}
// Open the logger window
var winWidth = 600;
var winHeight = 350;
var winLeft = window.screen.width - winWidth;
var winTop = window.screen.height - winHeight;
var params = "toolbar=no,scrollbars=yes,resizable=yes,"
+ "width=" + winWidth + ",height=" + winHeight
+ ",left=" + winLeft + ",top=" + winTop;
// NOTE: In window.open the browser will process the event queue.
// Which means that other log events may arrive during this time.
// The log window is then in an inconsistent state, because the
// this._logElem is not created yet. These events will be added to the
// this._logEventQueue and logged after this._logElem is created.
this._logWindow = window.open("", this._name, params);
if (!this._logWindow || this._logWindow.closed)
{
if (!this._popupBlockerWarning) {
alert("Couldn't open debug window. Please disable your popup blocker!");
}
this._popupBlockerWarning = true;
return;
}
// Seems to be OK now.
this._popupBlockerWarning = false;
// Store that window is open
this._logWindowOpened = true;
if (this.getPopUnder()) {
this._logWindow.blur();
window.focus();
}
var logDocument = this._logWindow.document;
// NOTE: We have to use a static onunload handler, because an onunload
// that is set later using DOM is ignored completely.
// (at least in Firefox, but maybe in IE, too)
logDocument.open();
logDocument.write("
" + this._name + ""
+ ''
+ '');
logDocument.close();
this._logElem = logDocument.getElementById("log");
// Log the events from the queue
if (this._logEventQueue != null) {
for (var i = 0; i < this._logEventQueue.length; i++) {
this.appendLogEvent(this._logEventQueue[i]);
}
this._logEventQueue = null;
}
};
/**
* Closes the log window.
*/
qx.Proto.closeWindow = function() {
if (this._logWindow != null) {
this._logWindow.close();
this._logWindow = null;
this._logElem = null;
this._logWindowOpened = false;
}
};
/**
* Called when the window should be automatically closed (because the page that opened
* is is unloaded). Will only close the window if the autoClose***-Properties allow it
*/
qx.Proto._autoCloseWindow = function() {
if (this.getAutoCloseWithErrors() || this._errorsPreventingAutoCloseCount == 0){
this.closeWindow();
} else {
//Show message why auto-close has failed
this._showMessageInLog("Log window message: Note: " + this._errorsPreventingAutoCloseCount
+ " errors have been recorded, keeping log window open.");
}
};
/**
* Appends a line to the log showing the given text
* @param msg {String} message to show, may be HTML
*/
qx.Proto._showMessageInLog = function(msg) {
//Create dummy log event and use appendLogEvent()
//Reason is that it is rather complicated to get something into the log
//window when it is not already open -> reuse the existing code
//which does event queuing in such a case
var dummyEvent = {message: msg, isDummyEventForMessage : true};
this.appendLogEvent(dummyEvent);
};
// overridden
qx.Proto.appendLogEvent = function(evt) {
if (!this._logWindowOpened) {
this._logEventQueue = [];
this._logEventQueue.push(evt);
this.openWindow();
// Popup-Blocker was active!
if (!this._logWindowOpened) {
return;
}
} else if (this._logElem == null) {
// The window is currenlty opening, but not yet finished
// -> Put the event in the queue
this._logEventQueue.push(evt);
} else {
var divElem = this._logWindow.document.createElement("div");
if (evt.level >= qx.log.Logger.LEVEL_ERROR) {
divElem.style.backgroundColor = "#FFEEEE";
if (!this.getAutoCloseWithErrors()){
this._errorsPreventingAutoCloseCount += 1;
}
} else if (evt.level == qx.log.Logger.LEVEL_DEBUG) {
divElem.style.color = "gray";
}
if (evt.isDummyEventForMessage){
divElem.innerHTML = evt.message;
} else {
divElem.innerHTML = qx.html.String.fromText(this.formatLogEvent(evt));
}
this._logElem.appendChild(divElem);
while (this._logElem.childNodes.length > this.getMaxMessages()) {
this._logElem.removeChild(this._logElem.firstChild);
if (this._removedMessageCount == null) {
this._removedMessageCount = 1;
} else {
this._removedMessageCount++;
}
}
if (this._removedMessageCount != null) {
this._logElem.firstChild.innerHTML = "(" + this._removedMessageCount
+ " messages removed)";
}
// Scroll to bottom
this._logWindow.scrollTo(0, this._logElem.offsetHeight);
}
}
qx.Proto._modifyAutoCloseWithErrors = function(propValue, propOldValue, propData){
if (!propValue && propOldValue){
this._errorsPreventingAutoCloseCount = 0;
//Show message in log so user can see which errors have been counted
this._showMessageInLog("Log window message: Starting error recording, any errors below this line will prevent the log window from closing");
} else if (propValue && !propOldValue){
//Show message in log so user can see which errors have been counted
this._showMessageInLog("Log window message: Stopping error recording, discarding " + this._errorsPreventingAutoCloseCount + " errors.");
}
return true;
}
// overridden
qx.Proto.dispose = function() {
if (this.getDisposed()) {
return true;
}
this._autoCloseWindow();
return qx.log.Appender.prototype.dispose.call(this);
}
qx.Class._nextId = 1;
qx.Class._registeredAppenders = {};
/**
* Registers a WindowAppender. This is used by the WindowAppender internally.
* You don't have to call this.
*
* @param appender {WindowAppender} the WindowAppender to register.
* @return {Integer} the ID.
*/
qx.Class.register = function(appender) {
var WindowAppender = qx.log.WindowAppender;
var id = WindowAppender._nextId++;
WindowAppender._registeredAppenders[id] = appender;
return id;
}
/**
* Returns a prviously registered WindowAppender.
*
* @param id {Integer} the ID of the wanted WindowAppender.
* @return {WindowAppender} the WindowAppender or null if no
* WindowAppender with this ID is registered.
*/
qx.Class.getAppender = function(id) {
return qx.log.WindowAppender._registeredAppenders[id];
}