fb6e9ea3b3b65181b3d0791e6fb90dc5ec6c23ca
[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 deleteKeyPressed();
194     void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
195     void deleteSelection(const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
196     void deleteTextFromNode(DOM::TextImpl *node, long offset, long count);
197     void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
198     void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
199     void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
200     void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
201     void insertParagraphSeparator();
202     void insertTextIntoNode(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
203     void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
204     void rebalanceWhitespace();
205     void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
206     void removeFullySelectedNode(DOM::NodeImpl *);
207     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
208     void removeNode(DOM::NodeImpl *removeChild);
209     void removeNodePreservingChildren(DOM::NodeImpl *node);
210     void replaceTextInNode(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
211     void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
212     void splitTextNode(DOM::TextImpl *text, long offset);
213
214     DOM::NodeImpl *applyTypingStyle(DOM::NodeImpl *) const;
215
216     void deleteInsignificantText(DOM::TextImpl *, int start, int end);
217     void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
218     void deleteInsignificantTextDownstream(const DOM::Position &);
219
220     void insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
221     bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
222
223     QValueList<EditCommandPtr> m_cmds;
224 };
225
226 //==========================================================================================
227 // Concrete commands
228 //------------------------------------------------------------------------------------------
229 // AppendNodeCommand
230
231 class AppendNodeCommand : public EditCommand
232 {
233 public:
234     AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
235     virtual ~AppendNodeCommand();
236
237     virtual void doApply();
238     virtual void doUnapply();
239
240     DOM::NodeImpl *appendChild() const { return m_appendChild; }
241     DOM::NodeImpl *parentNode() const { return m_parentNode; }
242
243 private:
244     DOM::NodeImpl *m_appendChild;
245     DOM::NodeImpl *m_parentNode;    
246 };
247
248 //------------------------------------------------------------------------------------------
249 // ApplyStyleCommand
250
251 class ApplyStyleCommand : public CompositeEditCommand
252 {
253 public:
254     ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes);
255     virtual ~ApplyStyleCommand();
256         
257     virtual void doApply();
258     virtual EditAction editingAction() const;
259
260     DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style; }
261
262 private:
263     // style-removal helpers
264     bool isHTMLStyleNode(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
265     void removeHTMLStyleNode(DOM::HTMLElementImpl *);
266     void removeCSSStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
267     void removeBlockStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
268     void removeInlineStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
269     bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
270
271     // style-application helpers
272     void applyBlockStyle(DOM::CSSMutableStyleDeclarationImpl *);
273     void applyInlineStyle(DOM::CSSMutableStyleDeclarationImpl *);
274     void addBlockStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
275     void addInlineStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *start, DOM::NodeImpl *end);
276     bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
277     DOM::NodeImpl *splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
278     void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
279     DOM::Position positionInsertionPoint(DOM::Position);
280     
281     DOM::CSSMutableStyleDeclarationImpl *m_style;
282     EditAction m_editingAction;
283 };
284
285 //------------------------------------------------------------------------------------------
286 // DeleteFromTextNodeCommand
287
288 class DeleteFromTextNodeCommand : public EditCommand
289 {
290 public:
291     DeleteFromTextNodeCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
292     virtual ~DeleteFromTextNodeCommand();
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 // DeleteSelectionCommand
310
311 class DeleteSelectionCommand : public CompositeEditCommand
312
313 public:
314     DeleteSelectionCommand(DOM::DocumentImpl *document, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
315     DeleteSelectionCommand(DOM::DocumentImpl *document, const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
316         
317     virtual void doApply();
318     virtual EditAction editingAction() const;
319     
320 private:
321     virtual bool preservesTypingStyle() const;
322
323     void initializePositionData();
324     void saveTypingStyleState();
325     void insertPlaceholderForAncestorBlockContent();
326     bool handleSpecialCaseAllContentDelete();
327     bool handleSpecialCaseBRDelete();
328     void handleGeneralDelete();
329     void fixupWhitespace();
330     void moveNodesAfterNode();
331     void calculateEndingPosition();
332     void calculateTypingStyleAfterDelete();
333     void clearTransientState();
334
335     bool m_hasSelectionToDelete;
336     bool m_smartDelete;
337     bool m_mergeBlocksAfterDelete;
338     bool m_trailingWhitespaceValid;
339
340     // This data is transient and should be cleared at the end of the doApply function.
341     Selection m_selectionToDelete;
342     DOM::Position m_upstreamStart;
343     DOM::Position m_downstreamStart;
344     DOM::Position m_upstreamEnd;
345     DOM::Position m_downstreamEnd;
346     DOM::Position m_endingPosition;
347     DOM::Position m_leadingWhitespace;
348     DOM::Position m_trailingWhitespace;
349     DOM::NodeImpl *m_startBlock;
350     DOM::NodeImpl *m_endBlock;
351     DOM::NodeImpl *m_startNode;
352     DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
353 };
354
355 //------------------------------------------------------------------------------------------
356 // InsertIntoTextNode
357
358 class InsertIntoTextNode : public EditCommand
359 {
360 public:
361     InsertIntoTextNode(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
362     virtual ~InsertIntoTextNode();
363         
364     virtual void doApply();
365     virtual void doUnapply();
366
367     DOM::TextImpl *node() const { return m_node; }
368     long offset() const { return m_offset; }
369     DOM::DOMString text() const { return m_text; }
370
371 private:
372     DOM::TextImpl *m_node;
373     long m_offset;
374     DOM::DOMString m_text;
375 };
376
377 //------------------------------------------------------------------------------------------
378 // InsertNodeBeforeCommand
379
380 class InsertNodeBeforeCommand : public EditCommand
381 {
382 public:
383     InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
384     virtual ~InsertNodeBeforeCommand();
385
386     virtual void doApply();
387     virtual void doUnapply();
388
389     DOM::NodeImpl *insertChild() const { return m_insertChild; }
390     DOM::NodeImpl *refChild() const { return m_refChild; }
391
392 private:
393     DOM::NodeImpl *m_insertChild;
394     DOM::NodeImpl *m_refChild; 
395 };
396
397 //------------------------------------------------------------------------------------------
398 // InsertLineBreakCommand
399
400 class InsertLineBreakCommand : public CompositeEditCommand
401 {
402 public:
403     InsertLineBreakCommand(DOM::DocumentImpl *document);
404
405     virtual void doApply();
406
407 private:
408     virtual bool preservesTypingStyle() const;
409     void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
410     void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
411 };
412
413 //------------------------------------------------------------------------------------------
414 // InsertParagraphSeparatorCommand
415
416 class InsertParagraphSeparatorCommand : public CompositeEditCommand
417 {
418 public:
419     InsertParagraphSeparatorCommand(DOM::DocumentImpl *document);
420     virtual ~InsertParagraphSeparatorCommand();
421
422     virtual void doApply();
423
424 private:
425     DOM::ElementImpl *createParagraphElement();
426     void setFullTypingStyleBeforeInsertion(const DOM::Position &);
427     void calculateAndSetTypingStyleAfterInsertion();
428
429     virtual bool preservesTypingStyle() const;
430
431     QPtrList<DOM::NodeImpl> ancestors;
432     QPtrList<DOM::NodeImpl> clonedNodes;
433     DOM::CSSMutableStyleDeclarationImpl *m_fullTypingStyle;
434 };
435
436 //------------------------------------------------------------------------------------------
437 // InsertParagraphSeparatorInQuotedContentCommand
438
439 class InsertParagraphSeparatorInQuotedContentCommand : public CompositeEditCommand
440 {
441 public:
442     InsertParagraphSeparatorInQuotedContentCommand(DOM::DocumentImpl *);
443     virtual ~InsertParagraphSeparatorInQuotedContentCommand();
444         
445     virtual void doApply();
446     
447 private:
448     bool isMailBlockquote(const DOM::NodeImpl *) const;
449
450     QPtrList<DOM::NodeImpl> ancestors;
451     QPtrList<DOM::NodeImpl> clonedNodes;
452     DOM::ElementImpl *m_breakNode;
453 };
454
455 //------------------------------------------------------------------------------------------
456 // InsertTextCommand
457
458 class InsertTextCommand : public CompositeEditCommand
459 {
460 public:
461     InsertTextCommand(DOM::DocumentImpl *document);
462
463     virtual void doApply();
464
465     void deleteCharacter();
466     void input(const DOM::DOMString &text, bool selectInsertedText = false);
467     
468     unsigned long charactersAdded() const { return m_charactersAdded; }
469     
470 private:
471     virtual bool isInsertTextCommand() const;
472
473     DOM::Position prepareForTextInsertion(bool adjustDownstream);
474     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
475
476     unsigned long m_charactersAdded;
477 };
478
479 //------------------------------------------------------------------------------------------
480 // JoinTextNodesCommand
481
482 class JoinTextNodesCommand : public EditCommand
483 {
484 public:
485     JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
486     virtual ~JoinTextNodesCommand();
487         
488     virtual void doApply();
489     virtual void doUnapply();
490
491     DOM::TextImpl *firstNode() const { return m_text1; }
492     DOM::TextImpl *secondNode() const { return m_text2; }
493
494 private:
495     DOM::TextImpl *m_text1;
496     DOM::TextImpl *m_text2;
497     unsigned long m_offset;
498 };
499
500 //------------------------------------------------------------------------------------------
501 // MoveSelectionCommand
502
503 class MoveSelectionCommand : public CompositeEditCommand
504 {
505 public:
506     MoveSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position, bool smartMove=false);
507     virtual ~MoveSelectionCommand();
508     
509     virtual void doApply();
510     virtual EditAction editingAction() const;
511     
512 private:
513     DOM::DocumentFragmentImpl *m_fragment;
514     DOM::Position m_position;
515     bool m_smartMove;
516 };
517
518 //------------------------------------------------------------------------------------------
519 // RebalanceWhitespaceCommand
520
521 class RebalanceWhitespaceCommand : public EditCommand
522 {
523 public:
524     RebalanceWhitespaceCommand(DOM::DocumentImpl *, const DOM::Position &);
525     virtual ~RebalanceWhitespaceCommand();
526
527     virtual void doApply();
528     virtual void doUnapply();
529
530 private:
531     enum { InvalidOffset = -1 };
532
533     virtual bool preservesTypingStyle() const;
534
535     DOM::DOMString m_beforeString;
536     DOM::DOMString m_afterString;
537     DOM::Position m_position;
538     long m_upstreamOffset;
539     long m_downstreamOffset;
540 };
541
542 //------------------------------------------------------------------------------------------
543 // RemoveCSSPropertyCommand
544
545 class RemoveCSSPropertyCommand : public EditCommand
546 {
547 public:
548     RemoveCSSPropertyCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
549     virtual ~RemoveCSSPropertyCommand();
550
551     virtual void doApply();
552     virtual void doUnapply();
553
554     DOM::CSSMutableStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
555     int property() const { return m_property; }
556     
557 private:
558     DOM::CSSMutableStyleDeclarationImpl *m_decl;
559     int m_property;
560     DOM::DOMString m_oldValue;
561     bool m_important;
562 };
563
564 //------------------------------------------------------------------------------------------
565 // RemoveNodeAttributeCommand
566
567 class RemoveNodeAttributeCommand : public EditCommand
568 {
569 public:
570     RemoveNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
571     virtual ~RemoveNodeAttributeCommand();
572
573     virtual void doApply();
574     virtual void doUnapply();
575
576     DOM::ElementImpl *element() const { return m_element; }
577     DOM::NodeImpl::Id attribute() const { return m_attribute; }
578     
579 private:
580     DOM::ElementImpl *m_element;
581     DOM::NodeImpl::Id m_attribute;
582     DOM::DOMString m_oldValue;
583 };
584
585 //------------------------------------------------------------------------------------------
586 // RemoveNodeCommand
587
588 class RemoveNodeCommand : public EditCommand
589 {
590 public:
591     RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
592     virtual ~RemoveNodeCommand();
593         
594     virtual void doApply();
595     virtual void doUnapply();
596
597     DOM::NodeImpl *node() const { return m_removeChild; }
598
599 private:
600     DOM::NodeImpl *m_parent;    
601     DOM::NodeImpl *m_removeChild;
602     DOM::NodeImpl *m_refChild;    
603 };
604
605 //------------------------------------------------------------------------------------------
606 // RemoveNodePreservingChildrenCommand
607
608 class RemoveNodePreservingChildrenCommand : public CompositeEditCommand
609 {
610 public:
611     RemoveNodePreservingChildrenCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
612     virtual ~RemoveNodePreservingChildrenCommand();
613         
614     virtual void doApply();
615
616     DOM::NodeImpl *node() const { return m_node; }
617
618 private:
619     DOM::NodeImpl *m_node;
620 };
621
622 //------------------------------------------------------------------------------------------
623 // ReplaceSelectionCommand
624
625 // --- ReplacementFragment helper class
626
627 class ReplacementFragment
628 {
629 public:
630     ReplacementFragment(DOM::DocumentFragmentImpl *fragment);
631     ~ReplacementFragment();
632
633     enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
634
635     DOM::DocumentFragmentImpl *root() const { return m_fragment; }
636     DOM::NodeImpl *firstChild() const;
637     DOM::NodeImpl *lastChild() const;
638
639     DOM::NodeImpl *mergeStartNode() const;
640     DOM::NodeImpl *mergeEndNode() const;
641     
642     void pruneEmptyNodes();
643
644     EFragmentType type() const { return m_type; }
645     bool isEmpty() const { return m_type == EmptyFragment; }
646     bool isSingleTextNode() const { return m_type == SingleTextNodeFragment; }
647     bool isTreeFragment() const { return m_type == TreeFragment; }
648
649     bool hasMoreThanOneBlock() const { return m_hasMoreThanOneBlock; }
650     bool hasInterchangeNewline() const { return m_hasInterchangeNewline; }
651
652 private:
653     // no copy construction or assignment
654     ReplacementFragment(const ReplacementFragment &);
655     ReplacementFragment &operator=(const ReplacementFragment &);
656
657     static bool isInterchangeNewlineNode(const DOM::NodeImpl *);
658     static bool isInterchangeConvertedSpaceSpan(const DOM::NodeImpl *);
659
660     // A couple simple DOM helpers
661     DOM::NodeImpl *enclosingBlock(DOM::NodeImpl *) const;
662     void removeNode(DOM::NodeImpl *);
663     void insertNodeBefore(DOM::NodeImpl *node, DOM::NodeImpl *refNode);
664
665     EFragmentType m_type;
666     DOM::DocumentFragmentImpl *m_fragment;
667     bool m_hasInterchangeNewline;
668     bool m_hasMoreThanOneBlock;
669 };
670
671 // free-floating helper functions
672 bool isProbablyBlock(const DOM::NodeImpl *);
673
674 class ReplaceSelectionCommand : public CompositeEditCommand
675 {
676 public:
677     ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false);
678     virtual ~ReplaceSelectionCommand();
679     
680     virtual void doApply();
681     virtual EditAction editingAction() const;
682
683 private:
684     void completeHTMLReplacement(const DOM::Position &, const DOM::Position &);
685     void completeHTMLReplacement(DOM::NodeImpl *, DOM::NodeImpl *);
686     
687     ReplacementFragment m_fragment;
688     bool m_selectReplacement;
689     bool m_smartReplace;
690 };
691
692 //------------------------------------------------------------------------------------------
693 // SetNodeAttributeCommand
694
695 class SetNodeAttributeCommand : public EditCommand
696 {
697 public:
698     SetNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
699     virtual ~SetNodeAttributeCommand();
700
701     virtual void doApply();
702     virtual void doUnapply();
703
704     DOM::ElementImpl *element() const { return m_element; }
705     DOM::NodeImpl::Id attribute() const { return m_attribute; }
706     DOM::DOMString value() const { return m_value; }
707     
708 private:
709     DOM::ElementImpl *m_element;
710     DOM::NodeImpl::Id m_attribute;
711     DOM::DOMString m_value;
712     DOM::DOMString m_oldValue;
713 };
714
715 //------------------------------------------------------------------------------------------
716 // SplitTextNodeCommand
717
718 class SplitTextNodeCommand : public EditCommand
719 {
720 public:
721     SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
722     virtual ~SplitTextNodeCommand();
723         
724     virtual void doApply();
725     virtual void doUnapply();
726
727     DOM::TextImpl *node() const { return m_text2; }
728     long offset() const { return m_offset; }
729
730 private:
731     DOM::TextImpl *m_text1;
732     DOM::TextImpl *m_text2;
733     unsigned long m_offset;
734 };
735
736 //------------------------------------------------------------------------------------------
737 // TypingCommand
738
739 class TypingCommand : public CompositeEditCommand
740 {
741 public:
742     enum ETypingCommand { 
743         DeleteKey, 
744         InsertText, 
745         InsertLineBreak, 
746         InsertParagraphSeparator,
747         InsertParagraphSeparatorInQuotedContent,
748     };
749
750     TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
751
752     static void deleteKeyPressed(DOM::DocumentImpl *);
753     static void insertText(DOM::DocumentImpl *, const DOM::DOMString &, bool selectInsertedText = false);
754     static void insertLineBreak(DOM::DocumentImpl *);
755     static void insertParagraphSeparator(DOM::DocumentImpl *);
756     static void insertParagraphSeparatorInQuotedContent(DOM::DocumentImpl *);
757     static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
758     static void closeTyping(const EditCommandPtr &);
759     
760     virtual void doApply();
761     virtual EditAction editingAction() const;
762
763     bool openForMoreTyping() const { return m_openForMoreTyping; }
764     void closeTyping() { m_openForMoreTyping = false; }
765
766     void insertText(const DOM::DOMString &text, bool selectInsertedText);
767     void insertLineBreak();
768     void insertParagraphSeparatorInQuotedContent();
769     void insertParagraphSeparator();
770     void deleteKeyPressed();
771
772 private:
773     virtual bool isTypingCommand() const;
774     virtual bool preservesTypingStyle() const;
775
776     void issueCommandForDeleteKey();
777     void removeCommand(const EditCommandPtr &);
778     void markMisspellingsAfterTyping();
779     void typingAddedToOpenCommand();
780     
781     ETypingCommand m_commandType;
782     DOM::DOMString m_textToInsert;
783     bool m_openForMoreTyping;
784     bool m_applyEditing;
785     bool m_selectInsertedText;
786 };
787
788 //------------------------------------------------------------------------------------------
789
790 DOM::ElementImpl *createDefaultParagraphElement(DOM::DocumentImpl *document);
791 DOM::ElementImpl *createBlockPlaceholderElement(DOM::DocumentImpl *document);
792 DOM::ElementImpl *createBreakElement(DOM::DocumentImpl *document);
793
794 //------------------------------------------------------------------------------------------
795
796 } // end namespace khtml
797
798 #endif