Big command tidyup. Make the distinction between editor and composer command clearer, and remove vestiges of the old singleton composer command manager. Also tidy up command node state attribute code.

This commit is contained in:
sfraser%netscape.com 2000-05-05 23:20:21 +00:00
parent f9a3a34695
commit 1ebf5439a6
12 changed files with 308 additions and 358 deletions

View File

@ -40,63 +40,57 @@
#include "nsComposerCommands.h"
// utility methods
//---------------------------------------------------------------------------
static PRBool XULNodeExists(nsIEditorShell* aEditorShell, const char* nodeID)
//---------------------------------------------------------------------------
nsBaseComposerCommand::nsBaseComposerCommand()
{
nsCOMPtr<nsIDOMWindow> webshellWindow;
aEditorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
nsCOMPtr<nsIDOMDocument> chromeDoc;
webshellWindow->GetDocument(getter_AddRefs(chromeDoc));
if (!chromeDoc) return PR_FALSE;
nsCOMPtr<nsIDOMElement> elem;
nsresult rv = chromeDoc->GetElementById( NS_ConvertASCIItoUCS2(nodeID), getter_AddRefs(elem) );
return NS_SUCCEEDED(rv) && (elem.get() != nsnull);
NS_INIT_REFCNT();
}
//---------------------------------------------------------------------------
static nsresult SetNodeAttribute(nsIEditorShell* aEditorShell, const PRUnichar* nodeID,
const PRUnichar* attributeName, const nsString& newValue)
//---------------------------------------------------------------------------
{
nsCOMPtr<nsIDOMWindow> webshellWindow;
aEditorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
NS_IMPL_ISUPPORTS(nsBaseComposerCommand, NS_GET_IID(nsIControllerCommand));
//--------------------------------------------------------------------------------------------------------------------
nsresult
nsBaseComposerCommand::GetInterfaceNode(const PRUnichar* nodeID, nsIEditorShell* editorShell, nsIDOMElement **outNode)
//--------------------------------------------------------------------------------------------------------------------
{
*outNode = nsnull;
NS_ASSERTION(editorShell, "Should have an editorShell here");
nsCOMPtr<nsIDOMWindow> webshellWindow;
editorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
if (!webshellWindow) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMDocument> chromeDoc;
webshellWindow->GetDocument(getter_AddRefs(chromeDoc));
if (!chromeDoc) return PR_FALSE;
nsCOMPtr<nsIDOMElement> elem;
nsresult rv = chromeDoc->GetElementById( nsAutoString(nodeID), getter_AddRefs(elem) );
if (NS_FAILED(rv) || !elem) return rv;
if (!chromeDoc) return NS_ERROR_FAILURE;
return elem->SetAttribute(nsAutoString(attributeName), newValue);
nsCOMPtr<nsIDOMElement> elem;
return chromeDoc->GetElementById(nsAutoString(nodeID), outNode);
}
//--------------------------------------------------------------------------------------------------------------------
nsresult
nsBaseComposerCommand::GetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, nsString& outNodeState)
//--------------------------------------------------------------------------------------------------------------------
{
nsCOMPtr<nsIDOMElement> uiNode;
GetInterfaceNode(aCommand, editorShell, getter_AddRefs(uiNode));
if (!uiNode) return NS_ERROR_FAILURE;
return uiNode->GetAttribute(NS_ConvertASCIItoUCS2("state").GetUnicode(), outNodeState);
}
//---------------------------------------------------------------------------
static nsresult GetNodeAttribute(nsIEditorShell* aEditorShell, const PRUnichar* nodeID,
const PRUnichar* attributeName, nsString& outValue)
//---------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------
nsresult
nsBaseComposerCommand::SetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, const nsString& inNodeState)
//--------------------------------------------------------------------------------------------------------------------
{
nsCOMPtr<nsIDOMWindow> webshellWindow;
aEditorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
nsCOMPtr<nsIDOMDocument> chromeDoc;
webshellWindow->GetDocument(getter_AddRefs(chromeDoc));
if (!chromeDoc) return PR_FALSE;
nsCOMPtr<nsIDOMElement> elem;
nsresult rv = chromeDoc->GetElementById( nsAutoString(nodeID), getter_AddRefs(elem) );
if (NS_FAILED(rv) || !elem) return rv;
nsCOMPtr<nsIDOMElement> uiNode;
GetInterfaceNode(aCommand, editorShell, getter_AddRefs(uiNode));
if (!uiNode) return NS_ERROR_FAILURE;
return elem->GetAttribute(nsAutoString(attributeName), outValue);
return uiNode->SetAttribute(NS_ConvertASCIItoUCS2("state").GetUnicode(), inNodeState);
}
@ -106,7 +100,7 @@ static nsresult GetNodeAttribute(nsIEditorShell* aEditorShell, const PRUnichar*
nsBaseStateUpdatingCommand::nsBaseStateUpdatingCommand(const char* aTagName)
: nsBaseCommand()
: nsBaseComposerCommand()
, mTagName(aTagName)
{
}
@ -115,7 +109,7 @@ nsBaseStateUpdatingCommand::~nsBaseStateUpdatingCommand()
{
}
NS_IMPL_ISUPPORTS_INHERITED1(nsBaseStateUpdatingCommand, nsBaseCommand, nsIStateUpdatingControllerCommand);
NS_IMPL_ISUPPORTS_INHERITED1(nsBaseStateUpdatingCommand, nsBaseComposerCommand, nsIStateUpdatingControllerCommand);
NS_IMETHODIMP
nsBaseStateUpdatingCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
@ -158,27 +152,19 @@ nsBaseStateUpdatingCommand::UpdateCommandState(const PRUnichar *aCommandName, ns
rv = GetCurrentState(editorShell, mTagName, stateIsSet);
if (NS_FAILED(rv)) return rv;
PRBool oldState = !stateIsSet;
// what was it last set to?
void* stateData;
if (NS_SUCCEEDED(editorShell->GetCommandStateData(aCommandName, &stateData)))
oldState = (PRBool)stateData;
if (stateIsSet != oldState)
if (!mGotState || (stateIsSet != mState))
{
// poke the UI
rv = SetNodeAttribute(editorShell, aCommandName, NS_ConvertASCIItoUCS2("state").GetUnicode(),
NS_ConvertASCIItoUCS2(stateIsSet ? "true" : "false"));
editorShell->SetCommandStateData(aCommandName, (void*)stateIsSet);
SetCommandNodeState(aCommandName, editorShell, NS_ConvertASCIItoUCS2(stateIsSet ? "true" : "false"));
mGotState = PR_TRUE;
mState = stateIsSet;
}
}
return rv;
}
#ifdef XP_MAC
#pragma mark -
#endif
@ -608,10 +594,9 @@ nsParagraphStateCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refC
{
// we have to grab the state attribute on our command node to find out
// what format to set the paragraph to
nsAutoString stateAttribute;
rv = GetNodeAttribute(editorShell, aCommand, NS_ConvertASCIItoUCS2("state").GetUnicode(), stateAttribute);
nsAutoString stateAttribute;
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
if (NS_FAILED(rv)) return rv;
rv = editorShell->SetParagraphFormat(stateAttribute.GetUnicode());
}
@ -652,9 +637,8 @@ nsAlignCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
// we have to grab the state attribute on our command node to find out
// what format to set the paragraph to
nsAutoString stateAttribute;
rv = GetNodeAttribute(editorShell, aCommand, NS_ConvertASCIItoUCS2("state").GetUnicode(), stateAttribute);
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
if (NS_FAILED(rv)) return rv;
rv = editorShell->Align(stateAttribute.GetUnicode());
}
@ -694,6 +678,13 @@ nsRemoveStylesCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon
if (editorShell)
{
rv = editorShell->RemoveTextProperty(NS_ConvertASCIItoUCS2("all").GetUnicode(), NS_ConvertASCIItoUCS2("").GetUnicode());
if (NS_FAILED(rv)) return rv;
// now get all the style buttons to update
nsCOMPtr<nsIDOMWindow> contentWindow;
editorShell->GetContentWindow(getter_AddRefs(contentWindow));
if (contentWindow)
contentWindow->UpdateCommands(NS_ConvertASCIItoUCS2("style"));
}
return rv;

