return get()->isCompositeStep();
}
-bool EditCommandPtr::isInputTextCommand() const
+bool EditCommandPtr::isInsertTextCommand() const
{
IF_IMPL_NULL_RETURN_ARG(false);
- return get()->isInputTextCommand();
+ return get()->isInsertTextCommand();
}
bool EditCommandPtr::isTypingCommand() const
return false;
}
-bool EditCommand::isInputTextCommand() const
+bool EditCommand::isInsertTextCommand() const
{
return false;
}
void CompositeEditCommand::inputText(const DOMString &text, bool selectInsertedText)
{
- InputTextCommand *impl = new InputTextCommand(document());
+ InsertTextCommand *impl = new InsertTextCommand(document());
EditCommandPtr cmd(impl);
applyCommandToComposite(cmd);
impl->input(text, selectInsertedText);
}
-void CompositeEditCommand::insertText(TextImpl *node, long offset, const DOMString &text)
+void CompositeEditCommand::insertTextIntoNode(TextImpl *node, long offset, const DOMString &text)
{
- EditCommandPtr cmd(new InsertTextCommand(document(), node, offset, text));
+ EditCommandPtr cmd(new InsertIntoTextNode(document(), node, offset, text));
applyCommandToComposite(cmd);
}
-void CompositeEditCommand::deleteText(TextImpl *node, long offset, long count)
+void CompositeEditCommand::deleteTextFromNode(TextImpl *node, long offset, long count)
{
- EditCommandPtr cmd(new DeleteTextCommand(document(), node, offset, count));
+ EditCommandPtr cmd(new DeleteFromTextNodeCommand(document(), node, offset, count));
applyCommandToComposite(cmd);
}
-void CompositeEditCommand::replaceText(TextImpl *node, long offset, long count, const DOMString &replacementText)
+void CompositeEditCommand::replaceTextInNode(TextImpl *node, long offset, long count, const DOMString &replacementText)
{
- EditCommandPtr deleteCommand(new DeleteTextCommand(document(), node, offset, count));
+ EditCommandPtr deleteCommand(new DeleteFromTextNodeCommand(document(), node, offset, count));
applyCommandToComposite(deleteCommand);
- EditCommandPtr insertCommand(new InsertTextCommand(document(), node, offset, replacementText));
+ EditCommandPtr insertCommand(new InsertIntoTextNode(document(), node, offset, replacementText));
applyCommandToComposite(insertCommand);
}
if (str) {
// Replace the text between start and end with our pruned version.
if (str->l > 0) {
- replaceText(textNode, start, end - start, str);
+ replaceTextInNode(textNode, start, end - start, str);
}
else {
// Assert that we are not going to delete all of the text in the node.
// If we were, that should have been done above with the call to
// removeNode and return.
ASSERT(start > 0 || (unsigned long)end - start < textNode->length());
- deleteText(textNode, start, end - start);
+ deleteTextFromNode(textNode, start, end - start);
}
str->deref();
}
return false;
}
+bool CompositeEditCommand::isLastVisiblePositionInNode(const VisiblePosition &pos, const NodeImpl *node) const
+{
+ if (pos.isNull())
+ return false;
+
+ VisiblePosition next = pos.next();
+ return next.isNull() || !next.deepEquivalent().node()->isAncestor(node);
+}
+
//==========================================================================================
// Concrete commands
//------------------------------------------------------------------------------------------
return pos;
}
+//------------------------------------------------------------------------------------------
+// DeleteFromTextNodeCommand
+
+DeleteFromTextNodeCommand::DeleteFromTextNodeCommand(DocumentImpl *document, TextImpl *node, long offset, long count)
+ : EditCommand(document), m_node(node), m_offset(offset), m_count(count)
+{
+ ASSERT(m_node);
+ ASSERT(m_offset >= 0);
+ ASSERT(m_offset < (long)m_node->length());
+ ASSERT(m_count >= 0);
+
+ m_node->ref();
+}
+
+DeleteFromTextNodeCommand::~DeleteFromTextNodeCommand()
+{
+ ASSERT(m_node);
+ m_node->deref();
+}
+
+void DeleteFromTextNodeCommand::doApply()
+{
+ ASSERT(m_node);
+
+ int exceptionCode = 0;
+ m_text = m_node->substringData(m_offset, m_count, exceptionCode);
+ ASSERT(exceptionCode == 0);
+
+ m_node->deleteData(m_offset, m_count, exceptionCode);
+ ASSERT(exceptionCode == 0);
+}
+
+void DeleteFromTextNodeCommand::doUnapply()
+{
+ ASSERT(m_node);
+ ASSERT(!m_text.isEmpty());
+
+ int exceptionCode = 0;
+ m_node->insertData(m_offset, m_text, exceptionCode);
+ ASSERT(exceptionCode == 0);
+}
+
//------------------------------------------------------------------------------------------
// DeleteSelectionCommand
// Delete any insignificant text from this node.
TextImpl *text = static_cast<TextImpl *>(m_startNode);
if (text->length() > (unsigned)m_startNode->caretMaxOffset())
- deleteText(text, m_startNode->caretMaxOffset(), text->length() - m_startNode->caretMaxOffset());
+ deleteTextFromNode(text, m_startNode->caretMaxOffset(), text->length() - m_startNode->caretMaxOffset());
}
// shift the start node to the next
NodeImpl *old = m_startNode;
else if (m_downstreamEnd.offset() - startOffset > 0) {
// in a text node that needs to be trimmed
TextImpl *text = static_cast<TextImpl *>(m_startNode);
- deleteText(text, startOffset, m_downstreamEnd.offset() - startOffset);
+ deleteTextFromNode(text, startOffset, m_downstreamEnd.offset() - startOffset);
m_trailingWhitespaceValid = false;
}
}
if (startOffset > 0) {
// in a text node that needs to be trimmed
TextImpl *text = static_cast<TextImpl *>(node);
- deleteText(text, startOffset, text->length() - startOffset);
+ deleteTextFromNode(text, startOffset, text->length() - startOffset);
node = node->traverseNextNode();
}
// in a text node that needs to be trimmed
TextImpl *text = static_cast<TextImpl *>(m_downstreamEnd.node());
if (m_downstreamEnd.offset() > 0) {
- deleteText(text, 0, m_downstreamEnd.offset());
+ deleteTextFromNode(text, 0, m_downstreamEnd.offset());
m_trailingWhitespaceValid = false;
}
}
if (m_leadingWhitespace.isNotNull() && (m_trailingWhitespace.isNotNull() || !m_leadingWhitespace.isRenderedCharacter())) {
LOG(Editing, "replace leading");
TextImpl *textNode = static_cast<TextImpl *>(m_leadingWhitespace.node());
- replaceText(textNode, m_leadingWhitespace.offset(), 1, nonBreakingSpaceString());
+ replaceTextInNode(textNode, m_leadingWhitespace.offset(), 1, nonBreakingSpaceString());
}
else if (m_trailingWhitespace.isNotNull()) {
if (m_trailingWhitespaceValid) {
if (!m_trailingWhitespace.isRenderedCharacter()) {
LOG(Editing, "replace trailing [valid]");
TextImpl *textNode = static_cast<TextImpl *>(m_trailingWhitespace.node());
- replaceText(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
+ replaceTextInNode(textNode, m_trailingWhitespace.offset(), 1, nonBreakingSpaceString());
}
}
else {
if (isWS(pos) && !pos.isRenderedCharacter()) {
LOG(Editing, "replace trailing [invalid]");
TextImpl *textNode = static_cast<TextImpl *>(pos.node());
- replaceText(textNode, pos.offset(), 1, nonBreakingSpaceString());
+ replaceTextInNode(textNode, pos.offset(), 1, nonBreakingSpaceString());
// need to adjust ending position since the trailing position is not valid.
m_endingPosition = pos;
}
NodeImpl *moveNode = node;
node = node->nextSibling();
removeNode(moveNode);
- insertNodeAfter(moveNode, refNode);
+ if (refNode->isBlockFlow())
+ appendNode(moveNode, refNode);
+ else
+ insertNodeAfter(moveNode, refNode);
refNode = moveNode;
}
// and 'Two'. This is undesirable. We fix this up by adding a BR before the 'Three'.
// This may not be ideal, but it is better than nothing.
document()->updateLayout();
- if (startBlock->renderer() && startBlock->renderer()->height() == 0) {
+ if (!startBlock->renderer() || !startBlock->renderer()->firstChild()) {
removeNode(startBlock);
if (refNode->renderer() && refNode->renderer()->inlineBox() && refNode->renderer()->inlineBox()->nextOnLineExists()) {
int exceptionCode = 0;
}
//------------------------------------------------------------------------------------------
-// DeleteTextCommand
+// InsertIntoTextNode
-DeleteTextCommand::DeleteTextCommand(DocumentImpl *document, TextImpl *node, long offset, long count)
- : EditCommand(document), m_node(node), m_offset(offset), m_count(count)
+InsertIntoTextNode::InsertIntoTextNode(DocumentImpl *document, TextImpl *node, long offset, const DOMString &text)
+ : EditCommand(document), m_node(node), m_offset(offset)
{
ASSERT(m_node);
ASSERT(m_offset >= 0);
- ASSERT(m_offset < (long)m_node->length());
- ASSERT(m_count >= 0);
+ ASSERT(!text.isEmpty());
m_node->ref();
+ m_text = text.copy(); // make a copy to ensure that the string never changes
}
-DeleteTextCommand::~DeleteTextCommand()
+InsertIntoTextNode::~InsertIntoTextNode()
{
- ASSERT(m_node);
- m_node->deref();
+ if (m_node)
+ m_node->deref();
}
-void DeleteTextCommand::doApply()
+void InsertIntoTextNode::doApply()
{
ASSERT(m_node);
+ ASSERT(m_offset >= 0);
+ ASSERT(!m_text.isEmpty());
int exceptionCode = 0;
- m_text = m_node->substringData(m_offset, m_count, exceptionCode);
- ASSERT(exceptionCode == 0);
-
- m_node->deleteData(m_offset, m_count, exceptionCode);
+ m_node->insertData(m_offset, m_text, exceptionCode);
ASSERT(exceptionCode == 0);
}
-void DeleteTextCommand::doUnapply()
+void InsertIntoTextNode::doUnapply()
{
ASSERT(m_node);
+ ASSERT(m_offset >= 0);
ASSERT(!m_text.isEmpty());
int exceptionCode = 0;
- m_node->insertData(m_offset, m_text, exceptionCode);
+ m_node->deleteData(m_offset, m_text.length(), exceptionCode);
ASSERT(exceptionCode == 0);
}
//------------------------------------------------------------------------------------------
-// InputNewlineCommand
+// InsertLineBreakCommand
-InputNewlineCommand::InputNewlineCommand(DocumentImpl *document)
+InsertLineBreakCommand::InsertLineBreakCommand(DocumentImpl *document)
: CompositeEditCommand(document)
{
}
-void InputNewlineCommand::insertNodeAfterPosition(NodeImpl *node, const Position &pos)
+void InsertLineBreakCommand::insertNodeAfterPosition(NodeImpl *node, const Position &pos)
{
// Insert the BR after the caret position. In the case the
// position is a block, do an append. We don't want to insert
insertNodeAfter(node, pos.node());
}
-void InputNewlineCommand::insertNodeBeforePosition(NodeImpl *node, const Position &pos)
+void InsertLineBreakCommand::insertNodeBeforePosition(NodeImpl *node, const Position &pos)
{
// Insert the BR after the caret position. In the case the
// position is a block, do an append. We don't want to insert
insertNodeBefore(node, pos.node());
}
-void InputNewlineCommand::doApply()
+void InsertLineBreakCommand::doApply()
{
deleteSelection();
Selection selection = endingSelection();
// Do the split
TextImpl *textNode = static_cast<TextImpl *>(pos.node());
TextImpl *textBeforeNode = document()->createTextNode(textNode->substringData(0, selection.start().offset(), exceptionCode));
- deleteText(textNode, 0, pos.offset());
+ deleteTextFromNode(textNode, 0, pos.offset());
insertNodeBefore(textBeforeNode, textNode);
insertNodeBefore(nodeToInsert, textNode);
Position endingPosition = Position(textNode, 0);
if (!endingPosition.isRenderedCharacter()) {
// Clear out all whitespace and insert one non-breaking space
deleteInsignificantTextDownstream(endingPosition);
- insertText(textNode, 0, nonBreakingSpaceString());
+ insertTextIntoNode(textNode, 0, nonBreakingSpaceString());
}
setEndingSelection(endingPosition);
}
//------------------------------------------------------------------------------------------
-// InputNewlineInQuotedContentCommand
+// InsertNodeBeforeCommand
+
+InsertNodeBeforeCommand::InsertNodeBeforeCommand(DocumentImpl *document, NodeImpl *insertChild, NodeImpl *refChild)
+ : EditCommand(document), m_insertChild(insertChild), m_refChild(refChild)
+{
+ ASSERT(m_insertChild);
+ m_insertChild->ref();
+
+ ASSERT(m_refChild);
+ m_refChild->ref();
+}
+
+InsertNodeBeforeCommand::~InsertNodeBeforeCommand()
+{
+ ASSERT(m_insertChild);
+ m_insertChild->deref();
+
+ ASSERT(m_refChild);
+ m_refChild->deref();
+}
+
+void InsertNodeBeforeCommand::doApply()
+{
+ ASSERT(m_insertChild);
+ ASSERT(m_refChild);
+ ASSERT(m_refChild->parentNode());
+
+ int exceptionCode = 0;
+ m_refChild->parentNode()->insertBefore(m_insertChild, m_refChild, exceptionCode);
+ ASSERT(exceptionCode == 0);
+}
+
+void InsertNodeBeforeCommand::doUnapply()
+{
+ ASSERT(m_insertChild);
+ ASSERT(m_refChild);
+ ASSERT(m_refChild->parentNode());
+
+ int exceptionCode = 0;
+ m_refChild->parentNode()->removeChild(m_insertChild, exceptionCode);
+ ASSERT(exceptionCode == 0);
+}
+
+//------------------------------------------------------------------------------------------
+// InsertParagraphSeparatorCommand
+
+InsertParagraphSeparatorCommand::InsertParagraphSeparatorCommand(DocumentImpl *document)
+ : CompositeEditCommand(document)
+{
+ ancestors.setAutoDelete(true);
+ clonedNodes.setAutoDelete(true);
+}
+
+void InsertParagraphSeparatorCommand::doApply()
+{
+ Selection selection = endingSelection();
+ if (selection.isNone())
+ return;
+
+ // Delete the current selection.
+ // If the selection is a range and the start and end nodes are in different blocks,
+ // then this command bails after the delete, but takes the one additional step of
+ // moving the selection downstream so it is in the ending block (if that block is
+ // still around, that is).
+ Position pos = selection.start();
+ if (selection.isRange()) {
+ NodeImpl *startBlockBeforeDelete = selection.start().node()->enclosingBlockFlowElement();
+ NodeImpl *endBlockBeforeDelete = selection.end().node()->enclosingBlockFlowElement();
+ bool doneAfterDelete = startBlockBeforeDelete != endBlockBeforeDelete;
+ deleteSelection(false, false);
+ if (doneAfterDelete) {
+ document()->updateLayout();
+ setEndingSelection(endingSelection().start().downstream());
+ return;
+ }
+ pos = endingSelection().start().upstream();
+ }
+
+ // Find the start block.
+ NodeImpl *startNode = pos.node();
+ NodeImpl *startBlock = startNode->enclosingBlockFlowElement();
+ if (!startBlock || !startBlock->parentNode())
+ return;
+
+ // Build up list of ancestors in between the start node and the start block.
+ for (NodeImpl *n = startNode->parentNode(); n && n != startBlock; n = n->parentNode())
+ ancestors.prepend(n);
+
+ // Make new block to represent the newline.
+ // If the start block is the body, just make a P tag, otherwise, make a shallow clone
+ // of the the start block.
+ NodeImpl *addedBlock = 0;
+ if (startBlock->id() == ID_BODY) {
+ int exceptionCode = 0;
+ addedBlock = document()->createHTMLElement("P", exceptionCode);
+ ASSERT(exceptionCode == 0);
+ appendNode(addedBlock, startBlock);
+ }
+ else {
+ addedBlock = startBlock->cloneNode(false);
+ insertNodeAfter(addedBlock, startBlock);
+ }
+ clonedNodes.append(addedBlock);
+
+ if (!isLastVisiblePositionInNode(VisiblePosition(pos), startBlock)) {
+ // Split at pos if in the middle of a text node.
+ if (startNode->isTextNode()) {
+ TextImpl *textNode = static_cast<TextImpl *>(startNode);
+ bool atEnd = (unsigned long)pos.offset() >= textNode->length();
+ if (pos.offset() > 0 && !atEnd) {
+ SplitTextNodeCommand *splitCommand = new SplitTextNodeCommand(document(), textNode, pos.offset());
+ EditCommandPtr cmd(splitCommand);
+ applyCommandToComposite(cmd);
+ startNode = splitCommand->node();
+ pos = Position(startNode, 0);
+ }
+ else if (atEnd) {
+ startNode = startNode->traverseNextNode();
+ ASSERT(startNode);
+ }
+ }
+ else if (pos.offset() > 0) {
+ startNode = startNode->traverseNextNode();
+ ASSERT(startNode);
+ }
+
+ // Make clones of ancestors in between the start node and the start block.
+ NodeImpl *parent = addedBlock;
+ for (QPtrListIterator<NodeImpl> it(ancestors); it.current(); ++it) {
+ NodeImpl *child = it.current()->cloneNode(false); // shallow clone
+ clonedNodes.append(child);
+ appendNode(child, parent);
+ parent = child;
+ }
+
+ // Move the start node and the siblings of the start node.
+ NodeImpl *n = startNode;
+ if (n->id() == ID_BR)
+ n = n->nextSibling();
+ while (n && n != addedBlock) {
+ NodeImpl *next = n->nextSibling();
+ removeNode(n);
+ appendNode(n, parent);
+ n = next;
+ }
+
+ // Move everything after the start node.
+ NodeImpl *leftParent = ancestors.last();
+ while (leftParent && leftParent != startBlock) {
+ parent = parent->parentNode();
+ NodeImpl *n = leftParent->nextSibling();
+ while (n) {
+ NodeImpl *next = n->nextSibling();
+ removeNode(n);
+ appendNode(n, parent);
+ n = next;
+ }
+ leftParent = leftParent->parentNode();
+ }
+ }
+
+ // Put the selection right at the start of the added block.
+ setEndingSelection(Position(addedBlock, 0));
+}
+
+//------------------------------------------------------------------------------------------
+// InsertParagraphSeparatorInQuotedContentCommand
-InputNewlineInQuotedContentCommand::InputNewlineInQuotedContentCommand(DocumentImpl *document)
+InsertParagraphSeparatorInQuotedContentCommand::InsertParagraphSeparatorInQuotedContentCommand(DocumentImpl *document)
: CompositeEditCommand(document)
{
ancestors.setAutoDelete(true);
clonedNodes.setAutoDelete(true);
}
-InputNewlineInQuotedContentCommand::~InputNewlineInQuotedContentCommand()
+InsertParagraphSeparatorInQuotedContentCommand::~InsertParagraphSeparatorInQuotedContentCommand()
{
if (m_breakNode)
m_breakNode->deref();
}
-bool InputNewlineInQuotedContentCommand::isMailBlockquote(const NodeImpl *node) const
+bool InsertParagraphSeparatorInQuotedContentCommand::isMailBlockquote(const NodeImpl *node) const
{
if (!node || !node->renderer() || !node->isElementNode() && node->id() != ID_BLOCKQUOTE)
return false;
return static_cast<const ElementImpl *>(node)->getAttribute("type") == "cite";
}
-bool InputNewlineInQuotedContentCommand::isLastVisiblePositionInBlockquote(const VisiblePosition &pos, const NodeImpl *blockquote) const
-{
- if (pos.isNull())
- return false;
-
- VisiblePosition next = pos.next();
- return next.isNull() || !next.deepEquivalent().node()->isAncestor(blockquote);
-}
-
-void InputNewlineInQuotedContentCommand::doApply()
+void InsertParagraphSeparatorInQuotedContentCommand::doApply()
{
Selection selection = endingSelection();
if (selection.isNone())
ASSERT(exceptionCode == 0);
insertNodeAfter(m_breakNode, topBlockquote);
- if (!isLastVisiblePositionInBlockquote(VisiblePosition(pos), topBlockquote)) {
+ if (!isLastVisiblePositionInNode(VisiblePosition(pos), topBlockquote)) {
// Split at pos if in the middle of a text node.
if (startNode->isTextNode()) {
TextImpl *textNode = static_cast<TextImpl *>(startNode);
}
//------------------------------------------------------------------------------------------
-// InputTextCommand
+// InsertTextCommand
-InputTextCommand::InputTextCommand(DocumentImpl *document)
+InsertTextCommand::InsertTextCommand(DocumentImpl *document)
: CompositeEditCommand(document), m_charactersAdded(0)
{
}
-void InputTextCommand::doApply()
+void InsertTextCommand::doApply()
{
}
-void InputTextCommand::deleteCharacter()
+void InsertTextCommand::deleteCharacter()
{
ASSERT(state() == Applied);
}
}
-Position InputTextCommand::prepareForTextInsertion(bool adjustDownstream)
+Position InsertTextCommand::prepareForTextInsertion(bool adjustDownstream)
{
// Prepare for text input by looking at the current position.
// It may be necessary to insert a text node to receive characters.
return pos;
}
-void InputTextCommand::input(const DOMString &text, bool selectInsertedText)
+void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
{
Selection selection = endingSelection();
bool adjustDownstream = selection.start().downstream(StayInBlock).isFirstRenderedPositionOnLine();
// convert the nbsp to a regular space.
// EDIT FIXME: This needs to be improved some day to convert back only
// those nbsp's added by the editor to make rendering come out right.
- replaceText(textNode, offset - 1, 1, " ");
+ replaceTextInNode(textNode, offset - 1, 1, " ");
}
- insertText(textNode, offset, text);
+ insertTextIntoNode(textNode, offset, text);
if (selectInsertedText)
setEndingSelection(Selection(Position(textNode, offset), Position(textNode, offset + text.length())));
else
}
}
-void InputTextCommand::insertSpace(TextImpl *textNode, unsigned long offset)
+void InsertTextCommand::insertSpace(TextImpl *textNode, unsigned long offset)
{
ASSERT(textNode);
if (downstream.offset() < (long)text.length() && isWS(text[downstream.offset()]))
count--; // leave this WS in
if (count > 0)
- deleteText(textNode, offset, count);
+ deleteTextFromNode(textNode, offset, count);
}
if (offset > 0 && offset <= text.length() - 1 && !isWS(text[offset]) && !isWS(text[offset - 1])) {
// insert a "regular" space
- insertText(textNode, offset, " ");
+ insertTextIntoNode(textNode, offset, " ");
return;
}
// DOM looks like this:
// nbsp nbsp caret
// insert a space between the two nbsps
- insertText(textNode, offset - 1, " ");
+ insertTextIntoNode(textNode, offset - 1, " ");
return;
}
// insert an nbsp
- insertText(textNode, offset, nonBreakingSpaceString());
+ insertTextIntoNode(textNode, offset, nonBreakingSpaceString());
}
-bool InputTextCommand::isInputTextCommand() const
+bool InsertTextCommand::isInsertTextCommand() const
{
return true;
}
-//------------------------------------------------------------------------------------------
-// InsertNodeBeforeCommand
-
-InsertNodeBeforeCommand::InsertNodeBeforeCommand(DocumentImpl *document, NodeImpl *insertChild, NodeImpl *refChild)
- : EditCommand(document), m_insertChild(insertChild), m_refChild(refChild)
-{
- ASSERT(m_insertChild);
- m_insertChild->ref();
-
- ASSERT(m_refChild);
- m_refChild->ref();
-}
-
-InsertNodeBeforeCommand::~InsertNodeBeforeCommand()
-{
- ASSERT(m_insertChild);
- m_insertChild->deref();
-
- ASSERT(m_refChild);
- m_refChild->deref();
-}
-
-void InsertNodeBeforeCommand::doApply()
-{
- ASSERT(m_insertChild);
- ASSERT(m_refChild);
- ASSERT(m_refChild->parentNode());
-
- int exceptionCode = 0;
- m_refChild->parentNode()->insertBefore(m_insertChild, m_refChild, exceptionCode);
- ASSERT(exceptionCode == 0);
-}
-
-void InsertNodeBeforeCommand::doUnapply()
-{
- ASSERT(m_insertChild);
- ASSERT(m_refChild);
- ASSERT(m_refChild->parentNode());
-
- int exceptionCode = 0;
- m_refChild->parentNode()->removeChild(m_insertChild, exceptionCode);
- ASSERT(exceptionCode == 0);
-}
-
-//------------------------------------------------------------------------------------------
-// InsertTextCommand
-
-InsertTextCommand::InsertTextCommand(DocumentImpl *document, TextImpl *node, long offset, const DOMString &text)
- : EditCommand(document), m_node(node), m_offset(offset)
-{
- ASSERT(m_node);
- ASSERT(m_offset >= 0);
- ASSERT(!text.isEmpty());
-
- m_node->ref();
- m_text = text.copy(); // make a copy to ensure that the string never changes
-}
-
-InsertTextCommand::~InsertTextCommand()
-{
- if (m_node)
- m_node->deref();
-}
-
-void InsertTextCommand::doApply()
-{
- ASSERT(m_node);
- ASSERT(m_offset >= 0);
- ASSERT(!m_text.isEmpty());
-
- int exceptionCode = 0;
- m_node->insertData(m_offset, m_text, exceptionCode);
- ASSERT(exceptionCode == 0);
-}
-
-void InsertTextCommand::doUnapply()
-{
- ASSERT(m_node);
- ASSERT(m_offset >= 0);
- ASSERT(!m_text.isEmpty());
-
- int exceptionCode = 0;
- m_node->deleteData(m_offset, m_text.length(), exceptionCode);
- ASSERT(exceptionCode == 0);
-}
-
//------------------------------------------------------------------------------------------
// JoinTextNodesCommand
}
}
-void TypingCommand::insertNewline(DocumentImpl *document)
+void TypingCommand::insertLineBreak(DocumentImpl *document)
{
ASSERT(document);
EditCommandPtr lastEditCommand = part->lastEditCommand();
if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand *>(lastEditCommand.get())->insertNewline();
+ static_cast<TypingCommand *>(lastEditCommand.get())->insertLineBreak();
}
else {
- EditCommandPtr cmd(new TypingCommand(document, InsertNewline));
+ EditCommandPtr cmd(new TypingCommand(document, InsertLineBreak));
cmd.apply();
}
}
-void TypingCommand::insertNewlineInQuotedContent(DocumentImpl *document)
+void TypingCommand::insertParagraphSeparatorInQuotedContent(DocumentImpl *document)
{
ASSERT(document);
EditCommandPtr lastEditCommand = part->lastEditCommand();
if (isOpenForMoreTypingCommand(lastEditCommand)) {
- static_cast<TypingCommand *>(lastEditCommand.get())->insertNewlineInQuotedContent();
+ static_cast<TypingCommand *>(lastEditCommand.get())->insertParagraphSeparatorInQuotedContent();
}
else {
- EditCommandPtr cmd(new TypingCommand(document, InsertNewlineInQuotedContent));
+ EditCommandPtr cmd(new TypingCommand(document, InsertParagraphSeparatorInQuotedContent));
+ cmd.apply();
+ }
+}
+
+void TypingCommand::insertParagraphSeparator(DocumentImpl *document)
+{
+ ASSERT(document);
+
+ KHTMLPart *part = document->part();
+ ASSERT(part);
+
+ EditCommandPtr lastEditCommand = part->lastEditCommand();
+ if (isOpenForMoreTypingCommand(lastEditCommand)) {
+ static_cast<TypingCommand *>(lastEditCommand.get())->insertParagraphSeparator();
+ }
+ else {
+ EditCommandPtr cmd(new TypingCommand(document, InsertParagraphSeparator));
cmd.apply();
}
}
case DeleteKey:
deleteKeyPressed();
return;
- case InsertText:
- insertText(m_textToInsert, m_selectInsertedText);
+ case InsertLineBreak:
+ insertLineBreak();
return;
- case InsertNewline:
- insertNewline();
+ case InsertParagraphSeparator:
+ insertParagraphSeparator();
return;
- case InsertNewlineInQuotedContent:
- insertNewlineInQuotedContent();
+ case InsertParagraphSeparatorInQuotedContent:
+ insertParagraphSeparatorInQuotedContent();
+ return;
+ case InsertText:
+ insertText(m_textToInsert, m_selectInsertedText);
return;
}
// FIXME: Improve typing style.
// See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
if (document()->part()->typingStyle() || m_cmds.count() == 0) {
- InputTextCommand *impl = new InputTextCommand(document());
+ InsertTextCommand *impl = new InsertTextCommand(document());
EditCommandPtr cmd(impl);
applyCommandToComposite(cmd);
impl->input(text, selectInsertedText);
}
else {
EditCommandPtr lastCommand = m_cmds.last();
- if (lastCommand.isInputTextCommand()) {
- InputTextCommand *impl = static_cast<InputTextCommand *>(lastCommand.get());
+ if (lastCommand.isInsertTextCommand()) {
+ InsertTextCommand *impl = static_cast<InsertTextCommand *>(lastCommand.get());
impl->input(text, selectInsertedText);
}
else {
- InputTextCommand *impl = new InputTextCommand(document());
+ InsertTextCommand *impl = new InsertTextCommand(document());
EditCommandPtr cmd(impl);
applyCommandToComposite(cmd);
impl->input(text, selectInsertedText);
typingAddedToOpenCommand();
}
-void TypingCommand::insertNewline()
+void TypingCommand::insertLineBreak()
+{
+ EditCommandPtr cmd(new InsertLineBreakCommand(document()));
+ applyCommandToComposite(cmd);
+ typingAddedToOpenCommand();
+}
+
+void TypingCommand::insertParagraphSeparator()
{
- EditCommandPtr cmd(new InputNewlineCommand(document()));
+ EditCommandPtr cmd(new InsertParagraphSeparatorCommand(document()));
applyCommandToComposite(cmd);
typingAddedToOpenCommand();
}
-void TypingCommand::insertNewlineInQuotedContent()
+void TypingCommand::insertParagraphSeparatorInQuotedContent()
{
- EditCommandPtr cmd(new InputNewlineInQuotedContentCommand(document()));
+ EditCommandPtr cmd(new InsertParagraphSeparatorInQuotedContentCommand(document()));
applyCommandToComposite(cmd);
typingAddedToOpenCommand();
}
}
else {
EditCommandPtr lastCommand = m_cmds.last();
- if (lastCommand.isInputTextCommand()) {
- InputTextCommand &cmd = static_cast<InputTextCommand &>(lastCommand);
+ if (lastCommand.isInsertTextCommand()) {
+ InsertTextCommand &cmd = static_cast<InsertTextCommand &>(lastCommand);
cmd.deleteCharacter();
if (cmd.charactersAdded() == 0) {
removeCommand(lastCommand);
}
}
- else if (lastCommand.isInputNewlineCommand()) {
+ else if (lastCommand.isInsertLineBreakCommand()) {
lastCommand.unapply();
removeCommand(lastCommand);
}
switch (m_commandType) {
case DeleteKey:
return true;
+ case InsertLineBreak:
+ case InsertParagraphSeparator:
+ case InsertParagraphSeparatorInQuotedContent:
case InsertText:
- case InsertNewline:
- case InsertNewlineInQuotedContent:
return false;
}
ASSERT_NOT_REACHED();
EditCommandPtr parent() const;
void setParent(const EditCommandPtr &) const;
- bool isInputTextCommand() const;
- bool isInputNewlineCommand() const;
+ bool isInsertTextCommand() const;
+ bool isInsertLineBreakCommand() const;
bool isTypingCommand() const;
static EditCommandPtr &emptyCommand();
DOM::CSSStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
void setTypingStyle(DOM::CSSStyleDeclarationImpl *);
- virtual bool isInputTextCommand() const;
+ virtual bool isInsertTextCommand() const;
virtual bool isTypingCommand() const;
private:
void deleteKeyPressed();
void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
void deleteSelection(const khtml::Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
- void deleteText(DOM::TextImpl *node, long offset, long count);
+ void deleteTextFromNode(DOM::TextImpl *node, long offset, long count);
void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
- void insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
+ void insertTextIntoNode(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
void removeFullySelectedNode(DOM::NodeImpl *);
void removeNodeAttribute(DOM::ElementImpl *, int attribute);
void removeNode(DOM::NodeImpl *removeChild);
void removeNodePreservingChildren(DOM::NodeImpl *node);
- void replaceText(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
+ void replaceTextInNode(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
void splitTextNode(DOM::TextImpl *text, long offset);
void insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
+ bool isLastVisiblePositionInNode(const VisiblePosition &, const DOM::NodeImpl *) const;
+
QValueList<EditCommandPtr> m_cmds;
};
DOM::CSSStyleDeclarationImpl *m_style;
};
+//------------------------------------------------------------------------------------------
+// DeleteFromTextNodeCommand
+
+class DeleteFromTextNodeCommand : public EditCommand
+{
+public:
+ DeleteFromTextNodeCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
+ virtual ~DeleteFromTextNodeCommand();
+
+ virtual void doApply();
+ virtual void doUnapply();
+
+ DOM::TextImpl *node() const { return m_node; }
+ long offset() const { return m_offset; }
+ long count() const { return m_count; }
+
+private:
+ DOM::TextImpl *m_node;
+ long m_offset;
+ long m_count;
+ DOM::DOMString m_text;
+};
+
//------------------------------------------------------------------------------------------
// DeleteSelectionCommand
};
//------------------------------------------------------------------------------------------
-// DeleteTextCommand
+// InsertIntoTextNode
-class DeleteTextCommand : public EditCommand
+class InsertIntoTextNode : public EditCommand
{
public:
- DeleteTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
- virtual ~DeleteTextCommand();
+ InsertIntoTextNode(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
+ virtual ~InsertIntoTextNode();
virtual void doApply();
virtual void doUnapply();
DOM::TextImpl *node() const { return m_node; }
long offset() const { return m_offset; }
- long count() const { return m_count; }
+ DOM::DOMString text() const { return m_text; }
private:
DOM::TextImpl *m_node;
long m_offset;
- long m_count;
DOM::DOMString m_text;
};
//------------------------------------------------------------------------------------------
-// InputNewlineCommand
+// InsertNodeBeforeCommand
+
+class InsertNodeBeforeCommand : public EditCommand
+{
+public:
+ InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
+ virtual ~InsertNodeBeforeCommand();
+
+ virtual void doApply();
+ virtual void doUnapply();
+
+ DOM::NodeImpl *insertChild() const { return m_insertChild; }
+ DOM::NodeImpl *refChild() const { return m_refChild; }
+
+private:
+ DOM::NodeImpl *m_insertChild;
+ DOM::NodeImpl *m_refChild;
+};
+
+//------------------------------------------------------------------------------------------
+// InsertLineBreakCommand
-class InputNewlineCommand : public CompositeEditCommand
+class InsertLineBreakCommand : public CompositeEditCommand
{
public:
- InputNewlineCommand(DOM::DocumentImpl *document);
+ InsertLineBreakCommand(DOM::DocumentImpl *document);
virtual void doApply();
};
//------------------------------------------------------------------------------------------
-// InputNewlineInQuotedContentCommand
+// InsertParagraphSeparatorCommand
-class InputNewlineInQuotedContentCommand : public CompositeEditCommand
+class InsertParagraphSeparatorCommand : public CompositeEditCommand
{
public:
- InputNewlineInQuotedContentCommand(DOM::DocumentImpl *);
- virtual ~InputNewlineInQuotedContentCommand();
+ InsertParagraphSeparatorCommand(DOM::DocumentImpl *document);
+
+ virtual void doApply();
+
+private:
+ QPtrList<DOM::NodeImpl> ancestors;
+ QPtrList<DOM::NodeImpl> clonedNodes;
+};
+
+//------------------------------------------------------------------------------------------
+// InsertParagraphSeparatorInQuotedContentCommand
+
+class InsertParagraphSeparatorInQuotedContentCommand : public CompositeEditCommand
+{
+public:
+ InsertParagraphSeparatorInQuotedContentCommand(DOM::DocumentImpl *);
+ virtual ~InsertParagraphSeparatorInQuotedContentCommand();
virtual void doApply();
private:
bool isMailBlockquote(const DOM::NodeImpl *) const;
- bool isLastVisiblePositionInBlockquote(const VisiblePosition &pos, const DOM::NodeImpl *) const;
QPtrList<DOM::NodeImpl> ancestors;
QPtrList<DOM::NodeImpl> clonedNodes;
};
//------------------------------------------------------------------------------------------
-// InputTextCommand
+// InsertTextCommand
-class InputTextCommand : public CompositeEditCommand
+class InsertTextCommand : public CompositeEditCommand
{
public:
- InputTextCommand(DOM::DocumentImpl *document);
+ InsertTextCommand(DOM::DocumentImpl *document);
virtual void doApply();
unsigned long charactersAdded() const { return m_charactersAdded; }
private:
- virtual bool isInputTextCommand() const;
+ virtual bool isInsertTextCommand() const;
DOM::Position prepareForTextInsertion(bool adjustDownstream);
void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
unsigned long m_charactersAdded;
};
-//------------------------------------------------------------------------------------------
-// InsertNodeBeforeCommand
-
-class InsertNodeBeforeCommand : public EditCommand
-{
-public:
- InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
- virtual ~InsertNodeBeforeCommand();
-
- virtual void doApply();
- virtual void doUnapply();
-
- DOM::NodeImpl *insertChild() const { return m_insertChild; }
- DOM::NodeImpl *refChild() const { return m_refChild; }
-
-private:
- DOM::NodeImpl *m_insertChild;
- DOM::NodeImpl *m_refChild;
-};
-
-//------------------------------------------------------------------------------------------
-// InsertTextCommand
-
-class InsertTextCommand : public EditCommand
-{
-public:
- InsertTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
- virtual ~InsertTextCommand();
-
- virtual void doApply();
- virtual void doUnapply();
-
- DOM::TextImpl *node() const { return m_node; }
- long offset() const { return m_offset; }
- DOM::DOMString text() const { return m_text; }
-
-private:
- DOM::TextImpl *m_node;
- long m_offset;
- DOM::DOMString m_text;
-};
-
//------------------------------------------------------------------------------------------
// JoinTextNodesCommand
class TypingCommand : public CompositeEditCommand
{
public:
- enum ETypingCommand { DeleteKey, InsertText, InsertNewline, InsertNewlineInQuotedContent };
+ enum ETypingCommand {
+ DeleteKey,
+ InsertText,
+ InsertLineBreak,
+ InsertParagraphSeparator,
+ InsertParagraphSeparatorInQuotedContent,
+ };
TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
- static void deleteKeyPressed(DOM::DocumentImpl *document);
- static void insertText(DOM::DocumentImpl *document, const DOM::DOMString &text, bool selectInsertedText = false);
- static void insertNewline(DOM::DocumentImpl *document);
- static void insertNewlineInQuotedContent(DOM::DocumentImpl *document);
+ static void deleteKeyPressed(DOM::DocumentImpl *);
+ static void insertText(DOM::DocumentImpl *, const DOM::DOMString &, bool selectInsertedText = false);
+ static void insertLineBreak(DOM::DocumentImpl *);
+ static void insertParagraphSeparator(DOM::DocumentImpl *);
+ static void insertParagraphSeparatorInQuotedContent(DOM::DocumentImpl *);
static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
static void closeTyping(const EditCommandPtr &);
void closeTyping() { m_openForMoreTyping = false; }
void insertText(const DOM::DOMString &text, bool selectInsertedText);
- void insertNewline();
- void insertNewlineInQuotedContent();
+ void insertLineBreak();
+ void insertParagraphSeparatorInQuotedContent();
+ void insertParagraphSeparator();
void deleteKeyPressed();
private: