Пример #1
0
bool pt_PieceTable::_realInsertObject(PT_DocPosition dpos,
									PTObjectType pto,
									const gchar ** attributes,
									const gchar ** properties,  pf_Frag_Object ** ppfo)
{
	UT_ASSERT_HARMLESS((pto == PTO_Math) || (pto == PTO_Embed) || (properties == NULL));

	// dpos == 1 seems to be generally bad. - plam
	// I'm curious about how often it happens.  Please mail me if it does!
	UT_ASSERT_HARMLESS(dpos > 1);

	// TODO currently we force the caller to pass in the attr/prop.
	// TODO this is probably a good thing for Images, but might be
	// TODO bogus for things like Fields.

	UT_return_val_if_fail (m_pts==PTS_Editing, false);

	// store the attributes and properties and get an index to them.
	PT_AttrPropIndex apiOld = 0, indexAP;

	pf_Frag * pf = NULL;
	PT_BlockOffset fragOffset = 0;
	bool bFound = getFragFromPosition(dpos,&pf,&fragOffset);
	UT_return_val_if_fail (bFound,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 (bFoundStrux, false);
	
	apiOld = _chooseIndexAP(pf,fragOffset);

	if (!m_varset.mergeAP(PTC_AddFmt, apiOld, attributes, properties, &indexAP, m_pDocument))
		return false;

	// get the fragment at the given document position.

	PT_BlockOffset blockOffset = _computeBlockOffset(pfs,pf) + fragOffset;
        pf_Frag_Object * pfo = NULL;
	if (!_insertObject(pf,fragOffset,pto,indexAP,pfo))
		return false;

	// create a change record, add it to the history, and notify
	// anyone listening.

	PX_ChangeRecord_Object * pcr
		= new PX_ChangeRecord_Object(PX_ChangeRecord::PXT_InsertObject,
									 dpos,indexAP, pfo->getXID(), pto,blockOffset,
                                     pfo->getField(),reinterpret_cast<PL_ObjectHandle>(pfo));
	UT_return_val_if_fail (pcr,false);

	m_history.addChangeRecord(pcr);
	m_pDocument->notifyListeners(pfs,pcr);
        *ppfo = pfo;
	return true;
}
Пример #2
0
bool pt_PieceTable::insertStrux(PT_DocPosition dpos,
								PTStruxType pts,
								pf_Frag_Strux ** ppfs_ret)
{
	if(m_pDocument->isMarkRevisions())
	{
		// when the strux is inserted in non-revision mode, it inherits the AP from the previous
		// strux. In revision mode this does not necessarily work because we may need to have a
		// different revision attribute. Consequently, we need to ensure that the AP that gets
		// assigned to the new strux contains all relevant attrs and props from the AP of the
		// previous strux -- we do this by obtaining the index of the AP of the previous strux and
		// running it through _translateRevisionAttribute() which will gives back all attrs and
		// props that need to be passed to _realInsertStrux()
		pf_Frag_Strux * pfsContainer = NULL;
		bool bFoundContainer = _getStruxFromPosition(dpos,&pfsContainer); // the orig. strux
		UT_return_val_if_fail(bFoundContainer, false);
	
		if(isEndFootnote(pfsContainer))
		{
			bFoundContainer = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
			UT_return_val_if_fail(bFoundContainer, false);
		}

		PT_AttrPropIndex indexAP = 0;
		if (pfsContainer->getStruxType() == pts)
		{
			indexAP = pfsContainer->getIndexAP();
		}

		PP_RevisionAttr Revisions(NULL);
		const gchar ** ppRevAttrib = NULL;
		const gchar ** ppRevProps  = NULL;

		_translateRevisionAttribute(Revisions, indexAP, PP_REVISION_ADDITION, ppRevAttrib, ppRevProps, 0, 0);

		//return _realChangeStruxFmt(PTC_AddFmt, dpos, dpos + iLen, ppRevAttrib,ppRevProps,pts);
		return _realInsertStrux(dpos,pts,ppRevAttrib,ppRevProps,ppfs_ret);
	}
	else
	{
		return _realInsertStrux(dpos,pts,0,0,ppfs_ret);
	}
}
Пример #3
0
bool pt_PieceTable::_realChangeSpanFmt(PTChangeFmt ptc,
									   PT_DocPosition dpos1,
									   PT_DocPosition dpos2,
									   const gchar ** attributes,
									   const gchar ** properties,
									   bool bRevisionDelete)
{
	// apply a span-level formatting change to the given region.

	UT_return_val_if_fail (m_pts==PTS_Editing,false);
    _tweakFieldSpan(dpos1,dpos2);
//
// Deal with case of exactly selecting the endOfFootnote
//
	pf_Frag * pfEndDum = m_fragments.findFirstFragBeforePos(dpos2);
	if(isEndFootnote(pfEndDum))
	{
		if(dpos2 > dpos1)
		{
			dpos2--;
		}
	}
//
// Deal with addStyle
//
	bool bApplyStyle = (PTC_AddStyle == ptc);
	const gchar ** sProps = NULL;
	const gchar ** lProps = properties;
	if(bApplyStyle)
	{
//
// OK for styles we expand out all defined properties including BasedOn styles
// Then we use these to eliminate any specfic properties in the current strux
// Then properties in the current strux will resolve to those defined in the
// style (they exist there) to specifc values in strux (if not overridden by
// the style) then finally to default value.
//
		const gchar * szStyle = UT_getAttribute(PT_STYLE_ATTRIBUTE_NAME,attributes);
		PD_Style * pStyle = NULL;
		UT_return_val_if_fail (szStyle,false);
		getDocument()->getStyle(szStyle,&pStyle);
		UT_return_val_if_fail (pStyle,false);
		UT_Vector vProps;
//
// Get the vector of properties
//
		pStyle->getAllProperties(&vProps,0);
//
// Finally make the const gchar * array of properties
//
		UT_uint32 countp = vProps.getItemCount() + 1;
		sProps = (const gchar **) UT_calloc(countp, sizeof(gchar *));
		countp--;
		UT_uint32 i;
		for(i=0; i<countp; i++)
		{
			sProps[i] = (const gchar *) vProps.getNthItem(i);
		}
		sProps[i] = NULL;
		lProps = sProps;
	}
	if (dpos1 == dpos2) 		// if length of change is zero, then we have a toggle format.
	{
		UT_uint32 startUndoPos = m_history.getUndoPos();
		bool bRes = _insertFmtMarkFragWithNotify(ptc,dpos1,attributes,lProps);
		UT_uint32 endUndoPos = m_history.getUndoPos();
		// Won't be a persistant change if it's just a toggle
		PX_ChangeRecord *pcr=0;
		m_history.getUndo(&pcr,true);
		if (pcr && (startUndoPos != endUndoPos) )
		{
			UT_DEBUGMSG(("Setting persistance of change to false\n"));
			pcr->setPersistance(false);
			m_history.setSavePosition(m_history.getSavePosition()+1);
		}
		if(bApplyStyle)
		{
			FREEP(sProps);
		}
		return bRes;
	}

	UT_return_val_if_fail (dpos1 < dpos2,false);
	bool bHaveAttributes, bHaveProperties;
	bHaveAttributes = (attributes && *attributes);
	bHaveProperties = (lProps && *lProps);

	pf_Frag * pf_First;
	pf_Frag * pf_End;
	PT_BlockOffset fragOffset_First;
	PT_BlockOffset fragOffset_End;

	bool bFound;
	bFound = getFragsFromPositions(dpos1,dpos2,&pf_First,&fragOffset_First,&pf_End,&fragOffset_End);
	UT_return_val_if_fail (bFound, false);

#if 0
	{
		pf_Frag * pf1, * pf2;
		PT_BlockOffset fo1, fo2;

		bool bFound1 = getFragFromPosition(dpos1,&pf1,&fo1);
		bool bFound2 = getFragFromPosition(dpos2,&pf2,&fo2);
		UT_return_val_if_fail (bFound1 && bFound2, false);
		UT_return_val_if_fail ((pf1==pf_First) && (fragOffset_First==fo1), false);
		UT_return_val_if_fail ((pf2==pf_End) && (fragOffset_End==fo2), false);
	}
#endif

	// see if the amount of text to be changed is completely
	// contained within a single fragment.  if so, we have a
	// simple change.  otherwise, we need to set up a multi-step
	// change -- it may not actually take more than one step,
	// but it is too complicated to tell at this point, so we
	// assume it will and don't worry about it.
	//
	// we are in a simple change if the beginning and end are
	// within the same fragment.

	// NOTE: if we call beginMultiStepGlob() we ***MUST*** call
	// NOTE: endMultiStepGlob() before we return -- otherwise,
	// NOTE: the undo/redo won't be properly bracketed.

	bool bSimple = (pf_First == pf_End);
	if (!bSimple)
		beginMultiStepGlob();

	pf_Frag_Strux * pfsContainer = NULL;
	pf_Frag * pfNewEnd;
	UT_uint32 fragOffsetNewEnd;

	UT_uint32 length = dpos2 - dpos1;
	while (length != 0)
	{
		// FIXME: Special check to support a FmtMark at the end of the
		// document. This is necessary because FmtMarks don't have a
		// length...  See bug 452.
		if (0 == length
			&& (!pf_First || pf_Frag::PFT_FmtMark != pf_First->getType()))
			break;

		UT_return_val_if_fail (dpos1+length==dpos2, false);

		UT_uint32 lengthInFrag = pf_First->getLength() - fragOffset_First;
		UT_uint32 lengthThisStep = UT_MIN(lengthInFrag, length);

		switch (pf_First->getType())
		{
		case pf_Frag::PFT_EndOfDoc:
		default:
			UT_DEBUGMSG(("fragment type: %d\n",pf_First->getType()));
			UT_ASSERT_HARMLESS(0);
			if(bApplyStyle)
			{
				FREEP(sProps);
			}
			return false;

		case pf_Frag::PFT_Strux:
			{
				// we are only applying span-level changes, so we ignore strux.
				// but we still need to update our loop indices.

				pfNewEnd = pf_First->getNext();
				fragOffsetNewEnd = 0;
				pfsContainer = static_cast<pf_Frag_Strux *> (pf_First);
				bool bFoundStrux = false;
				if(isEndFootnote(pfsContainer))
				{
					bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux, false);
				}
			}
			break;

		case pf_Frag::PFT_Text:
			{
				if (!pfsContainer)
				{
					bool bFoundStrux;
					bFoundStrux = _getStruxFromPosition(dpos1,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux,false);
					if(isEndFootnote(pfsContainer))
					{
						bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
						UT_return_val_if_fail (bFoundStrux,false);
					}
				}

				bool bResult;
				bResult	= _fmtChangeSpanWithNotify(ptc,static_cast<pf_Frag_Text *>(pf_First),
											   fragOffset_First,dpos1,lengthThisStep,
											   attributes,lProps,
											   pfsContainer,&pfNewEnd,&fragOffsetNewEnd,bRevisionDelete);
				UT_return_val_if_fail (bResult,false);
			}
			break;

		case pf_Frag::PFT_Object:
			{
				if (!pfsContainer)
				{
					bool bFoundStrux;
					bFoundStrux = _getStruxFromPosition(dpos1,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux,false);
					if(isEndFootnote(pfsContainer))
					{
						bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
						UT_return_val_if_fail (bFoundStrux,false);
					}
				}

				bool bResult;
				bResult	= _fmtChangeObjectWithNotify(ptc,static_cast<pf_Frag_Object *>(pf_First),
												 fragOffset_First,dpos1,lengthThisStep,
												 attributes,lProps,
												 pfsContainer,&pfNewEnd,&fragOffsetNewEnd,false);
				UT_return_val_if_fail (bResult,false);
			}
			break;

		case pf_Frag::PFT_FmtMark:
			{
				if (!pfsContainer)
				{
					bool bFoundStrux;
					bFoundStrux = _getStruxFromPosition(dpos1,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux,false);
					if(isEndFootnote(pfsContainer))
					{
						bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
						UT_return_val_if_fail (bFoundStrux,false);
					}

				}

				bool bResult;
				bResult = _fmtChangeFmtMarkWithNotify(ptc,static_cast<pf_Frag_FmtMark *>(pf_First),
												  dpos1, attributes,lProps,
												  pfsContainer,&pfNewEnd,&fragOffsetNewEnd);
				UT_return_val_if_fail (bResult,false);
			}
			break;

		}

		dpos1 += lengthThisStep;
		length -= lengthThisStep;

		// since _fmtChange{Span,FmtMark,...}WithNotify(), can delete pf_First, mess with the
		// fragment list, and does some aggressive coalescing of
		// fragments, we cannot just do a pf_First->getNext() here.
		// to advance to the next fragment, we use the *NewEnd variables
		// that each of the cases routines gave us.

		pf_First = pfNewEnd;
		if (!pf_First)
			length = 0;
		fragOffset_First = fragOffsetNewEnd;
	}
	if(bApplyStyle)
	{
		FREEP(sProps);
	}

	if (!bSimple)
		endMultiStepGlob();

	return true;
}
Пример #4
0
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;
	}
}
Пример #5
0
bool pt_PieceTable::_realInsertStrux(PT_DocPosition dpos,
									 PTStruxType pts,
									 const gchar ** attributes,
									 const gchar ** properties,
									 pf_Frag_Strux ** ppfs_ret)
{
	// insert a new structure fragment at the given document position.
	// this function can only be called while editing the document.
	// Also can specify an indexAP to be used for the frag rather
	// than that obtained by default. Very useful for insertting
	// Cells where you can immediately specify the cell position in
	// a table.  this function can only be called while editing the
	// document.

	UT_return_val_if_fail (m_pts==PTS_Editing, false);

	// get the fragment at the doc postion containing the given
	// document position.

	pf_Frag * pf = NULL;
	PT_BlockOffset fragOffset = 0;
	bool bFoundFrag = getFragFromPosition(dpos,&pf,&fragOffset);
	UT_return_val_if_fail (bFoundFrag, false);

	// get the strux containing the given position.

	pf_Frag_Strux * pfsContainer = NULL;
	bool bFoundContainer = _getStruxFromPosition(dpos,&pfsContainer);
	UT_return_val_if_fail (bFoundContainer,false);
	//
	// Can only insert an endTOC into a TOC
	//
	if((pfsContainer->getStruxType() == PTX_SectionTOC) && (pts != PTX_EndTOC))
	{
		bFoundContainer = _getStruxFromPosition(pfsContainer->getPos(),&pfsContainer);
		dpos--;
	}
	if(isEndFootnote(pfsContainer))
	{
		bFoundContainer = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
	}
	// if we are inserting something similar to the previous strux,
	// we will clone the attributes/properties; we assume that the
	// new strux should have the same AP as the one which preceeds us.
	// This is generally true for inserting a paragraph -- it should
	// inherit the style of the one we just broke.

	PT_AttrPropIndex indexAP = 0;
	if (pfsContainer->getStruxType() == pts)
	{
		// TODO paul, add code here to see if this strux has a "followed-by"
		// TODO paul, property (or property in the style) and get the a/p
		// TODO paul, from there rather than just taking the attr/prop
		// TODO paul, of the previous strux.
		indexAP = pfsContainer->getIndexAP();
	}

//
// Look to see if we're in the middle of a hyperlink span now.
//
	pf_Frag * pHype = _findPrevHyperlink(pf);
	if(pHype != NULL && (pts != PTX_SectionFrame) // allow annotations in
	                                              // hyperlinks
	   && (pts != PTX_SectionAnnotation)
	   && (pts != PTX_EndAnnotation)) // frames are always placed
		                                           // at the end of blocks
                                                   // so we don't need this 
	{
//
// We have an open hyperlink! FIXME later we should allow this by terminating
// the hyperlink span just before this strux, then doing the insert strux.
// Instead for now we'll just disallow this insertStrux.
//
// This assert is to remind use to write the code to terminate
// the hyperlink.
//
		pf_Frag * pEndHype = _findNextHyperlink(pf);
		PT_DocPosition posEnd = 0;
		if(pEndHype)
		{
			posEnd = pEndHype->getPos();
		}
		//
		// OK now insert a new end of hyperlink at pf
		//
		insertObject(dpos, PTO_Hyperlink,NULL,NULL);
		m_fragments.cleanFrags();
		dpos++;
		if(posEnd > 0)
		{
			//
			// Now delete the old endhyperlink.
			//
			pf_Frag * pfEnd = NULL;
			UT_uint32 newOff = 0;
			posEnd++; // from the insert
			UT_uint32 offset = 0;
			_deleteObjectWithNotify(posEnd,
									static_cast<pf_Frag_Object*>(pEndHype),
									offset,1,pfsContainer,&pfEnd,&newOff,true);
		}
		m_fragments.cleanFrags();
		bFoundFrag = getFragFromPosition(dpos,&pf,&fragOffset);
		UT_return_val_if_fail (bFoundFrag, false);
	}	

//
// If desired, merge in the specified attributes/properties. This
// enables cells to inherit the properties of the block from which
// they were inserted.
//
	if (attributes || properties)
	{
		PT_AttrPropIndex pAPIold = indexAP;
		bool bMerged = m_varset.mergeAP(PTC_AddFmt,pAPIold,attributes,properties,&indexAP,getDocument());
        UT_UNUSED(bMerged);
		UT_ASSERT_HARMLESS(bMerged);
	}

	pf_Frag_Strux * pfsNew = NULL;
	if (!_createStrux(pts,indexAP,&pfsNew))
		return false;

	pfsNew->setXID(getXID());
	
	// when inserting paragraphs, we try to remember the current
	// span formatting active at the insertion point and add a
	// FmtMark immediately after the block.  this way, if the
	// user keeps typing text, the FmtMark will control it's
	// attr/prop -- if the user warps away and/or edits elsewhere
	// and then comes back to this point (the FmtMark may or may
	// not still be here) new text will either use the FmtMark or
	// look to the right.

	bool bNeedGlob = false;
	PT_AttrPropIndex apFmtMark = 0;
	if (pfsNew->getStruxType() == PTX_Block)
	{
		bNeedGlob = _computeFmtMarkForNewBlock(pfsNew,pf,fragOffset,&apFmtMark);
		if (bNeedGlob)
			beginMultiStepGlob();

		// if we are leaving an empty block (are stealing all it's content) we should
		// put a FmtMark in it to remember the active span fmt at the time.
		// this lets things like hitting two consecutive CR's and then comming
		// back to the first empty paragraph behave as expected.

		// fixme sevior here

		if ((pf->getType()==pf_Frag::PFT_Text) && (fragOffset == 0) &&
			(pf->getPrev()!=NULL) && (pf->getPrev()->getType()==pf_Frag::PFT_Strux))
		{
			pf_Frag_Strux *pfsStrux = static_cast<pf_Frag_Strux *>(pf->getPrev());
			if(pfsStrux->getStruxType() == PTX_Block)
			{
				_insertFmtMarkAfterBlockWithNotify(pfsContainer,dpos,apFmtMark);
			}
		}
	}
	//
	// Look if we're placing an endcell in an empty block. If so, 
	// insert a format mark
	//
	if (pfsNew->getStruxType() == PTX_EndCell)
	{
		if((pf->getPrev()!=NULL) && (pf->getPrev()->getType()==pf_Frag::PFT_Strux))
		{
			pf_Frag_Strux *pfsStrux = static_cast<pf_Frag_Strux *>(pf->getPrev());
			if(pfsStrux->getStruxType() == PTX_Block)
			{
				_insertFmtMarkAfterBlockWithNotify(pfsContainer,dpos,apFmtMark);
			}
		}
	}

	// insert this frag into the fragment list. Update the container strux as needed
	_insertStrux(pf,fragOffset,pfsNew);
	if (ppfs_ret)
		*ppfs_ret = pfsNew;

	// create a change record to describe the change, add
	// it to the history, and let our listeners know about it.
	if(pfsNew->getStruxType() == PTX_SectionFrame)
	{
		// Inserting a sectionFrame screws up dos. It goes just before the next
		// block strux found.
		dpos = pfsNew->getPrev()->getPos() + pfsNew->getPrev()->getLength();
	}
	PX_ChangeRecord_Strux * pcrs
		= new PX_ChangeRecord_Strux(PX_ChangeRecord::PXT_InsertStrux,
									dpos,indexAP,pfsNew->getXID(), pts);
	UT_return_val_if_fail (pcrs,false);

	// add record to history.  we do not attempt to coalesce these.
	m_history.addChangeRecord(pcrs);
	m_pDocument->notifyListeners(pfsContainer,pfsNew,pcrs);

	if (bNeedGlob)
	{
		UT_return_val_if_fail (!pfsNew->getNext() || pfsNew->getNext()->getType()!=pf_Frag::PFT_FmtMark, false);
		_insertFmtMarkAfterBlockWithNotify(pfsNew,dpos+pfsNew->getLength(),apFmtMark);
		endMultiStepGlob();
	}

	return true;
}
Пример #6
0
/*!
 * If we do an insert strux on a pf_Frag_Strux we actually insert the new strux
 * BEFORE pf. In this case the container is actually in strux before this one.
 * In this case pfsActual returns the rela containing strux.
 */
