8e135857d73ebfe7eac16af6bff5ceb241dd5269
[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 "qmap.h"
32 #include "qptrlist.h"
33 #include "qvaluelist.h"
34 #include "selection.h"
35 #include "shared.h"
36
37 namespace DOM {
38     class CSSMutableStyleDeclarationImpl;
39     class CSSProperty;
40     class CSSStyleDeclarationImpl;
41     class DocumentFragmentImpl;
42     class HTMLElementImpl;
43     class TextImpl;
44 }
45
46 namespace khtml {
47
48 class EditCommand;
49 class Selection;
50 class VisiblePosition;
51
52 //------------------------------------------------------------------------------------------
53 // EditCommandPtr
54
55 class EditCommandPtr : public SharedPtr<EditCommand>
56 {
57 public:
58     EditCommandPtr();
59     EditCommandPtr(EditCommand *);
60     EditCommandPtr(const EditCommandPtr &);
61     ~EditCommandPtr();
62
63     EditCommandPtr &operator=(const EditCommandPtr &);
64
65     bool isCompositeStep() const;
66
67     void apply() const;
68     void unapply() const;
69     void reapply() const;
70
71     EditAction editingAction() const;
72
73     DOM::DocumentImpl * const document() const;
74
75     Selection startingSelection() const;
76     Selection endingSelection() const;
77
78     void setStartingSelection(const Selection &s) const;
79     void setStartingSelection(const VisiblePosition &p) const;
80     void setStartingSelection(const DOM::Position &p, EAffinity affinity) const;
81     void setEndingSelection(const Selection &s) const;
82     void setEndingSelection(const VisiblePosition &p) const;
83     void setEndingSelection(const DOM::Position &p, EAffinity affinity) const;
84
85     DOM::CSSMutableStyleDeclarationImpl *typingStyle() const;
86     void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *) const;
87
88     EditCommandPtr parent() const;
89     void setParent(const EditCommandPtr &) const;
90
91     bool isInsertTextCommand() const;
92     bool isInsertLineBreakCommand() const;
93     bool isTypingCommand() const;
94
95     static EditCommandPtr &emptyCommand();
96 };
97
98 //------------------------------------------------------------------------------------------
99 // StyleChange
100
101 class StyleChange {
102 public:
103     enum ELegacyHTMLStyles { DoNotUseLegacyHTMLStyles, UseLegacyHTMLStyles };
104
105     explicit StyleChange(DOM::CSSStyleDeclarationImpl *, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
106     StyleChange(DOM::CSSStyleDeclarationImpl *, const DOM::Position &, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
107
108     static ELegacyHTMLStyles styleModeForParseMode(bool);
109
110     DOM::DOMString cssStyle() const { return m_cssStyle; }
111     bool applyBold() const { return m_applyBold; }
112     bool applyItalic() const { return m_applyItalic; }
113     bool applyFontColor() const { return m_applyFontColor.length() > 0; }
114     bool applyFontFace() const { return m_applyFontFace.length() > 0; }
115     bool applyFontSize() const { return m_applyFontSize.length() > 0; }
116
117     DOM::DOMString fontColor() { return m_applyFontColor; }
118     DOM::DOMString fontFace() { return m_applyFontFace; }
119     DOM::DOMString fontSize() { return m_applyFontSize; }
120
121     bool usesLegacyStyles() const { return m_usesLegacyStyles; }
122
123 private:
124     void init(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
125     bool checkForLegacyHTMLStyleChange(const DOM::CSSProperty *);
126     static bool currentlyHasStyle(const DOM::Position &, const DOM::CSSProperty *);
127     
128     DOM::DOMString m_cssStyle;
129     bool m_applyBold;
130     bool m_applyItalic;
131     DOM::DOMString m_applyFontColor;
132     DOM::DOMString m_applyFontFace;
133     DOM::DOMString m_applyFontSize;
134     bool m_usesLegacyStyles;
135 };
136
137 //------------------------------------------------------------------------------------------
138 // EditCommand
139
140 class EditCommand : public Shared<EditCommand>
141 {
142 public:
143     EditCommand(DOM::DocumentImpl *);
144     virtual ~EditCommand();
145
146     bool isCompositeStep() const { return m_parent != 0; }
147     EditCommand *parent() const { return m_parent; }
148     void setParent(EditCommand *parent) { m_parent = parent; }
149
150     enum ECommandState { NotApplied, Applied };
151     
152     void apply();       
153     void unapply();
154     void reapply();
155
156     virtual void doApply() = 0;
157     virtual void doUnapply() = 0;
158     virtual void doReapply();  // calls doApply()
159
160     virtual EditAction editingAction() const;
161
162     virtual DOM::DocumentImpl * const document() const { return m_document; }
163
164     Selection startingSelection() const { return m_startingSelection; }
165     Selection endingSelection() const { return m_endingSelection; }
166
167     void setEndingSelectionNeedsLayout(bool flag=true) { m_endingSelection.setNeedsLayout(flag); }
168         
169     ECommandState state() const { return m_state; }
170     void setState(ECommandState state) { m_state = state; }
171
172     void setStartingSelection(const Selection &s);
173     void setStartingSelection(const VisiblePosition &p);
174     void setStartingSelection(const DOM::Position &p, EAffinity affinity);
175     void setEndingSelection(const Selection &s);
176     void setEndingSelection(const VisiblePosition &p);
177     void setEndingSelection(const DOM::Position &p, EAffinity affinity);
178
179     DOM::CSSMutableStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
180     void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
181     
182     DOM::CSSMutableStyleDeclarationImpl *styleAtPosition(const DOM::Position &pos);
183     
184     virtual bool isInsertTextCommand() const;
185     virtual bool isTypingCommand() const;
186     
187 private:
188     void assignTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
189
190     virtual bool preservesTypingStyle() const;
191
192     DOM::DocumentImpl *m_document;
193     ECommandState m_state;
194     Selection m_startingSelection;
195     Selection m_endingSelection;
196     DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
197     EditCommand *m_parent;
198 };
199
200 //------------------------------------------------------------------------------------------
201 // CompositeEditCommand
202
203 class CompositeEditCommand : public EditCommand
204 {
205 public:
206     CompositeEditCommand(DOM::DocumentImpl *);
207         
208     virtual void doUnapply();
209     virtual void doReapply();
210
211 protected:
212     //
213     // sugary-sweet convenience functions to help create and apply edit commands in composite commands
214     //
215     void appendNode(DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
216     void applyCommandToComposite(EditCommandPtr &);
217     void applyStyle(DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes);
218     void deleteKeyPressed();
219     void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
220     void deleteSelection(const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
221     void deleteTextFromNode(DOM::TextImpl *node, long offset, long count);
222     void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
223     void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
224     void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
225     void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
226     void insertParagraphSeparator();
227     void insertTextIntoNode(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
228     void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
229     void rebalanceWhitespace();
230     void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
231     void removeFullySelectedNode(DOM::NodeImpl *node);
232     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
233     void removeChildrenInRange(DOM::NodeImpl *node, int from, int to);
234     void removeNode(DOM::NodeImpl *removeChild);
235     void removeNodePreservingChildren(DOM::NodeImpl *node);
236     void replaceTextInNode(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
237     void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
238     void splitTextNode(DOM::TextImpl *text, long offset);
239     void splitElement(DOM::ElementImpl *element, DOM::NodeImpl *atChild);
240     void mergeIdenticalElements(DOM::ElementImpl *first, DOM::ElementImpl *second);
241     void wrapContentsInDummySpan(DOM::ElementImpl *element);
242     void splitTextNodeContainingElement(DOM::TextImpl *text, long offset);
243
244     void deleteInsignificantText(DOM::TextImpl *, int start, int end);
245     void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
246     void deleteInsignificantTextDownstream(const DOM::Position &);
247
248     DOM::NodeImpl *appendBlockPlaceholder(DOM::NodeImpl *);
249     DOM::NodeImpl *insertBlockPlaceholder(const DOM::Position &pos);
250     DOM::NodeImpl *addBlockPlaceholderIfNeeded(DOM::NodeImpl *);
251     bool removeBlockPlaceholder(DOM::NodeImpl *);
252     DOM::NodeImpl *findBlockPlaceholder(DOM::NodeImpl *);
253
254     void moveParagraphContentsToNewBlockIfNecessary(const DOM::Position &);
255
256     QValueList<EditCommandPtr> m_cmds;
257 };
258
259 //==========================================================================================
260 // Concrete commands
261 //------------------------------------------------------------------------------------------
262 // AppendNodeCommand
263
264 class AppendNodeCommand : public EditCommand
265 {
266 public:
267     AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
268     virtual ~AppendNodeCommand();
269
270     virtual void doApply();
271     virtual void doUnapply();
272
273     DOM::NodeImpl *appendChild() const { return m_appendChild; }
274     DOM::NodeImpl *parentNode() const { return m_parentNode; }
275
276 private:
277     DOM::NodeImpl *m_appendChild;
278     DOM::NodeImpl *m_parentNode;    
279 };
280
281 //------------------------------------------------------------------------------------------
282 // ApplyStyleCommand
283
284 class ApplyStyleCommand : public CompositeEditCommand
285 {
286 public:
287     enum EPropertyLevel { PropertyDefault, ForceBlockProperties };
288
289     ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes, EPropertyLevel=PropertyDefault);
290     virtual ~ApplyStyleCommand();
291         
292     virtual void doApply();
293     virtual EditAction editingAction() const;
294
295     DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style; }
296
297 private:
298     // style-removal helpers
299     bool isHTMLStyleNode(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
300     void removeHTMLStyleNode(DOM::HTMLElementImpl *);
301     void removeHTMLFontStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
302     void removeCSSStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
303     void removeBlockStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
304     void removeInlineStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
305     bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
306     bool nodeFullyUnselected(DOM::NodeImpl *node, const DOM::Position &start, const DOM::Position &end) const;
307     DOM::CSSMutableStyleDeclarationImpl *extractTextDecorationStyle(DOM::NodeImpl *node);
308     DOM::CSSMutableStyleDeclarationImpl *extractAndNegateTextDecorationStyle(DOM::NodeImpl *node);
309     void applyTextDecorationStyle(DOM::NodeImpl *node, DOM::CSSMutableStyleDeclarationImpl *style);
310     void pushDownTextDecorationStyleAroundNode(DOM::NodeImpl *node, const DOM::Position &start, const DOM::Position &end, bool force);
311     void pushDownTextDecorationStyleAtBoundaries(const DOM::Position &start, const DOM::Position &end);
312     
313     // style-application helpers
314     void applyBlockStyle(DOM::CSSMutableStyleDeclarationImpl *);
315     void applyRelativeFontStyleChange(DOM::CSSMutableStyleDeclarationImpl *);
316     void applyInlineStyle(DOM::CSSMutableStyleDeclarationImpl *);
317     void addBlockStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *);
318     void addInlineStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *start, DOM::NodeImpl *end);
319     bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
320     bool splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
321     bool splitTextElementAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
322     bool splitTextElementAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
323     bool mergeStartWithPreviousIfIdentical(const DOM::Position &start, const DOM::Position &end);
324     bool mergeEndWithNextIfIdentical(const DOM::Position &start, const DOM::Position &end);
325     void cleanUpEmptyStyleSpans(const DOM::Position &start, const DOM::Position &end);
326
327     void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
328     float computedFontSize(const DOM::NodeImpl *);
329     void joinChildTextNodes(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end);
330     
331     DOM::CSSMutableStyleDeclarationImpl *m_style;
332     EditAction m_editingAction;
333     EPropertyLevel m_propertyLevel;
334 };
335
336 //------------------------------------------------------------------------------------------
337 // DeleteFromTextNodeCommand
338
339 class DeleteFromTextNodeCommand : public EditCommand
340 {
341 public:
342     DeleteFromTextNodeCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
343     virtual ~DeleteFromTextNodeCommand();
344         
345     virtual void doApply();
346     virtual void doUnapply();
347
348     DOM::TextImpl *node() const { return m_node; }
349     long offset() const { return m_offset; }
350     long count() const { return m_count; }
351
352 private:
353     DOM::TextImpl *m_node;
354     long m_offset;
355     long m_count;
356     DOM::DOMString m_text;
357 };
358
359 //------------------------------------------------------------------------------------------
360 // DeleteSelectionCommand
361
362 class DeleteSelectionCommand : public CompositeEditCommand
363
364 public:
365     DeleteSelectionCommand(DOM::DocumentImpl *document, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
366     DeleteSelectionCommand(DOM::DocumentImpl *document, const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
367         
368     virtual void doApply();
369     virtual EditAction editingAction() const;
370     
371 private:
372     virtual bool preservesTypingStyle() const;
373
374     void initializePositionData();
375     void saveTypingStyleState();
376     void insertPlaceholderForAncestorBlockContent();
377     bool handleSpecialCaseBRDelete();
378     void handleGeneralDelete();
379     void fixupWhitespace();
380     void moveNodesAfterNode();
381     void calculateEndingPosition();
382     void calculateTypingStyleAfterDelete(DOM::NodeImpl *insertedPlaceholder);
383     void clearTransientState();
384
385     void setStartNode(DOM::NodeImpl *);
386
387     bool m_hasSelectionToDelete;
388     bool m_smartDelete;
389     bool m_mergeBlocksAfterDelete;
390     bool m_trailingWhitespaceValid;
391
392     // This data is transient and should be cleared at the end of the doApply function.
393     Selection m_selectionToDelete;
394     DOM::Position m_upstreamStart;
395     DOM::Position m_downstreamStart;
396     DOM::Position m_upstreamEnd;
397     DOM::Position m_downstreamEnd;
398     DOM::Position m_endingPosition;
399     DOM::Position m_leadingWhitespace;
400     DOM::Position m_trailingWhitespace;
401     DOM::NodeImpl *m_startBlock;
402     DOM::NodeImpl *m_endBlock;
403     DOM::NodeImpl *m_startNode;
404     DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
405 };
406
407 //------------------------------------------------------------------------------------------
408 // InsertIntoTextNode
409
410 class InsertIntoTextNode : public EditCommand
411 {
412 public:
413     InsertIntoTextNode(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
414     virtual ~InsertIntoTextNode();
415         
416     virtual void doApply();
417     virtual void doUnapply();
418
419     DOM::TextImpl *node() const { return m_node; }
420     long offset() const { return m_offset; }
421     DOM::DOMString text() const { return m_text; }
422
423 private:
424     DOM::TextImpl *m_node;
425     long m_offset;
426     DOM::DOMString m_text;
427 };
428
429 //------------------------------------------------------------------------------------------
430 // InsertNodeBeforeCommand
431
432 class InsertNodeBeforeCommand : public EditCommand
433 {
434 public:
435     InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
436     virtual ~InsertNodeBeforeCommand();
437
438     virtual void doApply();
439     virtual void doUnapply();
440
441     DOM::NodeImpl *insertChild() const { return m_insertChild; }
442     DOM::NodeImpl *refChild() const { return m_refChild; }
443
444 private:
445     DOM::NodeImpl *m_insertChild;
446     DOM::NodeImpl *m_refChild; 
447 };
448
449 //------------------------------------------------------------------------------------------
450 // InsertLineBreakCommand
451
452 class InsertLineBreakCommand : public CompositeEditCommand
453 {
454 public:
455     InsertLineBreakCommand(DOM::DocumentImpl *document);
456
457     virtual void doApply();
458
459 private:
460     virtual bool preservesTypingStyle() const;
461     void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
462     void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
463 };
464
465 //------------------------------------------------------------------------------------------
466 // InsertParagraphSeparatorCommand
467
468 class InsertParagraphSeparatorCommand : public CompositeEditCommand
469 {
470 public:
471     InsertParagraphSeparatorCommand(DOM::DocumentImpl *document);
472     virtual ~InsertParagraphSeparatorCommand();
473
474     virtual void doApply();
475
476 private:
477     DOM::ElementImpl *createParagraphElement();
478     void calculateStyleBeforeInsertion(const DOM::Position &);
479     void applyStyleAfterInsertion();
480
481     virtual bool preservesTypingStyle() const;
482
483     QPtrList<DOM::NodeImpl> ancestors;
484     QPtrList<DOM::NodeImpl> clonedNodes;
485     DOM::CSSMutableStyleDeclarationImpl *m_style;
486 };
487
488 //------------------------------------------------------------------------------------------
489 // InsertParagraphSeparatorInQuotedContentCommand
490
491 class InsertParagraphSeparatorInQuotedContentCommand : public CompositeEditCommand
492 {
493 public:
494     InsertParagraphSeparatorInQuotedContentCommand(DOM::DocumentImpl *);
495     virtual ~InsertParagraphSeparatorInQuotedContentCommand();
496         
497     virtual void doApply();
498     
499 private:
500     QPtrList<DOM::NodeImpl> ancestors;
501     QPtrList<DOM::NodeImpl> clonedNodes;
502     DOM::ElementImpl *m_breakNode;
503 };
504
505 //------------------------------------------------------------------------------------------
506 // InsertTextCommand
507
508 class InsertTextCommand : public CompositeEditCommand
509 {
510 public:
511     InsertTextCommand(DOM::DocumentImpl *document);
512
513     virtual void doApply();
514
515     void deleteCharacter();
516     void input(const DOM::DOMString &text, bool selectInsertedText = false);
517     
518     unsigned long charactersAdded() const { return m_charactersAdded; }
519     
520 private:
521     virtual bool isInsertTextCommand() const;
522
523     DOM::Position prepareForTextInsertion(bool adjustDownstream);
524     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
525
526     unsigned long m_charactersAdded;
527 };
528
529 //------------------------------------------------------------------------------------------
530 // JoinTextNodesCommand
531
532 class JoinTextNodesCommand : public EditCommand
533 {
534 public:
535     JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
536     virtual ~JoinTextNodesCommand();
537         
538     virtual void doApply();
539     virtual void doUnapply();
540
541     DOM::TextImpl *firstNode() const { return m_text1; }
542     DOM::TextImpl *secondNode() const { return m_text2; }
543
544 private:
545     DOM::TextImpl *m_text1;
546     DOM::TextImpl *m_text2;
547     unsigned long m_offset;
548 };
549
550 //------------------------------------------------------------------------------------------
551 // MoveSelectionCommand
552
553 class MoveSelectionCommand : public CompositeEditCommand
554 {
555 public:
556     MoveSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position, bool smartMove=false);
557     virtual ~MoveSelectionCommand();
558     
559     virtual void doApply();
560     virtual EditAction editingAction() const;
561     
562 private:
563     DOM::DocumentFragmentImpl *m_fragment;
564     DOM::Position m_position;
565     bool m_smartMove;
566 };
567
568 //------------------------------------------------------------------------------------------
569 // RebalanceWhitespaceCommand
570
571 class RebalanceWhitespaceCommand : public EditCommand
572 {
573 public:
574     RebalanceWhitespaceCommand(DOM::DocumentImpl *, const DOM::Position &);
575     virtual ~RebalanceWhitespaceCommand();
576
577     virtual void doApply();
578     virtual void doUnapply();
579
580 private:
581     enum { InvalidOffset = -1 };
582
583     virtual bool preservesTypingStyle() const;
584
585     DOM::DOMString m_beforeString;
586     DOM::DOMString m_afterString;
587     DOM::Position m_position;
588     long m_upstreamOffset;
589     long m_downstreamOffset;
590 };
591
592 //------------------------------------------------------------------------------------------
593 // RemoveCSSPropertyCommand
594
595 class RemoveCSSPropertyCommand : public EditCommand
596 {
597 public:
598     RemoveCSSPropertyCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
599     virtual ~RemoveCSSPropertyCommand();
600
601     virtual void doApply();
602     virtual void doUnapply();
603
604     DOM::CSSMutableStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
605     int property() const { return m_property; }
606     
607 private:
608     DOM::CSSMutableStyleDeclarationImpl *m_decl;
609     int m_property;
610     DOM::DOMString m_oldValue;
611     bool m_important;
612 };
613
614 //------------------------------------------------------------------------------------------
615 // RemoveNodeAttributeCommand
616
617 class RemoveNodeAttributeCommand : public EditCommand
618 {
619 public:
620     RemoveNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
621     virtual ~RemoveNodeAttributeCommand();
622
623     virtual void doApply();
624     virtual void doUnapply();
625
626     DOM::ElementImpl *element() const { return m_element; }
627     DOM::NodeImpl::Id attribute() const { return m_attribute; }
628     
629 private:
630     DOM::ElementImpl *m_element;
631     DOM::NodeImpl::Id m_attribute;
632     DOM::DOMString m_oldValue;
633 };
634
635 //------------------------------------------------------------------------------------------
636 // RemoveNodeCommand
637
638 class RemoveNodeCommand : public EditCommand
639 {
640 public:
641     RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
642     virtual ~RemoveNodeCommand();
643         
644     virtual void doApply();
645     virtual void doUnapply();
646
647     DOM::NodeImpl *node() const { return m_removeChild; }
648
649 private:
650     DOM::NodeImpl *m_parent;    
651     DOM::NodeImpl *m_removeChild;
652     DOM::NodeImpl *m_refChild;    
653 };
654
655 //------------------------------------------------------------------------------------------
656 // RemoveNodePreservingChildrenCommand
657
658 class RemoveNodePreservingChildrenCommand : public CompositeEditCommand
659 {
660 public:
661     RemoveNodePreservingChildrenCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
662     virtual ~RemoveNodePreservingChildrenCommand();
663         
664     virtual void doApply();
665
666     DOM::NodeImpl *node() const { return m_node; }
667
668 private:
669     DOM::NodeImpl *m_node;
670 };
671
672 //------------------------------------------------------------------------------------------
673 // ReplaceSelectionCommand
674
675 // --- NodeDesiredStyle helper class
676
677 class NodeDesiredStyle
678 {
679 public:
680     NodeDesiredStyle(DOM::NodeImpl *, DOM::CSSMutableStyleDeclarationImpl *);
681     NodeDesiredStyle(const NodeDesiredStyle &);
682     ~NodeDesiredStyle();
683     
684     DOM::NodeImpl *node() const { return m_node; }
685     DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style; }
686
687     NodeDesiredStyle &operator=(const NodeDesiredStyle &);
688
689 private:
690     DOM::NodeImpl *m_node;
691     DOM::CSSMutableStyleDeclarationImpl *m_style;
692 };
693
694 // --- ReplacementFragment helper class
695
696 class ReplacementFragment
697 {
698 public:
699     ReplacementFragment(DOM::DocumentImpl *, DOM::DocumentFragmentImpl *, bool matchStyle);
700     ~ReplacementFragment();
701
702     enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
703
704     DOM::DocumentFragmentImpl *root() const { return m_fragment; }
705     DOM::NodeImpl *firstChild() const;
706     DOM::NodeImpl *lastChild() const;
707
708     DOM::NodeImpl *mergeStartNode() const;
709
710     const QValueList<NodeDesiredStyle> &desiredStyles() { return m_styles; }
711         
712     void pruneEmptyNodes();
713
714     EFragmentType type() const { return m_type; }
715     bool isEmpty() const { return m_type == EmptyFragment; }
716     bool isSingleTextNode() const { return m_type == SingleTextNodeFragment; }
717     bool isTreeFragment() const { return m_type == TreeFragment; }
718
719     bool hasMoreThanOneBlock() const { return m_hasMoreThanOneBlock; }
720     bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAtStart; }
721     bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEnd; }
722
723 private:
724     // no copy construction or assignment
725     ReplacementFragment(const ReplacementFragment &);
726     ReplacementFragment &operator=(const ReplacementFragment &);
727     
728     static bool isInterchangeNewlineNode(const DOM::NodeImpl *);
729     static bool isInterchangeConvertedSpaceSpan(const DOM::NodeImpl *);
730
731     DOM::NodeImpl *insertFragmentForTestRendering();
732     void restoreTestRenderingNodesToFragment(DOM::NodeImpl *);
733     void computeStylesUsingTestRendering(DOM::NodeImpl *);
734     void removeUnrenderedNodesUsingTestRendering(DOM::NodeImpl *);
735     int countRenderedBlocks(DOM::NodeImpl *holder);
736     void removeStyleNodes();
737
738     // A couple simple DOM helpers
739     DOM::NodeImpl *enclosingBlock(DOM::NodeImpl *) const;
740     void removeNode(DOM::NodeImpl *);
741     void removeNodePreservingChildren(DOM::NodeImpl *);
742     void insertNodeBefore(DOM::NodeImpl *node, DOM::NodeImpl *refNode);
743
744     EFragmentType m_type;
745     DOM::DocumentImpl *m_document;
746     DOM::DocumentFragmentImpl *m_fragment;
747     QValueList<NodeDesiredStyle> m_styles;
748     bool m_matchStyle;
749     bool m_hasInterchangeNewlineAtStart;
750     bool m_hasInterchangeNewlineAtEnd;
751     bool m_hasMoreThanOneBlock;
752 };
753
754 class ReplaceSelectionCommand : public CompositeEditCommand
755 {
756 public:
757     ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false, bool matchStyle=false);
758     virtual ~ReplaceSelectionCommand();
759     
760     virtual void doApply();
761     virtual EditAction editingAction() const;
762
763 private:
764     void completeHTMLReplacement(const DOM::Position &lastPositionToSelect);
765
766     void insertNodeAfterAndUpdateNodesInserted(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
767     void insertNodeAtAndUpdateNodesInserted(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
768     void insertNodeBeforeAndUpdateNodesInserted(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
769
770     void updateNodesInserted(DOM::NodeImpl *);
771     void fixupNodeStyles(const QValueList<NodeDesiredStyle> &);
772     void removeLinePlaceholderIfNeeded(DOM::NodeImpl *);
773
774     ReplacementFragment m_fragment;
775     DOM::NodeImpl *m_firstNodeInserted;
776     DOM::NodeImpl *m_lastNodeInserted;
777     DOM::NodeImpl *m_lastTopNodeInserted;
778     DOM::CSSMutableStyleDeclarationImpl *m_insertionStyle;
779     bool m_selectReplacement;
780     bool m_smartReplace;
781     bool m_matchStyle;
782 };
783
784 void computeAndStoreNodeDesiredStyle(DOM::NodeImpl *, QValueList<NodeDesiredStyle> &);
785
786 //------------------------------------------------------------------------------------------
787 // SetNodeAttributeCommand
788
789 class SetNodeAttributeCommand : public EditCommand
790 {
791 public:
792     SetNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
793     virtual ~SetNodeAttributeCommand();
794
795     virtual void doApply();
796     virtual void doUnapply();
797
798     DOM::ElementImpl *element() const { return m_element; }
799     DOM::NodeImpl::Id attribute() const { return m_attribute; }
800     DOM::DOMString value() const { return m_value; }
801     
802 private:
803     DOM::ElementImpl *m_element;
804     DOM::NodeImpl::Id m_attribute;
805     DOM::DOMString m_value;
806     DOM::DOMString m_oldValue;
807 };
808
809 //------------------------------------------------------------------------------------------
810 // SplitTextNodeCommand
811
812 class SplitTextNodeCommand : public EditCommand
813 {
814 public:
815     SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
816     virtual ~SplitTextNodeCommand();
817         
818     virtual void doApply();
819     virtual void doUnapply();
820
821     DOM::TextImpl *node() const { return m_text2; }
822     long offset() const { return m_offset; }
823
824 private:
825     DOM::TextImpl *m_text1;
826     DOM::TextImpl *m_text2;
827     unsigned long m_offset;
828 };
829
830 //------------------------------------------------------------------------------------------
831 // WrapContentsInDummySpanCommand
832
833 class WrapContentsInDummySpanCommand : public EditCommand
834 {
835 public:
836     WrapContentsInDummySpanCommand(DOM::DocumentImpl *, DOM::ElementImpl *);
837     virtual ~WrapContentsInDummySpanCommand();
838         
839     virtual void doApply();
840     virtual void doUnapply();
841
842 private:
843     DOM::ElementImpl *m_element;
844     DOM::ElementImpl *m_dummySpan;
845 };
846
847 //------------------------------------------------------------------------------------------
848 // SplitElementCommand
849
850 class SplitElementCommand : public EditCommand
851 {
852 public:
853     SplitElementCommand(DOM::DocumentImpl *, DOM::ElementImpl *element, DOM::NodeImpl *atChild);
854     virtual ~SplitElementCommand();
855         
856     virtual void doApply();
857     virtual void doUnapply();
858
859 private:
860     DOM::ElementImpl *m_element1;
861     DOM::ElementImpl *m_element2;
862     DOM::NodeImpl *m_atChild;
863 };
864
865 //------------------------------------------------------------------------------------------
866 // MergeIdenticalElementsCommand
867
868 class MergeIdenticalElementsCommand : public EditCommand
869 {
870 public:
871     MergeIdenticalElementsCommand(DOM::DocumentImpl *, DOM::ElementImpl *first, DOM::ElementImpl *second);
872     virtual ~MergeIdenticalElementsCommand();
873         
874     virtual void doApply();
875     virtual void doUnapply();
876
877 private:
878     DOM::ElementImpl *m_element1;
879     DOM::ElementImpl *m_element2;
880     DOM::NodeImpl *m_atChild;
881 };
882
883 //------------------------------------------------------------------------------------------
884 // SplitTextNodeContainingElementCommand
885
886 class SplitTextNodeContainingElementCommand : public CompositeEditCommand
887 {
888 public:
889     SplitTextNodeContainingElementCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
890     virtual ~SplitTextNodeContainingElementCommand();
891         
892     virtual void doApply();
893
894 private:
895     DOM::TextImpl *m_text;
896     long m_offset;
897 };
898
899
900 //------------------------------------------------------------------------------------------
901 // TypingCommand
902
903 class TypingCommand : public CompositeEditCommand
904 {
905 public:
906     enum ETypingCommand { 
907         DeleteKey, 
908         ForwardDeleteKey, 
909         InsertText, 
910         InsertLineBreak, 
911         InsertParagraphSeparator,
912         InsertParagraphSeparatorInQuotedContent,
913     };
914
915     TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
916
917     static void deleteKeyPressed(DOM::DocumentImpl *, bool smartDelete = false);
918     static void forwardDeleteKeyPressed(DOM::DocumentImpl *, bool smartDelete = false);
919     static void insertText(DOM::DocumentImpl *, const DOM::DOMString &, bool selectInsertedText = false);
920     static void insertLineBreak(DOM::DocumentImpl *);
921     static void insertParagraphSeparator(DOM::DocumentImpl *);
922     static void insertParagraphSeparatorInQuotedContent(DOM::DocumentImpl *);
923     static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
924     static void closeTyping(const EditCommandPtr &);
925     
926     virtual void doApply();
927     virtual EditAction editingAction() const;
928
929     bool openForMoreTyping() const { return m_openForMoreTyping; }
930     void closeTyping() { m_openForMoreTyping = false; }
931
932     void insertText(const DOM::DOMString &text, bool selectInsertedText);
933     void insertTextRunWithoutNewlines(const DOM::DOMString &text, bool selectInsertedText);
934     void insertLineBreak();
935     void insertParagraphSeparatorInQuotedContent();
936     void insertParagraphSeparator();
937     void deleteKeyPressed();
938     void forwardDeleteKeyPressed();
939
940     bool smartDelete() { return m_smartDelete; }
941     void setSmartDelete(bool smartDelete) { m_smartDelete = smartDelete; }
942
943 private:
944     virtual bool isTypingCommand() const;
945     virtual bool preservesTypingStyle() const;
946
947     void markMisspellingsAfterTyping();
948     void typingAddedToOpenCommand();
949     
950     ETypingCommand m_commandType;
951     DOM::DOMString m_textToInsert;
952     bool m_openForMoreTyping;
953     bool m_applyEditing;
954     bool m_selectInsertedText;
955     bool m_smartDelete;
956 };
957
958 //------------------------------------------------------------------------------------------
959
960 DOM::ElementImpl *floatRefdElement(DOM::ElementImpl *element);
961 DOM::ElementImpl *createDefaultParagraphElement(DOM::DocumentImpl *document);
962 DOM::ElementImpl *createBlockPlaceholderElement(DOM::DocumentImpl *document);
963 DOM::ElementImpl *createBreakElement(DOM::DocumentImpl *document);
964 DOM::ElementImpl *createFontElement(DOM::DocumentImpl *document);
965 DOM::ElementImpl *createStyleSpanElement(DOM::DocumentImpl *document);
966
967 bool isNodeRendered(const DOM::NodeImpl *);
968 bool isProbablyBlock(const DOM::NodeImpl *);
969 bool isProbablyTableStructureNode(const DOM::NodeImpl *);
970 bool isMailBlockquote(const DOM::NodeImpl *);
971 DOM::NodeImpl *nearestMailBlockquote(const DOM::NodeImpl *);
972 bool isMailPasteAsQuotationNode(const DOM::NodeImpl *node);
973
974 //------------------------------------------------------------------------------------------
975
976 } // end namespace khtml
977
978 #endif