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
EditCommand(Document * document)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
~EditCommand()53 EditCommand::~EditCommand()
54 {
55 }
56
apply()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
unapply()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
reapply()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
doReapply()152 void EditCommand::doReapply()
153 {
154 doApply();
155 }
156
editingAction() const157 EditAction EditCommand::editingAction() const
158 {
159 return EditActionUnspecified;
160 }
161
setStartingSelection(const VisibleSelection & s)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
setEndingSelection(const VisibleSelection & s)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
preservesTypingStyle() const182 bool EditCommand::preservesTypingStyle() const
183 {
184 return false;
185 }
186
isInsertTextCommand() const187 bool EditCommand::isInsertTextCommand() const
188 {
189 return false;
190 }
191
isTypingCommand() const192 bool EditCommand::isTypingCommand() const
193 {
194 return false;
195 }
196
shouldRetainAutocorrectionIndicator() const197 bool EditCommand::shouldRetainAutocorrectionIndicator() const
198 {
199 return false;
200 }
201
setShouldRetainAutocorrectionIndicator(bool)202 void EditCommand::setShouldRetainAutocorrectionIndicator(bool)
203 {
204 }
205
updateLayout() const206 void EditCommand::updateLayout() const
207 {
208 document()->updateLayoutIgnorePendingStylesheets();
209 }
210
setParent(CompositeEditCommand * parent)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
applyCommand(PassRefPtr<EditCommand> command)222 void applyCommand(PassRefPtr<EditCommand> command)
223 {
224 command->apply();
225 }
226
227 } // namespace WebCore
228