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
EditCommand(Document * document)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
~EditCommand()54 EditCommand::~EditCommand()
55 {
56 }
57
apply()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
unapply()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
reapply()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
doReapply()153 void EditCommand::doReapply()
154 {
155 doApply();
156 }
157
editingAction() const158 EditAction EditCommand::editingAction() const
159 {
160 return EditActionUnspecified;
161 }
162
setStartingSelection(const VisibleSelection & s)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
setEndingSelection(const VisibleSelection & s)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
preservesTypingStyle() const183 bool EditCommand::preservesTypingStyle() const
184 {
185 return false;
186 }
187
isInsertTextCommand() const188 bool EditCommand::isInsertTextCommand() const
189 {
190 return false;
191 }
192
isTypingCommand() const193 bool EditCommand::isTypingCommand() const
194 {
195 return false;
196 }
197
198
updateLayout() const199 void EditCommand::updateLayout() const
200 {
201 document()->updateLayoutIgnorePendingStylesheets();
202 }
203
setParent(CompositeEditCommand * parent)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
applyCommand(PassRefPtr<EditCommand> command)215 void applyCommand(PassRefPtr<EditCommand> command)
216 {
217 command->apply();
218 }
219
220 } // namespace WebCore
221