Search code examples
c++wxwidgets

Clipboard - copy/paste of custom data type randomly works


The interaction with the clipboard is randomly successful. Below code adds different formats to clipboard:

std::pair<wxGridCellCoords, wxGridCellCoords> AddSelToClipbrd(const WorksheetBase* ws)
{
    //some code
    wxString HTMLStr = GenerateHTMLTable(ws, TL, BR);
    wxString XMLStr = xml::GenerateXMLString(ws, TL, BR);
    wxString TabStr = GenerateTabString(ws, TL, BR);

    wxDataObjectComposite* dataobj = new wxDataObjectComposite();
    dataobj->Add(new xml::XMLDataObject(XMLStr), true);
    dataobj->Add(new wxTextDataObject(TabStr));
    dataobj->Add(new wxHTMLDataObject(HTMLStr));

    if (wxTheClipboard->Open())
    {
        wxTheClipboard->SetData(dataobj);
        wxTheClipboard->Flush();
        wxTheClipboard->Close();
    }
}

The XMLDataFormat is implemented as follows:

export struct XMLDataFormat : public wxDataFormat
{
    XMLDataFormat() : wxDataFormat("XMLDataFormat") {}
};


export class XMLDataObject : public wxDataObjectSimple
{

public:
    XMLDataObject(const wxString& xmlstring = wxEmptyString) :
        wxDataObjectSimple(), m_XMLString{ xmlstring }
    {
        SetFormat(XMLDataFormat());
    }

    size_t GetLength() const 
    {
        std::string s = (const char*)m_XMLString.mb_str(wxConvUTF8);
        return  s.length() + 1;
    }

    wxString GetXML() const {
        return m_XMLString;
    }

    void SetXML(const wxString& xml) {
        m_XMLString = xml;
    }

    // Must provide overloads to avoid hiding them (and warnings about it)
    size_t GetDataSize() const {
        return GetLength();
    }

    bool GetDataHere(void* buf) const
    {
        std::string s = (const char*)m_XMLString.mb_str(wxConvUTF8);
        memcpy(buf, s.c_str(), s.length() + 1);
        return true;
    }

    bool SetData(size_t len, const void* buf) {
        m_XMLString = wxString::FromUTF8((const char*)buf, len + 1);
        return true;
    }

    size_t GetDataSize(const wxDataFormat&) const {
        return GetDataSize();
    }

    bool GetDataHere(const wxDataFormat&, void* buf) const {
        return GetDataHere(buf);
    }

    bool SetData(const wxDataFormat&, size_t len, const void* buf)
    {
        return SetData(len, buf);
    }

private:
    wxString m_XMLString;
};

To get the XML data from the clipboard:

wxString GetXMLData()
{
    if (!wxTheClipboard->Open())
        return wxEmptyString;

    if (!wxTheClipboard->IsSupported(XMLDataFormat()))
            return wxEmptyString;

    XMLDataObject xmlObj;

    wxTheClipboard->GetData(xmlObj);
    wxTheClipboard->Close();

    return xmlObj.GetXML();
}

The problem seems to be that GetXMLData returns empty string but this is random; so I run the application and it gives error and then quit the application and run it again (same copy/paste) and it pastes (always tested with the same data).

Any ideas appreciated.


Solution

  • It seems the error comes from implementation of XMLDataObject. Therefore, instead of deriving from wxDataObjectSimple now it is changed to wxTextDataObject and so far it works stable.

    So the new implementation is as simple as the following:

    export struct XMLDataFormat : public wxDataFormat
    {
        XMLDataFormat() : wxDataFormat("XMLDataFormat") {}
    };
    
    
    export class XMLDataObject : public wxTextDataObject
    {
    
    public:
        XMLDataObject(const std::string& UTF8 = "") :
            wxTextDataObject(UTF8)
        {
            SetFormat(XMLDataFormat());
        }
    };