Bug 472090, change scale to use a listener instead of mutation events, r=smaug,sr=neil

This commit is contained in:
Neil Deakin 2009-01-14 13:21:58 -05:00
Родитель 043ac8e978
Коммит dd6cf51b95
5 изменённых файлов: 130 добавлений и 80 удалений

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

@ -63,6 +63,7 @@ XPIDLSRCS= nsIBoxObject.idl \
nsIEditorBoxObject.idl \
nsIContainerBoxObject.idl \
nsIListBoxObject.idl \
nsISliderListener.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

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

@ -12,15 +12,13 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code.
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* The Initial Developer of the Original Code is Neil Deakin
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Original Author: David W. Hyatt (hyatt@netscape.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -36,29 +34,19 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsIScrollbarListener_h___
#define nsIScrollbarListener_h___
#include "nsISupports.idl"
// {A0ADBD81-2911-11d3-97FA-00400553EEF0}
#define NS_ISCROLLBARLISTENER_IID \
{ 0xa0adbd81, 0x2911, 0x11d3, { 0x97, 0xfa, 0x0, 0x40, 0x5, 0x53, 0xee, 0xf0 } }
static NS_DEFINE_IID(kIScrollbarListenerIID, NS_ISCROLLBARLISTENER_IID);
class nsPresContext;
class nsIScrollbarListener : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCROLLBARLISTENER_IID)
NS_IMETHOD PositionChanged(nsPresContext* aPresContext, PRInt32 aOldIndex, PRInt32& aNewIndex) = 0;
NS_IMETHOD PagedUpDown() = 0;
/**
* Used for <scale> to listen to slider changes to avoid mutation listeners
*/
[scriptable, uuid(CD380CB5-E9F6-4B7D-A19F-B1FD7B31C532)]
interface nsISliderListener : nsISupports
{
/**
* Called when the current, minimum or maximum value has been changed to
* newValue. The which parameter will either be 'curpos', 'minpos' or 'maxpos'.
* If userChanged is true, then the user changed ths slider, otherwise it
* was changed via some other means.
*/
void valueChanged(in AString which, in long newValue, in boolean userChanged);
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScrollbarListener, NS_ISCROLLBARLISTENER_IID)
#endif

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

