/*! * This method sets all the local properties from a vector of pointers * to const gchar * strings of Property - Value pairs. * This method wipes out all the old values and clears all the bools * assciated with them. */ void XAP_Dialog_FontChooser::setAllPropsFromVec(const UT_Vector & vProps) { UT_sint32 remCount = vProps.getItemCount(); if(remCount <= 0) return; // BAD BAD, we have wrong count UT_ASSERT_HARMLESS(remCount % 2 == 0); if(remCount % 2) { remCount--; } m_mapProps.clear(); UT_sint32 i = 0; for(i=0; i< remCount; i+=2) { m_mapProps.insert(std::make_pair((const char*)vProps.getNthItem(i), (const char*)vProps.getNthItem(i+1))); } // // Do the Text decorations // const std::string sDecor = getVal("text-decoration"); m_bUnderline = (NULL != strstr(sDecor.c_str(),"underline")); m_bOverline = (NULL != strstr(sDecor.c_str(),"overline")); m_bStrikeout = (NULL != strstr(sDecor.c_str(),"line-through")); m_bTopline = (NULL != strstr(sDecor.c_str(),"topline")); m_bBottomline = (NULL != strstr(sDecor.c_str(),"bottomline")); const std::string sDisplay = getVal("display"); m_bHidden = !strcmp(sDisplay.c_str(),"none"); const std::string sPosition = getVal("text-position"); m_bSuperScript = strcmp(sPosition.c_str(),"superscript")==0; m_bSubScript = strcmp(sPosition.c_str(),"subscript")==0; }
/*! \fn bool PP_AttrProp::explodeStyle(const PD_Document * pDoc, bool bOverwrite) \brief This function transfers attributes and properties defined in style into the AP. \param bOverwrite indicates what happens if the property/attribute is already present. If false \ (default) the style definition is ignored; if true the style value overrides the present value. */ bool PP_AttrProp::explodeStyle(const PD_Document * pDoc, bool bOverwrite) { UT_return_val_if_fail(pDoc,false); // expand style if present const gchar * pszStyle = NULL; if(getAttribute(PT_STYLE_ATTRIBUTE_NAME, pszStyle)) { PD_Style * pStyle = NULL; if(pszStyle && (strcmp(pszStyle, "None") != 0) && pDoc->getStyle(pszStyle,&pStyle)) { UT_Vector vAttrs; UT_Vector vProps; UT_sint32 i; pStyle->getAllAttributes(&vAttrs, 100); pStyle->getAllProperties(&vProps, 100); for(i = 0; i < vProps.getItemCount(); i += 2) { const gchar * pName = (const gchar *)vProps.getNthItem(i); const gchar * pValue = (const gchar *)vProps.getNthItem(i+1); const gchar * p; bool bSet = bOverwrite || !getProperty(pName, p); if(bSet) setProperty(pName, pValue); } // attributes are more complicated, because there are some style attributes that must // not be transferred to the generic AP for(i = 0; i < vAttrs.getItemCount(); i += 2) { const gchar * pName = (const gchar *)vAttrs.getNthItem(i); if(!pName || !strcmp(pName, "type") || !strcmp(pName, "name") || !strcmp(pName, "basedon") || !strcmp(pName, "followedby") || !strcmp(pName, "props")) { continue; } const gchar * pValue = (const gchar *)vAttrs.getNthItem(i+1); const gchar * p; bool bSet = bOverwrite || !getAttribute(pName, p); if(bSet) setAttribute(pName, pValue); } } } return true; }
bool AP_Dialog_Paragraph::getDialogData(const gchar **& pProps) { UT_Vector v; struct propPair { gchar * prop; gchar * val; }; propPair * p; // only do this if the control has a proper value if (_wasChanged(id_MENU_ALIGNMENT) && _getMenuItemValue(id_MENU_ALIGNMENT)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("text-align"); switch (_getMenuItemValue(id_MENU_ALIGNMENT)) { case align_LEFT: p->val = g_strdup("left"); break; case align_CENTERED: p->val = g_strdup("center"); break; case align_RIGHT: p->val = g_strdup("right"); break; case align_JUSTIFIED: p->val = g_strdup("justify"); break; default: UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } v.addItem(p); } if (_wasChanged(id_CHECK_DOMDIRECTION)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("dom-dir"); if (_getCheckItemValue(id_CHECK_DOMDIRECTION) == check_TRUE) p->val = g_strdup("rtl"); else p->val = g_strdup("ltr"); v.addItem(p); } if (_wasChanged(id_SPIN_LEFT_INDENT)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("margin-left"); p->val = g_strdup(_getSpinItemValue(id_SPIN_LEFT_INDENT)); v.addItem(p); } if (_wasChanged(id_SPIN_RIGHT_INDENT)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("margin-right"); p->val = g_strdup(_getSpinItemValue(id_SPIN_RIGHT_INDENT)); v.addItem(p); } // TODO : The logic here might not be bulletproof. If the user triggers // TODO : a change in the TYPE of special indent (hanging, first line, // TODO : none), we will always save what's in the box as a property. // TODO : One could make it smarter with a stronger contract with // TODO : the platform interfaces. if (_getMenuItemValue(id_MENU_SPECIAL_INDENT) && (_wasChanged(id_MENU_SPECIAL_INDENT) || _wasChanged(id_SPIN_SPECIAL_INDENT))) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("text-indent"); tIndentState i = (tIndentState) _getMenuItemValue(id_MENU_SPECIAL_INDENT); if (i == indent_NONE) p->val = g_strdup(UT_convertInchesToDimensionString(m_dim, 0)); else if (i == indent_FIRSTLINE) p->val = g_strdup(_getSpinItemValue(id_SPIN_SPECIAL_INDENT)); else if (i == indent_HANGING) { // we have to flip the sign for "hanging" indents to a negative quantity for // storage in the document as a text-indent // get with no dimension UT_Dimension dim = UT_determineDimension(_getSpinItemValue(id_SPIN_SPECIAL_INDENT)); double val = UT_convertDimensionless(_getSpinItemValue(id_SPIN_SPECIAL_INDENT)); // Convert to inches val = UT_convertDimToInches(val, dim); // flip sign val = val * (double) -1; // store the reconstructed p->val = g_strdup(UT_convertInchesToDimensionString(dim, val)); } v.addItem(p); } if (_wasChanged(id_SPIN_BEFORE_SPACING)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("margin-top"); p->val = g_strdup(_getSpinItemValue(id_SPIN_BEFORE_SPACING)); v.addItem(p); } if (_wasChanged(id_SPIN_AFTER_SPACING)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("margin-bottom"); p->val = g_strdup(_getSpinItemValue(id_SPIN_AFTER_SPACING)); v.addItem(p); } // TODO : The logic here might not be bulletproof. If the user triggers // TODO : a change in the TYPE of special indent (single, double, etc.) // TODO : we will always save what's in the box as a property. // TODO : One could make it smarter with a stronger contract with // TODO : the platform interfaces. if(_getMenuItemValue(id_MENU_SPECIAL_SPACING) && (_wasChanged(id_MENU_SPECIAL_SPACING) || _wasChanged(id_SPIN_SPECIAL_SPACING))) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("line-height"); // normal spacings (single, 1.5, double) are just simple numbers. // "at least" needs a "+" at the end of the number (no units). // "exactly" simply has units. // "multiple" has no units. gchar * pTmp = NULL; const gchar * pString = _getSpinItemValue(id_SPIN_SPECIAL_SPACING); UT_uint32 nSize = 0; switch(_getMenuItemValue(id_MENU_SPECIAL_SPACING)) { case spacing_SINGLE: p->val = g_strdup("1.0"); break; case spacing_ONEANDHALF: p->val = g_strdup("1.5"); break; case spacing_DOUBLE: p->val = g_strdup("2.0"); break; case spacing_ATLEAST: nSize = strlen(pString); pTmp = (gchar *) UT_calloc(nSize + 2, sizeof(gchar)); UT_return_val_if_fail (pTmp, false); strncpy(pTmp, pString, nSize); // stick a '+' at the end pTmp[nSize] = '+'; p->val = g_strdup(pTmp); FREEP(pTmp); break; case spacing_EXACTLY: // fallthrough case spacing_MULTIPLE: // both these cases either do or don't have units associated with them. // the platform dialog code takes care of that. p->val = g_strdup(pString); break; default: UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } v.addItem(p); } // NOTE : "orphans" and "widows" hold a number specifying the number // NOTE : of lines to consider an orphaned or widowed piece of text. // NOTE : If they're both 0 they're off. If either is greater than // NOTE : 0, then some form of control is in effect. If the property // NOTE : is not set, they're indeterminate. if (_wasChanged(id_CHECK_WIDOW_ORPHAN)) { // TODO : fix this! we stomp on both properties (setting them // TODO : to "2"s or "0"s) if the one check box was ever // TODO : changed { ALLOC_PROP_PAIR(p); p->prop = g_strdup("orphans"); if (_getCheckItemValue(id_CHECK_WIDOW_ORPHAN) == check_TRUE) p->val = g_strdup("2"); else p->val = g_strdup("0"); v.addItem(p); } { ALLOC_PROP_PAIR(p); p->prop = g_strdup("widows"); if (_getCheckItemValue(id_CHECK_WIDOW_ORPHAN) == check_TRUE) p->val = g_strdup("2"); else p->val = g_strdup("0"); v.addItem(p); } } if (_wasChanged(id_CHECK_KEEP_LINES)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("keep-together"); if (_getCheckItemValue(id_CHECK_KEEP_LINES) == check_TRUE) p->val = g_strdup("yes"); else p->val = g_strdup("no"); v.addItem(p); } if (_wasChanged(id_CHECK_KEEP_NEXT)) { ALLOC_PROP_PAIR(p); p->prop = g_strdup("keep-with-next"); if (_getCheckItemValue(id_CHECK_KEEP_NEXT) == check_TRUE) p->val = g_strdup("yes"); else p->val = g_strdup("no"); v.addItem(p); } // TODO : add these to PP_Property (pp_Property.cpp) !!! /* m_pageBreakBefore; m_suppressLineNumbers; m_noHyphenate; */ // export everything in the array UT_uint32 count = v.getItemCount()*2 + 1; const gchar ** newprops = (const gchar **) UT_calloc(count, sizeof(gchar *)); if (!newprops) return false; const gchar ** newitem = newprops; UT_uint32 i = v.getItemCount(); while (i > 0) { p = (propPair *) v.getNthItem(i-1); i--; newitem[0] = p->prop; newitem[1] = p->val; newitem += 2; } // DO purge the vector's CONTENTS, which are just propPair structs UT_VECTOR_FREEALL(propPair *, v); // DO NOT purge the propPair's CONTENTS, because they will be pointed to // by the pointers we just copied into memory typed (gchar **) pProps = newprops; return true; }
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; }