• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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