71ff0c17a60d7ff038619c204734dfacc88684a8
[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 "editing/edit_actions.h"
31 #include "qptrlist.h"
32 #include "qvaluelist.h"
33 #include "selection.h"
34 #include "shared.h"
35
36 namespace DOM {
37     class CSSMutableStyleDeclarationImpl;
38     class CSSProperty;
39     class CSSStyleDeclarationImpl;
40     class DocumentFragmentImpl;
41     class HTMLElementImpl;
42     class TextImpl;
43 }
44
45 namespace khtml {
46
47 class EditCommand;
48 class Selection;
49 class VisiblePosition;
50
51 //------------------------------------------------------------------------------------------
52 // EditCommandPtr
53
54 class EditCommandPtr : public SharedPtr<EditCommand>
55 {
56 public:
57     EditCommandPtr();
58     EditCommandPtr(EditCommand *);
59     EditCommandPtr(const EditCommandPtr &);
60     ~EditCommandPtr();
61
62     EditCommandPtr &operator=(const EditCommandPtr &);
63
64     bool isCompositeStep() const;
65
66     void apply() const;
67     void unapply() const;
68     void reapply() const;
69
70     EditAction editingAction() const;
71
72     DOM::DocumentImpl * const document() const;
73
74     Selection startingSelection() const;
75     Selection endingSelection() const;
76
77     void setStartingSelection(const Selection &s) const;
78     void setEndingSelection(const Selection &s) const;
79
80     DOM::CSSMutableStyleDeclarationImpl *typingStyle() const;
81     void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *) const;
82
83     EditCommandPtr parent() const;
84     void setParent(const EditCommandPtr &) const;
85
86     bool isInsertTextCommand() const;
87     bool isInsertLineBreakCommand() const;
88     bool isTypingCommand() const;
89
90     static EditCommandPtr &emptyCommand();
91 };
92
93 //------------------------------------------------------------------------------------------
94 // StyleChange
95
96 class StyleChange {
97 public:
98     enum ELegacyHTMLStyles { DoNotUseLegacyHTMLStyles, UseLegacyHTMLStyles };
99
100     explicit StyleChange(DOM::CSSStyleDeclarationImpl *, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
101     StyleChange(DOM::CSSStyleDeclarationImpl *, const DOM::Position &, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
102
103     DOM::DOMString cssStyle() const { return m_cssStyle; }
104     bool applyBold() const { return m_applyBold; }
105     bool applyItalic() const { return m_applyItalic; }
106     bool usesLegacyStyles() const { return m_usesLegacyStyles; }
107
108 private:
109     void init(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
110     bool checkForLegacyHTMLStyleChange(const DOM::CSSProperty *);
111     static bool currentlyHasStyle(const DOM::Position &, const DOM::CSSProperty *);
112     
113     DOM::DOMString m_cssStyle;
114     bool m_applyBold;
115     bool m_applyItalic;
116     bool m_usesLegacyStyles;
117 };
118
119 //------------------------------------------------------------------------------------------
120 // EditCommand
121
122 class EditCommand : public Shared<EditCommand>
123 {
124 public:
125     EditCommand(DOM::DocumentImpl *);
126     virtual ~EditCommand();
127
128     bool isCompositeStep() const { return m_parent != 0; }
129     EditCommand *parent() const { return m_parent; }
130     void setParent(EditCommand *parent) { m_parent = parent; }
131
132     enum ECommandState { NotApplied, Applied };
133     
134     void apply();       
135     void unapply();
136     void reapply();
137
138     virtual void doApply() = 0;
139     virtual void doUnapply() = 0;
140     virtual void doReapply();  // calls doApply()
141
142     virtual EditAction editingAction() const;
143
144     virtual DOM::DocumentImpl * const document() const { return m_document; }
145
146     Selection startingSelection() const { return m_startingSelection; }
147     Selection endingSelection() const { return m_endingSelection; }
148
149     void setEndingSelectionNeedsLayout(bool flag=true) { m_endingSelection.setNeedsLayout(flag); }
150         
151     ECommandState state() const { return m_state; }
152     void setState(ECommandState state) { m_state = state; }
153
154     void setStartingSelection(const Selection &s);
155     void setEndingSelection(const Selection &s);
156
157     DOM::CSSMutableStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
158     void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
159     
160     virtual bool isInsertTextCommand() const;
161     virtual bool isTypingCommand() const;
162     
163 private:
164     void assignTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
165
166     virtual bool preservesTypingStyle() const;
167
168     DOM::DocumentImpl *m_document;
169     ECommandState m_state;
170     Selection m_startingSelection;
171     Selection m_endingSelection;
172     DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
173     EditCommand *m_parent;
174 };
175
176 //------------------------------------------------------------------------------------------
177 // CompositeEditCommand
178
179 class CompositeEditCommand : public EditCommand
180 {
181 public:
182     CompositeEditCommand(DOM::DocumentImpl *);
183         
184     virtual void doUnapply();
185     virtual void doReapply();
186
187 protected:
188     //
189     // sugary-sweet convenience functions to help create and apply edit commands in composite commands
190     //
191     void appendNode(DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
192     void applyCommandToComposite(EditCommandPtr &);
193     void applyStyle(DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes);
194     void deleteKeyPressed();
195     void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
196     void deleteSelection(const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
197     void deleteTextFromNode(DOM::TextImpl *node, long offset, long count);
198     void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
199     void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
200     void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
201     void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
202     void insertParagraphSeparator();
203     void insertTextIntoNode(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
204     void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
205     void rebalanceWhitespace();
206     void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
207     void removeFullySelectedNode(DOM::NodeImpl *);
208     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
209     void removeNode(DOM::NodeImpl *removeChild);
210     void removeNodePreservingChildren(DOM::NodeImpl *node);
211     void replaceTextInNode(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
212     void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
213     void splitTextNode(DOM::TextImpl *text, long offset);
214
215     DOM::NodeImpl *applyTypingStyle(DOM::NodeImpl *) const;
216
217     void deleteInsignificantText(DOM::TextImpl *, int start, int end);
218     void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
219     void deleteInsignificantTextDownstream(const DOM::Position &);
220
221     void insertBlockPlaceholder(DOM::NodeImpl *);
222     bool insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
223     bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
224
225     void moveParagraphContentsToNewBlockIfNecessary(const DOM::Position &);
226
227     bool isMailBlockquote(const DOM::NodeImpl *) const;
228
229     QValueList<EditCommandPtr> m_cmds;
230 };
231
232 //==========================================================================================
233 // Concrete commands
234 //------------------------------------------------------------------------------------------
235 // AppendNodeCommand
236
237 class AppendNodeCommand : public EditCommand
238 {
239 public:
240     AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
241     virtual ~AppendNodeCommand();
242
243     virtual void doApply();
244     virtual void doUnapply();
245
246     DOM::NodeImpl *appendChild() const { return m_appendChild; }
247     DOM::NodeImpl *parentNode() const { return m_parentNode; }
248
249 private:
250     DOM::NodeImpl *m_appendChild;
251     DOM::NodeImpl *m_parentNode;    
252 };
253
254 //------------------------------------------------------------------------------------------
255 // ApplyStyleCommand
256
257 class ApplyStyleCommand : public CompositeEditCommand
258 {
259 public:
260     ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes);
261     virtual ~ApplyStyleCommand();
262         
263     virtual void doApply();
264     virtual EditAction editingAction() const;
265
266     DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style; }
267
268 private:
269     // style-removal helpers
270     bool isHTMLStyleNode(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
271     void removeHTMLStyleNode(DOM::HTMLElementImpl *);
272     void removeCSSStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
273     void removeBlockStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
274     void removeInlineStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
275     bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
276
277     // style-application helpers
278     void applyBlockStyle(DOM::CSSMutableStyleDeclarationImpl *);
279     void applyRelativeFontStyleChange(DOM::CSSMutableStyleDeclarationImpl *);
280     void applyInlineStyle(DOM::CSSMutableStyleDeclarationImpl *);
281     void addBlockStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *);
282     void addInlineStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *start, DOM::NodeImpl *end);
283     bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
284     bool splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
285     void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
286     DOM::Position positionInsertionPoint(DOM::Position);
287     float computedFontSize(const DOM::NodeImpl *);
288     void joinChildTextNodes(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end);
289     
290     DOM::CSSMutableStyleDeclarationImpl *m_style;
291     EditAction m_editingAction;
292 };
293
294 //------------------------------------------------------------------------------------------
295 // DeleteFromTextNodeCommand
296
297 class DeleteFromTextNodeCommand : public EditCommand
298 {
299 public:
300     DeleteFromTextNodeCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
301     virtual ~DeleteFromTextNodeCommand();
302         
303     virtual void doApply();
304     virtual void doUnapply();
305
306     DOM::TextImpl *node() const { return m_node; }
307     long offset() const { return m_offset; }
308     long count() const { return m_count; }
309
310 private:
311     DOM::TextImpl *m_node;
312     long m_offset;
313     long m_count;
314     DOM::DOMString m_text;
315 };
316
317 //------------------------------------------------------------------------------------------
318 // DeleteSelectionCommand
319
320 class DeleteSelectionCommand : public CompositeEditCommand
321
322 public:
323     DeleteSelectionCommand(DOM::DocumentImpl *document, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
324     DeleteSelectionCommand(DOM::DocumentImpl *document, const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
325         
326     virtual void doApply();
327     virtual EditAction editingAction() const;
328     
329 private:
330     virtual bool preservesTypingStyle() const;
331
332     void initializePositionData();
333     void saveTypingStyleState();
334     void insertPlaceholderForAncestorBlockContent();
335     bool handleSpecialCaseAllContentDelete();
336     bool handleSpecialCaseBRDelete();
337     void handleGeneralDelete();
338     void fixupWhitespace();
339     void moveNodesAfterNode();
340     void calculateEndingPosition();
341     void calculateTypingStyleAfterDelete(bool insertedPlaceholder);
342     void clearTransientState();
343
344     bool m_hasSelectionToDelete;
345     bool m_smartDelete;
346     bool m_mergeBlocksAfterDelete;
347     bool m_trailingWhitespaceValid;
348
349     // This data is transient and should be cleared at the end of the doApply function.
350     Selection m_selectionToDelete;
351     DOM::Position m_upstreamStart;
352     DOM::Position m_downstreamStart;
353     DOM::Position m_upstreamEnd;
354     DOM::Position m_downstreamEnd;
355     DOM::Position m_endingPosition;
356     DOM::Position m_leadingWhitespace;
357     DOM::Position m_trailingWhitespace;
358     DOM::NodeImpl *m_startBlock;
359     DOM::NodeImpl *m_endBlock;
360     DOM::NodeImpl *m_startNode;
361     DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
362 };
363
364 //------------------------------------------------------------------------------------------
365 // InsertIntoTextNode
366
367 class InsertIntoTextNode : public EditCommand
368 {
369 public:
370     InsertIntoTextNode(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
371     virtual ~InsertIntoTextNode();
372         
373     virtual void doApply();
374     virtual void doUnapply();
375
376     DOM::TextImpl *node() const { return m_node; }
377     long offset() const { return m_offset; }
378     DOM::DOMString text() const { return m_text; }
379
380 private:
381     DOM::TextImpl *m_node;
382     long m_offset;
383     DOM::DOMString m_text;
384 };
385
386 //------------------------------------------------------------------------------------------
387 // InsertNodeBeforeCommand
388
389 class InsertNodeBeforeCommand : public EditCommand
390 {
391 public:
392     InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
393     virtual ~InsertNodeBeforeCommand();
394
395     virtual void doApply();
396     virtual void doUnapply();
397
398     DOM::NodeImpl *insertChild() const { return m_insertChild; }
399     DOM::NodeImpl *refChild() const { return m_refChild; }
400
401 private:
402     DOM::NodeImpl *m_insertChild;
403     DOM::NodeImpl *m_refChild; 
404 };
405
406 //------------------------------------------------------------------------------------------
407 // InsertLineBreakCommand
408
409 class InsertLineBreakCommand : public CompositeEditCommand
410 {
411 public:
412     InsertLineBreakCommand(DOM::DocumentImpl *document);
413
414     virtual void doApply();
415
416 private:
417     virtual bool preservesTypingStyle() const;
418     void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
419     void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
420 };
421
422 //------------------------------------------------------------------------------------------
423 // InsertParagraphSeparatorCommand
424
425 class InsertParagraphSeparatorCommand : public CompositeEditCommand
426 {
427 public:
428     InsertParagraphSeparatorCommand(DOM::DocumentImpl *document);
429     virtual ~InsertParagraphSeparatorCommand();
430
431     virtual void doApply();
432
433 private:
434     DOM::ElementImpl *createParagraphElement();
435     void calculateStyleBeforeInsertion(const DOM::Position &);
436     void applyStyleAfterInsertion();
437
438     virtual bool preservesTypingStyle() const;
439
440     QPtrList<DOM::NodeImpl> ancestors;
441     QPtrList<DOM::NodeImpl> clonedNodes;
442     DOM::CSSMutableStyleDeclarationImpl *m_style;
443 };
444
445 //------------------------------------------------------------------------------------------
446 // InsertParagraphSeparatorInQuotedContentCommand
447
448 class InsertParagraphSeparatorInQuotedContentCommand : public CompositeEditCommand
449 {
450 public:
451     InsertParagraphSeparatorInQuotedContentCommand(DOM::DocumentImpl *);
452     virtual ~InsertParagraphSeparatorInQuotedContentCommand();
453         
454     virtual void doApply();
455     
456 private:
457     QPtrList<DOM::NodeImpl> ancestors;
458     QPtrList<DOM::NodeImpl> clonedNodes;
459     DOM::ElementImpl *m_breakNode;
460 };
461
462 //------------------------------------------------------------------------------------------
463 // InsertTextCommand
464
465 class InsertTextCommand : public CompositeEditCommand
466 {
467 public:
468     InsertTextCommand(DOM::DocumentImpl *document);
469
470     virtual void doApply();
471
472     void deleteCharacter();
473     void input(const DOM::DOMString &text, bool selectInsertedText = false);
474     
475     unsigned long charactersAdded() const { return m_charactersAdded; }
476     
477 private:
478     virtual bool isInsertTextCommand() const;
479
480     DOM::Position prepareForTextInsertion(bool adjustDownstream);
481     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
482
483     unsigned long m_charactersAdded;
484 };
485
486 //------------------------------------------------------------------------------------------
487 // JoinTextNodesCommand
488
489 class JoinTextNodesCommand : public EditCommand
490 {
491 public:
492     JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
493     virtual ~JoinTextNodesCommand();
494         
495     virtual void doApply();
496     virtual void doUnapply();
497
498     DOM::TextImpl *firstNode() const { return m_text1; }
499     DOM::TextImpl *secondNode() const { return m_text2; }
500
501 private:
502     DOM::TextImpl *m_text1;
503     DOM::TextImpl *m_text2;
504     unsigned long m_offset;
505 };
506
507 //------------------------------------------------------------------------------------------
508 // MoveSelectionCommand
509
510 class MoveSelectionCommand : public CompositeEditCommand
511 {
512 public:
513     MoveSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position, bool smartMove=false);
514     virtual ~MoveSelectionCommand();
515     
516     virtual void doApply();
517     virtual EditAction editingAction() const;
518     
519 private:
520     DOM::DocumentFragmentImpl *m_fragment;
521     DOM::Position m_position;
522     bool m_smartMove;
523 };
524
525 //------------------------------------------------------------------------------------------
526 // RebalanceWhitespaceCommand
527
528 class RebalanceWhitespaceCommand : public EditCommand
529 {
530 public:
531     RebalanceWhitespaceCommand(DOM::DocumentImpl *, const DOM::Position &);
532     virtual ~RebalanceWhitespaceCommand();
533
534     virtual void doApply();
535     virtual void doUnapply();
536
537 private:
538     enum { InvalidOffset = -1 };
539
540     virtual bool preservesTypingStyle() const;
541
542     DOM::DOMString m_beforeString;
543     DOM::DOMString m_afterString;
544     DOM::Position m_position;
545     long m_upstreamOffset;
546     long m_downstreamOffset;
547 };
548
549 //------------------------------------------------------------------------------------------
550 // RemoveCSSPropertyCommand
551
552 class RemoveCSSPropertyCommand : public EditCommand
553 {
554 public:
555     RemoveCSSPropertyCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
556     virtual ~RemoveCSSPropertyCommand();
557
558     virtual void doApply();
559     virtual void doUnapply();
560
561     DOM::CSSMutableStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
562     int property() const { return m_property; }
563     
564 private:
565     DOM::CSSMutableStyleDeclarationImpl *m_decl;
566     int m_property;
567     DOM::DOMString m_oldValue;
568     bool m_important;
569 };
570
571 //------------------------------------------------------------------------------------------
572 // RemoveNodeAttributeCommand
573
574 class RemoveNodeAttributeCommand : public EditCommand
575 {
576 public:
577     RemoveNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
578     virtual ~RemoveNodeAttributeCommand();
579
580     virtual void doApply();
581     virtual void doUnapply();
582
583     DOM::ElementImpl *element() const { return m_element; }
584     DOM::NodeImpl::Id attribute() const { return m_attribute; }
585     
586 private:
587     DOM::ElementImpl *m_element;
588     DOM::NodeImpl::Id m_attribute;
589     DOM::DOMString m_oldValue;
590 };
591
592 //------------------------------------------------------------------------------------------
593 // RemoveNodeCommand
594
595 class RemoveNodeCommand : public EditCommand
596 {
597 public:
598     RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
599     virtual ~RemoveNodeCommand();
600         
601     virtual void doApply();
602     virtual void doUnapply();
603
604     DOM::NodeImpl *node() const { return m_removeChild; }
605
606 private:
607     DOM::NodeImpl *m_parent;    
608     DOM::NodeImpl *m_removeChild;
609     DOM::NodeImpl *m_refChild;    
610 };
611
612 //------------------------------------------------------------------------------------------
613 // RemoveNodePreservingChildrenCommand
614
615 class RemoveNodePreservingChildrenCommand : public CompositeEditCommand
616 {
617 public:
618     RemoveNodePreservingChildrenCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
619     virtual ~RemoveNodePreservingChildrenCommand();
620         
621     virtual void doApply();
622
623     DOM::NodeImpl *node() const { return m_node; }
624
625 private:
626     DOM::NodeImpl *m_node;
627 };
628
629 //------------------------------------------------------------------------------------------
630 // ReplaceSelectionCommand
631
632 // --- ReplacementFragment helper class
633
634 class ReplacementFragment
635 {
636 public:
637     ReplacementFragment(DOM::DocumentFragmentImpl *fragment);
638     ~ReplacementFragment();
639
640     enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
641
642     DOM::DocumentFragmentImpl *root() const { return m_fragment; }
643     DOM::NodeImpl *firstChild() const;
644     DOM::NodeImpl *lastChild() const;
645
646     DOM::NodeImpl *mergeStartNode() const;
647     DOM::NodeImpl *mergeEndNode() const;
648     
649     void pruneEmptyNodes();
650
651     EFragmentType type() const { return m_type; }
652     bool isEmpty() const { return m_type == EmptyFragment; }
653     bool isSingleTextNode() const { return m_type == SingleTextNodeFragment; }
654     bool isTreeFragment() const { return m_type == TreeFragment; }
655
656     bool hasMoreThanOneBlock() const { return m_hasMoreThanOneBlock; }
657     bool hasInterchangeNewline() const { return m_hasInterchangeNewline; }
658
659 private:
660     // no copy construction or assignment
661     ReplacementFragment(const ReplacementFragment &);
662     ReplacementFragment &operator=(const ReplacementFragment &);
663
664     static bool isInterchangeNewlineNode(const DOM::NodeImpl *);
665     static bool isInterchangeConvertedSpaceSpan(const DOM::NodeImpl *);
666
667     // A couple simple DOM helpers
668     DOM::NodeImpl *enclosingBlock(DOM::NodeImpl *) const;
669     void removeNode(DOM::NodeImpl *);
670     void insertNodeBefore(DOM::NodeImpl *node, DOM::NodeImpl *refNode);
671
672     EFragmentType m_type;
673     DOM::DocumentFragmentImpl *m_fragment;
674     bool m_hasInterchangeNewline;
675     bool m_hasMoreThanOneBlock;
676 };
677
678 // free-floating helper functions
679 bool isProbablyBlock(const DOM::NodeImpl *);
680
681 class ReplaceSelectionCommand : public CompositeEditCommand
682 {
683 public:
684     ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false);
685     virtual ~ReplaceSelectionCommand();
686     
687     virtual void doApply();
688     virtual EditAction editingAction() const;
689
690 private:
691     void completeHTMLReplacement(const DOM::Position &, const DOM::Position &);
692     void completeHTMLReplacement(DOM::NodeImpl *, DOM::NodeImpl *);
693     
694     ReplacementFragment m_fragment;
695     bool m_selectReplacement;
696     bool m_smartReplace;
697 };
698
699 //------------------------------------------------------------------------------------------
700 // SetNodeAttributeCommand
701
702 class SetNodeAttributeCommand : public EditCommand
703 {
704 public:
705     SetNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
706     virtual ~SetNodeAttributeCommand();
707
708     virtual void doApply();
709     virtual void doUnapply();
710
711     DOM::ElementImpl *element() const { return m_element; }
712     DOM::NodeImpl::Id attribute() const { return m_attribute; }
713     DOM::DOMString value() const { return m_value; }
714     
715 private:
716     DOM::ElementImpl *m_element;
717     DOM::NodeImpl::Id m_attribute;
718     DOM::DOMString m_value;
719     DOM::DOMString m_oldValue;
720 };
721
722 //------------------------------------------------------------------------------------------
723 // SplitTextNodeCommand
724
725 class SplitTextNodeCommand : public EditCommand
726 {
727 public:
728     SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
729     virtual ~SplitTextNodeCommand();
730         
731     virtual void doApply();
732     virtual void doUnapply();
733
734     DOM::TextImpl *node() const { return m_text2; }
735     long offset() const { return m_offset; }
736
737 private:
738     DOM::TextImpl *m_text1;
739     DOM::TextImpl *m_text2;
740     unsigned long m_offset;
741 };
742
743 //------------------------------------------------------------------------------------------
744 // TypingCommand
745
746 class TypingCommand : public CompositeEditCommand
747 {
748 public:
749     enum ETypingCommand { 
750         DeleteKey, 
751         InsertText, 
752         InsertLineBreak, 
753         InsertParagraphSeparator,
754         InsertParagraphSeparatorInQuotedContent,
755     };
756
757     TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
758
759     static void deleteKeyPressed(DOM::DocumentImpl *);
760     static void insertText(DOM::DocumentImpl *, const DOM::DOMString &, bool selectInsertedText = false);
761     static void insertLineBreak(DOM::DocumentImpl *);
762     static void insertParagraphSeparator(DOM::DocumentImpl *);
763     static void insertParagraphSeparatorInQuotedContent(DOM::DocumentImpl *);
764     static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
765     static void closeTyping(const EditCommandPtr &);
766     
767     virtual void doApply();
768     virtual EditAction editingAction() const;
769
770     bool openForMoreTyping() const { return m_openForMoreTyping; }
771     void closeTyping() { m_openForMoreTyping = false; }
772
773     void insertText(const DOM::DOMString &text, bool selectInsertedText);
774     void insertLineBreak();
775     void insertParagraphSeparatorInQuotedContent();
776     void insertParagraphSeparator();
777     void deleteKeyPressed();
778
779 private:
780     virtual bool isTypingCommand() const;
781     virtual bool preservesTypingStyle() const;
782
783     void issueCommandForDeleteKey();
784     void removeCommand(const EditCommandPtr &);
785     void markMisspellingsAfterTyping();
786     void typingAddedToOpenCommand();
787     
788     ETypingCommand m_commandType;
789     DOM::DOMString m_textToInsert;
790     bool m_openForMoreTyping;
791     bool m_applyEditing;
792     bool m_selectInsertedText;
793 };
794
795 //------------------------------------------------------------------------------------------
796
797 DOM::ElementImpl *createDefaultParagraphElement(DOM::DocumentImpl *document);
798 DOM::ElementImpl *createBlockPlaceholderElement(DOM::DocumentImpl *document);
799 DOM::ElementImpl *createBreakElement(DOM::DocumentImpl *document);
800 DOM::ElementImpl *createStyleSpanElement(DOM::DocumentImpl *document);
801
802 //------------------------------------------------------------------------------------------
803
804 } // end namespace khtml
805
806 #endif