void pt_PieceTable::_insertStrux(pf_Frag * pf,
								 PT_BlockOffset fragOffset,
								 pf_Frag_Strux * pfsNew)
{
	// insert the new strux frag at (pf,fragOffset)
	//
	// In the case of Frames, the frame must be placed just before the next
	// strux (that's not an emebedded-type strux
	//

	if(pfsNew->getStruxType() == PTX_SectionFrame)
	{
		pf_Frag_Strux * pfsNext = NULL;
		if(pf->getType() != pf_Frag::PFT_Strux)
		{
			_getNextStruxAfterFragSkip(pf, &pfsNext);
			if(pfsNext != NULL)
			{
				pf = static_cast<pf_Frag *>(pfsNext);
			}
			if(isEndFootnote(pf))
			{
				pf = pf->getNext();
			}
			fragOffset = 0;
		}
	}
	switch (pf->getType())
	{
	default:
		UT_ASSERT_HARMLESS(0);
		return;

	case pf_Frag::PFT_Object:
	case pf_Frag::PFT_EndOfDoc:
	case pf_Frag::PFT_Strux:
		{
			// insert pfsNew before pf.
			// TODO this may introduce some oddities due to empty paragraphs.
			// TODO investigate this later.
			UT_return_if_fail (fragOffset == 0);
//
// OK find the real container strux.
//
			m_fragments.insertFrag(pf->getPrev(),pfsNew);
			return;
		}

	case pf_Frag::PFT_FmtMark:
		{
			// insert pfsNew after pf.
            // before this.
			// TODO check this.
			UT_return_if_fail (fragOffset == 0);
			m_fragments.insertFrag(pf,pfsNew);
			return;
		}

	case pf_Frag::PFT_Text:
		{
			// insert pfsNew somewhere inside pf.
			// we have a text fragment which we must deal with.
			// if we are in the middle of it, we split it.
			// if we are at one of the ends of it, we just insert
			// the fragment.

			// TODO if we are at one of the ends of the fragment,
			// TODO should we create a zero-length fragment in one
			// TODO of the paragraphs so that text typed will have
			// TODO the right attributes.

			pf_Frag_Text * pft = static_cast<pf_Frag_Text *> (pf);
			UT_uint32 fragLen = pft->getLength();
			if (fragOffset == fragLen)
			{
				// we are at the right end of the fragment.
				// insert the strux after the text fragment.

				m_fragments.insertFrag(pft,pfsNew);

				// TODO decide if we should create a zero-length
				// TODO fragment in the new paragraph to retain
				// TODO the attr/prop of the pft.
				// TODO         pf_Frag_Text * pftNew = new...
				// TODO         m_fragments.insertFrag(pfsNew,pftNew);
			}
			else if (fragOffset == 0)
			{
				// we are at the left end of the fragment.
				// insert the strux before the text fragment.

				m_fragments.insertFrag(pft->getPrev(),pfsNew);
			}
			else
			{
				// we are in the middle of a text fragment.  split it
				// and insert the new strux in between the pieces.

				UT_uint32 lenTail = pft->getLength() - fragOffset;
				PT_BufIndex biTail = m_varset.getBufIndex(pft->getBufIndex(),fragOffset);
				pf_Frag_Text * pftTail = new pf_Frag_Text(this,biTail,lenTail,pft->getIndexAP(),pft->getField());
				UT_return_if_fail (pftTail);

				pft->changeLength(fragOffset);
				m_fragments.insertFrag(pft,pfsNew);
				m_fragments.insertFrag(pfsNew,pftTail);
			}

			return;
		}
	}
}
Пример #7
0
bool pt_PieceTable::insertStrux(PT_DocPosition dpos,
								PTStruxType pts,
								const gchar ** attributes,
								const gchar ** properties,
								pf_Frag_Strux ** ppfs_ret)
{
	if(m_pDocument->isMarkRevisions())
	{
		// This is just like the previous method, except that in addition to calling
		// _translateRevisionAttribute() we also need to set the attrs and props
		// passed to us.
		pf_Frag_Strux * pfsContainer = NULL;
		bool bFoundContainer = _getStruxFromPosition(dpos,&pfsContainer); // the orig. strux
		UT_return_val_if_fail(bFoundContainer, false);
	
		if(isEndFootnote(pfsContainer))
		{
			bFoundContainer = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
			UT_return_val_if_fail(bFoundContainer, false);
		}

		PT_AttrPropIndex indexAP = 0;
		if (pfsContainer->getStruxType() == pts)
		{
			indexAP = pfsContainer->getIndexAP();
		}

		PP_RevisionAttr Revisions(NULL);
		const gchar ** ppRevAttrs = NULL;
		const gchar ** ppRevProps  = NULL;

		_translateRevisionAttribute(Revisions, indexAP, PP_REVISION_ADDITION,
									ppRevAttrs, ppRevProps, NULL, NULL);

		// count original attributes and the revision-inherited attributes
		// and add them to the revision attribute
		UT_uint32 iAttrCount = 0;
		for (; attributes && attributes[iAttrCount]; iAttrCount+=2){}

		UT_uint32 iRevAttrCount = 0;
		for (; ppRevAttrs && ppRevAttrs[iRevAttrCount]; iRevAttrCount+=2){}

		const gchar ** ppRevAttrib = NULL;
		if(iAttrCount + iRevAttrCount > 0)
		{
			ppRevAttrib = new const gchar * [iAttrCount + iRevAttrCount + 1];
			UT_return_val_if_fail( ppRevAttrib, false );

			UT_uint32 i = 0;
			for (i = 0; i < iAttrCount; ++i)
			{
				ppRevAttrib[i] = attributes[i];
			}

			for (; i < iRevAttrCount + iAttrCount; ++i)
			{
				ppRevAttrib[i] = ppRevAttrs[i - iAttrCount];
			}
		
			ppRevAttrib[i]   = NULL;
		}
		
		//return _realChangeStruxFmt(PTC_AddFmt, dpos, dpos + iLen, ppRevAttrib,NULL,pts);
		bool bRet = _realInsertStrux(dpos,pts,ppRevAttrib,properties,ppfs_ret);
		delete [] ppRevAttrib;
		return bRet;
	}
	else
	{
		return _realInsertStrux(dpos,pts,attributes,properties,ppfs_ret);
	}
}
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;
}
Пример #9
0
bool pt_PieceTable::_realInsertObject(PT_DocPosition dpos,
									PTObjectType pto,
									const gchar ** attributes,
									const gchar ** properties )
{

	// dpos == 1 seems to be generally bad. - plam
	// I'm curious about how often it happens.  Please mail me if it does!
	UT_ASSERT_HARMLESS(dpos > 1);

	// TODO currently we force the caller to pass in the attr/prop.
	// TODO this is probably a good thing for Images, but might be
	// TODO bogus for things like Fields.

	UT_return_val_if_fail (m_pts==PTS_Editing,false);

	// store the attributes and properties and get an index to them.
	UT_UTF8String sProps;
	UT_sint32 i = 0;
	sProps.clear();
	if(properties != NULL)
	{
	    for(i=0;(properties[i] != NULL);i+=2)
	    {
		UT_DEBUGMSG(("Object: szProps = |%s| \n",properties[i]));
		sProps +=properties[i];
		sProps += ":";
		sProps += properties[i+1];
		if(properties[i+2] != NULL)
		{
		    sProps += ";";
		}
	    }
	}
	UT_GenericVector<const gchar*>  Atts;
	Atts.clear();
	if(attributes)
	{
		for(i=0; attributes[i] != 0; i++)
		{
		    Atts.addItem(attributes[i]);
		}
	}
	if(sProps.size() > 0)
	{
	    Atts.addItem("props");
	    Atts.addItem(sProps.utf8_str());
	}
	PT_AttrPropIndex indexAP;
	if (!m_varset.storeAP(&Atts,&indexAP))
		return 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);

	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 (bFoundStrux,false);
	PT_BlockOffset blockOffset = _computeBlockOffset(pfs,pf) + fragOffset;
    pf_Frag_Object * pfo = NULL;
	if (!_insertObject(pf,fragOffset,pto,indexAP,pfo))
		return false;

	// create a change record, add it to the history, and notify
	// anyone listening.

	PX_ChangeRecord_Object * pcr
		= new PX_ChangeRecord_Object(PX_ChangeRecord::PXT_InsertObject,
									 dpos,indexAP,pfo->getXID(),pto,blockOffset,
                                     pfo->getField(),reinterpret_cast<PL_ObjectHandle>(pfo));
	UT_return_val_if_fail (pcr,false);

	m_history.addChangeRecord(pcr);
	m_pDocument->notifyListeners(pfs,pcr);

	return true;
}