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 "DeleteButtonController.h" 31 #include "Document.h" 32 #include "Editor.h" 33 #include "Element.h" 34 #include "EventNames.h" 35 #include "Frame.h" 36 #include "ScopedEventQueue.h" 37 #include "SelectionController.h" 38 #include "VisiblePosition.h" 39 #include "htmlediting.h" 40 41 namespace WebCore { 42 43 EditCommand::EditCommand(Document* document) 44 : m_document(document) 45 , m_parent(0) 46 { 47 ASSERT(m_document); 48 ASSERT(m_document->frame()); 49 setStartingSelection(avoidIntersectionWithNode(m_document->frame()->selection()->selection(), m_document->frame()->editor()->deleteButtonController()->containerElement())); 50 setEndingSelection(m_startingSelection); 51 } 52 53 EditCommand::~EditCommand() 54 { 55 } 56 57 void EditCommand::apply() 58 { 59 ASSERT(m_document); 60 ASSERT(m_document->frame()); 61 62 Frame* frame = m_document->frame(); 63 64 if (isTopLevelCommand()) { 65 if (!endingSelection().isContentRichlyEditable()) { 66 switch (editingAction()) { 67 case EditActionTyping: 68 case EditActionPaste: 69 case EditActionDrag: 70 case EditActionSetWritingDirection: 71 case EditActionCut: 72 case EditActionUnspecified: 73 break; 74 default: 75 ASSERT_NOT_REACHED(); 76 return; 77 } 78 } 79 } 80 81 // Changes to the document may have been made since the last editing operation that 82 // require a layout, as in <rdar://problem/5658603>. Low level operations, like 83 // RemoveNodeCommand, don't require a layout because the high level operations that 84 // use them perform one if one is necessary (like for the creation of VisiblePositions). 85 if (isTopLevelCommand()) 86 updateLayout(); 87 88 { 89 EventQueueScope scope; 90 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); 91 deleteButtonController->disable(); 92 doApply(); 93 deleteButtonController->enable(); 94 } 95 96 if (isTopLevelCommand()) { 97 // Only need to call appliedEditing for top-level commands, and TypingCommands do it on their 98 // own (see TypingCommand::typingAddedToOpenCommand). 99 if (!isTypingCommand()) 100 frame->editor()->appliedEditing(this); 101 } 102 103 setShouldRetainAutocorrectionIndicator(false); 104 } 105 106 void EditCommand::unapply() 107 { 108 ASSERT(m_document); 109 ASSERT(m_document->frame()); 110 111 Frame* frame = m_document->frame(); 112 113 // Changes to the document may have been made since the last editing operation that 114 // require a layout, as in <rdar://problem/5658603>. Low level operations, like 115 // RemoveNodeCommand, don't require a layout because the high level operations that 116 // use them perform one if one is necessary (like for the creation of VisiblePositions). 117 if (isTopLevelCommand()) 118 updateLayout(); 119 120 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); 121 deleteButtonController->disable(); 122 doUnapply(); 123 deleteButtonController->enable(); 124 125 if (isTopLevelCommand()) 126 frame->editor()->unappliedEditing(this); 127 } 128 129 void EditCommand::reapply() 130 { 131 ASSERT(m_document); 132 ASSERT(m_document->frame()); 133 134 Frame* frame = m_document->frame(); 135 136 // Changes to the document may have been made since the last editing operation that 137 // require a layout, as in <rdar://problem/5658603>. Low level operations, like 138 // RemoveNodeCommand, don't require a layout because the high level operations that 139 // use them perform one if one is necessary (like for the creation of VisiblePositions). 140 if (isTopLevelCommand()) 141 updateLayout(); 142 143 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController(); 144 deleteButtonController->disable(); 145 doReapply(); 146 deleteButtonController->enable(); 147 148 if (isTopLevelCommand()) 149 frame->editor()->reappliedEditing(this); 150 } 151 152 void EditCommand::doReapply() 153 { 154 doApply(); 155 } 156 157 EditAction EditCommand::editingAction() const 158 { 159 return EditActionUnspecified; 160 } 161 162 void EditCommand::setStartingSelection(const VisibleSelection& s) 163 { 164 Element* root = s.rootEditableElement(); 165 for (EditCommand* cmd = this; ; cmd = cmd->m_parent) { 166 cmd->m_startingSelection = s; 167 cmd->m_startingRootEditableElement = root; 168 if (!cmd->m_parent || cmd->m_parent->isFirstCommand(cmd)) 169 break; 170 } 171 } 172 173 void EditCommand::setEndingSelection(const VisibleSelection &s) 174 { 175 Element* root = s.rootEditableElement(); 176 for (EditCommand* cmd = this; cmd; cmd = cmd->m_parent) { 177 cmd->m_endingSelection = s; 178 cmd->m_endingRootEditableElement = root; 179 } 180 } 181 182 bool EditCommand::preservesTypingStyle() const 183 { 184 return false; 185 } 186 187 bool EditCommand::isInsertTextCommand() const 188 { 189 return false; 190 } 191 192 bool EditCommand::isTypingCommand() const 193 { 194 return false; 195 } 196 197 bool EditCommand::shouldRetainAutocorrectionIndicator() const 198 { 199 return false; 200 } 201 202 void EditCommand::setShouldRetainAutocorrectionIndicator(bool) 203 { 204 } 205 206 void EditCommand::updateLayout() const 207 { 208 document()->updateLayoutIgnorePendingStylesheets(); 209 } 210 211 void EditCommand::setParent(CompositeEditCommand* parent) 212 { 213 ASSERT(parent); 214 ASSERT(!m_parent); 215 m_parent = parent; 216 m_startingSelection = parent->m_endingSelection; 217 m_endingSelection = parent->m_endingSelection; 218 m_startingRootEditableElement = parent->m_endingRootEditableElement; 219 m_endingRootEditableElement = parent->m_endingRootEditableElement; 220 } 221 222 void applyCommand(PassRefPtr<EditCommand> command) 223 { 224 command->apply(); 225 } 226 227 } // namespace WebCore 228