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 "qptrlist.h"
31 #include "qvaluelist.h"
32 #include "selection.h"
33 #include "shared.h"
34
35 namespace DOM {
36     class CSSProperty;
37     class DocumentFragmentImpl;
38     class HTMLElementImpl;
39     class TextImpl;
40 }
41
42 namespace khtml {
43
44 class EditCommand;
45 class Selection;
46 class VisiblePosition;
47
48 //------------------------------------------------------------------------------------------
49 // EditCommandPtr
50
51 class EditCommandPtr : public SharedPtr<EditCommand>
52 {
53 public:
54     EditCommandPtr();
55     EditCommandPtr(EditCommand *);
56     EditCommandPtr(const EditCommandPtr &);
57     ~EditCommandPtr();
58
59     EditCommandPtr &operator=(const EditCommandPtr &);
60
61     bool isCompositeStep() const;
62
63     void apply() const;
64     void unapply() const;
65     void reapply() const;
66
67     DOM::DocumentImpl * const document() const;
68
69     khtml::Selection startingSelection() const;
70     khtml::Selection endingSelection() const;
71
72     void setStartingSelection(const khtml::Selection &s) const;
73     void setEndingSelection(const khtml::Selection &s) const;
74
75     DOM::CSSStyleDeclarationImpl *typingStyle() const;
76     void setTypingStyle(DOM::CSSStyleDeclarationImpl *) const;
77
78     EditCommandPtr parent() const;
79     void setParent(const EditCommandPtr &) const;
80
81     bool isInputTextCommand() const;
82     bool isInputNewlineCommand() const;
83     bool isTypingCommand() const;
84
85     static EditCommandPtr &emptyCommand();
86 };
87
88 //------------------------------------------------------------------------------------------
89 // StyleChange
90
91 class StyleChange {
92 public:
93     StyleChange() : m_applyBold(false), m_applyItalic(false) { }
94     explicit StyleChange(DOM::CSSStyleDeclarationImpl *);
95     StyleChange(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
96
97     DOM::DOMString cssStyle() const { return m_cssStyle; }
98     bool applyBold() const { return m_applyBold; }
99     bool applyItalic() const { return m_applyItalic; }
100
101 private:
102     void init(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
103     static bool currentlyHasStyle(const DOM::Position &, const DOM::CSSProperty *);
104     
105     DOM::DOMString m_cssStyle;
106     bool m_applyBold;
107     bool m_applyItalic;
108 };
109
110 //------------------------------------------------------------------------------------------
111 // EditCommand
112
113 class EditCommand : public Shared<EditCommand>
114 {
115 public:
116     EditCommand(DOM::DocumentImpl *);
117     virtual ~EditCommand();
118
119     bool isCompositeStep() const { return m_parent.notNull(); }
120     EditCommand *parent() const { return m_parent.get(); }
121     void setParent(EditCommand *parent) { m_parent = parent; }
122
123     enum ECommandState { NotApplied, Applied };
124     
125     void apply();       
126     void unapply();
127     void reapply();
128
129     virtual void doApply() = 0;
130     virtual void doUnapply() = 0;
131     virtual void doReapply();  // calls doApply()
132
133     virtual DOM::DocumentImpl * const document() const { return m_document; }
134
135     khtml::Selection startingSelection() const { return m_startingSelection; }
136     khtml::Selection endingSelection() const { return m_endingSelection; }
137         
138     ECommandState state() const { return m_state; }
139     void setState(ECommandState state) { m_state = state; }
140
141     void setStartingSelection(const khtml::Selection &s);
142     void setEndingSelection(const khtml::Selection &s);
143
144     DOM::CSSStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
145     void setTypingStyle(DOM::CSSStyleDeclarationImpl *);
146     
147     virtual bool isInputTextCommand() const;
148     virtual bool isTypingCommand() const;
149
150 private:
151     void assignTypingStyle(DOM::CSSStyleDeclarationImpl *);
152
153     virtual bool preservesTypingStyle() const;
154
155     DOM::DocumentImpl *m_document;
156     ECommandState m_state;
157     khtml::Selection m_startingSelection;
158     khtml::Selection m_endingSelection;
159     DOM::CSSStyleDeclarationImpl *m_typingStyle;
160     EditCommandPtr m_parent;
161 };
162
163 //------------------------------------------------------------------------------------------
164 // CompositeEditCommand
165
166 class CompositeEditCommand : public EditCommand
167 {
168 public:
169     CompositeEditCommand(DOM::DocumentImpl *);
170         
171     virtual void doUnapply();
172     virtual void doReapply();
173
174 protected:
175     //
176     // sugary-sweet convenience functions to help create and apply edit commands in composite commands
177     //
178     void appendNode(DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
179     void applyCommandToComposite(EditCommandPtr &);
180     void deleteKeyPressed();
181     void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
182     void deleteSelection(const khtml::Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
183     void deleteText(DOM::TextImpl *node, long offset, long count);
184     void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
185     void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
186     void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
187     void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
188     void insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
189     void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
190     void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
191     void removeFullySelectedNode(DOM::NodeImpl *);
192     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
193     void removeNode(DOM::NodeImpl *removeChild);
194     void removeNodePreservingChildren(DOM::NodeImpl *node);
195     void replaceText(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
196     void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
197     void splitTextNode(DOM::TextImpl *text, long offset);
198
199     DOM::NodeImpl *applyTypingStyle(DOM::NodeImpl *) const;
200
201     void deleteInsignificantText(DOM::TextImpl *, int start, int end);
202     void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
203     void deleteInsignificantTextDownstream(const DOM::Position &);
204
205     void insertBlockPlaceholderIfNeeded(DOM::NodeImpl *);
206     bool removeBlockPlaceholderIfNeeded(DOM::NodeImpl *);
207
208     QValueList<EditCommandPtr> m_cmds;
209 };
210
211 //==========================================================================================
212 // Concrete commands
213 //------------------------------------------------------------------------------------------
214 // AppendNodeCommand
215
216 class AppendNodeCommand : public EditCommand
217 {
218 public:
219     AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
220     virtual ~AppendNodeCommand();
221
222     virtual void doApply();
223     virtual void doUnapply();
224
225     DOM::NodeImpl *appendChild() const { return m_appendChild; }
226     DOM::NodeImpl *parentNode() const { return m_parentNode; }
227
228 private:
229     DOM::NodeImpl *m_appendChild;
230     DOM::NodeImpl *m_parentNode;    
231 };
232
233 //------------------------------------------------------------------------------------------
234 // ApplyStyleCommand
235
236 class ApplyStyleCommand : public CompositeEditCommand
237 {
238 public:
239     ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style);
240     virtual ~ApplyStyleCommand();
241         
242     virtual void doApply();
243
244     DOM::CSSStyleDeclarationImpl *style() const { return m_style; }
245
246 private:
247     // style-removal helpers
248     bool isHTMLStyleNode(DOM::HTMLElementImpl *);
249     void removeHTMLStyleNode(DOM::HTMLElementImpl *);
250     void removeCSSStyle(DOM::HTMLElementImpl *);
251     void removeStyle(const DOM::Position &start, const DOM::Position &end);
252     bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
253
254     // style-application helpers
255     bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
256     DOM::NodeImpl *splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
257     void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
258     DOM::Position positionInsertionPoint(DOM::Position);
259     void applyStyleIfNeeded(DOM::NodeImpl *start, DOM::NodeImpl *end);
260     
261     DOM::CSSStyleDeclarationImpl *m_style;
262 };
263
264 //------------------------------------------------------------------------------------------
265 // DeleteSelectionCommand
266
267 class DeleteSelectionCommand : public CompositeEditCommand
268
269 public:
270     DeleteSelectionCommand(DOM::DocumentImpl *document, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
271     DeleteSelectionCommand(DOM::DocumentImpl *document, const khtml::Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
272         
273     virtual void doApply();
274     
275 private:
276     virtual bool preservesTypingStyle() const;
277
278     void moveNodesAfterNode(DOM::NodeImpl *startNode, DOM::NodeImpl *dstNode);
279     DOM::Position startPositionForDelete() const;
280     DOM::Position endPositionForDelete() const;
281
282     khtml::Selection m_selectionToDelete;
283     bool m_hasSelectionToDelete;
284     bool m_smartDelete;
285     bool m_mergeBlocksAfterDelete;
286 };
287
288 //------------------------------------------------------------------------------------------
289 // DeleteTextCommand
290
291 class DeleteTextCommand : public EditCommand
292 {
293 public:
294     DeleteTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
295     virtual ~DeleteTextCommand();
296         
297     virtual void doApply();
298     virtual void doUnapply();
299
300     DOM::TextImpl *node() const { return m_node; }
301     long offset() const { return m_offset; }
302     long count() const { return m_count; }
303
304 private:
305     DOM::TextImpl *m_node;
306     long m_offset;
307     long m_count;
308     DOM::DOMString m_text;
309 };
310
311 //------------------------------------------------------------------------------------------
312 // InputNewlineCommand
313
314 class InputNewlineCommand : public CompositeEditCommand
315 {
316 public:
317     InputNewlineCommand(DOM::DocumentImpl *document);
318
319     virtual void doApply();
320
321 private:
322     void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
323     void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
324 };
325
326 //------------------------------------------------------------------------------------------
327 // InputNewlineInQuotedContentCommand
328
329 class InputNewlineInQuotedContentCommand : public CompositeEditCommand
330 {
331 public:
332     InputNewlineInQuotedContentCommand(DOM::DocumentImpl *);
333     virtual ~InputNewlineInQuotedContentCommand();
334         
335     virtual void doApply();
336     
337 private:
338     bool isMailBlockquote(const DOM::NodeImpl *) const;
339     bool isLastVisiblePositionInBlockquote(const VisiblePosition &pos, const DOM::NodeImpl *) const;
340
341     QPtrList<DOM::NodeImpl> ancestors;
342     QPtrList<DOM::NodeImpl> clonedNodes;
343     DOM::ElementImpl *m_breakNode;
344 };
345
346 //------------------------------------------------------------------------------------------
347 // InputTextCommand
348
349 class InputTextCommand : public CompositeEditCommand
350 {
351 public:
352     InputTextCommand(DOM::DocumentImpl *document);
353
354     virtual void doApply();
355
356     void deleteCharacter();
357     void input(const DOM::DOMString &text, bool selectInsertedText = false);
358     
359     unsigned long charactersAdded() const { return m_charactersAdded; }
360     
361 private:
362     virtual bool isInputTextCommand() const;
363
364     DOM::Position prepareForTextInsertion(bool adjustDownstream);
365     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
366
367     unsigned long m_charactersAdded;
368 };
369
370 //------------------------------------------------------------------------------------------
371 // InsertNodeBeforeCommand
372
373 class InsertNodeBeforeCommand : public EditCommand
374 {
375 public:
376     InsertNodeBeforeCommand(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
377     virtual ~InsertNodeBeforeCommand();
378
379     virtual void doApply();
380     virtual void doUnapply();
381
382     DOM::NodeImpl *insertChild() const { return m_insertChild; }
383     DOM::NodeImpl *refChild() const { return m_refChild; }
384
385 private:
386     DOM::NodeImpl *m_insertChild;
387     DOM::NodeImpl *m_refChild; 
388 };
389
390 //------------------------------------------------------------------------------------------
391 // InsertTextCommand
392
393 class InsertTextCommand : public EditCommand
394 {
395 public:
396     InsertTextCommand(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
397     virtual ~InsertTextCommand();
398         
399     virtual void doApply();
400     virtual void doUnapply();
401
402     DOM::TextImpl *node() const { return m_node; }
403     long offset() const { return m_offset; }
404     DOM::DOMString text() const { return m_text; }
405
406 private:
407     DOM::TextImpl *m_node;
408     long m_offset;
409     DOM::DOMString m_text;
410 };
411
412 //------------------------------------------------------------------------------------------
413 // JoinTextNodesCommand
414
415 class JoinTextNodesCommand : public EditCommand
416 {
417 public:
418     JoinTextNodesCommand(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
419     virtual ~JoinTextNodesCommand();
420         
421     virtual void doApply();
422     virtual void doUnapply();
423
424     DOM::TextImpl *firstNode() const { return m_text1; }
425     DOM::TextImpl *secondNode() const { return m_text2; }
426
427 private:
428     DOM::TextImpl *m_text1;
429     DOM::TextImpl *m_text2;
430     unsigned long m_offset;
431 };
432
433 //------------------------------------------------------------------------------------------
434 // ReplaceSelectionCommand
435
436 class ReplaceSelectionCommand : public CompositeEditCommand
437 {
438 public:
439     ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false);
440     virtual ~ReplaceSelectionCommand();
441     
442     virtual void doApply();
443
444 private:
445     DOM::DocumentFragmentImpl *m_fragment;
446     bool m_selectReplacement;
447     bool m_smartReplace;
448 };
449
450 //------------------------------------------------------------------------------------------
451 // MoveSelectionCommand
452
453 class MoveSelectionCommand : public CompositeEditCommand
454 {
455 public:
456     MoveSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position, bool smartMove=false);
457     virtual ~MoveSelectionCommand();
458     
459     virtual void doApply();
460     
461 private:
462     DOM::DocumentFragmentImpl *m_fragment;
463     DOM::Position m_position;
464     bool m_smartMove;
465 };
466
467 //------------------------------------------------------------------------------------------
468 // RemoveCSSPropertyCommand
469
470 class RemoveCSSPropertyCommand : public EditCommand
471 {
472 public:
473     RemoveCSSPropertyCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
474     virtual ~RemoveCSSPropertyCommand();
475
476     virtual void doApply();
477     virtual void doUnapply();
478
479     DOM::CSSStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
480     int property() const { return m_property; }
481     
482 private:
483     DOM::CSSStyleDeclarationImpl *m_decl;
484     int m_property;
485     DOM::DOMString m_oldValue;
486     bool m_important;
487 };
488
489 //------------------------------------------------------------------------------------------
490 // RemoveNodeAttributeCommand
491
492 class RemoveNodeAttributeCommand : public EditCommand
493 {
494 public:
495     RemoveNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
496     virtual ~RemoveNodeAttributeCommand();
497
498     virtual void doApply();
499     virtual void doUnapply();
500
501     DOM::ElementImpl *element() const { return m_element; }
502     DOM::NodeImpl::Id attribute() const { return m_attribute; }
503     
504 private:
505     DOM::ElementImpl *m_element;
506     DOM::NodeImpl::Id m_attribute;
507     DOM::DOMString m_oldValue;
508 };
509
510 //------------------------------------------------------------------------------------------
511 // RemoveNodeCommand
512
513 class RemoveNodeCommand : public EditCommand
514 {
515 public:
516     RemoveNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
517     virtual ~RemoveNodeCommand();
518         
519     virtual void doApply();
520     virtual void doUnapply();
521
522     DOM::NodeImpl *node() const { return m_removeChild; }
523
524 private:
525     DOM::NodeImpl *m_parent;    
526     DOM::NodeImpl *m_removeChild;
527     DOM::NodeImpl *m_refChild;    
528 };
529
530 //------------------------------------------------------------------------------------------
531 // RemoveNodePreservingChildrenCommand
532
533 class RemoveNodePreservingChildrenCommand : public CompositeEditCommand
534 {
535 public:
536     RemoveNodePreservingChildrenCommand(DOM::DocumentImpl *, DOM::NodeImpl *);
537     virtual ~RemoveNodePreservingChildrenCommand();
538         
539     virtual void doApply();
540
541     DOM::NodeImpl *node() const { return m_node; }
542
543 private:
544     DOM::NodeImpl *m_node;
545 };
546
547 //------------------------------------------------------------------------------------------
548 // SetNodeAttributeCommand
549
550 class SetNodeAttributeCommand : public EditCommand
551 {
552 public:
553     SetNodeAttributeCommand(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
554     virtual ~SetNodeAttributeCommand();
555
556     virtual void doApply();
557     virtual void doUnapply();
558
559     DOM::ElementImpl *element() const { return m_element; }
560     DOM::NodeImpl::Id attribute() const { return m_attribute; }
561     DOM::DOMString value() const { return m_value; }
562     
563 private:
564     DOM::ElementImpl *m_element;
565     DOM::NodeImpl::Id m_attribute;
566     DOM::DOMString m_value;
567     DOM::DOMString m_oldValue;
568 };
569
570 //------------------------------------------------------------------------------------------
571 // SplitTextNodeCommand
572
573 class SplitTextNodeCommand : public EditCommand
574 {
575 public:
576     SplitTextNodeCommand(DOM::DocumentImpl *, DOM::TextImpl *, long);
577     virtual ~SplitTextNodeCommand();
578         
579     virtual void doApply();
580     virtual void doUnapply();
581
582     DOM::TextImpl *node() const { return m_text2; }
583     long offset() const { return m_offset; }
584
585 private:
586     DOM::TextImpl *m_text1;
587     DOM::TextImpl *m_text2;
588     unsigned long m_offset;
589 };
590
591 //------------------------------------------------------------------------------------------
592 // TypingCommand
593
594 class TypingCommand : public CompositeEditCommand
595 {
596 public:
597     enum ETypingCommand { DeleteKey, InsertText, InsertNewline, InsertNewlineInQuotedContent };
598
599     TypingCommand(DOM::DocumentImpl *document, ETypingCommand, const DOM::DOMString &text = "", bool selectInsertedText = false);
600
601     static void deleteKeyPressed(DOM::DocumentImpl *document);
602     static void insertText(DOM::DocumentImpl *document, const DOM::DOMString &text, bool selectInsertedText = false);
603     static void insertNewline(DOM::DocumentImpl *document);
604     static void insertNewlineInQuotedContent(DOM::DocumentImpl *document);
605     static bool isOpenForMoreTypingCommand(const EditCommandPtr &);
606     static void closeTyping(const EditCommandPtr &);
607     
608     virtual void doApply();
609
610     bool openForMoreTyping() const { return m_openForMoreTyping; }
611     void closeTyping() { m_openForMoreTyping = false; }
612
613     void insertText(const DOM::DOMString &text, bool selectInsertedText);
614     void insertNewline();
615     void insertNewlineInQuotedContent();
616     void deleteKeyPressed();
617
618 private:
619     virtual bool isTypingCommand() const;
620     virtual bool preservesTypingStyle() const;
621
622     void issueCommandForDeleteKey();
623     void removeCommand(const EditCommandPtr &);
624     void markMisspellingsAfterTyping();
625     void typingAddedToOpenCommand();
626     
627     ETypingCommand m_commandType;
628     DOM::DOMString m_textToInsert;
629     bool m_openForMoreTyping;
630     bool m_applyEditing;
631     bool m_selectInsertedText;
632 };
633
634 //------------------------------------------------------------------------------------------
635
636 } // end namespace khtml
637
638 #endif