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