void ODe_AbiDocListener::_closeBookmark(UT_UTF8String &sBookmarkName) {
    if (!m_bInBookmark || sBookmarkName.empty())
        return;

    _closeSpan();

    m_pCurrentImpl->closeBookmark(sBookmarkName);
    m_bInBookmark = false;
    m_bookmarkName.clear();
}
void ODe_DocumentData::handleDefaultTabInterval(ODe_Style_Style* pStyle) {
    UT_return_if_fail(pStyle);
    
    UT_UTF8String defaultTabInterval = pStyle->getDefaultTabInterval();
    if (defaultTabInterval.empty())
        return;

    // remove the default tab interval property from the style
    pStyle->setDefaultTabInterval("");

    // ... and create a default style to hold the default tab interval property
    ODe_Style_Style* pDefaultStyle = m_styles.getDefaultStyles().getStyle("paragraph");
    if (!pDefaultStyle) {
        pDefaultStyle = new ODe_Style_Style();
        pDefaultStyle->setFamily("paragraph");
        pDefaultStyle->makeDefaultStyle();
        m_styles.getDefaultStyles().storeStyle("paragraph", pDefaultStyle);
    }
    // NOTE: if a paragraph default style already exists with a default tab interval
    // property set, then we'll just overwrite it. This can happen because AbiWord 
    // supports such a property on every paragraph and paragraph style, but ODT only 
    // supports one on the default paragraph style.
    pDefaultStyle->setDefaultTabInterval(defaultTabInterval);
}
bool ODe_MetaDataWriter::writeMetaData(PD_Document* pDoc, GsfOutfile* oo) {
    
    GsfOutput* meta = gsf_outfile_new_child (oo, "meta.xml", FALSE);

    static const UT_UTF8String preamble =
        UT_UTF8String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        "<office:document-meta"
            " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""
            " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
            " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
            " xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\""
            " xmlns:ooo=\"http://openoffice.org/2004/office\""
            " office:version=\"1.1\">\n"
        "<office:meta>\n"
        "<meta:generator>AbiWord/") + PACKAGE_VERSION + " (" + PLATFORM + ", " + TOOLKIT + ")</meta:generator>\n";

    static const char * const postamble [] = {
        "</office:meta>\n",
        "</office:document-meta>\n"
    };

    ODe_writeUTF8String(meta, preamble);

    UT_UTF8String meta_val, val;
    
#define WRITE_METADATA_ELEMENT(abiwordKey, odElementName) if (pDoc->getMetaDataProp(abiwordKey, meta_val) && meta_val.size()) { \
                                                               meta_val.escapeXML(); \
                                                               val = UT_UTF8String_sprintf("<%s>%s</%s>\n", odElementName, meta_val.utf8_str(), odElementName); \
                                                               ODe_writeUTF8String (meta, val); \
                                                          }
    
    WRITE_METADATA_ELEMENT(PD_META_KEY_TITLE, "dc:title");
    WRITE_METADATA_ELEMENT(PD_META_KEY_DESCRIPTION, "dc:description");
    WRITE_METADATA_ELEMENT(PD_META_KEY_SUBJECT, "dc:subject");

    //Each keyword needs to be exported individually:

    UT_UTF8String keywords;
    if (pDoc->getMetaDataProp (PD_META_KEY_KEYWORDS, keywords) && keywords.size())
    {
        UT_UTF8String buf = "";
        UT_UCS4String keyword = keywords.utf8_str();

        for(UT_uint32 i = 0;i < keyword.length(); i++)
        {
            if(keyword[i] != ' ')
            {
                buf += keyword[i];
            }
            else
            {
                if(buf.empty())  //only blank space encountered
                    continue;

                buf.escapeXML();
                val = UT_UTF8String_sprintf("<meta:keyword>%s</meta:keyword>\n", buf.utf8_str());
                ODe_writeUTF8String(meta, val);
                buf.clear();
            }
        }

        if(buf.length())  //there may only be one keyword (i.e. no spaces encountered)
        {
            buf.escapeXML();
            val = UT_UTF8String_sprintf("<meta:keyword>%s</meta:keyword>\n", buf.utf8_str());
            ODe_writeUTF8String(meta, val);
        }
    }

    // Should have a PD_META_KEY_INITIAL_CREATOR macro for this one, but only
    // if it gets implemented on the document properties dialog.
    WRITE_METADATA_ELEMENT("meta:initial-creator", "meta:initial-creator");
    
    WRITE_METADATA_ELEMENT(PD_META_KEY_CREATOR, "dc:creator");
    
    WRITE_METADATA_ELEMENT("meta:printed-by", "meta:printed-by");
    
    // ATTENTION: I'm assuming that dc.date is used by AbiWord as
    // the document creation date & time.
    WRITE_METADATA_ELEMENT(PD_META_KEY_DATE, "meta:creation-date");
    
    // Note that, for the OpenDocument standard, dc.date
    // is the last modification date & time.
    WRITE_METADATA_ELEMENT(PD_META_KEY_DATE_LAST_CHANGED, "dc:date");
    
    WRITE_METADATA_ELEMENT("meta:print-date", "meta:print-date");
    
    WRITE_METADATA_ELEMENT(PD_META_KEY_LANGUAGE, "dc:language");
    
