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