blob: 0aec7864617fe49efc131417b7b6f3f0bf4edfb2 [file] [log] [blame]
/*
* Copyright (C) 2005 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 __replace_selection_command_h__
#define __replace_selection_command_h__
#include "composite_edit_command.h"
#include <kxmlcore/PassRefPtr.h>
namespace DOM {
class DocumentFragmentImpl;
}
namespace khtml {
class NodeDesiredStyle
{
public:
NodeDesiredStyle(DOM::NodeImpl *, DOM::CSSMutableStyleDeclarationImpl *);
DOM::NodeImpl *node() const { return m_node.get(); }
DOM::CSSMutableStyleDeclarationImpl *style() const { return m_style.get(); }
private:
RefPtr<DOM::NodeImpl> m_node;
RefPtr<DOM::CSSMutableStyleDeclarationImpl> m_style;
};
// --- ReplacementFragment helper class
class ReplacementFragment
{
public:
ReplacementFragment(DOM::DocumentImpl *, DOM::DocumentFragmentImpl *, bool matchStyle);
~ReplacementFragment();
enum EFragmentType { EmptyFragment, SingleTextNodeFragment, TreeFragment };
DOM::DocumentFragmentImpl *root() const { return m_fragment.get(); }
DOM::NodeImpl *firstChild() const;
DOM::NodeImpl *lastChild() const;
DOM::NodeImpl *mergeStartNode() const;
const QValueList<NodeDesiredStyle> &desiredStyles() { return m_styles; }
EFragmentType type() const { return m_type; }
bool isEmpty() const { return m_type == EmptyFragment; }
bool isSingleTextNode() const { return m_type == SingleTextNodeFragment; }
bool isTreeFragment() const { return m_type == TreeFragment; }
bool hasMoreThanOneBlock() const { return m_hasMoreThanOneBlock; }
bool hasInterchangeNewlineAtStart() const { return m_hasInterchangeNewlineAtStart; }
bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEnd; }
private:
// no copy construction or assignment
ReplacementFragment(const ReplacementFragment &);
ReplacementFragment &operator=(const ReplacementFragment &);
static bool isInterchangeNewlineNode(const DOM::NodeImpl *);
static bool isInterchangeConvertedSpaceSpan(const DOM::NodeImpl *);
PassRefPtr<DOM::NodeImpl> insertFragmentForTestRendering();
void restoreTestRenderingNodesToFragment(DOM::NodeImpl *);
void computeStylesUsingTestRendering(DOM::NodeImpl *);
void removeUnrenderedNodesUsingTestRendering(DOM::NodeImpl *);
int countRenderedBlocks(DOM::NodeImpl *holder);
void removeStyleNodes();
// A couple simple DOM helpers
DOM::NodeImpl *enclosingBlock(DOM::NodeImpl *) const;
void removeNode(PassRefPtr<DOM::NodeImpl>);
void removeNodePreservingChildren(DOM::NodeImpl *);
void insertNodeBefore(DOM::NodeImpl *node, DOM::NodeImpl *refNode);
EFragmentType m_type;
RefPtr<DOM::DocumentImpl> m_document;
RefPtr<DOM::DocumentFragmentImpl> m_fragment;
QValueList<NodeDesiredStyle> m_styles;
bool m_matchStyle;
bool m_hasInterchangeNewlineAtStart;
bool m_hasInterchangeNewlineAtEnd;
bool m_hasMoreThanOneBlock;
};
class ReplaceSelectionCommand : public CompositeEditCommand
{
public:
ReplaceSelectionCommand(DOM::DocumentImpl *document, DOM::DocumentFragmentImpl *fragment, bool selectReplacement=true, bool smartReplace=false, bool matchStyle=false);
virtual ~ReplaceSelectionCommand();
virtual void doApply();
virtual EditAction editingAction() const;
private:
void completeHTMLReplacement(const DOM::Position &lastPositionToSelect);
void insertNodeAfterAndUpdateNodesInserted(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
void insertNodeAtAndUpdateNodesInserted(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild, int offset);
void insertNodeBeforeAndUpdateNodesInserted(DOM::NodeImpl *insertChild, DOM::NodeImpl *refChild);
void updateNodesInserted(DOM::NodeImpl *);
void fixupNodeStyles(const QValueList<NodeDesiredStyle> &);
void removeLinePlaceholderIfNeeded(DOM::NodeImpl *);
ReplacementFragment m_fragment;
RefPtr<DOM::NodeImpl> m_firstNodeInserted;
RefPtr<DOM::NodeImpl> m_lastNodeInserted;
RefPtr<DOM::NodeImpl> m_lastTopNodeInserted;
RefPtr<DOM::CSSMutableStyleDeclarationImpl> m_insertionStyle;
bool m_selectReplacement;
bool m_smartReplace;
bool m_matchStyle;
};
} // namespace khtml
#endif // __replace_selection_command_h__