LayoutTests:
[WebKit-https.git] / WebCore / editing / Editor.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, 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 "Editor.h"
28
29 #include "ApplyStyleCommand.h"
30 #include "CSSComputedStyleDeclaration.h"
31 #include "DeleteButtonController.h"
32 #include "Document.h"
33 #include "DocumentFragment.h"
34 #include "EditorClient.h"
35 #include "EditCommand.h"
36 #include "htmlediting.h"
37 #include "HTMLElement.h"
38 #include "HTMLNames.h"
39 #include "markup.h"
40 #include "Range.h"
41 #include "ReplaceSelectionCommand.h"
42 #include "SelectionController.h"
43 #include "Sound.h"
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48
49 // implement as platform-specific
50 static Pasteboard generalPasteboard()
51 {
52     return 0;
53 }
54
55 bool Editor::canCopy()
56 {
57     return false;
58 }
59
60 bool Editor::canCut()
61 {
62     return false;
63 }
64
65 bool Editor::canDelete()
66 {
67     return false;
68 }
69
70 bool Editor::canDeleteRange(Range* range)
71 {
72     ExceptionCode ec = 0;
73     Node* startContainer = range->startContainer(ec);
74     Node* endContainer = range->endContainer(ec);
75     if (!startContainer || !endContainer)
76         return false;
77     
78     if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
79         return false;
80     
81     if (range->collapsed(ec)) {
82         VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
83         VisiblePosition previous = start.previous();
84         // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
85         if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
86             return false;
87     }
88     return true;
89 }
90
91 bool Editor::canPaste()
92 {
93     return false;
94 }
95
96 bool Editor::canSmartCopyOrDelete()
97 {
98     return false;
99 }
100
101 void Editor::deleteSelection()
102 {
103 }
104
105 void Editor::deleteSelectionWithSmartDelete(bool enabled)
106 {
107 }
108
109 bool Editor::isSelectionRichlyEditable()
110 {
111     return false;
112 }
113
114 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard pasteboard)
115 {
116 }
117
118 void Editor::pasteWithPasteboard(Pasteboard pasteboard, bool allowPlainText)
119 {
120 }
121
122 Range* Editor::selectedRange()
123 {
124     return 0;
125 }
126
127 bool Editor::shouldDeleteRange(Range* range)
128 {
129     ExceptionCode ec;
130     if (!range || range->collapsed(ec))
131         return false;
132     
133     if (!canDeleteRange(range))
134         return false;
135
136     return m_client->shouldDeleteRange(range);
137  }
138
139 bool Editor::tryDHTMLCopy()
140 {
141     bool handled = false;
142     return handled;
143 }
144
145 bool Editor::tryDHTMLCut()
146 {
147     bool handled = false;
148     return handled;
149 }
150
151 bool Editor::tryDHTMLPaste()
152 {
153     bool handled = false;
154     return handled;
155 }
156
157 void Editor::writeSelectionToPasteboard(Pasteboard pasteboard)
158 {
159 }
160
161 bool Editor::shouldShowDeleteInterface(HTMLElement* element)
162 {
163     return m_client->shouldShowDeleteInterface(element);
164 }
165
166 void Editor::respondToChangedSelection(const Selection& oldSelection)
167 {
168     m_deleteButtonController->respondToChangedSelection(oldSelection);
169 }
170
171 void Editor::respondToChangedContents()
172 {
173     m_deleteButtonController->respondToChangedContents();
174 }
175
176 Frame::TriState Editor::selectionUnorderedListState() const
177 {
178     if (m_frame->selectionController()->isCaret()) {
179         Node* selectionNode = m_frame->selectionController()->selection().start().node();
180         if (enclosingNodeWithTag(selectionNode, ulTag))
181             return Frame::trueTriState;
182     } else if (m_frame->selectionController()->isRange()) {
183         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
184         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
185         if (startNode && endNode && startNode == endNode)
186             return Frame::trueTriState;
187     }
188
189     return Frame::falseTriState;
190 }
191
192 Frame::TriState Editor::selectionOrderedListState() const
193 {
194     if (m_frame->selectionController()->isCaret()) {
195         Node* selectionNode = m_frame->selectionController()->selection().start().node();
196         if (enclosingNodeWithTag(selectionNode, olTag))
197             return Frame::trueTriState;
198     } else if (m_frame->selectionController()->isRange()) {
199         Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
200         Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
201         if (startNode && endNode && startNode == endNode)
202             return Frame::trueTriState;
203     }
204
205     return Frame::falseTriState;
206 }
207
208 void Editor::removeFormattingAndStyle()
209 {
210     Document* document = frame()->document();
211     
212     // Make a plain text string from the selection to remove formatting like tables and lists.
213     RefPtr<DocumentFragment> text = createFragmentFromText(frame()->selectionController()->toRange().get(), frame()->selectionController()->toString());
214     
215     // Put the fragment made from that string into a style span with the document's
216     // default style to make sure that it is unstyled regardless of where it is inserted.
217     Position pos(document->documentElement(), 0);
218     RefPtr<CSSComputedStyleDeclaration> computedStyle = pos.computedStyle();
219     RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle->copyInheritableProperties();
220     
221     RefPtr<Element> span = createStyleSpanElement(document);
222     span->setAttribute(styleAttr, defaultStyle->cssText());
223     
224     ExceptionCode ec;
225     
226     while (text->lastChild())
227         span->appendChild(text->lastChild(), ec);
228     
229     RefPtr<DocumentFragment> fragment = new DocumentFragment(document);
230     fragment->appendChild(span, ec);
231     
232     applyCommand(new ReplaceSelectionCommand(document, fragment, false, false, false, true, EditActionUnspecified));
233 }
234
235 // =============================================================================
236 //
237 // public editing commands
238 //
239 // =============================================================================
240
241 Editor::Editor(Frame* frame, PassRefPtr<EditorClient> client)
242     : m_frame(frame)
243     , m_client(client)
244     , m_deleteButtonController(new DeleteButtonController(frame))
245
246 }
247
248 Editor::~Editor()
249 {
250 }
251
252 void Editor::cut()
253 {
254     if (tryDHTMLCut())
255         return; // DHTML did the whole operation
256     if (!canCut()) {
257         systemBeep();
258         return;
259     }
260     
261     if (shouldDeleteRange(selectedRange())) {
262         writeSelectionToPasteboard(generalPasteboard());
263         deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
264     }
265 }
266
267 void Editor::copy()
268 {
269     if (tryDHTMLCopy())
270         return; // DHTML did the whole operation
271     if (!canCopy()) {
272         systemBeep();
273         return;
274     }
275     writeSelectionToPasteboard(generalPasteboard());
276 }
277
278 void Editor::paste()
279 {
280     if (tryDHTMLPaste())
281         return;     // DHTML did the whole operation
282     if (!canPaste())
283         return;
284     if (isSelectionRichlyEditable())
285         pasteWithPasteboard(generalPasteboard(), true);
286     else
287         pasteAsPlainTextWithPasteboard(generalPasteboard());
288 }
289
290 void Editor::performDelete()
291 {
292     if (!canDelete()) {
293         systemBeep();
294         return;
295     }
296     deleteSelection();
297 }
298
299 } // namespace WebCore