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