[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.15-1-40151-g37bb677

kocienda kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Sat Sep 26 08:26:09 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit 1af684d9b4b218e889603235c64f87d025950c32
Author: kocienda <kocienda at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Feb 11 04:56:17 2004 +0000

    WebCore:
    
            Reviewed by Hyatt
    
            Several big changes.
    
            EditSteps are now all EditCommands.
            Smart pointer for Shared classes added to shared.h.
    		Some events, like text input events, are now coalesced.
    		"Undo typing" now implemented, even though the name is not in the menu yet.
    		Integer id's added to EditCommand and its subclasses.
    		A bunch of cleanup in the EditCommand classes.
    
            * khtml/editing/htmlediting.cpp:
            (EditCommand::EditCommand):
            (EditCommand::~EditCommand):
            (EditCommand::commandID):
            (EditCommand::reapply):
            (EditCommand::beginApply):
            (EditCommand::endApply):
            (EditCommand::beginUnapply):
            (EditCommand::endUnapply):
            (EditCommand::beginReapply):
            (EditCommand::endReapply):
            (EditCommand::currentSelection):
            (EditCommand::coalesce):
            (EditCommand::groupForUndo):
            (EditCommand::groupForRedo):
            (EditCommand::moveToStartingSelection):
            (EditCommand::moveToEndingSelection):
            (EditCommand::name):
            (CompositeEditCommand::CompositeEditCommand):
            (CompositeEditCommand::~CompositeEditCommand):
            (CompositeEditCommand::unapply):
            (CompositeEditCommand::reapply):
            (CompositeEditCommand::applyCommand):
            (CompositeEditCommand::insertNodeBefore):
            (CompositeEditCommand::insertNodeAfter):
            (CompositeEditCommand::appendNode):
            (CompositeEditCommand::removeNode):
            (CompositeEditCommand::splitTextNode):
            (CompositeEditCommand::joinTextNodes):
            (CompositeEditCommand::insertText):
            (CompositeEditCommand::deleteText):
            (CompositeEditCommand::moveSelectionTo):
            (CompositeEditCommand::deleteSelection):
            (InsertNodeBeforeCommand::InsertNodeBeforeCommand):
            (InsertNodeBeforeCommand::~InsertNodeBeforeCommand):
            (InsertNodeBeforeCommand::apply):
            (InsertNodeBeforeCommand::unapply):
            (AppendNodeCommand::AppendNodeCommand):
            (AppendNodeCommand::~AppendNodeCommand):
            (AppendNodeCommand::apply):
            (AppendNodeCommand::unapply):
            (RemoveNodeCommand::RemoveNodeCommand):
            (RemoveNodeCommand::~RemoveNodeCommand):
            (RemoveNodeCommand::apply):
            (RemoveNodeCommand::unapply):
            (ModifyTextNodeCommand::ModifyTextNodeCommand):
            (ModifyTextNodeCommand::~ModifyTextNodeCommand):
            (ModifyTextNodeCommand::splitTextNode):
            (ModifyTextNodeCommand::joinTextNodes):
            (SplitTextNodeCommand::SplitTextNodeCommand):
            (SplitTextNodeCommand::~SplitTextNodeCommand):
            (SplitTextNodeCommand::apply):
            (SplitTextNodeCommand::unapply):
            (JoinTextNodesCommand::JoinTextNodesCommand):
            (JoinTextNodesCommand::~JoinTextNodesCommand):
            (JoinTextNodesCommand::apply):
            (JoinTextNodesCommand::unapply):
            (InsertTextCommand::InsertTextCommand):
            (InsertTextCommand::~InsertTextCommand):
            (InsertTextCommand::apply):
            (InsertTextCommand::unapply):
            (DeleteTextCommand::DeleteTextCommand):
            (DeleteTextCommand::~DeleteTextCommand):
            (DeleteTextCommand::apply):
            (DeleteTextCommand::unapply):
            (MoveSelectionToCommand::MoveSelectionToCommand):
            (MoveSelectionToCommand::~MoveSelectionToCommand):
            (MoveSelectionToCommand::commandID):
            (MoveSelectionToCommand::apply):
            (MoveSelectionToCommand::unapply):
            (DeleteSelectionCommand::DeleteSelectionCommand):
            (DeleteSelectionCommand::~DeleteSelectionCommand):
            (DeleteSelectionCommand::apply):
            (InputTextCommand::InputTextCommand):
            (InputTextCommand::~InputTextCommand):
            (InputTextCommand::commandID):
            (InputTextCommand::isLineBreak):
            (InputTextCommand::isSpace):
            (InputTextCommand::apply):
            (InputTextCommand::coalesce):
            (InputTextCommand::groupForUndo):
            (InputTextCommand::groupForRedo):
            (InputTextCommand::execute):
            (DeleteKeyCommand::DeleteKeyCommand):
            (DeleteKeyCommand::~DeleteKeyCommand):
            (DeleteKeyCommand::commandID):
            (DeleteKeyCommand::apply):
            (DeleteKeyCommand::groupForUndo):
            (DeleteKeyCommand::groupForRedo):
            (PasteHTMLCommand::PasteHTMLCommand):
            (PasteHTMLCommand::~PasteHTMLCommand):
            (PasteHTMLCommand::apply):
            * khtml/editing/htmlediting.h:
            (khtml::):
            (khtml::EditCommand::):
            (khtml::EditCommand::document):
            (khtml::EditCommand::state):
            (khtml::EditCommand::setState):
            (khtml::SplitTextNodeCommand::joinState):
            (khtml::SplitTextNodeCommand::splitState):
            (khtml::JoinTextNodesCommand::joinState):
            (khtml::JoinTextNodesCommand::splitState):
            * khtml/khtml_part.cpp:
            (KHTMLPart::openURL):
            (KHTMLPart::deleteSelection):
            (KHTMLPart::applyCommand):
            (KHTMLPart::undoEditing):
            (KHTMLPart::redoEditing):
            (KHTMLPart::pasteHTMLString):
            * khtml/khtml_part.h:
            * khtml/khtmlpart_p.h:
            (KHTMLPartPrivate::~KHTMLPartPrivate):
            * khtml/misc/shared.h:
            (khtml::SharedPtr::SharedPtr):
            (khtml::SharedPtr::~SharedPtr):
            (khtml::SharedPtr::isEmpty):
            (khtml::SharedPtr::get):
            (khtml::SharedPtr::operator*):
            (khtml::SharedPtr::operator->):
            (khtml::SharedPtr::operator!):
            (khtml::SharedPtr::operator==):
            (khtml::::operator):
            (khtml::operator!=):
            * khtml/xml/dom_elementimpl.cpp:
            (ElementImpl::defaultEventHandler):
            * kwq/KWQKHTMLPart.h:
            * kwq/KWQKHTMLPart.mm:
            (KWQKHTMLPart::registerCommandForUndo):
            (KWQKHTMLPart::registerCommandForRedo):
            (KWQKHTMLPart::clearUndoRedoOperations):
            * kwq/WebCoreBridge.h:
            * kwq/WebCoreBridge.mm:
            (-[WebCoreBridge undoEditing:]):
            (-[WebCoreBridge redoEditing:]):
    
    WebKit:
    
            Reviewed by Hyatt
    
            * WebCoreSupport.subproj/WebBridge.m:
            (-[WebBridge registerCommandForUndo]): Some cleanup. Cookie for events no longer needed.
            (-[WebBridge registerCommandForRedo]): Ditto.
            (-[WebBridge clearUndoRedoOperations]): Tells the Cocoa undo manager to clear
            steps targeted at the bridge.
            * WebView.subproj/WebFrame.h: Declare undo manager accessor.
            * WebView.subproj/WebFrame.m:
            (-[WebFramePrivate dealloc]): Release undo manager
            (-[WebFrame undoManager]): Allocate and return an undo manager. This helps
            undo in a browser to be per tab.
            * WebView.subproj/WebFramePrivate.h: Declare undo manager ivar.
    
    WebBrowser:
    
            Reviewed by Hyatt
    
            * BrowserDocument.h:
            * BrowserDocument.m:
            (-[BrowserDocument undoManager]): Now calls on its main frame
            to provide an undo manager. This will allow us to do some
            necessary custom stuff in the future. For now, it enables
            undo to work in multiple tabs.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@6065 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index 4610ed4..d44a57d 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,151 @@
+2004-02-10  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+        
+        Several big changes.
+        
+        EditSteps are now all EditCommands.
+        Smart pointer for Shared classes added to shared.h.
+		Some events, like text input events, are now coalesced.
+		"Undo typing" now implemented, even though the name is not in the menu yet.
+		Integer id's added to EditCommand and its subclasses.
+		A bunch of cleanup in the EditCommand classes.
+
+        * khtml/editing/htmlediting.cpp:
+        (EditCommand::EditCommand):
+        (EditCommand::~EditCommand):
+        (EditCommand::commandID):
+        (EditCommand::reapply):
+        (EditCommand::beginApply):
+        (EditCommand::endApply):
+        (EditCommand::beginUnapply):
+        (EditCommand::endUnapply):
+        (EditCommand::beginReapply):
+        (EditCommand::endReapply):
+        (EditCommand::currentSelection):
+        (EditCommand::coalesce):
+        (EditCommand::groupForUndo):
+        (EditCommand::groupForRedo):
+        (EditCommand::moveToStartingSelection):
+        (EditCommand::moveToEndingSelection):
+        (EditCommand::name):
+        (CompositeEditCommand::CompositeEditCommand):
+        (CompositeEditCommand::~CompositeEditCommand):
+        (CompositeEditCommand::unapply):
+        (CompositeEditCommand::reapply):
+        (CompositeEditCommand::applyCommand):
+        (CompositeEditCommand::insertNodeBefore):
+        (CompositeEditCommand::insertNodeAfter):
+        (CompositeEditCommand::appendNode):
+        (CompositeEditCommand::removeNode):
+        (CompositeEditCommand::splitTextNode):
+        (CompositeEditCommand::joinTextNodes):
+        (CompositeEditCommand::insertText):
+        (CompositeEditCommand::deleteText):
+        (CompositeEditCommand::moveSelectionTo):
+        (CompositeEditCommand::deleteSelection):
+        (InsertNodeBeforeCommand::InsertNodeBeforeCommand):
+        (InsertNodeBeforeCommand::~InsertNodeBeforeCommand):
+        (InsertNodeBeforeCommand::apply):
+        (InsertNodeBeforeCommand::unapply):
+        (AppendNodeCommand::AppendNodeCommand):
+        (AppendNodeCommand::~AppendNodeCommand):
+        (AppendNodeCommand::apply):
+        (AppendNodeCommand::unapply):
+        (RemoveNodeCommand::RemoveNodeCommand):
+        (RemoveNodeCommand::~RemoveNodeCommand):
+        (RemoveNodeCommand::apply):
+        (RemoveNodeCommand::unapply):
+        (ModifyTextNodeCommand::ModifyTextNodeCommand):
+        (ModifyTextNodeCommand::~ModifyTextNodeCommand):
+        (ModifyTextNodeCommand::splitTextNode):
+        (ModifyTextNodeCommand::joinTextNodes):
+        (SplitTextNodeCommand::SplitTextNodeCommand):
+        (SplitTextNodeCommand::~SplitTextNodeCommand):
+        (SplitTextNodeCommand::apply):
+        (SplitTextNodeCommand::unapply):
+        (JoinTextNodesCommand::JoinTextNodesCommand):
+        (JoinTextNodesCommand::~JoinTextNodesCommand):
+        (JoinTextNodesCommand::apply):
+        (JoinTextNodesCommand::unapply):
+        (InsertTextCommand::InsertTextCommand):
+        (InsertTextCommand::~InsertTextCommand):
+        (InsertTextCommand::apply):
+        (InsertTextCommand::unapply):
+        (DeleteTextCommand::DeleteTextCommand):
+        (DeleteTextCommand::~DeleteTextCommand):
+        (DeleteTextCommand::apply):
+        (DeleteTextCommand::unapply):
+        (MoveSelectionToCommand::MoveSelectionToCommand):
+        (MoveSelectionToCommand::~MoveSelectionToCommand):
+        (MoveSelectionToCommand::commandID):
+        (MoveSelectionToCommand::apply):
+        (MoveSelectionToCommand::unapply):
+        (DeleteSelectionCommand::DeleteSelectionCommand):
+        (DeleteSelectionCommand::~DeleteSelectionCommand):
+        (DeleteSelectionCommand::apply):
+        (InputTextCommand::InputTextCommand):
+        (InputTextCommand::~InputTextCommand):
+        (InputTextCommand::commandID):
+        (InputTextCommand::isLineBreak):
+        (InputTextCommand::isSpace):
+        (InputTextCommand::apply):
+        (InputTextCommand::coalesce):
+        (InputTextCommand::groupForUndo):
+        (InputTextCommand::groupForRedo):
+        (InputTextCommand::execute):
+        (DeleteKeyCommand::DeleteKeyCommand):
+        (DeleteKeyCommand::~DeleteKeyCommand):
+        (DeleteKeyCommand::commandID):
+        (DeleteKeyCommand::apply):
+        (DeleteKeyCommand::groupForUndo):
+        (DeleteKeyCommand::groupForRedo):
+        (PasteHTMLCommand::PasteHTMLCommand):
+        (PasteHTMLCommand::~PasteHTMLCommand):
+        (PasteHTMLCommand::apply):
+        * khtml/editing/htmlediting.h:
+        (khtml::):
+        (khtml::EditCommand::):
+        (khtml::EditCommand::document):
+        (khtml::EditCommand::state):
+        (khtml::EditCommand::setState):
+        (khtml::SplitTextNodeCommand::joinState):
+        (khtml::SplitTextNodeCommand::splitState):
+        (khtml::JoinTextNodesCommand::joinState):
+        (khtml::JoinTextNodesCommand::splitState):
+        * khtml/khtml_part.cpp:
+        (KHTMLPart::openURL):
+        (KHTMLPart::deleteSelection):
+        (KHTMLPart::applyCommand):
+        (KHTMLPart::undoEditing):
+        (KHTMLPart::redoEditing):
+        (KHTMLPart::pasteHTMLString):
+        * khtml/khtml_part.h:
+        * khtml/khtmlpart_p.h:
+        (KHTMLPartPrivate::~KHTMLPartPrivate):
+        * khtml/misc/shared.h:
+        (khtml::SharedPtr::SharedPtr):
+        (khtml::SharedPtr::~SharedPtr):
+        (khtml::SharedPtr::isEmpty):
+        (khtml::SharedPtr::get):
+        (khtml::SharedPtr::operator*):
+        (khtml::SharedPtr::operator->):
+        (khtml::SharedPtr::operator!):
+        (khtml::SharedPtr::operator==):
+        (khtml::::operator):
+        (khtml::operator!=):
+        * khtml/xml/dom_elementimpl.cpp:
+        (ElementImpl::defaultEventHandler):
+        * kwq/KWQKHTMLPart.h:
+        * kwq/KWQKHTMLPart.mm:
+        (KWQKHTMLPart::registerCommandForUndo):
+        (KWQKHTMLPart::registerCommandForRedo):
+        (KWQKHTMLPart::clearUndoRedoOperations):
+        * kwq/WebCoreBridge.h:
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge undoEditing:]):
+        (-[WebCoreBridge redoEditing:]):
+
 2004-02-10  David Hyatt  <hyatt at apple.com>
 
 	Eliminate the double-completion and double-parsing of KURLs for every single image request.
diff --git a/WebCore/khtml/editing/htmlediting.cpp b/WebCore/khtml/editing/htmlediting.cpp
index fe3345f..ea5fd19 100644
--- a/WebCore/khtml/editing/htmlediting.cpp
+++ b/WebCore/khtml/editing/htmlediting.cpp
@@ -55,23 +55,21 @@ using DOM::Range;
 using DOM::RangeImpl;
 using DOM::TextImpl;
 
-using khtml::AppendNodeStep;
-using khtml::CompositeEditStep;
-using khtml::DeleteSelectionStep;
-using khtml::DeleteTextStep;
-using khtml::EditStep;
-using khtml::InsertNodeBeforeStep;
-using khtml::InsertTextStep;
-using khtml::JoinTextNodesStep;
-using khtml::ModifyTextNodeStep;
-using khtml::MoveSelectionToStep;
-using khtml::RemoveNodeStep;
-using khtml::SplitTextNodeStep;
-
+using khtml::AppendNodeCommand;
+using khtml::CompositeEditCommand;
+using khtml::DeleteKeyCommand;
+using khtml::DeleteSelectionCommand;
 using khtml::DeleteTextCommand;
 using khtml::EditCommand;
 using khtml::InputTextCommand;
+using khtml::InsertNodeBeforeCommand;
+using khtml::InsertTextCommand;
+using khtml::JoinTextNodesCommand;
+using khtml::ModifyTextNodeCommand;
+using khtml::RemoveNodeCommand;
+using khtml::MoveSelectionToCommand;
 using khtml::PasteHTMLCommand;
+using khtml::SplitTextNodeCommand;
 
 #if !APPLE_CHANGES
 #define ASSERT(assertion) ((void)0)
@@ -82,13 +80,9 @@ using khtml::PasteHTMLCommand;
 #endif
 
 //------------------------------------------------------------------------------------------
+// EditCommand
 
-#pragma mark EditSteps
-
-//------------------------------------------------------------------------------------------
-// EditStep
-
-EditStep::EditStep(DocumentImpl *document) : m_document(document), m_state(NOT_APPLIED)
+EditCommand::EditCommand(DocumentImpl *document) : m_document(document), m_state(NOT_APPLIED)
 {
     ASSERT(m_document);
     ASSERT(m_document->part());
@@ -97,105 +91,165 @@ EditStep::EditStep(DocumentImpl *document) : m_document(document), m_state(NOT_A
     m_endingSelection = m_startingSelection;
 }
 
-EditStep::~EditStep()
+EditCommand::~EditCommand()
 {
     ASSERT(m_document);
     m_document->deref();
 }
 
-void EditStep::reapply()
+int EditCommand::commandID() const
+{
+    return EditCommandID;
+}
+
+void EditCommand::reapply()
 {
     apply();
 }
 
-inline void EditStep::beginApply()
+inline void EditCommand::beginApply()
 {
     ASSERT(state() == NOT_APPLIED);
 }
 
-inline void EditStep::endApply()
+inline void EditCommand::endApply()
 {
-    ASSERT(m_document);
-    ASSERT(m_document->part());
-
     m_state = APPLIED;
-    m_document->part()->setSelection(m_endingSelection);
+    moveToEndingSelection();
 }
 
-inline void EditStep::beginUnapply()
+inline void EditCommand::beginUnapply()
 {
     ASSERT(state() == APPLIED);
 }
 
-inline void EditStep::endUnapply()
+inline void EditCommand::endUnapply()
+{
+    m_state = NOT_APPLIED;
+    moveToStartingSelection();
+}
+
+inline void EditCommand::beginReapply()
+{
+    beginApply();
+}
+
+inline void EditCommand::endReapply()
+{
+    endApply();
+}
+
+const KHTMLSelection &EditCommand::currentSelection() const
 {
     ASSERT(m_document);
     ASSERT(m_document->part());
+    return m_document->part()->selection();
+}
 
-    m_state = NOT_APPLIED;
+bool EditCommand::coalesce(const EditCommandPtr &cmd)
+{
+    // default is no coalescing
+    return false;
+}
+
+bool EditCommand::groupForUndo(const EditCommandPtr &) const
+{
+    // default is not continuing
+    return false;
+}
+
+bool EditCommand::groupForRedo(const EditCommandPtr &) const
+{
+    // default is not continuing
+    return false;
+}
+
+void EditCommand::moveToStartingSelection()
+{
+    ASSERT(m_document);
+    ASSERT(m_document->part());
     m_document->part()->setSelection(m_startingSelection);
 }
 
-inline void EditStep::beginReapply()
+void EditCommand::moveToEndingSelection()
 {
-    beginApply();
+    ASSERT(m_document);
+    ASSERT(m_document->part());
+    m_document->part()->setSelection(m_endingSelection);
 }
 
-inline void EditStep::endReapply()
+QString EditCommand::name() const
 {
-    endApply();
+    switch (commandID()) {
+        case EditCommandID:
+            return "EditCommandID";
+            break;
+        case InputTextCommandID:
+            return "InputTextCommandID";
+            break;
+        case DeleteKeyCommandID:
+            return "DeleteKeyCommandID";
+            break;
+        case MoveSelectionToCommandID:
+            return "MoveSelectionToCommand";
+            break;
+    }
+    
+    ASSERT_NOT_REACHED();
+    return "";
 }
 
 //------------------------------------------------------------------------------------------
-// CompositeEditStep
+// CompositeEditCommand
 
-CompositeEditStep::CompositeEditStep(DocumentImpl *document) 
-    : EditStep(document)
+CompositeEditCommand::CompositeEditCommand(DocumentImpl *document) 
+    : EditCommand(document)
 {
-    m_steps.setAutoDelete(true);
 }
 
-CompositeEditStep::~CompositeEditStep()
+CompositeEditCommand::~CompositeEditCommand()
 {
 }
 
-void CompositeEditStep::unapply()
+void CompositeEditCommand::unapply()
 {
-    if (m_steps.count() == 0) {
-        ERROR("Unapplying composite step containing zero steps");
+    if (m_cmds.count() == 0) {
+        ERROR("Unapplying composite command containing zero steps");
     }
-    QPtrListIterator<EditStep> it(m_steps);
-    for (it.toLast(); it.current(); --it) {
-        it.current()->unapply();
+    for (int i = m_cmds.count() - 1; i >= 0; --i) {
+        m_cmds[i]->unapply();
     }
+    moveToStartingSelection();
+    setState(NOT_APPLIED);
 }
 
-void CompositeEditStep::reapply()
+void CompositeEditCommand::reapply()
 {
-    if (m_steps.count() == 0) {
-        ERROR("Reapplying composite step containing zero steps");
+    if (m_cmds.count() == 0) {
+        ERROR("Reapplying composite command containing zero steps");
     }
-    QPtrListIterator<EditStep> it(m_steps);
-    for (; it.current(); ++it) {
-        it.current()->reapply();
+    for (QValueList<EditCommandPtr>::ConstIterator it = m_cmds.begin(); it != m_cmds.end(); ++it) {
+        (*it)->reapply();
     }
+    moveToEndingSelection();
+    setState(APPLIED);
 }
 
 //
-// sugary-sweet convenience functions to help create and apply edit steps
+// sugary-sweet convenience functions to help create and apply edit commands in composite commands
 //
-void CompositeEditStep::applyStep(EditStep *step)
+void CompositeEditCommand::applyCommand(const EditCommandPtr &step)
 {
     step->apply();
-    m_steps.append(step);
+    m_cmds.append(step);
 }
 
-void CompositeEditStep::insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
+void CompositeEditCommand::insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
 {
-    applyStep(new InsertNodeBeforeStep(document(), insertChild, refChild));
+    applyCommand(EditCommandPtr(new InsertNodeBeforeCommand(document(), insertChild, refChild)));
 }
 
-void CompositeEditStep::insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
+void CompositeEditCommand::insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild)
 {
     if (refChild->parentNode()->lastChild() == refChild) {
         appendNode(refChild->parentNode(), insertChild);
@@ -206,66 +260,70 @@ void CompositeEditStep::insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImp
     }
 }
 
-void CompositeEditStep::appendNode(DOM::NodeImpl *parent, DOM::NodeImpl *appendChild)
+void CompositeEditCommand::appendNode(DOM::NodeImpl *parent, DOM::NodeImpl *appendChild)
 {
-    applyStep(new AppendNodeStep(document(), parent, appendChild));
+    applyCommand(EditCommandPtr(new AppendNodeCommand(document(), parent, appendChild)));
 }
 
-void CompositeEditStep::removeNode(DOM::NodeImpl *removeChild)
+void CompositeEditCommand::removeNode(DOM::NodeImpl *removeChild)
 {
-    applyStep(new RemoveNodeStep(document(), removeChild));
+    applyCommand(EditCommandPtr(new RemoveNodeCommand(document(), removeChild)));
 }
 
-void CompositeEditStep::splitTextNode(DOM::TextImpl *text, long offset)
+void CompositeEditCommand::splitTextNode(DOM::TextImpl *text, long offset)
 {
-    applyStep(new SplitTextNodeStep(document(), text, offset));
+    applyCommand(EditCommandPtr(new SplitTextNodeCommand(document(), text, offset)));
 }
 
-void CompositeEditStep::joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2)
+void CompositeEditCommand::joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2)
 {
-    applyStep(new JoinTextNodesStep(document(), text1, text2));
+    applyCommand(EditCommandPtr(new JoinTextNodesCommand(document(), text1, text2)));
 }
 
-void CompositeEditStep::insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text)
+void CompositeEditCommand::insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text)
 {
-    applyStep(new InsertTextStep(document(), node, offset, text));
+    applyCommand(EditCommandPtr(new InsertTextCommand(document(), node, offset, text)));
 }
 
-void CompositeEditStep::deleteText(DOM::TextImpl *node, long offset, long count)
+void CompositeEditCommand::deleteText(DOM::TextImpl *node, long offset, long count)
 {
-    applyStep(new DeleteTextStep(document(), node, offset, count));
+    applyCommand(EditCommandPtr(new DeleteTextCommand(document(), node, offset, count)));
 }
 
-void CompositeEditStep::moveSelectionTo(const KHTMLSelection &selection)
+void CompositeEditCommand::moveSelectionTo(const KHTMLSelection &selection)
 {
-    applyStep(new MoveSelectionToStep(document(), selection));
+    applyCommand(EditCommandPtr(new MoveSelectionToCommand(document(), selection)));
 }
 
-void CompositeEditStep::moveSelectionTo(DOM::NodeImpl *node, long offset)
+void CompositeEditCommand::moveSelectionTo(DOM::NodeImpl *node, long offset)
 {
-    applyStep(new MoveSelectionToStep(document(), node, offset));
+    applyCommand(EditCommandPtr(new MoveSelectionToCommand(document(), node, offset)));
 }
 
-void CompositeEditStep::moveSelectionTo(const DOM::DOMPosition &pos)
+void CompositeEditCommand::moveSelectionTo(const DOM::DOMPosition &pos)
 {
-    applyStep(new MoveSelectionToStep(document(), pos));
+    applyCommand(EditCommandPtr(new MoveSelectionToCommand(document(), pos)));
 }
 
-void CompositeEditStep::deleteSelection()
+void CompositeEditCommand::deleteSelection()
 {
-    applyStep(new DeleteSelectionStep(document()));
+    if (currentSelection().state() == KHTMLSelection::RANGE) {
+        applyCommand(EditCommandPtr(new DeleteSelectionCommand(document())));
+    }
 }
 
-void CompositeEditStep::deleteSelection(const KHTMLSelection &selection)
+void CompositeEditCommand::deleteSelection(const KHTMLSelection &selection)
 {
-    applyStep(new DeleteSelectionStep(document(), selection));
+    if (selection.state() == KHTMLSelection::RANGE) {
+        applyCommand(EditCommandPtr(new DeleteSelectionCommand(document(), selection)));
+    }
 }
 
 //------------------------------------------------------------------------------------------
-// InsertNodeBeforeStep
+// InsertNodeBeforeCommand
 
