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