View File

@ -24,11 +24,50 @@
#ifndef nsComposerCommands_h_
#define nsComposerCommands_h_
#include "nsIControllerCommand.h"
#include "nsEditorCommands.h"
// This is a virtual base class for commands registered with the composer controller.
// Note that such commands are instantiated once per composer, so can store state.
// Also note that IsCommandEnabled can be called with an editorShell that may not
// have an editor yet (because the document is loading). Most commands will want
// to return false in this case.
// Don't hold on to any references to the editorShell, editor, or document from
// your command. This will cause leaks. Also, be aware that the document the
// editor is editing can change under you (if the user Reverts the file, for
// instance).
class nsBaseComposerCommand : public nsIControllerCommand
{
public:
nsBaseComposerCommand();
virtual ~nsBaseComposerCommand() {}
NS_DECL_ISUPPORTS
NS_IMETHOD IsCommandEnabled(const PRUnichar *aCommand, nsISupports* refCon, PRBool *_retval) = 0;
NS_IMETHOD DoCommand(const PRUnichar *aCommand, nsISupports* refCon) = 0;
protected:
// utility methods to get/set the "state" attribute on the command node in the XUL
nsresult GetInterfaceNode(const PRUnichar* nodeID, nsIEditorShell* editorShell, nsIDOMElement **outNode);
nsresult GetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, nsString& outNodeState);
nsresult SetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, const nsString& inNodeState);
};
#define NS_DECL_COMPOSER_COMMAND(_cmd) \
class _cmd : public nsBaseComposerCommand \
{ \
public: \
NS_DECL_NSICONTROLLERCOMMAND \
};
// virtual base class for commands that need to save and update state
class nsBaseStateUpdatingCommand : public nsBaseCommand,
class nsBaseStateUpdatingCommand : public nsBaseComposerCommand,
public nsIStateUpdatingControllerCommand
{
public:
@ -54,6 +93,8 @@ protected:
const char* mTagName;
const char* mAttributeName;
PRPackedBool mGotState; // do we know the state yet?
PRPackedBool mState; // is this style "on" ?
};
@ -92,35 +133,35 @@ protected:
// composer commands
NS_DECL_EDITOR_COMMAND(nsAlwaysEnabledCommands)
NS_DECL_COMPOSER_COMMAND(nsAlwaysEnabledCommands)
NS_DECL_EDITOR_COMMAND(nsCloseCommand)
NS_DECL_EDITOR_COMMAND(nsPrintingCommands)
NS_DECL_COMPOSER_COMMAND(nsCloseCommand)
NS_DECL_COMPOSER_COMMAND(nsPrintingCommands)
// Generic commands
// File menu
NS_DECL_EDITOR_COMMAND(nsNewCommands) // handles 'new' anything
NS_DECL_COMPOSER_COMMAND(nsNewCommands) // handles 'new' anything
NS_DECL_EDITOR_COMMAND(nsSaveCommand)
NS_DECL_EDITOR_COMMAND(nsSaveAsCommand)
NS_DECL_COMPOSER_COMMAND(nsSaveCommand)
NS_DECL_COMPOSER_COMMAND(nsSaveAsCommand)
// Edit menu
NS_DECL_EDITOR_COMMAND(nsPasteQuotationCommand)
NS_DECL_COMPOSER_COMMAND(nsPasteQuotationCommand)
// Block transformations
NS_DECL_EDITOR_COMMAND(nsIndentCommand)
NS_DECL_EDITOR_COMMAND(nsOutdentCommand)
NS_DECL_COMPOSER_COMMAND(nsIndentCommand)
NS_DECL_COMPOSER_COMMAND(nsOutdentCommand)
NS_DECL_EDITOR_COMMAND(nsParagraphStateCommand)
NS_DECL_EDITOR_COMMAND(nsAlignCommand)
NS_DECL_EDITOR_COMMAND(nsRemoveStylesCommand)
NS_DECL_EDITOR_COMMAND(nsIncreaseFontSizeCommand)
NS_DECL_EDITOR_COMMAND(nsDecreaseFontSizeCommand)
NS_DECL_COMPOSER_COMMAND(nsParagraphStateCommand)
NS_DECL_COMPOSER_COMMAND(nsAlignCommand)
NS_DECL_COMPOSER_COMMAND(nsRemoveStylesCommand)
NS_DECL_COMPOSER_COMMAND(nsIncreaseFontSizeCommand)
NS_DECL_COMPOSER_COMMAND(nsDecreaseFontSizeCommand)

