extend the api for Midas functionality (bug 177700, r=akkana, sr=jst)

git-svn-id: svn://10.0.0.236/trunk@133301 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
brade%netscape.com
2002-11-07 15:38:35 +00:00
parent 79ef0005b1
commit 205b1f301d
2 changed files with 499 additions and 1 deletions

View File

@@ -136,6 +136,8 @@
#include "nsBidiUtils.h"
#endif
#include "nsIEditingSession.h"
#define DETECTOR_CONTRACTID_MAX 127
static char g_detector_contractid[DETECTOR_CONTRACTID_MAX + 1];
static PRBool gInitDetector = PR_FALSE;
@@ -292,7 +294,8 @@ nsHTMLDocument::nsHTMLDocument()
mReferrer(nsnull),
mNumForms(0),
mIsWriting(0),
mDomainWasSet(PR_FALSE)
mDomainWasSet(PR_FALSE),
mEditingIsOn(PR_FALSE)
{
mImages = nsnull;
mApplets = nsnull;
@@ -4025,3 +4028,467 @@ nsHTMLDocument::RemoveWyciwygChannel(void)
return rv;
}
/* attribute DOMString designMode; */
NS_IMETHODIMP
nsHTMLDocument::GetDesignMode(nsAString & aDesignMode)
{
if (mEditingIsOn) {
aDesignMode.Assign(NS_LITERAL_STRING("on"));
}
else {
aDesignMode.Assign(NS_LITERAL_STRING("off"));
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
{
// get editing session
if (!mScriptGlobalObject)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocShell> docshell;
mScriptGlobalObject->GetDocShell(getter_AddRefs(docshell));
if (!docshell)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell);
if (!editSession)
return NS_ERROR_FAILURE;
if (aDesignMode.Equals(NS_LITERAL_STRING("on"),
nsCaseInsensitiveStringComparator())) {
// go through hoops to get dom window (see nsHTMLDocument::GetSelection)
nsCOMPtr<nsIPresShell> shell = (nsIPresShell*)mPresShells.SafeElementAt(0);
NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
nsCOMPtr<nsIPresContext> cx;
shell->GetPresContext(getter_AddRefs(cx));
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
nsCOMPtr<nsISupports> container;
cx->GetContainer(getter_AddRefs(container));
NS_ENSURE_TRUE(container, NS_OK);
nsCOMPtr<nsIDOMWindow> domwindow(do_GetInterface(container));
NS_ENSURE_TRUE(domwindow, NS_ERROR_FAILURE);
nsresult rv = editSession->Init(domwindow); // content root frame
if (NS_FAILED(rv))
return rv;
rv = editSession->MakeWindowEditable(domwindow, "html", false);
if (NS_FAILED(rv))
return rv;
// now that we've successfully created the editor, we can reset our flag
mEditingIsOn = PR_TRUE;
}
else { // turn editing off
// right now we don't have a way to turn off editing :-(
mEditingIsOn = PR_FALSE;
}
return NS_OK;
}
nsresult
nsHTMLDocument::GetMidasCommandManager(nsICommandManager** aCmdMgr)
{
// initialize return value
NS_ENSURE_ARG_POINTER(aCmdMgr);
// check if we have it cached
if (mMidasCommandManager) {
NS_ADDREF(*aCmdMgr = mMidasCommandManager);
return NS_OK;
}
*aCmdMgr = nsnull;
if (!mScriptGlobalObject)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocShell> docshell;
mScriptGlobalObject->GetDocShell(getter_AddRefs(docshell));
if (!docshell)
return NS_ERROR_FAILURE;
nsCOMPtr<nsICommandManager> mMidasCommandManager = do_GetInterface(docshell);
if (!mMidasCommandManager)
return NS_ERROR_FAILURE;
NS_ADDREF(*aCmdMgr = mMidasCommandManager);
return NS_OK;
}
struct MidasCommand {
const char* incomingCommandString;
const char* internalCommandString;
const char* internalParamString;
PRBool useNewParam;
};
static struct MidasCommand gMidasCommandTable[] = {
{ "bold", "cmd_bold", "", PR_TRUE },
{ "italic", "cmd_italic", "", PR_TRUE },
{ "underline", "cmd_underline", "", PR_TRUE },
{ "strikethrough", "cmd_strikethrough", "", PR_TRUE },
{ "subscript", "cmd_subscript", "", PR_TRUE },
{ "superscript", "cmd_superscript", "", PR_TRUE },
{ "cut", "cmd_cut", "", PR_TRUE },
{ "copy", "cmd_copy", "", PR_TRUE },
{ "paste", "cmd_paste", "", PR_TRUE },
{ "delete", "cmd_delete", "", PR_TRUE },
{ "selectall", "cmd_selectall", "", PR_TRUE },
{ "undo", "cmd_undo", "", PR_TRUE },
{ "redo", "cmd_redo", "", PR_TRUE },
{ "indent", "cmd_indent", "", PR_TRUE },
{ "outdent", "cmd_outdent", "", PR_TRUE },
{ "backcolor", "cmd_backgroundColor", "", PR_FALSE },
{ "forecolor", "cmd_fontColor", "", PR_FALSE },
{ "fontname", "cmd_fontFace", "", PR_FALSE },
{ "horizontalline", "cmd_hline", "", PR_TRUE },
{ "hr", "cmd_hline", "", PR_TRUE },
{ "createlink", "cmd_link", "", PR_TRUE },
{ "justifyleft", "cmd_align", "left", PR_TRUE },
{ "justifyright", "cmd_align", "right", PR_TRUE },
{ "justifycenter", "cmd_align", "center", PR_TRUE },
{ "justifyfull", "cmd_align", "justify", PR_TRUE },
{ "removeformat", "cmd_removeStyles", "", PR_TRUE },
{ "unlink", "cmd_removeLinks", "", PR_TRUE },
{ "orderlist", "cmd_ol", "", PR_TRUE },
{ "unorderlist", "cmd_ul", "", PR_TRUE },
{ "paragraph", "cmd_paragraphState", "p", PR_TRUE },
{ "formatblock", "cmd_paragraphState", "", PR_FALSE },
{ "heading", "cmd_paragraphState", "", PR_FALSE },
#if 0
{ "fontsize", "cmd_fontSize", "", PR_FALSE },
{ "justifynone", "cmd_align", "", PR_TRUE },
{ "saveas", "cmd_saveAs", "", PR_TRUE },
{ "print", "cmd_print", "", PR_TRUE },
#endif
{ NULL, NULL, NULL, PR_FALSE }
};
#define MidasCommandCount ((sizeof(gMidasCommandTable) / sizeof(struct MidasCommand)) - 1)
// this function will return false if the command is not recognized
// inCommandID will be converted as necessary for internal operations
// inParam will be converted as necessary for internal operations
// outParam will be Empty if no parameter is needed
PRBool
nsHTMLDocument::ConvertToMidasInternalCommand(const nsAString & inCommandID,
const nsAString & inParam,
nsACString& outCommandID,
nsACString& outParam)
{
nsCAutoString convertedCommandID = NS_ConvertUCS2toUTF8(inCommandID);
PRUint32 i;
for (i = 0; i < MidasCommandCount; ++i) {
if (convertedCommandID.Equals(gMidasCommandTable[i].incomingCommandString,
nsCaseInsensitiveCStringComparator())) {
// set outCommandID (what we use internally)
outCommandID.Assign(gMidasCommandTable[i].internalCommandString);
// set outParam based on the flag from the table
if (gMidasCommandTable[i].useNewParam) {
outParam.Assign(gMidasCommandTable[i].internalParamString);
}
else {
// pass through the parameter that was passed to us
outParam.Assign(NS_ConvertUCS2toUTF8(inParam));
}
return PR_TRUE;
}
}
// reset results if the command is not found in our table
outCommandID.SetLength(0);
outParam.SetLength(0);
return PR_FALSE;
}
/* TODO: don't let this call do anything if the page is not done loading */
/* boolean execCommand(in DOMString commandID, in boolean doShowUI,
in DOMString value); */
NS_IMETHODIMP
nsHTMLDocument::ExecCommand(const nsAString & commandID,
PRBool doShowUI,
const nsAString & value,
PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
// for optional parameters see dom/src/base/nsHistory.cpp: HistoryImpl::Go()
// this might add some ugly JS dependencies?
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
// if they are requesting UI from us, let's fail since we have no UI
if (doShowUI)
return NS_ERROR_NOT_IMPLEMENTED;
// TEMPORARY HACK: (this block will go away very soon)
// always set focus to this widget so the command can be executed only in
// this scope (we wouldn't want to be able to execute commands outside of
// our own editor scope
nsCOMPtr<nsIDOMWindowInternal> wintmp = do_QueryInterface(mScriptGlobalObject);
if (!wintmp)
return NS_ERROR_FAILURE;
nsresult rv2 = wintmp->Focus();
if (NS_FAILED(rv2))
return rv2;
// get command manager and dispatch command to our window if it's acceptable
nsCOMPtr<nsICommandManager> cmdMgr;
nsresult rv = GetMidasCommandManager(getter_AddRefs(cmdMgr));
if (NS_FAILED(rv))
return rv;
if (!cmdMgr)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
if (!window)
return NS_ERROR_FAILURE;
nsCAutoString cmdToDispatch, paramStr;
if (!ConvertToMidasInternalCommand(commandID, value, cmdToDispatch, paramStr))
return NS_ERROR_NOT_IMPLEMENTED;
if (paramStr.IsEmpty()) {
rv = cmdMgr->DoCommand(cmdToDispatch.get(), nsnull);
} else {
// we have a command that requires a parameter, create params
nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
NS_COMMAND_PARAMS_CONTRACTID, &rv);
if (!cmdParams)
return NS_ERROR_OUT_OF_MEMORY;
rv = cmdParams->SetCStringValue("state_attribute", paramStr.get());
if (NS_FAILED(rv))
return rv;
rv = cmdMgr->DoCommand(cmdToDispatch.get(), cmdParams);
}
*_retval = NS_SUCCEEDED(rv);
return rv;
}
/* TODO: don't let this call do anything if the page is not done loading */
/* boolean execCommandShowHelp(in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::ExecCommandShowHelp(const nsAString & commandID,
PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
}
/* boolean queryCommandEnabled(in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::QueryCommandEnabled(const nsAString & commandID,
PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
}
/* boolean queryCommandIndeterm (in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID,
PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
}
/* boolean queryCommandState(in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::QueryCommandState(const nsAString & commandID, PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
// TEMPORARY HACK: (this block will go away very soon)
// always set focus to this widget so the command can be executed only in
// this scope (we wouldn't want to be able to execute commands outside of
// our own editor scope
nsCOMPtr<nsIDOMWindowInternal> wintmp = do_QueryInterface(mScriptGlobalObject);
if (!wintmp)
return NS_ERROR_FAILURE;
nsresult rv2 = wintmp->Focus();
if (NS_FAILED(rv2))
return rv2;
// get command manager and dispatch command to our window if it's acceptable
nsCOMPtr<nsICommandManager> cmdMgr;
nsresult rv = GetMidasCommandManager(getter_AddRefs(cmdMgr));
if (NS_FAILED(rv))
return rv;
if (!cmdMgr)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
if (!window)
return NS_ERROR_FAILURE;
nsCAutoString cmdToDispatch, paramToCheck;
if (!ConvertToMidasInternalCommand(commandID, commandID,
cmdToDispatch, paramToCheck))
return NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
NS_COMMAND_PARAMS_CONTRACTID, &rv);
if (!cmdParams)
return NS_ERROR_OUT_OF_MEMORY;
rv = cmdMgr->GetCommandState(cmdToDispatch.get(), cmdParams);
if (NS_FAILED(rv))
return rv;
// handle alignment as a special case (possibly other commands too?)
// Alignment is special because the external api is individual commands
// but internally we use cmd_align with different parameters. When getting
// the state of this command, we need to return the boolean for this
// particular alignment rather than the string of 'which alignment is this?'
if (cmdToDispatch.Equals("cmd_align")) {
char * actualAlignmentType = nsnull;
rv = cmdParams->GetCStringValue("state_attribute", &actualAlignmentType);
if (NS_SUCCEEDED(rv) && actualAlignmentType && actualAlignmentType[0]) {
*_retval = paramToCheck.Equals(actualAlignmentType);
}
if (actualAlignmentType)
nsMemory::Free(actualAlignmentType);
}
else {
rv = cmdParams->GetBooleanValue("state_all", _retval);
if (NS_FAILED(rv))
*_retval = PR_FALSE;
}
return rv;
}
/* boolean queryCommandSupported(in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
}
/* DOMString queryCommandText(in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::QueryCommandText(const nsAString & commandID,
nsAString & _retval)
{
_retval.SetLength(0);
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
}
/* DOMString queryCommandValue(in DOMString commandID); */
NS_IMETHODIMP
nsHTMLDocument::QueryCommandValue(const nsAString & commandID,
nsAString &_retval)
{
_retval.SetLength(0);
// if editing is not on, bail
if (!mEditingIsOn)
return NS_ERROR_FAILURE;
// TEMPORARY HACK: (this block will go away very soon)
// always set focus to this widget so the command can be executed only in
// this scope (we wouldn't want to be able to execute commands outside of
// our own editor scope
nsCOMPtr<nsIDOMWindowInternal> wintmp = do_QueryInterface(mScriptGlobalObject);
if (!wintmp)
return NS_ERROR_FAILURE;
nsresult rv2 = wintmp->Focus();
if (NS_FAILED(rv2))
return rv2;
// get command manager and dispatch command to our window if it's acceptable
nsCOMPtr<nsICommandManager> cmdMgr;
nsresult rv = GetMidasCommandManager(getter_AddRefs(cmdMgr));
if (NS_FAILED(rv))
return rv;
if (!cmdMgr)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
if (!window)
return NS_ERROR_FAILURE;
nsCAutoString cmdToDispatch, paramStr;
if (!ConvertToMidasInternalCommand(commandID, commandID,
cmdToDispatch, paramStr))
return NS_ERROR_NOT_IMPLEMENTED;
// create params
nsCOMPtr<nsICommandParams> cmdParams = do_CreateInstance(
NS_COMMAND_PARAMS_CONTRACTID, &rv);
if (!cmdParams)
return NS_ERROR_OUT_OF_MEMORY;
rv = cmdParams->SetCStringValue("state_attribute", paramStr.get());
if (NS_FAILED(rv))
return rv;
rv = cmdMgr->GetCommandState(cmdToDispatch.get(), cmdParams);
if (NS_FAILED(rv))
return rv;
char *cStringResult = nsnull;
rv = cmdParams->GetCStringValue("state_attribute", &cStringResult);
if (NS_SUCCEEDED(rv) && cStringResult && cStringResult[0]) {
_retval.Assign(NS_ConvertUTF8toUCS2(cStringResult));
}
if (cStringResult) {
nsMemory::Free(cStringResult);
}
return rv;
}