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