Reviewed by Harrison
[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 removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
199     void removeFullySelectedNode(DOM::NodeImpl *);
200     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
201     void removeNode(DOM::NodeImpl *removeChild);
202     void removeNodePreservingChildren(DOM::NodeImpl *node);
203     void replaceTextInNode(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
204     void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
205     void splitTextNode(DOM::TextImpl *text, long offset);
206
207     DOM::NodeImpl *applyTypingStyle(DOM::NodeImpl *) const;
208
209     void deleteInsignificantText(DOM::TextImpl *, int start, int end);
210     void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
211     void deleteInsignificantTextDownstream(const DOM::Position &);
212
213     void insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
214     bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
215
216     QValueList<EditCommandPtr> m_cmds;
217 };
218
219 //==========================================================================================
220 // Concrete commands
221 //------------------------------------------------------------------------------------------
222 // AppendNodeCommand
223
224 class AppendNodeCommand : public EditCommand
225 {
226 public:
227     AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
228     virtual ~AppendNodeCommand();
229
230     virtual void doApply();
231     virtual void doUnapply();
232
233     DOM::NodeImpl *appendChild() const { return m_appendChild; }
234     DOM::NodeImpl *parentNode() const { return m_parentNode; }
235
236 private:
237     DOM::NodeImpl *m_appendChild;
238     DOM::NodeImpl *m_parentNode;    
239 };
240
241 //------------------------------------------------------------------------------------------
242 // ApplyStyleCommand
243
244 class ApplyStyleCommand : public CompositeEditCommand
245 {
246 public:
247     ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style);
248     virtual ~ApplyStyleCommand();
249         
250     virtual void doApply();
251
252     DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style; }
253
254 private:
255     // style-removal helpers
256     bool isHTMLStyleNode(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
257     void removeHTMLStyleNode(DOM::HTMLElementImpl *);
258     void removeCSSStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
259     void removeBlockStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
260     void removeInlineStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
261     bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
262
263     // style-application helpers
264     void applyBlockStyle(DOM::CSSMutableStyleDeclarationImpl *);
265     void applyInlineStyle(DOM::CSSMutableStyleDeclarationImpl *);
266     void addBlockStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
267     void addInlineStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *start, DOM::NodeImpl *end);
268     bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
269     DOM::NodeImpl *splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
270     void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
271     DOM::Position positionInsertionPoint(DOM::Position);
272     
273     DOM::CSSMutableStyleDeclarationImpl *m_style;
274 };
275
276 //------------------------------------------------------------------------------------------
277 // DeleteFromTextNodeCommand
278
279 class DeleteFromTextNodeCommand : public EditCommand
280 {
281 public:
282     DeleteFromTextNodeCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
283     virtual ~DeleteFromTextNodeCommand();
284         
285     virtual void doApply();
286     virtual void doUnapply();
287
288     DOM::TextImpl *node() const { return m_node; }
289     long offset() const { return m_offset; }
290     long count() const { return m_count; }
291
292 private:
293     DOM::TextImpl *m_node;
294     long m_offset;
295     long m_count;
296     DOM::DOMString m_text;
297 };
298
299 //------------------------------------------------------------------------------------------
300 // DeleteSelectionCommand
301
302 class DeleteSelectionCommand : public CompositeEditCommand
303
304 public:
305     DeleteSelectionCommand(DOM::DocumentImpl *document, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
306     DeleteSelectionCommand(DOM::DocumentImpl *document, const khtml::Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
307         
308     virtual void doApply();
309     
310 private:
311     virtual bool preservesTypingStyle() const;
312
313     void initializePositionData();
314     void saveTypingStyleState();
315     bool handleSpecialCaseAllContentDelete();
316     bool handleSpecialCaseBRDelete();
317     void handleGeneralDelete();
318     void fixupWhitespace();
319     void moveNodesAfterNode();
320     void calculateEndingPosition();
321     void calculateTypingStyleAfterDelete();
322     void clearTransientState();
323
324     bool m_hasSelectionToDelete;
325     bool m_smartDelete;
326     bool m_mergeBlocksAfterDelete;
327     bool m_trailingWhitespaceValid;
328
329     // This data is transient and should be cleared at the end of the doApply function.
330     khtml::Selection m_selectionToDelete;
331     DOM::Position m_upstreamStart;
332     DOM::Position m_downstreamStart;
333     DOM::Position m_upstreamEnd;
334     DOM::Position m_downstreamEnd;
335     DOM::Position m_endingPosition;
336     DOM::Position m_leadingWhitespace;
337     DOM::Position m_trailingWhitespace;
338     DOM::NodeImpl *m_startBlock;
339     DOM::NodeImpl *m_endBlock;
340     DOM::NodeImpl *m_startNode;
341     DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
342 };
343
344 //------------------------------------------------------------------------------------------
345 // InsertIntoTextNode
346
347 class InsertIntoTextNode : public EditCommand
348 {
349 public:
350     InsertIntoTextNode(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
351     virtual ~InsertIntoTextNode();
352         
353     virtual void doApply();
354     virtual void doUnapply();
355
356     DOM::TextImpl *node() const { return m_node; }
357     long offset() const { return m_offset; }
358     DOM::DOMString text() const { return m_text; }
359
360 private:
361     DOM::TextImpl *m_node;
362     long m_offset;
363     DOM::DOMString m_text;
364 };
365
366 //------------------------------------------------------------------------------------------
367 // InsertNodeBeforeCommand
368
369 class InsertNodeBeforeCommand : public EditCommand
370 {
371 public:
372     InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
373     virtual ~InsertNodeBeforeCommand();
374
375     virtual void doApply();
376     virtual void doUnapply();
377
378     DOM::NodeImpl *insertChild() const { return m_insertChild; }
379     DOM::NodeImpl *refChild() const { return m_refChild; }
380
381 private:
382     DOM::NodeImpl *m_insertChild;
383     DOM::NodeImpl *m_refChild; 
384 };
385
386 //------------------------------------------------------------------------------------------
387 // InsertLineBreakCommand
388
389 class InsertLineBreakCommand : public CompositeEditCommand
390 {
391 public:
392     InsertLineBreakCommand(DOM::DocumentImpl *document);
393
394     virtual void doApply();
395
396 private:
397     void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
398     void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
399 };
400
401 //------------------------------------------------------------------------------------------
402 // InsertParagraphSeparatorCommand
403
404 class InsertParagraphSeparatorCommand : public CompositeEditCommand
405 {
406 public:
407     InsertParagraphSeparatorCommand(DOM::DocumentImpl *document);
408     virtual ~InsertParagraphSeparatorCommand();
409
410     virtual void doApply();
411
412 private:
413     QPtrList<DOM::NodeImpl> ancestors;
414     QPtrList<DOM::NodeImpl> clonedNodes;
415 };
416
417 //------------------------------------------------------------------------------------------
418 // InsertParagraphSeparatorInQuotedContentCommand
419
420 class InsertParagraphSeparatorInQuotedContentCommand : public CompositeEditCommand
421 {
422 public:
423     InsertParagraphSeparatorInQuotedContentCommand(DOM::DocumentImpl *);
424     virtual ~InsertParagraphSeparatorInQuotedContentCommand();
425         
426     virtual void doApply();
427     
428 private:
429     bool isMailBlockquote(const DOM::NodeImpl *) const;
430
431     QPtrList<DOM::NodeImpl> ancestors;
432     QPtrList<DOM::NodeImpl> clonedNodes;
433     DOM::ElementImpl *m_breakNode;
434 };
435
436 //------------------------------------------------------------------------------------------
437 // InsertTextCommand
438
439 class InsertTextCommand : public CompositeEditCommand
440 {
441 public:
442     InsertTextCommand(DOM::DocumentImpl *document);
443
444     virtual void doApply();
445
446     void deleteCharacter();
447     void input(const DOM::DOMString &text, bool selectInsertedText = false);
448     
449     unsigned long charactersAdded() const { return m_charactersAdded; }
450     
451 private:
452     virtual bool isInsertTextCommand() const;
453
454     DOM::Position prepareForTextInsertion(bool adjustDownstream);
455     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
456
457     unsigned long m_charactersAdded;
458 };
459
460 //------------------------------------------------------------------------------------------
461 // JoinTextNodesCommand
462
463 class JoinTextNodesCommand : public EditCommand
464 {
465 public:
466     JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
467     virtual ~JoinTextNodesCommand();
468         
469     virtual void doApply();
470     virtual void doUnapply();
471
472     DOM::TextImpl *firstNode() const { return m_text1; }
473     DOM::TextImpl *secondNode() const { return m_text2; }
474
475 private:
476     DOM::TextImpl *m_text1;
477     DOM::TextImpl *m_text2;
478     unsigned long m_offset;
479 };
480
481 //------------------------------------------------------------------------------------------
482 // ReplaceSelectionCommand
483
484 class ReplaceSelectionCommand : public CompositeEditCommand
485 {
486 public:
487     ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false);
488     virtual ~ReplaceSelectionCommand();
489     
490     virtual void doApply();
491
492 private:
493     DOM::DocumentFragmentImpl *m_fragment;
494     bool m_selectReplacement;
495     bool m_smartReplace;
496 };
497
498 //------------------------------------------------------------------------------------------
499 // MoveSelectionCommand
500
501 class MoveSelectionCommand : public CompositeEditCommand
502 {
503 public:
504     MoveSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position, bool smartMove=false);
505     virtual ~MoveSelectionCommand();
506     
507     virtual void doApply();
508     
509 private:
510     DOM::DocumentFragmentImpl *m_fragment;
511     DOM::Position m_position;
512     bool m_smartMove;
513 };
514
515 //------------------------------------------------------------------------------------------
516 // RemoveCSSPropertyCommand
517
518 class RemoveCSSPropertyCommand : public EditCommand
519 {
520 public:
521     RemoveCSSPropertyCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
522     virtual ~RemoveCSSPropertyCommand();
523
524     virtual void doApply();
525     virtual void doUnapply();
526
527     DOM::CSSMutableStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
528     int property() const { return m_property; }
529     
530 private:
531     DOM::CSSMutableStyleDeclarationImpl *m_decl;
532     int m_property;
533     DOM::DOMString m_oldValue;
534     bool m_important;
535 };
536
537 //------------------------------------------------------------------------------------------
538 // RemoveNodeAttributeCommand
539
540 class RemoveNodeAttributeCommand : public EditCommand
541 {
542 public:
543     RemoveNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
544     virtual ~RemoveNodeAttributeCommand();
545
546     virtual void doApply();
547     virtual void doUnapply();
548
549     DOM::ElementImpl *element() const { return m_element; }
550     DOM::NodeImpl::Id attribute() const { return m_attribute; }
551     
552 private:
553     DOM::ElementImpl *m_element;
554     DOM::NodeImpl::Id m_attribute;
555     DOM::DOMString m_oldValue;
556 };
557
558 //------------------------------------------------------------------------------------------
559 // RemoveNodeCommand
560
561 class RemoveNodeCommand : public EditCommand
562 {
563 public:
564     RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
565     virtual ~RemoveNodeCommand();
566         
567     virtual void doApply();
568     virtual void doUnapply();
569
570     DOM::NodeImpl *node() const { return m_removeChild; }
571
572 private:
573     DOM::NodeImpl *m_parent;    
574     DOM::NodeImpl *m_removeChild;
575     DOM::NodeImpl *m_refChild;    
576 };
577
578 //------------------------------------------------------------------------------------------
579 // RemoveNodePreservingChildrenCommand
580
581 class RemoveNodePreservingChildrenCommand : public CompositeEditCommand
582 {
583 public:
584     RemoveNodePreservingChildrenCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
585     virtual ~RemoveNodePreservingChildrenCommand();
586         
587     virtual void doApply();
588
589     DOM::NodeImpl *node() const { return m_node; }
590
591 private:
592     DOM::NodeImpl *m_node;
593 };
594
595 //------------------------------------------------------------------------------------------
596 // SetNodeAttributeCommand
597
598 class SetNodeAttributeCommand : public EditCommand
599 {
600 public:
601     SetNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
602     virtual ~SetNodeAttributeCommand();
603
604     virtual void doApply();
605     virtual void doUnapply();
606
607     DOM::ElementImpl *element() const { return m_element; }
608     DOM::NodeImpl::Id attribute() const { return m_attribute; }
609     DOM::DOMString value() const { return m_value; }
610     
611 private:
612     DOM::ElementImpl *m_element;
613     DOM::NodeImpl::Id m_attribute;
614     DOM::DOMString m_value;
615     DOM::DOMString m_oldValue;
616 };
617
618 //------------------------------------------------------------------------------------------
619 // SplitTextNodeCommand
620
621 class SplitTextNodeCommand : public EditCommand
622 {
623 public:
624     SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
625     virtual ~SplitTextNodeCommand();
626         
627     virtual void doApply();
628     virtual void doUnapply();
629
630     DOM::TextImpl *node() const { return m_text2; }
631     long offset() const { return m_offset; }
632
633 private:
634     DOM::TextImpl *m_text1;
635     DOM::TextImpl *m_text2;
636     unsigned long m_offset;
637 };
638
639 //------------------------------------------------------------------------------------------
640 // TypingCommand
641
642 class TypingCommand : public CompositeEditCommand
643 {
644 public:
645     enum ETypingCommand { 
646         DeleteKey, 
647         InsertText, 
648         InsertLineBreak, 
649         InsertParagraphSeparator,
650         InsertParagraphSeparatorInQuotedContent,
651     };
652
653     TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
654
655     static void deleteKeyPressed(DOM::DocumentImpl *);
656     static void insertText(DOM::DocumentImpl *, const DOM::DOMString &, bool selectInsertedText = false);
657     static void insertLineBreak(DOM::DocumentImpl *);
658     static void insertParagraphSeparator(DOM::DocumentImpl *);
659     static void insertParagraphSeparatorInQuotedContent(DOM::DocumentImpl *);
660     static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
661     static void closeTyping(const EditCommandPtr &);
662     
663     virtual void doApply();
664
665     bool openForMoreTyping() const { return m_openForMoreTyping; }
666     void closeTyping() { m_openForMoreTyping = false; }
667
668     void insertText(const DOM::DOMString &text, bool selectInsertedText);
669     void insertLineBreak();
670     void insertParagraphSeparatorInQuotedContent();
671     void insertParagraphSeparator();
672     void deleteKeyPressed();
673
674 private:
675     virtual bool isTypingCommand() const;
676     virtual bool preservesTypingStyle() const;
677
678     void issueCommandForDeleteKey();
679     void removeCommand(const EditCommandPtr &);
680     void markMisspellingsAfterTyping();
681     void typingAddedToOpenCommand();
682     
683     ETypingCommand m_commandType;
684     DOM::DOMString m_textToInsert;
685     bool m_openForMoreTyping;
686     bool m_applyEditing;
687     bool m_selectInsertedText;
688 };
689
690 //------------------------------------------------------------------------------------------
691
692 } // end namespace khtml
693
694 #endif