--- ie_imp_WordPerfectMetadata.cpp Sat Jun 8 03:59:57 2002 +++ ie_imp_WordPerfect.cpp Sat Jun 8 04:54:44 2002 @@ -1,6 +1,6 @@ /* AbiWord * Copyright (C) 2001 AbiSource, Inc. - * Copyright (C) 2001 William Lachance (wlach@interlog.com) + * Copyright (C) 2001-2002 William Lachance (wlach@interlog.com) * Copyright (C) 2002 Marc Maurer (j.m.maurer@student.utwente.nl) * * This program is free software; you can redistribute it and/or @@ -38,6 +38,7 @@ #include "ut_assert.h" #include "ut_debugmsg.h" #include "ut_math.h" // for rint (font size) +#include "ut_rand.h" #include "xap_Frame.h" #include "xap_EncodingManager.h" @@ -45,15 +46,22 @@ #include "pd_Document.h" #include "pt_Types.h" +#include "fl_AutoLists.h" +#include "fl_AutoNum.h" + #include "ap_Strings.h" #include "ie_imp_WordPerfect.h" + #define X_CheckFileError(v) if (v==EOF) { UT_DEBUGMSG(("X_CheckFileError: %d\n", __LINE__)); return UT_IE_IMPORTERROR; } #define X_CheckFileReadElementError(v) if (v != 1) { UT_DEBUGMSG(("X_CheckFileReadElementError: %d\n", __LINE__)); return UT_IE_IMPORTERROR; } // makes sure that one element is read #define X_CheckDocumentError(v) if (!v) { UT_DEBUGMSG(("X_CheckDocumentError: %d\n", __LINE__)); return UT_IE_IMPORTERROR; } #define X_CheckWordPerfectError(v) if ((v != UT_OK)) { UT_DEBUGMSG(("X_CheckWordPerfectError: %d\n", __LINE__)); return UT_IE_IMPORTERROR; } +// This should probably be defined in pt_Types.h +static const UT_uint32 PT_MAX_ATTRIBUTES = 8; + WordPerfectTextAttributes::WordPerfectTextAttributes() { m_extraLarge = false; @@ -133,6 +141,73 @@ m_hasChildren = hasChildren; } +WordPerfectListDefinition::WordPerfectListDefinition(UT_uint16 outlineHash, unsigned char *numberingMethods) +{ + m_outlineHash = outlineHash; + for (unsigned int i=0; i 32 && readVal < 127 && !m_undoOn) // Standard ASCII characters - { - //UT_DEBUGMSG((" current char = %c \n",(char)readVal)); - UT_GrowBufElement wc = (UT_GrowBufElement) readVal; - m_textBuf.append(&wc, 1); - } - else if(readVal > 0 && readVal < 32 && !m_undoOn) // International Characters + if(readVal > 0 && readVal < 127 && !m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2DisplayReferencing && m_paragraphStyleState !=end) // Standard ASCII characters { - UT_GrowBufElement internationalCharacter = (UT_GrowBufElement) wp_internationalCharacterMapping[(readVal-1)]; - m_textBuf.append( &internationalCharacter, 1); + // FIXME: probably not the smartest move to put a comparison here + if (m_paragraphStyleState == beginPart2Numbering) + { + UT_DEBUGMSG(("WordPerfect: Character during numbering.. assuming right delim\n")); + UT_UCS4Char wc = (UT_UCS4Char) readVal; + m_rightListDelim+=wc; + // (AFAIK WP doesn't do left delimiters on bullets?) + //if (m_paragraphStyleState == beginPart2BeforeNumbering) + // m_leftListDelim+=wc; + //else + } + else + { + UT_GrowBufElement wc; + if (readVal < 32) // International Characters + wc = (UT_GrowBufElement) wp_internationalCharacterMapping[(readVal-1)]; + else // normal ASCII characters + wc = (UT_GrowBufElement) readVal; + m_textBuf.append(&wc, 1); + } + } else - { - + { for (unsigned int i=0; im_func)) (); break; - } + } } } } - UT_DEBUGMSG(("WordPerfect: File Pointer at %i equals or exceeds document length of %i\n", (int)ftell(m_importFile), (int)m_documentEnd)); - + UT_DEBUGMSG(("WordPerfect: File Pointer at %i equals or exceeds document length of %i\n", (int)ftell(m_importFile), (int)m_documentEnd)); + X_CheckWordPerfectError(_flushText()); - + return UT_OK; } @@ -670,16 +803,18 @@ { // (TODO: eliminate a prev space if it's just before this) UT_DEBUGMSG(("WordPerfect: Handling a hard EOL \n")); - if(!m_undoOn) - { - if (!m_bParagraphChanged) + if(!m_undoOn && m_paragraphStyleState != end) + { + // it's a sure sign that we've hit the end of a list if we do a hard end of line inside of one + if (!m_bParagraphChanged) { - X_CheckWordPerfectError(_flushText()); - _appendCurrentParagraphProperties(); + UT_DEBUGMSG(("WordPerfect: Going with option 1\n")); + X_CheckWordPerfectError(_flushText()); + m_numDeferredParagraphBreaks++; } else { - X_CheckWordPerfectError(_flushText()); + X_CheckWordPerfectError(_flushText()); } } @@ -698,11 +833,11 @@ long startPosition = ftell(m_importFile); X_CheckFileReadElementError(fread(&subGroup, sizeof(unsigned char), 1, m_importFile)); - X_CheckFileReadElementError(fread(&size, sizeof(UT_uint16), 1, m_importFile)); // I have no idea WHAT this var. does. but it's there. + X_CheckFileReadElementError(fread(&size, sizeof(UT_uint16), 1, m_importFile)); UT_GrowBufElement wc = 0; - if(!m_undoOn) + if(!m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2Numbering && m_paragraphStyleState !=end) { switch(subGroup) { @@ -767,7 +902,7 @@ } // handles a column group -// (TODO: partially implemented +// (TODO: partially implemented) UT_Error IE_Imp_WordPerfect::_handleColumnGroup() { UT_DEBUGMSG(("WordPerfect: Handling a column group\n")); @@ -778,7 +913,7 @@ X_CheckWordPerfectError(_handleVariableGroupHeader(startPosition, subGroup, size, flags)); - if(!m_undoOn) + if(!m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2Numbering && m_paragraphStyleState !=end) { UT_DEBUGMSG(("WordPerfect: Column subgroup: %d\n", subGroup)); @@ -903,22 +1038,29 @@ long startPosition; unsigned char subGroup, flags; UT_uint16 size; - UT_uint16 nonDeletableInfoSize; X_CheckWordPerfectError(_handleVariableGroupHeader(startPosition, subGroup, size, flags)); - X_CheckFileReadElementError(fread(&nonDeletableInfoSize, sizeof(UT_uint16), 1, m_importFile)); // dispatch to subgroup to handle the rest of the relevant properties within the // group (and thus, read more of the file-- so we keep this even if undo is 'on') - switch (subGroup) - { - case WP_PARAGRAPH_GROUP_JUSTIFICATION: - { - X_CheckWordPerfectError(_handleParagraphGroupJustification()); - m_bParagraphChanged = true; - break; - } - } + if (!m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2Numbering && m_paragraphStyleState !=end) + { + switch (subGroup) + { + case WP_PARAGRAPH_GROUP_JUSTIFICATION: + { + X_CheckWordPerfectError(_handleParagraphGroupJustification()); + m_bParagraphChanged = true; + break; + } + case WP_PARAGRAPH_GROUP_OUTLINE_DEFINE: + { + UT_DEBUGMSG(("WordPerfect: LISTS: Outline Define\n")); + X_CheckWordPerfectError(_handleOutlineDefine()); + break; + } + } + } X_CheckWordPerfectError(_skipGroup(startPosition, size)); @@ -927,7 +1069,7 @@ // handles a style group -// (TODO: not implemented, just skips over it) +// (partially implemented, handles stuff which is relevant to list properties being set) UT_Error IE_Imp_WordPerfect::_handleStyleGroup() { UT_DEBUGMSG(("WordPerfect: Handling a style group\n")); @@ -937,6 +1079,53 @@ unsigned char flags; X_CheckWordPerfectError(_handleVariableGroupHeader(startPosition, subGroup, size, flags)); + + if (!m_undoOn) + { + switch (subGroup) + { + case WP_STYLE_GROUP_PARASTYLE_BEGIN_ON_PART1: + UT_DEBUGMSG(("WordPerfect: Handling para style begin 1 (ON)\n")); + if (m_numDeferredParagraphBreaks > 0) // wordperfect does not consider that a list may cause a paragraph break. we do. + m_numDeferredParagraphBreaks--; + if (m_bParagraphExists) // (if to handle scary case where we start with a paragraph style sequence) + X_CheckWordPerfectError(_flushText()); // flush anything that came before this (especially eol breaks) + m_paragraphStyleState=beginPart1; + m_paragraphStyleMarginLeft = WP_PARAGRAPH_STYLE_MARGIN_LEFT_INCREMENT; + m_paragraphStyleTextIndent = WP_PARAGRAPH_STYLE_TEXT_INDENT_DECREMENT; // WL: this is abi's default (not wordperfect's) -- I think it is better to use abi's + m_bPutativeListHasParagraphNumber = false; + break; + case WP_STYLE_GROUP_PARASTYLE_BEGIN_OFF_PART1: + UT_DEBUGMSG(("WordPerfect: Handling a para style begin 1 (OFF)\n")); + break; + case WP_STYLE_GROUP_PARASTYLE_BEGIN_ON_PART2: + UT_DEBUGMSG(("WordPerfect: Handling a para style begin 2 (ON)\n")); + m_paragraphStyleState = beginPart2BeforeNumbering; + break; + case WP_STYLE_GROUP_PARASTYLE_BEGIN_OFF_PART2: + UT_DEBUGMSG(("WordPerfect: Handling a para style begin 2 (OFF)\n")); + m_paragraphStyleState = styleBody; + if (m_bPutativeListHasParagraphNumber) + { + X_CheckWordPerfectError(_appendCurrentListProperties()); + } + break; + case WP_STYLE_GROUP_PARASTYLE_END_ON: + UT_DEBUGMSG(("WordPerfect: Handling a para style end (ON)\n")); + m_paragraphStyleState = end; + break; + case WP_STYLE_GROUP_PARASTYLE_END_OFF: + UT_DEBUGMSG(("WordPerfect: Handling a parastyle end (OFF)\n")); + if(m_textBuf.getLength() > 0) // don't paste ANYTHING if this paragraph style doesn't have any content + { + X_CheckWordPerfectError(_flushText()); // flush the list item text + } + m_paragraphStyleState = notInStyle; + m_numDeferredParagraphBreaks++; + break; + } + } + X_CheckWordPerfectError(_skipGroup(startPosition, size)); return UT_OK; @@ -980,8 +1169,18 @@ case 26: // 11010b = decimal tab // TODO: fix stupid default implementation of adding just a TAB char without looking what it actually should be { - UT_GrowBufElement wc = '\t'; - m_textBuf.append(&wc, 1); + // we handle things a bit differently in certain parts of wordperfect list parsing + if (m_paragraphStyleState == beginPart1 || m_paragraphStyleState == beginPart2BeforeNumbering) + { + UT_DEBUGMSG(("WordPerfect: Incrementing paragraph style margin left\n")); + m_paragraphStyleMarginLeft += WP_PARAGRAPH_STYLE_MARGIN_LEFT_INCREMENT; + } + else + { + UT_GrowBufElement wc = '\t'; + m_textBuf.append(&wc, 1); + } + } break; default: // something else shouldn't be possible according to the documentation @@ -1054,7 +1253,7 @@ return UT_OK; } -// handles a numbering method group +// handles a number method group // (TODO: not implemented, just skips over it) UT_Error IE_Imp_WordPerfect::_handleNumberingMethodGroup() { @@ -1070,16 +1269,31 @@ } -// handles a display number reference group -// (TODO: not implemented, just skips over it) +// handles a display number reference group: which, as of now, we just use to determine +// where a list bullet starts and ends (but only for numbered lists..) UT_Error IE_Imp_WordPerfect::_handleDisplayNumberReferenceGroup() { - UT_DEBUGMSG(("WordPerfect: Handling a display number rerference group\n")); + UT_DEBUGMSG(("WordPerfect: Handling a display number reference group\n")); unsigned char subGroup, flags; long startPosition; UT_uint16 size; X_CheckWordPerfectError(_handleVariableGroupHeader(startPosition, subGroup, size, flags)); + + switch (subGroup) + { + case WP_DISPLAY_NUMBER_REFERENCE_GROUP_PARAGRAPH_NUMBER_DISPLAY_ON: + UT_DEBUGMSG(("WordPerfect: Display number reference group (about to display number)\n")); + if (m_paragraphStyleState == beginPart2Numbering) + m_paragraphStyleState = beginPart2DisplayReferencing; + break; + case WP_DISPLAY_NUMBER_REFERENCE_GROUP_PARAGRAPH_NUMBER_DISPLAY_OFF: + UT_DEBUGMSG(("WordPerfect: Display number reference group (no longer displaying number)\n")); + if (m_paragraphStyleState == beginPart2DisplayReferencing) + m_paragraphStyleState = beginPart2Numbering; + break; + } + X_CheckWordPerfectError(_skipGroup(startPosition, size)); return UT_OK; @@ -1116,6 +1330,8 @@ return UT_OK; } +// handles a merge group +// (TODO: not implemented, just skips over it) UT_Error IE_Imp_WordPerfect::_handleMergeGroup() { UT_DEBUGMSG(("WordPerfect: Handling a merge group\n")); @@ -1129,6 +1345,8 @@ return UT_OK; } +// handles a box group (which has something to do with wordperfect graphics) +// (TODO: not really implemented, parses a bunch of info, but doesn't do anything with it) UT_Error IE_Imp_WordPerfect::_handleBoxGroup() { UT_DEBUGMSG(("WordPerfect: Handling a box group\n")); @@ -1196,7 +1414,9 @@ int readVal = fgetc(m_importFile); // TODO: handle case that we get eof? X_CheckFileError(readVal); - if(!m_undoOn) + if(!m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2Numbering && + m_paragraphStyleState != beginPart2DisplayReferencing && m_paragraphStyleState != beginPart2AfterNumbering && + m_paragraphStyleState != end) { // flush what's come before this change (even if it's nothing, which // IS a case we have to be worried about in case we are writing the first @@ -1232,7 +1452,9 @@ int readVal = fgetc(m_importFile); // TODO: handle case that we get eof? X_CheckFileError(readVal); - if(!m_undoOn) + if(!m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2Numbering && + m_paragraphStyleState != beginPart2DisplayReferencing && m_paragraphStyleState != beginPart2AfterNumbering && + m_paragraphStyleState != end) { // flush what's come before this change (even if it's nothing, which // IS a case we have to be worried about in case we are writing the first @@ -1258,6 +1480,7 @@ return UT_OK; } +// handles a character group (related to stuff like font size changing and list recognition) UT_Error IE_Imp_WordPerfect::_handleCharacterGroup() { UT_DEBUGMSG(("WordPerfect: Handling a character group\n")); @@ -1277,6 +1500,34 @@ case WP_CHARACTER_GROUP_FONT_SIZE_CHANGE: X_CheckWordPerfectError(_handleFontSizeChange()); break; + case WP_CHARACTER_GROUP_PARAGRAPH_NUMBER_ON: + if (m_paragraphStyleState == beginPart2BeforeNumbering) + { + m_bPutativeListHasParagraphNumber = true; // indicates that a paragraph style really does encapsulate a list + UT_uint16 nonDeletableInfoSize; + UT_uint16 outlineStyleHash; + unsigned char flag; + X_CheckFileReadElementError(fread(&nonDeletableInfoSize, sizeof(UT_uint16), 1, m_importFile)); + X_CheckFileReadElementError(fread(&m_currentOutlineHash, sizeof(UT_uint16), 1, m_importFile)); + X_CheckFileReadElementError(fread(&m_currentListLevel, sizeof(unsigned char), 1, m_importFile)); + X_CheckFileReadElementError(fread(&flag, sizeof(unsigned char), 1, m_importFile)); + UT_DEBUGMSG(("WordPerfect: LISTS Paragraph Number ON (outlineStyleHash: %i, level: %i, flag: %i)\n", (int)m_currentOutlineHash, (int)m_currentListLevel, (int) flag)); + // first, find the correct list definition + WordPerfectListDefinition *listDefinition = _getListDefinition(m_currentOutlineHash); + if( listDefinition == NULL ) + return UT_ERROR; + X_CheckWordPerfectError(_updateDocumentListDefinition(listDefinition, m_currentListLevel)); + if (listDefinition->isLevelNumbered(m_currentListLevel)) + listDefinition->incrementLevelNumber(m_currentListLevel); + m_currentListTag = UT_rand(); + m_paragraphStyleState = beginPart2Numbering; + } + break; + case WP_CHARACTER_GROUP_PARAGRAPH_NUMBER_OFF: + UT_DEBUGMSG(("WordPerfect: LISTS Paragraph Number OFF\n")); + if (m_paragraphStyleState == beginPart2Numbering || m_paragraphStyleState == beginPart2DisplayReferencing) + m_paragraphStyleState = beginPart2AfterNumbering; + break; default: break; } @@ -1379,7 +1630,7 @@ int characterSet = fgetc(m_importFile); X_CheckFileError(characterSet); - if(!m_undoOn) + if(!m_undoOn && m_paragraphStyleState != beginPart2BeforeNumbering && m_paragraphStyleState != beginPart2Numbering && m_paragraphStyleState != beginPart2AfterNumbering && m_paragraphStyleState !=end) { // TODO: hack, hack, hack // find out how to reliably map ALL characters between character sets and extended characters @@ -1410,6 +1661,9 @@ return UT_OK; } +// handles a font face change +// (supposedly, not really actually, we parse a bunch of information but don't do anything with it yet-- abi's font system +// is too fucked at the moment to make it worth bothering with -WL) UT_Error IE_Imp_WordPerfect::_handleFontFaceChange() { UT_DEBUGMSG(("WordPerfect: Handling a Font Face Change\n")); @@ -1433,13 +1687,15 @@ UT_DEBUGMSG(("WordPerfect: Got this font face change info: (num PIDS: %i, font descriptor PID: %i, old matched point size: %i, hash: %i, matched font index: %i, matched font point size: %i)\n", (int) numPIDs, (int) fontDescriptorPID, (int) oldMatchedPointSize, (int) hash, (int) matchedFontIndex, (int) matchedFontPointSize)); - m_textAttributes.m_fontSize = (UT_uint16) rint((double)((((float)matchedFontPointSize)/100.0f)*2.0f)); // fixme: ghastly magic numbers; + m_textAttributes.m_fontSize = (UT_uint16) rint((double)((((float)matchedFontPointSize)/100.0f)*2.0f)); // fixme: ghastly magic numbers; X_CheckWordPerfectError(_flushText()); X_CheckWordPerfectError(_appendCurrentTextProperties()); return UT_OK; } +// handles a font size change +// FIXME: we could be more precise about this.. UT_Error IE_Imp_WordPerfect::_handleFontSizeChange() { UT_DEBUGMSG(("WordPerfect: Handling a Font Size Change\n")); @@ -1470,10 +1726,12 @@ return UT_OK; } +// _handleUndo: handles a wordperfect undo group, which defines area of text which are "invalid" +// we basically handle this by skipping over any text which wordperfect deems invalid UT_Error IE_Imp_WordPerfect::_handleUndo() { - // this function isn't very well documented and could very well be buggy - // it is based off of my interpretation of a single test file + // this function isn't very well documented + // but this seems to work fine after repeated testing UT_DEBUGMSG(("WordPerfect: Handling an undo group\n")); long startPosition = ftell(m_importFile); @@ -1496,42 +1754,90 @@ return UT_OK; } +// handles a paragraph justification (e.g.: manipulating how a paragraph is positioned) UT_Error IE_Imp_WordPerfect::_handleParagraphGroupJustification() { UT_DEBUGMSG(("WordPerfect: Handling a paragraph group's justification\n")); + UT_uint16 nonDeletableInfoSize; // we don't really care about this.. + X_CheckFileReadElementError(fread(&nonDeletableInfoSize, sizeof(UT_uint16), 1, m_importFile)); + unsigned char paragraphJustification; X_CheckFileReadElementError(fread(¶graphJustification, sizeof(unsigned char), 1, m_importFile)); - if(!m_undoOn) - { - switch(paragraphJustification) - { - case WP_PARAGRAPH_GROUP_JUSTIFICATION_LEFT: - m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::left; - break; - case WP_PARAGRAPH_GROUP_JUSTIFICATION_FULL: - m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::full; - break; - case WP_PARAGRAPH_GROUP_JUSTIFICATION_CENTER: - m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::center; - break; - case WP_PARAGRAPH_GROUP_JUSTIFICATION_RIGHT: - m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::right; - break; - case WP_PARAGRAPH_GROUP_JUSTIFICATION_FULL_ALL_LINES: - m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::fullAllLines; - break; - case WP_PARAGRAPH_GROUP_JUSTIFICATION_RESERVED: - m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::reserved; - break; - } - UT_DEBUGMSG(("WordPerfect: Paragraph Justification is now: %i\n", paragraphJustification)); + switch(paragraphJustification) + { + case WP_PARAGRAPH_GROUP_JUSTIFICATION_LEFT: + m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::left; + break; + case WP_PARAGRAPH_GROUP_JUSTIFICATION_FULL: + m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::full; + break; + case WP_PARAGRAPH_GROUP_JUSTIFICATION_CENTER: + m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::center; + break; + case WP_PARAGRAPH_GROUP_JUSTIFICATION_RIGHT: + m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::right; + break; + case WP_PARAGRAPH_GROUP_JUSTIFICATION_FULL_ALL_LINES: + m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::fullAllLines; + break; + case WP_PARAGRAPH_GROUP_JUSTIFICATION_RESERVED: + m_paragraphProperties.m_justificationMode = WordPerfectParagraphProperties::reserved; + break; } + UT_DEBUGMSG(("WordPerfect: Paragraph Justification is now: %i\n", paragraphJustification)); return UT_OK; } +// _handleOutlineDefine: parses a WordPerfect outline definition, creates an importer-temporary list definition and stores it for later use +// Outline Definitions are used to define "lists" in WordPerfect +UT_Error IE_Imp_WordPerfect::_handleOutlineDefine() +{ + unsigned char numPrefixIDs; + UT_uint16 outlineStylePID; + UT_uint16 paragraphStylePIDs[WP_NUM_LIST_LEVELS]; // seemingly useless + UT_uint16 nonDeletableInfoSize; + UT_uint16 definitionHash; + UT_uint16 numberingMethods[WP_NUM_LIST_LEVELS]; + unsigned char outlineFlags; + unsigned char tabBehaviourFlag; + + X_CheckFileReadElementError(fread(&numPrefixIDs, sizeof(unsigned char), 1, m_importFile)); + X_CheckFileReadElementError(fread(&outlineStylePID, sizeof(UT_uint16), 1, m_importFile)); + for (unsigned int i=0; igetOutlineHash() == definitionHash ) + { + tempListDefinition->resetListIDsAndNumbers(); + tempListDefinition->updateListTypes(numberingMethods); + return UT_OK; + } + } + + // couldn't find the list definition matching the outline hash. this is scary, abort. + return UT_ERROR; +} + + // _handleVariableGroupHeader: gets the info common to all groups UT_Error IE_Imp_WordPerfect::_handleVariableGroupHeader(long &startPosition, unsigned char &subGroup, UT_uint16 &size, unsigned char &flags) { @@ -1559,14 +1865,23 @@ UT_Error IE_Imp_WordPerfect::_flushText() { UT_DEBUGMSG(("WordPerfect: Flushing Text\n")); - + + // place any deferred paragraph breaks in now + while (m_numDeferredParagraphBreaks > 0) + { + UT_DEBUGMSG(("WordPerfect: Placing in a deferred paragraph break\n")); + _appendCurrentParagraphProperties(); + m_numDeferredParagraphBreaks--; + } + // append the current paragraph properties, but only when the paragraph properties - // have changed or there is no paragraph at all + // have changed or there is no paragraph at all (and there is text to flush) if(m_bParagraphChanged || (!m_bParagraphExists)) { + UT_DEBUGMSG(("WordPerfect: Appending Paragraph Properties\n")); _appendCurrentParagraphProperties(); } - + if(m_textBuf.getLength() > 0) X_CheckDocumentError(getDoc()->appendSpan((UT_UCSChar *)m_textBuf.getPointer(0), m_textBuf.getLength())); m_textBuf.truncate(0); @@ -1575,10 +1890,102 @@ return UT_OK; } +// insert the text in the current textbuf to the document, taking its +// style into account +UT_Error IE_Imp_WordPerfect::_appendCurrentListProperties() +{ + UT_DEBUGMSG(("WordPerfect: Appending Current List Properties (outline hash: %i)\n", m_currentOutlineHash)); + + WordPerfectListDefinition *listDefinition = _getListDefinition(m_currentOutlineHash); + if (listDefinition == NULL) + return UT_ERROR; + + UT_String szListID; + UT_String szParentID; + UT_String szLevel; + UT_String_sprintf(szListID,"%d",listDefinition->getListID(m_currentListLevel)); + if (m_currentListLevel > 0) + UT_String_sprintf(szParentID,"%d", listDefinition->getListID((m_currentListLevel-1))); + else + UT_String_sprintf(szParentID,"0"); + UT_String_sprintf(szLevel,"%d", (m_currentListLevel+1)); + + const XML_Char* listAttribs[PT_MAX_ATTRIBUTES*2 + 1]; + UT_uint32 attribsCount=0; + + listAttribs[attribsCount++] = PT_LISTID_ATTRIBUTE_NAME; + listAttribs[attribsCount++] = szListID.c_str(); + listAttribs[attribsCount++] = PT_PARENTID_ATTRIBUTE_NAME; + listAttribs[attribsCount++] = szParentID.c_str(); + listAttribs[attribsCount++] = PT_LEVEL_ATTRIBUTE_NAME; + listAttribs[attribsCount++] = szLevel.c_str(); + + // Now handle the Abi List properties + UT_String propBuffer; + UT_String tempBuffer; + UT_String_sprintf(tempBuffer,"list-style:%d;", listDefinition->getListType(m_currentListLevel)); + propBuffer += tempBuffer; + // FIXME: writing the list delimiter is kind of tricky and silly (because wordperfect wants to define + // it within the document, while abi wants to (sensibly probably) define it in the list definition) + // (we reset it each time but only for numbered lists) + if (listDefinition->isLevelNumbered(m_currentListLevel)) + { + UT_DEBUGMSG(("WordPerfect: Appending this list delim: %s\n", m_rightListDelim.c_str())); + listDefinition->setListRightDelimText(m_currentListLevel, m_rightListDelim.c_str()); + X_CheckWordPerfectError(_updateDocumentListDefinition(listDefinition, m_currentListLevel)); + } + if (listDefinition->getListType(m_currentListLevel) == BULLETED_LIST) + UT_String_sprintf(tempBuffer, "field-font:Symbol; "); + else + UT_String_sprintf(tempBuffer, "field-font:NULL; "); + propBuffer += tempBuffer; + UT_String_sprintf(tempBuffer, "start-value:%i; ", listDefinition->getListNumber(m_currentListLevel)); + propBuffer += tempBuffer; + UT_String_sprintf(tempBuffer, "text-indent:%fin; ", m_paragraphStyleTextIndent); + propBuffer += tempBuffer; + UT_String_sprintf(tempBuffer, "margin-left:%fin", m_paragraphStyleMarginLeft); + propBuffer += tempBuffer; + listAttribs[attribsCount++] = PT_PROPS_ATTRIBUTE_NAME; + listAttribs[attribsCount++] = propBuffer.c_str(); + listAttribs[attribsCount++] = NULL; + + if ( (!m_bInSection) || m_bSectionChanged) + X_CheckWordPerfectError(_appendSection ()); + + X_CheckDocumentError(getDoc()->appendStrux(PTX_Block, listAttribs)); + + UT_DEBUGMSG(("WordPerfect: LISTS - Appended a list attributes section (text-indent: %f, margin-left:%f)\n", m_paragraphStyleTextIndent, m_paragraphStyleMarginLeft)); + + // hang text off of a list label + X_CheckWordPerfectError(_appendCurrentTextProperties()); + getDoc()->appendFmtMark(); + m_currentListTag = 0; + UT_DEBUGMSG(("WordPerfect: LISTS - Appended a list tag def'n (character props)\n")); + + // append a list field label + const XML_Char* fielddef[3]; + fielddef[0] ="type"; + fielddef[1] = "list_label"; + fielddef[2] = NULL; + X_CheckDocumentError(getDoc()->appendObject(PTO_Field,fielddef)); + UT_DEBUGMSG(("WordPerfect: LISTS - Appended a field def'n\n")); + + //X_CheckWordPerfectError(_appendCurrentTextProperties()); + X_CheckWordPerfectError(_appendCurrentTextProperties()); + + m_bParagraphExists = true; // in case we start the document with a list + m_bParagraphChanged = false; // we already changed the paragraph here, so don't go around saying it hasn't been changed when we flush the text + + //m_leftListDelim.clear(); + m_rightListDelim.clear(); + + return UT_OK; +} + UT_Error IE_Imp_WordPerfect::_appendCurrentTextProperties() { UT_DEBUGMSG(("WordPerfect: Appending current text properties\n")); - + XML_Char* pProps = "props"; UT_String propBuffer; UT_String tempBuffer; @@ -1620,12 +2027,26 @@ UT_String_sprintf(tempBuffer, "; font-size:%spt", std_size_string((float)m_textAttributes.m_fontSize)); propBuffer += tempBuffer; + if(m_currentListTag != 0) + { + // List Tag to hang lists off + UT_String_sprintf(tempBuffer, "; list-tag:%d", m_currentListTag); + propBuffer += tempBuffer; + } + UT_DEBUGMSG(("Appending Format: %s\n", propBuffer.c_str())); - const XML_Char* propsArray[3]; + const XML_Char* propsArray[5]; + propsArray[0] = pProps; propsArray[1] = propBuffer.c_str(); propsArray[2] = NULL; - + if (m_bPutativeListHasParagraphNumber) + { + propsArray[2] ="type"; + propsArray[3] = "list_label"; + propsArray[4] = NULL; + } + X_CheckDocumentError(getDoc()->appendFmt(propsArray)); return UT_OK; @@ -1725,5 +2146,60 @@ m_bInSection = true; m_bSectionChanged = false; m_bParagraphInSection = false; + return UT_OK; +} + +WordPerfectListDefinition * IE_Imp_WordPerfect::_getListDefinition(UT_uint16 outlineHash) +{ + for (UT_uint32 i=0; igetOutlineHash() == outlineHash ) + { + return tempListDefinition; + } + } + + return NULL; +} + +UT_Error IE_Imp_WordPerfect::_updateDocumentListDefinition(WordPerfectListDefinition *listDefinition, int level) +{ + // add a list definition to the current document, if necessary + if (listDefinition->getListID(level) == 0) + listDefinition->setListID(level, UT_rand()); + + // finally, set the document's list identification info.. + // FIXME: AbiWord doesn't support different types of lists being appended to their parents.. so we just have to stick with what level 0 provides + int startingNumber; + if (listDefinition->getListType(0) == BULLETED_LIST) // REPLACE WITH (WHEN FIXED IN ABI): if (listDefinition->getListType(level) == BULLETED_LIST) + startingNumber = 0; + else + startingNumber = 1; + fl_AutoNum * pAuto = getDoc()->getListByID(listDefinition->getListID(level)); + // not in document yet, we should create a list for it + if (pAuto == NULL) + { + if (level > 0) + { + // REPLACE WITH (WHEN FIXED IN ABI): pAuto = new fl_AutoNum(listDefinition->getListID(level), listDefinition->getListID((level-1)), listDefinition->getListType(level), startingNumber, (XML_Char *)"%L", ".", getDoc()); + pAuto = new fl_AutoNum(listDefinition->getListID(level), listDefinition->getListID((level-1)), listDefinition->getListType(0), startingNumber, (XML_Char *)listDefinition->getListDelim(level).c_str(), ".", getDoc()); + } + else + pAuto = new fl_AutoNum(listDefinition->getListID(level), 0, listDefinition->getListType(level), startingNumber, (XML_Char *)listDefinition->getListDelim(level).c_str(), ".", getDoc()); + + getDoc()->addList(pAuto); + } + // we should update what we have + else + { + + // ADD (WHEN FIXED IN ABI): pAuto->setListType(listDefinition->getListType(level)); + pAuto->setStartValue(startingNumber); + pAuto->setDelim((XML_Char *)listDefinition->getListDelim(level).c_str()); + } + + pAuto->fixHierarchy(); + return UT_OK; }