#include "wx/image.h"
#include "wx/cmdproc.h"
#include "wx/txtstrm.h"
+#include "wx/variant.h"
#if wxUSE_DATAOBJ
#include "wx/dataobj.h"
#endif
// Compatibility
+//#define wxRichTextAttr wxTextAttr
#define wxTextAttrEx wxTextAttr
// Setting wxRICHTEXT_USE_OWN_CARET to 1 implements a
// don't use for now
#define wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 0
+// The following two symbols determine whether an output implementation
+// is present. To switch the relevant one on, set wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT in
+// richtextxml.cpp. By default, the faster direct output implementation is used.
+
+// Include the wxXmlDocument implementation for output
+#define wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT 1
+
+// Include the faster, direct implementation for output
+#define wxRICHTEXT_HAVE_DIRECT_OUTPUT 1
+
/*!
* Special characters
*/
class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextEvent;
class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextRenderer;
class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextBuffer;
-class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextAnchoredObject;
-class wxRichTextFloatCollector;
+class WXDLLIMPEXP_FWD_RICHTEXT wxRichTextXMLHandler;
+class WXDLLIMPEXP_FWD_XML wxXmlNode;
+class wxRichTextFloatCollector;
/*!
* Flags determining the available space, passed to Layout
void SetValueMM(float value) { m_value = (int) ((value * 10.0) + 0.5); m_flags |= wxTEXT_ATTR_VALUE_PRESENT; }
void SetValue(int value) { m_value = value; m_flags |= wxTEXT_ATTR_VALUE_PRESENT; }
void SetValue(int value, wxTextAttrDimensionFlags flags) { m_value = value; m_flags = flags; }
+ void SetValue(const wxTextAttrDimension& dim) { (*this) = dim; }
wxTextAttrUnits GetUnits() const { return (wxTextAttrUnits) (m_flags & wxTEXT_ATTR_UNITS_MASK); }
void SetUnits(wxTextAttrUnits units) { m_flags &= ~wxTEXT_ATTR_UNITS_MASK; m_flags |= units; }
bool IsPresent() const { return (m_flags & wxTEXT_ATTR_VALUE_PRESENT) != 0; }
void SetPresent(bool b) { m_flags &= ~wxTEXT_ATTR_VALUE_PRESENT_MASK; m_flags |= (b ? wxTEXT_ATTR_VALUE_PRESENT : 0); }
+ wxTextAttrDimensionFlags GetFlags() const { return m_flags; }
+ void SetFlags(wxTextAttrDimensionFlags flags) { m_flags = flags; }
+
int m_value;
wxTextAttrDimensionFlags m_flags;
};
-class WXDLLIMPEXP_RICHTEXT wxTextBoxAttrDimensions
+// A class for left, right, top and bottom dimensions
+class WXDLLIMPEXP_RICHTEXT wxTextAttrDimensions
{
public:
void Reset() { m_left.Reset(); m_top.Reset(); m_right.Reset(); m_bottom.Reset(); }
- bool operator==(const wxTextBoxAttrDimensions& dims) const { return m_left == dims.m_left && m_top == dims.m_top && m_right == dims.m_right && m_bottom == dims.m_bottom; }
+ bool operator==(const wxTextAttrDimensions& dims) const { return m_left == dims.m_left && m_top == dims.m_top && m_right == dims.m_right && m_bottom == dims.m_bottom; }
// Partial equality test
- bool EqPartial(const wxTextBoxAttrDimensions& dims) const;
+ bool EqPartial(const wxTextAttrDimensions& dims) const;
// Apply border to 'this', but not if the same as compareWith
- bool Apply(const wxTextBoxAttrDimensions& dims, const wxTextBoxAttrDimensions* compareWith = NULL);
+ bool Apply(const wxTextAttrDimensions& dims, const wxTextAttrDimensions* compareWith = NULL);
// Collects the attributes that are common to a range of content, building up a note of
// which attributes are absent in some objects and which clash in some objects.
- void CollectCommonAttributes(const wxTextBoxAttrDimensions& attr, wxTextBoxAttrDimensions& clashingAttr, wxTextBoxAttrDimensions& absentAttr);
+ void CollectCommonAttributes(const wxTextAttrDimensions& attr, wxTextAttrDimensions& clashingAttr, wxTextAttrDimensions& absentAttr);
// Remove specified attributes from this object
- bool RemoveStyle(const wxTextBoxAttrDimensions& attr);
+ bool RemoveStyle(const wxTextAttrDimensions& attr);
+
+ const wxTextAttrDimension& GetLeft() const { return m_left; }
+ wxTextAttrDimension& GetLeft() { return m_left; }
+
+ const wxTextAttrDimension& GetRight() const { return m_right; }
+ wxTextAttrDimension& GetRight() { return m_right; }
+
+ const wxTextAttrDimension& GetTop() const { return m_top; }
+ wxTextAttrDimension& GetTop() { return m_top; }
+
+ const wxTextAttrDimension& GetBottom() const { return m_bottom; }
+ wxTextAttrDimension& GetBottom() { return m_bottom; }
wxTextAttrDimension m_left;
wxTextAttrDimension m_top;
wxTextAttrDimension m_bottom;
};
+// A class to make it easier to convert dimensions
+class WXDLLIMPEXP_RICHTEXT wxTextAttrDimensionConverter
+{
+public:
+ wxTextAttrDimensionConverter(wxDC& dc, double scale = 1.0, const wxSize& parentSize = wxDefaultSize)
+ { m_ppi = dc.GetPPI().x; m_scale = scale; m_parentSize = parentSize; }
+
+ wxTextAttrDimensionConverter(int ppi, double scale = 1.0, const wxSize& parentSize = wxDefaultSize)
+ { m_ppi = ppi; m_scale = scale; m_parentSize = parentSize; }
+
+ int GetPixels(const wxTextAttrDimension& dim, int direction = wxHORIZONTAL) const;
+ int GetTenthsMM(const wxTextAttrDimension& dim) const;
+
+ int ConvertTenthsMMToPixels(int units) const;
+ int ConvertPixelsToTenthsMM(int pixels) const;
+
+ int m_ppi;
+ double m_scale;
+ wxSize m_parentSize;
+};
+
// Border styles
-enum wxTextBoxAttrBorderStyle
+enum wxTextAttrBorderStyle
{
wxTEXT_BOX_ATTR_BORDER_NONE = 0,
wxTEXT_BOX_ATTR_BORDER_SOLID = 1,
};
// Border style presence flags
-enum wxTextBoxAttrBorderFlags
+enum wxTextAttrBorderFlags
{
wxTEXT_BOX_ATTR_BORDER_STYLE = 0x0001,
wxTEXT_BOX_ATTR_BORDER_COLOUR = 0x0002
};
+// Border width symbols for qualitative widths
+enum wxTextAttrBorderWidth
+{
+ wxTEXT_BOX_ATTR_BORDER_THIN = -1,
+ wxTEXT_BOX_ATTR_BORDER_MEDIUM = -2,
+ wxTEXT_BOX_ATTR_BORDER_THICK = -3
+};
+
// Float styles
enum wxTextBoxAttrFloatStyle
{
};
// Border
-class WXDLLIMPEXP_RICHTEXT wxTextBoxAttrBorder
+class WXDLLIMPEXP_RICHTEXT wxTextAttrBorder
{
public:
- wxTextBoxAttrBorder() { Reset(); }
+ wxTextAttrBorder() { Reset(); }
- bool operator==(const wxTextBoxAttrBorder& border) const
+ bool operator==(const wxTextAttrBorder& border) const
{
return m_flags == border.m_flags && m_borderStyle == border.m_borderStyle &&
m_borderColour == border.m_borderColour && m_borderWidth == border.m_borderWidth;
void Reset() { m_borderStyle = 0; m_borderColour = 0; m_flags = 0; m_borderWidth.Reset(); }
// Partial equality test
- bool EqPartial(const wxTextBoxAttrBorder& border) const;
+ bool EqPartial(const wxTextAttrBorder& border) const;
// Apply border to 'this', but not if the same as compareWith
- bool Apply(const wxTextBoxAttrBorder& border, const wxTextBoxAttrBorder* compareWith = NULL);
+ bool Apply(const wxTextAttrBorder& border, const wxTextAttrBorder* compareWith = NULL);
// Remove specified attributes from this object
- bool RemoveStyle(const wxTextBoxAttrBorder& attr);
+ bool RemoveStyle(const wxTextAttrBorder& attr);
// Collects the attributes that are common to a range of content, building up a note of
// which attributes are absent in some objects and which clash in some objects.
- void CollectCommonAttributes(const wxTextBoxAttrBorder& attr, wxTextBoxAttrBorder& clashingAttr, wxTextBoxAttrBorder& absentAttr);
+ void CollectCommonAttributes(const wxTextAttrBorder& attr, wxTextAttrBorder& clashingAttr, wxTextAttrBorder& absentAttr);
void SetStyle(int style) { m_borderStyle = style; m_flags |= wxTEXT_BOX_ATTR_BORDER_STYLE; }
int GetStyle() const { return m_borderStyle; }
const wxTextAttrDimension& GetWidth() const { return m_borderWidth; }
void SetWidth(const wxTextAttrDimension& width) { m_borderWidth = width; }
- bool HasStyle() const { return (m_flags & wxTEXT_BOX_ATTR_BORDER_STYLE) == 0; }
- bool HasColour() const { return (m_flags & wxTEXT_BOX_ATTR_BORDER_COLOUR) == 0; }
+ bool HasStyle() const { return (m_flags & wxTEXT_BOX_ATTR_BORDER_STYLE) != 0; }
+ bool HasColour() const { return (m_flags & wxTEXT_BOX_ATTR_BORDER_COLOUR) != 0; }
bool HasWidth() const { return m_borderWidth.IsPresent(); }
+ bool IsValid() const { return HasStyle() && HasColour() && HasWidth(); }
+
int GetFlags() const { return m_flags; }
void SetFlags(int flags) { m_flags = flags; }
void AddFlag(int flag) { m_flags |= flag; }
};
// Borders
-class WXDLLIMPEXP_RICHTEXT wxTextBoxAttrBorders
+class WXDLLIMPEXP_RICHTEXT wxTextAttrBorders
{
public:
- wxTextBoxAttrBorders() { }
+ wxTextAttrBorders() { }
- bool operator==(const wxTextBoxAttrBorders& borders) const
+ bool operator==(const wxTextAttrBorders& borders) const
{
return m_left == borders.m_left && m_right == borders.m_right &&
m_top == borders.m_top && m_bottom == borders.m_bottom;
void Reset() { m_left.Reset(); m_right.Reset(); m_top.Reset(); m_bottom.Reset(); }
// Partial equality test
- bool EqPartial(const wxTextBoxAttrBorders& borders) const;
+ bool EqPartial(const wxTextAttrBorders& borders) const;
// Apply border to 'this', but not if the same as compareWith
- bool Apply(const wxTextBoxAttrBorders& borders, const wxTextBoxAttrBorders* compareWith = NULL);
+ bool Apply(const wxTextAttrBorders& borders, const wxTextAttrBorders* compareWith = NULL);
// Remove specified attributes from this object
- bool RemoveStyle(const wxTextBoxAttrBorders& attr);
+ bool RemoveStyle(const wxTextAttrBorders& attr);
// Collects the attributes that are common to a range of content, building up a note of
// which attributes are absent in some objects and which clash in some objects.
- void CollectCommonAttributes(const wxTextBoxAttrBorders& attr, wxTextBoxAttrBorders& clashingAttr, wxTextBoxAttrBorders& absentAttr);
+ void CollectCommonAttributes(const wxTextAttrBorders& attr, wxTextAttrBorders& clashingAttr, wxTextAttrBorders& absentAttr);
+
+ bool HasBorder() const { return m_left.IsValid() || m_right.IsValid() || m_top.IsValid() || m_bottom.IsValid(); }
- wxTextBoxAttrBorder m_left, m_right, m_top, m_bottom;
+ const wxTextAttrBorder& GetLeft() const { return m_left; }
+ wxTextAttrBorder& GetLeft() { return m_left; }
+
+ const wxTextAttrBorder& GetRight() const { return m_right; }
+ wxTextAttrBorder& GetRight() { return m_right; }
+
+ const wxTextAttrBorder& GetTop() const { return m_top; }
+ wxTextAttrBorder& GetTop() { return m_top; }
+
+ const wxTextAttrBorder& GetBottom() const { return m_bottom; }
+ wxTextAttrBorder& GetBottom() { return m_bottom; }
+
+ wxTextAttrBorder m_left, m_right, m_top, m_bottom;
};
// Reset this object.
void Reset();
- // Copy. Unecessary since we let it do a binary copy
+ // Copy. Unnecessary since we let it do a binary copy
//void Copy(const wxTextBoxAttr& attr);
// Assignment
// Margins
+ wxTextAttrDimensions& GetMargins() { return m_margins; }
+ const wxTextAttrDimensions& GetMargins() const { return m_margins; }
+
wxTextAttrDimension& GetLeftMargin() { return m_margins.m_left; }
const wxTextAttrDimension& GetLeftMargin() const { return m_margins.m_left; }
// Position
+ wxTextAttrDimensions& GetPosition() { return m_position; }
+ const wxTextAttrDimensions& GetPosition() const { return m_position; }
+
wxTextAttrDimension& GetLeft() { return m_position.m_left; }
const wxTextAttrDimension& GetLeft() const { return m_position.m_left; }
// Padding
+ wxTextAttrDimensions& GetPadding() { return m_padding; }
+ const wxTextAttrDimensions& GetPadding() const { return m_padding; }
+
wxTextAttrDimension& GetLeftPadding() { return m_padding.m_left; }
const wxTextAttrDimension& GetLeftPadding() const { return m_padding.m_left; }
// Border
- wxTextBoxAttrBorders& GetBorder() { return m_border; }
- const wxTextBoxAttrBorders& GetBorder() const { return m_border; }
+ wxTextAttrBorders& GetBorder() { return m_border; }
+ const wxTextAttrBorders& GetBorder() const { return m_border; }
- wxTextBoxAttrBorder& GetLeftBorder() { return m_border.m_left; }
- const wxTextBoxAttrBorder& GetLeftBorder() const { return m_border.m_left; }
+ wxTextAttrBorder& GetLeftBorder() { return m_border.m_left; }
+ const wxTextAttrBorder& GetLeftBorder() const { return m_border.m_left; }
- wxTextBoxAttrBorder& GetTopBorder() { return m_border.m_top; }
- const wxTextBoxAttrBorder& GetTopBorder() const { return m_border.m_top; }
+ wxTextAttrBorder& GetTopBorder() { return m_border.m_top; }
+ const wxTextAttrBorder& GetTopBorder() const { return m_border.m_top; }
- wxTextBoxAttrBorder& GetRightBorder() { return m_border.m_right; }
- const wxTextBoxAttrBorder& GetRightBorder() const { return m_border.m_right; }
+ wxTextAttrBorder& GetRightBorder() { return m_border.m_right; }
+ const wxTextAttrBorder& GetRightBorder() const { return m_border.m_right; }
- wxTextBoxAttrBorder& GetBottomBorder() { return m_border.m_bottom; }
- const wxTextBoxAttrBorder& GetBottomBorder() const { return m_border.m_bottom; }
+ wxTextAttrBorder& GetBottomBorder() { return m_border.m_bottom; }
+ const wxTextAttrBorder& GetBottomBorder() const { return m_border.m_bottom; }
// Outline
- wxTextBoxAttrBorders& GetOutline() { return m_outline; }
- const wxTextBoxAttrBorders& GetOutline() const { return m_outline; }
+ wxTextAttrBorders& GetOutline() { return m_outline; }
+ const wxTextAttrBorders& GetOutline() const { return m_outline; }
- wxTextBoxAttrBorder& GetLeftOutline() { return m_outline.m_left; }
- const wxTextBoxAttrBorder& GetLeftOutline() const { return m_outline.m_left; }
+ wxTextAttrBorder& GetLeftOutline() { return m_outline.m_left; }
+ const wxTextAttrBorder& GetLeftOutline() const { return m_outline.m_left; }
- wxTextBoxAttrBorder& GetTopOutline() { return m_outline.m_top; }
- const wxTextBoxAttrBorder& GetTopOutline() const { return m_outline.m_top; }
+ wxTextAttrBorder& GetTopOutline() { return m_outline.m_top; }
+ const wxTextAttrBorder& GetTopOutline() const { return m_outline.m_top; }
- wxTextBoxAttrBorder& GetRightOutline() { return m_outline.m_right; }
- const wxTextBoxAttrBorder& GetRightOutline() const { return m_outline.m_right; }
+ wxTextAttrBorder& GetRightOutline() { return m_outline.m_right; }
+ const wxTextAttrBorder& GetRightOutline() const { return m_outline.m_right; }
- wxTextBoxAttrBorder& GetBottomOutline() { return m_outline.m_bottom; }
- const wxTextBoxAttrBorder& GetBottomOutline() const { return m_outline.m_bottom; }
+ wxTextAttrBorder& GetBottomOutline() { return m_outline.m_bottom; }
+ const wxTextAttrBorder& GetBottomOutline() const { return m_outline.m_bottom; }
// Width and height
int m_flags;
- wxTextBoxAttrDimensions m_margins;
- wxTextBoxAttrDimensions m_padding;
- wxTextBoxAttrDimensions m_position;
+ wxTextAttrDimensions m_margins;
+ wxTextAttrDimensions m_padding;
+ wxTextAttrDimensions m_position;
wxTextAttrDimension m_width;
wxTextAttrDimension m_height;
- wxTextBoxAttrBorders m_border;
- wxTextBoxAttrBorders m_outline;
+ wxTextAttrBorders m_border;
+ wxTextAttrBorders m_outline;
short int m_floatMode;
short int m_clearMode;
wxTextBoxAttr m_textBoxAttr;
};
+WX_DECLARE_USER_EXPORTED_OBJARRAY(wxVariant, wxRichTextVariantArray, WXDLLIMPEXP_RICHTEXT);
+
+// ----------------------------------------------------------------------------
+// wxRichTextProperties - A simple property class using wxVariants
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextProperties: public wxObject
+{
+DECLARE_DYNAMIC_CLASS(wxRichTextProperties)
+public:
+ wxRichTextProperties() {}
+ wxRichTextProperties(const wxRichTextProperties& props) { Copy(props); }
+
+ void operator=(const wxRichTextProperties& props) { Copy(props); }
+ bool operator==(const wxRichTextProperties& props) const;
+ void Copy(const wxRichTextProperties& props) { m_properties = props.m_properties; }
+ const wxVariant& operator[](size_t idx) const { return m_properties[idx]; }
+ wxVariant& operator[](size_t idx) { return m_properties[idx]; }
+ void Clear() { m_properties.Clear(); }
+
+ const wxRichTextVariantArray& GetProperties() const { return m_properties; }
+ wxRichTextVariantArray& GetProperties() { return m_properties; }
+ void SetProperties(const wxRichTextVariantArray& props) { m_properties = props; }
+
+ wxArrayString GetPropertyNames() const;
+
+ size_t GetCount() const { return m_properties.GetCount(); }
+
+ int HasProperty(const wxString& name) const { return Find(name) != -1; }
+
+ int Find(const wxString& name) const;
+ const wxVariant& GetProperty(const wxString& name) const;
+ wxVariant* FindOrCreateProperty(const wxString& name);
+
+ wxString GetPropertyString(const wxString& name) const;
+ long GetPropertyLong(const wxString& name) const;
+ bool GetPropertyBool(const wxString& name) const;
+ double GetPropertyDouble(const wxString& name) const;
+
+ void SetProperty(const wxVariant& variant);
+ void SetProperty(const wxString& name, const wxVariant& variant);
+ void SetProperty(const wxString& name, const wxString& value);
+ void SetProperty(const wxString& name, long value);
+ void SetProperty(const wxString& name, double value);
+ void SetProperty(const wxString& name, bool value);
+
+protected:
+ wxRichTextVariantArray m_properties;
+};
+
+
/*!
* wxRichTextFontTable
* Manages quick access to a pool of fonts for rendering rich text
virtual bool IsFloatable() const { return false; }
/// Whether this object is currently floating
- virtual bool IsFloating() const { return false; }
+ virtual bool IsFloating() const { return GetAttributes().GetTextBoxAttr().IsFloating(); }
/// Whether this object is a place holding one
// virtual bool IsPlaceHolding() const { return false; }
- /// Floating direction
- virtual int GetFloatDirection() const { return wxTEXT_BOX_ATTR_FLOAT_NONE; }
+ /// The floating direction
+ virtual int GetFloatDirection() const { return GetAttributes().GetTextBoxAttr().GetFloatMode(); }
/// Get any text in this object for the given range
virtual wxString GetTextForRange(const wxRichTextRange& WXUNUSED(range)) const { return wxEmptyString; }
/// Edit properties via a GUI
virtual bool EditProperties(wxWindow* WXUNUSED(parent), wxRichTextBuffer* WXUNUSED(buffer)) { return false; }
+#if wxUSE_XML
+ /// Import this object from XML
+ virtual bool ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ /// Export this object directly to the given stream.
+ virtual bool ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+ /// Export this object to the given parent node, usually creating at least one child node.
+ virtual bool ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler);
+#endif
+
+ /// Does this object take note of paragraph attributes? Text and image objects don't.
+ virtual bool UsesParagraphAttributes() const { return true; }
+
+ /// What is the XML node name of this object?
+ virtual wxString GetXMLNodeName() const { return wxT("unknown"); }
+
// Accessors
/// Get/set the cached object size as calculated by Layout.
virtual int GetTopMargin() const { return m_topMargin; }
virtual int GetBottomMargin() const { return m_bottomMargin; }
- /// Set attributes object
+ /// Set/get attributes object
void SetAttributes(const wxRichTextAttr& attr) { m_attributes = attr; }
const wxRichTextAttr& GetAttributes() const { return m_attributes; }
wxRichTextAttr& GetAttributes() { return m_attributes; }
+
+ /// Set/get properties
+ wxRichTextProperties& GetProperties() { return m_properties; }
+ const wxRichTextProperties& GetProperties() const { return m_properties; }
+ void SetProperties(const wxRichTextProperties& props) { m_properties = props; }
/// Set/get stored descent
void SetDescent(int descent) { m_descent = descent; }
/// Convert units in tenths of a millimetre to device units
int ConvertTenthsMMToPixels(wxDC& dc, int units) const;
- static int ConvertTenthsMMToPixels(int ppi, int units);
+ static int ConvertTenthsMMToPixels(int ppi, int units, double scale = 1.0);
/// Convert units in pixels to tenths of a millimetre
int ConvertPixelsToTenthsMM(wxDC& dc, int pixels) const;
- static int ConvertPixelsToTenthsMM(int ppi, int pixels);
+ static int ConvertPixelsToTenthsMM(int ppi, int pixels, double scale = 1.0);
+
+ /// Draw the borders and background for the given rectangle and attributes.
+ /// Width and height are taken to be the content size, so excluding any
+ /// border, margin and padding.
+ static bool DrawBoxAttributes(wxDC& dc, const wxRichTextAttr& attr, const wxRect& boxRect);
+
+ /// Draw a border
+ static bool DrawBorder(wxDC& dc, const wxTextAttrBorders& attr, const wxRect& rect);
+
+ /// Get the various rectangles of the box model in pixels. You can either specify contentRect (inner)
+ /// or marginRect (outer), and the other must be the default rectangle (no width or height).
+ /// Note that the outline doesn't affect the position of the rectangle, it's drawn in whatever space
+ /// is available.
+ static bool GetBoxRects(wxDC& dc, const wxRichTextAttr& attr, wxRect& marginRect, wxRect& borderRect, wxRect& contentRect, wxRect& paddingRect, wxRect& outlineRect);
protected:
wxSize m_size;
/// Attributes
wxRichTextAttr m_attributes;
+
+ /// Properties
+ wxRichTextProperties m_properties;
};
WX_DECLARE_LIST_WITH_DECL( wxRichTextObject, wxRichTextObjectList, class WXDLLIMPEXP_RICHTEXT );
wxRichTextObjectList m_children;
};
-/*!
- * wxRichTextBox class declaration
- * This defines a 2D space to lay out objects
- */
-
-class WXDLLIMPEXP_RICHTEXT wxRichTextBox: public wxRichTextCompositeObject
-{
- DECLARE_DYNAMIC_CLASS(wxRichTextBox)
-public:
-// Constructors
-
- wxRichTextBox(wxRichTextObject* parent = NULL);
- wxRichTextBox(const wxRichTextBox& obj): wxRichTextCompositeObject() { Copy(obj); }
-
-// Overrideables
-
- /// Draw the item
- virtual bool Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int descent, int style);
-
- /// Lay the item out
- virtual bool Layout(wxDC& dc, const wxRect& rect, int style);
-
- /// Get/set the object size for the given range. Returns false if the range
- /// is invalid for this object.
- virtual bool GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const;
-
-// Accessors
-
-// Operations
-
- /// Clone
- virtual wxRichTextObject* Clone() const { return new wxRichTextBox(*this); }
-
- /// Copy
- void Copy(const wxRichTextBox& obj);
-
-protected:
-};
-
/*!
* wxRichTextParagraphBox class declaration
* This box knows how to lay out paragraphs.
*/
-class WXDLLIMPEXP_RICHTEXT wxRichTextParagraphLayoutBox: public wxRichTextBox
+class WXDLLIMPEXP_RICHTEXT wxRichTextParagraphLayoutBox: public wxRichTextCompositeObject
{
DECLARE_DYNAMIC_CLASS(wxRichTextParagraphLayoutBox)
public:
// Constructors
wxRichTextParagraphLayoutBox(wxRichTextObject* parent = NULL);
- wxRichTextParagraphLayoutBox(const wxRichTextParagraphLayoutBox& obj): wxRichTextBox() { Init(); Copy(obj); }
+ wxRichTextParagraphLayoutBox(const wxRichTextParagraphLayoutBox& obj): wxRichTextCompositeObject() { Init(); Copy(obj); }
~wxRichTextParagraphLayoutBox();
// Overrideables
/// Get any text in this object for the given range
virtual wxString GetTextForRange(const wxRichTextRange& range) const;
+#if wxUSE_XML
+ /// Import this object from XML
+ virtual bool ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ /// Export this object directly to the given stream.
+ virtual bool ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+ /// Export this object to the given parent node, usually creating at least one child node.
+ virtual bool ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler);
+#endif
+
+ /// What is the XML node name of this object?
+ virtual wxString GetXMLNodeName() const { return wxT("paragraphlayout"); }
+
// Accessors
/// Associate a control with the buffer, for operations that for example require refreshing the window.
void DrawFloats(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int descent, int style);
/// Move an anchored object to another paragraph
- void MoveAnchoredObjectToParagraph(wxRichTextParagraph* from, wxRichTextParagraph* to, wxRichTextAnchoredObject* obj);
+ void MoveAnchoredObjectToParagraph(wxRichTextParagraph* from, wxRichTextParagraph* to, wxRichTextObject* obj);
/// Initialize the object.
void Init();
wxRichTextFloatCollector* m_floatCollector;
};
+/*!
+ * wxRichTextBox class declaration
+ * TODO: a floating text box
+ */
+
+class WXDLLIMPEXP_RICHTEXT wxRichTextBox: public wxRichTextParagraphLayoutBox
+{
+ DECLARE_DYNAMIC_CLASS(wxRichTextBox)
+public:
+// Constructors
+
+ wxRichTextBox(wxRichTextObject* parent = NULL);
+ wxRichTextBox(const wxRichTextBox& obj): wxRichTextParagraphLayoutBox() { Copy(obj); }
+
+// Overrideables
+
+ /// Draw the item
+ virtual bool Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int descent, int style);
+
+ /// Lay the item out
+ virtual bool Layout(wxDC& dc, const wxRect& rect, int style);
+
+// Accessors
+
+// Operations
+
+ /// Clone
+ virtual wxRichTextObject* Clone() const { return new wxRichTextBox(*this); }
+
+ /// Copy
+ void Copy(const wxRichTextBox& obj);
+
+protected:
+};
+
/*!
* wxRichTextLine class declaration
* This object represents a line in a paragraph, and stores
/// Calculate range
virtual void CalculateRange(long start, long& end);
+ /// What is the XML node name of this object?
+ virtual wxString GetXMLNodeName() const { return wxT("paragraph"); }
+
// Accessors
/// Get the cached lines
/// Get the first position from pos that has a line break character.
long GetFirstLineBreakPosition(long pos);
+ /// Does this object take note of paragraph attributes? Text and image objects don't.
+ virtual bool UsesParagraphAttributes() const { return false; }
+
+#if wxUSE_XML
+ /// Import this object from XML
+ virtual bool ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ /// Export this object directly to the given stream.
+ virtual bool ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+ /// Export this object to the given parent node, usually creating at least one child node.
+ virtual bool ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler);
+#endif
+
+ /// What is the XML node name of this object?
+ virtual wxString GetXMLNodeName() const { return wxT("text"); }
+
// Accessors
/// Get the text
wxBitmapType m_imageType;
};
-/*!
- * wxRichTextAnchoredObject class declaration
- * This object is an abstract one that represent some objects which can floats
- */
-class WXDLLIMPEXP_RICHTEXT wxRichTextAnchoredObject: public wxRichTextObject
-{
- DECLARE_CLASS(wxRichTextAnchoredObject)
-public:
-// Constructors
- wxRichTextAnchoredObject(wxRichTextObject* parent = NULL, const wxRichTextAttr& attr = wxRichTextAttr());
- wxRichTextAnchoredObject(const wxRichTextAnchoredObject& obj) : wxRichTextObject(obj) /* , m_ph(NULL) */ { Copy(obj); }
- ~wxRichTextAnchoredObject();
-
-// Virtuals
- virtual bool IsFloatable() const { return true; }
-
- /// Whether this object is currently floating
- virtual bool IsFloating() const { return GetAttributes().GetTextBoxAttr().IsFloating(); }
-
- virtual void SetParent(wxRichTextObject* parent);
-
-// Accessors
-
- /// The floating direction
- virtual int GetFloatDirection() const { return GetAttributes().GetTextBoxAttr().GetFloatMode(); }
-
- void operator=(const wxRichTextAnchoredObject&) { wxASSERT("Nobody can reset this object using ="); }
-
-// Functions
- void Copy(const wxRichTextAnchoredObject& obj);
-
-protected:
-
-};
-
/*!
* wxRichTextImage class declaration
* This object represents an image.
*/
-class WXDLLIMPEXP_RICHTEXT wxRichTextImage: public wxRichTextAnchoredObject
+class WXDLLIMPEXP_RICHTEXT wxRichTextImage: public wxRichTextObject
{
DECLARE_DYNAMIC_CLASS(wxRichTextImage)
public:
// Constructors
- wxRichTextImage(wxRichTextObject* parent = NULL): wxRichTextAnchoredObject(parent) { }
+ wxRichTextImage(wxRichTextObject* parent = NULL): wxRichTextObject(parent) { }
wxRichTextImage(const wxImage& image, wxRichTextObject* parent = NULL, wxRichTextAttr* charStyle = NULL);
wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent = NULL, wxRichTextAttr* charStyle = NULL);
- wxRichTextImage(const wxRichTextImage& obj): wxRichTextAnchoredObject(obj) { Copy(obj); }
+ wxRichTextImage(const wxRichTextImage& obj): wxRichTextObject(obj) { Copy(obj); }
// Overrideables
/// is invalid for this object.
virtual bool GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position = wxPoint(0,0), wxArrayInt* partialExtents = NULL) const;
- /// Returns true if the object is empty
- virtual bool IsEmpty() const { return !m_imageBlock.Ok(); }
+ /// Returns true if the object is empty. An image is never empty; if the image is broken, that's not the same thing as empty.
+ virtual bool IsEmpty() const { return false; /* !m_imageBlock.Ok(); */ }
/// Can we edit properties via a GUI?
virtual bool CanEditProperties() const { return true; }
/// Edit properties via a GUI
virtual bool EditProperties(wxWindow* parent, wxRichTextBuffer* buffer);
+ /// Does this object take note of paragraph attributes? Text and image objects don't.
+ virtual bool UsesParagraphAttributes() const { return false; }
+
+#if wxUSE_XML
+ /// Import this object from XML
+ virtual bool ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ /// Export this object directly to the given stream.
+ virtual bool ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler);
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+ /// Export this object to the given parent node, usually creating at least one child node.
+ virtual bool ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler);
+#endif
+
+ // Images can be floatable (optionally).
+ virtual bool IsFloatable() const { return true; }
+
+ /// What is the XML node name of this object?
+ virtual wxString GetXMLNodeName() const { return wxT("image"); }
+
// Accessors
/// Get the image cache (scaled bitmap)
/// Copy
void Copy(const wxRichTextBuffer& obj);
+ /// Assignment
+ void operator= (const wxRichTextBuffer& obj) { Copy(obj); }
+
/// Clone
virtual wxRichTextObject* Clone() const { return new wxRichTextBuffer(*this); }
#include "wx/richtext/richtextimagedlg.h"
#include "wx/listimpl.cpp"
+#include "wx/arrimpl.cpp"
WX_DEFINE_LIST(wxRichTextObjectList)
WX_DEFINE_LIST(wxRichTextLineList)
if (floating->IsFloating())
{
- wxRichTextAnchoredObject* anchor = wxDynamicCast(floating, wxRichTextAnchoredObject);
- if (anchor)
- {
- CollectFloat(para, floating);
- }
+ CollectFloat(para, floating);
}
node = node->GetNext();
m_dirty = obj.m_dirty;
m_range = obj.m_range;
m_attributes = obj.m_attributes;
+ m_properties = obj.m_properties;
m_descent = obj.m_descent;
}
// Convert units in tenths of a millimetre to device units
int wxRichTextObject::ConvertTenthsMMToPixels(wxDC& dc, int units) const
{
- int p = ConvertTenthsMMToPixels(dc.GetPPI().x, units);
-
// Unscale
- wxRichTextBuffer* buffer = GetBuffer();
- if (buffer)
- p = (int) ((double)p / buffer->GetScale());
+ double scale = 1.0;
+ if (GetBuffer())
+ scale = GetBuffer()->GetScale();
+ int p = ConvertTenthsMMToPixels(dc.GetPPI().x, units, scale);
+
return p;
}
// Convert units in tenths of a millimetre to device units
-int wxRichTextObject::ConvertTenthsMMToPixels(int ppi, int units)
+int wxRichTextObject::ConvertTenthsMMToPixels(int ppi, int units, double scale)
{
// There are ppi pixels in 254.1 "1/10 mm"
double pixels = ((double) units * (double)ppi) / 254.1;
+ if (scale != 1.0)
+ pixels /= scale;
return (int) pixels;
}
int wxRichTextObject::ConvertPixelsToTenthsMM(wxDC& dc, int pixels) const
{
int p = pixels;
- if (GetBuffer() && GetBuffer()->GetScale() != 1.0)
- p = (int) (double(p) * GetBuffer()->GetScale());
- return ConvertPixelsToTenthsMM(dc.GetPPI().x, p);
+ double scale = 1.0;
+ if (GetBuffer())
+ scale = GetBuffer()->GetScale();
+
+ return ConvertPixelsToTenthsMM(dc.GetPPI().x, p, scale);
}
-int wxRichTextObject::ConvertPixelsToTenthsMM(int ppi, int pixels)
+int wxRichTextObject::ConvertPixelsToTenthsMM(int ppi, int pixels, double scale)
{
// There are ppi pixels in 254.1 "1/10 mm"
-
- int units = int( double(pixels) * 254.1 / (double) ppi );
+
+ double p = double(pixels);
+
+ if (scale != 1.0)
+ p *= scale;
+
+ int units = int( p * 254.1 / (double) ppi );
return units;
}
+// Draw the borders and background for the given rectangle and attributes.
+// Width and height are taken to be the content size, so excluding any
+// border, margin and padding.
+bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, const wxRichTextAttr& attr, const wxRect& boxRect)
+{
+ // Assume boxRect is the area around the content
+ wxRect contentRect = boxRect;
+ wxRect marginRect, borderRect, paddingRect, outlineRect;
+
+ GetBoxRects(dc, attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
+
+ // Margin is transparent. Draw background from margin.
+ if (attr.HasBackgroundColour())
+ {
+ wxPen pen(attr.GetBackgroundColour());
+ wxBrush brush(attr.GetBackgroundColour());
+
+ dc.SetPen(pen);
+ dc.SetBrush(brush);
+ dc.DrawRectangle(marginRect);
+ }
+
+ if (attr.GetTextBoxAttr().GetBorder().HasBorder())
+ DrawBorder(dc, attr.GetTextBoxAttr().GetBorder(), borderRect);
+
+ if (attr.GetTextBoxAttr().GetOutline().HasBorder())
+ DrawBorder(dc, attr.GetTextBoxAttr().GetOutline(), outlineRect);
+
+ return true;
+}
+
+// Draw a border
+bool wxRichTextObject::DrawBorder(wxDC& dc, const wxTextAttrBorders& attr, const wxRect& rect)
+{
+ int borderLeft = 0, borderRight = 0, borderTop = 0, borderBottom = 0;
+ wxTextAttrDimensionConverter converter(dc);
+
+ if (attr.GetLeft().IsValid())
+ {
+ borderLeft = converter.GetPixels(attr.GetLeft().GetWidth());
+ wxColour col(attr.GetLeft().GetColour());
+
+ // If pen width is > 1, resorts to a solid rectangle.
+ if (borderLeft == 1)
+ {
+ int penStyle = wxSOLID;
+ if (attr.GetLeft().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED)
+ penStyle = wxDOT;
+ else if (attr.GetLeft().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED)
+ penStyle = wxLONG_DASH;
+ wxPen pen(col);
+ dc.SetPen(pen);
+ dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
+
+ }
+ else if (borderLeft > 1)
+ {
+ wxPen pen(col);
+ wxBrush brush(col);
+ dc.SetPen(pen);
+ dc.SetBrush(brush);
+ dc.DrawRectangle(rect.x, rect.y, borderLeft, rect.height);
+ }
+ }
+
+ if (attr.GetRight().IsValid())
+ {
+ borderRight = converter.GetPixels(attr.GetRight().GetWidth());
+
+ wxColour col(attr.GetRight().GetColour());
+
+ // If pen width is > 1, resorts to a solid rectangle.
+ if (borderRight == 1)
+ {
+ int penStyle = wxSOLID;
+ if (attr.GetRight().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED)
+ penStyle = wxDOT;
+ else if (attr.GetRight().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED)
+ penStyle = wxLONG_DASH;
+ wxPen pen(col);
+ dc.SetPen(pen);
+ dc.DrawLine(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height);
+
+ }
+ else if (borderRight > 1)
+ {
+ wxPen pen(col);
+ wxBrush brush(col);
+ dc.SetPen(pen);
+ dc.SetBrush(brush);
+ dc.DrawRectangle(rect.x - borderRight, rect.y, borderRight, rect.height);
+ }
+ }
+
+ if (attr.GetTop().IsValid())
+ {
+ borderTop = converter.GetPixels(attr.GetTop().GetWidth());
+
+ wxColour col(attr.GetTop().GetColour());
+
+ // If pen width is > 1, resorts to a solid rectangle.
+ if (borderTop == 1)
+ {
+ int penStyle = wxSOLID;
+ if (attr.GetTop().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED)
+ penStyle = wxDOT;
+ else if (attr.GetTop().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED)
+ penStyle = wxLONG_DASH;
+ wxPen pen(col);
+ dc.SetPen(pen);
+ dc.DrawLine(rect.x, rect.y, rect.x + rect.width, rect.y);
+
+ }
+ else if (borderTop > 1)
+ {
+ wxPen pen(col);
+ wxBrush brush(col);
+ dc.SetPen(pen);
+ dc.SetBrush(brush);
+ dc.DrawRectangle(rect.x, rect.y, rect.width, borderTop);
+ }
+ }
+
+ if (attr.GetBottom().IsValid())
+ {
+ borderBottom = converter.GetPixels(attr.GetBottom().GetWidth());
+ wxColour col(attr.GetTop().GetColour());
+
+ // If pen width is > 1, resorts to a solid rectangle.
+ if (borderBottom == 1)
+ {
+ int penStyle = wxSOLID;
+ if (attr.GetBottom().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED)
+ penStyle = wxDOT;
+ else if (attr.GetBottom().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED)
+ penStyle = wxLONG_DASH;
+ wxPen pen(col);
+ dc.SetPen(pen);
+ dc.DrawLine(rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height);
+
+ }
+ else if (borderBottom > 1)
+ {
+ wxPen pen(col);
+ wxBrush brush(col);
+ dc.SetPen(pen);
+ dc.SetBrush(brush);
+ dc.DrawRectangle(rect.x, rect.y - rect.height - borderBottom, rect.width, borderBottom);
+ }
+ }
+
+ return true;
+}
+
+// Get the various rectangles of the box model in pixels. You can either specify contentRect (inner)
+// or marginRect (outer), and the other must be the default rectangle (no width or height).
+// Note that the outline doesn't affect the position of the rectangle, it's drawn in whatever space
+// is available.
+//
+// | Margin | Border | Padding | CONTENT | Padding | Border | Margin |
+
+bool wxRichTextObject::GetBoxRects(wxDC& dc, const wxRichTextAttr& attr, wxRect& marginRect, wxRect& borderRect, wxRect& contentRect, wxRect& paddingRect, wxRect& outlineRect)
+{
+ int borderLeft = 0, borderRight = 0, borderTop = 0, borderBottom = 0;
+ int outlineLeft = 0, outlineRight = 0, outlineTop = 0, outlineBottom = 0;
+ int paddingLeft = 0, paddingRight = 0, paddingTop = 0, paddingBottom = 0;
+ int marginLeft = 0, marginRight = 0, marginTop = 0, marginBottom = 0;
+
+ wxTextAttrDimensionConverter converter(dc);
+
+ if (attr.GetTextBoxAttr().GetMargins().GetLeft().IsPresent())
+ marginLeft = converter.GetPixels(attr.GetTextBoxAttr().GetMargins().GetLeft());
+ if (attr.GetTextBoxAttr().GetMargins().GetRight().IsPresent())
+ marginRight = converter.GetPixels(attr.GetTextBoxAttr().GetMargins().GetRight());
+ if (attr.GetTextBoxAttr().GetMargins().GetTop().IsPresent())
+ marginTop = converter.GetPixels(attr.GetTextBoxAttr().GetMargins().GetTop());
+ if (attr.GetTextBoxAttr().GetMargins().GetLeft().IsPresent())
+ marginBottom = converter.GetPixels(attr.GetTextBoxAttr().GetMargins().GetBottom());
+
+ if (attr.GetTextBoxAttr().GetBorder().GetLeft().GetWidth().IsPresent())
+ borderLeft = converter.GetPixels(attr.GetTextBoxAttr().GetBorder().GetLeft().GetWidth());
+ if (attr.GetTextBoxAttr().GetBorder().GetRight().GetWidth().IsPresent())
+ borderRight = converter.GetPixels(attr.GetTextBoxAttr().GetBorder().GetRight().GetWidth());
+ if (attr.GetTextBoxAttr().GetBorder().GetTop().GetWidth().IsPresent())
+ borderTop = converter.GetPixels(attr.GetTextBoxAttr().GetBorder().GetTop().GetWidth());
+ if (attr.GetTextBoxAttr().GetBorder().GetLeft().GetWidth().IsPresent())
+ borderBottom = converter.GetPixels(attr.GetTextBoxAttr().GetBorder().GetBottom().GetWidth());
+
+ if (attr.GetTextBoxAttr().GetPadding().GetLeft().IsPresent())
+ paddingLeft = converter.GetPixels(attr.GetTextBoxAttr().GetPadding().GetLeft());
+ if (attr.GetTextBoxAttr().GetPadding().GetRight().IsPresent())
+ paddingRight = converter.GetPixels(attr.GetTextBoxAttr().GetPadding().GetRight());
+ if (attr.GetTextBoxAttr().GetPadding().GetTop().IsPresent())
+ paddingTop = converter.GetPixels(attr.GetTextBoxAttr().GetPadding().GetTop());
+ if (attr.GetTextBoxAttr().GetPadding().GetLeft().IsPresent())
+ paddingBottom = converter.GetPixels(attr.GetTextBoxAttr().GetPadding().GetBottom());
+
+ if (attr.GetTextBoxAttr().GetOutline().GetLeft().GetWidth().IsPresent())
+ outlineLeft = converter.GetPixels(attr.GetTextBoxAttr().GetOutline().GetLeft().GetWidth());
+ if (attr.GetTextBoxAttr().GetOutline().GetRight().GetWidth().IsPresent())
+ outlineRight = converter.GetPixels(attr.GetTextBoxAttr().GetOutline().GetRight().GetWidth());
+ if (attr.GetTextBoxAttr().GetOutline().GetTop().GetWidth().IsPresent())
+ outlineTop = converter.GetPixels(attr.GetTextBoxAttr().GetOutline().GetTop().GetWidth());
+ if (attr.GetTextBoxAttr().GetOutline().GetLeft().GetWidth().IsPresent())
+ outlineBottom = converter.GetPixels(attr.GetTextBoxAttr().GetOutline().GetBottom().GetWidth());
+
+ int leftTotal = marginLeft + borderLeft + paddingLeft;
+ int rightTotal = marginRight + borderRight + paddingRight;
+ int topTotal = marginTop + borderTop + paddingTop;
+ int bottomTotal = marginBottom + borderBottom + paddingBottom;
+
+ if (marginRect != wxRect())
+ {
+ contentRect.x = marginRect.x + leftTotal;
+ contentRect.y = marginRect.y + topTotal;
+ contentRect.width = marginRect.width - (leftTotal + rightTotal);
+ contentRect.height = marginRect.height - (topTotal + bottomTotal);
+ }
+ else
+ {
+ marginRect.x = contentRect.x - leftTotal;
+ marginRect.y = contentRect.y - topTotal;
+ marginRect.width = contentRect.width + (leftTotal + rightTotal);
+ marginRect.height = contentRect.height + (topTotal + bottomTotal);
+ }
+
+ borderRect.x = marginRect.x + marginLeft;
+ borderRect.y = marginRect.y + marginTop;
+ borderRect.width = marginRect.width - (marginLeft + marginRight);
+ borderRect.height = marginRect.height - (marginTop + marginBottom);
+
+ paddingRect.x = marginRect.x + marginLeft + borderLeft;
+ paddingRect.y = marginRect.y + marginTop + borderTop;
+ paddingRect.width = marginRect.width - (marginLeft + marginRight + borderLeft + borderRight);
+ paddingRect.height = marginRect.height - (marginTop + marginBottom + borderTop + borderBottom);
+
+ // The outline is outside the margin and doesn't influence the overall box position or content size.
+ outlineRect.x = marginRect.x - outlineLeft;
+ outlineRect.y = marginRect.y - outlineTop;
+ outlineRect.width = marginRect.width + (outlineLeft + outlineRight);
+ outlineRect.height = marginRect.height + (outlineTop + outlineBottom);
+
+ return true;
+}
+
+
/// Dump to output stream for debugging
void wxRichTextObject::Dump(wxTextOutputStream& stream)
{
node = node->GetNext();
}
- return true;
-}
-
-/// Dump to output stream for debugging
-void wxRichTextCompositeObject::Dump(wxTextOutputStream& stream)
-{
- wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
- while (node)
+ // Delete any remaining empty objects, but leave at least one empty object per composite object.
+ if (GetChildCount() > 1)
{
- wxRichTextObject* child = node->GetData();
- child->Dump(stream);
- node = node->GetNext();
+ node = m_children.GetFirst();
+ while (node)
+ {
+ wxRichTextObjectList::compatibility_iterator next = node->GetNext();
+ wxRichTextObject* child = node->GetData();
+ if (range == wxRICHTEXT_ALL || !child->GetRange().IsOutside(range))
+ {
+ if (child->IsEmpty())
+ {
+ child->Dereference();
+ m_children.Erase(node);
+ }
+ node = next;
+ }
+ else
+ node = node->GetNext();
+ }
}
-}
-
-/*!
- * wxRichTextBox
- * This defines a 2D space to lay out objects
- */
-
-IMPLEMENT_DYNAMIC_CLASS(wxRichTextBox, wxRichTextCompositeObject)
-
-wxRichTextBox::wxRichTextBox(wxRichTextObject* parent):
- wxRichTextCompositeObject(parent)
-{
-}
-
-/// Draw the item
-bool wxRichTextBox::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& WXUNUSED(rect), int descent, int style)
-{
- wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
- while (node)
- {
- wxRichTextObject* child = node->GetData();
-
- wxRect childRect = wxRect(child->GetPosition(), child->GetCachedSize());
- child->Draw(dc, range, selectionRange, childRect, descent, style);
-
- node = node->GetNext();
- }
return true;
}
-/// Lay the item out
-bool wxRichTextBox::Layout(wxDC& dc, const wxRect& rect, int style)
+/// Dump to output stream for debugging
+void wxRichTextCompositeObject::Dump(wxTextOutputStream& stream)
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
wxRichTextObject* child = node->GetData();
- child->Layout(dc, rect, style);
-
+ child->Dump(stream);
node = node->GetNext();
}
- m_dirty = false;
- return true;
-}
-
-/// Get/set the size for the given range. Assume only has one child.
-bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
-{
- wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
- if (node)
- {
- wxRichTextObject* child = node->GetData();
- return child->GetRangeSize(range, size, descent, dc, flags, position, partialExtents);
- }
- else
- return false;
}
-/// Copy
-void wxRichTextBox::Copy(const wxRichTextBox& obj)
-{
- wxRichTextCompositeObject::Copy(obj);
-}
-
-
/*!
* wxRichTextParagraphLayoutBox
* This box knows how to lay out paragraphs.
*/
-IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraphLayoutBox, wxRichTextBox)
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraphLayoutBox, wxRichTextCompositeObject)
wxRichTextParagraphLayoutBox::wxRichTextParagraphLayoutBox(wxRichTextObject* parent):
- wxRichTextBox(parent)
+ wxRichTextCompositeObject(parent)
{
Init();
}
m_floatCollector = NULL;
}
+void wxRichTextParagraphLayoutBox::Clear()
+{
+ DeleteChildren();
+
+ if (m_floatCollector)
+ delete m_floatCollector;
+ m_floatCollector = NULL;
+ m_partialParagraph = false;
+}
+
+/// Copy
+void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox& obj)
+{
+ Clear();
+
+ wxRichTextCompositeObject::Copy(obj);
+
+ m_partialParagraph = obj.m_partialParagraph;
+ m_defaultAttributes = obj.m_defaultAttributes;
+}
+
// Gather information about floating objects
bool wxRichTextParagraphLayoutBox::UpdateFloatingObjects(int width, wxRichTextObject* untilObj)
{
m_floatCollector->Draw(dc, range, selectionRange, rect, descent, style);
}
-void wxRichTextParagraphLayoutBox::MoveAnchoredObjectToParagraph(wxRichTextParagraph* from, wxRichTextParagraph* to, wxRichTextAnchoredObject* obj)
+void wxRichTextParagraphLayoutBox::MoveAnchoredObjectToParagraph(wxRichTextParagraph* from, wxRichTextParagraph* to, wxRichTextObject* obj)
{
if (from == to)
return;
return true;
}
-/// Copy
-void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox& obj)
-{
- wxRichTextBox::Copy(obj);
-
- m_partialParagraph = obj.m_partialParagraph;
- m_defaultAttributes = obj.m_defaultAttributes;
-}
-
/// Get/set the size for the given range.
bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* WXUNUSED(partialExtents)) const
{
action->SetRange(image->GetRange().FromInternal());
action->SetPosition(GetRichTextCtrl()->GetCaretPosition());
image->SetAttributes(textAttr);
-
+
// Set the new attribute
newPara = new wxRichTextParagraph(*para);
action->GetNewParagraphs().AppendChild(newPara);
return foundCount == matchingCount && foundCount != 0;
}
-void wxRichTextParagraphLayoutBox::Clear()
-{
- DeleteChildren();
-}
-
void wxRichTextParagraphLayoutBox::Reset()
{
Clear();
void wxRichTextParagraph::Copy(const wxRichTextParagraph& obj)
{
- wxRichTextBox::Copy(obj);
+ wxRichTextCompositeObject::Copy(obj);
}
/// Clear the cached lines
wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
while (node)
{
- wxRichTextAnchoredObject* anchored = wxDynamicCast(node->GetData(), wxRichTextAnchoredObject);
+ wxRichTextObject* anchored = node->GetData();
if (anchored && anchored->IsFloating())
{
wxSize size;
int descent, x = 0;
anchored->GetRangeSize(anchored->GetRange(), size, descent, dc, style);
-
+
int offsetY = 0;
if (anchored->GetAttributes().GetTextBoxAttr().GetTop().IsPresent())
{
offsetY = ConvertTenthsMMToPixels(dc, offsetY);
}
}
-
+
int pos = floatCollector->GetFitPosition(anchored->GetAttributes().GetTextBoxAttr().GetFloatMode(), rect.y + offsetY, size.y);
/* Update the offset */
newOffsetY = ConvertPixelsToTenthsMM(dc, newOffsetY);
anchored->GetAttributes().GetTextBoxAttr().GetTop().SetValue(newOffsetY);
}
-
- // attr.m_offset = pos - rect.y;
- //anchored->SetAnchoredAttr(attr);
if (anchored->GetAttributes().GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT)
x = 0;
m_styleSheet = obj.m_styleSheet;
m_modified = obj.m_modified;
- m_batchedCommandDepth = obj.m_batchedCommandDepth;
- m_batchedCommand = obj.m_batchedCommand;
+ m_batchedCommandDepth = 0;
+ if (m_batchedCommand)
+ delete m_batchedCommand;
+ m_batchedCommand = NULL;
m_suppressUndo = obj.m_suppressUndo;
}
wxRichTextImage* imageObject = new wxRichTextImage(imageBlock, newPara);
newPara->AppendChild(imageObject);
imageObject->SetAttributes(textAttr);
- //imageObject->SetAnchoredAttr(floatAttr);
action->GetNewParagraphs().AppendChild(newPara);
action->GetNewParagraphs().UpdateRanges();
return true;
}
+/*!
+ * wxRichTextBox
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextBox, wxRichTextCompositeObject)
+
+wxRichTextBox::wxRichTextBox(wxRichTextObject* parent):
+ wxRichTextParagraphLayoutBox(parent)
+{
+}
+
+/// Draw the item
+bool wxRichTextBox::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int descent, int style)
+{
+ return wxRichTextParagraphLayoutBox::Draw(dc, range, selectionRange, rect, descent, style);
+}
+
+/// Lay the item out
+bool wxRichTextBox::Layout(wxDC& dc, const wxRect& rect, int style)
+{
+ return wxRichTextParagraphLayoutBox::Layout(dc, rect, style);
+}
+
+/// Copy
+void wxRichTextBox::Copy(const wxRichTextBox& obj)
+{
+ wxRichTextParagraphLayoutBox::Copy(obj);
+}
+
/*
* Module to initialise and clean up handlers
*/
return true;
}
-/*!
- * wxRichTextAnchoredObject implementation
- */
-IMPLEMENT_CLASS(wxRichTextAnchoredObject, wxRichTextObject)
-
-wxRichTextAnchoredObject::wxRichTextAnchoredObject(wxRichTextObject* parent, const wxRichTextAttr& attr):
- wxRichTextObject(parent)
-{
- SetAttributes(attr);
-}
-
-wxRichTextAnchoredObject::~wxRichTextAnchoredObject()
-{
-}
-
-void wxRichTextAnchoredObject::Copy(const wxRichTextAnchoredObject& obj)
-{
- wxRichTextObject::Copy(obj);
-}
-
-void wxRichTextAnchoredObject::SetParent(wxRichTextObject* parent)
-{
- wxRichTextObject::SetParent(parent);
-}
-
/*!
* wxRichTextImage implementation
* This object represents an image.
*/
-IMPLEMENT_DYNAMIC_CLASS(wxRichTextImage, wxRichTextAnchoredObject)
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextImage, wxRichTextObject)
wxRichTextImage::wxRichTextImage(const wxImage& image, wxRichTextObject* parent, wxRichTextAttr* charStyle):
- wxRichTextAnchoredObject(parent)
+ wxRichTextObject(parent)
{
m_imageBlock.MakeImageBlockDefaultQuality(image, wxBITMAP_TYPE_PNG);
if (charStyle)
}
wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichTextObject* parent, wxRichTextAttr* charStyle):
- wxRichTextAnchoredObject(parent)
+ wxRichTextObject(parent)
{
m_imageBlock = imageBlock;
if (charStyle)
int width = image.GetWidth();
int height = image.GetHeight();
-
+
if (GetAttributes().GetTextBoxAttr().GetWidth().IsPresent() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0)
{
if (GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
/// Copy
void wxRichTextImage::Copy(const wxRichTextImage& obj)
{
- wxRichTextAnchoredObject::Copy(obj);
+ wxRichTextObject::Copy(obj);
m_imageBlock = obj.m_imageBlock;
}
m_floatMode = 0;
m_clearMode = 0;
m_collapseMode = 0;
-
+
m_margins.Reset();
m_padding.Reset();
m_position.Reset();
m_floatMode == attr.m_floatMode &&
m_clearMode == attr.m_clearMode &&
m_collapseMode == attr.m_collapseMode &&
-
+
m_margins == attr.m_margins &&
m_padding == attr.m_padding &&
m_position == attr.m_position &&
m_width == attr.m_width &&
- m_height == attr.m_height &&
+ m_height == attr.m_height &&
m_border == attr.m_border &&
m_outline == attr.m_outline
if (!(compareWith && compareWith->HasCollapseBorders() && compareWith->GetCollapseBorders() == attr.GetCollapseBorders()))
SetCollapseBorders(true);
}
-
- m_margins.Apply(attr.m_margins, compareWith ? (& attr.m_margins) : (const wxTextBoxAttrDimensions*) NULL);
- m_padding.Apply(attr.m_padding, compareWith ? (& attr.m_padding) : (const wxTextBoxAttrDimensions*) NULL);
- m_position.Apply(attr.m_position, compareWith ? (& attr.m_position) : (const wxTextBoxAttrDimensions*) NULL);
+
+ m_margins.Apply(attr.m_margins, compareWith ? (& attr.m_margins) : (const wxTextAttrDimensions*) NULL);
+ m_padding.Apply(attr.m_padding, compareWith ? (& attr.m_padding) : (const wxTextAttrDimensions*) NULL);
+ m_position.Apply(attr.m_position, compareWith ? (& attr.m_position) : (const wxTextAttrDimensions*) NULL);
m_width.Apply(attr.m_width, compareWith ? (& attr.m_width) : (const wxTextAttrDimension*) NULL);
m_height.Apply(attr.m_height, compareWith ? (& attr.m_height) : (const wxTextAttrDimension*) NULL);
- m_border.Apply(attr.m_border, compareWith ? (& attr.m_border) : (const wxTextBoxAttrBorders*) NULL);
- m_outline.Apply(attr.m_outline, compareWith ? (& attr.m_outline) : (const wxTextBoxAttrBorders*) NULL);
+ m_border.Apply(attr.m_border, compareWith ? (& attr.m_border) : (const wxTextAttrBorders*) NULL);
+ m_outline.Apply(attr.m_outline, compareWith ? (& attr.m_outline) : (const wxTextAttrBorders*) NULL);
return true;
}
}
else
absentAttr.AddFlag(wxTEXT_BOX_ATTR_FLOAT);
-
+
if (attr.HasClearMode())
{
if (!clashingAttr.HasClearMode() && !absentAttr.HasClearMode())
}
else
absentAttr.AddFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS);
-
+
m_margins.CollectCommonAttributes(attr.m_margins, clashingAttr.m_margins, absentAttr.m_margins);
m_padding.CollectCommonAttributes(attr.m_padding, clashingAttr.m_padding, absentAttr.m_padding);
m_position.CollectCommonAttributes(attr.m_position, clashingAttr.m_position, absentAttr.m_position);
void wxRichTextAttr::Copy(const wxRichTextAttr& attr)
{
- wxTextAttr::Copy(attr);
-
+ wxTextAttr::Copy(attr);
+
m_textBoxAttr = attr.m_textBoxAttr;
}
{
if (!(wxTextAttr::operator==(attr)))
return false;
-
+
return (m_textBoxAttr == attr.m_textBoxAttr);
}
{
if (!(wxTextAttr::EqPartial(attr)))
return false;
-
+
return m_textBoxAttr.EqPartial(attr.m_textBoxAttr);
}
void wxRichTextAttr::CollectCommonAttributes(const wxRichTextAttr& attr, wxRichTextAttr& clashingAttr, wxRichTextAttr& absentAttr)
{
wxTextAttrCollectCommonAttributes(*this, attr, clashingAttr, absentAttr);
-
+
m_textBoxAttr.CollectCommonAttributes(attr.m_textBoxAttr, clashingAttr.m_textBoxAttr, absentAttr.m_textBoxAttr);
}
// Partial equality test
-bool wxTextBoxAttrBorder::EqPartial(const wxTextBoxAttrBorder& border) const
+bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border) const
{
if (border.HasStyle() && !HasStyle() && (border.GetStyle() != GetStyle()))
return false;
}
// Apply border to 'this', but not if the same as compareWith
-bool wxTextBoxAttrBorder::Apply(const wxTextBoxAttrBorder& border, const wxTextBoxAttrBorder* compareWith)
+bool wxTextAttrBorder::Apply(const wxTextAttrBorder& border, const wxTextAttrBorder* compareWith)
{
if (border.HasStyle())
{
}
// Remove specified attributes from this object
-bool wxTextBoxAttrBorder::RemoveStyle(const wxTextBoxAttrBorder& attr)
+bool wxTextAttrBorder::RemoveStyle(const wxTextAttrBorder& attr)
{
if (attr.HasStyle() && HasStyle())
SetFlags(GetFlags() & ~wxTEXT_BOX_ATTR_BORDER_STYLE);
// Collects the attributes that are common to a range of content, building up a note of
// which attributes are absent in some objects and which clash in some objects.
-void wxTextBoxAttrBorder::CollectCommonAttributes(const wxTextBoxAttrBorder& attr, wxTextBoxAttrBorder& clashingAttr, wxTextBoxAttrBorder& absentAttr)
+void wxTextAttrBorder::CollectCommonAttributes(const wxTextAttrBorder& attr, wxTextAttrBorder& clashingAttr, wxTextAttrBorder& absentAttr)
{
if (attr.HasStyle())
{
}
else
absentAttr.AddFlag(wxTEXT_BOX_ATTR_BORDER_COLOUR);
-
+
m_borderWidth.CollectCommonAttributes(attr.m_borderWidth, clashingAttr.m_borderWidth, absentAttr.m_borderWidth);
}
// Partial equality test
-bool wxTextBoxAttrBorders::EqPartial(const wxTextBoxAttrBorders& borders) const
+bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders) const
{
return m_left.EqPartial(borders.m_left) && m_right.EqPartial(borders.m_right) &&
m_top.EqPartial(borders.m_top) && m_bottom.EqPartial(borders.m_bottom);
}
// Apply border to 'this', but not if the same as compareWith
-bool wxTextBoxAttrBorders::Apply(const wxTextBoxAttrBorders& borders, const wxTextBoxAttrBorders* compareWith)
+bool wxTextAttrBorders::Apply(const wxTextAttrBorders& borders, const wxTextAttrBorders* compareWith)
{
- m_left.Apply(borders.m_left, compareWith ? (& compareWith->m_left) : (const wxTextBoxAttrBorder*) NULL);
- m_right.Apply(borders.m_right, compareWith ? (& compareWith->m_right) : (const wxTextBoxAttrBorder*) NULL);
- m_top.Apply(borders.m_top, compareWith ? (& compareWith->m_top) : (const wxTextBoxAttrBorder*) NULL);
- m_bottom.Apply(borders.m_bottom, compareWith ? (& compareWith->m_bottom) : (const wxTextBoxAttrBorder*) NULL);
+ m_left.Apply(borders.m_left, compareWith ? (& compareWith->m_left) : (const wxTextAttrBorder*) NULL);
+ m_right.Apply(borders.m_right, compareWith ? (& compareWith->m_right) : (const wxTextAttrBorder*) NULL);
+ m_top.Apply(borders.m_top, compareWith ? (& compareWith->m_top) : (const wxTextAttrBorder*) NULL);
+ m_bottom.Apply(borders.m_bottom, compareWith ? (& compareWith->m_bottom) : (const wxTextAttrBorder*) NULL);
return true;
}
// Remove specified attributes from this object
-bool wxTextBoxAttrBorders::RemoveStyle(const wxTextBoxAttrBorders& attr)
+bool wxTextAttrBorders::RemoveStyle(const wxTextAttrBorders& attr)
{
m_left.RemoveStyle(attr.m_left);
m_right.RemoveStyle(attr.m_right);
// Collects the attributes that are common to a range of content, building up a note of
// which attributes are absent in some objects and which clash in some objects.
-void wxTextBoxAttrBorders::CollectCommonAttributes(const wxTextBoxAttrBorders& attr, wxTextBoxAttrBorders& clashingAttr, wxTextBoxAttrBorders& absentAttr)
+void wxTextAttrBorders::CollectCommonAttributes(const wxTextAttrBorders& attr, wxTextAttrBorders& clashingAttr, wxTextAttrBorders& absentAttr)
{
m_left.CollectCommonAttributes(attr.m_left, clashingAttr.m_left, absentAttr.m_left);
m_right.CollectCommonAttributes(attr.m_right, clashingAttr.m_right, absentAttr.m_right);
}
// Set style of all borders
-void wxTextBoxAttrBorders::SetStyle(int style)
+void wxTextAttrBorders::SetStyle(int style)
{
m_left.SetStyle(style);
m_right.SetStyle(style);
}
// Set colour of all borders
-void wxTextBoxAttrBorders::SetColour(unsigned long colour)
+void wxTextAttrBorders::SetColour(unsigned long colour)
{
m_left.SetColour(colour);
m_right.SetColour(colour);
m_bottom.SetColour(colour);
}
-void wxTextBoxAttrBorders::SetColour(const wxColour& colour)
+void wxTextAttrBorders::SetColour(const wxColour& colour)
{
m_left.SetColour(colour);
m_right.SetColour(colour);
}
// Set width of all borders
-void wxTextBoxAttrBorders::SetWidth(const wxTextAttrDimension& width)
+void wxTextAttrBorders::SetWidth(const wxTextAttrDimension& width)
{
m_left.SetWidth(width);
m_right.SetWidth(width);
absentAttr.SetPresent(true);
}
+int wxTextAttrDimensionConverter::ConvertTenthsMMToPixels(int units) const
+{
+ return wxRichTextObject::ConvertTenthsMMToPixels(m_ppi, units, m_scale);
+}
+
+int wxTextAttrDimensionConverter::ConvertPixelsToTenthsMM(int pixels) const
+{
+ return wxRichTextObject::ConvertPixelsToTenthsMM(m_ppi, pixels, m_scale);
+}
+
+int wxTextAttrDimensionConverter::GetPixels(const wxTextAttrDimension& dim, int direction) const
+{
+ if (dim.GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
+ return ConvertTenthsMMToPixels(dim.GetValue());
+ else if (dim.GetUnits() == wxTEXT_ATTR_UNITS_PIXELS)
+ return dim.GetValue();
+ else if (dim.GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE)
+ {
+ wxASSERT(m_parentSize != wxDefaultSize);
+ if (direction == wxHORIZONTAL)
+ return (int) (double(m_parentSize.x) * double(dim.GetValue()) / 100.0);
+ else
+ return (int) (double(m_parentSize.y) * double(dim.GetValue()) / 100.0);
+ }
+ else
+ {
+ wxASSERT(false);
+ return 0;
+ }
+}
+
+int wxTextAttrDimensionConverter::GetTenthsMM(const wxTextAttrDimension& dim) const
+{
+ if (dim.GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM)
+ return dim.GetValue();
+ else if (dim.GetUnits() == wxTEXT_ATTR_UNITS_PIXELS)
+ return ConvertPixelsToTenthsMM(dim.GetValue());
+ else
+ {
+ wxASSERT(false);
+ return 0;
+ }
+}
+
// Partial equality test
-bool wxTextBoxAttrDimensions::EqPartial(const wxTextBoxAttrDimensions& dims) const
+bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims) const
{
if (!m_left.EqPartial(dims.m_left))
return false;
}
// Apply border to 'this', but not if the same as compareWith
-bool wxTextBoxAttrDimensions::Apply(const wxTextBoxAttrDimensions& dims, const wxTextBoxAttrDimensions* compareWith)
+bool wxTextAttrDimensions::Apply(const wxTextAttrDimensions& dims, const wxTextAttrDimensions* compareWith)
{
m_left.Apply(dims.m_left, compareWith ? (& compareWith->m_left) : (const wxTextAttrDimension*) NULL);
m_right.Apply(dims.m_right, compareWith ? (& compareWith->m_right): (const wxTextAttrDimension*) NULL);
}
// Remove specified attributes from this object
-bool wxTextBoxAttrDimensions::RemoveStyle(const wxTextBoxAttrDimensions& attr)
+bool wxTextAttrDimensions::RemoveStyle(const wxTextAttrDimensions& attr)
{
if (attr.m_left.IsPresent())
m_left.Reset();
// Collects the attributes that are common to a range of content, building up a note of
// which attributes are absent in some objects and which clash in some objects.
-void wxTextBoxAttrDimensions::CollectCommonAttributes(const wxTextBoxAttrDimensions& attr, wxTextBoxAttrDimensions& clashingAttr, wxTextBoxAttrDimensions& absentAttr)
+void wxTextAttrDimensions::CollectCommonAttributes(const wxTextAttrDimensions& attr, wxTextAttrDimensions& clashingAttr, wxTextAttrDimensions& absentAttr)
{
m_left.CollectCommonAttributes(attr.m_left, clashingAttr.m_left, absentAttr.m_left);
m_right.CollectCommonAttributes(attr.m_right, clashingAttr.m_right, absentAttr.m_right);
}
}
+WX_DEFINE_OBJARRAY(wxRichTextVariantArray);
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties, wxObject)
+
+bool wxRichTextProperties::operator==(const wxRichTextProperties& props) const
+{
+ if (m_properties.GetCount() != props.GetCount())
+ return false;
+
+ size_t i;
+ for (i = 0; i < m_properties.GetCount(); i++)
+ {
+ const wxVariant& var1 = m_properties[i];
+ int idx = props.Find(var1.GetName());
+ if (idx == -1)
+ return false;
+ const wxVariant& var2 = props.m_properties[idx];
+ if (!(var1 == var2))
+ return false;
+ }
+
+ return true;
+}
+
+wxArrayString wxRichTextProperties::GetPropertyNames() const
+{
+ wxArrayString arr;
+ size_t i;
+ for (i = 0; i < m_properties.GetCount(); i++)
+ {
+ arr.Add(m_properties[i].GetName());
+ }
+ return arr;
+}
+
+int wxRichTextProperties::Find(const wxString& name) const
+{
+ size_t i;
+ for (i = 0; i < m_properties.GetCount(); i++)
+ {
+ if (m_properties[i].GetName() == name)
+ return (int) i;
+ }
+ return -1;
+}
+
+wxVariant* wxRichTextProperties::FindOrCreateProperty(const wxString& name)
+{
+ int idx = Find(name);
+ if (idx == wxNOT_FOUND)
+ SetProperty(name, wxString());
+ idx = Find(name);
+ if (idx != wxNOT_FOUND)
+ {
+ return & (*this)[idx];
+ }
+ else
+ return NULL;
+}
+
+const wxVariant& wxRichTextProperties::GetProperty(const wxString& name) const
+{
+ static const wxVariant nullVariant;
+ int idx = Find(name);
+ if (idx != -1)
+ return m_properties[idx];
+ else
+ return nullVariant;
+}
+
+wxString wxRichTextProperties::GetPropertyString(const wxString& name) const
+{
+ return GetProperty(name).GetString();
+}
+
+long wxRichTextProperties::GetPropertyLong(const wxString& name) const
+{
+ return GetProperty(name).GetLong();
+}
+
+bool wxRichTextProperties::GetPropertyBool(const wxString& name) const
+{
+ return GetProperty(name).GetBool();
+}
+
+double wxRichTextProperties::GetPropertyDouble(const wxString& name) const
+{
+ return GetProperty(name).GetDouble();
+}
+
+void wxRichTextProperties::SetProperty(const wxVariant& variant)
+{
+ wxASSERT(!variant.GetName().IsEmpty());
+
+ int idx = Find(variant.GetName());
+
+ if (idx == -1)
+ m_properties.Add(variant);
+ else
+ m_properties[idx] = variant;
+}
+
+void wxRichTextProperties::SetProperty(const wxString& name, const wxVariant& variant)
+{
+ int idx = Find(name);
+ wxVariant var(variant);
+ var.SetName(name);
+
+ if (idx == -1)
+ m_properties.Add(var);
+ else
+ m_properties[idx] = var;
+}
+
+void wxRichTextProperties::SetProperty(const wxString& name, const wxString& value)
+{
+ SetProperty(name, wxVariant(value, name));
+}
+
+void wxRichTextProperties::SetProperty(const wxString& name, long value)
+{
+ SetProperty(name, wxVariant(value, name));
+}
+
+void wxRichTextProperties::SetProperty(const wxString& name, double value)
+{
+ SetProperty(name, wxVariant(value, name));
+}
+
+void wxRichTextProperties::SetProperty(const wxString& name, bool value)
+{
+ SetProperty(name, wxVariant(value, name));
+}
#endif
// wxUSE_RICHTEXT
#include "wx/wfstream.h"
#include "wx/sstream.h"
#include "wx/txtstrm.h"
+#include "wx/mstream.h"
#include "wx/tokenzr.h"
+#include "wx/stopwatch.h"
#include "wx/xml/xml.h"
+// Set to 1 for slower wxXmlDocument method, 0 for faster direct method.
+// If we make wxXmlDocument::Save more efficient, we might switch to this
+// method.
+#define wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT 0
+
+#if wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT && !wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+# error Must define wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT in richtextxml.h to use this method.
+#endif
+
+#if !wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT && !wxRICHTEXT_HAVE_DIRECT_OUTPUT
+# error Must define wxRICHTEXT_HAVE_DIRECT_OUTPUT in richtextxml.h to use this method.
+#endif
+
+// Set to 1 to time file saving
+#define wxRICHTEXT_USE_OUTPUT_TIMINGS 0
+
+// Convert a colour to a 6-digit hex string
+static wxString ColourToHexString(const wxColour& col)
+{
+ wxString hex;
+
+ hex += wxDecToHex(col.Red());
+ hex += wxDecToHex(col.Green());
+ hex += wxDecToHex(col.Blue());
+
+ return hex;
+}
+
+// Convert 6-digit hex string to a colour
+static wxColour HexStringToColour(const wxString& hex)
+{
+ unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2));
+ unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2));
+ unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2));
+
+ return wxColour(r, g, b);
+}
+
+static inline wxString MakeString(const int& v) { return wxString::Format(wxT("%d"), v); }
+static inline wxString MakeString(const long& v) { return wxString::Format(wxT("%ld"), v); }
+static inline wxString MakeString(const double& v) { return wxString::Format(wxT("%.2f"), (float) v); }
+static inline wxString MakeString(const wxString& s) { return s; }
+static inline wxString MakeString(const wxColour& col) { return wxT("#") + ColourToHexString(col); }
+
+static inline void AddString(wxString& str, const int& v) { str << wxString::Format(wxT("%d"), v); }
+static inline void AddString(wxString& str, const long& v) { str << wxString::Format(wxT("%ld"), v); }
+static inline void AddString(wxString& str, const double& v) { str << wxString::Format(wxT("%.2f"), (float) v); }
+static inline void AddString(wxString& str, const wxChar* s) { str << s; }
+static inline void AddString(wxString& str, const wxString& s) { str << s; }
+static inline void AddString(wxString& str, const wxColour& col) { str << wxT("#") << ColourToHexString(col); }
+
IMPLEMENT_DYNAMIC_CLASS(wxRichTextXMLHandler, wxRichTextFileHandler)
+void wxRichTextXMLHandler::Init()
+{
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+ // Used during saving
+ m_convMem = NULL;
+ m_convFile = NULL;
+#endif
+}
+
#if wxUSE_STREAMS
bool wxRichTextXMLHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
{
{
}
else
- ImportXML(buffer, child);
+ ImportXML(buffer, buffer, child);
}
child = child->GetNext();
return success;
}
-/// Recursively import an object
-bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxXmlNode* node)
+/// Creates an object given an XML element name
+wxRichTextObject* wxRichTextXMLHandler::CreateObjectForXMLName(wxRichTextObject* WXUNUSED(parent), const wxString& name) const
{
- wxString name = node->GetName();
-
- bool doneChildren = false;
-
- if (name == wxT("paragraphlayout"))
- {
- wxString partial = node->GetAttribute(wxT("partialparagraph"), wxEmptyString);
- if (partial == wxT("true"))
- buffer->SetPartialParagraph(true);
- }
+ if (name == wxT("text") || name == wxT("symbol"))
+ return new wxRichTextPlainText;
+ else if (name == wxT("image"))
+ return new wxRichTextImage;
else if (name == wxT("paragraph"))
- {
- wxRichTextParagraph* para = new wxRichTextParagraph(buffer);
- buffer->AppendChild(para);
-
- GetStyle(para->GetAttributes(), node, true);
+ return new wxRichTextParagraph;
+ else if (name == wxT("paragraphlayout"))
+ return new wxRichTextParagraphLayoutBox;
+ else
+ return NULL;
+}
+/// Recursively import an object
+bool wxRichTextXMLHandler::ImportXML(wxRichTextBuffer* buffer, wxRichTextObject* obj, wxXmlNode* node)
+{
+ obj->ImportFromXML(buffer, node, this);
+
+ wxRichTextCompositeObject* compositeParent = wxDynamicCast(obj, wxRichTextCompositeObject);
+ if (compositeParent)
+ {
wxXmlNode* child = node->GetChildren();
while (child)
{
- wxString childName = child->GetName();
- if (childName == wxT("text"))
+ if (child->GetName() == wxT("stylesheet"))
{
- wxString text;
- wxXmlNode* textChild = child->GetChildren();
- while (textChild)
+ if (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)
{
- if (textChild->GetType() == wxXML_TEXT_NODE ||
- textChild->GetType() == wxXML_CDATA_SECTION_NODE)
+ wxRichTextStyleSheet* sheet = new wxRichTextStyleSheet;
+ wxString sheetName = child->GetAttribute(wxT("name"), wxEmptyString);
+ wxString sheetDescription = child->GetAttribute(wxT("description"), wxEmptyString);
+ sheet->SetName(sheetName);
+ sheet->SetDescription(sheetDescription);
+
+ wxXmlNode* child2 = child->GetChildren();
+ while (child2)
{
- wxString text2 = textChild->GetContent();
-
- // Strip whitespace from end
- if (!text2.empty() && text2[text2.length()-1] == wxT('\n'))
- text2 = text2.Mid(0, text2.length()-1);
-
- if (!text2.empty() && text2[0] == wxT('"'))
- text2 = text2.Mid(1);
- if (!text2.empty() && text2[text2.length()-1] == wxT('"'))
- text2 = text2.Mid(0, text2.length() - 1);
+ ImportStyleDefinition(sheet, child2);
- text += text2;
+ child2 = child2->GetNext();
}
- textChild = textChild->GetNext();
- }
-
- wxRichTextPlainText* textObject = new wxRichTextPlainText(text, para);
- GetStyle(textObject->GetAttributes(), child, false);
- para->AppendChild(textObject);
- }
- else if (childName == wxT("symbol"))
- {
- // This is a symbol that XML can't read in the normal way
- wxString text;
- wxXmlNode* textChild = child->GetChildren();
- while (textChild)
- {
- if (textChild->GetType() == wxXML_TEXT_NODE ||
- textChild->GetType() == wxXML_CDATA_SECTION_NODE)
- {
- wxString text2 = textChild->GetContent();
- text += text2;
- }
- textChild = textChild->GetNext();
+ // Notify that styles have changed. If this is vetoed by the app,
+ // the new sheet will be deleted. If it is not vetoed, the
+ // old sheet will be deleted and replaced with the new one.
+ buffer->SetStyleSheetAndNotify(sheet);
}
-
- wxString actualText;
- actualText << (wxChar) wxAtoi(text);
-
- wxRichTextPlainText* textObject = new wxRichTextPlainText(actualText, para);
- GetStyle(textObject->GetAttributes(), child, false);
-
- para->AppendChild(textObject);
}
- else if (childName == wxT("image"))
+ else
{
- wxBitmapType imageType = wxBITMAP_TYPE_PNG;
- wxString value = child->GetAttribute(wxT("imagetype"), wxEmptyString);
- if (!value.empty())
- {
- int type = wxAtoi(value);
-
- // note: 0 == wxBITMAP_TYPE_INVALID
- if (type <= 0 || type >= wxBITMAP_TYPE_MAX)
- {
- wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type);
- }
- else
- {
- imageType = (wxBitmapType)type;
- }
- }
-
- wxString data;
-
- wxXmlNode* imageChild = child->GetChildren();
- while (imageChild)
- {
- wxString childName = imageChild->GetName();
- if (childName == wxT("data"))
- {
- wxXmlNode* dataChild = imageChild->GetChildren();
- while (dataChild)
- {
- data = dataChild->GetContent();
- // wxLogDebug(data);
- dataChild = dataChild->GetNext();
- }
-
- }
- imageChild = imageChild->GetNext();
- }
-
- if (!data.empty())
+ wxRichTextObject* childObj = CreateObjectForXMLName(obj, child->GetName());
+ if (childObj)
{
- wxRichTextImage* imageObj = new wxRichTextImage(para);
- GetStyle(imageObj->GetAttributes(), child, false);
- para->AppendChild(imageObj);
-
- wxStringInputStream strStream(data);
-
- imageObj->GetImageBlock().ReadHex(strStream, data.length(), imageType);
+ compositeParent->AppendChild(childObj);
+ ImportXML(buffer, childObj, child);
}
}
child = child->GetNext();
}
-
- doneChildren = true;
}
- else if (name == wxT("stylesheet"))
- {
- if (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET)
- {
- wxRichTextStyleSheet* sheet = new wxRichTextStyleSheet;
- wxString sheetName = node->GetAttribute(wxT("name"), wxEmptyString);
- wxString sheetDescription = node->GetAttribute(wxT("description"), wxEmptyString);
- sheet->SetName(sheetName);
- sheet->SetDescription(sheetDescription);
-
- wxXmlNode* child = node->GetChildren();
- while (child)
- {
- ImportStyleDefinition(sheet, child);
- child = child->GetNext();
- }
-
- // Notify that styles have changed. If this is vetoed by the app,
- // the new sheet will be deleted. If it is not vetoed, the
- // old sheet will be deleted and replaced with the new one.
- buffer->SetStyleSheetAndNotify(sheet);
- }
- doneChildren = true;
- }
+ return true;
+}
- if (!doneChildren)
+bool wxRichTextXMLHandler::ImportProperties(wxRichTextObject* obj, wxXmlNode* node)
+{
+ wxXmlNode* child = node->GetChildren();
+ while (child)
{
- wxXmlNode* child = node->GetChildren();
- while (child)
+ if (child->GetName() == wxT("properties"))
{
- ImportXML(buffer, child);
- child = child->GetNext();
+ wxXmlNode* propertyChild = child->GetChildren();
+ while (propertyChild)
+ {
+ if (propertyChild->GetName() == wxT("property"))
+ {
+ wxString name = propertyChild->GetAttribute(wxT("name"), wxEmptyString);
+ wxString value = propertyChild->GetAttribute(wxT("value"), wxEmptyString);
+ wxString type = propertyChild->GetAttribute(wxT("type"), wxEmptyString);
+
+ wxVariant var = MakePropertyFromString(name, value, type);
+ if (!var.IsNull())
+ {
+ obj->GetProperties().SetProperty(var);
+ }
+ }
+ propertyChild = propertyChild->GetNext();
+ }
}
+ child = child->GetNext();
}
-
return true;
}
wxString styleName = node->GetAttribute(wxT("name"), wxEmptyString);
wxString baseStyleName = node->GetAttribute(wxT("basestyle"), wxEmptyString);
- if (styleName.IsEmpty())
+ if (styleName.empty())
return false;
if (styleType == wxT("characterstyle"))
if (child->GetName() == wxT("style"))
{
wxRichTextAttr attr;
- GetStyle(attr, child, false);
+ ImportStyle(attr, child, false);
def->SetStyle(attr);
}
child = child->GetNext();
if (child->GetName() == wxT("style"))
{
wxRichTextAttr attr;
- GetStyle(attr, child, false);
+ ImportStyle(attr, child, true);
def->SetStyle(attr);
}
child = child->GetNext();
if (child->GetName() == wxT("style"))
{
wxRichTextAttr attr;
- GetStyle(attr, child, false);
+ ImportStyle(attr, child, true);
wxString styleLevel = child->GetAttribute(wxT("level"), wxEmptyString);
- if (styleLevel.IsEmpty())
+ if (styleLevel.empty())
{
def->SetStyle(attr);
}
#endif
#endif
-// write string to output:
+// write string to output
inline static void OutputString(wxOutputStream& stream, const wxString& str,
- wxMBConv *WXUNUSED_IN_UNICODE(convMem) = NULL, wxMBConv *convFile = NULL)
+ wxMBConv *WXUNUSED_IN_UNICODE(convMem), wxMBConv *convFile)
{
if (str.empty()) return;
#if wxUSE_UNICODE
#endif
}
+static void OutputIndentation(wxOutputStream& stream, int indent)
+{
+ wxString str = wxT("\n");
+ for (int i = 0; i < indent; i++)
+ str << wxT(' ') << wxT(' ');
+ ::OutputString(stream, str, NULL, NULL);
+}
+
// Same as above, but create entities first.
// Translates '<' to "<", '>' to ">" and '&' to "&"
static void OutputStringEnt(wxOutputStream& stream, const wxString& str,
OutputString(stream, str.Mid(last, i - last), convMem, convFile);
}
-static wxString AttributeToXML(const wxString& str)
+void wxRichTextXMLHandler::OutputString(wxOutputStream& stream, const wxString& str)
+{
+ ::OutputString(stream, str, m_convMem, m_convFile);
+}
+
+void wxRichTextXMLHandler::OutputStringEnt(wxOutputStream& stream, const wxString& str)
+{
+ ::OutputStringEnt(stream, str, m_convMem, m_convFile);
+}
+
+void wxRichTextXMLHandler::OutputIndentation(wxOutputStream& stream, int indent)
+{
+ wxString str = wxT("\n");
+ for (int i = 0; i < indent; i++)
+ str << wxT(' ') << wxT(' ');
+ ::OutputString(stream, str, NULL, NULL);
+}
+
+wxString wxRichTextXMLHandler::AttributeToXML(const wxString& str)
{
wxString str1;
size_t i, last, len;
return str1;
}
-inline static void OutputIndentation(wxOutputStream& stream, int indent)
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+
+static inline void AddAttribute(wxString& str, const wxChar* name, const int& v)
{
- wxString str = wxT("\n");
- for (int i = 0; i < indent; i++)
- str << wxT(' ') << wxT(' ');
- OutputString(stream, str, NULL, NULL);
+ str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%d"), v) << wxT("\"");
}
-// Convert a colour to a 6-digit hex string
-static wxString ColourToHexString(const wxColour& col)
+static inline void AddAttribute(wxString& str, const wxChar* name, const long& v)
{
- wxString hex;
+ str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%ld"), v) << wxT("\"");
+}
- hex += wxDecToHex(col.Red());
- hex += wxDecToHex(col.Green());
- hex += wxDecToHex(col.Blue());
+static inline void AddAttribute(wxString& str, const wxChar* name, const double& v)
+{
+ str << wxT(" ") << name << wxT("=\"") << wxString::Format(wxT("%.2f"), (float) v) << wxT("\"");
+}
- return hex;
+static inline void AddAttribute(wxString& str, const wxChar* name, const wxChar* s)
+{
+ str << wxT(" ") << name << wxT("=\"") << s << wxT("\"");
}
-// Convert 6-digit hex string to a colour
-static wxColour HexStringToColour(const wxString& hex)
+static inline void AddAttribute(wxString& str, const wxChar* name, const wxString& s)
{
- unsigned char r = (unsigned char)wxHexToDec(hex.Mid(0, 2));
- unsigned char g = (unsigned char)wxHexToDec(hex.Mid(2, 2));
- unsigned char b = (unsigned char)wxHexToDec(hex.Mid(4, 2));
+ str << wxT(" ") << name << wxT("=\"") << s << wxT("\"");
+}
- return wxColour(r, g, b);
+static inline void AddAttribute(wxString& str, const wxChar* name, const wxColour& col)
+{
+ str << wxT(" ") << name << wxT("=\"") << wxT("#") << ColourToHexString(col) << wxT("\"");
+}
+
+static inline void AddAttribute(wxString& str, const wxChar* name, const wxTextAttrDimension& dim)
+{
+ if (dim.IsPresent())
+ {
+ wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString((int) dim.GetFlags());
+ str << wxT(" ") << name << wxT("=\"");
+ str << value;
+ str << wxT("\"");
+ }
+}
+
+static inline void AddAttribute(wxString& str, const wxChar* rootName, const wxTextAttrDimensions& dims)
+{
+ if (dims.GetLeft().IsPresent())
+ AddAttribute(str, rootName + wxString(wxT("-left")), dims.GetLeft());
+ if (dims.GetRight().IsPresent())
+ AddAttribute(str, rootName + wxString(wxT("-right")), dims.GetRight());
+ if (dims.GetTop().IsPresent())
+ AddAttribute(str, rootName + wxString(wxT("-top")), dims.GetTop());
+ if (dims.GetBottom().IsPresent())
+ AddAttribute(str, rootName + wxString(wxT("-bottom")), dims.GetBottom());
+}
+
+static inline void AddAttribute(wxString& str, const wxChar* rootName, const wxTextAttrBorder& border)
+{
+ if (border.HasStyle())
+ AddAttribute(str, rootName + wxString(wxT("-style")), border.GetStyle());
+ if (border.HasColour())
+ AddAttribute(str, rootName + wxString(wxT("-color")), border.GetColour());
+ if (border.HasWidth())
+ AddAttribute(str, rootName + wxString(wxT("-width")), border.GetWidth());
+}
+
+static inline void AddAttribute(wxString& str, const wxChar* rootName, const wxTextAttrBorders& borders)
+{
+ AddAttribute(str, rootName + wxString(wxT("-left")), borders.GetLeft());
+ AddAttribute(str, rootName + wxString(wxT("-right")), borders.GetRight());
+ AddAttribute(str, rootName + wxString(wxT("-top")), borders.GetTop());
+ AddAttribute(str, rootName + wxString(wxT("-bottom")), borders.GetBottom());
+}
+
+#endif
+ // wxRICHTEXT_HAVE_DIRECT_OUTPUT
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* name, const int& v)
+{
+ node->AddAttribute(name, MakeString(v));
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* name, const long& v)
+{
+ node->AddAttribute(name, MakeString(v));
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* name, const double& v)
+{
+ node->AddAttribute(name, MakeString(v));
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* name, const wxString& s)
+{
+ node->AddAttribute(name, s);
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* name, const wxColour& col)
+{
+ node->AddAttribute(name, MakeString(col));
}
+static inline void AddAttribute(wxXmlNode* node, const wxChar* name, const wxTextAttrDimension& dim)
+{
+ if (dim.IsPresent())
+ {
+ wxString value = MakeString(dim.GetValue()) + wxT(",") + MakeString(dim.GetFlags());
+ AddAttribute(node, name, value);
+ }
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* rootName, const wxTextAttrDimensions& dims)
+{
+ if (dims.GetLeft().IsPresent())
+ AddAttribute(node, rootName + wxString(wxT("-left")), dims.GetLeft());
+ if (dims.GetRight().IsPresent())
+ AddAttribute(node, rootName + wxString(wxT("-right")), dims.GetRight());
+ if (dims.GetTop().IsPresent())
+ AddAttribute(node, rootName + wxString(wxT("-top")), dims.GetTop());
+ if (dims.GetBottom().IsPresent())
+ AddAttribute(node, rootName + wxString(wxT("-bottom")), dims.GetBottom());
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* rootName, const wxTextAttrBorder& border)
+{
+ if (border.HasStyle())
+ AddAttribute(node, rootName + wxString(wxT("-style")), border.GetStyle());
+ if (border.HasColour())
+ AddAttribute(node, rootName + wxString(wxT("-color")), border.GetColour());
+ if (border.HasWidth())
+ AddAttribute(node, rootName + wxString(wxT("-width")), border.GetWidth());
+}
+
+static inline void AddAttribute(wxXmlNode* node, const wxChar* rootName, const wxTextAttrBorders& borders)
+{
+ AddAttribute(node, rootName + wxString(wxT("-left")), borders.GetLeft());
+ AddAttribute(node, rootName + wxString(wxT("-right")), borders.GetRight());
+ AddAttribute(node, rootName + wxString(wxT("-top")), borders.GetTop());
+ AddAttribute(node, rootName + wxString(wxT("-bottom")), borders.GetBottom());
+}
+#endif
+ // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+
bool wxRichTextXMLHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
{
if (!stream.IsOk())
return false;
wxString version(wxT("1.0") ) ;
-
+
bool deleteConvFile = false;
wxString fileEncoding;
- wxMBConv* convFile = NULL;
+ //wxMBConv* convFile = NULL;
#if wxUSE_UNICODE
fileEncoding = wxT("UTF-8");
- convFile = & wxConvUTF8;
+ m_convFile = & wxConvUTF8;
#else
fileEncoding = wxT("ISO-8859-1");
- convFile = & wxConvISO8859_1;
+ m_convFile = & wxConvISO8859_1;
#endif
// If SetEncoding has been called, change the output encoding.
#else
fileEncoding = wxT("ISO-8859-1");
#endif
- convFile = new wxCSConv(fileEncoding);
+ m_convFile = new wxCSConv(fileEncoding);
deleteConvFile = true;
}
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT
+#if wxRICHTEXT_USE_OUTPUT_TIMINGS
+ wxStopWatch stopwatch;
+#endif
+ wxXmlDocument* doc = new wxXmlDocument;
+ doc->SetFileEncoding(fileEncoding);
+
+ wxXmlNode* rootNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("richtext"));
+ doc->SetRoot(rootNode);
+ rootNode->AddAttribute(wxT("version"), wxT("1.0.0.0"));
+ rootNode->AddAttribute(wxT("xmlns"), wxT("http://www.wxwidgets.org"));
+
+ if (buffer->GetStyleSheet() && (GetFlags() & wxRICHTEXT_HANDLER_INCLUDE_STYLESHEET))
+ {
+ wxXmlNode* styleSheetNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("stylesheet"));
+ rootNode->AddChild(styleSheetNode);
+
+ wxString nameAndDescr;
+
+ if (!buffer->GetStyleSheet()->GetName().empty())
+ styleSheetNode->AddAttribute(wxT("name"), buffer->GetStyleSheet()->GetName());
+
+ if (!buffer->GetStyleSheet()->GetDescription().empty())
+ styleSheetNode->AddAttribute(wxT("description"), buffer->GetStyleSheet()->GetDescription());
+
+ int i;
+ for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++)
+ {
+ wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i);
+ ExportStyleDefinition(styleSheetNode, def);
+ }
+
+ for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++)
+ {
+ wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i);
+ ExportStyleDefinition(styleSheetNode, def);
+ }
+
+ for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++)
+ {
+ wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i);
+ ExportStyleDefinition(styleSheetNode, def);
+ }
+ }
+ bool success = ExportXML(rootNode, *buffer);
+#if wxRICHTEXT_USE_OUTPUT_TIMINGS
+ long t = stopwatch.Time();
+ wxLogDebug(wxT("Creating the document took %ldms"), t);
+ wxMessageBox(wxString::Format(wxT("Creating the document took %ldms"), t));
+#endif
+ if (success)
+ {
+#if wxRICHTEXT_USE_OUTPUT_TIMINGS
+ wxStopWatch s2;
+#endif
+ success = doc->Save(stream);
+#if wxRICHTEXT_USE_OUTPUT_TIMINGS
+ long t2 = s2.Time();
+ wxLogDebug(wxT("Save() took %ldms"), t2);
+ wxMessageBox(wxString::Format(wxT("Save() took %ldms"), t2));
+#endif
+ }
+ delete doc;
+ doc = NULL;
+
+#else
+ // !(wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT && wxRICHTEXT_USE_XMLDOCUMENT_OUTPUT)
+
#if !wxUSE_UNICODE
- wxMBConv* convMem = wxConvCurrent;
+ m_convMem = wxConvCurrent;
#else
- wxMBConv* convMem = NULL;
+ m_convMem = NULL;
#endif
wxString s ;
s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
version, fileEncoding);
- OutputString(stream, s, NULL, NULL);
- OutputString(stream, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">") , NULL, NULL);
+ OutputString(stream, s);
+ OutputString(stream, wxT("<richtext version=\"1.0.0.0\" xmlns=\"http://www.wxwidgets.org\">"));
int level = 1;
{
OutputIndentation(stream, level);
wxString nameAndDescr;
- if (!buffer->GetStyleSheet()->GetName().IsEmpty())
+ if (!buffer->GetStyleSheet()->GetName().empty())
nameAndDescr << wxT(" name=\"") << buffer->GetStyleSheet()->GetName() << wxT("\"");
- if (!buffer->GetStyleSheet()->GetDescription().IsEmpty())
+ if (!buffer->GetStyleSheet()->GetDescription().empty())
nameAndDescr << wxT(" description=\"") << buffer->GetStyleSheet()->GetDescription() << wxT("\"");
- OutputString(stream, wxString(wxT("<stylesheet")) + nameAndDescr + wxT(">"), convMem, convFile);
+ OutputString(stream, wxString(wxT("<stylesheet")) + nameAndDescr + wxT(">"));
int i;
for (i = 0; i < (int) buffer->GetStyleSheet()->GetCharacterStyleCount(); i++)
{
wxRichTextCharacterStyleDefinition* def = buffer->GetStyleSheet()->GetCharacterStyle(i);
- ExportStyleDefinition(stream, convMem, convFile, def, level + 1);
+ ExportStyleDefinition(stream, def, level + 1);
}
for (i = 0; i < (int) buffer->GetStyleSheet()->GetParagraphStyleCount(); i++)
{
wxRichTextParagraphStyleDefinition* def = buffer->GetStyleSheet()->GetParagraphStyle(i);
- ExportStyleDefinition(stream, convMem, convFile, def, level + 1);
+ ExportStyleDefinition(stream, def, level + 1);
}
for (i = 0; i < (int) buffer->GetStyleSheet()->GetListStyleCount(); i++)
{
wxRichTextListStyleDefinition* def = buffer->GetStyleSheet()->GetListStyle(i);
- ExportStyleDefinition(stream, convMem, convFile, def, level + 1);
+ ExportStyleDefinition(stream, def, level + 1);
}
OutputIndentation(stream, level);
- OutputString(stream, wxT("</stylesheet>"), convMem, convFile);
+ OutputString(stream, wxT("</stylesheet>"));
}
- bool success = ExportXML(stream, convMem, convFile, *buffer, level);
+ bool success = ExportXML(stream, *buffer, level);
- OutputString(stream, wxT("\n</richtext>") , NULL, NULL);
- OutputString(stream, wxT("\n"), NULL, NULL);
+ OutputString(stream, wxT("\n</richtext>"));
+ OutputString(stream, wxT("\n"));
if (deleteConvFile)
- delete convFile;
+ delete m_convFile;
+ m_convFile = NULL;
+ m_convMem = NULL;
+#endif
return success;
}
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+
/// Recursively export an object
-bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextObject& obj, int indent)
-{
- wxString objectName;
- if (obj.IsKindOf(CLASSINFO(wxRichTextParagraphLayoutBox)))
- objectName = wxT("paragraphlayout");
- else if (obj.IsKindOf(CLASSINFO(wxRichTextParagraph)))
- objectName = wxT("paragraph");
- else if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
- objectName = wxT("text");
- else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
- objectName = wxT("image");
- else
- objectName = wxT("object");
+bool wxRichTextXMLHandler::ExportXML(wxOutputStream& stream, wxRichTextObject& obj, int indent)
+{
+ obj.ExportXML(stream, indent, this);
- bool terminateTag = true;
+ return true;
+}
- if (obj.IsKindOf(CLASSINFO(wxRichTextPlainText)))
- {
- wxRichTextPlainText& textObj = (wxRichTextPlainText&) obj;
+bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream& stream, wxRichTextStyleDefinition* def, int level)
+{
+ wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
+ wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
+ wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
- wxString style = CreateStyle(obj.GetAttributes(), false);
+ wxString baseStyle = def->GetBaseStyle();
+ wxString baseStyleProp;
+ if (!baseStyle.empty())
+ baseStyleProp = wxT(" basestyle=\"") + baseStyle + wxT("\"");
- int i;
- int last = 0;
- const wxString& text = textObj.GetText();
- int len = (int) text.Length();
+ wxString descr = def->GetDescription();
+ wxString descrProp;
+ if (!descr.empty())
+ descrProp = wxT(" description=\"") + descr + wxT("\"");
- if (len == 0)
- {
- i = 0;
- OutputIndentation(stream, indent);
- OutputString(stream, wxT("<") + objectName, convMem, convFile);
- OutputString(stream, style + wxT(">"), convMem, convFile);
- OutputString(stream, wxT("</text>"), convMem, convFile);
- }
- else for (i = 0; i < len; i++)
- {
-#if wxUSE_UNICODE
- int c = (int) text[i];
-#else
- int c = (int) wxUChar(text[i]);
-#endif
- if ((c < 32 || c == 34) && /* c != 9 && */ c != 10 && c != 13)
- {
- if (i > 0)
- {
- wxString fragment(text.Mid(last, i-last));
- if (!fragment.IsEmpty())
- {
- OutputIndentation(stream, indent);
- OutputString(stream, wxT("<") + objectName, convMem, convFile);
+ if (charDef)
+ {
+ OutputIndentation(stream, level);
+ OutputString(stream, wxT("<characterstyle") + baseStyleProp + descrProp + wxT(">"));
- OutputString(stream, style + wxT(">"), convMem, convFile);
+ level ++;
- if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
- {
- OutputString(stream, wxT("\""), convMem, convFile);
- OutputStringEnt(stream, fragment, convMem, convFile);
- OutputString(stream, wxT("\""), convMem, convFile);
- }
- else
- OutputStringEnt(stream, fragment, convMem, convFile);
-
- OutputString(stream, wxT("</text>"), convMem, convFile);
- }
- }
-
-
- // Output this character as a number in a separate tag, because XML can't cope
- // with entities below 32 except for 10 and 13
- last = i + 1;
- OutputIndentation(stream, indent);
- OutputString(stream, wxT("<symbol"), convMem, convFile);
-
- OutputString(stream, style + wxT(">"), convMem, convFile);
- OutputString(stream, wxString::Format(wxT("%d"), c), convMem, convFile);
-
- OutputString(stream, wxT("</symbol>"), convMem, convFile);
- }
- }
-
- wxString fragment;
- if (last == 0)
- fragment = text;
- else
- fragment = text.Mid(last, i-last);
-
- if (last < len)
- {
- OutputIndentation(stream, indent);
- OutputString(stream, wxT("<") + objectName, convMem, convFile);
-
- OutputString(stream, style + wxT(">"), convMem, convFile);
-
- if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
- {
- OutputString(stream, wxT("\""), convMem, convFile);
- OutputStringEnt(stream, fragment, convMem, convFile);
- OutputString(stream, wxT("\""), convMem, convFile);
- }
- else
- OutputStringEnt(stream, fragment, convMem, convFile);
- }
- else
- terminateTag = false;
- }
- else if (obj.IsKindOf(CLASSINFO(wxRichTextImage)))
- {
- wxRichTextImage& imageObj = (wxRichTextImage&) obj;
-
- wxString style = CreateStyle(obj.GetAttributes(), false);
-
- //if (imageObj.GetImage().Ok() && !imageObj.GetImageBlock().Ok())
- // imageObj.MakeBlock();
-
- OutputIndentation(stream, indent);
- OutputString(stream, wxT("<") + objectName, convMem, convFile);
- if (!imageObj.GetImageBlock().Ok())
- {
- // No data
- OutputString(stream, style + wxT(">"), convMem, convFile);
- }
- else
- {
- OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\""), (int) imageObj.GetImageBlock().GetImageType()) + style + wxT(">"));
- }
-
- OutputIndentation(stream, indent+1);
- OutputString(stream, wxT("<data>"), convMem, convFile);
-
- imageObj.GetImageBlock().WriteHex(stream);
-
- OutputString(stream, wxT("</data>"), convMem, convFile);
- }
- else if (obj.IsKindOf(CLASSINFO(wxRichTextCompositeObject)))
- {
- OutputIndentation(stream, indent);
- OutputString(stream, wxT("<") + objectName, convMem, convFile);
-
- bool isPara = false;
- if (objectName == wxT("paragraph") || objectName == wxT("paragraphlayout"))
- isPara = true;
-
- wxString style = CreateStyle(obj.GetAttributes(), isPara);
-
- if (objectName == wxT("paragraphlayout") && ((wxRichTextParagraphLayoutBox&) obj).GetPartialParagraph())
- style << wxT(" partialparagraph=\"true\"");
-
- OutputString(stream, style + wxT(">"), convMem, convFile);
-
- wxRichTextCompositeObject& composite = (wxRichTextCompositeObject&) obj;
- size_t i;
- for (i = 0; i < composite.GetChildCount(); i++)
- {
- wxRichTextObject* child = composite.GetChild(i);
- ExportXML(stream, convMem, convFile, *child, indent+1);
- }
- }
-
- if (objectName != wxT("text"))
- OutputIndentation(stream, indent);
-
- if (terminateTag)
- OutputString(stream, wxT("</") + objectName + wxT(">"), convMem, convFile);
-
- return true;
-}
-
-bool wxRichTextXMLHandler::ExportStyleDefinition(wxOutputStream& stream, wxMBConv* convMem, wxMBConv* convFile, wxRichTextStyleDefinition* def, int level)
-{
- wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
- wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
- wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
-
- wxString baseStyle = def->GetBaseStyle();
- wxString baseStyleProp;
- if (!baseStyle.IsEmpty())
- baseStyleProp = wxT(" basestyle=\"") + baseStyle + wxT("\"");
-
- wxString descr = def->GetDescription();
- wxString descrProp;
- if (!descr.IsEmpty())
- descrProp = wxT(" description=\"") + descr + wxT("\"");
-
- if (charDef)
- {
- OutputIndentation(stream, level);
- OutputString(stream, wxT("<characterstyle") + baseStyleProp + descrProp + wxT(">"), convMem, convFile);
-
- level ++;
-
- wxString style = CreateStyle(def->GetStyle(), false);
+ wxString style = AddAttributes(def->GetStyle(), false);
OutputIndentation(stream, level);
- OutputString(stream, wxT("<style ") + style + wxT(">"), convMem, convFile);
+ OutputString(stream, wxT("<style ") + style + wxT(">"));
OutputIndentation(stream, level);
- OutputString(stream, wxT("</style>"), convMem, convFile);
+ OutputString(stream, wxT("</style>"));
level --;
OutputIndentation(stream, level);
- OutputString(stream, wxT("</characterstyle>"), convMem, convFile);
+ OutputString(stream, wxT("</characterstyle>"));
}
else if (listDef)
{
OutputIndentation(stream, level);
- if (!listDef->GetNextStyle().IsEmpty())
- baseStyleProp << wxT(" basestyle=\"") << listDef->GetNextStyle() << wxT("\"");
+ if (!listDef->GetNextStyle().empty())
+ baseStyleProp << wxT(" nextstyle=\"") << listDef->GetNextStyle() << wxT("\"");
- OutputString(stream, wxT("<liststyle") + baseStyleProp + descrProp + wxT(">"), convMem, convFile);
+ OutputString(stream, wxT("<liststyle") + baseStyleProp + descrProp + wxT(">"));
level ++;
- wxString style = CreateStyle(def->GetStyle(), false);
+ wxString style = AddAttributes(def->GetStyle(), true);
OutputIndentation(stream, level);
- OutputString(stream, wxT("<style ") + style + wxT(">"), convMem, convFile);
+ OutputString(stream, wxT("<style ") + style + wxT(">"));
OutputIndentation(stream, level);
- OutputString(stream, wxT("</style>"), convMem, convFile);
+ OutputString(stream, wxT("</style>"));
int i;
for (i = 0; i < 10; i ++)
wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i);
if (levelAttr)
{
- wxString style = CreateStyle(def->GetStyle(), false);
+ wxString style = AddAttributes(def->GetStyle(), true);
wxString levelStr = wxString::Format(wxT(" level=\"%d\" "), (i+1));
OutputIndentation(stream, level);
- OutputString(stream, wxT("<style ") + levelStr + style + wxT(">"), convMem, convFile);
+ OutputString(stream, wxT("<style ") + levelStr + style + wxT(">"));
OutputIndentation(stream, level);
- OutputString(stream, wxT("</style>"), convMem, convFile);
+ OutputString(stream, wxT("</style>"));
}
}
level --;
OutputIndentation(stream, level);
- OutputString(stream, wxT("</liststyle>"), convMem, convFile);
+ OutputString(stream, wxT("</liststyle>"));
}
else if (paraDef)
{
OutputIndentation(stream, level);
- if (!paraDef->GetNextStyle().IsEmpty())
- baseStyleProp << wxT(" basestyle=\"") << paraDef->GetNextStyle() << wxT("\"");
+ if (!paraDef->GetNextStyle().empty())
+ baseStyleProp << wxT(" nextstyle=\"") << paraDef->GetNextStyle() << wxT("\"");
- OutputString(stream, wxT("<paragraphstyle") + baseStyleProp + descrProp + wxT(">"), convMem, convFile);
+ OutputString(stream, wxT("<paragraphstyle") + baseStyleProp + descrProp + wxT(">"));
level ++;
- wxString style = CreateStyle(def->GetStyle(), false);
+ wxString style = AddAttributes(def->GetStyle(), false);
OutputIndentation(stream, level);
- OutputString(stream, wxT("<style ") + style + wxT(">"), convMem, convFile);
+ OutputString(stream, wxT("<style ") + style + wxT(">"));
OutputIndentation(stream, level);
- OutputString(stream, wxT("</style>"), convMem, convFile);
+ OutputString(stream, wxT("</style>"));
level --;
OutputIndentation(stream, level);
- OutputString(stream, wxT("</paragraphstyle>"), convMem, convFile);
+ OutputString(stream, wxT("</paragraphstyle>"));
}
return true;
}
-/// Create style parameters
-wxString wxRichTextXMLHandler::CreateStyle(const wxRichTextAttr& attr, bool isPara)
+/// Create a string containing style attributes
+wxString wxRichTextXMLHandler::AddAttributes(const wxRichTextAttr& attr, bool isPara)
{
wxString str;
if (attr.HasTextColour() && attr.GetTextColour().Ok())
- {
- str << wxT(" textcolor=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
- }
+ AddAttribute(str, wxT("textcolor"), attr.GetTextColour());
+
if (attr.HasBackgroundColour() && attr.GetBackgroundColour().Ok())
- {
- str << wxT(" bgcolor=\"#") << ColourToHexString(attr.GetBackgroundColour()) << wxT("\"");
- }
+ AddAttribute(str, wxT("bgcolor"), attr.GetBackgroundColour());
if (attr.HasFontSize())
- str << wxT(" fontsize=\"") << attr.GetFontSize() << wxT("\"");
+ AddAttribute(str, wxT("fontsize"), attr.GetFontSize());
if (attr.HasFontFamily())
- str << wxT(" fontfamily=\"") << attr.GetFont().GetFamily() << wxT("\"");
+ AddAttribute(str, wxT("fontfamily"), attr.GetFontFamily());
if (attr.HasFontItalic())
- str << wxT(" fontstyle=\"") << attr.GetFontStyle() << wxT("\"");
+ AddAttribute(str, wxT("fontstyle"), attr.GetFontStyle());
if (attr.HasFontWeight())
- str << wxT(" fontweight=\"") << attr.GetFontWeight() << wxT("\"");
+ AddAttribute(str, wxT("fontweight"), attr.GetFontWeight());
if (attr.HasFontUnderlined())
- str << wxT(" fontunderlined=\"") << (int) attr.GetFontUnderlined() << wxT("\"");
+ AddAttribute(str, wxT("fontunderlined"), (int) attr.GetFontUnderlined());
if (attr.HasFontFaceName())
- str << wxT(" fontface=\"") << attr.GetFontFaceName() << wxT("\"");
+ AddAttribute(str, wxT("fontface"), attr.GetFontFaceName());
if (attr.HasTextEffects())
{
- str << wxT(" texteffects=\"");
- str << attr.GetTextEffects();
- str << wxT("\"");
-
- str << wxT(" texteffectflags=\"");
- str << attr.GetTextEffectFlags();
- str << wxT("\"");
+ AddAttribute(str, wxT("texteffects"), attr.GetTextEffects());
+ AddAttribute(str, wxT("texteffectflags"), attr.GetTextEffectFlags());
}
if (!attr.GetCharacterStyleName().empty())
- str << wxT(" characterstyle=\"") << wxString(attr.GetCharacterStyleName()) << wxT("\"");
+ AddAttribute(str, wxT("characterstyle"), attr.GetCharacterStyleName());
if (attr.HasURL())
- str << wxT(" url=\"") << AttributeToXML(attr.GetURL()) << wxT("\"");
+ AddAttribute(str, wxT("url"), AttributeToXML(attr.GetURL()));
if (isPara)
{
if (attr.HasAlignment())
- str << wxT(" alignment=\"") << (int) attr.GetAlignment() << wxT("\"");
+ AddAttribute(str, wxT("alignment"), (int) attr.GetAlignment());
if (attr.HasLeftIndent())
{
- str << wxT(" leftindent=\"") << (int) attr.GetLeftIndent() << wxT("\"");
- str << wxT(" leftsubindent=\"") << (int) attr.GetLeftSubIndent() << wxT("\"");
+ AddAttribute(str, wxT("leftindent"), (int) attr.GetLeftIndent());
+ AddAttribute(str, wxT("leftsubindent"), (int) attr.GetLeftSubIndent());
}
if (attr.HasRightIndent())
- str << wxT(" rightindent=\"") << (int) attr.GetRightIndent() << wxT("\"");
+ AddAttribute(str, wxT("rightindent"), (int) attr.GetRightIndent());
if (attr.HasParagraphSpacingAfter())
- str << wxT(" parspacingafter=\"") << (int) attr.GetParagraphSpacingAfter() << wxT("\"");
+ AddAttribute(str, wxT("parspacingafter"), (int) attr.GetParagraphSpacingAfter());
if (attr.HasParagraphSpacingBefore())
- str << wxT(" parspacingbefore=\"") << (int) attr.GetParagraphSpacingBefore() << wxT("\"");
+ AddAttribute(str, wxT("parspacingbefore"), (int) attr.GetParagraphSpacingBefore());
if (attr.HasLineSpacing())
- str << wxT(" linespacing=\"") << (int) attr.GetLineSpacing() << wxT("\"");
+ AddAttribute(str, wxT("linespacing"), (int) attr.GetLineSpacing());
if (attr.HasBulletStyle())
- str << wxT(" bulletstyle=\"") << (int) attr.GetBulletStyle() << wxT("\"");
+ AddAttribute(str, wxT("bulletstyle"), (int) attr.GetBulletStyle());
if (attr.HasBulletNumber())
- str << wxT(" bulletnumber=\"") << (int) attr.GetBulletNumber() << wxT("\"");
+ AddAttribute(str, wxT("bulletnumber"), (int) attr.GetBulletNumber());
if (attr.HasBulletText())
{
// If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
// Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
- if (!attr.GetBulletText().IsEmpty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL))
- str << wxT(" bulletsymbol=\"") << (int) (attr.GetBulletText()[0]) << wxT("\"");
+ if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL))
+ AddAttribute(str, wxT("bulletsymbol"), (int) (attr.GetBulletText()[0]));
else
- str << wxT(" bullettext=\"") << attr.GetBulletText() << wxT("\"");
+ AddAttribute(str, wxT("bullettext"), attr.GetBulletText());
- str << wxT(" bulletfont=\"") << attr.GetBulletFont() << wxT("\"");
+ AddAttribute(str, wxT("bulletfont"), attr.GetBulletFont());
}
if (attr.HasBulletName())
- str << wxT(" bulletname=\"") << attr.GetBulletName() << wxT("\"");
+ AddAttribute(str, wxT("bulletname"), attr.GetBulletName());
if (!attr.GetParagraphStyleName().empty())
- str << wxT(" parstyle=\"") << wxString(attr.GetParagraphStyleName()) << wxT("\"");
+ AddAttribute(str, wxT("parstyle"), attr.GetParagraphStyleName());
if (!attr.GetListStyleName().empty())
- str << wxT(" liststyle=\"") << wxString(attr.GetListStyleName()) << wxT("\"");
+ AddAttribute(str, wxT("liststyle"), attr.GetListStyleName());
if (attr.HasTabs())
{
- str << wxT(" tabs=\"");
+ wxString strTabs;
size_t i;
for (i = 0; i < attr.GetTabs().GetCount(); i++)
{
- if (i > 0)
- str << wxT(",");
- str << attr.GetTabs()[i];
+ if (i > 0) strTabs << wxT(",");
+ strTabs << attr.GetTabs()[i];
}
- str << wxT("\"");
+ AddAttribute(str, wxT("tabs"), strTabs);
}
if (attr.HasPageBreak())
{
- str << wxT(" pagebreak=\"1\"");
+ AddAttribute(str, wxT("pagebreak"), 1);
}
if (attr.HasOutlineLevel())
- str << wxT(" outlinelevel=\"") << (int) attr.GetOutlineLevel() << wxT("\"");
+ AddAttribute(str, wxT("outlinelevel"), (int) attr.GetOutlineLevel());
+ }
+
+ AddAttribute(str, wxT("margin"), attr.GetTextBoxAttr().GetMargins());
+ AddAttribute(str, wxT("padding"), attr.GetTextBoxAttr().GetPadding());
+ AddAttribute(str, wxT("position"), attr.GetTextBoxAttr().GetPosition());
+ AddAttribute(str, wxT("border"), attr.GetTextBoxAttr().GetBorder());
+ AddAttribute(str, wxT("outline"), attr.GetTextBoxAttr().GetOutline());
+ AddAttribute(str, wxT("width"), attr.GetTextBoxAttr().GetWidth());
+ AddAttribute(str, wxT("height"), attr.GetTextBoxAttr().GetWidth());
+
+ if (attr.GetTextBoxAttr().HasFloatMode())
+ {
+ wxString value;
+ if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT)
+ value = wxT("left");
+ else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT)
+ value = wxT("right");
+ else
+ value = wxT("none");
+ AddAttribute(str, wxT("float"), value);
+ }
+ if (attr.GetTextBoxAttr().HasClearMode())
+ {
+ wxString value;
+ if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT)
+ value = wxT("left");
+ else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT)
+ value = wxT("right");
+ else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH)
+ value = wxT("both");
+ else
+ value = wxT("none");
+ AddAttribute(str, wxT("clear"), value);
}
+ if (attr.GetTextBoxAttr().HasCollapseBorders())
+ AddAttribute(str, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders());
+
return str;
}
-/// Replace face name with current name for platform.
-/// TODO: introduce a virtual function or settable table to
-/// do this comprehensively.
-bool wxRichTextFixFaceName(wxString& facename)
+// Make a string from the given property. This can be overridden for custom variants.
+wxString wxRichTextXMLHandler::MakeStringFromProperty(const wxVariant& var)
{
- if (facename.IsEmpty())
- return false;
+ return var.MakeString();
+}
-#ifdef __WXMSW__
- if (facename == wxT("Times"))
- {
- facename = wxT("Times New Roman");
- return true;
- }
- else if (facename == wxT("Helvetica"))
- {
- facename = wxT("Arial");
- return true;
- }
- else if (facename == wxT("Courier"))
- {
- facename = wxT("Courier New");
- return true;
- }
- else
- return false;
-#else
- if (facename == wxT("Times New Roman"))
- {
- facename = wxT("Times");
- return true;
- }
- else if (facename == wxT("Arial"))
- {
- facename = wxT("Helvetica");
- return true;
- }
- else if (facename == wxT("Courier New"))
+// Create a proprty from the string read from the XML file.
+wxVariant wxRichTextXMLHandler::MakePropertyFromString(const wxString& name, const wxString& value, const wxString& WXUNUSED(type))
+{
+ wxVariant var(value, name);
+ // TODO: use type to create using common types
+ return var;
+}
+
+// Write the properties
+bool wxRichTextXMLHandler::WriteProperties(wxOutputStream& stream, const wxRichTextProperties& properties, int level)
+{
+ if (properties.GetCount() > 0)
{
- facename = wxT("Courier");
- return true;
+ level ++;
+
+ OutputIndentation(stream, level);
+ OutputString(stream, wxT("<properties"));
+
+ level ++;
+
+ size_t i;
+ for (i = 0; i < properties.GetCount(); i++)
+ {
+ const wxVariant& var = properties[i];
+ if (!var.IsNull())
+ {
+ const wxString& name = var.GetName();
+ wxString value = MakeStringFromProperty(var);
+
+ OutputIndentation(stream, level);
+ OutputString(stream, wxT("<property name=\"") + name +
+ wxT("\" type=\"") + var.GetType() + wxT("\" value=\""));
+ OutputStringEnt(stream, value);
+ OutputString(stream, wxT("\"/>\n"));
+ }
+ }
+
+ level --;
+
+ OutputIndentation(stream, level);
+ OutputString(stream, wxT("</properties>\n"));
+
+ level --;
}
- else
- return false;
-#endif
+
+ return true;
}
-/// Get style parameters
-bool wxRichTextXMLHandler::GetStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara)
+
+#endif
+ // wxRICHTEXT_HAVE_DIRECT_OUTPUT
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+bool wxRichTextXMLHandler::ExportXML(wxXmlNode* parent, wxRichTextObject& obj)
{
- wxString fontFacename;
- int fontSize = 12;
- wxFontFamily fontFamily = wxFONTFAMILY_DEFAULT;
- wxFontWeight fontWeight = wxFONTWEIGHT_NORMAL;
- wxFontStyle fontStyle = wxFONTSTYLE_NORMAL;
- bool fontUnderlined = false;
- const wxString emptyString; // save a temporary string construction in GetPropVal
+ obj.ExportXML(parent, this);
- // int fontFlags = 0;
+ return true;
+}
- fontFacename = node->GetAttribute(wxT("fontface"), emptyString);
- if (!fontFacename.IsEmpty())
- {
- attr.SetFontFaceName(fontFacename);
- if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES)
- wxRichTextFixFaceName(fontFacename);
- }
+bool wxRichTextXMLHandler::ExportStyleDefinition(wxXmlNode* parent, wxRichTextStyleDefinition* def)
+{
+ wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
+ wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
+ wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
- wxString value;
- value = node->GetAttribute(wxT("fontfamily"), emptyString);
- if (!value.empty())
+ wxString baseStyle = def->GetBaseStyle();
+ wxString descr = def->GetDescription();
+
+ wxXmlNode* defNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxEmptyString);
+ parent->AddChild(defNode);
+ if (!baseStyle.empty())
+ defNode->AddAttribute(wxT("basestyle"), baseStyle);
+ if (!descr.empty())
+ defNode->AddAttribute(wxT("description"), descr);
+
+ wxXmlNode* styleNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style"));
+ defNode->AddChild(styleNode);
+
+ if (charDef)
{
- fontFamily = (wxFontFamily)wxAtoi(value);
- attr.SetFontFamily(fontFamily);
+ defNode->SetName(wxT("characterstyle"));
+ AddAttributes(styleNode, def->GetStyle(), false);
}
-
- value = node->GetAttribute(wxT("fontstyle"), emptyString);
- if (!value.empty())
+ else if (listDef)
{
- fontStyle = (wxFontStyle)wxAtoi(value);
- attr.SetFontStyle(fontStyle);
- }
+ defNode->SetName(wxT("liststyle"));
- value = node->GetAttribute(wxT("fontsize"), emptyString);
- if (!value.empty())
- {
- fontSize = wxAtoi(value);
- attr.SetFontSize(fontSize);
- }
+ if (!listDef->GetNextStyle().empty())
+ defNode->AddAttribute(wxT("nextstyle"), listDef->GetNextStyle());
- value = node->GetAttribute(wxT("fontweight"), emptyString);
- if (!value.empty())
- {
- fontWeight = (wxFontWeight)wxAtoi(value);
- attr.SetFontWeight(fontWeight);
- }
+ AddAttributes(styleNode, def->GetStyle(), true);
- value = node->GetAttribute(wxT("fontunderlined"), emptyString);
- if (!value.empty())
- {
- fontUnderlined = wxAtoi(value) != 0;
- attr.SetFontUnderlined(fontUnderlined);
+ int i;
+ for (i = 0; i < 10; i ++)
+ {
+ wxRichTextAttr* levelAttr = listDef->GetLevelAttributes(i);
+ if (levelAttr)
+ {
+ wxXmlNode* levelNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("style"));
+ defNode->AddChild(levelNode);
+ levelNode->AddAttribute(wxT("level"), MakeString(i+1));
+ AddAttributes(levelNode, * levelAttr, true);
+ }
+ }
}
-
- value = node->GetAttribute(wxT("textcolor"), emptyString);
- if (!value.empty())
+ else if (paraDef)
{
- if (value[0] == wxT('#'))
- attr.SetTextColour(HexStringToColour(value.Mid(1)));
- else
- attr.SetTextColour(value);
- }
+ defNode->SetName(wxT("paragraphstyle"));
- value = node->GetAttribute(wxT("bgcolor"), emptyString);
- if (!value.empty())
- {
- if (value[0] == wxT('#'))
- attr.SetBackgroundColour(HexStringToColour(value.Mid(1)));
- else
- attr.SetBackgroundColour(value);
+ if (!paraDef->GetNextStyle().empty())
+ defNode->AddAttribute(wxT("nextstyle"), paraDef->GetNextStyle());
+
+ AddAttributes(styleNode, def->GetStyle(), true);
}
- value = node->GetAttribute(wxT("characterstyle"), emptyString);
- if (!value.empty())
- attr.SetCharacterStyleName(value);
+ return true;
+}
- value = node->GetAttribute(wxT("texteffects"), emptyString);
- if (!value.IsEmpty())
- {
- attr.SetTextEffects(wxAtoi(value));
- }
+bool wxRichTextXMLHandler::AddAttributes(wxXmlNode* node, wxRichTextAttr& attr, bool isPara)
+{
+ if (attr.HasTextColour() && attr.GetTextColour().Ok())
+ node->AddAttribute(wxT("textcolor"), MakeString(attr.GetTextColour()));
+ if (attr.HasBackgroundColour() && attr.GetBackgroundColour().Ok())
+ node->AddAttribute(wxT("bgcolor"), MakeString(attr.GetBackgroundColour()));
- value = node->GetAttribute(wxT("texteffectflags"), emptyString);
- if (!value.IsEmpty())
+ if (attr.HasFontSize())
+ node->AddAttribute(wxT("fontsize"), MakeString(attr.GetFontSize()));
+ if (attr.HasFontFamily())
+ node->AddAttribute(wxT("fontfamily"), MakeString(attr.GetFontFamily()));
+ if (attr.HasFontItalic())
+ node->AddAttribute(wxT("fontstyle"), MakeString(attr.GetFontStyle()));
+ if (attr.HasFontWeight())
+ node->AddAttribute(wxT("fontweight"), MakeString(attr.GetFontWeight()));
+ if (attr.HasFontUnderlined())
+ node->AddAttribute(wxT("fontunderlined"), MakeString((int) attr.GetFontUnderlined()));
+ if (attr.HasFontFaceName())
+ node->AddAttribute(wxT("fontface"), attr.GetFontFaceName());
+
+ if (attr.HasTextEffects())
{
- attr.SetTextEffectFlags(wxAtoi(value));
+ node->AddAttribute(wxT("texteffects"), MakeString(attr.GetTextEffects()));
+ node->AddAttribute(wxT("texteffectflags"), MakeString(attr.GetTextEffectFlags()));
}
+ if (attr.HasCharacterStyleName() && !attr.GetCharacterStyleName().empty())
+ node->AddAttribute(wxT("characterstyle"), attr.GetCharacterStyleName());
- value = node->GetAttribute(wxT("url"), emptyString);
- if (!value.empty())
- attr.SetURL(value);
+ if (attr.HasURL())
+ node->AddAttribute(wxT("url"), attr.GetURL()); // TODO: do we need to wrap this in AttributeToXML?
- // Set paragraph attributes
if (isPara)
{
- value = node->GetAttribute(wxT("alignment"), emptyString);
- if (!value.empty())
- attr.SetAlignment((wxTextAttrAlignment) wxAtoi(value));
-
- int leftSubIndent = 0;
- int leftIndent = 0;
- bool hasLeftIndent = false;
-
- value = node->GetAttribute(wxT("leftindent"), emptyString);
- if (!value.empty())
- {
- leftIndent = wxAtoi(value);
- hasLeftIndent = true;
- }
+ if (attr.HasAlignment())
+ node->AddAttribute(wxT("alignment"), MakeString((int) attr.GetAlignment()));
- value = node->GetAttribute(wxT("leftsubindent"), emptyString);
- if (!value.empty())
+ if (attr.HasLeftIndent())
{
- leftSubIndent = wxAtoi(value);
- hasLeftIndent = true;
+ node->AddAttribute(wxT("leftindent"), MakeString((int) attr.GetLeftIndent()));
+ node->AddAttribute(wxT("leftsubindent"), MakeString((int) attr.GetLeftSubIndent()));
}
- if (hasLeftIndent)
- attr.SetLeftIndent(leftIndent, leftSubIndent);
-
- value = node->GetAttribute(wxT("rightindent"), emptyString);
- if (!value.empty())
- attr.SetRightIndent(wxAtoi(value));
+ if (attr.HasRightIndent())
+ node->AddAttribute(wxT("rightindent"), MakeString((int) attr.GetRightIndent()));
- value = node->GetAttribute(wxT("parspacingbefore"), emptyString);
- if (!value.empty())
- attr.SetParagraphSpacingBefore(wxAtoi(value));
+ if (attr.HasParagraphSpacingAfter())
+ node->AddAttribute(wxT("parspacingafter"), MakeString((int) attr.GetParagraphSpacingAfter()));
- value = node->GetAttribute(wxT("parspacingafter"), emptyString);
- if (!value.empty())
- attr.SetParagraphSpacingAfter(wxAtoi(value));
+ if (attr.HasParagraphSpacingBefore())
+ node->AddAttribute(wxT("parspacingbefore"), MakeString((int) attr.GetParagraphSpacingBefore()));
- value = node->GetAttribute(wxT("linespacing"), emptyString);
- if (!value.empty())
- attr.SetLineSpacing(wxAtoi(value));
+ if (attr.HasLineSpacing())
+ node->AddAttribute(wxT("linespacing"), MakeString((int) attr.GetLineSpacing()));
- value = node->GetAttribute(wxT("bulletstyle"), emptyString);
- if (!value.empty())
- attr.SetBulletStyle(wxAtoi(value));
+ if (attr.HasBulletStyle())
+ node->AddAttribute(wxT("bulletstyle"), MakeString((int) attr.GetBulletStyle()));
- value = node->GetAttribute(wxT("bulletnumber"), emptyString);
- if (!value.empty())
- attr.SetBulletNumber(wxAtoi(value));
+ if (attr.HasBulletNumber())
+ node->AddAttribute(wxT("bulletnumber"), MakeString((int) attr.GetBulletNumber()));
- value = node->GetAttribute(wxT("bulletsymbol"), emptyString);
- if (!value.empty())
+ if (attr.HasBulletText())
{
- wxChar ch = wxAtoi(value);
- wxString s;
- s << ch;
- attr.SetBulletText(s);
- }
-
- value = node->GetAttribute(wxT("bullettext"), emptyString);
- if (!value.empty())
- attr.SetBulletText(value);
+ // If using a bullet symbol, convert to integer in case it's a non-XML-friendly character.
+ // Otherwise, assume it's XML-friendly text such as outline numbering, e.g. 1.2.3.1
+ if (!attr.GetBulletText().empty() && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL))
+ node->AddAttribute(wxT("bulletsymbol"), MakeString((int) (attr.GetBulletText()[0])));
+ else
+ node->AddAttribute(wxT("bullettext"), attr.GetBulletText());
- value = node->GetAttribute(wxT("bulletfont"), emptyString);
- if (!value.empty())
- attr.SetBulletFont(value);
+ if (!attr.GetBulletFont().empty())
+ node->AddAttribute(wxT("bulletfont"), attr.GetBulletFont());
+ }
- value = node->GetAttribute(wxT("bulletname"), emptyString);
- if (!value.empty())
- attr.SetBulletName(value);
+ if (attr.HasBulletName())
+ node->AddAttribute(wxT("bulletname"), attr.GetBulletName());
- value = node->GetAttribute(wxT("parstyle"), emptyString);
- if (!value.empty())
- attr.SetParagraphStyleName(value);
+ if (!attr.GetParagraphStyleName().empty())
+ node->AddAttribute(wxT("parstyle"), attr.GetParagraphStyleName());
- value = node->GetAttribute(wxT("liststyle"), emptyString);
- if (!value.empty())
- attr.SetListStyleName(value);
+ if (!attr.GetListStyleName().empty())
+ node->AddAttribute(wxT("liststyle"), attr.GetListStyleName());
- value = node->GetAttribute(wxT("tabs"), emptyString);
- if (!value.empty())
+ if (attr.HasTabs())
{
- wxArrayInt tabs;
- wxStringTokenizer tkz(value, wxT(","));
- while (tkz.HasMoreTokens())
+ wxString tabs;
+ size_t i;
+ for (i = 0; i < attr.GetTabs().GetCount(); i++)
{
- wxString token = tkz.GetNextToken();
- tabs.Add(wxAtoi(token));
+ if (i > 0)
+ tabs << wxT(",");
+ tabs << attr.GetTabs()[i];
}
- attr.SetTabs(tabs);
+ node->AddAttribute(wxT("tabs"), tabs);
}
- value = node->GetAttribute(wxT("pagebreak"), emptyString);
- if (!value.IsEmpty())
- {
- attr.SetPageBreak(wxAtoi(value) != 0);
- }
+ if (attr.HasPageBreak())
+ node->AddAttribute(wxT("pagebreak"), wxT("1"));
- value = node->GetAttribute(wxT("outlinelevel"), emptyString);
- if (!value.IsEmpty())
- {
- attr.SetOutlineLevel(wxAtoi(value));
- }
+ if (attr.HasOutlineLevel())
+ node->AddAttribute(wxT("outlinelevel"), MakeString((int) attr.GetOutlineLevel()));
+ }
+
+ AddAttribute(node, wxT("margin"), attr.GetTextBoxAttr().GetMargins());
+ AddAttribute(node, wxT("padding"), attr.GetTextBoxAttr().GetPadding());
+ AddAttribute(node, wxT("position"), attr.GetTextBoxAttr().GetPosition());
+ AddAttribute(node, wxT("border"), attr.GetTextBoxAttr().GetBorder());
+ AddAttribute(node, wxT("outline"), attr.GetTextBoxAttr().GetOutline());
+ AddAttribute(node, wxT("width"), attr.GetTextBoxAttr().GetWidth());
+ AddAttribute(node, wxT("height"), attr.GetTextBoxAttr().GetWidth());
+
+ if (attr.GetTextBoxAttr().HasFloatMode())
+ {
+ wxString value;
+ if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT)
+ value = wxT("left");
+ else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT)
+ value = wxT("right");
+ else
+ value = wxT("none");
+ AddAttribute(node, wxT("float"), value);
}
+ if (attr.GetTextBoxAttr().HasClearMode())
+ {
+ wxString value;
+ if (attr.GetTextBoxAttr().GetClearMode() == wxTEXT_BOX_ATTR_CLEAR_LEFT)
+ value = wxT("left");
+ else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_RIGHT)
+ value = wxT("right");
+ else if (attr.GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_CLEAR_BOTH)
+ value = wxT("both");
+ else
+ value = wxT("none");
+ AddAttribute(node, wxT("clear"), value);
+ }
+
+ if (attr.GetTextBoxAttr().HasCollapseBorders())
+ AddAttribute(node, wxT("collapse-borders"), (int) attr.GetTextBoxAttr().GetCollapseBorders());
+
return true;
}
-#endif
- // wxUSE_STREAMS
+bool wxRichTextXMLHandler::WriteProperties(wxXmlNode* node, const wxRichTextProperties& properties)
+{
+ if (properties.GetCount() > 0)
+ {
+ wxXmlNode* propertiesNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("properties"));
+ node->AddChild(propertiesNode);
+ size_t i;
+ for (i = 0; i < properties.GetCount(); i++)
+ {
+ const wxVariant& var = properties[i];
+ if (!var.IsNull())
+ {
+ wxXmlNode* propertyNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("property"));
+ propertiesNode->AddChild(propertyNode);
+
+ const wxString& name = var.GetName();
+ wxString value = MakeStringFromProperty(var);
+
+ AddAttribute(propertyNode, wxT("name"), name);
+ AddAttribute(propertyNode, wxT("type"), var.GetType());
+ AddAttribute(propertyNode, wxT("value"), value);
+ }
+ }
+ }
+ return true;
+}
+
+#endif
+ // wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+
+/// Replace face name with current name for platform.
+/// TODO: introduce a virtual function or settable table to
+/// do this comprehensively.
+bool wxRichTextFixFaceName(wxString& facename)
+{
+ if (facename.empty())
+ return false;
+
+#ifdef __WXMSW__
+ if (facename == wxT("Times"))
+ {
+ facename = wxT("Times New Roman");
+ return true;
+ }
+ else if (facename == wxT("Helvetica"))
+ {
+ facename = wxT("Arial");
+ return true;
+ }
+ else if (facename == wxT("Courier"))
+ {
+ facename = wxT("Courier New");
+ return true;
+ }
+ else
+ return false;
+#else
+ if (facename == wxT("Times New Roman"))
+ {
+ facename = wxT("Times");
+ return true;
+ }
+ else if (facename == wxT("Arial"))
+ {
+ facename = wxT("Helvetica");
+ return true;
+ }
+ else if (facename == wxT("Courier New"))
+ {
+ facename = wxT("Courier");
+ return true;
+ }
+ else
+ return false;
+#endif
+}
+
+static inline long wxRichTextColourStringToLong(const wxString& colStr)
+{
+ if (!colStr.IsEmpty())
+ {
+ wxColour col(colStr);
+ return col.GetRGB();
+ }
+ else
+ return 0;
+}
+
+static inline wxTextAttrDimension wxRichTextParseDimension(const wxString& dimStr)
+{
+ wxString valuePart = dimStr.BeforeFirst(wxT(','));
+ wxString flagsPart;
+ if (dimStr.Contains(wxT(",")))
+ flagsPart = dimStr.AfterFirst(wxT(','));
+ wxTextAttrDimension dim;
+ dim.SetValue(wxAtoi(valuePart));
+ dim.SetFlags(wxAtoi(flagsPart));
+
+ return dim;
+}
+
+/// Import style parameters
+bool wxRichTextXMLHandler::ImportStyle(wxRichTextAttr& attr, wxXmlNode* node, bool isPara)
+{
+ wxXmlAttribute* xmlAttr = node->GetAttributes();
+ bool found;
+ while (xmlAttr)
+ {
+ const wxString& name = xmlAttr->GetName();
+ const wxString& value = xmlAttr->GetValue();
+ found = true;
+
+ if (name == wxT("fontface"))
+ {
+ if (!value.empty())
+ {
+ wxString v = value;
+ if (GetFlags() & wxRICHTEXT_HANDLER_CONVERT_FACENAMES)
+ wxRichTextFixFaceName(v);
+ attr.SetFontFaceName(v);
+ }
+ }
+ else if (name == wxT("fontfamily"))
+ {
+ if (!value.empty())
+ attr.SetFontFamily((wxFontFamily)wxAtoi(value));
+ }
+ else if (name == wxT("fontstyle"))
+ {
+ if (!value.empty())
+ attr.SetFontStyle((wxFontStyle)wxAtoi(value));
+ }
+ else if (name == wxT("fontsize"))
+ {
+ if (!value.empty())
+ attr.SetFontSize(wxAtoi(value));
+ }
+ else if (name == wxT("fontweight"))
+ {
+ if (!value.empty())
+ attr.SetFontWeight((wxFontWeight) wxAtoi(value));
+ }
+ else if (name == wxT("fontunderlined"))
+ {
+ if (!value.empty())
+ attr.SetFontUnderlined(wxAtoi(value) != 0);
+ }
+ else if (name == wxT("textcolor"))
+ {
+ if (!value.empty())
+ {
+ if (value[0] == wxT('#'))
+ attr.SetTextColour(HexStringToColour(value.Mid(1)));
+ else
+ attr.SetTextColour(value);
+ }
+ }
+ else if (name == wxT("bgcolor"))
+ {
+ if (!value.empty())
+ {
+ if (value[0] == wxT('#'))
+ attr.SetBackgroundColour(HexStringToColour(value.Mid(1)));
+ else
+ attr.SetBackgroundColour(value);
+ }
+ }
+ else if (name == wxT("characterstyle"))
+ {
+ if (!value.empty())
+ attr.SetCharacterStyleName(value);
+ }
+ else if (name == wxT("texteffects"))
+ {
+ if (!value.empty())
+ attr.SetTextEffects(wxAtoi(value));
+ }
+ else if (name == wxT("texteffectflags"))
+ {
+ if (!value.empty())
+ attr.SetTextEffectFlags(wxAtoi(value));
+ }
+ else if (name == wxT("url"))
+ {
+ if (!value.empty())
+ attr.SetURL(value);
+ }
+ else if (isPara)
+ {
+ if (name == wxT("alignment"))
+ {
+ if (!value.empty())
+ attr.SetAlignment((wxTextAttrAlignment) wxAtoi(value));
+ }
+ else if (name == wxT("leftindent"))
+ {
+ if (!value.empty())
+ attr.SetLeftIndent(wxAtoi(value), attr.GetLeftSubIndent());
+ }
+ else if (name == wxT("leftsubindent"))
+ {
+ if (!value.empty())
+ attr.SetLeftIndent(attr.GetLeftIndent(), wxAtoi(value));
+ }
+ else if (name == wxT("rightindent"))
+ {
+ if (!value.empty())
+ attr.SetRightIndent(wxAtoi(value));
+ }
+ else if (name == wxT("parspacingbefore"))
+ {
+ if (!value.empty())
+ attr.SetParagraphSpacingBefore(wxAtoi(value));
+ }
+ else if (name == wxT("parspacingafter"))
+ {
+ if (!value.empty())
+ attr.SetParagraphSpacingAfter(wxAtoi(value));
+ }
+ else if (name == wxT("linespacing"))
+ {
+ if (!value.empty())
+ attr.SetLineSpacing(wxAtoi(value));
+ }
+ else if (name == wxT("bulletstyle"))
+ {
+ if (!value.empty())
+ attr.SetBulletStyle(wxAtoi(value));
+ }
+ else if (name == wxT("bulletnumber"))
+ {
+ if (!value.empty())
+ attr.SetBulletNumber(wxAtoi(value));
+ }
+ else if (name == wxT("bulletsymbol"))
+ {
+ if (!value.empty())
+ {
+ wxChar ch = wxAtoi(value);
+ wxString s;
+ s << ch;
+ attr.SetBulletText(s);
+ }
+ }
+ else if (name == wxT("bullettext"))
+ {
+ if (!value.empty())
+ {
+ attr.SetBulletText(value);
+ }
+ }
+ else if (name == wxT("bulletfont"))
+ {
+ if (!value.empty())
+ {
+ attr.SetBulletFont(value);
+ }
+ }
+ else if (name == wxT("bulletname"))
+ {
+ if (!value.empty())
+ {
+ attr.SetBulletName(value);
+ }
+ }
+ else if (name == wxT("parstyle"))
+ {
+ if (!value.empty())
+ {
+ attr.SetParagraphStyleName(value);
+ }
+ }
+ else if (name == wxT("liststyle"))
+ {
+ if (!value.empty())
+ {
+ attr.SetListStyleName(value);
+ }
+ }
+ else if (name == wxT("tabs"))
+ {
+ if (!value.empty())
+ {
+ wxArrayInt tabs;
+ wxStringTokenizer tkz(value, wxT(","));
+ while (tkz.HasMoreTokens())
+ {
+ wxString token = tkz.GetNextToken();
+ tabs.Add(wxAtoi(token));
+ }
+ attr.SetTabs(tabs);
+ }
+ }
+ else if (name == wxT("pagebreak"))
+ {
+ if (!value.empty())
+ {
+ attr.SetPageBreak(wxAtoi(value) != 0);
+ }
+ }
+ else if (name == wxT("outlinelevel"))
+ {
+ if (!value.empty())
+ {
+ attr.SetOutlineLevel(wxAtoi(value));
+ }
+ }
+ else
+ found = false;
+ }
+ else
+ found = false;
+
+ if (!found)
+ {
+ // Box attributes
+
+ if (name == wxT("width"))
+ {
+ attr.GetTextBoxAttr().GetWidth().SetValue(wxRichTextParseDimension(value));
+ }
+ else if (name == wxT("height"))
+ {
+ attr.GetTextBoxAttr().GetHeight().SetValue(wxRichTextParseDimension(value));
+ }
+
+ else if (name == wxT("float"))
+ {
+ if (value == wxT("left"))
+ attr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_LEFT);
+ else if (value == wxT("right"))
+ attr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_RIGHT);
+ else if (value == wxT("none"))
+ attr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_NONE);
+ }
+ else if (name == wxT("clear"))
+ {
+ if (value == wxT("left"))
+ attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_LEFT);
+ else if (value == wxT("right"))
+ attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_RIGHT);
+ else if (value == wxT("both"))
+ attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_BOTH);
+ else if (value == wxT("none"))
+ attr.GetTextBoxAttr().SetClearMode(wxTEXT_BOX_ATTR_CLEAR_NONE);
+ }
+ else if (name == wxT("collapse-borders"))
+ attr.GetTextBoxAttr().SetCollapseBorders(value == wxT("1"));
+
+ else if (name.Contains(wxT("border-")))
+ {
+ if (name == wxT("border-left-style"))
+ attr.GetTextBoxAttr().GetBorder().GetLeft().SetStyle(wxAtoi(value));
+ else if (name == wxT("border-right-style"))
+ attr.GetTextBoxAttr().GetBorder().GetRight().SetStyle(wxAtoi(value));
+ else if (name == wxT("border-top-style"))
+ attr.GetTextBoxAttr().GetBorder().GetTop().SetStyle(wxAtoi(value));
+ else if (name == wxT("border-bottom-style"))
+ attr.GetTextBoxAttr().GetBorder().GetBottom().SetStyle(wxAtoi(value));
+
+ else if (name == wxT("border-left-colour"))
+ attr.GetTextBoxAttr().GetBorder().GetLeft().SetColour(wxRichTextColourStringToLong(value));
+ else if (name == wxT("border-right-colour"))
+ attr.GetTextBoxAttr().GetBorder().GetRight().SetColour(wxRichTextColourStringToLong(value));
+ else if (name == wxT("border-top-colour"))
+ attr.GetTextBoxAttr().GetBorder().GetTop().SetColour(wxRichTextColourStringToLong(value));
+ else if (name == wxT("border-bottom-colour"))
+ attr.GetTextBoxAttr().GetBorder().GetBottom().SetColour(wxRichTextColourStringToLong(value));
+
+ else if (name == wxT("border-left-width"))
+ attr.GetTextBoxAttr().GetBorder().GetLeft().SetWidth(wxRichTextParseDimension(value));
+ else if (name == wxT("border-right-width"))
+ attr.GetTextBoxAttr().GetBorder().GetRight().SetWidth(wxRichTextParseDimension(value));
+ else if (name == wxT("border-top-width"))
+ attr.GetTextBoxAttr().GetBorder().GetTop().SetWidth(wxRichTextParseDimension(value));
+ else if (name == wxT("border-bottom-width"))
+ attr.GetTextBoxAttr().GetBorder().GetBottom().SetWidth(wxRichTextParseDimension(value));
+ }
+ else if (name.Contains(wxT("outline-")))
+ {
+ if (name == wxT("outline-left-style"))
+ attr.GetTextBoxAttr().GetOutline().GetLeft().SetStyle(wxAtoi(value));
+ else if (name == wxT("outline-right-style"))
+ attr.GetTextBoxAttr().GetOutline().GetRight().SetStyle(wxAtoi(value));
+ else if (name == wxT("outline-top-style"))
+ attr.GetTextBoxAttr().GetOutline().GetTop().SetStyle(wxAtoi(value));
+ else if (name == wxT("outline-bottom-style"))
+ attr.GetTextBoxAttr().GetOutline().GetBottom().SetStyle(wxAtoi(value));
+
+ else if (name == wxT("outline-left-colour"))
+ attr.GetTextBoxAttr().GetOutline().GetLeft().SetColour(wxRichTextColourStringToLong(value));
+ else if (name == wxT("outline-right-colour"))
+ attr.GetTextBoxAttr().GetOutline().GetRight().SetColour(wxRichTextColourStringToLong(value));
+ else if (name == wxT("outline-top-colour"))
+ attr.GetTextBoxAttr().GetOutline().GetTop().SetColour(wxRichTextColourStringToLong(value));
+ else if (name == wxT("outline-bottom-colour"))
+ attr.GetTextBoxAttr().GetOutline().GetBottom().SetColour(wxRichTextColourStringToLong(value));
+
+ else if (name == wxT("outline-left-width"))
+ attr.GetTextBoxAttr().GetOutline().GetLeft().SetWidth(wxRichTextParseDimension(value));
+ else if (name == wxT("outline-right-width"))
+ attr.GetTextBoxAttr().GetOutline().GetRight().SetWidth(wxRichTextParseDimension(value));
+ else if (name == wxT("outline-top-width"))
+ attr.GetTextBoxAttr().GetOutline().GetTop().SetWidth(wxRichTextParseDimension(value));
+ else if (name == wxT("outline-bottom-width"))
+ attr.GetTextBoxAttr().GetOutline().GetBottom().SetWidth(wxRichTextParseDimension(value));
+ }
+ else if (name.Contains(wxT("margin-")))
+ {
+ if (name == wxT("margin-left"))
+ attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("margin-right"))
+ attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("margin-top"))
+ attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("margin-bottom"))
+ attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(wxRichTextParseDimension(value));
+ }
+ else if (name.Contains(wxT("padding-")))
+ {
+ if (name == wxT("padding-left"))
+ attr.GetTextBoxAttr().GetPadding().GetLeft().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("padding-right"))
+ attr.GetTextBoxAttr().GetPadding().GetRight().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("padding-top"))
+ attr.GetTextBoxAttr().GetPadding().GetTop().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("padding-bottom"))
+ attr.GetTextBoxAttr().GetPadding().GetBottom().SetValue(wxRichTextParseDimension(value));
+ }
+ else if (name.Contains(wxT("position-")))
+ {
+ if (name == wxT("position-left"))
+ attr.GetTextBoxAttr().GetPosition().GetLeft().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("position-right"))
+ attr.GetTextBoxAttr().GetPosition().GetRight().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("position-top"))
+ attr.GetTextBoxAttr().GetPosition().GetTop().SetValue(wxRichTextParseDimension(value));
+ else if (name == wxT("position-bottom"))
+ attr.GetTextBoxAttr().GetPosition().GetBottom().SetValue(wxRichTextParseDimension(value));
+ }
+ }
+
+ xmlAttr = xmlAttr->GetNext();
+ }
+
+ return true;
+}
+
+#endif
+ // wxUSE_STREAMS
+
+// Import this object from XML
+bool wxRichTextObject::ImportFromXML(wxRichTextBuffer* WXUNUSED(buffer), wxXmlNode* node, wxRichTextXMLHandler* handler)
+{
+ handler->ImportProperties(this, node);
+ handler->ImportStyle(GetAttributes(), node, UsesParagraphAttributes());
+
+ return true;
+}
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+// Export this object directly to the given stream.
+bool wxRichTextObject::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
+{
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<") + GetXMLNodeName(), handler->GetConvMem(), handler->GetConvFile());
+
+ wxString style = handler->AddAttributes(GetAttributes(), true);
+
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ }
+
+ wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject);
+ if (composite)
+ {
+ size_t i;
+ for (i = 0; i < composite->GetChildCount(); i++)
+ {
+ wxRichTextObject* child = composite->GetChild(i);
+ child->ExportXML(stream, indent+1, handler);
+ }
+ }
+
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("</") + GetXMLNodeName() + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+ return true;
+}
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+// Export this object to the given parent node, usually creating at least one child node.
+bool wxRichTextObject::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
+{
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, GetXMLNodeName());
+ parent->AddChild(elementNode);
+ handler->AddAttributes(elementNode, GetAttributes(), true);
+ handler->WriteProperties(elementNode, GetProperties());
+
+ wxRichTextCompositeObject* composite = wxDynamicCast(this, wxRichTextCompositeObject);
+ if (composite)
+ {
+ size_t i;
+ for (i = 0; i < composite->GetChildCount(); i++)
+ {
+ wxRichTextObject* child = composite->GetChild(i);
+ child->ExportXML(elementNode, handler);
+ }
+ }
+ return true;
+}
+#endif
+
+
+// Import this object from XML
+bool wxRichTextPlainText::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler)
+{
+ wxRichTextObject::ImportFromXML(buffer, node, handler);
+
+ if (node->GetName() == wxT("text"))
+ {
+ wxString text;
+ wxXmlNode* textChild = node->GetChildren();
+ while (textChild)
+ {
+ if (textChild->GetType() == wxXML_TEXT_NODE ||
+ textChild->GetType() == wxXML_CDATA_SECTION_NODE)
+ {
+ wxString text2 = textChild->GetContent();
+
+ // Strip whitespace from end
+ if (!text2.empty() && text2[text2.length()-1] == wxT('\n'))
+ text2 = text2.Mid(0, text2.length()-1);
+
+ if (!text2.empty() && text2[0] == wxT('"'))
+ text2 = text2.Mid(1);
+ if (!text2.empty() && text2[text2.length()-1] == wxT('"'))
+ text2 = text2.Mid(0, text2.length() - 1);
+
+ text += text2;
+ }
+ textChild = textChild->GetNext();
+ }
+
+ SetText(text);
+ }
+ else if (node->GetName() == wxT("symbol"))
+ {
+ // This is a symbol that XML can't read in the normal way
+ wxString text;
+ wxXmlNode* textChild = node->GetChildren();
+ while (textChild)
+ {
+ if (textChild->GetType() == wxXML_TEXT_NODE ||
+ textChild->GetType() == wxXML_CDATA_SECTION_NODE)
+ {
+ wxString text2 = textChild->GetContent();
+ text += text2;
+ }
+ textChild = textChild->GetNext();
+ }
+
+ wxString actualText;
+ actualText << (wxChar) wxAtoi(text);
+ SetText(actualText);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+// Export this object directly to the given stream.
+bool wxRichTextPlainText::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
+{
+ wxString style = handler->AddAttributes(GetAttributes(), false);
+
+ int i;
+ int last = 0;
+ const wxString& text = GetText();
+ int len = (int) text.Length();
+
+ if (len == 0)
+ {
+ i = 0;
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<text"), handler->GetConvMem(), handler->GetConvFile());
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ ::OutputIndentation(stream, indent);
+ }
+ ::OutputString(stream, wxT("</text>"), handler->GetConvMem(), handler->GetConvFile());
+ }
+ else for (i = 0; i < len; i++)
+ {
+#if wxUSE_UNICODE
+ int c = (int) text[i];
+#else
+ int c = (int) wxUChar(text[i]);
+#endif
+ if ((c < 32 || c == 34) && /* c != 9 && */ c != 10 && c != 13)
+ {
+ if (i > 0)
+ {
+ wxString fragment(text.Mid(last, i-last));
+ if (!fragment.empty())
+ {
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<text"), handler->GetConvMem(), handler->GetConvFile());
+
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+
+ if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
+ {
+ ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
+ ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
+ ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
+ }
+ else
+ ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ ::OutputIndentation(stream, indent);
+ }
+ ::OutputString(stream, wxT("</text>"), handler->GetConvMem(), handler->GetConvFile());
+ }
+ }
+
+
+ // Output this character as a number in a separate tag, because XML can't cope
+ // with entities below 32 except for 10 and 13
+ last = i + 1;
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<symbol"), handler->GetConvMem(), handler->GetConvFile());
+
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+ ::OutputString(stream, wxString::Format(wxT("%d"), c), handler->GetConvMem(), handler->GetConvFile());
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ ::OutputIndentation(stream, indent);
+ }
+ ::OutputString(stream, wxT("</symbol>"), handler->GetConvMem(), handler->GetConvFile());
+ }
+ }
+
+ wxString fragment;
+ if (last == 0)
+ fragment = text;
+ else
+ fragment = text.Mid(last, i-last);
+
+ if (last < len)
+ {
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<text"), handler->GetConvMem(), handler->GetConvFile());
+
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ ::OutputIndentation(stream, indent);
+ }
+
+ if (!fragment.empty() && (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' ')))
+ {
+ ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
+ ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
+ ::OutputString(stream, wxT("\""), handler->GetConvMem(), handler->GetConvFile());
+ }
+ else
+ ::OutputStringEnt(stream, fragment, handler->GetConvMem(), handler->GetConvFile());
+
+ ::OutputString(stream, wxT("</text>"), handler->GetConvMem(), handler->GetConvFile());
+ }
+ return true;
+}
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+// Export this object to the given parent node, usually creating at least one child node.
+bool wxRichTextPlainText::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
+{
+ int i;
+ int last = 0;
+ const wxString& text = GetText();
+ int len = (int) text.Length();
+
+ if (len == 0)
+ {
+ i = 0;
+
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
+ parent->AddChild(elementNode);
+
+ handler->AddAttributes(elementNode, GetAttributes(), false);
+ handler->WriteProperties(elementNode, GetProperties());
+ }
+ else for (i = 0; i < len; i++)
+ {
+#if wxUSE_UNICODE
+ int c = (int) text[i];
+#else
+ int c = (int) wxUChar(text[i]);
+#endif
+ if ((c < 32 || c == 34) && c != 10 && c != 13)
+ {
+ if (i > 0)
+ {
+ wxString fragment(text.Mid(last, i-last));
+ if (!fragment.empty())
+ {
+ // TODO: I'm assuming wxXmlDocument will output quotes if necessary
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
+ parent->AddChild(elementNode);
+ handler->AddAttributes(elementNode, GetAttributes(), false);
+ handler->WriteProperties(elementNode, GetProperties());
+
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ elementNode->AddChild(textNode);
+
+ if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))
+ fragment = wxT("\"") + fragment + wxT("\"");
+
+ textNode->SetContent(fragment);
+ }
+ }
+
+
+ // Output this character as a number in a separate tag, because XML can't cope
+ // with entities below 32 except for 10 and 13
+
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("symbol"));
+ parent->AddChild(elementNode);
+
+ handler->AddAttributes(elementNode, GetAttributes(), false);
+ handler->WriteProperties(elementNode, GetProperties());
+
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ elementNode->AddChild(textNode);
+ textNode->SetContent(wxString::Format(wxT("%d"), c));
+
+ last = i + 1;
+ }
+ }
+
+ wxString fragment;
+ if (last == 0)
+ fragment = text;
+ else
+ fragment = text.Mid(last, i-last);
+
+ if (last < len)
+ {
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("text"));
+ parent->AddChild(elementNode);
+ handler->AddAttributes(elementNode, GetAttributes(), false);
+
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ elementNode->AddChild(textNode);
+
+ if (fragment[0] == wxT(' ') || fragment[fragment.length()-1] == wxT(' '))
+ fragment = wxT("\"") + fragment + wxT("\"");
+
+ textNode->SetContent(fragment);
+ }
+ return true;
+}
+#endif
+
+
+// Import this object from XML
+bool wxRichTextImage::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler)
+{
+ wxRichTextObject::ImportFromXML(buffer, node, handler);
+
+ wxBitmapType imageType = wxBITMAP_TYPE_PNG;
+ wxString value = node->GetAttribute(wxT("imagetype"), wxEmptyString);
+ if (!value.empty())
+ {
+ int type = wxAtoi(value);
+
+ // note: 0 == wxBITMAP_TYPE_INVALID
+ if (type <= 0 || type >= wxBITMAP_TYPE_MAX)
+ {
+ wxLogWarning("Invalid bitmap type specified for <image> tag: %d", type);
+ }
+ else
+ {
+ imageType = (wxBitmapType)type;
+ }
+ }
+
+ wxString data;
+
+ wxXmlNode* imageChild = node->GetChildren();
+ while (imageChild)
+ {
+ wxString childName = imageChild->GetName();
+ if (childName == wxT("data"))
+ {
+ wxXmlNode* dataChild = imageChild->GetChildren();
+ while (dataChild)
+ {
+ data = dataChild->GetContent();
+ // wxLogDebug(data);
+ dataChild = dataChild->GetNext();
+ }
+
+ }
+ imageChild = imageChild->GetNext();
+ }
+
+ if (!data.empty())
+ {
+ wxStringInputStream strStream(data);
+
+ GetImageBlock().ReadHex(strStream, data.length(), imageType);
+
+ return true;
+ }
+ else
+ return false;
+}
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+// Export this object directly to the given stream.
+bool wxRichTextImage::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
+{
+ wxString style = handler->AddAttributes(GetAttributes(), false);
+
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<image"), handler->GetConvMem(), handler->GetConvFile());
+ if (!GetImageBlock().Ok())
+ {
+ // No data
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+ }
+ else
+ {
+ ::OutputString(stream, wxString::Format(wxT(" imagetype=\"%d\""), (int) GetImageBlock().GetImageType()) + style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+ }
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ ::OutputIndentation(stream, indent);
+ }
+
+ ::OutputIndentation(stream, indent+1);
+ ::OutputString(stream, wxT("<data>"), handler->GetConvMem(), handler->GetConvFile());
+
+ // wxStopWatch stopwatch;
+
+ GetImageBlock().WriteHex(stream);
+
+ // wxLogDebug(wxT("Image conversion to hex took %ldms"), stopwatch.Time());
+
+ ::OutputString(stream, wxT("</data>\n"), handler->GetConvMem(), handler->GetConvFile());
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("</image>"), handler->GetConvMem(), handler->GetConvFile());
+ return true;
+}
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+// Export this object to the given parent node, usually creating at least one child node.
+bool wxRichTextImage::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
+{
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("image"));
+ parent->AddChild(elementNode);
+
+ if (GetImageBlock().Ok())
+ elementNode->AddAttribute(wxT("imagetype"), MakeString((int) GetImageBlock().GetImageType()));
+
+ handler->AddAttributes(elementNode, GetAttributes(), false);
+ handler->WriteProperties(elementNode, GetProperties());
+
+ wxXmlNode* dataNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("data"));
+ elementNode->AddChild(dataNode);
+ wxXmlNode* textNode = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"));
+ dataNode->AddChild(textNode);
+
+ wxString strData;
+#if 1
+ {
+ wxMemoryOutputStream stream;
+ if (GetImageBlock().WriteHex(stream))
+ {
+ if (stream.GetSize() > 0)
+ {
+ int size = stream.GetSize();
+ int size2 = stream.GetOutputStreamBuffer()->GetIntPosition();
+ wxASSERT(size == size2);
+
+ unsigned char* data = new unsigned char[size];
+ stream.CopyTo(data, size);
+ strData = wxString((const char*) data, wxConvUTF8, size);
+ delete[] data;
+ }
+ else
+ strData = wxEmptyString;
+ }
+
+ }
+#else
+ {
+ wxStringOutputStream strStream(& strData);
+ GetImageBlock().WriteHex(strStream);
+ }
+#endif
+
+ textNode->SetContent(strData);
+ textNode->SetNoConversion(true); // optimize speed
+
+ return true;
+}
+#endif
+
+
+// Import this object from XML
+bool wxRichTextParagraphLayoutBox::ImportFromXML(wxRichTextBuffer* buffer, wxXmlNode* node, wxRichTextXMLHandler* handler)
+{
+ wxRichTextObject::ImportFromXML(buffer, node, handler);
+
+ wxString partial = node->GetAttribute(wxT("partialparagraph"), wxEmptyString);
+ if (partial == wxT("true"))
+ SetPartialParagraph(true);
+
+ return true;
+}
+
+#if wxRICHTEXT_HAVE_DIRECT_OUTPUT
+// Export this object directly to the given stream.
+bool wxRichTextParagraphLayoutBox::ExportXML(wxOutputStream& stream, int indent, wxRichTextXMLHandler* handler)
+{
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("<paragraphlayout"), handler->GetConvMem(), handler->GetConvFile());
+
+ wxString style = handler->AddAttributes(GetAttributes(), true);
+
+ if (GetPartialParagraph())
+ style << wxT(" partialparagraph=\"true\"");
+
+ ::OutputString(stream, style + wxT(">"), handler->GetConvMem(), handler->GetConvFile());
+
+ if (GetProperties().GetCount() > 0)
+ {
+ handler->WriteProperties(stream, GetProperties(), indent);
+ }
+
+ size_t i;
+ for (i = 0; i < GetChildCount(); i++)
+ {
+ wxRichTextObject* child = GetChild(i);
+ child->ExportXML(stream, indent+1, handler);
+ }
+
+ ::OutputIndentation(stream, indent);
+ ::OutputString(stream, wxT("</paragraphlayout>"), handler->GetConvMem(), handler->GetConvFile());
+ return true;
+}
+#endif
+
+#if wxRICHTEXT_HAVE_XMLDOCUMENT_OUTPUT
+// Export this object to the given parent node, usually creating at least one child node.
+bool wxRichTextParagraphLayoutBox::ExportXML(wxXmlNode* parent, wxRichTextXMLHandler* handler)
+{
+ wxXmlNode* elementNode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("paragraphlayout"));
+ parent->AddChild(elementNode);
+ handler->AddAttributes(elementNode, GetAttributes(), true);
+ handler->WriteProperties(elementNode, GetProperties());
+
+ if (GetPartialParagraph())
+ elementNode->AddAttribute(wxT("partialparagraph"), wxT("true"));
+
+ size_t i;
+ for (i = 0; i < GetChildCount(); i++)
+ {
+ wxRichTextObject* child = GetChild(i);
+ child->ExportXML(elementNode, handler);
+ }
+
+ return true;
+}
+#endif
#endif
// wxUSE_RICHTEXT && wxUSE_XML