#undef WRITE_METADATA_ELEMENT

    ODe_writeToStream(meta, postamble, G_N_ELEMENTS(postamble));

    ODe_gsf_output_close(meta);

    return true;
}
/**
 * @param ppAtts The attributes of a <draw:text-box> element.
 * @param rAction Any action to be taken, regarding state change.
 */
void ODi_Frame_ListenerState::_drawTextBox (const gchar** ppAtts,
                                           ODi_ListenerStateAction& rAction) {
    const gchar* attribs[3];
    const gchar* pStyleName = NULL;
    const ODi_Style_Style* pGraphicStyle = NULL;
    UT_UTF8String props;
    UT_UTF8String sThickness;
    
    props = "frame-type:textbox";
            
    if (!_getFrameProperties(props, ppAtts)) {
        // Abort mission!

        // <draw:frame>     -  0
        //  <draw:text-box> - -1
        //
        // We want to ignore the whole frame.
        rAction.ignoreElement(0);
        return;
    }
    
    if (!props.empty()) {
        props += "; ";
    }

    if (m_rElementStack.getStartTag(0)) {
        pStyleName = m_rElementStack.getStartTag(0)->getAttributeValue("draw:style-name");
    }

    if (pStyleName) {
        pGraphicStyle = m_pStyles->getGraphicStyle(pStyleName, m_bOnContentStream);
    }

    if (pGraphicStyle) {
        // For now, we'll assume HAVE_BORDER_UNSPECIFIED == HAVE_BORDER_YES
        if (pGraphicStyle->hasBottomBorder() != ODi_Style_Style::HAVE_BORDER_NO) {
            props += "bot-style:1";
            if(pGraphicStyle->getBorderBottom_color() && !pGraphicStyle->getBorderBottom_color()->empty()) {
                props += "; bot-color:";
                props += *(pGraphicStyle->getBorderBottom_color());
            }
        } else {
            props += "bot-style:0";
        }

        if (pGraphicStyle->hasLeftBorder() != ODi_Style_Style::HAVE_BORDER_NO) {
            props += "; left-style:1";
            if(pGraphicStyle->getBorderLeft_color() && !pGraphicStyle->getBorderLeft_color()->empty()) {
                props += "; left-color:";
                props += *(pGraphicStyle->getBorderLeft_color());
            }
        } else {
            props += "; left-style:0";
        }

        if (pGraphicStyle->hasRightBorder() != ODi_Style_Style::HAVE_BORDER_NO) {
            props += "; right-style:1";
            if(pGraphicStyle->getBorderRight_color() && !pGraphicStyle->getBorderRight_color()->empty()) {
                props += "; right-color:";
                props += *(pGraphicStyle->getBorderRight_color());
            }
        } else {
            props += "; right-style:0";
        }

        if (pGraphicStyle->hasTopBorder() != ODi_Style_Style::HAVE_BORDER_NO) {
            props += "; top-style:1";
            if(pGraphicStyle->getBorderTop_color() && !pGraphicStyle->getBorderTop_color()->empty()) {
                props += "; top-color:";
                props += *(pGraphicStyle->getBorderTop_color());
            }
        } else {
            props += "; top-style:0";
        }

        if(pGraphicStyle->getBorderBottom_thickness() && !pGraphicStyle->getBorderBottom_thickness()->empty()) {

            sThickness.clear();
            bool bRet = _convertBorderThickness(pGraphicStyle->getBorderBottom_thickness()->utf8_str(), sThickness);

            if(bRet) {
                props += "; bot-thickness:";
                props += sThickness.utf8_str();
            }
        }

        if(pGraphicStyle->getBorderLeft_thickness() && !pGraphicStyle->getBorderLeft_thickness()->empty()) {

            sThickness.clear();
            bool bRet = _convertBorderThickness(pGraphicStyle->getBorderLeft_thickness()->utf8_str(), sThickness);

            if(bRet) {
                props += "; left-thickness:";
                props += sThickness.utf8_str();
            }
        }

        if(pGraphicStyle->getBorderRight_thickness() && !pGraphicStyle->getBorderRight_thickness()->empty()) {

            sThickness.clear();
            bool bRet = _convertBorderThickness(pGraphicStyle->getBorderRight_thickness()->utf8_str(), sThickness);

            if(bRet) {
                props += "; right-thickness:";
                props += sThickness.utf8_str();
            }
        }

        if(pGraphicStyle->getBorderTop_thickness() && !pGraphicStyle->getBorderTop_thickness()->empty()) {

            sThickness.clear();
            bool bRet = _convertBorderThickness(pGraphicStyle->getBorderTop_thickness()->utf8_str(), sThickness);

            if(bRet) {
                props += "; top-thickness:";
                props += sThickness.utf8_str();
            }
        }


        if(pGraphicStyle->getHorizPos(true) && !pGraphicStyle->getHorizPos(true)->empty()) 
	{
	       props += "; frame-horiz-align:";
	       props += pGraphicStyle->getHorizPos(true)->utf8_str();
            
        }


    } else {  //just hard-code some defaults
        props += "bot-style:1; left-style:1; right-style:1; top-style:1";
    }

    attribs[0] = "props";
    attribs[1] = props.utf8_str();
    attribs[2] = 0;
		   
    if(!m_pAbiDocument->appendStrux(PTX_SectionFrame, attribs)) {
        UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
    } else {
        m_iFrameDepth++;
    }

    // We are going to receive text content.
    rAction.pushState("TextContent");
}
void ODe_AbiDocListener::_outputData(const UT_UCSChar* pData, UT_uint32 length) {
    UT_UTF8String sBuf;
    const UT_UCSChar* p;
    UT_uint32 nSpaces = 0;

    UT_ASSERT(sizeof(UT_Byte) == sizeof(char));
    sBuf.reserve(length);

    for (p=pData; (p<pData+length); /**/)
    {
        switch (*p)
        {
        case '<':
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

            sBuf += "&lt;";
            p++;
            break;

        case '>':
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

            sBuf += "&gt;";
            p++;
            break;

        case '&':
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

            sBuf += "&amp;";
            p++;
            break;

        case ' ':
            nSpaces++;

            if(nSpaces == 1)
                sBuf.appendUCS4 (p, 1);

            p++;
            break;

        case UCS_LF:               // LF -- representing a Forced-Line-Break
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

            m_pCurrentImpl->insertText(sBuf);
            m_pCurrentImpl->insertLineBreak();
            sBuf.clear();
            p++;
            break;

        case UCS_VTAB:             // VTAB -- representing a Forced-Column-Break
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

            m_pCurrentImpl->insertText(sBuf);
            m_pCurrentImpl->insertColumnBreak();
            sBuf.clear();
            p++;
            break;

        case UCS_TAB:
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

			m_pCurrentImpl->insertText(sBuf);
			m_pCurrentImpl->insertTabChar();
			sBuf.clear();
            p++;
            break;

        case UCS_FF:               // FF -- representing a Forced-Page-Break
            if(nSpaces > 1)
                _appendSpaces(&sBuf, nSpaces);
            nSpaces = 0;

            m_pCurrentImpl->insertText(sBuf);
            m_pCurrentImpl->insertPageBreak();
            sBuf.clear();
            p++;
            break;

        default:
            if (*p < 0x20)         // Silently eat these characters.
            {
                if(nSpaces > 1)
                    _appendSpaces(&sBuf, nSpaces);
                nSpaces = 0;
                p++;
            }
            else
            {
                if(nSpaces > 1)
                    _appendSpaces(&sBuf, nSpaces);
                nSpaces = 0;

                sBuf.appendUCS4 (p, 1);
                p++;
            }
        }
    }

    if (!sBuf.empty()) {
        if(nSpaces > 1)
            _appendSpaces(&sBuf, nSpaces);
        nSpaces = 0;
        m_pCurrentImpl->insertText(sBuf);
    }
}
void ODe_AbiDocListener::_insertMath(PT_AttrPropIndex api) {

    const gchar* szMath = NULL;
    szMath = _getObjectKey(api, static_cast<const gchar*>("dataid"));

    UT_return_if_fail(szMath);

    const UT_ByteBuf * pByteBuf = NULL;
    bool bOK = m_pDocument->getDataItemDataByName(szMath, const_cast<const UT_ByteBuf **>(&pByteBuf), NULL, NULL);

    UT_return_if_fail(bOK);

    UT_UCS4_mbtowc myWC;
    UT_UTF8String sMathML;
    sMathML.appendBuf(*pByteBuf, myWC);

    UT_return_if_fail(!sMathML.empty());

    UT_UCS4String buf = sMathML.utf8_str();
    UT_UTF8String output = "";

    const PP_AttrProp * pAP = NULL;
    bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
    UT_LocaleTransactor t(LC_NUMERIC, "C");
    UT_UTF8String dimension;
    double dInch;

    UT_return_if_fail(bHaveProp && pAP);

    _openSpan(api);

    if(pAP->getProperty("width", szMath)) {
        dInch = static_cast<double>(atoi(szMath))/UT_LAYOUT_RESOLUTION;
        UT_UTF8String_sprintf(dimension,"%fin",dInch);
        output += "<draw:frame svg:width=\"";
        output += dimension;
        output += "\" svg:height=\"";
    } else {
        UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
        _closeSpan();
        return;
    }

    if(pAP->getProperty("height", szMath)) {
        dInch = static_cast<double>(atoi(szMath))/UT_LAYOUT_RESOLUTION;
        dimension.clear();
        UT_UTF8String_sprintf(dimension,"%fin",dInch);
        output += dimension;
        output += "\"><draw:object>";
    } else {
        UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
        _closeSpan();
        return;
    }

    for (UT_uint32 i = 0; i < buf.length(); i++) {
        if (buf[i] == '<') {
            if (((i + 1) < buf.length()) && (buf[i+1] == '/')) {
                output += "</math:";
                i++; // skip the '/'
            } else if ((i + 1) < buf.length()) {
                output += "<math:";
            } else {
                UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
            }
        } else {
            output += buf[i];
        }
    }
    output += "</draw:object></draw:frame>";
    m_pCurrentImpl->insertText(output);
    _closeSpan();
}