/*! 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; }
bool pp_TableAttrProp::createAP(const gchar ** attributes, const gchar ** properties, 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(attributes) || !pAP->setProperties(properties)) return false; pAP->markReadOnly(); m_vecTableSorted.addItemSorted(pAP,compareAP); *pSubscript = subscript; return true; }
/*! 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; }
/*! * 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; }