1 /* 2 * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "EditCommand.h" 28 29 #include "CompositeEditCommand.h" 30 #include "CSSComputedStyleDeclaration.h" 31 #include "CSSMutableStyleDeclaration.h" 32 #include "DeleteButtonController.h" 33 #include "Document.h" 34 #include "Editor.h" 35 #include "Element.h" 36 #include "EventNames.h" 37 #include "Frame.h" 38 #include "SelectionController.h" 39 #include "VisiblePosition.h" 40 #include "htmlediting.h" 41 42 namespace WebCore { 43 44 EditCommand::EditCommand(Document* document) 45 : m_document(document) 46 , m_parent(0) 47 { 48 ASSERT(m_document); 49 ASSERT(m_document->frame()); 50 setStartingSelection(avoidIntersectionWithNode(m_document->frame()->selection()->selection(), m_document->frame()->editor()->deleteButtonController()->containerElement())); 51 setEndingSelection(m_startingSelection); 52 } 53 54 EditCommand::~EditCommand() 55 { 56 } 57 58 void EditCommand::apply() 59 { 60 ASSERT(m_document); 61 ASSERT(m_document->frame()); 62 63 Frame* frame = m_document->frame(); 64 65 if (!m_parent) { 66 if (!endingSelection().isContentRichlyEditable()) { 67 switch (editingAction()) { 68 case EditActionTyping: 69 case EditActionPaste: 70 case EditActionDrag: 71 case EditActionSetWritingDirection: 72 case EditActionCut: 73 case EditActionUnspecified: 74 break; 75 default: 76 ASSERT_NOT_REACHED(); 77 return; 78 } 79 } 80 } 81 82 // Changes to the document may have been made since the last editing operation that 83 // require a layout, as in <rdar://problem/5658603>. Low level operations, like 84 // RemoveNodeCommand, don't require a layout because the high level operations that 85 // use them perform one if one is necessary (like for the creation of VisiblePositions). 86 if (!m_parent) 87 updateLayout(); 88 89 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); 90 deleteButtonController->disable(); 91 doApply(); 92 deleteButtonController->enable(); 93 94 if (!m_parent) { 95 updateLayout(); 96 // Only need to call appliedEditing for top-level commands, and TypingCommands do it on their 97 // own (see TypingCommand::typingAddedToOpenCommand). 98 if (!isTypingCommand()) 99 frame->editor()->appliedEditing(this); 100 } 101 } 102 103 void EditCommand::unapply() 104 { 105 ASSERT(m_document); 106 ASSERT(m_document->frame()); 107 108 Frame* frame = m_document->frame(); 109 110 // Changes to the document may have been made since the last editing operation that 111 // require a layout, as in <rdar://problem/5658603>. Low level operations, like 112 // RemoveNodeCommand, don't require a layout because the high level operations that 113 // use them perform one if one is necessary (like for the creation of VisiblePositions). 114 if (!m_parent) 115 updateLayout(); 116 117 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); 118 deleteButtonController->disable(); 119 doUnapply(); 120 deleteButtonController->enable(); 121 122 if (!m_parent) { 123 updateLayout(); 124 frame->editor()->unappliedEditing(this); 125 } 126 } 127 128 void EditCommand::reapply() 129 { 130 ASSERT(m_document); 131 ASSERT(m_document->frame()); 132 133 Frame* frame = m_document->frame(); 134 135 // Changes to the document may have been made since the last editing operation that 136 // require a layout, as in <rdar://problem/5658603>. Low level operations, like 137 // RemoveNodeCommand, don't require a layout because the high level operations that 138 // use them perform one if one is necessary (like for the creation of VisiblePositions). 139 if (!m_parent) 140 updateLayout(); 141 142 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); 143 deleteButtonController->disable(); 144 doReapply(); 145 deleteButtonController->enable(); 146 147 if (!m_parent) { 148 updateLayout(); 149 frame->editor()->reappliedEditing(this); 150 } 151 } 152 153 void EditCommand::doReapply() 154 { 155 doApply(); 156 } 157 158 EditAction EditCommand::editingAction() const 159 { 160 return EditActionUnspecified; 161 } 162 163 void EditCommand::setStartingSelection(const VisibleSelection& s) 164 { 165 Element* root = s.rootEditableElement(); 166 for (EditCommand* cmd = this; ; cmd = cmd->m_parent) { 167 cmd->m_startingSelection = s; 168 cmd->m_startingRootEditableElement = root; 169 if (!cmd->m_parent || cmd->m_parent->isFirstCommand(cmd)) 170 break; 171 } 172 } 173 174 void EditCommand::setEndingSelection(const VisibleSelection &s) 175 { 176 Element* root = s.rootEditableElement(); 177 for (EditCommand* cmd = this; cmd; cmd = cmd->m_parent) { 178 cmd->m_endingSelection = s; 179 cmd->m_endingRootEditableElement = root; 180 } 181 } 182 183 bool EditCommand::preservesTypingStyle() const 184 { 185 return false; 186 } 187 188 bool EditCommand::isInsertTextCommand() const 189 { 190 return false; 191 } 192 193 bool EditCommand::isTypingCommand() const 194 { 195 return false; 196 } 197 198 199 void EditCommand::updateLayout() const 200 { 201 document()->updateLayoutIgnorePendingStylesheets(); 202 } 203 204 void EditCommand::setParent(CompositeEditCommand* parent) 205 { 206 ASSERT(parent); 207 ASSERT(!m_parent); 208 m_parent = parent; 209 m_startingSelection = parent->m_endingSelection; 210 m_endingSelection = parent->m_endingSelection; 211 m_startingRootEditableElement = parent->m_endingRootEditableElement; 212 m_endingRootEditableElement = parent->m_endingRootEditableElement; 213 } 214 215 void applyCommand(PassRefPtr<EditCommand> command) 216 { 217 command->apply(); 218 } 219 220 } // namespace WebCore 221