View File

@ -33,12 +33,12 @@
#include "nsEditorCommands.h"
nsBaseCommand::nsBaseCommand()
nsBaseEditorCommand::nsBaseEditorCommand()
{
NS_INIT_REFCNT();
}
NS_IMPL_ISUPPORTS(nsBaseCommand, NS_GET_IID(nsIControllerCommand));
NS_IMPL_ISUPPORTS(nsBaseEditorCommand, NS_GET_IID(nsIControllerCommand));
#ifdef XP_MAC
#pragma mark -

View File

@ -28,13 +28,15 @@
#include "nsIControllerCommand.h"
#include "nsIAtom.h"
class nsBaseCommand : public nsIControllerCommand
// This is a virtual base class for commands registered with the editor controller.
// Note that such commands can be shared by more than on editor instance, so
// MUST be stateless. Any state must be stored via the refCon (an nsIEditor).
class nsBaseEditorCommand : public nsIControllerCommand
{
public:
nsBaseCommand();
virtual ~nsBaseCommand() {}
nsBaseEditorCommand();
virtual ~nsBaseEditorCommand() {}
NS_DECL_ISUPPORTS
@ -45,7 +47,7 @@ public:
#define NS_DECL_EDITOR_COMMAND(_cmd) \
class _cmd : public nsBaseCommand \
class _cmd : public nsBaseEditorCommand \
{ \
public: \
NS_DECL_NSICONTROLLERCOMMAND \

View File

@ -39,8 +39,6 @@
#include "nsEditorCommands.h"
#include "nsComposerCommands.h"
#define kMaxStackCommandNameLength 128
NS_IMPL_ADDREF(nsEditorController)
NS_IMPL_RELEASE(nsEditorController)
@ -94,22 +92,30 @@ NS_IMETHODIMP nsEditorController::GetInterface(const nsIID & aIID, void * *resul
}
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd = new _cmdClass; \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd; \
NS_NEWXPCOM(theCmd, _cmdClass); \
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \
}
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd = new _cmdClass; \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd; \
NS_NEWXPCOM(theCmd, _cmdClass); \
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd));
#define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName) \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd);
#define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName) \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd));
#define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName) \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName) \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \
}
@ -171,21 +177,6 @@ nsresult nsEditorController::RegisterEditorCommands(nsIControllerCommandManager
return NS_OK;
}
// static
nsresult nsEditorController::RegisterOneCommand(const PRUnichar* aCommandName,
nsIControllerCommandManager *inCommandManager,
nsBaseCommand* aCommand)
{
nsCOMPtr<nsIControllerCommand> editorCommand;
NS_ADDREF(aCommand);
nsresult rv = aCommand->QueryInterface(NS_GET_IID(nsIControllerCommand), getter_AddRefs(editorCommand));
NS_RELEASE(aCommand);
if (NS_FAILED(rv)) return rv;
return inCommandManager->RegisterCommand(aCommandName, editorCommand); // this is the owning ref
}
/* =======================================================================
* nsIController
* ======================================================================= */
@ -271,17 +262,22 @@ NS_IMETHODIMP nsComposerController::Init(nsISupports *aCommandRefCon)
rv = nsEditorController::Init(aCommandRefCon);
if (NS_FAILED(rv)) return rv;
// get our ref to the singleton command manager
rv = GetComposerCommandManager(getter_AddRefs(mCommandManager));
if (NS_FAILED(rv)) return rv;
mCommandManager = do_CreateInstance("component://netscape/rdf/controller-command-manager", &rv);
if (NS_FAILED(rv)) return rv;
// register the commands.
rv = nsComposerController::RegisterComposerCommands(mCommandManager);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
#define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag) \
{ \
_cmdClass* theCmd = new _cmdClass(_styleTag); \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag) \
{ \
_cmdClass* theCmd = new _cmdClass(_styleTag); \
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \
}
@ -289,8 +285,6 @@ NS_IMETHODIMP nsComposerController::Init(nsISupports *aCommandRefCon)
nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandManager *inCommandManager)
{
nsresult rv;
// These are composer-only commands
// File menu
NS_REGISTER_ONE_COMMAND(nsSaveCommand, "cmd_save");
@ -341,42 +335,3 @@ nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandMana
return NS_OK;
}
nsWeakPtr nsComposerController::sComposerCommandManager = NULL;
nsresult nsComposerController::GetComposerCommandManager(nsIControllerCommandManager* *outCommandManager)
{
NS_ENSURE_ARG_POINTER(outCommandManager);
/*
nsCOMPtr<nsIControllerCommandManager> cmdManager = do_QueryReferent(sComposerCommandManager);
if (!cmdManager)
{
nsresult rv;
cmdManager = do_CreateInstance("component://netscape/rdf/controller-command-manager", &rv);
if (NS_FAILED(rv)) return rv;
// register the commands. This just happens once per instance
rv = nsComposerController::RegisterComposerCommands(cmdManager);
if (NS_FAILED(rv)) return rv;
// save the singleton in our static weak reference
sComposerCommandManager = getter_AddRefs(NS_GetWeakReference(cmdManager, &rv));
if (NS_FAILED(rv)) return rv;
}
*/
// always make a new one
nsresult rv;
nsCOMPtr<nsIControllerCommandManager> cmdManager;
cmdManager = do_CreateInstance("component://netscape/rdf/controller-command-manager", &rv);
if (NS_FAILED(rv)) return rv;
// register the commands.
rv = nsComposerController::RegisterComposerCommands(cmdManager);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*outCommandManager = cmdManager);
return NS_OK;
}