@ -59,7 +59,7 @@
#include "nsIDOMMouseEvent.h"
#include "nsIDocument.h"
#include "nsScrollbarButtonFrame.h"
#include "nsIScrollbarListener.h"
#include "nsISliderListener.h"
#include "nsIScrollbarMediator.h"
#include "nsIScrollbarFrame.h"
#include "nsILookAndFeel.h"
@ -115,8 +115,8 @@ NS_NewSliderFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
nsSliderFrame::nsSliderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext):
nsBoxFrame(aPresShell, aContext),
mCurPos(0),
mScrollbarListener(nsnull),
mChange(0)
mChange(0),
mUserChanged(PR_FALSE)
{
}
@ -228,6 +228,30 @@ nsSliderFrame::GetIntegerAttribute(nsIContent* content, nsIAtom* atom, PRInt32 d
return defaultValue;
}
class nsValueChangedRunnable : public nsRunnable
{
public:
nsValueChangedRunnable(nsISliderListener* aListener,
nsIAtom* aWhich,
PRInt32 aValue,
PRBool aUserChanged)
: mListener(aListener), mWhich(aWhich),
mValue(aValue), mUserChanged(aUserChanged)
{}
NS_IMETHODIMP Run()
{
nsAutoString which;
mWhich->ToString(atom);
return mListener->ValueChanged(which, mValue, mUserChanged);
}
nsCOMPtr<nsISliderListener> mListener;
nsCOMPtr<nsIAtom> mWhich;
PRInt32 mValue;
PRBool mUserChanged;
};
NS_IMETHODIMP
nsSliderFrame::AttributeChanged(PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
@ -251,6 +275,18 @@ nsSliderFrame::AttributeChanged(PRInt32 aNameSpaceID,
PRInt32 current = GetCurrentPosition(scrollbar);
PRInt32 min = GetMinPosition(scrollbar);
PRInt32 max = GetMaxPosition(scrollbar);
// inform the parent <scale> that the minimum or maximum changed
nsIFrame* parent = GetParent();
if (parent) {
nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
if (sliderListener) {
nsContentUtils::AddScriptRunner(
new nsValueChangedRunnable(sliderListener, aAttribute,
aAttribute == nsGkAtoms::minpos ? min : max, PR_FALSE));
}
}
if (current < min || current > max)
{
if (current < min || max < min)
@ -610,9 +646,6 @@ nsSliderFrame::PageUpDown(nscoord change)
nsGkAtoms::reverse, eCaseMatters))
change = -change;
if (mScrollbarListener)
mScrollbarListener->PagedUpDown(); // Let the listener decide our increment.
nscoord pageIncrement = GetPageIncrement(scrollbar);
PRInt32 curpos = GetCurrentPosition(scrollbar);
PRInt32 minpos = GetMinPosition(scrollbar);
@ -685,11 +718,18 @@ nsSliderFrame::CurrentPositionChanged(nsPresContext* aPresContext,
// Redraw the scrollbar
InvalidateWithFlags(clientRect, aImmediateRedraw ? INVALIDATE_IMMEDIATE : 0);
if (mScrollbarListener)
mScrollbarListener->PositionChanged(aPresContext, mCurPos, curpospx);
mCurPos = curpospx;
// inform the parent <scale> if it exists that the value changed
nsIFrame* parent = GetParent();
if (parent) {
nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
if (sliderListener) {
nsContentUtils::AddScriptRunner(
new nsValueChangedRunnable(sliderListener, nsGkAtoms::curpos, mCurPos, mUserChanged));
}
}
return NS_OK;
}
@ -766,6 +806,9 @@ nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, PRInt32 aNewPo
{
nsCOMPtr<nsIContent> scrollbar = aScrollbar;
nsIBox* scrollbarBox = GetScrollbar();
mUserChanged = PR_TRUE;
nsIScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox);
if (scrollbarFrame) {
// See if we have a mediator.
@ -784,11 +827,13 @@ nsSliderFrame::SetCurrentPositionInternal(nsIContent* aScrollbar, PRInt32 aNewPo
CurrentPositionChanged(frame->PresContext(), aImmediateRedraw);
}
}
mUserChanged = PR_FALSE;
return;
}
}
UpdateAttribute(scrollbar, aNewPos, PR_TRUE, aIsSmooth);
mUserChanged = PR_FALSE;
#ifdef DEBUG_SLIDER
printf("Current Pos=%d\n",aNewPos);
@ -1091,13 +1136,6 @@ nsSliderFrame::EnsureOrient()
}
void
nsSliderFrame::SetScrollbarListener(nsIScrollbarListener* aListener)
{
// Don't addref/release this, since it's actually a frame.
mScrollbarListener = aListener;
}
void nsSliderFrame::Notify(void)
{
PRBool stop = PR_FALSE;

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

@ -47,7 +47,6 @@
#include "nsIDOMMouseListener.h"
class nsString;
class nsIScrollbarListener;
class nsISupportsArray;
class nsITimer;
class nsSliderFrame;
@ -186,8 +185,6 @@ public:
static PRInt32 GetIntegerAttribute(nsIContent* content, nsIAtom* atom, PRInt32 defaultValue);
void EnsureOrient();
void SetScrollbarListener(nsIScrollbarListener* aListener);
virtual nsIView* GetMouseCapturer() const { return GetView(); }
NS_IMETHOD HandlePress(nsPresContext* aPresContext,
@ -242,12 +239,15 @@ private:
PRInt32 mCurPos;
nsIScrollbarListener* mScrollbarListener;
nscoord mChange;
nsPoint mDestinationPoint;
nsRefPtr<nsSliderMediator> mMediator;
// true if an attribute change has been caused by the user manipulating the
// slider. This allows notifications to tell how a slider's current position
// was changed.
PRBool mUserChanged;
static PRBool gMiddlePref;
static PRInt32 gSnapMultiplier;
}; // class nsSliderFrame

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

@ -39,7 +39,7 @@
</xul:slider>
</content>
<implementation implements="nsIAccessibleProvider">
<implementation implements="nsIAccessibleProvider, nsISliderListener">
<property name="accessibleType" readonly="true">
<getter>
return Components.interfaces.nsIAccessibleProvider.XULScale;
@ -57,6 +57,7 @@
<property name="pageIncrement" onget="return this._getIntegerAttribute('pageincrement', 10);"
onset="return this._setIntegerAttribute('pageincrement', val);"/>
<field name="_userChanged">false</field>
<field name="_sliderElement"/>
<property name="_slider" readonly="true">
<getter>
@ -148,55 +149,77 @@
</body>
</method>
<method name="valueChanged">
<parameter name="which"/>
<parameter name="newValue"/>
<parameter name="userChanged"/>
<body>
<![CDATA[
switch (which) {
case "curpos":
this.setAttribute("value", newValue);
// in the future, only fire the change event when userChanged
// or _userChanged is true
var changeEvent = document.createEvent("Events");
changeEvent.initEvent("change", true, true);
this.dispatchEvent(changeEvent);
break;
case "minpos":
this.setAttribute("min", newValue);
break;
case "maxpos":
this.setAttribute("max", newValue);
break;
}
]]>
</body>
</method>
</implementation>
<handlers>
<handler event="DOMAttrModified">
if (event.originalTarget != this._slider)
return;
switch (event.attrName) {
case "curpos":
this.setAttribute("value", event.newValue);
var changeEvent = document.createEvent("Events");
changeEvent.initEvent("change", true, true);
this.dispatchEvent(changeEvent);
break;
case "minpos":
this.setAttribute("min", event.newValue);
break;
case "maxpos":
this.setAttribute("max", event.newValue);
break;
}
</handler>
<handler event="keypress" keycode="VK_UP" preventdefault="true">
return (this.dir == "reverse") ? this.increase() : this.decrease();
this._userChanged = true;
(this.dir == "reverse") ? this.increase() : this.decrease();
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_LEFT" preventdefault="true">
return (this.dir == "reverse") ? this.increase() : this.decrease();
this._userChanged = true;
(this.dir == "reverse") ? this.increase() : this.decrease();
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_DOWN" preventdefault="true">
return (this.dir == "reverse") ? this.decrease() : this.increase();
this._userChanged = true;
(this.dir == "reverse") ? this.decrease() : this.increase();
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_RIGHT" preventdefault="true">
return (this.dir == "reverse") ? this.decrease() : this.increase();
this._userChanged = true;
(this.dir == "reverse") ? this.decrease() : this.increase();
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_PAGE_UP" preventdefault="true">
return (this.dir == "reverse") ? this.increasePage() : this.decreasePage();
this._userChanged = true;
(this.dir == "reverse") ? this.increasePage() : this.decreasePage();
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_PAGE_DOWN" preventdefault="true">
return (this.dir == "reverse") ? this.decreasePage() : this.increasePage();
this._userChanged = true;
(this.dir == "reverse") ? this.decreasePage() : this.increasePage();
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_HOME" preventdefault="true">
this._userChanged = true;
this.value = (this.dir == "reverse") ? this.max : this.min;
this._userChanged = false;
</handler>
<handler event="keypress" keycode="VK_END" preventdefault="true">
this._userChanged = true;
this.value = (this.dir == "reverse") ? this.min : this.max;
this._userChanged = false;
</handler>
</handlers>