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