View File

@ -38,7 +38,6 @@
class nsIEditor;
class nsIEditorShell;
class nsBaseCommand;
// the editor controller is used for both text widgets, and basic text editing
@ -74,9 +73,6 @@ protected:
/** return PR_TRUE if the editor associated with mContent is enabled */
PRBool IsEnabled();
/* register a command */
nsresult RegisterEditorCommand(nsBaseCommand* aCommand);
protected:
//if editor is null then look to mContent. this is for dual use of window and content
@ -85,11 +81,6 @@ protected:
nsCOMPtr<nsIControllerCommandManager> mCommandManager; // our reference to the command manager
protected:
static nsresult RegisterOneCommand(const PRUnichar* aCommandName, nsIControllerCommandManager *inCommandManager, nsBaseCommand* aCommand);
private:
static nsresult GetEditorCommandManager(nsIControllerCommandManager* *outCommandManager);
@ -115,13 +106,8 @@ public:
/** init the controller */
NS_IMETHOD Init(nsISupports *aCommandRefCon);
protected:
private:
static nsresult GetComposerCommandManager(nsIControllerCommandManager* *outCommandManager);
static nsresult RegisterComposerCommands(nsIControllerCommandManager* inCommandManager);
// the singleton command manager
static nsWeakPtr sComposerCommandManager; // composer-specific commands (lots of them)
};

View File

