gecko-dev/editor/base/nsTextEditRules.h

307 lines
12 KiB
C
Raw Normal View History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsTextEditRules_h__
#define nsTextEditRules_h__
#include "nsCOMPtr.h"
#include "nsHTMLEditor.h"
#include "nsIDOMNode.h"
#include "nsEditRules.h"
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used anywhere any more. * Cleaned up split and join undo/redo. * Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type * Ctrl-B with an insertion point and the next character will be bold. * Added all the logic to handle inline vs. block elements when setting text properties. * Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline. * Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements. * Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ... * Fully undoable and redoable. * Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree. Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 17:58:07 +00:00
#include "TypeInState.h"
/** Object that encapsulates HTML text-specific editing rules.
*
* To be a good citizen, edit rules must live by these restrictions:
* 1. All data manipulation is through the editor.
* Content nodes in the document tree must <B>not</B> be manipulated directly.
* Content nodes in document fragments that are not part of the document itself
* may be manipulated at will. Operations on document fragments must <B>not</B>
* go through the editor.
* 2. Selection must not be explicitly set by the rule method.
* Any manipulation of Selection must be done by the editor.
*/
1999-04-05 17:21:59 +00:00
class nsTextEditRules : public nsEditRules
{
public:
nsTextEditRules();
virtual ~nsTextEditRules();
1999-04-05 17:21:59 +00:00
// nsEditRules methods
NS_IMETHOD Init(nsHTMLEditor *aEditor, PRUint32 aFlags);
NS_IMETHOD BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection);
NS_IMETHOD WillDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, PRBool *aCancel, PRBool *aHandled);
1999-04-12 12:01:32 +00:00
NS_IMETHOD DidDoAction(nsIDOMSelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
Preparation for ender-based text control * added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start. We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to another app. * added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the rules system deal with those flags. The flags I added are: TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus. TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus. * added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line behavior. * cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the ownership model on the listeners, it was a big help. * added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-28 21:24:18 +00:00
NS_IMETHOD GetFlags(PRUint32 *aFlags);
NS_IMETHOD SetFlags(PRUint32 aFlags);
NS_IMETHOD DocumentIsEmpty(PRBool *aDocumentIsEmpty);
1999-04-05 17:21:59 +00:00
// nsTextEditRules action id's
enum
{
1999-09-17 23:15:12 +00:00
kDefault = 0,
// any editor that has a txn mgr
1999-09-17 23:15:12 +00:00
kUndo = 1000,
kRedo = 1001,
// text actions
1999-09-17 23:15:12 +00:00
kInsertText = 2000,
kInsertTextIME = 2001,
kDeleteSelection = 2002,
kSetTextProperty = 2003,
kRemoveTextProperty = 2004,
kOutputText = 2005,
// html only action
1999-09-17 23:15:12 +00:00
kInsertBreak = 3000,
kMakeList = 3001,
kIndent = 3002,
kOutdent = 3003,
kAlign = 3004,
kMakeBasicBlock = 3005,
kRemoveList = 3006,
kInsertElement = 3008
1999-04-05 17:21:59 +00:00
};
protected:
1999-04-05 17:21:59 +00:00
// nsTextEditRules implementation methods
nsresult WillInsertText( PRInt32 aAction,
nsIDOMSelection *aSelection,
PRBool *aCancel,
PRBool *aHandled,
const nsString *inString,
nsString *outString,
TypeInState typeInState,
PRInt32 aMaxLength);
1999-04-12 12:01:32 +00:00
nsresult DidInsertText(nsIDOMSelection *aSelection, nsresult aResult);
nsresult GetTopEnclosingPre(nsIDOMNode *aNode, nsIDOMNode** aOutPreNode);
1999-04-12 12:01:32 +00:00
nsresult CreateStyleForInsertText(nsIDOMSelection *aSelection, TypeInState &aTypeInState);
nsresult WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
Preparation for ender-based text control * added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start. We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to another app. * added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the rules system deal with those flags. The flags I added are: TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus. TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus. * added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line behavior. * cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the ownership model on the listeners, it was a big help. * added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-28 21:24:18 +00:00
nsresult DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult);
1999-04-12 12:01:32 +00:00
nsresult WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel);
nsresult DidInsert(nsIDOMSelection *aSelection, nsresult aResult);
1999-06-24 23:36:56 +00:00
nsresult WillDeleteSelection(nsIDOMSelection *aSelection,
nsIEditor::EDirection aCollapsedAction,
PRBool *aCancel,
PRBool *aHandled);
1999-06-24 23:36:56 +00:00
nsresult DidDeleteSelection(nsIDOMSelection *aSelection,
nsIEditor::EDirection aCollapsedAction,
1999-06-24 23:36:56 +00:00
nsresult aResult);
nsresult WillSetTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult DidSetTextProperty(nsIDOMSelection *aSelection, nsresult aResult);
nsresult WillRemoveTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
nsresult DidRemoveTextProperty(nsIDOMSelection *aSelection, nsresult aResult);
nsresult WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
1999-04-12 12:01:32 +00:00
nsresult DidUndo(nsIDOMSelection *aSelection, nsresult aResult);
nsresult WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled);
1999-04-12 12:01:32 +00:00
nsresult DidRedo(nsIDOMSelection *aSelection, nsresult aResult);
/** called prior to nsIEditor::OutputToString
* @param aSelection
* @param aInFormat the format requested for the output, a MIME type
* @param aOutText the string to use for output, if aCancel is set to true
* @param aOutCancel if set to PR_TRUE, the caller should cancel the operation
* and use aOutText as the result.
*/
nsresult WillOutputText(nsIDOMSelection *aSelection,
const nsString *aInFormat,
nsString *aOutText,
PRBool *aOutCancel,
PRBool *aHandled);
1999-06-24 23:36:56 +00:00
nsresult DidOutputText(nsIDOMSelection *aSelection, nsresult aResult);
// helper functions
/** insert aNode into a new style node of type aTag.
* aSelection is optional. If provided, aSelection is set to (aNode, 0)
* if aNode was successfully placed in a new style node
* @param aNewStyleNode [OUT] The newly created style node, if result is successful
* undefined if result is a failure.
*/
nsresult InsertStyleNode(nsIDOMNode *aNode,
nsIAtom *aTag,
nsIDOMSelection *aSelection,
nsIDOMNode **aNewStyleNode);
/** inserts a new <FONT> node and sets the aAttr attribute to aValue */
nsresult CreateFontStyleForInsertText(nsIDOMNode *aNewTextNode,
const nsString &aAttr,
const nsString &aValue,
nsIDOMSelection *aInOutSelection);
/** create a new style node of type aTag in aParentNode at aOffset,
* and create a new text node in the new style node.
*
* @param aParentNode the node that will be the parent of the new style node
* @param aOffset the positoin in aParentNode to put the new style node
* @param aTag the type of style node to create
* no validation of aTag is done, caller is responsible
* for passing in a reasonable tag name
* @param aAttr optional attribute to set on new style node
* ignored if it is an empty string
* @param aValue optional value for aAttr. Ignored if aAttr is an empty string
* @param aInOutSelection optional. If provided and if it is collapsed to a text node,
* we use the text node and wrap a style node around it.
* If provided, aSelection is collapsed to (newTextNode, 0)
* if newTextNode was successfully created.
*/
1999-04-12 12:01:32 +00:00
nsresult InsertStyleAndNewTextNode(nsIDOMNode *aParentNode,
PRInt32 aOffset,
nsIAtom *aTag,
const nsString &aAttr,
const nsString &aValue,
nsIDOMSelection *aSelection);
Preparation for ender-based text control * added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start. We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to another app. * added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the rules system deal with those flags. The flags I added are: TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus. TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus. * added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line behavior. * cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the ownership model on the listeners, it was a big help. * added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-28 21:24:18 +00:00
/** replaces newllines with breaks, if needed. acts on doc portion in aRange */
nsresult ReplaceNewlines(nsIDOMRange *aRange);
Preparation for ender-based text control * added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start. We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to another app. * added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the rules system deal with those flags. The flags I added are: TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus. TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus. * added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line behavior. * cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the ownership model on the listeners, it was a big help. * added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-28 21:24:18 +00:00
/** creates a bogus text node if the document has no editable content */
nsresult CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection);
1999-06-24 23:36:56 +00:00
/** returns a truncated insertion string if insertion would place us
over aMaxLength */
nsresult TruncateInsertionIfNeeded(nsIDOMSelection *aSelection,
const nsString *aInString,
nsString *aOutString,
PRInt32 aMaxLength);
/** Echo's the insertion text into the password buffer, and converts
insertion text to '*'s */
nsresult EchoInsertionToPWBuff(nsIDOMSelection *aSelection, nsString *aOutString);
/** do the actual text insertion */
nsresult DoTextInsertion(nsIDOMSelection *aSelection,
PRBool *aCancel,
const nsString *aInString,
TypeInState aTypeInState);
nsresult GetPriorHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLSibling(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetPriorHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inNode, nsCOMPtr<nsIDOMNode> *outNode);
nsresult GetNextHTMLNode(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outNode);
nsresult IsFirstEditableChild( nsIDOMNode *aNode, PRBool *aOutIsFirst);
nsresult IsLastEditableChild( nsIDOMNode *aNode, PRBool *aOutIsLast);
nsresult GetFirstEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutFirstChild);
nsresult GetLastEditableChild( nsIDOMNode *aNode, nsCOMPtr<nsIDOMNode> *aOutLastChild);
nsresult CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode);
// data members
nsHTMLEditor *mEditor; // note that we do not refcount the editor
1999-06-24 23:36:56 +00:00
nsString mPasswordText; // a buffer we use to store the real value of password editors
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
Preparation for ender-based text control * added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start. We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to another app. * added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the rules system deal with those flags. The flags I added are: TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus. TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus. * added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line behavior. * cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the ownership model on the listeners, it was a big help. * added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-28 21:24:18 +00:00
PRUint32 mFlags;
PRUint32 mActionNesting;
PRBool mLockRulesSniffing;
// friends
friend class nsAutoLockRulesSniffing;
};
1999-04-12 12:01:32 +00:00
class nsTextRulesInfo : public nsRulesInfo
{
public:
1999-06-24 23:36:56 +00:00
nsTextRulesInfo(int aAction) :
nsRulesInfo(aAction),
inString(0),
outString(0),
outputFormat(0),
1999-06-24 23:36:56 +00:00
typeInState(),
maxLength(-1),
collapsedAction(nsIEditor::eNext),
1999-08-09 22:51:40 +00:00
bOrdered(PR_FALSE),
alignType(0),
blockType(0),
1999-08-09 22:51:40 +00:00
insertElement(0)
1999-06-24 23:36:56 +00:00
{};
virtual ~nsTextRulesInfo() {};
1999-04-12 12:01:32 +00:00
// kInsertText
1999-04-12 12:01:32 +00:00
const nsString *inString;
nsString *outString;
const nsString *outputFormat;
1999-04-12 12:01:32 +00:00
TypeInState typeInState;
PRInt32 maxLength;
1999-04-26 14:08:52 +00:00
// kDeleteSelection
nsIEditor::EDirection collapsedAction;
// kMakeList
PRBool bOrdered;
// kAlign
const nsString *alignType;
1999-08-09 22:51:40 +00:00
// kMakeBasicBlock
const nsString *blockType;
1999-08-09 22:51:40 +00:00
// kInsertElement
const nsIDOMElement* insertElement;
1999-04-12 12:01:32 +00:00
};
/***************************************************************************
* stack based helper class for StartOperation()/EndOperation() sandwich.
* this class sets a bool letting us know to ignore any rules sniffing
* that tries to occur reentrantly.
*/
class nsAutoLockRulesSniffing
{
public:
nsAutoLockRulesSniffing(nsTextEditRules *rules) : mRules(rules)
{if (mRules) mRules->mLockRulesSniffing = PR_TRUE;}
~nsAutoLockRulesSniffing()
{if (mRules) mRules->mLockRulesSniffing = PR_FALSE;}
protected:
nsTextEditRules *mRules;
};
#endif //nsTextEditRules_h__