예제 #1
0
/*! changes formatting of a strux while loading document */
bool pt_PieceTable::appendStruxFmt(pf_Frag_Strux * pfs, const gchar ** attributes)
{
	// can only be used while loading the document
	UT_return_val_if_fail (m_pts==PTS_Loading,false);

	// Only a strux can be appended to an empty document
	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
	if (!m_fragments.getFirst())
		return false;

	UT_return_val_if_fail ( pfs, false );

	PT_AttrPropIndex currentAP = pfs->getIndexAP();

	const PP_AttrProp * pOldAP;
    if(!getAttrProp(currentAP,&pOldAP))
		return false;

	PP_AttrProp * pNewAP = pOldAP->cloneWithReplacements(attributes,NULL,true);
	pNewAP->markReadOnly();

	PT_AttrPropIndex indexAP;
	if (!m_varset.addIfUniqueAP(pNewAP,&indexAP))
		return false;

	pfs->setIndexAP(indexAP);

	return true;
}
예제 #2
0
void PP_AttrProp::operator = (const PP_AttrProp &Other)
{
	UT_uint32 countMyAttrs = ((Other.m_pAttributes) ? Other.m_pAttributes->size() : 0);

	UT_uint32 Index;
	for(Index = 0; Index < countMyAttrs; Index++)
	{
		const gchar * szName;
		const gchar * szValue;
		if(Other.getNthAttribute(Index, szName, szValue))
		{
			setAttribute(szName, szValue);
		}
	}

	UT_uint32 countMyProps = ((Other.m_pProperties) ? Other.m_pProperties->size() : 0);

	for(Index = 0; Index < countMyProps; Index++)
	{
		const gchar * szName;
		const gchar * szValue;
		if(Other.getNthProperty(Index, szName, szValue))
		{
			setProperty(szName, szValue);
		}
	}

}
예제 #3
0
bool pp_TableAttrProp::createAP(UT_sint32 * pSubscript)
{
	PP_AttrProp * pNew = new PP_AttrProp();
	if (!pNew)
		return false;
 	UT_sint32 u;
 	if (m_vecTable.addItem(pNew,&u) != 0)
	{
		delete pNew;
		return false;
	}

	pNew->setIndex(u);	//$HACK

	if (pSubscript)
 	{
 		*pSubscript = u;
 	}
	else
	{
		// create default empty AP
		pNew->markReadOnly();
		m_vecTableSorted.addItem(pNew, NULL);
	} 

	return true;
}
예제 #4
0
/*! Create a new AttrProp with exactly the attributes/properties given.
  \return NULL on failure, the newly-created PP_AttrProp.
*/
PP_AttrProp * PP_AttrProp::createExactly(const gchar ** attributes,
					 const gchar ** properties) const
{
	// first, create a new AttrProp using just the values given.

	PP_AttrProp * papNew = new PP_AttrProp();
	if (!papNew)
		goto Failed;
	if (!papNew->setAttributes(attributes) || !papNew->setProperties(properties))
		goto Failed;
	return papNew;

Failed:
	DELETEP(papNew);
	return NULL;
}
예제 #5
0
bool pp_TableAttrProp::createAP(const UT_GenericVector<const gchar*> * pVector,
								   UT_sint32 * pSubscript)
{
	UT_sint32 subscript;
	if (!createAP(&subscript))
		return false;

	PP_AttrProp * pAP = m_vecTable.getNthItem(subscript);
	UT_return_val_if_fail (pAP, false);
	if (!pAP->setAttributes(pVector))
		return false;
	
	pAP->markReadOnly();

	m_vecTableSorted.addItemSorted(pAP,compareAP);
	
	*pSubscript = subscript;
	return true;
}
예제 #6
0
void ODe_Style_List::setLevelStyle(UT_uint8 level, const PP_AttrProp& rBlockAP) {
    
    UT_UTF8String levelString;
    ODe_ListLevelStyle* pLevelStyle;
    const gchar* pValue = NULL;
    bool ok;
    
    UT_UTF8String_sprintf(levelString, "%u", level);
    
    pLevelStyle = m_levelStyles.pick(levelString.utf8_str());
    
    if (pLevelStyle != NULL) {
        // This level style aws already set. There's nothing to be done.
        return;
    }
    
    ok = rBlockAP.getProperty("list-style", pValue);
    UT_return_if_fail(ok && pValue);
    
    if (!strcmp(pValue, "Numbered List") ||
        !strcmp(pValue, "Lower Case List") ||
        !strcmp(pValue, "Upper Case List") ||
        !strcmp(pValue, "Lower Roman List") ||
        !strcmp(pValue, "Upper Roman List") ||
        !strcmp(pValue, "Hebrew List") ||
        !strcmp(pValue, "Arabic List")) {
            
        pLevelStyle = new ODe_Numbered_ListLevelStyle();

    } else if (!strcmp(pValue, "Bullet List") ||
               !strcmp(pValue, "Dashed List") ||
               !strcmp(pValue, "Square List") ||
               !strcmp(pValue, "Triangle List") ||
               !strcmp(pValue, "Diamond List") ||
               !strcmp(pValue, "Star List") ||
               !strcmp(pValue, "Tick List") ||
               !strcmp(pValue, "Box List") ||
               !strcmp(pValue, "Hand List") ||
               !strcmp(pValue, "Heart List") ||
               !strcmp(pValue, "Implies List")) {
                
        pLevelStyle = new ODe_Bullet_ListLevelStyle();
        
        
    } else {
        UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
        return;
    }


    m_levelStyles.insert(levelString.utf8_str(), pLevelStyle);
    pLevelStyle->fetchAttributesFromAbiBlock(rBlockAP);
}
예제 #7
0
bool pp_TableAttrProp::findMatch(const PP_AttrProp * pMatch,
									UT_sint32 * pSubscript) const
{
	// return true if we find an AP in our table which is
	// an exact match for the attributes/properties in pMatch.
	// set *pSubscript to the subscript of the matching item.

	UT_sint32 kLimit = m_vecTable.getItemCount();
	UT_sint32 k;
  
	UT_uint32 checksum = pMatch->getCheckSum();
 	k = m_vecTableSorted.binarysearch(reinterpret_cast<void *>(&checksum), compareAPBinary);
 	UT_uint32 cksum = pMatch->getCheckSum();
 
 	if (k == -1)
 	{
 		k = kLimit;
 	}
 
 	for (; (k < kLimit); k++)
  	{
 		PP_AttrProp * pK = (PP_AttrProp *)m_vecTableSorted.getNthItem(k);
 		if (cksum != pK->getCheckSum())
 		{
 			break;
 		}
  		if (pMatch->isExactMatch(pK))
  		{
 			// Need to return an index of the element in the MAIN
 			// vector table
			*pSubscript = pK->getIndex();
			return true;
		}
	}
	return false;
}
예제 #8
0
/*!
    Changes formating of the last strux of type pts
    bSkipEmbededSections indicates whether when an end of an embeded section is
    encountered, the entire section is to be skipped over, for example if the end of the
    document looks like

    <p><footnote><p></p></footnote>

    when searching for <p> if bSkipEmbededSections == true the paragraph before <footnote>
    will be modified
*/
bool pt_PieceTable::appendLastStruxFmt(PTStruxType pst, const gchar ** attributes, const gchar ** props,
									   bool bSkipEmbededSections)
{
	// can only be used while loading the document
	UT_return_val_if_fail (m_pts==PTS_Loading,false);

	// Only a strux can be appended to an empty document
	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
	if (!m_fragments.getFirst())
		return false;

	pf_Frag * pf = m_fragments.getLast();

	UT_return_val_if_fail ( pf, false );
	
	pf = _findLastStruxOfType(pf, pst, bSkipEmbededSections);
	
	UT_return_val_if_fail( pf, false );
	
	PT_AttrPropIndex currentAP = pf->getIndexAP();

	const PP_AttrProp * pOldAP;
    if(!getAttrProp(currentAP,&pOldAP))
		return false;

	PP_AttrProp * pNewAP = pOldAP->cloneWithReplacements(attributes,props,false);
	pNewAP->markReadOnly();

	PT_AttrPropIndex indexAP;
	if (!m_varset.addIfUniqueAP(pNewAP,&indexAP))
		return false;

	pf->setIndexAP(indexAP);

	return true;
}
void AccountHandler::_handlePacket(Packet* packet, BuddyPtr buddy)
{
	// packet and buddy must always be set
	UT_return_if_fail(packet);
	UT_return_if_fail(buddy);
	
	// as must the session manager
	AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager();
	UT_return_if_fail(pManager);
	
	// manager didn't handle it, see what we can do
	switch (packet->getClassType()) 
	{			
		case PCT_JoinSessionRequestEvent:
		{
			JoinSessionRequestEvent* jse = static_cast<JoinSessionRequestEvent*>(packet);
			
			// lookup session
			AbiCollab* pSession = pManager->getSessionFromSessionId(jse->getSessionId());
			UT_return_if_fail(pSession);

            // check if this buddy is allowed to access this document
            // TODO: this should be done for every session packet, not just join session packets
            if (!hasAccess(pSession->getAcl(), buddy))
            {
                // we should only reach this point if someone is brute forcing trying
                // out session IDs while not being on the ACL. Ban this uses.
                UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
                return;
            }
		
			// lookup exporter
			ABI_Collab_Export* pExport = pSession->getExport();
			UT_return_if_fail(pExport);
			
			// lookup adjusts
			const UT_GenericVector<ChangeAdjust *>* pExpAdjusts = pExport->getAdjusts();
			UT_return_if_fail(pExpAdjusts);
		
			PD_Document* pDoc = pSession->getDocument();

			// add this author to the document if we don't recognize him
			UT_sint32 iAuthorId = -1;
			UT_UTF8String buddyDescriptor = buddy->getDescriptor();
			UT_GenericVector<pp_Author*> authors = pDoc->getAuthors();
			UT_DEBUGMSG(("Scanning %d authors to see if we recognize this buddy\n", authors.getItemCount()));
			for (UT_sint32 i = 0; i < authors.getItemCount(); i++)
			{
				pp_Author* pAuthor = authors.getNthItem(i);
				UT_continue_if_fail(pAuthor);

				const gchar* szDescriptor = NULL;
				pAuthor->getProperty("abicollab-descriptor", szDescriptor);
				if (!szDescriptor)
					continue;

				if (buddyDescriptor != szDescriptor)
					continue;

				// yay, we know this author!
				iAuthorId = pAuthor->getAuthorInt();
				UT_DEBUGMSG(("Found known author with descriptior %s, id %d!\n", buddyDescriptor.utf8_str(), iAuthorId));
				break;
			}
			
			if (iAuthorId == -1)
			{
				// we don't know this author yet, create a new author object for him
				iAuthorId = pDoc->findFirstFreeAuthorInt();
				pp_Author * pA = pDoc->addAuthor(iAuthorId);
				PP_AttrProp * pPA = pA->getAttrProp();
				pPA->setProperty("abicollab-descriptor", buddyDescriptor.utf8_str());
				pDoc->sendAddAuthorCR(pA);
				UT_DEBUGMSG(("Added a new author to the documument with descriptor %s, id %d\n", buddyDescriptor.utf8_str(), iAuthorId));
			}
			
			// serialize entire document into string
			JoinSessionRequestResponseEvent jsre(jse->getSessionId(), iAuthorId);
			if (AbiCollabSessionManager::serializeDocument(pDoc, jsre.m_sZABW, false /* no base64 */) == UT_OK)
			{
				// set more document properties
				jsre.m_iRev = pDoc->getCRNumber();
				jsre.m_sDocumentId = pDoc->getDocUUIDString();
				if (pDoc->getFilename())
					jsre.m_sDocumentName = UT_go_basename_from_uri(pDoc->getFilename());
				
				// send to buddy!
				send(&jsre, buddy);
				
				// add this buddy to the collaboration session
				pSession->addCollaborator(buddy);
			}
			break;
		}
		
		case PCT_JoinSessionRequestResponseEvent:
		{
			JoinSessionRequestResponseEvent* jsre = static_cast<JoinSessionRequestResponseEvent*>( packet );
			PD_Document* pDoc = 0;
			if (AbiCollabSessionManager::deserializeDocument(&pDoc, jsre->m_sZABW, false) == UT_OK)
			{
				if (pDoc)
				{
					// NOTE: we could adopt the same document name here, but i'd
					// rather not at the moment - MARCM
					pDoc->forceDirty();
					if (jsre->m_sDocumentName.size() > 0)
					{
						gchar* fname = g_strdup(jsre->m_sDocumentName.utf8_str());
						pDoc->setFilename(fname);
					}
					// The default ownership when joining is FALSE, as that seems 
					// to make sense for the generic case. The person sharing the 
					// document by default owns the document (and is thus allowed
					// to modify the ACL).
					pManager->joinSession(jsre->getSessionId(), pDoc, jsre->m_sDocumentId, jsre->m_iRev, jsre->getAuthorId(), buddy, this, false, NULL);
				}
				else 
				{
					UT_DEBUGMSG(("AccountHandler::_handlePacket() - deserializing document failed!\n"));
				}
			}
			break;
		}
		
		case PCT_GetSessionsEvent:
		{
			GetSessionsResponseEvent gsre;
			const UT_GenericVector<AbiCollab *> sessions = pManager->getSessions();
			for (UT_sint32 i = 0; i < sessions.getItemCount(); i++)
			{
				AbiCollab* pSession = sessions.getNthItem(i);
				if (pSession && pSession->isLocallyControlled())
				{
                    // check if the buddy has access to this session
                    if (!hasAccess(pSession->getAcl(), buddy))
                    {
                        UT_DEBUGMSG(("Buddy %s denied access to session %s by ALC\n", buddy->getDescriptor(true).utf8_str(), pSession->getSessionId().utf8_str()));
                        continue;
                    }

					const PD_Document * pDoc = pSession->getDocument();
                    UT_continue_if_fail(pDoc);

                    // determine name
					UT_UTF8String documentBaseName;
					if (pDoc->getFilename())
						documentBaseName = UT_go_basename_from_uri(pDoc->getFilename());
					// set session info
					gsre.m_Sessions[ pSession->getSessionId() ] = documentBaseName;
				}
			}
			send(&gsre, buddy);
			break;
		}
		
		case PCT_GetSessionsResponseEvent:
		{
			GetSessionsResponseEvent* gsre = static_cast<GetSessionsResponseEvent*>( packet );
			UT_GenericVector<DocHandle*> vDocHandles;
			for (std::map<UT_UTF8String,UT_UTF8String>::iterator it=gsre->m_Sessions.begin(); it!=gsre->m_Sessions.end(); ++it) {
				DocHandle* pDocHandle = new DocHandle((*it).first, (*it).second);
				vDocHandles.addItem(pDocHandle);
			}
			pManager->setDocumentHandles(buddy, vDocHandles);
			break;
		}
		
		default:
		{
			UT_DEBUGMSG(("Unhandled packet class: 0x%x\n", packet->getClassType()));
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
			break;
		}
	}
}
예제 #10
0
/*! Create a new AttrProp based upon the given one, adding or replacing the items given.
	 \return NULL on failure, the newly-created PP_AttrProp clone otherwise.
*/
PP_AttrProp * PP_AttrProp::cloneWithReplacements(const gchar ** attributes,
												 const gchar ** properties,
												 bool bClearProps) const
{
	bool bIgnoreProps = false; // see below

	// first, create a new AttrProp using just the values given.

	PP_AttrProp * papNew = new PP_AttrProp();
	if (!papNew)
		goto Failed;
	if (!papNew->setAttributes(attributes) || !papNew->setProperties(properties))
		goto Failed;

	// next, add any items that we have that are not present
	// (have not been overridden) in the new one.

	UT_uint32 k;
	const gchar * n;
	const gchar * v;
	const gchar * vNew;

	k = 0;
	while (getNthAttribute(k++,n,v))
	{
		// TODO decide if/whether to allow PT_PROPS_ATTRIBUTE_NAME here.
		// TODO The issue is: we use it to store the CSS properties and
		// TODO when we see it, we expand the value into one or more
		// TODO properties.  if we allow it to be given here, should
		// TODO we blowaway all of the existing properties and create
		// TODO them from this?  or should we expand it and override
		// TODO individual properties?
		// TODO for now, we just barf on it.
		UT_return_val_if_fail (strcmp(n,PT_PROPS_ATTRIBUTE_NAME)!=0, false); // cannot handle PROPS here
		if (!papNew->getAttribute(n,vNew))
			if (!papNew->setAttribute(n,v))
				goto Failed;
	}

	// we want to be able to remove all properties by setting the
	// props attribute to ""; in order for that to work, we need to
	// skip the following loop if props is set to ""
	const gchar * szValue;

	if(papNew->getAttribute("props", szValue) && !*szValue)
		bIgnoreProps = true;

	if (!bClearProps && !bIgnoreProps)
	{
		k = 0;
		while (getNthProperty(k++,n,v))
		{
			if (!papNew->getProperty(n,vNew))
				if (!papNew->setProperty(n,v))
					goto Failed;
		}
	}

	// the following will remove all properties set to ""; this allows us
	// to remove properties by setting them to ""
	papNew->_clearEmptyProperties();
	papNew->_clearEmptyAttributes();

	return papNew;

Failed:
	DELETEP(papNew);
	return NULL;
}
예제 #11
0
/*! Create a new AttrProp based upon the given one, removing the items given
	 if their value is equal to that given.  See also PP_AttrProp::cloneWithElimination,
	 which does similarly but removes the items given regardless of whether or not
	 their value is equal to the value given.
	 \return NULL on failure, the newly-created PP_AttrProp clone otherwise.
*/
PP_AttrProp * PP_AttrProp::cloneWithEliminationIfEqual(const gchar ** attributes,
												const gchar ** properties) const
{
	// first, create an empty AttrProp.
	PP_AttrProp * papNew = new PP_AttrProp();
	if (!papNew)
		goto Failed;

	UT_uint32 k;
	const gchar * n;
	const gchar * v;

	k = 0;
	while (getNthAttribute(k++,n,v))
	{
		// for each attribute in the old set, add it to the
		// new set only if it is not present in the given array.

		if (attributes && *attributes)
		{
			const gchar ** p = attributes;
			while (*p)
			{
				if(strcmp(p[0],PT_PROPS_ATTRIBUTE_NAME)!=0)
					goto DoNotIncludeAttribute; // cannot handle PROPS here
				if (strcmp(n,p[0])==0 && strcmp(n,p[1])==0)		// found it, so we don't put it in the result.
					goto DoNotIncludeAttribute;
				p += 2;								// skip over value
			}
		}

		// we didn't find it in the given array, add it to the new set.

		if (!papNew->setAttribute(n,v))
			goto Failed;

	DoNotIncludeAttribute:
		;
	}

	k = 0;
	while (getNthProperty(k++,n,v))
	{
		// for each property in the old set, add it to the
		// new set only if it is not present in the given array.

		if (properties && *properties)
		{
			const gchar ** p = properties;
			while (*p)
			{
				if (strcmp(n,p[0])==0 && strcmp(n,p[1])==0)		// found it, so we don't put it in the result.
					goto DoNotIncludeProperty;
				p += 2;
			}
		}

		// we didn't find it in the given array, add it to the new set.

		if (!papNew->setProperty(n,v))
			goto Failed;

	DoNotIncludeProperty:
		;
	}

	return papNew;

Failed:
	DELETEP(papNew);
	return NULL;
}
/*!
 * Take a packet, interpret it's contents and apply the implied operations on the document.
 */
