Reviewed by Hyatt
[WebKit-https.git] / WebCore / khtml / editing / htmlediting.h
1 /*
2  * Copyright (C) 2004 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 #ifndef __htmlediting_h__
27 #define __htmlediting_h__
28
29 #include "dom_nodeimpl.h"
30 #include "qvaluelist.h"
31 #include "selection.h"
32 #include "shared.h"
33
34 namespace DOM {
35     class CSSProperty;
36     class DocumentFragmentImpl;
37     class HTMLElementImpl;
38     class TextImpl;
39 }
40
41 namespace khtml {
42
43 class EditCommand;
44 class Selection;
45
46 //------------------------------------------------------------------------------------------
47 // EditCommandPtr
48
49 class EditCommandPtr : public SharedPtr<EditCommand>
50 {
51 public:
52     EditCommandPtr();
53     EditCommandPtr(EditCommand *);
54     EditCommandPtr(const EditCommandPtr &);
55     ~EditCommandPtr();
56
57     EditCommandPtr &operator=(const EditCommandPtr &);
58
59     bool isCompositeStep() const;
60
61     void apply() const;
62     void unapply() const;
63     void reapply() const;
64
65     DOM::DocumentImpl * const document() const;
66
67     khtml::Selection startingSelection() const;
68     khtml::Selection endingSelection() const;
69
70     void setStartingSelection(const khtml::Selection &s) const;
71     void setEndingSelection(const khtml::Selection &s) const;
72
73     DOM::CSSStyleDeclarationImpl *typingStyle() const;
74     void setTypingStyle(DOM::CSSStyleDeclarationImpl *) const;
75
76     EditCommandPtr parent() const;
77     void setParent(const EditCommandPtr &) const;
78
79     bool isInputTextCommand() const;
80     bool isInputNewlineCommand() const;
81     bool isTypingCommand() const;
82
83     static EditCommandPtr &emptyCommand();
84 };
85
86 //------------------------------------------------------------------------------------------
87 // StyleChange
88
89 class StyleChange {
90 public:
91     StyleChange() : m_applyBold(false), m_applyItalic(false) { }
92     explicit StyleChange(DOM::CSSStyleDeclarationImpl *);
93     StyleChange(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
94
95     DOM::DOMString cssStyle() const { return m_cssStyle; }
96     bool applyBold() const { return m_applyBold; }
97     bool applyItalic() const { return m_applyItalic; }
98
99 private:
100     void init(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
101     static bool currentlyHasStyle(const DOM::Position &, const DOM::CSSProperty *);
102     
103     DOM::DOMString m_cssStyle;
104     bool m_applyBold;
105     bool m_applyItalic;
106 };
107
108 //------------------------------------------------------------------------------------------
109 // EditCommand
110
111 class EditCommand : public Shared<EditCommand>
112 {
113 public:
114     EditCommand(DOM::DocumentImpl *);
115     virtual ~EditCommand();
116
117     bool isCompositeStep() const { return m_parent.notNull(); }
118     EditCommand *parent() const { return m_parent.get(); }
119     void setParent(EditCommand *parent) { m_parent = parent; }
120
121     enum ECommandState { NotApplied, Applied };
122     
123     void apply();       
124     void unapply();
125     void reapply();
126
127     virtual void doApply() = 0;
128     virtual void doUnapply() = 0;
129     virtual void doReapply();  // calls doApply()
130
131     virtual DOM::DocumentImpl * const document() const { return m_document; }
132
133     khtml::Selection startingSelection() const { return m_startingSelection; }
134     khtml::Selection endingSelection() const { return m_endingSelection; }
135         
136     ECommandState state() const { return m_state; }
137     void setState(ECommandState state) { m_state = state; }
138
139     void setStartingSelection(const khtml::Selection &s);
140     void setEndingSelection(const khtml::Selection &s);
141
142     DOM::CSSStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
143     void setTypingStyle(DOM::CSSStyleDeclarationImpl *);
144     
145     virtual bool isInputTextCommand() const;
146     virtual bool isTypingCommand() const;
147
148 private:
149     void assignTypingStyle(DOM::CSSStyleDeclarationImpl *);
150
151     virtual bool preservesTypingStyle() const;
152
153     DOM::DocumentImpl *m_document;
154     ECommandState m_state;
155     khtml::Selection m_startingSelection;
156     khtml::Selection m_endingSelection;
157     DOM::CSSStyleDeclarationImpl *m_typingStyle;
158     EditCommandPtr m_parent;
159 };
160
161 //------------------------------------------------------------------------------------------
162 // CompositeEditCommand
163
164 class CompositeEditCommand : public EditCommand
165 {
166 public:
167     CompositeEditCommand(DOM::DocumentImpl *);
168         
169     virtual void doUnapply();
170     virtual void doReapply();
171
172 protected:
173     //
174     // sugary-sweet convenience functions to help create and apply edit commands in composite commands
175     //
176     void appendNode(DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
177     void applyCommandToComposite(EditCommandPtr &);
178     void deleteKeyPressed();
179     void deleteSelection(bool smartDelete=false);
180     void deleteSelection(const khtml::Selection &selection, bool smartDelete=false);
181     void deleteText(DOM::TextImpl *node, long offset, long count);
182     void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
183     void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
184     void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
185     void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
186     void insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
187     void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
188     void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
189     void removeFullySelectedNode(DOM::NodeImpl *);
190     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
191     void removeNode(DOM::NodeImpl *removeChild);
192     void removeNodePreservingChildren(DOM::NodeImpl *node);
193     void replaceText(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
194     void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
195     void splitTextNode(DOM::TextImpl *text, long offset);
196
197     DOM::NodeImpl *applyTypingStyle(DOM::NodeImpl *) const;
198
199     void deleteInsignificantText(DOM::TextImpl *, int start, int end);
200     void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
201     void deleteInsignificantTextDownstream(const DOM::Position &);
202
203     void insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
204     bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
205
206     QValueList<EditCommandPtr> m_cmds;
207 };
208
209 //==========================================================================================
210 // Concrete commands
211 //------------------------------------------------------------------------------------------
212 // AppendNodeCommand
213
214 class AppendNodeCommand : public EditCommand
215 {
216 public:
217     AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
218     virtual ~AppendNodeCommand();
219
220     virtual void doApply();
221     virtual void doUnapply();
222
223     DOM::NodeImpl *appendChild() const { return m_appendChild; }
224     DOM::NodeImpl *parentNode() const { return m_parentNode; }
225
226 private:
227     DOM::NodeImpl *m_appendChild;
228     DOM::NodeImpl *m_parentNode;    
229 };
230
231 //------------------------------------------------------------------------------------------
232 // ApplyStyleCommand
233
234 class ApplyStyleCommand : public CompositeEditCommand
235 {
236 public:
237     ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style);
238     virtual ~ApplyStyleCommand();
239         
240     virtual void doApply();
241
242     DOM::CSSStyleDeclarationImpl *style() const { return m_style; }
243
244 private:
245     // style-removal helpers
246     bool isHTMLStyleNode(DOM::HTMLElementImpl *);
247     void removeHTMLStyleNode(DOM::HTMLElementImpl *);
248     void removeCSSStyle(DOM::HTMLElementImpl *);
249     void removeStyle(const DOM::Position &start, const DOM::Position &end);
250     bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
251
252     // style-application helpers
253     bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
254     DOM::NodeImpl *splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
255     void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
256     DOM::Position positionInsertionPoint(DOM::Position);
257     void applyStyleIfNeeded(DOM::NodeImpl *start, DOM::NodeImpl *end);
258     
259     DOM::CSSStyleDeclarationImpl *m_style;
260 };
261
262 //------------------------------------------------------------------------------------------
263 // DeleteSelectionCommand
264
265 class DeleteSelectionCommand : public CompositeEditCommand
266
267 public:
268     DeleteSelectionCommand(DOM::DocumentImpl *document, bool smartDelete=false);
269     DeleteSelectionCommand(DOM::DocumentImpl *document, const khtml::Selection &selection, bool smartDelete=false);
270         
271     virtual void doApply();
272     
273 private:
274     virtual bool preservesTypingStyle() const;
275
276     void moveNodesAfterNode(DOM::NodeImpl *startNode, DOM::NodeImpl *dstNode);
277     DOM::Position startPositionForDelete() const;
278     DOM::Position endPositionForDelete() const;
279
280     khtml::Selection m_selectionToDelete;
281     bool m_hasSelectionToDelete;
282     bool m_smartDelete;
283 };
284
285 //------------------------------------------------------------------------------------------
286 // DeleteTextCommand
287
288 class DeleteTextCommand : public EditCommand
289 {
290 public:
291     DeleteTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
292     virtual ~DeleteTextCommand();
293         
294     virtual void doApply();
295     virtual void doUnapply();
296
297     DOM::TextImpl *node() const { return m_node; }
298     long offset() const { return m_offset; }
299     long count() const { return m_count; }
300
301 private:
302     DOM::TextImpl *m_node;
303     long m_offset;
304     long m_count;
305     DOM::DOMString m_text;
306 };
307
308 //------------------------------------------------------------------------------------------
309 // InputNewlineCommand
310
311 class InputNewlineCommand : public CompositeEditCommand
312 {
313 public:
314     InputNewlineCommand(DOM::DocumentImpl *document);
315
316     virtual void doApply();
317
318 private:
319     void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
320     void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
321 };
322
323 //------------------------------------------------------------------------------------------
324 // InputTextCommand
325
326 class InputTextCommand : public CompositeEditCommand
327 {
328 public:
329     InputTextCommand(DOM::DocumentImpl *document);
330
331     virtual void doApply();
332
333     void deleteCharacter();
334     void input(const DOM::DOMString &text, bool selectInsertedText = false);
335     
336     unsigned long charactersAdded() const { return m_charactersAdded; }
337     
338 private:
339     virtual bool isInputTextCommand() const;
340
341     DOM::Position prepareForTextInsertion(bool adjustDownstream);
342     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
343
344     unsigned long m_charactersAdded;
345 };
346
347 //------------------------------------------------------------------------------------------
348 // InsertNodeBeforeCommand
349
350 class InsertNodeBeforeCommand : public EditCommand
351 {
352 public:
353     InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
354     virtual ~InsertNodeBeforeCommand();
355
356     virtual void doApply();
357     virtual void doUnapply();
358
359     DOM::NodeImpl *insertChild() const { return m_insertChild; }
360     DOM::NodeImpl *refChild() const { return m_refChild; }
361
362 private:
363     DOM::NodeImpl *m_insertChild;
364     DOM::NodeImpl *m_refChild; 
365 };
366
367 //------------------------------------------------------------------------------------------
368 // InsertTextCommand
369
370 class InsertTextCommand : public EditCommand
371 {
372 public:
373     InsertTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
374     virtual ~InsertTextCommand();
375         
376     virtual void doApply();
377     virtual void doUnapply();
378
379     DOM::TextImpl *node() const { return m_node; }
380     long offset() const { return m_offset; }
381     DOM::DOMString text() const { return m_text; }
382
383 private:
384     DOM::TextImpl *m_node;
385     long m_offset;
386     DOM::DOMString m_text;
387 };
388
389 //------------------------------------------------------------------------------------------
390 // JoinTextNodesCommand
391
392 class JoinTextNodesCommand : public EditCommand
393 {
394 public:
395     JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
396     virtual ~JoinTextNodesCommand();
397         
398     virtual void doApply();
399     virtual void doUnapply();
400
401     DOM::TextImpl *firstNode() const { return m_text1; }
402     DOM::TextImpl *secondNode() const { return m_text2; }
403
404 private:
405     DOM::TextImpl *m_text1;
406     DOM::TextImpl *m_text2;
407     unsigned long m_offset;
408 };
409
410 //------------------------------------------------------------------------------------------
411 // ReplaceSelectionCommand
412
413 class ReplaceSelectionCommand : public CompositeEditCommand
414 {
415 public:
416     ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false);
417     virtual ~ReplaceSelectionCommand();
418     
419     virtual void doApply();
420
421 private:
422     DOM::DocumentFragmentImpl *m_fragment;
423     bool m_selectReplacement;
424     bool m_smartReplace;
425 };
426
427 //------------------------------------------------------------------------------------------
428 // MoveSelectionCommand
429
430 class MoveSelectionCommand : public CompositeEditCommand
431 {
432 public:
433     MoveSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position, bool smartMove=false);
434     virtual ~MoveSelectionCommand();
435     
436     virtual void doApply();
437     
438 private:
439     DOM::DocumentFragmentImpl *m_fragment;
440     DOM::Position m_position;
441     bool m_smartMove;
442 };
443
444 //------------------------------------------------------------------------------------------
445 // RemoveCSSPropertyCommand
446
447 class RemoveCSSPropertyCommand : public EditCommand
448 {
449 public:
450     RemoveCSSPropertyCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
451     virtual ~RemoveCSSPropertyCommand();
452
453     virtual void doApply();
454     virtual void doUnapply();
455
456     DOM::CSSStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
457     int property() const { return m_property; }
458     
459 private:
460     DOM::CSSStyleDeclarationImpl *m_decl;
461     int m_property;
462     DOM::DOMString m_oldValue;
463     bool m_important;
464 };
465
466 //------------------------------------------------------------------------------------------
467 // RemoveNodeAttributeCommand
468
469 class RemoveNodeAttributeCommand : public EditCommand
470 {
471 public:
472     RemoveNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
473     virtual ~RemoveNodeAttributeCommand();
474
475     virtual void doApply();
476     virtual void doUnapply();
477
478     DOM::ElementImpl *element() const { return m_element; }
479     DOM::NodeImpl::Id attribute() const { return m_attribute; }
480     
481 private:
482     DOM::ElementImpl *m_element;
483     DOM::NodeImpl::Id m_attribute;
484     DOM::DOMString m_oldValue;
485 };
486
487 //------------------------------------------------------------------------------------------
488 // RemoveNodeCommand
489
490 class RemoveNodeCommand : public EditCommand
491 {
492 public:
493     RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
494     virtual ~RemoveNodeCommand();
495         
496     virtual void doApply();
497     virtual void doUnapply();
498
499     DOM::NodeImpl *node() const { return m_removeChild; }
500
501 private:
502     DOM::NodeImpl *m_parent;    
503     DOM::NodeImpl *m_removeChild;
504     DOM::NodeImpl *m_refChild;    
505 };
506
507 //------------------------------------------------------------------------------------------
508 // RemoveNodePreservingChildrenCommand
509
510 class RemoveNodePreservingChildrenCommand : public CompositeEditCommand
511 {
512 public:
513     RemoveNodePreservingChildrenCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
514     virtual ~RemoveNodePreservingChildrenCommand();
515         
516     virtual void doApply();
517
518     DOM::NodeImpl *node() const { return m_node; }
519
520 private:
521     DOM::NodeImpl *m_node;
522 };
523
524 //------------------------------------------------------------------------------------------
525 // SetNodeAttributeCommand
526
527 class SetNodeAttributeCommand : public EditCommand
528 {
529 public:
530     SetNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
531     virtual ~SetNodeAttributeCommand();
532
533     virtual void doApply();
534     virtual void doUnapply();
535
536     DOM::ElementImpl *element() const { return m_element; }
537     DOM::NodeImpl::Id attribute() const { return m_attribute; }
538     DOM::DOMString value() const { return m_value; }
539     
540 private:
541     DOM::ElementImpl *m_element;
542     DOM::NodeImpl::Id m_attribute;
543     DOM::DOMString m_value;
544     DOM::DOMString m_oldValue;
545 };
546
547 //------------------------------------------------------------------------------------------
548 // SplitTextNodeCommand
549
550 class SplitTextNodeCommand : public EditCommand
551 {
552 public:
553     SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
554     virtual ~SplitTextNodeCommand();
555         
556     virtual void doApply();
557     virtual void doUnapply();
558
559     DOM::TextImpl *node() const { return m_text2; }
560     long offset() const { return m_offset; }
561
562 private:
563     DOM::TextImpl *m_text1;
564     DOM::TextImpl *m_text2;
565     unsigned long m_offset;
566 };
567
568 //------------------------------------------------------------------------------------------
569 // TypingCommand
570
571 class TypingCommand : public CompositeEditCommand
572 {
573 public:
574     enum ETypingCommand { DeleteKey, InsertText, InsertNewline };
575
576     TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
577
578     static void deleteKeyPressed(DOM::DocumentImpl *document);
579     static void insertText(DOM::DocumentImpl *document, const DOM::DOMString &text, bool selectInsertedText = false);
580     static void insertNewline(DOM::DocumentImpl *document);
581     static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
582     static void closeTyping(const EditCommandPtr &);
583     
584     virtual void doApply();
585
586     bool openForMoreTyping() const { return m_openForMoreTyping; }
587     void closeTyping() { m_openForMoreTyping = false; }
588
589     void insertText(const DOM::DOMString &text, bool selectInsertedText);
590     void insertNewline();
591     void deleteKeyPressed();
592
593 private:
594     virtual bool isTypingCommand() const;
595     virtual bool preservesTypingStyle() const;
596
597     void issueCommandForDeleteKey();
598     void removeCommand(const EditCommandPtr &);
599     void markMisspellingsAfterTyping();
600     void typingAddedToOpenCommand();
601     
602     ETypingCommand m_commandType;
603     DOM::DOMString m_textToInsert;
604     bool m_openForMoreTyping;
605     bool m_applyEditing;
606     bool m_selectInsertedText;
607 };
608
609 //------------------------------------------------------------------------------------------
610
611 } // end namespace khtml
612
613 #endif