/** Start tracking line movement in VWindow starting at ptFrom. On
	success, this function will return VTRUE and set the point in ptResult
	to the ending position. The function returns VFALSE on failure. If
	bEraseLineWhenDone is VTRUE, the line drawn between the original and
	ending point will be erased.*/
	VBOOL			Track(	VWindow const&	window,
							VPoint const&	ptFrom,
							VPoint&			ptResult,
							VBOOL			bEraseLineWhenDone = VTRUE)
	{
		/* Initialize out parameter.*/
		ptResult = ptFrom;

		/* Get a client DC to use.*/
		VClientDC dc(window);

		if ( !dc.GetHandle() )
			return VFALSE;

		/* Save pointer to DC.*/
		m_pClientDC = &dc;

		/* Call base class to start tracking.*/
		VBOOL bResult =
			VCapturedMouseTracker::Track(window, ptFrom, ptResult);

		/* Draw one last time to erase line? Only if the user moved
		the tracker.*/
		if ( ptFrom != ptResult )
		{
			if ( !bResult || bEraseLineWhenDone )
				Draw(ptFrom, ptResult);
		}

		/* Rest members.*/
		ResetMembers();

		return bResult;
	}
	/** Construct with existing VRect object. Can also be initialized with
	class options (which default to 0), the rectangle fill color (defaults
	to gray, the pen color to use on the left and top edges of the rectangle
	(defaults to dark gray), the pen color to use on the right and bottom
	edges of the rectangle (defaults to white), and the border width
	(defaults to 1 pixel).*/
	V3DRect(	VRect const&	r,
				VUINT			nOptions = 0,
				COLORREF		crFill = RGB(192,192,192),
				COLORREF		crLeftTop = RGB(127,127,127),
				COLORREF		crRightBottom = RGB(255,255,255),
				VUINT			nBorderWidth = 1)
		: VRect(r)
	{
		ResetMembers(	nOptions,
						crFill,
						crLeftTop,
						crRightBottom,
						nBorderWidth);
	}
	/** Construct with existing X, Y, and CX, CY coordinates, or default of
	0, 0, 0, 0. Can also be initialized with class options (which default
	to 0), the rectangle fill color (defaults to gray, the pen color to use
	on the left and top edges of the rectangle (defaults to dark gray), the
	pen color to use on the right and bottom edges of the rectangle
	(defaults to white), and the border width (defaults to 1 pixel).*/
	V3DRect(	VLONG		nx = 0,
				VLONG		ny = 0,
				VLONG		ncx = 0,
				VLONG		ncy = 0,
				VUINT		nOptions = 0,
				COLORREF	crFill = RGB(192,192,192),
				COLORREF	crLeftTop = RGB(127,127,127),
				COLORREF	crRightBottom = RGB(255,255,255),
				VUINT		nBorderWidth = 1)
		: VRect(nx, ny, ncx, ncy)
	{
		ResetMembers(	nOptions,
						crFill,
						crLeftTop,
						crRightBottom,
						nBorderWidth);
	}
	/** Default constructor initializes VCapturedMouseTracker base class
	and local members.*/
	VLineTracker(	VUINT	nOptions = OPTION_DEFAULT,
					VUSHORT	nKeyboardIncrement = 5)
		: VCapturedMouseTracker(nOptions, nKeyboardIncrement)
		{ ResetMembers(); }
NS_IMETHODIMP
nsBrowserStatusFilter::OnStateChange(nsIWebProgress *aWebProgress,
                                     nsIRequest *aRequest,
                                     PRUint32 aStateFlags,
                                     nsresult aStatus)
{
    if (!mListener)
        return NS_OK;

    if (aStateFlags & STATE_START) {
        if (aStateFlags & STATE_IS_NETWORK) {
            ResetMembers();
        }
        if (aStateFlags & STATE_IS_REQUEST) {
            ++mTotalRequests;

            // if the total requests exceeds 1, then we'll base our progress
            // notifications on the percentage of completed requests.
            // otherwise, progress for the single request will be reported.
            mUseRealProgressFlag = (mTotalRequests == 1);
        }
    }
    else if (aStateFlags & STATE_STOP) {
        if (aStateFlags & STATE_IS_REQUEST) {
            ++mFinishedRequests;
            // Note: Do not return from here. This is necessary so that the
            // STATE_STOP can still be relayed to the listener if needed
            // (bug 209330)
            if (!mUseRealProgressFlag && mTotalRequests)
                OnProgressChange(nsnull, nsnull, 0, 0,
                                 mFinishedRequests, mTotalRequests);
        }
    }
    else if (aStateFlags & STATE_TRANSFERRING) {
        if (aStateFlags & STATE_IS_REQUEST) {
            if (!mUseRealProgressFlag && mTotalRequests)
                return OnProgressChange(nsnull, nsnull, 0, 0,
                                        mFinishedRequests, mTotalRequests);
        }

        // no need to forward this state change
        return NS_OK;
    } else {
        // no need to forward this state change
        return NS_OK;
    }

    // If we're here, we have either STATE_START or STATE_STOP.  The
    // listener only cares about these in certain conditions.
    PRBool isLoadingDocument = PR_FALSE;
    if ((aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK ||
         (aStateFlags & nsIWebProgressListener::STATE_IS_REQUEST &&
          mFinishedRequests == mTotalRequests &&
          (aWebProgress->GetIsLoadingDocument(&isLoadingDocument),
           !isLoadingDocument)))) {
        if (mTimer && (aStateFlags & nsIWebProgressListener::STATE_STOP)) {
            mTimer->Cancel();
            ProcessTimeout();
        }

        return mListener->OnStateChange(aWebProgress, aRequest, aStateFlags,
                                        aStatus);
    }

    return NS_OK;
}