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 41namespace WebCore { 42 43EditCommand::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 53EditCommand::~EditCommand() 54{ 55} 56 57void 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 106void 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 129void 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 152void EditCommand::doReapply() 153{ 154 doApply(); 155} 156 157EditAction EditCommand::editingAction() const 158{ 159 return EditActionUnspecified; 160} 161 162void 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 173void 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 182bool EditCommand::preservesTypingStyle() const 183{ 184 return false; 185} 186 187bool EditCommand::isInsertTextCommand() const 188{ 189 return false; 190} 191 192bool EditCommand::isTypingCommand() const 193{ 194 return false; 195} 196 197bool EditCommand::shouldRetainAutocorrectionIndicator() const 198{ 199 return false; 200} 201 202void EditCommand::setShouldRetainAutocorrectionIndicator(bool) 203{ 204} 205 206void EditCommand::updateLayout() const 207{ 208 document()->updateLayoutIgnorePendingStylesheets(); 209} 210 211void 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 222void applyCommand(PassRefPtr<EditCommand> command) 223{ 224 command->apply(); 225} 226 227} // namespace WebCore 228