bool ABI_Collab_Import::_import(const SessionPacket& packet, UT_sint32 iImportAdjustment, BuddyPtr pCollaborator, bool inGlob)
{
	UT_DEBUGMSG(("ABI_Collab_Import::_import() - packet class type: %d, iImportAdjustment: %d\n", packet.getClassType(), iImportAdjustment));
	UT_return_val_if_fail(pCollaborator, false);

	switch (packet.getClassType())
	{
		case PCT_GlobSessionPacket:
			{
				const GlobSessionPacket* gp = static_cast<const GlobSessionPacket*>(&packet);
				UT_return_val_if_fail(gp->getPackets().size() > 0, false);

				// store the last seen revision from this collaborator (it is immediately used by the export)
				m_remoteRevs[pCollaborator] = gp->getRev();

				for (UT_uint32 j = 0; j < gp->getPackets().size(); j++)
				{
					SessionPacket* pGlobPacket = gp->getPackets()[j];
					if (pGlobPacket)
					{
						bool res = _import(*pGlobPacket, iImportAdjustment, pCollaborator, true); // yay for recursion :)
						if (!res)
						{
							UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
						}
					}
				}

				return true;
			}
		
		case PCT_SignalSessionPacket:
			{
				const SignalSessionPacket* sp = static_cast<const SignalSessionPacket*>(&packet);
				m_pDoc->signalListeners(sp->getSignalType());
				return true;
			}

		case PCT_RevertSessionPacket:
			{
				const RevertSessionPacket* rrp = static_cast<const RevertSessionPacket*>(&packet);
				UT_DEBUGMSG(("Revert packet seen on import for rev: %d\n", rrp->getRev()));

				if (m_iAlreadyRevertedRevs.size() == 0 || m_iAlreadyRevertedRevs.front() != rrp->getRev())
				{
					UT_DEBUGMSG(("Incoming revert for revision %d, which we didn't detect locally (m_iAlreadyRevertedRev: %d)!\n", rrp->getRev(), m_iAlreadyRevertedRevs.front()));
					UT_DEBUGMSG(("DOCUMENT OUT OF SYNC DETECTED!!!!\n"));
					UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
					return false;
				}	

				m_iAlreadyRevertedRevs.pop_front();
				return true;
			}
		case PCT_RevertAckSessionPacket:
			{
				UT_DEBUGMSG(("RevertAck packet seen on import for rev: %d\n", static_cast<const RevertAckSessionPacket*>(&packet)->getRev()));

				// remove this collaborator from our revert ack list; he can play again...
				for (std::vector<std::pair<BuddyPtr, UT_sint32> >::iterator it = m_revertSet.begin(); it != m_revertSet.end(); it++)
				{
					if ((*it).first == pCollaborator)
					{
						UT_DEBUGMSG(("Found collaborator %s on our revert ack list with rev %d! Removing him from the list...\n", (*it).first->getDescription().utf8_str(), (*it).second));
						UT_ASSERT_HARMLESS((*it).second == static_cast<const RevertAckSessionPacket*>(&packet)->getRev());
						m_revertSet.erase(it);
						return true;
					}
				}

				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
				return false;
			}

		default:
			// silly C++ can't switch on ranges
			if (packet.getClassType() >= _PCT_FirstChangeRecord && packet.getClassType() <= _PCT_LastChangeRecord)
			{
				const ChangeRecordSessionPacket* crp = static_cast<const ChangeRecordSessionPacket*>(&packet);
				UT_DEBUGMSG(("It's safe to import this packet\n"));

				UT_DEBUGMSG(("For CR number %d requested point %d adjustment %d \n",  crp->getRev(), crp->getPos(), iImportAdjustment));

				PT_DocPosition pos = static_cast<PT_DocPosition>(crp->getPos() + iImportAdjustment);
				UT_ASSERT(pos <= getEndOfDoc());

				if (!inGlob)
				{
					// store the last seen revision from this collaborator (it is immediately used by the export)
					// NOTE: if this changerecord is part of a glob, then we don't do this; we'll have
					// already set the revision of the glob itself as the last seen one
					m_remoteRevs[pCollaborator] = crp->getRev();
				}

				// todo: remove these temp vars
				PT_DocPosition iPos2 = 0;

				// process the packet
				switch(crp->getPXType())
				{
					case PX_ChangeRecord::PXT_GlobMarker:
					{
						UT_DEBUGMSG(("Found GLOB marker (ignoring)\n"));
						return true;
					}
					case PX_ChangeRecord::PXT_InsertSpan:
					{
						const InsertSpan_ChangeRecordSessionPacket* icrsp = static_cast<const InsertSpan_ChangeRecordSessionPacket*>( crp );
						UT_UCS4String UCSChars = const_cast<UT_UTF8String&>(icrsp->m_sText).ucs4_str();	// ugly, ucs4_str should be const func!
						PP_AttrProp attrProp;
						attrProp.setAttributes(const_cast<const gchar**>(icrsp->getAtts()));
						attrProp.setProperties(const_cast<const gchar**>(icrsp->getProps()));
						m_pDoc->insertSpan(pos,UCSChars.ucs4_str(),UCSChars.length(), &attrProp);
						break;
					}
					case PX_ChangeRecord::PXT_DeleteSpan:
					{
						iPos2 = pos + crp->getLength();
						PP_AttrProp *p_AttrProp_Before = NULL;
						UT_uint32 icnt = 0;
						m_pDoc->deleteSpan(pos,iPos2,p_AttrProp_Before,icnt,true);
						break;
					}
					case PX_ChangeRecord::PXT_ChangeSpan:
					{
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						iPos2 = pos + pcrsp->getLength();
						if((szProps == NULL) && (szAtts == NULL))
						{
							//
							// This happens if we remove all formats
							// we have to handle this seperately
							//
							// Get style of containing block
							//
							pf_Frag_Strux* sdh = NULL;
							m_pDoc->getStruxOfTypeFromPosition(pos,PTX_Block,&sdh);
							if(!sdh)
							{
								UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
								return false;
							}
							PD_Style * pStyle = m_pDoc->getStyleFromSDH(sdh);
							if(!pStyle)
							{
								UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
								return false;
							}
							const gchar * szName =  pStyle->getName();
							const gchar * atts[3] = {PT_STYLE_ATTRIBUTE_NAME,szName,NULL};
							m_pDoc->changeSpanFmt(PTC_SetExactly, pos, iPos2, atts, const_cast<const gchar**>( szProps ) );
						}
						else
						{
							m_pDoc->changeSpanFmt(PTC_SetExactly, pos, iPos2, const_cast<const gchar**>(szAtts), const_cast<const gchar**>( szProps ) );
						}
						break;
					}
					case PX_ChangeRecord::PXT_InsertStrux:
					{
						const ChangeStrux_ChangeRecordSessionPacket* pcrsp = static_cast<const ChangeStrux_ChangeRecordSessionPacket*>( crp );
						PTStruxType pts = pcrsp->m_eStruxType;
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						
						if((szProps != NULL) || (szAtts != NULL))
						{
							m_pDoc->insertStrux( pos, pts, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ) );
						}
						else
						{
							m_pDoc->insertStrux(pos, pts);
						}
						break;
					}
					case PX_ChangeRecord::PXT_DeleteStrux:
					{
						const DeleteStrux_ChangeRecordSessionPacket* pcrsp = static_cast<const DeleteStrux_ChangeRecordSessionPacket*>( crp );
						PTStruxType pts = pcrsp->m_eStruxType;
						m_pDoc->deleteStrux(pos,pts,true);
						break;
					}
					case PX_ChangeRecord::PXT_ChangeStrux:
					{
						const ChangeStrux_ChangeRecordSessionPacket* pcrsp = static_cast<const ChangeStrux_ChangeRecordSessionPacket*>( crp );
						PTStruxType pts = pcrsp->m_eStruxType;
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						UT_return_val_if_fail(szProps != NULL || szAtts != NULL, false);

						UT_DEBUGMSG(("Executing ChangeStrux pos= %d \n",pos));
						m_pDoc->changeStruxFmt(PTC_SetExactly, pos, pos, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ), pts);
						
						// TODO: this mask is waaaay to generic
						XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame();
						if (pFrame)
						{
							FV_View* pView = static_cast<FV_View*>(pFrame->getCurrentView());
							if (pView)
								pView->notifyListeners(AV_CHG_TYPING | AV_CHG_FMTCHAR | AV_CHG_FMTBLOCK | AV_CHG_PAGECOUNT | AV_CHG_FMTSTYLE );
						}
						break;
					}
					case PX_ChangeRecord::PXT_InsertObject:
					{
						const Object_ChangeRecordSessionPacket* ocrsp = static_cast<const Object_ChangeRecordSessionPacket*>( crp );
						PTObjectType pto = ocrsp->getObjectType();
						gchar** szAtts = ocrsp->getAtts();
						gchar** szProps = ocrsp->getProps();
						
						if((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						m_pDoc->insertObject(pos, pto, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ) );
						break;
					}
					case PX_ChangeRecord::PXT_DeleteObject:
					{
						iPos2 = pos + 1;
						PP_AttrProp *p_AttrProp_Before = NULL;
						UT_uint32 icnt = 0;
						m_pDoc->deleteSpan(pos, iPos2, p_AttrProp_Before, icnt, true);
						break;
					}
					case PX_ChangeRecord::PXT_ChangeObject:
					{
						const Object_ChangeRecordSessionPacket* ccrsp = static_cast<const Object_ChangeRecordSessionPacket*>( crp );
						//PTObjectType pto = ccrsp->m_eObjectType;
						gchar** szAtts = ccrsp->getAtts();
						gchar** szProps = ccrsp->getProps();
						
						if ((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						m_pDoc->changeSpanFmt(PTC_SetExactly, pos, pos + 1, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ));
						break;
					}
                    case PX_ChangeRecord::PXT_ChangeDocRDF:
                    {
                        // down cast crp to get dcrp
						const RDF_ChangeRecordSessionPacket* dcrp = static_cast<const RDF_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = dcrp->getAtts();
						gchar** szProps = dcrp->getProps();

						if ((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}

                        {
                            // update the local document RDF to remove
                            // szAtts RDF and then add the szProps RDF
                            m_pDoc->getDocumentRDF()->handleCollabEvent( szAtts, szProps );
                        }                        
                        break;
                    }
					case PX_ChangeRecord::PXT_InsertFmtMark:
					{
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						
						if((szProps == NULL) && (szAtts == NULL))
						{
							// nothing to do here, please move along
							
							// NOTE: why does this happen anyway? 
							// This happens when for example when sending over tables:
							UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						return m_pDoc->changeSpanFmt(PTC_SetExactly, pos, pos, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ));
					}
					case PX_ChangeRecord::PXT_DeleteFmtMark:
					{
						return m_pDoc->deleteFmtMark(pos);
					}
					case PX_ChangeRecord::PXT_ChangeFmtMark:
					{
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						gchar** szAtts = pcrsp->getAtts();
						gchar** szProps = pcrsp->getProps();
						
						if ((szProps == NULL) && (szAtts == NULL))
						{
							UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
							return false;
						}
						return m_pDoc->changeSpanFmt(PTC_SetExactly, pos, pos, const_cast<const gchar**>( szAtts ), const_cast<const gchar**>( szProps ));
					}
					case PX_ChangeRecord::PXT_ChangePoint:
					{
						UT_DEBUGMSG(("Change Point CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true, 0);
					}
					case PX_ChangeRecord::PXT_ListUpdate:
					{
						UT_DEBUGMSG(("ListUpdate CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_StopList:
					{
						UT_DEBUGMSG(("StopList CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_UpdateField:
					{
						UT_DEBUGMSG(("UpdateFiled CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_RemoveList:
					{
						UT_DEBUGMSG(("RemoveList CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_UpdateLayout:
					{
						UT_DEBUGMSG(("UpdateLayout CR \n"));
						return m_pDoc->createAndSendCR(pos, crp->getPXType(), true,0);
					}
					case PX_ChangeRecord::PXT_CreateDataItem:
					{
						const Data_ChangeRecordSessionPacket* dp = static_cast<const Data_ChangeRecordSessionPacket*>( crp );
						const char * szNameV = g_strdup(dp->getAttribute(PT_DATAITEM_ATTRIBUTE_NAME));
						PD_DataItemHandle pHandle = NULL;
						std::string sToken = dp->m_bTokenSet ? dp->m_sToken : "";
						UT_ByteBuf * pBuf= new UT_ByteBuf();
						UT_DEBUGMSG(("PXT_CreateDataItem: append image buffer @ 0x%p, %lu bytes, sToken %s\n", &dp->m_vecData[0], (long unsigned)dp->m_vecData.size(), sToken.c_str()));
						pBuf->append(reinterpret_cast<const UT_Byte *>( &dp->m_vecData[0] ), dp->m_vecData.size() );
						bool res = m_pDoc->createDataItem(szNameV,false,pBuf,sToken,&pHandle);
						delete pBuf;
						return res;
					}
					case PX_ChangeRecord::PXT_ChangeDocProp:
					{
						UT_DEBUGMSG(("ChangeDocProp CR \n"));
						const Props_ChangeRecordSessionPacket* pcrsp = static_cast<const Props_ChangeRecordSessionPacket*>( crp );
						//
						// Assemble the Attributes for different properties
						//
						const gchar** szAtts = const_cast<const gchar **>(pcrsp->getAtts());
						const gchar** szProps = const_cast<const gchar **>(pcrsp->getProps());
						//
						// Now direct the document to make the changes
						//
						return m_pDoc->changeDocPropeties(szAtts,szProps);
					}
					default:
					{
						UT_DEBUGMSG(("Unimplemented crp->getPXType(): %d\n", crp->getPXType()));
						UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
						break;
					}
				}
				
				return true;
			}
			else
			{
				UT_DEBUGMSG(("ABI_Collab_Import::import called with unhandled packet class type: %d!\n", packet.getClassType()));
				return false;
			}
			break;		
	}

	return false;
}
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;
}
예제 #14
0
void ODe_Frame_Listener::_openODTextbox(const PP_AttrProp& rAP,
                                        ODe_ListenerAction& /*rAction*/) 
{
    UT_UTF8String output;
    UT_UTF8String str;
    bool ok;
    const gchar* pValue = NULL;
    ODe_Style_Style* pStyle;
    
    pStyle = new ODe_Style_Style();
    pStyle->setFamily("graphic");
    pStyle->fetchAttributesFromAbiFrame(rAP);
    
    // Abi frames have no padding
    // (no margin between frame borders and its content)
    pStyle->setPadding("0cm");
    
    // Abi frames are aways positioned from its top-left corner.
    pStyle->setHorizontalPos("from-left");
    pStyle->setVerticalPos("from-top");
    
    // For OOo to recognize a textbox as being a textbox, it will
    // need to have the parent style name "Frame". I can't find it
    // in the ODF spec, but without it OOo considers the textbox to
    // be a generic drawing object (check the Navigator window in OOo).
    pStyle->setParentStyleName("Frame");
    // Make sure an (empty) Frame style exists, for completeness sake
	// (OOo doesn't seem to care if it exists or not).
    if (!m_rStyles.getGraphicsStyle("Frame")) {
        ODe_Style_Style* pFrameStyle = new ODe_Style_Style();
		pFrameStyle->setStyleName("Frame");
		pFrameStyle->setFamily("graphic");
        m_rStyles.addGraphicsStyle(pFrameStyle);
    }

	m_rAutomatiStyles.storeGraphicStyle(pStyle);

    ////
    // Write <draw:frame>
    
    _printSpacesOffset(output);
    output += "<draw:frame";

    UT_UTF8String_sprintf(str, "Frame%u", m_rAuxiliaryData.m_frameCount+1);
    ODe_writeAttribute(output, "draw:name", str);
    m_rAuxiliaryData.m_frameCount++;
    
    ODe_writeAttribute(output, "draw:style-name", pStyle->getName());

    UT_UTF8String_sprintf(str, "%u", m_zIndex);
    ODe_writeAttribute(output, "draw:z-index", str);


    ok = rAP.getProperty("position-to", pValue);

    if (pValue && !strcmp(pValue, "block-above-text")) {

        ODe_writeAttribute(output, "text:anchor-type", "paragraph");

        ok = rAP.getProperty("xpos", pValue);
        UT_ASSERT(ok && pValue != NULL);
        ODe_writeAttribute(output, "svg:x", pValue);

        ok = rAP.getProperty("ypos", pValue);
        UT_ASSERT(ok && pValue != NULL);
        ODe_writeAttribute(output, "svg:y", pValue);
    } else {
        // Everything else (column and page) will be treated as page
        // anchored.
        
        ODe_writeAttribute(output, "text:anchor-type", "page");

	if(pValue && !strcmp(pValue, "column-above-text"))
	{
	  //
	  // Get the most recent page style so we can do the arithmetic
	  // Won't work for x in multi-columned docs
	  //
	    UT_uint32 numPStyles =  m_rAutomatiStyles.getSectionStylesCount();
	    UT_UTF8String stylePName;
	    UT_UTF8String_sprintf(stylePName, "PLayout%d", numPStyles + 1);
	    ODe_Style_PageLayout * pPageL = m_rAutomatiStyles.getPageLayout(stylePName.utf8_str());

	    ok = rAP.getProperty("frame-col-xpos", pValue);
	    UT_ASSERT(ok && pValue != NULL);
	    double xCol =  UT_convertToInches(pValue);
	    const gchar* pSVal= pPageL->getPageMarginLeft();
	    double xPageL = UT_convertToInches(pSVal);
	    double xTot = xPageL + xCol;
	    pValue = UT_convertInchesToDimensionString(DIM_IN,xTot,"4");
	    ODe_writeAttribute(output, "svg:x", pValue);
        
	    ok = rAP.getProperty("frame-col-ypos", pValue);
	    UT_ASSERT(ok && pValue != NULL);
	    double yCol =  UT_convertToInches(pValue);
	    pSVal= pPageL->getPageMarginTop();
	    double yPageL = UT_convertToInches(pSVal);
	    double yTot = yPageL + yCol;
	    pValue = UT_convertInchesToDimensionString(DIM_IN,yTot,"4");
	    ODe_writeAttribute(output, "svg:y", pValue);	  
	}
	else
	{
	    ok = rAP.getProperty("frame-page-xpos", pValue);
	    UT_ASSERT(ok && pValue != NULL);
	    ODe_writeAttribute(output, "svg:x", pValue);
        
	    ok = rAP.getProperty("frame-page-ypos", pValue);
	    UT_ASSERT(ok && pValue != NULL);
	    ODe_writeAttribute(output, "svg:y", pValue);
	}
    }
    
    
    ok = rAP.getProperty("frame-width", pValue);
    if (ok && pValue != NULL) {
        ODe_writeAttribute(output, "svg:width", pValue);
    }
    
    output += ">\n";
    
    ODe_writeUTF8String(m_pTextOutput, output);
    m_spacesOffset++;
    
    ////
    // Write <draw:text-box>
    
    output.clear();
    _printSpacesOffset(output);
    output += "<draw:text-box";
    
    ok = rAP.getProperty("frame-height", pValue);
    if (ok && pValue != NULL) {
        ODe_writeAttribute(output, "fo:min-height", pValue);
    }
    
    output += ">\n";
    
    ODe_writeUTF8String(m_pTextOutput, output);
    m_spacesOffset++;
}
예제 #15
0
AbiCollab* AbiCollabSessionManager::startSession(PD_Document* pDoc, UT_UTF8String& sSessionId, 
			AccountHandler* pAclAccount, bool bLocallyOwned, XAP_Frame* pFrame, 
			const UT_UTF8String& masterDescriptor)
{
	UT_DEBUGMSG(("Starting collaboration session for document with id %s, master descriptor: %s\n",
			pDoc->getDocUUIDString(), masterDescriptor.utf8_str()));
	UT_return_val_if_fail(pDoc, NULL);
	UT_return_val_if_fail(pAclAccount, NULL);

	if (sSessionId == "")
	{
		XAP_App* pApp = XAP_App::getApp();	
		UT_UUID* pUUID = pApp->getUUIDGenerator()->createUUID();
		pUUID->toString(sSessionId);
	}

	if (masterDescriptor != "")
	{
		// search for a buddy descriptor in the authors list that matches this 
		// descriptor, and make that the active author; if such an author does
		// not exist, then search for an author with no abicollab property set 
		// at all, and give it this buddy descriptor (ie, we assume that it is 
		// "us", even though it might not always be a valid assumption).

		int iAuthorId = -1;
		UT_GenericVector<pp_Author*> authors = pDoc->getAuthors();
		pp_Author* pEmptyAuthor = NULL;
		UT_DEBUGMSG(("Scanning %d authors to see if we recognize this master buddy\n", authors.getItemCount()));
		for (UT_sint32 i = 0; i < authors.getItemCount(); i++)
		{
			pp_Author* pAuthor = authors.getNthItem(i);
			UT_continue_if_fail(pAuthor);

			const gchar* szDescriptor = NULL;
			pAuthor->getProperty("abicollab-descriptor", szDescriptor);
			if (!szDescriptor)
			{
				if (!pEmptyAuthor && !pAuthor->getAttrProp()->hasProperties())
					pEmptyAuthor = pAuthor;
				continue;
			}

			if (masterDescriptor != szDescriptor)
				continue;

			// yay, we already editted this document ourselves!
			iAuthorId = pAuthor->getAuthorInt();
			pDoc->setMyAuthorInt(iAuthorId);
			UT_DEBUGMSG(("Found our own author object with descriptior %s, id %d!\n", masterDescriptor.utf8_str(), iAuthorId));
			break;
		}

		if (iAuthorId == -1)
		{
			if (pEmptyAuthor)
			{
				// reuse this author object and make it our own
				iAuthorId = pEmptyAuthor->getAuthorInt();
				PP_AttrProp * pPA = pEmptyAuthor->getAttrProp();
				pPA->setProperty("abicollab-descriptor", masterDescriptor.utf8_str());
				pDoc->setMyAuthorInt(iAuthorId);
				pDoc->sendChangeAuthorCR(pEmptyAuthor);
				UT_DEBUGMSG(("Reusing empty author object with id %d, setting descriptor to %s!\n", iAuthorId, masterDescriptor.utf8_str()));
			}
			else
			{
				UT_DEBUGMSG(("No suitable author found in the document for descriptor %s\n", masterDescriptor.utf8_str()));
				
				iAuthorId = pDoc->findFirstFreeAuthorInt();
				pp_Author * pA = pDoc->addAuthor(iAuthorId);
				pDoc->setMyAuthorInt(iAuthorId);
				PP_AttrProp * pPA = pA->getAttrProp();
				pPA->setProperty("abicollab-descriptor", masterDescriptor.utf8_str());
				pDoc->sendAddAuthorCR(pA);
				UT_DEBUGMSG(("Added a new author to the documument with descriptor %s, id %d\n", masterDescriptor.utf8_str(), iAuthorId));
			}
		}
	}
	
	UT_DEBUGMSG(("Creating a new collaboration session with UUID: %s\n", sSessionId.utf8_str()));

	UT_return_val_if_fail(_setupFrame(&pFrame, pDoc), NULL);
	AbiCollab* pAbiCollab = new AbiCollab(pDoc, sSessionId, pAclAccount, bLocallyOwned);
	m_vecSessions.push_back(pAbiCollab);
	
	// notify all people we are sharing a new document
	// FIXME: since we only allow a session to be shared on 1 account, we should
	// only notify the buddies on that account, instead of notifying the buddies
	// on all accounts.
	StartSessionEvent event;
	event.setBroadcast(true);
	signal(event);
	
	return pAbiCollab;
}