📄 htmlediting.h
字号:
/*
* Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __htmlediting_h__
#define __htmlediting_h__
#include "dom_nodeimpl.h"
#include "editing/edit_actions.h"
#include "qmap.h"
#include "qptrlist.h"
#include "qvaluelist.h"
#include "selection.h"
#include "shared.h"
namespace DOM {
class CSSMutableStyleDeclarationImpl;
class CSSProperty;
class CSSStyleDeclarationImpl;
class DocumentFragmentImpl;
class HTMLElementImpl;
class TextImpl;
}
namespace khtml {
class EditCommand;
class Selection;
class VisiblePosition;
//------------------------------------------------------------------------------------------
// EditCommandPtr
class EditCommandPtr : public SharedPtr<EditCommand>
{
public:
EditCommandPtr();
EditCommandPtr(EditCommand *);
EditCommandPtr(const EditCommandPtr &);
~EditCommandPtr();
EditCommandPtr &operator=(const EditCommandPtr &);
bool isCompositeStep() const;
void apply() const;
void unapply() const;
void reapply() const;
EditAction editingAction() const;
DOM::DocumentImpl * const document() const;
Selection startingSelection() const;
Selection endingSelection() const;
void setStartingSelection(const Selection &s) const;
void setStartingSelection(const VisiblePosition &p) const;
void setStartingSelection(const DOM::Position &p, EAffinity affinity) const;
void setEndingSelection(const Selection &s) const;
void setEndingSelection(const VisiblePosition &p) const;
void setEndingSelection(const DOM::Position &p, EAffinity affinity) const;
DOM::CSSMutableStyleDeclarationImpl *typingStyle() const;
void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *) const;
EditCommandPtr parent() const;
void setParent(const EditCommandPtr &) const;
bool isInsertTextCommand() const;
bool isInsertLineBreakCommand() const;
bool isTypingCommand() const;
static EditCommandPtr &emptyCommand();
};
//------------------------------------------------------------------------------------------
// StyleChange
class StyleChange
OOM_MODIFIED
{
public:
enum ELegacyHTMLStyles { DoNotUseLegacyHTMLStyles, UseLegacyHTMLStyles };
explicit StyleChange(DOM::CSSStyleDeclarationImpl *, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
StyleChange(DOM::CSSStyleDeclarationImpl *, const DOM::Position &, ELegacyHTMLStyles usesLegacyStyles=UseLegacyHTMLStyles);
static ELegacyHTMLStyles styleModeForParseMode(bool);
DOM::DOMString cssStyle() const { return m_cssStyle; }
bool applyBold() const { return m_applyBold; }
bool applyItalic() const { return m_applyItalic; }
bool applyFontColor() const { return m_applyFontColor.length() > 0; }
bool applyFontFace() const { return m_applyFontFace.length() > 0; }
bool applyFontSize() const { return m_applyFontSize.length() > 0; }
DOM::DOMString fontColor() { return m_applyFontColor; }
DOM::DOMString fontFace() { return m_applyFontFace; }
DOM::DOMString fontSize() { return m_applyFontSize; }
bool usesLegacyStyles() const { return m_usesLegacyStyles; }
private:
void init(DOM::CSSStyleDeclarationImpl *, const DOM::Position &);
bool checkForLegacyHTMLStyleChange(const DOM::CSSProperty *);
static bool currentlyHasStyle(const DOM::Position &, const DOM::CSSProperty *);
DOM::DOMString m_cssStyle;
bool m_applyBold;
bool m_applyItalic;
DOM::DOMString m_applyFontColor;
DOM::DOMString m_applyFontFace;
DOM::DOMString m_applyFontSize;
bool m_usesLegacyStyles;
};
//------------------------------------------------------------------------------------------
// EditCommand
class EditCommand : public Shared<EditCommand>
{
public:
EditCommand(DOM::DocumentImpl *);
virtual ~EditCommand();
bool isCompositeStep() const { return m_parent != 0; }
EditCommand *parent() const { return m_parent; }
void setParent(EditCommand *parent) { m_parent = parent; }
enum ECommandState { NotApplied, Applied };
void apply();
void unapply();
void reapply();
virtual void doApply() = 0;
virtual void doUnapply() = 0;
virtual void doReapply(); // calls doApply()
virtual EditAction editingAction() const;
virtual DOM::DocumentImpl * const document() const { return m_document; }
Selection startingSelection() const { return m_startingSelection; }
Selection endingSelection() const { return m_endingSelection; }
void setEndingSelectionNeedsLayout(bool flag=true) { m_endingSelection.setNeedsLayout(flag); }
ECommandState state() const { return m_state; }
void setState(ECommandState state) { m_state = state; }
void setStartingSelection(const Selection &s);
void setStartingSelection(const VisiblePosition &p);
void setStartingSelection(const DOM::Position &p, EAffinity affinity);
void setEndingSelection(const Selection &s);
void setEndingSelection(const VisiblePosition &p);
void setEndingSelection(const DOM::Position &p, EAffinity affinity);
DOM::CSSMutableStyleDeclarationImpl *typingStyle() const { return m_typingStyle; };
void setTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
DOM::CSSMutableStyleDeclarationImpl *styleAtPosition(const DOM::Position &pos);
virtual bool isInsertTextCommand() const;
virtual bool isTypingCommand() const;
private:
void assignTypingStyle(DOM::CSSMutableStyleDeclarationImpl *);
virtual bool preservesTypingStyle() const;
DOM::DocumentImpl *m_document;
ECommandState m_state;
Selection m_startingSelection;
Selection m_endingSelection;
DOM::CSSMutableStyleDeclarationImpl *m_typingStyle;
EditCommand *m_parent;
};
//------------------------------------------------------------------------------------------
// CompositeEditCommand
class CompositeEditCommand : public EditCommand
{
public:
CompositeEditCommand(DOM::DocumentImpl *);
virtual void doUnapply();
virtual void doReapply();
protected:
//
// sugary-sweet convenience functions to help create and apply edit commands in composite commands
//
void appendNode(DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
void applyCommandToComposite(EditCommandPtr &);
void applyStyle(DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes);
void deleteKeyPressed();
void deleteSelection(bool smartDelete=false, bool mergeBlocksAfterDelete=true);
void deleteSelection(const Selection &selection, bool smartDelete=false, bool mergeBlocksAfterDelete=true);
void deleteTextFromNode(DOM::TextImpl *node, long offset, long count);
void inputText(const DOM::DOMString &text, bool selectInsertedText = false);
void insertNodeAfter(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
void insertNodeAt(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, long offset);
void insertNodeBefore(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
void insertParagraphSeparator();
void insertTextIntoNode(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
void rebalanceWhitespace();
void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
void removeFullySelectedNodePreservingPosition(DOM::NodeImpl *node, DOM::Position &pos);
void removeNodeAttribute(DOM::ElementImpl *, int attribute);
void removeChildrenInRangePreservingPosition(DOM::NodeImpl *node, int from, int to, DOM::Position &pos);
void removeNode(DOM::NodeImpl *removeChild);
void removeNodePreservingPosition(DOM::NodeImpl *removeChild, DOM::Position &pos);
void removeNodePreservingChildren(DOM::NodeImpl *node);
void replaceTextInNode(DOM::TextImpl *node, long offset, long count, const DOM::DOMString &replacementText);
void setNodeAttribute(DOM::ElementImpl *, int attribute, const DOM::DOMString &);
void splitTextNode(DOM::TextImpl *text, long offset);
void splitElement(DOM::ElementImpl *element, DOM::NodeImpl *atChild);
void mergeIdenticalElements(DOM::ElementImpl *first, DOM::ElementImpl *second);
void wrapContentsInDummySpan(DOM::ElementImpl *element);
void splitTextNodeContainingElement(DOM::TextImpl *text, long offset);
void deleteInsignificantText(DOM::TextImpl *, int start, int end);
void deleteInsignificantText(const DOM::Position &start, const DOM::Position &end);
void deleteInsignificantTextDownstream(const DOM::Position &);
DOM::NodeImpl *appendBlockPlaceholder(DOM::NodeImpl *);
DOM::NodeImpl *insertBlockPlaceholder(const DOM::Position &pos);
DOM::NodeImpl *addBlockPlaceholderIfNeeded(DOM::NodeImpl *);
bool removeBlockPlaceholder(DOM::NodeImpl *);
DOM::NodeImpl *findBlockPlaceholder(DOM::NodeImpl *);
void moveParagraphContentsToNewBlockIfNecessary(const DOM::Position &);
QValueList<EditCommandPtr> m_cmds;
};
//==========================================================================================
// Concrete commands
//------------------------------------------------------------------------------------------
// AppendNodeCommand
class AppendNodeCommand : public EditCommand
{
public:
AppendNodeCommand(DOM::DocumentImpl *, DOM::NodeImpl *appendChild, DOM::NodeImpl *parentNode);
virtual ~AppendNodeCommand();
virtual void doApply();
virtual void doUnapply();
DOM::NodeImpl *appendChild() const { return m_appendChild; }
DOM::NodeImpl *parentNode() const { return m_parentNode; }
private:
DOM::NodeImpl *m_appendChild;
DOM::NodeImpl *m_parentNode;
};
//------------------------------------------------------------------------------------------
// ApplyStyleCommand
class ApplyStyleCommand : public CompositeEditCommand
{
public:
enum EPropertyLevel { PropertyDefault, ForceBlockProperties };
ApplyStyleCommand(DOM::DocumentImpl *, DOM::CSSStyleDeclarationImpl *style, EditAction editingAction=EditActionChangeAttributes, EPropertyLevel=PropertyDefault);
virtual ~ApplyStyleCommand();
virtual void doApply();
virtual EditAction editingAction() const;
DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style; }
private:
// style-removal helpers
bool isHTMLStyleNode(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
void removeHTMLStyleNode(DOM::HTMLElementImpl *);
void removeHTMLFontStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
void removeCSSStyle(DOM::CSSMutableStyleDeclarationImpl *, DOM::HTMLElementImpl *);
void removeBlockStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
void removeInlineStyle(DOM::CSSMutableStyleDeclarationImpl *, const DOM::Position &start, const DOM::Position &end);
bool nodeFullySelected(DOM::NodeImpl *, const DOM::Position &start, const DOM::Position &end) const;
bool nodeFullyUnselected(DOM::NodeImpl *node, const DOM::Position &start, const DOM::Position &end) const;
DOM::CSSMutableStyleDeclarationImpl *extractTextDecorationStyle(DOM::NodeImpl *node);
DOM::CSSMutableStyleDeclarationImpl *extractAndNegateTextDecorationStyle(DOM::NodeImpl *node);
void applyTextDecorationStyle(DOM::NodeImpl *node, DOM::CSSMutableStyleDeclarationImpl *style);
void pushDownTextDecorationStyleAroundNode(DOM::NodeImpl *node, const DOM::Position &start, const DOM::Position &end, bool force);
void pushDownTextDecorationStyleAtBoundaries(const DOM::Position &start, const DOM::Position &end);
// style-application helpers
void applyBlockStyle(DOM::CSSMutableStyleDeclarationImpl *);
void applyRelativeFontStyleChange(DOM::CSSMutableStyleDeclarationImpl *);
void applyInlineStyle(DOM::CSSMutableStyleDeclarationImpl *);
void addBlockStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *);
void addInlineStyleIfNeeded(DOM::CSSMutableStyleDeclarationImpl *, DOM::NodeImpl *start, DOM::NodeImpl *end);
bool splitTextAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
bool splitTextAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
bool splitTextElementAtStartIfNeeded(const DOM::Position &start, const DOM::Position &end);
bool splitTextElementAtEndIfNeeded(const DOM::Position &start, const DOM::Position &end);
bool mergeStartWithPreviousIfIdentical(const DOM::Position &start, const DOM::Position &end);
bool mergeEndWithNextIfIdentical(const DOM::Position &start, const DOM::Position &end);
void cleanUpEmptyStyleSpans(const DOM::Position &start, const DOM::Position &end);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -