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