-InsertNodeBeforeStep::InsertNodeBeforeStep(DocumentImpl *document, NodeImpl *insertChild, NodeImpl *refChild)
-    : EditStep(document), m_insertChild(insertChild), m_refChild(refChild)
+InsertNodeBeforeCommand::InsertNodeBeforeCommand(DocumentImpl *document, NodeImpl *insertChild, NodeImpl *refChild)
+    : EditCommand(document), m_insertChild(insertChild), m_refChild(refChild)
 {
     ASSERT(m_insertChild);
     m_insertChild->ref();
@@ -274,7 +332,7 @@ InsertNodeBeforeStep::InsertNodeBeforeStep(DocumentImpl *document, NodeImpl *ins
     m_refChild->ref();
 }
 
-InsertNodeBeforeStep::~InsertNodeBeforeStep()
+InsertNodeBeforeCommand::~InsertNodeBeforeCommand()
 {
     if (m_insertChild)
         m_insertChild->deref();
@@ -282,7 +340,7 @@ InsertNodeBeforeStep::~InsertNodeBeforeStep()
         m_refChild->deref();
 }
 
-void InsertNodeBeforeStep::apply()
+void InsertNodeBeforeCommand::apply()
 {
     beginApply();
 
@@ -297,7 +355,7 @@ void InsertNodeBeforeStep::apply()
     endApply();
 }
 
-void InsertNodeBeforeStep::unapply()
+void InsertNodeBeforeCommand::unapply()
 {
     beginUnapply();
 
@@ -313,10 +371,10 @@ void InsertNodeBeforeStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// AppendNodeStep
+// AppendNodeCommand
 
-AppendNodeStep::AppendNodeStep(DocumentImpl *document, NodeImpl *parent, NodeImpl *appendChild)
-    : EditStep(document), m_parent(parent), m_appendChild(appendChild)
+AppendNodeCommand::AppendNodeCommand(DocumentImpl *document, NodeImpl *parent, NodeImpl *appendChild)
+    : EditCommand(document), m_parent(parent), m_appendChild(appendChild)
 {
     ASSERT(m_parent);
     m_parent->ref();
@@ -325,7 +383,7 @@ AppendNodeStep::AppendNodeStep(DocumentImpl *document, NodeImpl *parent, NodeImp
     m_appendChild->ref();
 }
 
-AppendNodeStep::~AppendNodeStep()
+AppendNodeCommand::~AppendNodeCommand()
 {
     if (m_parent)
         m_parent->deref();
@@ -333,7 +391,7 @@ AppendNodeStep::~AppendNodeStep()
         m_appendChild->deref();
 }
 
-void AppendNodeStep::apply()
+void AppendNodeCommand::apply()
 {
     beginApply();
 
@@ -347,7 +405,7 @@ void AppendNodeStep::apply()
     endApply();
 }
 
-void AppendNodeStep::unapply()
+void AppendNodeCommand::unapply()
 {
     beginUnapply();
 
@@ -363,10 +421,10 @@ void AppendNodeStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// RemoveNodeStep
+// RemoveNodeCommand
 
-RemoveNodeStep::RemoveNodeStep(DocumentImpl *document, NodeImpl *removeChild)
-    : EditStep(document), m_parent(0), m_removeChild(removeChild), m_refChild(0)
+RemoveNodeCommand::RemoveNodeCommand(DocumentImpl *document, NodeImpl *removeChild)
+    : EditCommand(document), m_parent(0), m_removeChild(removeChild), m_refChild(0)
 {
     ASSERT(m_removeChild);
     m_removeChild->ref();
@@ -387,7 +445,7 @@ RemoveNodeStep::RemoveNodeStep(DocumentImpl *document, NodeImpl *removeChild)
         m_refChild->ref();
 }
 
-RemoveNodeStep::~RemoveNodeStep()
+RemoveNodeCommand::~RemoveNodeCommand()
 {
     if (m_parent)
         m_parent->deref();
@@ -397,7 +455,7 @@ RemoveNodeStep::~RemoveNodeStep()
         m_refChild->deref();
 }
 
-void RemoveNodeStep::apply()
+void RemoveNodeCommand::apply()
 {
     beginApply();
 
@@ -411,7 +469,7 @@ void RemoveNodeStep::apply()
     endApply();
 }
 
-void RemoveNodeStep::unapply()
+void RemoveNodeCommand::unapply()
 {
     beginUnapply();
 
@@ -429,10 +487,10 @@ void RemoveNodeStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// ModifyTextNodeStep
+// ModifyTextNodeCommand
 
-ModifyTextNodeStep::ModifyTextNodeStep(DocumentImpl *document, TextImpl *text, long offset)
-    : EditStep(document), m_text1(0), m_text2(text), m_offset(offset)
+ModifyTextNodeCommand::ModifyTextNodeCommand(DocumentImpl *document, TextImpl *text, long offset)
+    : EditCommand(document), m_text1(0), m_text2(text), m_offset(offset)
 {
     ASSERT(m_text2);
     ASSERT(m_text2->length() > 0);
@@ -441,8 +499,8 @@ ModifyTextNodeStep::ModifyTextNodeStep(DocumentImpl *document, TextImpl *text, l
     m_text2->ref();
 }
 
-ModifyTextNodeStep::ModifyTextNodeStep(DocumentImpl *document, TextImpl *text1, TextImpl *text2)
-    : EditStep(document), m_text1(text1), m_text2(text2), m_offset(0)
+ModifyTextNodeCommand::ModifyTextNodeCommand(DocumentImpl *document, TextImpl *text1, TextImpl *text2)
+    : EditCommand(document), m_text1(text1), m_text2(text2), m_offset(0)
 {
     ASSERT(m_text1);
     ASSERT(m_text2);
@@ -454,7 +512,7 @@ ModifyTextNodeStep::ModifyTextNodeStep(DocumentImpl *document, TextImpl *text1,
     m_text2->ref();
 }
 
-ModifyTextNodeStep::~ModifyTextNodeStep()
+ModifyTextNodeCommand::~ModifyTextNodeCommand()
 {
     if (m_text2)
         m_text2->deref();
@@ -462,7 +520,7 @@ ModifyTextNodeStep::~ModifyTextNodeStep()
         m_text1->deref();
 }
 
-void ModifyTextNodeStep::splitTextNode()
+void ModifyTextNodeCommand::splitTextNode()
 {
     ASSERT(m_text2);
     ASSERT(m_text1 == 0);
@@ -487,7 +545,7 @@ void ModifyTextNodeStep::splitTextNode()
     m_text1 = static_cast<TextImpl *>(m_text2->previousSibling());
 }
 
-void ModifyTextNodeStep::joinTextNodes()
+void ModifyTextNodeCommand::joinTextNodes()
 {
     ASSERT(m_text1);
     ASSERT(m_text2);
@@ -508,25 +566,25 @@ void ModifyTextNodeStep::joinTextNodes()
 }
 
 //------------------------------------------------------------------------------------------
-// SplitTextNodeStep
+// SplitTextNodeCommand
 
-SplitTextNodeStep::SplitTextNodeStep(DocumentImpl *document, TextImpl *text, long offset)
-    : ModifyTextNodeStep(document, text, offset)
+SplitTextNodeCommand::SplitTextNodeCommand(DocumentImpl *document, TextImpl *text, long offset)
+    : ModifyTextNodeCommand(document, text, offset)
 {
 }
 
-SplitTextNodeStep::~SplitTextNodeStep()
+SplitTextNodeCommand::~SplitTextNodeCommand()
 {
 }
 
-void SplitTextNodeStep::apply()
+void SplitTextNodeCommand::apply()
 {
     beginApply();
     splitTextNode();
     endApply();
 }
 
-void SplitTextNodeStep::unapply()
+void SplitTextNodeCommand::unapply()
 {
     beginUnapply();
     joinTextNodes();
@@ -534,25 +592,25 @@ void SplitTextNodeStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// SplitTextNodeStep
+// SplitTextNodeCommand
 
-JoinTextNodesStep::JoinTextNodesStep(DocumentImpl *document, TextImpl *text1, TextImpl *text2)
-    : ModifyTextNodeStep(document, text1, text2)
+JoinTextNodesCommand::JoinTextNodesCommand(DocumentImpl *document, TextImpl *text1, TextImpl *text2)
+    : ModifyTextNodeCommand(document, text1, text2)
 {
 }
 
-JoinTextNodesStep::~JoinTextNodesStep()
+JoinTextNodesCommand::~JoinTextNodesCommand()
 {
 }
 
-void JoinTextNodesStep::apply()
+void JoinTextNodesCommand::apply()
 {
     beginApply();
     joinTextNodes();
     endApply();
 }
 
-void JoinTextNodesStep::unapply()
+void JoinTextNodesCommand::unapply()
 {
     beginUnapply();
     splitTextNode();
@@ -560,10 +618,10 @@ void JoinTextNodesStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// InsertTextStep
+// InsertTextCommand
 
-InsertTextStep::InsertTextStep(DocumentImpl *document, TextImpl *node, long offset, const DOMString &text)
-    : EditStep(document), m_node(node), m_offset(offset)
+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);
@@ -573,13 +631,13 @@ InsertTextStep::InsertTextStep(DocumentImpl *document, TextImpl *node, long offs
     m_text = text.copy(); // make a copy to ensure that the string never changes
 }
 
-InsertTextStep::~InsertTextStep()
+InsertTextCommand::~InsertTextCommand()
 {
     if (m_node)
         m_node->deref();
 }
 
-void InsertTextStep::apply()
+void InsertTextCommand::apply()
 {
     beginApply();
 
@@ -593,7 +651,7 @@ void InsertTextStep::apply()
     endApply();
 }
 
-void InsertTextStep::unapply()
+void InsertTextCommand::unapply()
 {
     beginUnapply();
 
@@ -608,10 +666,10 @@ void InsertTextStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// DeleteTextStep
+// DeleteTextCommand
 
-DeleteTextStep::DeleteTextStep(DocumentImpl *document, TextImpl *node, long offset, long count)
-    : EditStep(document), m_node(node), m_offset(offset), m_count(count)
+DeleteTextCommand::DeleteTextCommand(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);
@@ -620,13 +678,13 @@ DeleteTextStep::DeleteTextStep(DocumentImpl *document, TextImpl *node, long offs
     m_node->ref();
 }
 
-DeleteTextStep::~DeleteTextStep()
+DeleteTextCommand::~DeleteTextCommand()
 {
     if (m_node)
         m_node->deref();
 }
 
-void DeleteTextStep::apply()
+void DeleteTextCommand::apply()
 {
     beginApply();
 
@@ -642,7 +700,7 @@ void DeleteTextStep::apply()
     endApply();
 }
 
-void DeleteTextStep::unapply()
+void DeleteTextCommand::unapply()
 {
     beginUnapply();
 
@@ -657,59 +715,69 @@ void DeleteTextStep::unapply()
 }
 
 //------------------------------------------------------------------------------------------
-// MoveSelectionToStep
+// MoveSelectionToCommand
 
-MoveSelectionToStep::MoveSelectionToStep(DocumentImpl *document, const KHTMLSelection &selection)
-    : EditStep(document)
+MoveSelectionToCommand::MoveSelectionToCommand(DocumentImpl *document, const KHTMLSelection &selection)
+    : EditCommand(document)
 {
     setEndingSelection(selection);
 }
 
-MoveSelectionToStep::MoveSelectionToStep(DocumentImpl *document, DOM::NodeImpl *node, long offset)
-    : EditStep(document)
+MoveSelectionToCommand::MoveSelectionToCommand(DocumentImpl *document, DOM::NodeImpl *node, long offset)
+    : EditCommand(document)
 {
     KHTMLSelection selection(node, offset);
     setEndingSelection(selection);
 }
 
-MoveSelectionToStep::MoveSelectionToStep(DOM::DocumentImpl *document, const DOM::DOMPosition &pos)
-    : EditStep(document)
+MoveSelectionToCommand::MoveSelectionToCommand(DOM::DocumentImpl *document, const DOM::DOMPosition &pos)
+    : EditCommand(document)
 {
     KHTMLSelection selection(pos);
     setEndingSelection(selection);
 }
 
-void MoveSelectionToStep::apply()
+MoveSelectionToCommand::~MoveSelectionToCommand() 
+{
+}
+
+int MoveSelectionToCommand::commandID() const
+{
+    return MoveSelectionToCommandID;
+}
+
+
+void MoveSelectionToCommand::apply()
 {
     beginApply();
     endApply();
 }
 
-void MoveSelectionToStep::unapply()
+void MoveSelectionToCommand::unapply()
 {
     beginUnapply();
     endUnapply();
 }
 
 //------------------------------------------------------------------------------------------
-// DeleteSelectionStep
+// DeleteSelectionCommand
 
-DeleteSelectionStep::DeleteSelectionStep(DOM::DocumentImpl *document)
-    : CompositeEditStep(document)
+DeleteSelectionCommand::DeleteSelectionCommand(DOM::DocumentImpl *document)
+    : CompositeEditCommand(document)
 {
 }
 
-DeleteSelectionStep::DeleteSelectionStep(DOM::DocumentImpl *document, const KHTMLSelection &selection)
-    : CompositeEditStep(document)
+DeleteSelectionCommand::DeleteSelectionCommand(DOM::DocumentImpl *document, const KHTMLSelection &selection)
+    : CompositeEditCommand(document)
 {
     setStartingSelection(selection);
 }
 
-DeleteSelectionStep::~DeleteSelectionStep()
+DeleteSelectionCommand::~DeleteSelectionCommand()
 {
 }
 	
-void DeleteSelectionStep::apply()
+void DeleteSelectionCommand::apply()
 {
     beginApply();
 
@@ -835,73 +903,86 @@ void DeleteSelectionStep::apply()
 }
 
 //------------------------------------------------------------------------------------------
+// InputTextCommand
 
-#pragma mark EditCommands
-
-//------------------------------------------------------------------------------------------
-// EditCommand
+InputTextCommand::InputTextCommand(DocumentImpl *document, const DOMString &text) 
+    : CompositeEditCommand(document)
+{
+    ASSERT(!text.isEmpty());
+    m_text = text; 
+}
 
-static int cookieCounter = 0;
+InputTextCommand::~InputTextCommand() 
+{
+}
 
-EditCommand::EditCommand(DocumentImpl *document) : CompositeEditStep(document)
+int InputTextCommand::commandID() const
 {
-    m_cookie = cookieCounter++;
+    return InputTextCommandID;
 }
 
-EditCommand::~EditCommand()
+bool InputTextCommand::isLineBreak(const DOM::DOMString &text) const
 {
+    return text.length() == 1 && (text[0] == '\n' || text[0] == '\r');
 }
 
-const KHTMLSelection &EditCommand::currentSelection() const
+bool InputTextCommand::isSpace(const DOM::DOMString &text) const
 {
-    ASSERT(document());
-    ASSERT(document()->part());
-    return document()->part()->selection();
+    return text.length() == 1 && (text[0] == ' ');
 }
 
-//------------------------------------------------------------------------------------------
-// InputTextCommand
+void InputTextCommand::apply()
+{
+    beginApply();
+    execute(m_text);
+    endApply();
+}
 
-InputTextCommand::InputTextCommand(DocumentImpl *document, const DOMString &text) 
-    : EditCommand(document)
+bool InputTextCommand::coalesce(const EditCommandPtr &cmd)
 {
-    if (text.isEmpty()) {
-#if APPLE_CHANGES
-        ERROR("InputTextCommand constructed with zero-length string");
-#endif
-        m_text = "";
-    }
-    else {
-        m_text = text; 
+    ASSERT(state() == APPLIED);
+    
+    if (cmd->commandID() == InputTextCommandID && endingSelection() == cmd->startingSelection()) {
+        // InputTextCommands coalesce with each other if they 
+        const InputTextCommand *c = static_cast<const InputTextCommand *>(cmd.get());
+        execute(c->text());
+        m_text += c->text();
+        moveToEndingSelection();
+        return true;
     }
+
+    return false;
 }
 
-bool InputTextCommand::isLineBreak() const
+bool InputTextCommand::groupForUndo(const EditCommandPtr &cmd) const
 {
-    return m_text.length() == 1 && (m_text[0] == '\n' || m_text[0] == '\r');
+    if ((cmd->commandID() == InputTextCommandID || cmd->commandID() == DeleteKeyCommandID) && startingSelection() == cmd->endingSelection()) {
+        return true;
+    }
+    return false;
 }
 
-bool InputTextCommand::isSpace() const
+bool InputTextCommand::groupForRedo(const EditCommandPtr &cmd) const
 {
-    return m_text.length() == 1 && (m_text[0] == ' ');
+    if ((cmd->commandID() == InputTextCommandID || cmd->commandID() == DeleteKeyCommandID) && endingSelection() == cmd->startingSelection()) {
+        return true;
+    }
+    return false;
 }
 
-void InputTextCommand::apply()
+void InputTextCommand::execute(const DOM::DOMString &text)
 {
-    KHTMLSelection selection = startingSelection();
+    KHTMLSelection selection = currentSelection();
 
     if (!selection.startNode()->isTextNode())
         return;
 
     // Delete the current selection
-    if (selection.state() == KHTMLSelection::RANGE) {
-        deleteSelection();
-    }
-    selection = currentSelection();
+    deleteSelection();
     
     TextImpl *textNode = static_cast<TextImpl *>(selection.startNode());
     
-    if (isLineBreak()) {
+    if (isLineBreak(text)) {
         int exceptionCode;
         ElementImpl *breakNode = document()->createHTMLElement("BR", exceptionCode);
 
@@ -910,12 +991,14 @@ void InputTextCommand::apply()
         if (atStart) {
             // Set the cursor at the beginning of text node now following the new BR.
             insertNodeBefore(breakNode, textNode);
-            moveSelectionTo(textNode, 0);
+            selection = KHTMLSelection(textNode, 0);
+            setEndingSelection(selection);
         }
         else if (atEnd) {
             insertNodeAfter(breakNode, textNode);
             // Set the cursor at the beginning of the the BR.
-            moveSelectionTo(selection.nextCharacterPosition());
+            selection = selection.nextCharacterPosition();
+            setEndingSelection(selection);
         }
         else {
             TextImpl *textBeforeNode = document()->createTextNode(textNode->substringData(0, selection.startOffset(), exceptionCode));
@@ -924,27 +1007,40 @@ void InputTextCommand::apply()
             insertNodeBefore(breakNode, textNode);
             textBeforeNode->deref();
             // Set the cursor at the beginning of the node after the BR.
-            moveSelectionTo(textNode, 0);
+            selection = KHTMLSelection(textNode, 0);
+            setEndingSelection(selection);
         }
         
         breakNode->deref();
     }
     else {
-        insertText(textNode, selection.startOffset(), text());
-        moveSelectionTo(selection.startNode(), selection.startOffset() + text().length());
+        insertText(textNode, selection.startOffset(), text);
+        selection = KHTMLSelection(selection.startNode(), selection.startOffset() + text.length());
+        setEndingSelection(selection);
     }
 }
 
 //------------------------------------------------------------------------------------------
-// DeleteTextCommand
+// DeleteKeyCommand
 
-DeleteTextCommand::DeleteTextCommand(DocumentImpl *document) 
-    : EditCommand(document)
+DeleteKeyCommand::DeleteKeyCommand(DocumentImpl *document) 
+    : CompositeEditCommand(document)
 {
 }
 
-void DeleteTextCommand::apply()
+DeleteKeyCommand::~DeleteKeyCommand() 
+{
+}
+
+int DeleteKeyCommand::commandID() const
+{
+    return DeleteKeyCommandID;
+}
+
+void DeleteKeyCommand::apply()
 {
+    beginApply();
+
     KHTMLPart *part = document()->part();
     ASSERT(part);
 
@@ -954,6 +1050,7 @@ void DeleteTextCommand::apply()
     // Delete the current selection
     if (selection.state() == KHTMLSelection::RANGE) {
         deleteSelection();
+        endApply();
         return;
     }
 
@@ -965,7 +1062,9 @@ void DeleteTextCommand::apply()
         if (offset >= caretNode->caretMinOffset()) {
             TextImpl *textNode = static_cast<TextImpl *>(caretNode);
             deleteText(textNode, offset, 1);
-            moveSelectionTo(textNode, offset);
+            selection = KHTMLSelection(textNode, offset);
+            setEndingSelection(selection);
+            endApply();
             return;
         }
         
@@ -973,6 +1072,7 @@ void DeleteTextCommand::apply()
         NodeImpl *previousSibling = caretNode->previousSibling();
         if (previousSibling->renderer() && previousSibling->renderer()->isBR()) {
             removeNode(previousSibling);
+            endApply();
             return;
         }
         
@@ -982,21 +1082,47 @@ void DeleteTextCommand::apply()
             TextImpl *textNode = static_cast<TextImpl *>(previousLeafNode);
             offset = previousLeafNode->caretMaxOffset() - 1;
             deleteText(textNode, offset, 1);
-            moveSelectionTo(textNode, offset);
+            selection = KHTMLSelection(textNode, offset);
+            setEndingSelection(selection);
+            endApply();
             return;
         }
     }
 }
 
-PasteHTMLCommand::PasteHTMLCommand(DocumentImpl *document, const DOM::DOMString &HTMLString) 
-: EditCommand(document)
+bool DeleteKeyCommand::groupForUndo(const EditCommandPtr &cmd) const
+{
+    if ((cmd->commandID() == InputTextCommandID || cmd->commandID() == DeleteKeyCommandID) && startingSelection() == cmd->endingSelection()) {
+        return true;
+    }
+
+    return false;
+}
+
+bool DeleteKeyCommand::groupForRedo(const EditCommandPtr &cmd) const
+{
+    if ((cmd->commandID() == InputTextCommandID || cmd->commandID() == DeleteKeyCommandID) && endingSelection() == cmd->startingSelection()) {
+        return true;
+    }
+
+    return false;
+}
+
+PasteHTMLCommand::PasteHTMLCommand(DocumentImpl *document, const DOMString &HTMLString) 
+    : CompositeEditCommand(document)
 {
     ASSERT(!HTMLString.isEmpty());
     m_HTMLString = HTMLString; 
 }
 
+PasteHTMLCommand::~PasteHTMLCommand()
+{
+}
+
 void PasteHTMLCommand::apply()
-{    
+{
+    beginApply();
+    
     DOM::DocumentFragmentImpl *root = static_cast<HTMLElementImpl *>(document()->documentElement())->createContextualFragment(m_HTMLString);
     ASSERT(root);
     
@@ -1020,8 +1146,10 @@ void PasteHTMLCommand::apply()
     if (textNode && firstChild == lastChild && firstChild->isTextNode()) {
         // Simple text paste. Add the text to the text node with the caret.
         insertText(textNode, startOffset, static_cast<TextImpl *>(firstChild)->data());
-        moveSelectionTo(textNode, startOffset + static_cast<TextImpl *>(firstChild)->length());
-    } else {
+        selection = KHTMLSelection(textNode, startOffset + static_cast<TextImpl *>(firstChild)->length());
+        setEndingSelection(selection);
+    } 
+    else {
         // HTML tree paste.
         DOM::NodeImpl *child = firstChild;
         DOM::NodeImpl *beforeNode = NULL;
@@ -1031,11 +1159,13 @@ void PasteHTMLCommand::apply()
             insertNodeBefore(child, startNode);
             beforeNode = child;
             child = nextSibling;
-        } else if (textNode && textNode->caretMaxOffset() != startOffset) {
+        } 
+        else if (textNode && textNode->caretMaxOffset() != startOffset) {
             // Caret is in middle of a text node. Split the text node and insert in between.
             splitTextNode(textNode, startOffset);
             beforeNode = textNode->previousSibling();
-        } else {
+        } 
+        else {
             // Caret is at the end of the node. Insert after it.
             beforeNode = startNode;
         }
@@ -1059,6 +1189,10 @@ void PasteHTMLCommand::apply()
             }
             child = nextChild;
         }
-        moveSelectionTo(child, child->caretMaxOffset());
+        selection = KHTMLSelection(child, child->caretMaxOffset());
+        setEndingSelection(selection);
     }
+
+    endApply();
 }
+
diff --git a/WebCore/khtml/editing/htmlediting.h b/WebCore/khtml/editing/htmlediting.h
index b146b00..8390655 100644
--- a/WebCore/khtml/editing/htmlediting.h
+++ b/WebCore/khtml/editing/htmlediting.h
@@ -30,7 +30,8 @@
 #include <dom_position.h>
 #include <dom_string.h>
 
-#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <shared.h>
 
 class KHTMLSelection;
 
@@ -46,35 +47,45 @@ namespace DOM {
 namespace khtml {
 
 //------------------------------------------------------------------------------------------
-// Edit result codes
+// EditCommand classes
 
-enum {
-    EditResultOK                 = 0,
-    EditResultFailed             = -1,
-    EditResultNoActionTaken      = -2,
-};
+class EditCommand;
 
-//------------------------------------------------------------------------------------------
-// EditStep classes
+typedef SharedPtr<EditCommand> EditCommandPtr;
 
-class EditStep
+enum EditCommandID { 
+    EditCommandID, 
+    InputTextCommandID, 
+    DeleteKeyCommandID,
+    MoveSelectionToCommandID, 
+};
+
+class EditCommand : public Shared<EditCommand>
 {
 public:
-	EditStep(DOM::DocumentImpl *);
-	virtual ~EditStep();
-	
-    enum EditStepState { NOT_APPLIED, APPLIED };
+	EditCommand(DOM::DocumentImpl *);
+	virtual ~EditCommand();
+
+    virtual int commandID() const;
+	QString name() const;
+
+    enum EditCommandState { NOT_APPLIED, APPLIED };
     
 	virtual void apply() = 0;	
 	virtual void unapply() = 0;
 	virtual void reapply();  // calls apply()
-        
+
+    virtual bool coalesce(const EditCommandPtr &);
+
+    virtual bool groupForUndo(const EditCommandPtr &) const;
+    virtual bool groupForRedo(const EditCommandPtr &) const;
+            
     DOM::DocumentImpl * const document() const { return m_document; }
-    EditStepState state() const { return m_state; }
 
     const KHTMLSelection &startingSelection() const { return m_startingSelection; }
     const KHTMLSelection &endingSelection() const { return m_endingSelection; }
-    
+    const KHTMLSelection &currentSelection() const;
+        
 protected:
     void beginApply();
     void endApply();
@@ -82,22 +93,28 @@ protected:
     void endUnapply();
     void beginReapply();
     void endReapply();
+    
+    EditCommandState state() const { return m_state; }
+    void setState(EditCommandState state) { m_state = state; }
 
     void setStartingSelection(const KHTMLSelection &s) { m_startingSelection = s; }
     void setEndingSelection(const KHTMLSelection &s) { m_endingSelection = s; }
 
+    void moveToStartingSelection();
+    void moveToEndingSelection();
+
 private:
     DOM::DocumentImpl *m_document;
-    EditStepState m_state;
+    EditCommandState m_state;
     KHTMLSelection m_startingSelection;
     KHTMLSelection m_endingSelection;
 };
 
-class CompositeEditStep : public EditStep
+class CompositeEditCommand : public EditCommand
 {
 public:
-	CompositeEditStep(DOM::DocumentImpl *);
-	virtual ~CompositeEditStep();
+	CompositeEditCommand(DOM::DocumentImpl *);
+	virtual ~CompositeEditCommand();
 	
 	virtual void apply() = 0;	
 	virtual void unapply();
@@ -105,9 +122,9 @@ public:
     
 protected:
     //
-    // sugary-sweet convenience functions to help create and apply edit steps
+    // sugary-sweet convenience functions to help create and apply edit commands in composite commands
     //
-    void applyStep(EditStep *step);
+    void applyCommand(const EditCommandPtr &step);
     void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
     void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
     void appendNode(DOM::NodeImpl *parent, DOM::NodeImpl *appendChild);
@@ -122,14 +139,14 @@ protected:
     void deleteSelection();
     void deleteSelection(const KHTMLSelection &selection);
 
-    QPtrList<EditStep> m_steps;
+    QValueList<EditCommandPtr> m_cmds;
 };
 
-class InsertNodeBeforeStep : public EditStep
+class InsertNodeBeforeCommand : public EditCommand
 {
 public:
-    InsertNodeBeforeStep(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
-	virtual ~InsertNodeBeforeStep();
+    InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
+	virtual ~InsertNodeBeforeCommand();
 
 	virtual void apply();
 	virtual void unapply();
@@ -139,11 +156,11 @@ private:
     DOM::NodeImpl *m_refChild;    
 };
 
-class AppendNodeStep : public EditStep
+class AppendNodeCommand : public EditCommand
 {
 public:
-    AppendNodeStep(DOM::DocumentImpl *, DOM::NodeImpl *parent, DOM::NodeImpl *appendChild);
-	virtual ~AppendNodeStep();
+    AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *parent, DOM::NodeImpl *appendChild);
+	virtual ~AppendNodeCommand();
 
 	virtual void apply();
 	virtual void unapply();
@@ -153,11 +170,11 @@ private:
     DOM::NodeImpl *m_appendChild;
 };
 
-class RemoveNodeStep : public EditStep
+class RemoveNodeCommand : public EditCommand
 {
 public:
-	RemoveNodeStep(DOM::DocumentImpl *, DOM::NodeImpl *);
-	virtual ~RemoveNodeStep();
+	RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
+	virtual ~RemoveNodeCommand();
 	
 	virtual void apply();
 	virtual void unapply();
@@ -168,58 +185,58 @@ private:
     DOM::NodeImpl *m_refChild;    
 };
 
-class ModifyTextNodeStep : public EditStep
+class ModifyTextNodeCommand : public EditCommand
 {
 public:
-    // used by SplitTextNodeStep derived class
-	ModifyTextNodeStep(DOM::DocumentImpl *, DOM::TextImpl *, long); 
-    // used by JoinTextNodesStep derived class
-    ModifyTextNodeStep(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
-	virtual ~ModifyTextNodeStep();
+    // used by SplitTextNodeCommand derived class
+	ModifyTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long); 
+    // used by JoinTextNodesCommand derived class
+    ModifyTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
+	virtual ~ModifyTextNodeCommand();
 	
 protected:
     void splitTextNode();
     void joinTextNodes();
 
-    virtual EditStepState joinState() = 0;
-    virtual EditStepState splitState() = 0;
+    virtual EditCommandState joinState() = 0;
+    virtual EditCommandState splitState() = 0;
 
     DOM::TextImpl *m_text1;
     DOM::TextImpl *m_text2;
     long m_offset;
 };
 
-class SplitTextNodeStep : public ModifyTextNodeStep
+class SplitTextNodeCommand : public ModifyTextNodeCommand
 {
 public:
-	SplitTextNodeStep(DOM::DocumentImpl *, DOM::TextImpl *, long);
-	virtual ~SplitTextNodeStep();
+	SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
+	virtual ~SplitTextNodeCommand();
 	
 	virtual void apply();
 	virtual void unapply();
 
-    virtual EditStepState joinState() { return APPLIED; }
-    virtual EditStepState splitState() { return NOT_APPLIED; }
+    virtual EditCommandState joinState() { return APPLIED; }
+    virtual EditCommandState splitState() { return NOT_APPLIED; }
 };
 
-class JoinTextNodesStep : public ModifyTextNodeStep
+class JoinTextNodesCommand : public ModifyTextNodeCommand
 {
 public:
-	JoinTextNodesStep(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
-	virtual ~JoinTextNodesStep();
+	JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
+	virtual ~JoinTextNodesCommand();
 	
 	virtual void apply();
 	virtual void unapply();
 
-    virtual EditStepState joinState() { return NOT_APPLIED; }
-    virtual EditStepState splitState() { return APPLIED; }
+    virtual EditCommandState joinState() { return NOT_APPLIED; }
+    virtual EditCommandState splitState() { return APPLIED; }
 };
 
-class InsertTextStep : public EditStep
+class InsertTextCommand : public EditCommand
 {
 public:
-	InsertTextStep(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
-	virtual ~InsertTextStep();
+	InsertTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
+	virtual ~InsertTextCommand();
 	
 	virtual void apply();
 	virtual void unapply();
@@ -230,11 +247,11 @@ private:
     DOM::DOMString m_text;
 };
 
-class DeleteTextStep : public EditStep
+class DeleteTextCommand : public EditCommand
 {
 public:
-	DeleteTextStep(DOM::DocumentImpl *document, DOM::TextImpl *, long offset, long count);
-	virtual ~DeleteTextStep();
+	DeleteTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *, long offset, long count);
+	virtual ~DeleteTextCommand();
 	
 	virtual void apply();
 	virtual void unapply();
@@ -246,79 +263,77 @@ private:
     DOM::DOMString m_text;
 };
 
-class MoveSelectionToStep : public EditStep
+class MoveSelectionToCommand : public EditCommand
 {
 public:
-	MoveSelectionToStep(DOM::DocumentImpl *document, const KHTMLSelection &selection);
-	MoveSelectionToStep(DOM::DocumentImpl *document, DOM::NodeImpl *, long);
-	MoveSelectionToStep(DOM::DocumentImpl *document, const DOM::DOMPosition &);
-	virtual ~MoveSelectionToStep() {};
+	MoveSelectionToCommand(DOM::DocumentImpl *document, const KHTMLSelection &selection);
+	MoveSelectionToCommand(DOM::DocumentImpl *document, DOM::NodeImpl *, long);
+	MoveSelectionToCommand(DOM::DocumentImpl *document, const DOM::DOMPosition &);
+	virtual ~MoveSelectionToCommand();
+
+    virtual int commandID() const;
 	
 	virtual void apply();
 	virtual void unapply();
 };
 
-class DeleteSelectionStep : public CompositeEditStep
+class DeleteSelectionCommand : public CompositeEditCommand
 {
 public:
-	DeleteSelectionStep(DOM::DocumentImpl *document);
-	DeleteSelectionStep(DOM::DocumentImpl *document, const KHTMLSelection &);
-	virtual ~DeleteSelectionStep();
+	DeleteSelectionCommand(DOM::DocumentImpl *document);
+	DeleteSelectionCommand(DOM::DocumentImpl *document, const KHTMLSelection &);
+	virtual ~DeleteSelectionCommand();
 	
 	virtual void apply();
 };
 
-//------------------------------------------------------------------------------------------
-// EditCommand
-
-class EditCommand : public CompositeEditStep
+class InputTextCommand : public CompositeEditCommand
 {
-public:    
-    EditCommand(DOM::DocumentImpl *document);
-    virtual ~EditCommand();
+public:
+    InputTextCommand(DOM::DocumentImpl *document, const DOM::DOMString &text);
+    virtual ~InputTextCommand();
 
-    const KHTMLSelection &currentSelection() const;
+    virtual int commandID() const;
 
-    virtual void apply() = 0;
+    virtual void apply();
 
-    int cookie() const { return m_cookie; }
-    
-private:
-    int m_cookie;
-};
+    virtual bool coalesce(const EditCommandPtr &);
 
-class InputTextCommand : public EditCommand
-{
-public:
-    InputTextCommand(DOM::DocumentImpl *document, const DOM::DOMString &text);
-    virtual ~InputTextCommand() {};
-    
-    virtual void apply();
+    virtual bool groupForUndo(const EditCommandPtr &) const;
+    virtual bool groupForRedo(const EditCommandPtr &) const;
 
     DOM::DOMString text() const { return m_text; }
-    bool isLineBreak() const;
-    bool isSpace() const;
+    bool isLineBreak(const DOM::DOMString &text) const;
+    bool isSpace(const DOM::DOMString &text) const;
     
 private:
+    void execute(const DOM::DOMString &text);
+
     DOM::DOMString m_text;
 };
 
-class DeleteTextCommand : public EditCommand
+class DeleteKeyCommand : public CompositeEditCommand
 {
 public:
-    DeleteTextCommand(DOM::DocumentImpl *document);
-    virtual ~DeleteTextCommand() {};
+    DeleteKeyCommand(DOM::DocumentImpl *document);
+    virtual ~DeleteKeyCommand();
     
+    virtual int commandID() const;
+
     virtual void apply();
+
+    virtual bool groupForUndo(const EditCommandPtr &) const;
+    virtual bool groupForRedo(const EditCommandPtr &) const;
 };
 
-class PasteHTMLCommand : public EditCommand
+class PasteHTMLCommand : public CompositeEditCommand
 {
 public:
     PasteHTMLCommand(DOM::DocumentImpl *document, const DOM::DOMString &HTMLString);
-    virtual ~PasteHTMLCommand() {};
+    virtual ~PasteHTMLCommand();
     
     virtual void apply();
+
 private:
     DOM::DOMString m_HTMLString;
 };
diff --git a/WebCore/khtml/khtml_part.cpp b/WebCore/khtml/khtml_part.cpp
index 8c23ced..fa53c24 100644
--- a/WebCore/khtml/khtml_part.cpp
+++ b/WebCore/khtml/khtml_part.cpp
@@ -99,8 +99,10 @@ using namespace DOM;
 #endif
 
 using khtml::Decoder;
-using khtml::DeleteTextCommand;
+using khtml::DeleteKeyCommand;
+using khtml::DeleteSelectionCommand;
 using khtml::EditCommand;
+using khtml::EditCommandPtr;
 using khtml::InlineTextBox;
 using khtml::PasteHTMLCommand;
 using khtml::RenderObject;
@@ -388,7 +390,15 @@ bool KHTMLPart::openURL( const KURL &url )
   }
   
   cancelRedirection();
-
+  
+  // clear edit commands
+  d->m_undoEditCommands.clear();
+  d->m_redoEditCommands.clear();
+  d->m_lastEditCommand = EditCommandPtr(0);
+#if APPLE_CHANGES
+  KWQ(this)->clearUndoRedoOperations();
+#endif
+  
 #if !APPLE_CHANGES
   // check to see if this is an "error://" URL. This is caused when an error
   // occurs before this part was loaded (e.g. KonqRun), and is passed to
@@ -2474,7 +2484,7 @@ void KHTMLPart::clearSelection()
 
 void KHTMLPart::deleteSelection()
 {
-    DeleteTextCommand *cmd = new DeleteTextCommand(d->m_doc);
+    EditCommandPtr cmd(new DeleteSelectionCommand(d->m_doc));
     applyCommand(cmd);
 }
 
@@ -5058,74 +5068,81 @@ bool KHTMLPart::isEditingAtCaret() const
     return false;
 }
 
-void KHTMLPart::applyCommand(EditCommand *cmd)
+void KHTMLPart::applyCommand(const khtml::EditCommandPtr &cmd)
 {
-    cmd->apply();
-    
-    // clear redo commands
-    QPtrListIterator<EditCommand> it(d->m_redoEditCommands);
-    for (; it.current(); ++it)
-        delete it.current();
-    d->m_redoEditCommands.clear();
+    if (d->m_lastEditCommand.isEmpty() || !d->m_lastEditCommand->coalesce(cmd)) {
+        cmd->apply();
+
+        // add to undo commands
+        d->m_undoEditCommands.append(cmd);
 
-    // add to undo commands
-    d->m_undoEditCommands.append(cmd);
 #if APPLE_CHANGES
-    KWQ(this)->registerCommandForUndo(cmd->cookie());
+        if (d->m_lastEditCommand.isEmpty() || !cmd->groupForUndo(d->m_lastEditCommand))
+            KWQ(this)->registerCommandForUndo();
 #endif
-}
 
-#if APPLE_CHANGES
-void KHTMLPart::undoRedoEditing(int cookie)
-{
-    EditCommand *undoCommand = d->m_undoEditCommands.last();
-    if (undoCommand && undoCommand->cookie() == cookie) {
-        undoEditing();
-        return;
-    }
-    
-    EditCommand *redoCommand = d->m_redoEditCommands.last();
-    if (redoCommand && redoCommand->cookie() == cookie) {
-        redoEditing();
-        return;
+        d->m_lastEditCommand = cmd;
     }
 
-    // should not reach this code
-    assert(0);
+    // always clear redo commands
+    d->m_redoEditCommands.clear();
 }
-#endif
 
 void KHTMLPart::undoEditing()
 {
-    EditCommand *cmd = d->m_undoEditCommands.last();
-
-    cmd->unapply();
-
-    d->m_undoEditCommands.removeLast();
-    d->m_redoEditCommands.append(cmd);
+    EditCommandPtr cmd;
+    EditCommandPtr next;
+    
+    do {
+        assert(d->m_undoEditCommands.count() > 0);
+        cmd = d->m_undoEditCommands.last();
+        
+        cmd->unapply();
 
+        // EDIT FIXME: Removal is O(N). Improve QValueList to implement 0(1) removal of last element. 
+        d->m_undoEditCommands.remove(cmd); 
+        d->m_redoEditCommands.append(cmd);
+    
+        next = d->m_undoEditCommands.count() > 0 ? d->m_undoEditCommands.last() : EditCommandPtr(0);
+    } 
+    while (!next.isEmpty() && cmd->groupForUndo(next));
+    
+    d->m_lastEditCommand = EditCommandPtr(0);
+    
 #if APPLE_CHANGES
-    KWQ(this)->registerCommandForUndo(cmd->cookie());
+    KWQ(this)->registerCommandForRedo();
 #endif
 }
 
 void KHTMLPart::redoEditing()
 {
-    EditCommand *cmd = d->m_redoEditCommands.last();
+    EditCommandPtr cmd;
+    EditCommandPtr next;
 
-    cmd->reapply();
+    do {
+        assert(d->m_redoEditCommands.count() > 0);
+        cmd = d->m_redoEditCommands.last();
+    
+        cmd->reapply();
 
-    d->m_redoEditCommands.removeLast();
-    d->m_undoEditCommands.append(cmd);
+        // EDIT FIXME: Removal is O(N). Improve QValueList to implement 0(1) removal of last element. 
+        d->m_redoEditCommands.remove(cmd); 
+        d->m_undoEditCommands.append(cmd);
 
+        next = d->m_redoEditCommands.count() > 0 ? d->m_redoEditCommands.last() : EditCommandPtr(0);
+    }
+    while (!next.isEmpty() && cmd->groupForRedo(next));
+
+    d->m_lastEditCommand = EditCommandPtr(0);
+    
 #if APPLE_CHANGES
-    KWQ(this)->registerCommandForUndo(cmd->cookie());
+    KWQ(this)->registerCommandForUndo();
 #endif
 }
 
 void KHTMLPart::pasteHTMLString(const QString &HTMLString)
 {
-    PasteHTMLCommand *cmd = new PasteHTMLCommand(d->m_doc, DOMString(HTMLString));
+    EditCommandPtr cmd(new PasteHTMLCommand(d->m_doc, DOMString(HTMLString)));
     applyCommand(cmd);
 }
 
diff --git a/WebCore/khtml/khtml_part.h b/WebCore/khtml/khtml_part.h
index 6346caf..096887a 100644
--- a/WebCore/khtml/khtml_part.h
+++ b/WebCore/khtml/khtml_part.h
@@ -30,6 +30,7 @@
 #include "dom/html_document.h"
 #include "dom/dom2_range.h"
 #include "dom/dom_misc.h"
+#include "editing/htmlediting.h"
 
 #include <kparts/part.h>
 #include <kparts/browserextension.h>
@@ -64,6 +65,7 @@ namespace DOM
 }
 
 using DOM::TristateFlag;
+using khtml::EditCommandPtr;
 
 namespace khtml
 {
@@ -83,7 +85,7 @@ namespace khtml
   class RenderPartObject;
   class RenderWidget;
   class XMLTokenizer;
-}
+};
 
 namespace KJS {
     class Window;
@@ -625,19 +627,9 @@ public:
   bool isEditingAtCaret() const;
 
   /**
-   * Applies the give edit command.
+   * Applies the given edit command.
    */
-  void applyCommand(khtml::EditCommand *);
-
-#if APPLE_CHANGES
-  /**
-   * Performs an undo or redo of the most previous edit
-   * by examining the undo and redo command list and
-   * matching the top item against the cookie passed in.
-   * A hack, but it helps us to hook into Cocoa undo/redo.
-   */
-  void undoRedoEditing(int cookie);
-#endif
+  void applyCommand(const khtml::EditCommandPtr &);
 
   /**
    * Performs an undo of the edit.
diff --git a/WebCore/khtml/khtmlpart_p.h b/WebCore/khtml/khtmlpart_p.h
index 7d5e4d4..b204312 100644
--- a/WebCore/khtml/khtmlpart_p.h
+++ b/WebCore/khtml/khtmlpart_p.h
@@ -214,16 +214,6 @@ public:
 #ifndef Q_WS_QWS
     delete m_javaContext;
 #endif
-    
-    QPtrListIterator<khtml::EditCommand> undos(m_undoEditCommands);
-    for (; undos.current(); ++undos) {
-        delete undos.current();
-    }
-    QPtrListIterator<khtml::EditCommand> redos(m_redoEditCommands);
-    for (; redos.current(); ++redos) {
-        delete redos.current();
-    }
-
   }
 
   FrameList m_frames;
@@ -375,8 +365,9 @@ public:
   bool m_focusNodeRestored:1;
 
   TristateFlag m_inEditMode;
-  QPtrList<khtml::EditCommand> m_undoEditCommands;
-  QPtrList<khtml::EditCommand> m_redoEditCommands;
+  QValueList<khtml::EditCommandPtr> m_undoEditCommands;
+  QValueList<khtml::EditCommandPtr> m_redoEditCommands;
+  khtml::EditCommandPtr m_lastEditCommand;
 
   int m_focusNodeNumber;
 
diff --git a/WebCore/khtml/misc/shared.h b/WebCore/khtml/misc/shared.h
index 09994d3..8f6b858 100644
--- a/WebCore/khtml/misc/shared.h
+++ b/WebCore/khtml/misc/shared.h
@@ -52,6 +52,49 @@ protected:
     type *m_parent;
 };
 
+template <class T> class SharedPtr
+{
+public:
+    SharedPtr() : m_ptr(0) {}
+	explicit SharedPtr(T *ptr) : m_ptr(ptr) { if (m_ptr) m_ptr->ref(); }
+	SharedPtr(const SharedPtr &o) : m_ptr(o.m_ptr) { if (m_ptr) m_ptr->ref(); }
+    ~SharedPtr() { if (m_ptr) m_ptr->deref(); }
+	
+    bool isEmpty() const { return m_ptr == 0; }
+    
+    T * get() const { return m_ptr; }
+	T &operator*() const { return *m_ptr; }
+	T *operator->() const { return m_ptr; }
+
+	bool operator!() const { return m_ptr == 0; }
+
+	inline friend bool operator==(const SharedPtr &a, const SharedPtr &b) { return a.m_ptr == b.m_ptr; }
+	inline friend bool operator==(const SharedPtr &a, const T *b) { return a.m_ptr == b; }
+	inline friend bool operator==(const T *a, const SharedPtr &b) { return a == b.m_ptr; }
+
+	SharedPtr &operator=(const SharedPtr &);
+
+private:
+	T* m_ptr;
+};
+
+template <class T> SharedPtr<T> &SharedPtr<T>::operator=(const SharedPtr<T> &o) 
+{
+	if (m_ptr != o.m_ptr) {
+		if (m_ptr)
+            m_ptr->deref();
+		m_ptr = o.m_ptr;
+		if (m_ptr) 
+            m_ptr->ref();
+	}
+	
+	return *this;
+}
+
+template <class T> inline bool operator!=(const SharedPtr<T> &a, const SharedPtr<T> &b) { return !(a==b); }
+template <class T> inline bool operator!=(const SharedPtr<T> &a, const T *b) { return !(a == b); }
+template <class T> inline bool operator!=(const T *a, const SharedPtr<T> &b) { return !(a == b); }
+
 };
 
 #endif
diff --git a/WebCore/khtml/xml/dom_elementimpl.cpp b/WebCore/khtml/xml/dom_elementimpl.cpp
index cd02d66..ac93325 100644
--- a/WebCore/khtml/xml/dom_elementimpl.cpp
+++ b/WebCore/khtml/xml/dom_elementimpl.cpp
@@ -366,11 +366,11 @@ void ElementImpl::defaultEventHandler(EventImpl *evt)
 {
     if (evt->id() == EventImpl::KEYPRESS_EVENT && isContentEditable()) {
         KeyboardEventImpl *k = static_cast<KeyboardEventImpl *>(evt);
-        EditCommand *cmd = 0;
+        EditCommandPtr cmd;
         if (k->keyIdentifier() == "U+00007F" || 
             k->keyIdentifier() == "U+000008" || 
             k->keyIdentifier() == "ForwardDelete") {
-            cmd = new DeleteTextCommand(getDocument());
+            cmd = EditCommandPtr(new DeleteKeyCommand(getDocument()));
         }
         else if (k->keyIdentifier() == "Right") {
             KHTMLPart *part = getDocument()->part();
@@ -398,9 +398,9 @@ void ElementImpl::defaultEventHandler(EventImpl *evt)
         }
         else {
             QString text(k->qKeyEvent()->text());
-            cmd = new InputTextCommand(getDocument(), text);
+            cmd = EditCommandPtr(new InputTextCommand(getDocument(), text));
         }
-        if (cmd) {
+        if (!cmd.isEmpty()) {
             KHTMLPart *part = getDocument()->part();
             if (part) {
                 part->applyCommand(cmd);
diff --git a/WebCore/kwq/KWQKHTMLPart.h b/WebCore/kwq/KWQKHTMLPart.h
index f143620..97633ad 100644
--- a/WebCore/kwq/KWQKHTMLPart.h
+++ b/WebCore/kwq/KWQKHTMLPart.h
@@ -257,7 +257,9 @@ public:
     void addPluginRootObject(const KJS::Bindings::RootObject *root);
     void cleanupPluginRootObjects();
     
-    void registerCommandForUndo(int cookie);
+    void registerCommandForUndo();
+    void registerCommandForRedo();
+    void clearUndoRedoOperations();
     
 private:
     virtual void khtmlMousePressEvent(khtml::MousePressEvent *);
diff --git a/WebCore/kwq/KWQKHTMLPart.mm b/WebCore/kwq/KWQKHTMLPart.mm
index b315e9d..99fb334 100644
--- a/WebCore/kwq/KWQKHTMLPart.mm
+++ b/WebCore/kwq/KWQKHTMLPart.mm
@@ -35,6 +35,7 @@
 #import "KWQWindowWidget.h"
 #import "WebCoreBridge.h"
 #import "WebCoreDOMPrivate.h"
+#import "WebCoreEditing.h"
 #import "WebCoreViewFactory.h"
 #import "csshelper.h"
 #import "html_documentimpl.h"
@@ -2825,7 +2826,17 @@ void KWQKHTMLPart::cleanupPluginRootObjects()
     }
 }
 
-void KWQKHTMLPart::registerCommandForUndo(int cookie)
+void KWQKHTMLPart::registerCommandForUndo()
 {
-    [_bridge registerCommandForUndo:cookie];
+    [_bridge registerCommandForUndo];
+}
+
+void KWQKHTMLPart::registerCommandForRedo()
+{
+    [_bridge registerCommandForRedo];
+}
+
+void KWQKHTMLPart::clearUndoRedoOperations()
+{
+    [_bridge clearUndoRedoOperations];
 }
diff --git a/WebCore/kwq/WebCoreBridge.h b/WebCore/kwq/WebCoreBridge.h
index 786ec87..4263ef6 100644
--- a/WebCore/kwq/WebCoreBridge.h
+++ b/WebCore/kwq/WebCoreBridge.h
@@ -248,7 +248,8 @@ typedef enum {
 
 - (NSString *)reconstructedSource;
 
-- (void)undoRedoEditing:(id)object;
+- (void)undoEditing:(id)arg;
+- (void)redoEditing:(id)arg;
 
 @end
 
@@ -386,7 +387,9 @@ typedef enum {
 
 - (jobject)pollForAppletInView:(NSView *)view;
 
-- (void)registerCommandForUndo:(int)cookie;
+- (void)registerCommandForUndo;
+- (void)registerCommandForRedo;
+- (void)clearUndoRedoOperations;
 
 @end
 
diff --git a/WebCore/kwq/WebCoreBridge.mm b/WebCore/kwq/WebCoreBridge.mm
index c499ad3..de0b969 100644
--- a/WebCore/kwq/WebCoreBridge.mm
+++ b/WebCore/kwq/WebCoreBridge.mm
@@ -29,6 +29,7 @@
 #import "dom_node.h"
 #import "dom_docimpl.h"
 #import "dom_nodeimpl.h"
+#import "htmlediting.h"
 #import "html_documentimpl.h"
 #import "html_formimpl.h"
 #import "html_imageimpl.h"
@@ -64,6 +65,7 @@
 #import "KWQAccObjectCache.h"
 
 #import "WebCoreDOMPrivate.h"
+#import "WebCoreEditing.h"
 #import "WebCoreImageRenderer.h"
 #import "WebCoreTextRendererFactory.h"
 #import "WebCoreViewFactory.h"
@@ -1201,10 +1203,14 @@ static HTMLFormElementImpl *formElementFromDOMElement(id <WebDOMElement>element)
     return string;
 }
 
-- (void)undoRedoEditing:(id)object
+- (void)undoEditing:(id)arg
 {
-    NSNumber *number = (NSNumber *)object;
-    _part->undoRedoEditing([number intValue]);
+    _part->undoEditing();
+}
+
+- (void)redoEditing:(id)arg
+{
+    _part->redoEditing();
 }
 
 @end
diff --git a/WebKit/ChangeLog b/WebKit/ChangeLog
index f95727a..f022da5 100644
--- a/WebKit/ChangeLog
+++ b/WebKit/ChangeLog
@@ -1,3 +1,19 @@
+2004-02-10  Ken Kocienda  <kocienda at apple.com>
+
+        Reviewed by Hyatt
+
+        * WebCoreSupport.subproj/WebBridge.m:
+        (-[WebBridge registerCommandForUndo]): Some cleanup. Cookie for events no longer needed.
+        (-[WebBridge registerCommandForRedo]): Ditto.
+        (-[WebBridge clearUndoRedoOperations]): Tells the Cocoa undo manager to clear
+        steps targeted at the bridge.
+        * WebView.subproj/WebFrame.h: Declare undo manager accessor.
+        * WebView.subproj/WebFrame.m:
+        (-[WebFramePrivate dealloc]): Release undo manager
+        (-[WebFrame undoManager]): Allocate and return an undo manager. This helps
+        undo in a browser to be per tab.
+        * WebView.subproj/WebFramePrivate.h: Declare undo manager ivar.
+
 2004-02-08  Darin Adler  <darin at apple.com>
 
         Reviewed by Dave.
diff --git a/WebKit/WebCoreSupport.subproj/WebBridge.m b/WebKit/WebCoreSupport.subproj/WebBridge.m
index 74ab667..28545cd 100644
--- a/WebKit/WebCoreSupport.subproj/WebBridge.m
+++ b/WebKit/WebCoreSupport.subproj/WebBridge.m
@@ -1161,10 +1161,22 @@ static id <WebFormDelegate> formDelegate(WebBridge *self)
     return applet;
 }
 
-- (void)registerCommandForUndo:(int)cookie
+- (void)registerCommandForUndo
 {
-    NSUndoManager *undoManager = [[_frame webView] undoManager];
-    [undoManager registerUndoWithTarget:self selector:@selector(undoRedoEditing:) object:[NSNumber numberWithInt:cookie]];
+    NSUndoManager *undoManager = [_frame undoManager];
+    [undoManager registerUndoWithTarget:self selector:@selector(undoEditing:) object:nil];
+}
+
+- (void)registerCommandForRedo
+{
+    NSUndoManager *undoManager = [_frame undoManager];
+    [undoManager registerUndoWithTarget:self selector:@selector(redoEditing:) object:nil];
+}
+
+- (void)clearUndoRedoOperations
+{
+    NSUndoManager *undoManager = [_frame undoManager];
+    [undoManager removeAllActionsWithTarget:self];
 }
 
 @end
diff --git a/WebKit/WebView.subproj/WebFrame.h b/WebKit/WebView.subproj/WebFrame.h
index f5615f9..eb9fd9d 100644
--- a/WebKit/WebView.subproj/WebFrame.h
+++ b/WebKit/WebView.subproj/WebFrame.h
@@ -131,4 +131,6 @@
 */
 - (NSArray *)childFrames;
 
+- (NSUndoManager *)undoManager;
+
 @end
diff --git a/WebKit/WebView.subproj/WebFrame.m b/WebKit/WebView.subproj/WebFrame.m
index 46fb02b..a11795c 100644
--- a/WebKit/WebView.subproj/WebFrame.m
+++ b/WebKit/WebView.subproj/WebFrame.m
@@ -169,6 +169,9 @@ NSString *WebPageCacheDocumentViewKey = @"WebPageCacheDocumentViewKey";
     [provisionalItem release];
     [previousItem release];
     
+    [undoManager release];
+    undoManager = nil;
+    
     ASSERT(listener == nil);
     ASSERT(policyRequest == nil);
     ASSERT(policyFrameName == nil);
@@ -2572,4 +2575,12 @@ static CFAbsoluteTime _timeOfLastCompletedLoad;
     return [[_private->children copy] autorelease];
 }
 
+- (NSUndoManager *)undoManager
+{
+    if (!_private->undoManager) {
+        _private->undoManager = [[NSUndoManager alloc] init];
+    }
+    return _private->undoManager;
+}
+
 @end
diff --git a/WebKit/WebView.subproj/WebFramePrivate.h b/WebKit/WebView.subproj/WebFramePrivate.h
index 8158553..cebed04 100644
--- a/WebKit/WebView.subproj/WebFramePrivate.h
+++ b/WebKit/WebView.subproj/WebFramePrivate.h
@@ -84,6 +84,7 @@ extern NSString *WebPageCacheDocumentViewKey;
     WebFormState *policyFormState;
     WebDataSource *policyDataSource;
     WebFrameLoadType policyLoadType;
+    NSUndoManager *undoManager;
 
     BOOL justOpenedForTargetedLink;
     BOOL quickRedirectComing;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list