fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / khtml / editing / htmlediting_impl.h
blob7de4fc829191821901370fc657492ed128bf55e2
1 /*
2 * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
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.
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.
26 #ifndef __htmleditingimpl_h__
27 #define __htmleditingimpl_h__
29 #include "misc/shared.h"
30 #include "htmlediting.h"
32 #include "xml/dom_position.h"
33 #include "xml/dom_selection.h"
34 #include "dom/dom_string.h"
36 #include <QList>
38 namespace DOM {
39 class CSSProperty;
40 class CSSStyleDeclarationImpl;
41 class DocumentImpl;
42 class DOMString;
43 class ElementImpl;
44 class HTMLElementImpl;
45 class NodeImpl;
46 class NodeListImpl;
47 class Position;
48 class Range;
49 class Selection;
50 class TextImpl;
51 class TreeWalkerImpl;
54 namespace khtml {
56 //------------------------------------------------------------------------------------------
57 // EditCommandImpl
59 class EditCommandImpl : public SharedCommandImpl
61 public:
62 EditCommandImpl(DOM::DocumentImpl *);
63 virtual ~EditCommandImpl();
65 virtual int commandID() const;
66 bool isCompositeStep() const { return parent(); }
67 EditCommandImpl* parent() const;
68 void setParent(EditCommandImpl *);
70 enum ECommandState { NotApplied, Applied };
72 void apply();
73 void unapply();
74 void reapply();
76 virtual void doApply() = 0;
77 virtual void doUnapply() = 0;
78 virtual void doReapply(); // calls doApply()
80 virtual DOM::DocumentImpl* document() const { return m_document.get(); }
82 DOM::Selection startingSelection() const { return m_startingSelection; }
83 DOM::Selection endingSelection() const { return m_endingSelection; }
85 ECommandState state() const { return m_state; }
86 void setState(ECommandState state) { m_state = state; }
88 void setStartingSelection(const DOM::Selection &s);
89 void setEndingSelection(const DOM::Selection &s);
91 private:
92 DocPtr<DOM::DocumentImpl> m_document;
93 ECommandState m_state;
94 DOM::Selection m_startingSelection;
95 DOM::Selection m_endingSelection;
96 EditCommandImpl* m_parent;
99 //------------------------------------------------------------------------------------------
100 // CompositeEditCommandImpl
102 class CompositeEditCommandImpl : public EditCommandImpl
104 public:
105 CompositeEditCommandImpl(DOM::DocumentImpl *);
106 virtual ~CompositeEditCommandImpl();
108 virtual int commandID() const;
110 virtual void doApply() = 0;
111 virtual void doUnapply();
112 virtual void doReapply();
114 protected:
116 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
118 void appendNode(DOM::NodeImpl *parent, DOM::NodeImpl *appendChild);
119 void applyCommandToComposite(EditCommand &);
120 void deleteCollapsibleWhitespace();
121 void deleteCollapsibleWhitespace(const DOM::Selection &selection);
122 void deleteKeyPressed();
123 void deleteSelection();
124 void deleteSelection(const DOM::Selection &selection);
125 void deleteText(DOM::TextImpl *node, long offset, long count);
126 void inputText(const DOM::DOMString &text);
127 void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
128 void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
129 void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
130 void insertText(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
131 void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
132 void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
133 void removeNodeAttribute(DOM::ElementImpl *, int attribute);
134 void removeNode(DOM::NodeImpl *removeChild);
135 void removeNodeAndPrune(DOM::NodeImpl *pruneNode, DOM::NodeImpl *stopNode=0);
136 void removeNodePreservingChildren(DOM::NodeImpl *node);
137 void replaceText(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
138 void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
139 void splitTextNode(DOM::TextImpl *text, long offset);
141 DOM::ElementImpl *createTypingStyleElement() const;
143 QList<EditCommand> m_cmds;
146 //==========================================================================================
147 // Concrete commands
148 //------------------------------------------------------------------------------------------
149 // AppendNodeCommandImpl
151 class AppendNodeCommandImpl : public EditCommandImpl
153 public:
154 AppendNodeCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *parentNode, DOM::NodeImpl *appendChild);
155 virtual ~AppendNodeCommandImpl();
157 virtual int commandID() const;
159 virtual void doApply();
160 virtual void doUnapply();
162 DOM::NodeImpl *parentNode() const { return m_parentNode; }
163 DOM::NodeImpl *appendChild() const { return m_appendChild; }
165 private:
166 DOM::NodeImpl *m_parentNode;
167 DOM::NodeImpl *m_appendChild;
170 //------------------------------------------------------------------------------------------
171 // ApplyStyleCommandImpl
173 class ApplyStyleCommandImpl : public CompositeEditCommandImpl
175 public:
176 ApplyStyleCommandImpl(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style);
177 virtual ~ApplyStyleCommandImpl();
179 virtual int commandID() const;
181 virtual void doApply();
183 DOM::CSSStyleDeclarationImpl *style() const { return m_style; }
185 struct StyleChange {
186 StyleChange() : applyBold(false), applyItalic(false) {}
187 DOM::DOMString cssStyle;
188 bool applyBold:1;
189 bool applyItalic:1;
192 private:
193 // style-removal helpers
194 bool isHTMLStyleNode(DOM::HTMLElementImpl *);
195 void removeHTMLStyleNode(DOM::HTMLElementImpl *);
196 void removeCSSStyle(DOM::HTMLElementImpl *);
197 void removeStyle(const DOM::Position &start, const DOM::Position &end);
198 bool nodeFullySelected(const DOM::NodeImpl *node) const;
200 // style-application helpers
201 bool currentlyHasStyle(const DOM::Position &, const DOM::CSSProperty *) const;
202 StyleChange computeStyleChange(const DOM::Position &, DOM::CSSStyleDeclarationImpl *);
203 bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
204 DOM::NodeImpl *splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
205 void surroundNodeRangeWithElement(DOM::NodeImpl *start, DOM::NodeImpl *end, DOM::ElementImpl *element);
206 DOM::Position positionInsertionPoint(DOM::Position);
207 void applyStyleIfNeeded(DOM::NodeImpl *start, DOM::NodeImpl *end);
209 DOM::CSSStyleDeclarationImpl *m_style;
212 //------------------------------------------------------------------------------------------
213 // DeleteCollapsibleWhitespaceCommandImpl
215 class DeleteCollapsibleWhitespaceCommandImpl : public CompositeEditCommandImpl
217 public:
218 DeleteCollapsibleWhitespaceCommandImpl(DOM::DocumentImpl *document);
219 DeleteCollapsibleWhitespaceCommandImpl(DOM::DocumentImpl *document, const DOM::Selection &selection);
221 virtual ~DeleteCollapsibleWhitespaceCommandImpl();
223 virtual int commandID() const;
225 virtual void doApply();
227 private:
228 DOM::Position deleteWhitespace(const DOM::Position &pos);
230 unsigned long m_charactersDeleted;
231 DOM::Selection m_selectionToCollapse;
232 bool m_hasSelectionToCollapse;
235 //------------------------------------------------------------------------------------------
236 // DeleteSelectionCommandImpl
238 class DeleteSelectionCommandImpl : public CompositeEditCommandImpl
240 public:
241 DeleteSelectionCommandImpl(DOM::DocumentImpl *document);
242 DeleteSelectionCommandImpl(DOM::DocumentImpl *document, const DOM::Selection &selection);
244 virtual ~DeleteSelectionCommandImpl();
246 virtual int commandID() const;
248 virtual void doApply();
250 private:
251 void deleteDownstreamWS(const DOM::Position &start);
252 bool containsOnlyWhitespace(const DOM::Position &start, const DOM::Position &end);
253 void joinTextNodesWithSameStyle();
255 DOM::Selection m_selectionToDelete;
256 bool m_hasSelectionToDelete;
259 //------------------------------------------------------------------------------------------
260 // DeleteTextCommandImpl
262 class DeleteTextCommandImpl : public EditCommandImpl
264 public:
265 DeleteTextCommandImpl(DOM::DocumentImpl *document, DOM::TextImpl *node, long offset, long count);
266 virtual ~DeleteTextCommandImpl();
268 virtual int commandID() const;
270 virtual void doApply();
271 virtual void doUnapply();
273 DOM::TextImpl *node() const { return m_node; }
274 long offset() const { return m_offset; }
275 long count() const { return m_count; }
277 private:
278 DOM::TextImpl *m_node;
279 long m_offset;
280 long m_count;
281 DOM::DOMString m_text;
284 //------------------------------------------------------------------------------------------
285 // InputNewlineCommandImpl
287 class InputNewlineCommandImpl : public CompositeEditCommandImpl
289 public:
290 InputNewlineCommandImpl(DOM::DocumentImpl *document);
291 virtual ~InputNewlineCommandImpl();
293 virtual int commandID() const;
295 virtual void doApply();
297 private:
298 void insertNodeAfterPosition(DOM::NodeImpl *node, const DOM::Position &pos);
299 void insertNodeBeforePosition(DOM::NodeImpl *node, const DOM::Position &pos);
302 //------------------------------------------------------------------------------------------
303 // InputTextCommandImpl
305 class InputTextCommandImpl : public CompositeEditCommandImpl
307 public:
308 InputTextCommandImpl(DOM::DocumentImpl *document);
309 virtual ~InputTextCommandImpl();
311 virtual int commandID() const;
313 virtual void doApply();
315 void deleteCharacter();
316 void input(const DOM::DOMString &text);
318 unsigned long charactersAdded() const { return m_charactersAdded; }
320 private:
321 DOM::Position prepareForTextInsertion(bool adjustDownstream);
322 void execute(const DOM::DOMString &text);
323 void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
325 unsigned long m_charactersAdded;
328 //------------------------------------------------------------------------------------------
329 // InsertNodeBeforeCommandImpl
331 class InsertNodeBeforeCommandImpl : public EditCommandImpl
333 public:
334 InsertNodeBeforeCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
335 virtual ~InsertNodeBeforeCommandImpl();
337 virtual int commandID() const;
339 virtual void doApply();
340 virtual void doUnapply();
342 DOM::NodeImpl *insertChild() const { return m_insertChild; }
343 DOM::NodeImpl *refChild() const { return m_refChild; }
345 private:
346 DOM::NodeImpl *m_insertChild;
347 DOM::NodeImpl *m_refChild;
350 //------------------------------------------------------------------------------------------
351 // InsertTextCommandImpl
353 class InsertTextCommandImpl : public EditCommandImpl
355 public:
356 InsertTextCommandImpl(DOM::DocumentImpl *document, DOM::TextImpl *, long, const DOM::DOMString &);
357 virtual ~InsertTextCommandImpl();
359 virtual int commandID() const;
361 virtual void doApply();
362 virtual void doUnapply();
364 DOM::TextImpl *node() const { return m_node; }
365 long offset() const { return m_offset; }
366 DOM::DOMString text() const { return m_text; }
368 private:
369 DOM::TextImpl *m_node;
370 long m_offset;
371 DOM::DOMString m_text;
374 //------------------------------------------------------------------------------------------
375 // JoinTextNodesCommandImpl
377 class JoinTextNodesCommandImpl : public EditCommandImpl
379 public:
380 JoinTextNodesCommandImpl(DOM::DocumentImpl *, DOM::TextImpl *, DOM::TextImpl *);
381 virtual ~JoinTextNodesCommandImpl();
383 virtual int commandID() const;
385 virtual void doApply();
386 virtual void doUnapply();
388 DOM::TextImpl *firstNode() const { return m_text1; }
389 DOM::TextImpl *secondNode() const { return m_text2; }
391 private:
392 DOM::TextImpl *m_text1;
393 DOM::TextImpl *m_text2;
394 unsigned long m_offset;
397 //------------------------------------------------------------------------------------------
398 // ReplaceSelectionCommandImpl
400 class ReplaceSelectionCommandImpl : public CompositeEditCommandImpl
402 public:
403 ReplaceSelectionCommandImpl(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true);
404 virtual ~ReplaceSelectionCommandImpl();
406 virtual int commandID() const;
408 virtual void doApply();
410 private:
411 DOM::DocumentFragmentImpl *m_fragment;
412 bool m_selectReplacement;
415 //------------------------------------------------------------------------------------------
416 // MoveSelectionCommandImpl
418 class MoveSelectionCommandImpl : public CompositeEditCommandImpl
420 public:
421 MoveSelectionCommandImpl(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, DOM::Position &position);
422 virtual ~MoveSelectionCommandImpl();
424 virtual int commandID() const;
426 virtual void doApply();
428 private:
429 DOM::DocumentFragmentImpl *m_fragment;
430 DOM::Position m_position;
433 //------------------------------------------------------------------------------------------
434 // RemoveCSSPropertyCommand
436 class RemoveCSSPropertyCommandImpl : public EditCommandImpl
438 public:
439 RemoveCSSPropertyCommandImpl(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *, int property);
440 virtual ~RemoveCSSPropertyCommandImpl();
442 virtual int commandID() const;
444 virtual void doApply();
445 virtual void doUnapply();
447 DOM::CSSStyleDeclarationImpl *styleDeclaration() const { return m_decl; }
448 int property() const { return m_property; }
450 private:
451 DOM::CSSStyleDeclarationImpl *m_decl;
452 int m_property;
453 DOM::DOMString m_oldValue;
454 bool m_important;
457 //------------------------------------------------------------------------------------------
458 // RemoveNodeAttributeCommandImpl
460 class RemoveNodeAttributeCommandImpl : public EditCommandImpl
462 public:
463 RemoveNodeAttributeCommandImpl(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute);
464 virtual ~RemoveNodeAttributeCommandImpl();
466 virtual int commandID() const;
468 virtual void doApply();
469 virtual void doUnapply();
471 DOM::ElementImpl *element() const { return m_element; }
472 DOM::NodeImpl::Id attribute() const { return m_attribute; }
474 private:
475 DOM::ElementImpl *m_element;
476 DOM::NodeImpl::Id m_attribute;
477 DOM::DOMString m_oldValue;
480 //------------------------------------------------------------------------------------------
481 // RemoveNodeCommandImpl
483 class RemoveNodeCommandImpl : public EditCommandImpl
485 public:
486 RemoveNodeCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *);
487 virtual ~RemoveNodeCommandImpl();
489 virtual int commandID() const;
491 virtual void doApply();
492 virtual void doUnapply();
494 DOM::NodeImpl *node() const { return m_removeChild; }
496 private:
497 DOM::NodeImpl *m_parent;
498 DOM::NodeImpl *m_removeChild;
499 DOM::NodeImpl *m_refChild;
502 //------------------------------------------------------------------------------------------
503 // RemoveNodeAndPruneCommandImpl
505 class RemoveNodeAndPruneCommandImpl : public CompositeEditCommandImpl
507 public:
508 RemoveNodeAndPruneCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *pruneNode, DOM::NodeImpl *stopNode=0);
509 virtual ~RemoveNodeAndPruneCommandImpl();
511 virtual int commandID() const;
513 virtual void doApply();
515 DOM::NodeImpl *pruneNode() const { return m_pruneNode; }
516 DOM::NodeImpl *stopNode() const { return m_stopNode; }
518 private:
519 DOM::NodeImpl *m_pruneNode;
520 DOM::NodeImpl *m_stopNode;
523 //------------------------------------------------------------------------------------------
524 // RemoveNodePreservingChildrenCommandImpl
526 class RemoveNodePreservingChildrenCommandImpl : public CompositeEditCommandImpl
528 public:
529 RemoveNodePreservingChildrenCommandImpl(DOM::DocumentImpl *, DOM::NodeImpl *);
530 virtual ~RemoveNodePreservingChildrenCommandImpl();
532 virtual int commandID() const;
534 virtual void doApply();
536 DOM::NodeImpl *node() const { return m_node; }
538 private:
539 DOM::NodeImpl *m_node;
542 //------------------------------------------------------------------------------------------
543 // SetNodeAttributeCommandImpl
545 class SetNodeAttributeCommandImpl : public EditCommandImpl
547 public:
548 SetNodeAttributeCommandImpl(DOM::DocumentImpl *, DOM::ElementImpl *, DOM::NodeImpl::Id attribute, const DOM::DOMString &value);
549 virtual ~SetNodeAttributeCommandImpl();
551 virtual int commandID() const;
553 virtual void doApply();
554 virtual void doUnapply();
556 DOM::ElementImpl *element() const { return m_element; }
557 DOM::NodeImpl::Id attribute() const { return m_attribute; }
558 DOM::DOMString value() const { return m_value; }
560 private:
561 DOM::ElementImpl *m_element;
562 DOM::NodeImpl::Id m_attribute;
563 DOM::DOMString m_value;
564 DOM::DOMString m_oldValue;
567 //------------------------------------------------------------------------------------------
568 // SplitTextNodeCommandImpl
570 class SplitTextNodeCommandImpl : public EditCommandImpl
572 public:
573 SplitTextNodeCommandImpl(DOM::DocumentImpl *, DOM::TextImpl *, long);
574 virtual ~SplitTextNodeCommandImpl();
576 virtual int commandID() const;
578 virtual void doApply();
579 virtual void doUnapply();
581 DOM::TextImpl *node() const { return m_text2; }
582 long offset() const { return m_offset; }
584 private:
585 DOM::TextImpl *m_text1;
586 DOM::TextImpl *m_text2;
587 unsigned long m_offset;
590 //------------------------------------------------------------------------------------------
591 // TypingCommandImpl
593 class TypingCommandImpl : public CompositeEditCommandImpl
595 public:
596 TypingCommandImpl(DOM::DocumentImpl *document);
597 virtual ~TypingCommandImpl();
599 virtual int commandID() const;
601 virtual void doApply();
603 bool openForMoreTyping() const { return m_openForMoreTyping; }
604 void closeTyping() { m_openForMoreTyping = false; }
606 void insertText(const DOM::DOMString &text);
607 void insertNewline();
608 void deleteKeyPressed();
610 private:
611 void issueCommandForDeleteKey();
612 void removeCommand(const EditCommand &);
613 void typingAddedToOpenCommand();
615 bool m_openForMoreTyping;
618 //------------------------------------------------------------------------------------------
620 } // end namespace khtml
622 #endif