@ -40,63 +40,57 @@
#include "nsComposerCommands.h"
// utility methods
//---------------------------------------------------------------------------
static PRBool XULNodeExists(nsIEditorShell* aEditorShell, const char* nodeID)
//---------------------------------------------------------------------------
nsBaseComposerCommand::nsBaseComposerCommand()
{
nsCOMPtr<nsIDOMWindow> webshellWindow;
aEditorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
nsCOMPtr<nsIDOMDocument> chromeDoc;
webshellWindow->GetDocument(getter_AddRefs(chromeDoc));
if (!chromeDoc) return PR_FALSE;
nsCOMPtr<nsIDOMElement> elem;
nsresult rv = chromeDoc->GetElementById( NS_ConvertASCIItoUCS2(nodeID), getter_AddRefs(elem) );
return NS_SUCCEEDED(rv) && (elem.get() != nsnull);
NS_INIT_REFCNT();
}
//---------------------------------------------------------------------------
static nsresult SetNodeAttribute(nsIEditorShell* aEditorShell, const PRUnichar* nodeID,
const PRUnichar* attributeName, const nsString& newValue)
//---------------------------------------------------------------------------
{
nsCOMPtr<nsIDOMWindow> webshellWindow;
aEditorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
NS_IMPL_ISUPPORTS(nsBaseComposerCommand, NS_GET_IID(nsIControllerCommand));
//--------------------------------------------------------------------------------------------------------------------
nsresult
nsBaseComposerCommand::GetInterfaceNode(const PRUnichar* nodeID, nsIEditorShell* editorShell, nsIDOMElement **outNode)
//--------------------------------------------------------------------------------------------------------------------
{
*outNode = nsnull;
NS_ASSERTION(editorShell, "Should have an editorShell here");
nsCOMPtr<nsIDOMWindow> webshellWindow;
editorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
if (!webshellWindow) return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMDocument> chromeDoc;
webshellWindow->GetDocument(getter_AddRefs(chromeDoc));
if (!chromeDoc) return PR_FALSE;
nsCOMPtr<nsIDOMElement> elem;
nsresult rv = chromeDoc->GetElementById( nsAutoString(nodeID), getter_AddRefs(elem) );
if (NS_FAILED(rv) || !elem) return rv;
if (!chromeDoc) return NS_ERROR_FAILURE;
return elem->SetAttribute(nsAutoString(attributeName), newValue);
nsCOMPtr<nsIDOMElement> elem;
return chromeDoc->GetElementById(nsAutoString(nodeID), outNode);
}
//--------------------------------------------------------------------------------------------------------------------
nsresult
nsBaseComposerCommand::GetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, nsString& outNodeState)
//--------------------------------------------------------------------------------------------------------------------
{
nsCOMPtr<nsIDOMElement> uiNode;
GetInterfaceNode(aCommand, editorShell, getter_AddRefs(uiNode));
if (!uiNode) return NS_ERROR_FAILURE;
return uiNode->GetAttribute(NS_ConvertASCIItoUCS2("state").GetUnicode(), outNodeState);
}
//---------------------------------------------------------------------------
static nsresult GetNodeAttribute(nsIEditorShell* aEditorShell, const PRUnichar* nodeID,
const PRUnichar* attributeName, nsString& outValue)
//---------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------
nsresult
nsBaseComposerCommand::SetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, const nsString& inNodeState)
//--------------------------------------------------------------------------------------------------------------------
{
nsCOMPtr<nsIDOMWindow> webshellWindow;
aEditorShell->GetWebShellWindow(getter_AddRefs(webshellWindow));
nsCOMPtr<nsIDOMDocument> chromeDoc;
webshellWindow->GetDocument(getter_AddRefs(chromeDoc));
if (!chromeDoc) return PR_FALSE;
nsCOMPtr<nsIDOMElement> elem;
nsresult rv = chromeDoc->GetElementById( nsAutoString(nodeID), getter_AddRefs(elem) );
if (NS_FAILED(rv) || !elem) return rv;
nsCOMPtr<nsIDOMElement> uiNode;
GetInterfaceNode(aCommand, editorShell, getter_AddRefs(uiNode));
if (!uiNode) return NS_ERROR_FAILURE;
return elem->GetAttribute(nsAutoString(attributeName), outValue);
return uiNode->SetAttribute(NS_ConvertASCIItoUCS2("state").GetUnicode(), inNodeState);
}
@ -106,7 +100,7 @@ static nsresult GetNodeAttribute(nsIEditorShell* aEditorShell, const PRUnichar*
nsBaseStateUpdatingCommand::nsBaseStateUpdatingCommand(const char* aTagName)
: nsBaseCommand()
: nsBaseComposerCommand()
, mTagName(aTagName)
{
}
@ -115,7 +109,7 @@ nsBaseStateUpdatingCommand::~nsBaseStateUpdatingCommand()
{
}
NS_IMPL_ISUPPORTS_INHERITED1(nsBaseStateUpdatingCommand, nsBaseCommand, nsIStateUpdatingControllerCommand);
NS_IMPL_ISUPPORTS_INHERITED1(nsBaseStateUpdatingCommand, nsBaseComposerCommand, nsIStateUpdatingControllerCommand);
NS_IMETHODIMP
nsBaseStateUpdatingCommand::IsCommandEnabled(const PRUnichar *aCommand, nsISupports * refCon, PRBool *outCmdEnabled)
@ -158,27 +152,19 @@ nsBaseStateUpdatingCommand::UpdateCommandState(const PRUnichar *aCommandName, ns
rv = GetCurrentState(editorShell, mTagName, stateIsSet);
if (NS_FAILED(rv)) return rv;
PRBool oldState = !stateIsSet;
// what was it last set to?
void* stateData;
if (NS_SUCCEEDED(editorShell->GetCommandStateData(aCommandName, &stateData)))
oldState = (PRBool)stateData;
if (stateIsSet != oldState)
if (!mGotState || (stateIsSet != mState))
{
// poke the UI
rv = SetNodeAttribute(editorShell, aCommandName, NS_ConvertASCIItoUCS2("state").GetUnicode(),
NS_ConvertASCIItoUCS2(stateIsSet ? "true" : "false"));
editorShell->SetCommandStateData(aCommandName, (void*)stateIsSet);
SetCommandNodeState(aCommandName, editorShell, NS_ConvertASCIItoUCS2(stateIsSet ? "true" : "false"));
mGotState = PR_TRUE;
mState = stateIsSet;
}
}
return rv;
}
#ifdef XP_MAC
#pragma mark -
#endif
@ -608,10 +594,9 @@ nsParagraphStateCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refC
{
// we have to grab the state attribute on our command node to find out
// what format to set the paragraph to
nsAutoString stateAttribute;
rv = GetNodeAttribute(editorShell, aCommand, NS_ConvertASCIItoUCS2("state").GetUnicode(), stateAttribute);
nsAutoString stateAttribute;
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
if (NS_FAILED(rv)) return rv;
rv = editorShell->SetParagraphFormat(stateAttribute.GetUnicode());
}
@ -652,9 +637,8 @@ nsAlignCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon)
// we have to grab the state attribute on our command node to find out
// what format to set the paragraph to
nsAutoString stateAttribute;
rv = GetNodeAttribute(editorShell, aCommand, NS_ConvertASCIItoUCS2("state").GetUnicode(), stateAttribute);
rv = GetCommandNodeState(aCommand, editorShell, stateAttribute);
if (NS_FAILED(rv)) return rv;
rv = editorShell->Align(stateAttribute.GetUnicode());
}
@ -694,6 +678,13 @@ nsRemoveStylesCommand::DoCommand(const PRUnichar *aCommand, nsISupports * refCon
if (editorShell)
{
rv = editorShell->RemoveTextProperty(NS_ConvertASCIItoUCS2("all").GetUnicode(), NS_ConvertASCIItoUCS2("").GetUnicode());
if (NS_FAILED(rv)) return rv;
// now get all the style buttons to update
nsCOMPtr<nsIDOMWindow> contentWindow;
editorShell->GetContentWindow(getter_AddRefs(contentWindow));
if (contentWindow)
contentWindow->UpdateCommands(NS_ConvertASCIItoUCS2("style"));
}
return rv;

View File

@ -24,11 +24,50 @@
#ifndef nsComposerCommands_h_
#define nsComposerCommands_h_
#include "nsIControllerCommand.h"
#include "nsEditorCommands.h"
// This is a virtual base class for commands registered with the composer controller.
// Note that such commands are instantiated once per composer, so can store state.
// Also note that IsCommandEnabled can be called with an editorShell that may not
// have an editor yet (because the document is loading). Most commands will want
// to return false in this case.
// Don't hold on to any references to the editorShell, editor, or document from
// your command. This will cause leaks. Also, be aware that the document the
// editor is editing can change under you (if the user Reverts the file, for
// instance).
class nsBaseComposerCommand : public nsIControllerCommand
{
public:
nsBaseComposerCommand();
virtual ~nsBaseComposerCommand() {}
NS_DECL_ISUPPORTS
NS_IMETHOD IsCommandEnabled(const PRUnichar *aCommand, nsISupports* refCon, PRBool *_retval) = 0;
NS_IMETHOD DoCommand(const PRUnichar *aCommand, nsISupports* refCon) = 0;
protected:
// utility methods to get/set the "state" attribute on the command node in the XUL
nsresult GetInterfaceNode(const PRUnichar* nodeID, nsIEditorShell* editorShell, nsIDOMElement **outNode);
nsresult GetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, nsString& outNodeState);
nsresult SetCommandNodeState(const PRUnichar *aCommand, nsIEditorShell* editorShell, const nsString& inNodeState);
};
#define NS_DECL_COMPOSER_COMMAND(_cmd) \
class _cmd : public nsBaseComposerCommand \
{ \
public: \
NS_DECL_NSICONTROLLERCOMMAND \
};
// virtual base class for commands that need to save and update state
class nsBaseStateUpdatingCommand : public nsBaseCommand,
class nsBaseStateUpdatingCommand : public nsBaseComposerCommand,
public nsIStateUpdatingControllerCommand
{
public:
@ -54,6 +93,8 @@ protected:
const char* mTagName;
const char* mAttributeName;
PRPackedBool mGotState; // do we know the state yet?
PRPackedBool mState; // is this style "on" ?
};
@ -92,35 +133,35 @@ protected:
// composer commands
NS_DECL_EDITOR_COMMAND(nsAlwaysEnabledCommands)
NS_DECL_COMPOSER_COMMAND(nsAlwaysEnabledCommands)
NS_DECL_EDITOR_COMMAND(nsCloseCommand)
NS_DECL_EDITOR_COMMAND(nsPrintingCommands)
NS_DECL_COMPOSER_COMMAND(nsCloseCommand)
NS_DECL_COMPOSER_COMMAND(nsPrintingCommands)
// Generic commands
// File menu
NS_DECL_EDITOR_COMMAND(nsNewCommands) // handles 'new' anything
NS_DECL_COMPOSER_COMMAND(nsNewCommands) // handles 'new' anything
NS_DECL_EDITOR_COMMAND(nsSaveCommand)
NS_DECL_EDITOR_COMMAND(nsSaveAsCommand)
NS_DECL_COMPOSER_COMMAND(nsSaveCommand)
NS_DECL_COMPOSER_COMMAND(nsSaveAsCommand)
// Edit menu
NS_DECL_EDITOR_COMMAND(nsPasteQuotationCommand)
NS_DECL_COMPOSER_COMMAND(nsPasteQuotationCommand)
// Block transformations
NS_DECL_EDITOR_COMMAND(nsIndentCommand)
NS_DECL_EDITOR_COMMAND(nsOutdentCommand)
NS_DECL_COMPOSER_COMMAND(nsIndentCommand)
NS_DECL_COMPOSER_COMMAND(nsOutdentCommand)
NS_DECL_EDITOR_COMMAND(nsParagraphStateCommand)
NS_DECL_EDITOR_COMMAND(nsAlignCommand)
NS_DECL_EDITOR_COMMAND(nsRemoveStylesCommand)
NS_DECL_EDITOR_COMMAND(nsIncreaseFontSizeCommand)
NS_DECL_EDITOR_COMMAND(nsDecreaseFontSizeCommand)
NS_DECL_COMPOSER_COMMAND(nsParagraphStateCommand)
NS_DECL_COMPOSER_COMMAND(nsAlignCommand)
NS_DECL_COMPOSER_COMMAND(nsRemoveStylesCommand)
NS_DECL_COMPOSER_COMMAND(nsIncreaseFontSizeCommand)
NS_DECL_COMPOSER_COMMAND(nsDecreaseFontSizeCommand)

