2 * Copyright (C) 2005, 2006, 2007 Apple, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "EditCommand.h"
29 #include "CompositeEditCommand.h"
30 #include "CSSComputedStyleDeclaration.h"
31 #include "CSSMutableStyleDeclaration.h"
32 #include "DeleteButtonController.h"
36 #include "EventNames.h"
38 #include "SelectionController.h"
39 #include "VisiblePosition.h"
40 #include "htmlediting.h"
44 EditCommand::EditCommand(Document* document)
45 : m_document(document)
49 ASSERT(m_document->frame());
50 DeleteButtonController* deleteButton = m_document->frame()->editor()->deleteButtonController();
51 setStartingSelection(avoidIntersectionWithNode(m_document->frame()->selection()->selection(), deleteButton ? deleteButton->containerElement() : 0));
52 setEndingSelection(m_startingSelection);
55 EditCommand::~EditCommand()
59 void EditCommand::apply()
62 ASSERT(m_document->frame());
64 Frame* frame = m_document->frame();
67 if (!endingSelection().isContentRichlyEditable()) {
68 switch (editingAction()) {
69 case EditActionTyping:
72 case EditActionSetWritingDirection:
74 case EditActionUnspecified:
83 // Changes to the document may have been made since the last editing operation that
84 // require a layout, as in <rdar://problem/5658603>. Low level operations, like
85 // RemoveNodeCommand, don't require a layout because the high level operations that
86 // use them perform one if one is necessary (like for the creation of VisiblePositions).
90 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
91 deleteButtonController->disable();
93 deleteButtonController->enable();
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);
104 void EditCommand::unapply()
107 ASSERT(m_document->frame());
109 Frame* frame = m_document->frame();
111 // Changes to the document may have been made since the last editing operation that
112 // require a layout, as in <rdar://problem/5658603>. Low level operations, like
113 // RemoveNodeCommand, don't require a layout because the high level operations that
114 // use them perform one if one is necessary (like for the creation of VisiblePositions).
118 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
119 deleteButtonController->disable();
121 deleteButtonController->enable();
125 frame->editor()->unappliedEditing(this);
129 void EditCommand::reapply()
132 ASSERT(m_document->frame());
134 Frame* frame = m_document->frame();
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).
143 DeleteButtonController* deleteButtonController = frame->editor()->deleteButtonController();
144 deleteButtonController->disable();
146 deleteButtonController->enable();
150 frame->editor()->reappliedEditing(this);
154 void EditCommand::doReapply()
159 EditAction EditCommand::editingAction() const
161 return EditActionUnspecified;
164 void EditCommand::setStartingSelection(const VisibleSelection& s)
166 Element* root = s.rootEditableElement();
167 for (EditCommand* cmd = this; ; cmd = cmd->m_parent) {
168 cmd->m_startingSelection = s;
169 cmd->m_startingRootEditableElement = root;
170 if (!cmd->m_parent || cmd->m_parent->isFirstCommand(cmd))
175 void EditCommand::setEndingSelection(const VisibleSelection &s)
177 Element* root = s.rootEditableElement();
178 for (EditCommand* cmd = this; cmd; cmd = cmd->m_parent) {
179 cmd->m_endingSelection = s;
180 cmd->m_endingRootEditableElement = root;
184 bool EditCommand::preservesTypingStyle() const
189 bool EditCommand::isInsertTextCommand() const
194 bool EditCommand::isTypingCommand() const
199 PassRefPtr<CSSMutableStyleDeclaration> EditCommand::styleAtPosition(const Position &pos)
201 RefPtr<CSSMutableStyleDeclaration> style = positionBeforeTabSpan(pos).computedStyle()->copyInheritableProperties();
203 // FIXME: It seems misleading to also include the typing style when returning the style at some arbitrary
204 // position in the document.
205 CSSMutableStyleDeclaration* typingStyle = document()->frame()->typingStyle();
207 style->merge(typingStyle);
209 return style.release();
212 void EditCommand::updateLayout() const
214 document()->updateLayoutIgnorePendingStylesheets();
217 void EditCommand::setParent(CompositeEditCommand* parent)
222 m_startingSelection = parent->m_endingSelection;
223 m_endingSelection = parent->m_endingSelection;
224 m_startingRootEditableElement = parent->m_endingRootEditableElement;
225 m_endingRootEditableElement = parent->m_endingRootEditableElement;
228 void applyCommand(PassRefPtr<EditCommand> command)
233 } // namespace WebCore