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