View File

@ -33,12 +33,12 @@
#include "nsEditorCommands.h"
nsBaseCommand::nsBaseCommand()
nsBaseEditorCommand::nsBaseEditorCommand()
{
NS_INIT_REFCNT();
}
NS_IMPL_ISUPPORTS(nsBaseCommand, NS_GET_IID(nsIControllerCommand));
NS_IMPL_ISUPPORTS(nsBaseEditorCommand, NS_GET_IID(nsIControllerCommand));
#ifdef XP_MAC
#pragma mark -

View File

@ -28,13 +28,15 @@
#include "nsIControllerCommand.h"
#include "nsIAtom.h"
class nsBaseCommand : public nsIControllerCommand
// This is a virtual base class for commands registered with the editor controller.
// Note that such commands can be shared by more than on editor instance, so
// MUST be stateless. Any state must be stored via the refCon (an nsIEditor).
class nsBaseEditorCommand : public nsIControllerCommand
{
public:
nsBaseCommand();
virtual ~nsBaseCommand() {}
nsBaseEditorCommand();
virtual ~nsBaseEditorCommand() {}
NS_DECL_ISUPPORTS
@ -45,7 +47,7 @@ public:
#define NS_DECL_EDITOR_COMMAND(_cmd) \
class _cmd : public nsBaseCommand \
class _cmd : public nsBaseEditorCommand \
{ \
public: \
NS_DECL_NSICONTROLLERCOMMAND \

View File

@ -39,8 +39,6 @@
#include "nsEditorCommands.h"
#include "nsComposerCommands.h"
#define kMaxStackCommandNameLength 128
NS_IMPL_ADDREF(nsEditorController)
NS_IMPL_RELEASE(nsEditorController)
@ -94,22 +92,30 @@ NS_IMETHODIMP nsEditorController::GetInterface(const nsIID & aIID, void * *resul
}
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd = new _cmdClass; \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd; \
NS_NEWXPCOM(theCmd, _cmdClass); \
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \
}
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd = new _cmdClass; \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
{ \
_cmdClass* theCmd; \
NS_NEWXPCOM(theCmd, _cmdClass); \
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd));
#define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName) \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd);
#define NS_REGISTER_NEXT_COMMAND(_cmdClass, _cmdName) \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd));
#define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName) \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_LAST_COMMAND(_cmdClass, _cmdName) \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \
}
@ -171,21 +177,6 @@ nsresult nsEditorController::RegisterEditorCommands(nsIControllerCommandManager
return NS_OK;
}
// static
nsresult nsEditorController::RegisterOneCommand(const PRUnichar* aCommandName,
nsIControllerCommandManager *inCommandManager,
nsBaseCommand* aCommand)
{
nsCOMPtr<nsIControllerCommand> editorCommand;
NS_ADDREF(aCommand);
nsresult rv = aCommand->QueryInterface(NS_GET_IID(nsIControllerCommand), getter_AddRefs(editorCommand));
NS_RELEASE(aCommand);
if (NS_FAILED(rv)) return rv;
return inCommandManager->RegisterCommand(aCommandName, editorCommand); // this is the owning ref
}
/* =======================================================================
* nsIController
* ======================================================================= */
@ -271,17 +262,22 @@ NS_IMETHODIMP nsComposerController::Init(nsISupports *aCommandRefCon)
rv = nsEditorController::Init(aCommandRefCon);
if (NS_FAILED(rv)) return rv;
// get our ref to the singleton command manager
rv = GetComposerCommandManager(getter_AddRefs(mCommandManager));
if (NS_FAILED(rv)) return rv;
mCommandManager = do_CreateInstance("component://netscape/rdf/controller-command-manager", &rv);
if (NS_FAILED(rv)) return rv;
// register the commands.
rv = nsComposerController::RegisterComposerCommands(mCommandManager);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
#define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag) \
{ \
_cmdClass* theCmd = new _cmdClass(_styleTag); \
rv = RegisterOneCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), inCommandManager, theCmd); \
#define NS_REGISTER_STYLE_COMMAND(_cmdClass, _cmdName, _styleTag) \
{ \
_cmdClass* theCmd = new _cmdClass(_styleTag); \
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
rv = inCommandManager->RegisterCommand(NS_ConvertASCIItoUCS2(_cmdName).GetUnicode(), \
NS_STATIC_CAST(nsIControllerCommand *, theCmd)); \
}
@ -289,8 +285,6 @@ NS_IMETHODIMP nsComposerController::Init(nsISupports *aCommandRefCon)
nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandManager *inCommandManager)
{
nsresult rv;
// These are composer-only commands
// File menu
NS_REGISTER_ONE_COMMAND(nsSaveCommand, "cmd_save");
@ -341,42 +335,3 @@ nsresult nsComposerController::RegisterComposerCommands(nsIControllerCommandMana
return NS_OK;
}
nsWeakPtr nsComposerController::sComposerCommandManager = NULL;
nsresult nsComposerController::GetComposerCommandManager(nsIControllerCommandManager* *outCommandManager)
{
NS_ENSURE_ARG_POINTER(outCommandManager);
/*
nsCOMPtr<nsIControllerCommandManager> cmdManager = do_QueryReferent(sComposerCommandManager);
if (!cmdManager)
{
nsresult rv;
cmdManager = do_CreateInstance("component://netscape/rdf/controller-command-manager", &rv);
if (NS_FAILED(rv)) return rv;
// register the commands. This just happens once per instance
rv = nsComposerController::RegisterComposerCommands(cmdManager);
if (NS_FAILED(rv)) return rv;
// save the singleton in our static weak reference
sComposerCommandManager = getter_AddRefs(NS_GetWeakReference(cmdManager, &rv));
if (NS_FAILED(rv)) return rv;
}
*/
// always make a new one
nsresult rv;
nsCOMPtr<nsIControllerCommandManager> cmdManager;
cmdManager = do_CreateInstance("component://netscape/rdf/controller-command-manager", &rv);
if (NS_FAILED(rv)) return rv;
// register the commands.
rv = nsComposerController::RegisterComposerCommands(cmdManager);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*outCommandManager = cmdManager);
return NS_OK;
}

