bool pt_PieceTable::_realInsertSpan(PT_DocPosition dpos, const UT_UCSChar * p, UT_uint32 length, const gchar ** attributes, const gchar ** properties, fd_Field * pField, bool bAddChangeRec) { // insert character data into the document at the given position. UT_return_val_if_fail (m_pts==PTS_Editing, false); // get the fragment at the given document position. pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(dpos,&pf,&fragOffset); UT_return_val_if_fail (bFound,false); // append the text data to the end of the current buffer. PT_BufIndex bi; if (!m_varset.appendBuf(p,length,&bi)) return false; pf_Frag_Strux * pfs = NULL; bool bFoundStrux = _getStruxFromFrag(pf,&pfs); UT_return_val_if_fail (bFoundStrux,false); if(isEndFootnote((pf_Frag *)pfs)) { bFoundStrux = _getStruxFromFragSkip((pf_Frag *) pfs,&pfs); } UT_return_val_if_fail (pfs,false); if(pfs->getStruxType() == PTX_EndFrame) { bFoundStrux = _getStruxFromFragSkip((pf_Frag *) pfs,&pfs); } // we just did a getFragFromPosition() which gives us the // the thing *starting* at that position. if we have a // fragment boundary at that position, it's sort of arbitrary // whether we treat this insert as a prepend to the one we just found // or an append to the previous one (when it's a text frag). // in the normal case, we want the Attr/Prop of a character // insertion to take the AP of the thing to the immediate // left (seems to be what MS-Word and MS-WordPad do). It's also // useful when the user hits the BOLD button (without a) // selection) and then starts typing -- ideally you'd like // all of the text to have bold not just the first. therefore, // we will see if we are on a text-text boundary and backup // (and thus appending) to the previous. bool bNeedGlob = false; PT_AttrPropIndex indexAP = 0; if ( (fragOffset==0) && (pf->getPrev()) ) { bool bRightOfFmtMark = (pf->getPrev()->getType() == pf_Frag::PFT_FmtMark); if (bRightOfFmtMark) { // if we're just to the right of a _FmtMark, we want to replace // it with a _Text frag with the same attr/prop (we // only used the _FmtMark to remember a toggle format // before we had text for it). pf_Frag_FmtMark * pfPrevFmtMark = static_cast<pf_Frag_FmtMark *>(pf->getPrev()); indexAP = pfPrevFmtMark->getIndexAP(); if (_lastUndoIsThisFmtMark(dpos)) { // if the last thing in the undo history is the insertion of this // _FmtMark, then let's remember the indexAP, do an undo, and then // insert the text. this way the only thing remaining in the undo // is the insertion of this text (with no globbing around it). then // a user-undo will undo all of the coalesced text back to this point // and leave the insertion point as if the original InsertFmtMark // had never happened. // // we don't allow consecutive FmtMarks, but the undo may be a // changeFmtMark and thus just re-change the mark frag rather // than actually deleting it. so we loop here to get back to // the original insertFmtMark (this is the case if the user hit // BOLD then ITALIC then UNDERLINE then typed a character). do { undoCmd(); } while (_lastUndoIsThisFmtMark(dpos)); } else { // for some reason, something else has happened to the document // since this _FmtMark was inserted (perhaps it was one that we // inserted when we did a paragraph break and inserted several // to remember the current inline formatting). // // here we have to do it the hard way and use a glob and an // explicit deleteFmtMark. note that this messes up the undo // coalescing. that is, if the user starts typing at this // position and then hits UNDO, we will erase all of the typing // except for the first character. the second UNDO, will erase // the first character and restores the current FmtMark. if the // user BACKSPACES instead of doing the second UNDO, both the // first character and the FmtMark would be gone. // // TODO decide if we like this... // NOTE this causes BUG#431.... :-) bNeedGlob = true; beginMultiStepGlob(); _deleteFmtMarkWithNotify(dpos,pfPrevFmtMark,pfs,&pf,&fragOffset); } // we now need to consider pf invalid, since the fragment list may have // been coalesced as the FmtMarks were deleted. let's recompute them // but with a few shortcuts. bFound = getFragFromPosition(dpos,&pf,&fragOffset); UT_return_val_if_fail (bFound, false); bFoundStrux = _getStruxFromFrag(pf,&pfs); UT_return_val_if_fail (bFoundStrux,false); if(isEndFootnote((pf_Frag *)pfs)) { bFoundStrux = _getStruxFromFragSkip((pf_Frag *)pfs,&pfs); } UT_return_val_if_fail (bFoundStrux, false); xxx_UT_DEBUGMSG(("Got FragStrux at Pos %d \n",pfs->getPos())); // with the FmtMark now gone, we make a minor adjustment so that we // try to append text to the previous rather than prepend to the current. // this makes us consistent with other places in the code. if ( (fragOffset==0) && (pf->getPrev()) && (pf->getPrev()->getType() == pf_Frag::PFT_Text) && pf->getPrev()->getField()== NULL ) { // append to the end of the previous frag rather than prepend to the current one. pf = pf->getPrev(); fragOffset = pf->getLength(); } } else if (pf->getPrev()->getType() == pf_Frag::PFT_Text && pf->getPrev()->getField()==NULL) { pf_Frag_Text * pfPrevText = static_cast<pf_Frag_Text *>(pf->getPrev()); indexAP = pfPrevText->getIndexAP(); // append to the end of the previous frag rather than prepend to the current one. pf = pf->getPrev(); fragOffset = pf->getLength(); } else { indexAP = _chooseIndexAP(pf,fragOffset); // PLAM: This is the list of field attrs that should not inherit // PLAM: to the span following a field. const gchar * pFieldAttrs[12]; pFieldAttrs[0] = "type"; pFieldAttrs[1] = NULL; pFieldAttrs[2] = "param"; pFieldAttrs[3] = NULL; pFieldAttrs[4] = "name"; pFieldAttrs[5] = NULL; pFieldAttrs[6] = "endnote-id"; pFieldAttrs[7] = NULL; pFieldAttrs[8] = NULL; pFieldAttrs[9] = NULL; pFieldAttrs[10] = NULL; pFieldAttrs[11] = NULL; const PP_AttrProp * pAP = NULL; if (!getAttrProp(indexAP, &pAP)) return false; if (pAP->areAnyOfTheseNamesPresent(pFieldAttrs, NULL)) { // We do not want to inherit a char style from a field. pFieldAttrs[8] = "style"; PP_AttrProp * pAPNew = pAP->cloneWithElimination(pFieldAttrs, NULL); if (!pAPNew) return false; pAPNew->markReadOnly(); if (!m_varset.addIfUniqueAP(pAPNew, &indexAP)) return false; } } } else { // is existing fragment a field? If so do nothing // Or should we display a message to the user? if(pf->getField() != NULL) { return false; } indexAP = _chooseIndexAP(pf,fragOffset); } PT_BlockOffset blockOffset = _computeBlockOffset(pfs,pf) + fragOffset; PX_ChangeRecord_Span * pcr = NULL; if(attributes || properties) { // we need to add the attrs and props passed to us ... PT_AttrPropIndex indexNewAP; bool bMerged; bMerged = m_varset.mergeAP(PTC_AddFmt,indexAP,attributes,properties,&indexNewAP,getDocument()); UT_ASSERT_HARMLESS( bMerged ); if(bMerged) indexAP = indexNewAP; } if (!_insertSpan(pf,bi,fragOffset,length,indexAP,pField)) { if (bNeedGlob) endMultiStepGlob(); return false; } // note: because of coalescing, pf should be considered invalid at this point. // create a change record, add it to the history, and notify // anyone listening. pcr = new PX_ChangeRecord_Span(PX_ChangeRecord::PXT_InsertSpan, dpos,indexAP,bi,length, blockOffset, pField); UT_return_val_if_fail (pcr, false); pcr->setDocument(m_pDocument); bool canCoalesce = _canCoalesceInsertSpan(pcr); if (!bAddChangeRec || (canCoalesce && !m_pDocument->isCoalescingMasked())) { if (canCoalesce) m_history.coalesceHistory(pcr); m_pDocument->notifyListeners(pfs,pcr); delete pcr; } else { m_history.addChangeRecord(pcr); m_pDocument->notifyListeners(pfs,pcr); } if (bNeedGlob) endMultiStepGlob(); return true; }
bool pt_PieceTable::_doTheDo(const PX_ChangeRecord * pcr, bool bUndo) { // actually do the work of the undo or redo. m_bDoingTheDo = true; switch (pcr->getType()) { ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// case PX_ChangeRecord::PXT_GlobMarker: DONE(); m_bDoingTheDo = false; return true; ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// case PX_ChangeRecord::PXT_InsertSpan: { const PX_ChangeRecord_Span * pcrSpan = static_cast<const PX_ChangeRecord_Span *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; UT_DEBUGMSG(("_undo insertspan Pos = %d \n",pcr->getPosition())); bool bFound = getFragFromPosition(pcrSpan->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound,false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux = _getStruxFromFrag(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux,false); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux,false); } PT_BlockOffset newOffset = pcrSpan->getPosition() - pfs->getPos() -1; if (!_insertSpan(pf,pcrSpan->getBufIndex(),fragOffset, pcrSpan->getLength(),pcrSpan->getIndexAP(), pcrSpan->getField())) return false; DONE(); pcrSpan->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_DeleteSpan: { // Our deleteSpan is much simpler than the main routine. // We can do this becase the change history is composed // of atomic operations, whereas the main routine has to // to deal with whatever the user chose to do (and cut // it into a series of steps). const PX_ChangeRecord_Span * pcrSpan = static_cast<const PX_ChangeRecord_Span *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrSpan->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound,false); UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_Text,false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux = _getStruxFromFrag(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux, false); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux, false); } UNDO_return_val_if_fail (bFoundStrux, false); UT_sint32 newOffset = pcrSpan->getPosition() - pfs->getPos() -1; //was -2 if(newOffset < 0) newOffset = 0; pf_Frag_Text * pft = static_cast<pf_Frag_Text *> (pf); UNDO_return_val_if_fail (pft->getIndexAP() == pcrSpan->getIndexAP(),false); xxx_UT_DEBUGMSG(("deletespan in _doTheDo length %d \n",pcrSpan->getLength())); UT_uint32 iLenDeleted = fragOffset + pft->getLength(); if(iLenDeleted >= pcrSpan->getLength()) { _deleteSpan(pft,fragOffset,pcrSpan->getBufIndex(),pcrSpan->getLength(),NULL,NULL); } else { pf_Frag_Text * pftNext = static_cast<pf_Frag_Text *>(pft->getNext()); UT_uint32 iLenDel = pft->getLength() - fragOffset; iLenDeleted = 0; while(pft && (pft ->getType() == pf_Frag::PFT_Text) && (iLenDeleted <pcrSpan->getLength()) ) { _deleteSpan(pft,fragOffset,pcrSpan->getBufIndex(),iLenDel,NULL,NULL); pft = pftNext; pftNext = static_cast<pf_Frag_Text *>(pft->getNext()); iLenDeleted += iLenDel; iLenDel = pcrSpan->getLength() - iLenDeleted; if(iLenDel > pft->getLength()) iLenDel = pft->getLength(); fragOffset = 0; } } UT_DEBUGMSG(("newOffset %d spanBlockOffset %d \n",newOffset,pcrSpan->getBlockOffset())); pcrSpan->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); DONE(); } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_ChangeSpan: { // ChangeSpan is it's own inverse. similarly, we have a much simpler // job than the main routine, because we have broken up the user's // request into atomic operations. const PX_ChangeRecord_SpanChange * pcrs = static_cast<const PX_ChangeRecord_SpanChange *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrs->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound, false); UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_Text, false); pf_Frag_Text * pft = static_cast<pf_Frag_Text *> (pf); pf_Frag_Strux * pfs = NULL; bool bFoundStrux = _getStruxFromFrag(pf,&pfs); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux, false); } UNDO_return_val_if_fail (bFoundStrux, false); PT_BlockOffset newOffset = pcrs->getPosition() - pfs->getPos() -1; // we need to loop here, because even though we have a simple (atomic) change, // the document may be fragmented slightly differently (or rather, it may not // yet be possible to coalesce it (until the end of the loop)). pf_Frag * pfEnd; UT_uint32 fragOffsetEnd; UT_uint32 length = pcrs->getLength(); while (length) { UT_uint32 lengthInFrag = pft->getLength() - fragOffset; UT_uint32 lengthThisStep = UT_MIN(lengthInFrag, length); _fmtChangeSpan(pft,fragOffset,lengthThisStep,pcrs->getIndexAP(),&pfEnd,&fragOffsetEnd); length -= lengthThisStep; if (length == 0) break; UNDO_return_val_if_fail (pfEnd->getType() == pf_Frag::PFT_Text, false); pft = static_cast<pf_Frag_Text *> (pfEnd); fragOffset = fragOffsetEnd; } DONE(); pcrs->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// case PX_ChangeRecord::PXT_InsertStrux: { const PX_ChangeRecord_Strux * pcrStrux = static_cast<const PX_ChangeRecord_Strux *>(pcr); pf_Frag_Strux * pfsNew = NULL; if (!_createStrux(pcrStrux->getStruxType(),pcrStrux->getIndexAP(),&pfsNew)) return false; pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFoundFrag = getFragFromPosition(pcrStrux->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFoundFrag, false); // get the strux containing the given position. // TODO see if we can avoid this call to _getStruxFromPosition ?? pf_Frag_Strux * pfsContainer = NULL; bool bFoundContainer = _getStruxFromPosition(pcrStrux->getPosition(),&pfsContainer); UNDO_return_val_if_fail (bFoundContainer,false); if(isEndFootnote(static_cast<pf_Frag *>(pfsContainer))) { bool bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfsContainer),&pfsContainer); UNDO_return_val_if_fail (bFoundStrux, false); } _insertStrux(pf,fragOffset,pfsNew); DONE(); m_pDocument->notifyListeners(pfsContainer,pfsNew,pcr); } return true; case PX_ChangeRecord::PXT_DeleteStrux: { const PX_ChangeRecord_Strux * pcrStrux = static_cast<const PX_ChangeRecord_Strux *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFoundFrag = getFragFromPosition(pcrStrux->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFoundFrag,false); UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_Strux,false); pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux *> (pf); UNDO_return_val_if_fail (pcrStrux->getStruxType() == pfs->getStruxType(),false); bool bResult = _unlinkStrux(pfs,NULL,NULL); m_pDocument->notifyListeners(pfs,pcr); UNDO_return_val_if_fail (bResult,false); DONE(); delete pfs; } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_ChangeStrux: { // ChangeStrux is it's own inverse. const PX_ChangeRecord_StruxChange * pcrs = static_cast<const PX_ChangeRecord_StruxChange *>(pcr); pf_Frag_Strux * pfs; bool bFound = _getStruxFromPosition(pcrs->getPosition(),&pfs); UNDO_return_val_if_fail (bFound,false); bool bResult = _fmtChangeStrux(pfs,pcrs->getIndexAP()); UNDO_return_val_if_fail (bResult,false); DONE(); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// case PX_ChangeRecord::PXT_InsertObject: { const PX_ChangeRecord_Object * pcrObject = static_cast<const PX_ChangeRecord_Object *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrObject->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound, false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux2 = _getStruxFromFrag(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux2, false); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bool bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux,false); } pf_Frag_Object * pfo = NULL; if (!_insertObject(pf,fragOffset,pcrObject->getObjectType(), pcrObject->getIndexAP(),pfo)) return false; pcrObject->setObjectHandle(pfo); UNDO_return_val_if_fail (pfo,false); UT_sint32 newOffset = pcrObject->getPosition() - pfs->getPos() -1; // need to set field pointers to values of new pointer // as old field doesn't exist pf = pfo->getNext(); while (pf&&pf->getType()==pf_Frag::PFT_Text&& pf->getField()) { pf_Frag_Text * pft = static_cast<pf_Frag_Text *>(pf); pft->setField(pfo->getField()); pf = pft->getNext(); } DONE(); pcrObject->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); // don't update field until all of changes have been made } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_DeleteObject: { const PX_ChangeRecord_Object * pcrObject = static_cast<const PX_ChangeRecord_Object *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrObject->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound, false); UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_Object,false); UNDO_return_val_if_fail (fragOffset == 0,false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux2 = _getStruxFromFrag(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux2,false); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bool bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux,false); } UT_sint32 newOffset = pcrObject->getPosition() - pfs->getPos() -1; // was -2 if(newOffset < 0) newOffset = 0; pf_Frag_Object * pfo = static_cast<pf_Frag_Object *> (pf); if((pfo->getObjectType() != PTO_Math) && ((pfo->getObjectType() != PTO_Embed))) { UNDO_return_val_if_fail (pfo->getIndexAP() == pcrObject->getIndexAP(),false); } _deleteObject(pfo,NULL,NULL); DONE(); pcrObject->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_ChangeObject: { // ChangeSpan is it's own inverse. const PX_ChangeRecord_ObjectChange * pcro = static_cast<const PX_ChangeRecord_ObjectChange *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcro->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound,false); UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_Object,false); UNDO_return_val_if_fail (fragOffset == 0, false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux2 = _getStruxFromFrag(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux2,false); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bool bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux,false); } UT_sint32 newOffset = pcro->getPosition() - pfs->getPos() -1; pf_Frag_Object * pfo = static_cast<pf_Frag_Object *> (pf); _fmtChangeObject(pfo,pcro->getIndexAP(),NULL,NULL); DONE(); pcro->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// case PX_ChangeRecord::PXT_InsertFmtMark: { const PX_ChangeRecord_FmtMark * pcrFM = static_cast<const PX_ChangeRecord_FmtMark *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrFM->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound, false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux2 = _getStruxFromFrag(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux2, false); if(isEndFootnote(static_cast<pf_Frag *>(pfs))) { bool bFoundStrux = _getStruxFromFragSkip(static_cast<pf_Frag *>(pfs),&pfs); UNDO_return_val_if_fail (bFoundStrux,false); } UT_sint32 newOffset = pcrFM->getPosition() - pfs->getPos() -1; if (!_insertFmtMark(pf,fragOffset,pcrFM->getIndexAP())) return false; DONE(); pcrFM->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_DeleteFmtMark: { const PX_ChangeRecord_FmtMark * pcrFM = static_cast<const PX_ChangeRecord_FmtMark *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrFM->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound, false); // we backup one because we have zero length and getFragFromPosition() // returns the right-most thing with this document position. if(pf->getType() != pf_Frag::PFT_FmtMark) pf = pf->getPrev(); if(pf->getType()==pf_Frag::PFT_Strux) { if(pf->getNext() && pf->getNext()->getType() == pf_Frag::PFT_Strux) { DONE(); m_bDoingTheDo = false; return true; } if(pf->getNext() && pf->getNext()->getType() == pf_Frag::PFT_Text) { pf = pf->getNext(); if(pf->getNext() && pf->getNext()->getType() == pf_Frag::PFT_FmtMark) { pf = pf->getNext(); } } } UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_FmtMark,false); UNDO_return_val_if_fail (fragOffset == 0,false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux = _getStruxFromFragSkip(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux,false); UT_sint32 newOffset = pcrFM->getPosition() - pfs->getPos() -1; pf_Frag_FmtMark * pffm = static_cast<pf_Frag_FmtMark *> (pf); // UNDO_return_val_if_fail (pffm->getIndexAP() == pcrFM->getIndexAP(),false); _deleteFmtMark(pffm,NULL,NULL); DONE(); pcrFM->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } m_bDoingTheDo = false; return true; case PX_ChangeRecord::PXT_ChangeFmtMark: { // ChangeFmt is it's own inverse. const PX_ChangeRecord_FmtMarkChange * pcrFMC = static_cast<const PX_ChangeRecord_FmtMarkChange *>(pcr); pf_Frag * pf = NULL; PT_BlockOffset fragOffset = 0; bool bFound = getFragFromPosition(pcrFMC->getPosition(),&pf,&fragOffset); UNDO_return_val_if_fail (bFound,false); // we backup one because we have zero length and getFragFromPosition() // returns the right-most thing with this document position. if(pf->getType() != pf_Frag::PFT_FmtMark) pf = pf->getPrev(); if(pf->getType()==pf_Frag::PFT_Strux) { if(pf->getNext() && pf->getNext()->getType() == pf_Frag::PFT_Strux) { DONE(); m_bDoingTheDo = false; return true; } } UNDO_return_val_if_fail (pf->getType() == pf_Frag::PFT_FmtMark,false); UNDO_return_val_if_fail (fragOffset == 0,false); pf_Frag_Strux * pfs = NULL; bool bFoundStrux = _getStruxFromFragSkip(pf,&pfs); UNDO_return_val_if_fail (bFoundStrux,false); UT_sint32 newOffset = pcrFMC->getPosition() - pfs->getPos() -1; pf_Frag_FmtMark * pffm = static_cast<pf_Frag_FmtMark *> (pf); _fmtChangeFmtMark(pffm,pcrFMC->getIndexAP(),NULL,NULL); DONE(); m_bDoingTheDo = false; pcrFMC->AdjustBlockOffset(newOffset); m_pDocument->notifyListeners(pfs,pcr); } return true; /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// case PX_ChangeRecord::PXT_ChangePoint: DONE(); m_pDocument->notifyListeners(NULL, pcr); m_bDoingTheDo = false; return true; default: UT_ASSERT_HARMLESS(0); m_bDoingTheDo = false; return false; } }
/*! Parse stream contents into the document \param stream Stream to import from This code is used for both files and the clipboard */ UT_Error IE_Imp_Text::_parseStream(ImportStream * pStream) { UT_return_val_if_fail(pStream, UT_ERROR); bool bFirstChar = true; UT_GrowBuf gbBlock(1024); UT_UCSChar c; if (!m_bExplicitlySetEncoding) { std::string prop; prop = getProperty ("encoding"); if (!prop.empty()) { _setEncoding (prop.c_str()); } } pStream->init(m_szEncoding); while (pStream->getChar(c)) { // TODO We should switch fonts when we encounter // TODO characters from different scripts switch (c) { case UCS_CR: case UCS_LF: case UCS_LINESEP: case UCS_PARASEP: // we interpret either CRLF, CR, or LF as a paragraph break. // we also accept U+2028 (line separator) and U+2029 (para separator) // especially since these are recommended by Mac OS X. // flush out what we have if (gbBlock.getLength() > 0) X_ReturnNoMemIfError(_insertSpan(gbBlock)); X_ReturnNoMemIfError(_insertBlock()); break; case UCS_BOM: // This is Byte Order Mark at the start of file, Zero Width Non Joiner elsewhere if (bFirstChar) break; // if we encounter any of the following characters we will // substitute a '?' as they correspond to control characters, // though some text files use them for their character representations // We do this instead of of immediately returning an error // (and assuming they have no business in a text file) so we can // still show usable text to a user who has one of these files. case 0x0000: case 0x0001: case 0x0002: case 0x0003: case 0x0004: case 0x0005: case 0x0006: case 0x0007: case 0x0008: case 0x000e: case 0x000f: case 0x0010: case 0x0011: case 0x0012: case 0x0013: case 0x0014: case 0x0015: case 0x0016: case 0x0017: case 0x0018: case 0x0019: case 0x001a: case 0x001b: case 0x001c: case 0x001d: case 0x001e: case 0x001f: // UT_ASSERT(!(c <= 0x001f)); c = '?'; /* return UT_ERROR; // fall through with modified character */ default: X_ReturnNoMemIfError(gbBlock.append(reinterpret_cast<UT_GrowBufElement*>(&c),1)); break; } bFirstChar = false; } if (gbBlock.getLength() > 0) X_ReturnNoMemIfError(_insertSpan(gbBlock)); return UT_OK; }