View File

@ -38,7 +38,6 @@
class nsIEditor;
class nsIEditorShell;
class nsBaseCommand;
// the editor controller is used for both text widgets, and basic text editing
@ -74,9 +73,6 @@ protected:
/** return PR_TRUE if the editor associated with mContent is enabled */
PRBool IsEnabled();
/* register a command */
nsresult RegisterEditorCommand(nsBaseCommand* aCommand);
protected:
//if editor is null then look to mContent. this is for dual use of window and content
@ -85,11 +81,6 @@ protected:
nsCOMPtr<nsIControllerCommandManager> mCommandManager; // our reference to the command manager
protected:
static nsresult RegisterOneCommand(const PRUnichar* aCommandName, nsIControllerCommandManager *inCommandManager, nsBaseCommand* aCommand);
private:
static nsresult GetEditorCommandManager(nsIControllerCommandManager* *outCommandManager);
@ -115,13 +106,8 @@ public:
/** init the controller */
NS_IMETHOD Init(nsISupports *aCommandRefCon);
protected:
private:
static nsresult GetComposerCommandManager(nsIControllerCommandManager* *outCommandManager);
static nsresult RegisterComposerCommands(nsIControllerCommandManager* inCommandManager);
// the singleton command manager
static nsWeakPtr sComposerCommandManager; // composer-specific commands (lots of them)
};