/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiWord * Copyright (C) 1998 AbiSource, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "ut_locale.h" #include "ut_types.h" #include "ut_misc.h" #include "ut_string.h" #include "ut_assert.h" #include "ut_debugmsg.h" #include "pt_PieceTable.h" #include "pd_Style.h" #include "fl_AutoLists.h" #include "ut_hash.h" #include "xap_Strings.h" #include "xap_App.h" #include "xap_EncodingManager.h" /////////////////////////////////////////////////////////////////// // Styles represent named collections of formatting properties. #define _s(name, displayed, type, base, follow, props) \ do { const gchar * a[] = { \ PT_NAME_ATTRIBUTE_NAME, name, \ PT_TYPE_ATTRIBUTE_NAME, type, \ PT_BASEDON_ATTRIBUTE_NAME, base, \ PT_FOLLOWEDBY_ATTRIBUTE_NAME, follow, \ PT_PROPS_ATTRIBUTE_NAME, props, \ 0}; \ if (!_createBuiltinStyle(name, displayed, a)) \ goto Failed; \ } while(0) typedef struct { const char* pStyle; int nID; } ST_LOCALISED_STYLES; // // A list of the styles and they correspondant localised name // // IMPORTANT: when adding styles here, please check also // s_translateStyleId() in ie_imp_MSWord_97.cpp and if there is a // corresponding Word style make sure that it gets translated into // this unlocalised name. Tomas, May 10, 2003 ST_LOCALISED_STYLES stLocalised[] = { {"Numbered List", XAP_STRING_ID_STYLE_NUMBER_LIST}, {"Plain Text", XAP_STRING_ID_STYLE_PLAIN_TEXT}, {"Heading 1", XAP_STRING_ID_STYLE_HEADING1}, {"Heading 2", XAP_STRING_ID_STYLE_HEADING2}, {"Heading 3", XAP_STRING_ID_STYLE_HEADING3}, {"Heading 4", XAP_STRING_ID_STYLE_HEADING4}, {"Contents Header", XAP_STRING_ID_STYLE_TOCHEADING}, {"Contents 1", XAP_STRING_ID_STYLE_TOCHEADING1}, {"Contents 2", XAP_STRING_ID_STYLE_TOCHEADING2}, {"Contents 3", XAP_STRING_ID_STYLE_TOCHEADING3}, {"Contents 4", XAP_STRING_ID_STYLE_TOCHEADING4}, {"Normal", XAP_STRING_ID_STYLE_NORMAL}, {"Block Text", XAP_STRING_ID_STYLE_BLOCKTEXT}, {"Lower Case List", XAP_STRING_ID_STYLE_LOWERCASELIST}, {"Upper Case List", XAP_STRING_ID_STYLE_UPPERCASTELIST}, {"Lower Roman List", XAP_STRING_ID_STYLE_LOWERROMANLIST}, {"Upper Roman List", XAP_STRING_ID_STYLE_UPPERROMANLIST}, {"Bullet List", XAP_STRING_ID_STYLE_BULLETLIST}, {"Dashed List", XAP_STRING_ID_STYLE_DASHEDLIST}, {"Square List", XAP_STRING_ID_STYLE_SQUARELIST}, {"Triangle List", XAP_STRING_ID_STYLE_TRIANGLELIST}, {"Diamond List", XAP_STRING_ID_STYLE_DIAMONLIST}, {"Star List", XAP_STRING_ID_STYLE_STARLIST}, {"Tick List", XAP_STRING_ID_STYLE_TICKLIST}, {"Box List", XAP_STRING_ID_STYLE_BOXLIST}, {"Hand List", XAP_STRING_ID_STYLE_HANDLIST}, {"Heart List", XAP_STRING_ID_STYLE_HEARTLIST}, {"Chapter Heading", XAP_STRING_ID_STYLE_CHAPHEADING}, {"Section Heading", XAP_STRING_ID_STYLE_SECTHEADING}, {"Endnote Reference", XAP_STRING_ID_STYLE_ENDREFERENCE}, {"Endnote Text", XAP_STRING_ID_STYLE_ENDTEXT}, {"Footnote Reference", XAP_STRING_ID_STYLE_FOOTREFERENCE}, {"Footnote Text", XAP_STRING_ID_STYLE_FOOTTEXT}, {"Numbered Heading 1", XAP_STRING_ID_STYLE_NUMHEAD1}, {"Numbered Heading 2", XAP_STRING_ID_STYLE_NUMHEAD2}, {"Numbered Heading 3", XAP_STRING_ID_STYLE_NUMHEAD3}, {"Implies List", XAP_STRING_ID_STYLE_IMPLIES_LIST}, {NULL, 0} }; /* Gets a style name and returns its localised name */ void pt_PieceTable::s_getLocalisedStyleName(const char *szStyle, UT_UTF8String &utf8) { static XAP_App * pApp = XAP_App::getApp(); const XAP_StringSet * pSS = pApp->getStringSet(); utf8 = szStyle; int n; for (n=0; stLocalised[n].pStyle; n++) { if (strcmp(szStyle, stLocalised[n].pStyle)==0) { pSS->getValueUTF8(stLocalised[n].nID, utf8); break; } } } bool pt_PieceTable::_loadBuiltinStyles(void) { /* !!! if adding or removing properties to the list_fmt, you have to make also changes to pt_VarSet.cpp mergeAP() */ UT_LocaleTransactor t(LC_NUMERIC, "C"); const char* list_fmt = " list-style:%s; start-value:%s; margin-left:%fin; text-indent:-%fin; " "field-color:%s;list-delim:%s; field-font:%s; list-decimal:%s"; UT_String list_fmt_tmp; UT_String stTmp; const char* szFmt; // findNearestFont will do a fuzzy match, and return the nearest font in the // system -- use the locale language UT_UTF8String s = XAP_EncodingManager::get_instance()->getLanguageISOName(); const char * pCountry = XAP_EncodingManager::get_instance()->getLanguageISOTerritory(); if(pCountry) { s += "-"; s += pCountry; } const char* pszFamily = XAP_App::findNearestFont("Times New Roman", "normal", "", "normal", "", "12pt", s.utf8_str()); UT_String_sprintf(stTmp, "font-family:%s; font-size:12pt; font-weight:normal; " "font-style:normal; font-stretch:normal; font-variant:normal; " "margin-top:0pt; margin-bottom:0pt; " "margin-left:0pt; margin-right:0pt; text-decoration:none; " "text-indent:0in; text-position:normal; line-height:1.0; " "color:000000; bgcolor:transparent; widows:2", pszFamily); pszFamily = XAP_App::findNearestFont("Arial", "normal", "", "normal", "", "12pt", s.utf8_str()); // used to set the dom-dir of the style here, but we do not want to do that. The // dom-dir property should be inherited from the section or document (the user can, of // course, modify the style, but that is up to them). # ifdef BIDI_RTL_DOMINANT stTmp += "; text-align:right"; # else stTmp += "; text-align:left"; # endif _s("Normal", true, "P", "", "Current Settings", stTmp.c_str()); szFmt = "font-family:%s; font-size:%dpt; font-weight:bold; margin-top:22pt; margin-bottom:3pt; keep-with-next:1"; UT_String_sprintf(stTmp, szFmt, pszFamily, 17); _s("Heading 1", true, "P", "Normal", "Normal", stTmp.c_str()); UT_String_sprintf(stTmp, szFmt, pszFamily, 14); _s("Heading 2", true, "P", "Normal", "Normal", stTmp.c_str()); UT_String_sprintf(stTmp, szFmt, pszFamily, 12); _s("Heading 3", true, "P", "Normal", "Normal", stTmp.c_str()); _s("Heading 4", true, "P", "Normal", "Normal", stTmp.c_str()); _s("Plain Text", true,"P", "Normal", "Current Settings", "font-family:Courier New"); _s("Block Text", true,"P", "Normal", "Current Settings", "margin-left:1in; margin-right:1in; margin-bottom:6pt"); UT_String_sprintf(stTmp, list_fmt, "Numbered List", "1",LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L.", "NULL", "."); _s("Numbered List",true,"P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Lower Case List","1", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L)", "NULL", "."); _s("Lower Case List",true,"P", "Numbered List", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Upper Case List","1", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L)", "NULL", "."); _s("Upper Case List",false,"P", "Numbered List", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Lower Roman List","1", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "NULL", "."); _s("Lower Roman List",false,"P", "Normal", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt,"Upper Roman List","1", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "NULL", "."); _s("Upper Roman List",false,"P", "Numbered List", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Bullet List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Symbol", "NULL"); _s("Bullet List",true, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Implies List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Symbol", "NULL"); _s("Implies List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Dashed List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "NULL", "NULL"); _s("Dashed List",true, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Square List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Square List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Triangle List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Triangle List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Diamond List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Diamond List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Star List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Star List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Tick List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Tick List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Box List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Box List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Hand List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Hand List",false, "P", "", "Current Settings", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Heart List","0", LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L", "Dingbats", "NULL"); _s("Heart List",false, "P", "", "Current Settings", stTmp.c_str()); // pszFamily is the nearest font to Arial found in the system UT_String_sprintf(stTmp, "tabstops:0.3in/L0; list-style:Numbered List; " "start-value:1; margin-left:0.0in; text-indent:0.0in; " "field-color:transparent; list-delim:%%L.; field-font:%s; " "list-decimal:", pszFamily); _s("Numbered Heading 1",true,"P","Heading 1","Normal", stTmp.c_str()); _s("Numbered Heading 2",true,"P","Heading 2","Normal", stTmp.c_str()); _s("Numbered Heading 3",true,"P","Heading 3","Normal", stTmp.c_str()); // pszFamily is the nearest font to Arial found in the system UT_String_sprintf(stTmp, list_fmt, "Numbered List", "1",LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L.", "NULL", "."); _s("Contents 1",false,"P","Normal","Normal", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Numbered List", "1",2*LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L.", "NULL", "."); _s("Contents 2",false,"P","Normal","Normal", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Numbered List", "1",3*LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L.", "NULL", "."); _s("Contents 3",false,"P","Normal","Normal", stTmp.c_str()); UT_String_sprintf(stTmp, list_fmt, "Numbered List", "1",4*LIST_DEFAULT_INDENT, LIST_DEFAULT_INDENT_LABEL, "transparent", "%L.", "NULL", "."); _s("Contents 4",false,"P","Normal","Normal", stTmp.c_str()); szFmt = "font-family:%s; font-size:%dpt; font-weight:bold; margin-top:12pt; margin-bottom:6pt; text-align:center; keep-with-next:1"; UT_String_sprintf(stTmp, szFmt, pszFamily, 16); _s("Contents Header",false,"P","Normal","Normal", stTmp.c_str()); szFmt = "tabstops:1.1in/L0; list-style:Numbered List; " "start-value:1; margin-left:0.0in; text-indent:0.0in; " "field-color:transparent; list-delim:%s %%L.; " "field-font:%s; list-decimal:"; UT_String_sprintf(stTmp, szFmt, "Chapter", pszFamily); _s("Chapter Heading",true,"P","Numbered Heading 1","Normal", stTmp.c_str()); UT_String_sprintf(stTmp, szFmt, "Section", pszFamily); _s("Section Heading",true,"P","Numbered Heading 1","Normal", stTmp.c_str()); _s("Endnote Reference",false,"C", "None", "Current Settings", "text-position:superscript; font-size:10pt"); _s("Endnote Text",false,"C", "Normal", "Current Settings", "text-position:normal"); _s("Footnote Reference",false,"C", "None", "Current Settings", "text-position:superscript; font-size:10pt"); _s("Footnote Text",false,"C", "Normal", "Current Settings", "text-position:normal; font-size:10pt"); return true; Failed: return false; } bool pt_PieceTable::_createBuiltinStyle(const char * szName, bool bDisplayed, const gchar ** attributes) { // this function can only be called before loading the document. UT_return_val_if_fail (m_pts==PTS_Create, false); PT_AttrPropIndex indexAP; if (!m_varset.storeAP(attributes,&indexAP)) return false; // verify unique name PD_Style * pStyle = NULL; if (getStyle(szName,&pStyle) == true) return false; // duplicate name pStyle = new PD_BuiltinStyle(this, indexAP, szName, bDisplayed); if (pStyle) m_hashStyles.insert(szName, pStyle); return true; } bool pt_PieceTable::appendStyle(const gchar ** attributes) { // this function can only be called while loading the document. //UT_ASSERT(m_pts==PTS_Loading); // first, store the attributes and properties and get an index to them. PT_AttrPropIndex indexAP; if (!m_varset.storeAP(attributes,&indexAP)) return false; // verify unique name UT_ASSERT_HARMLESS(sizeof(char) == sizeof(gchar)); const char * szName = UT_getAttribute(PT_NAME_ATTRIBUTE_NAME, attributes); if (!szName || !*szName) { UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); return true; // silently ignore unnamed styles } UT_DEBUGMSG(("STYLE: Appending style %s \n",szName)); PD_Style * pStyle = NULL; if (getStyle(szName,&pStyle) == true) { // duplicate name UT_return_val_if_fail (pStyle, false); if (pStyle->isUserDefined()) { // already loaded, ignore redefinition UT_DEBUGMSG(("appendStyle[%s]: duplicate definition ignored\n", szName)); return true; } // override builtin definition return pStyle->setIndexAP(indexAP); } else { // this is a new name pStyle = new PD_Style(this, indexAP, szName); UT_DEBUGMSG(("STYLE: Creating new style %s saving in hash \n",szName)); // // TODO: Learn how to use Dom's AbiObject instead of this hack. // Rob asks, as AbiObject is no more, is this still a hack? // if (pStyle) m_hashStyles.insert(szName,pStyle); return true; } } bool pt_PieceTable::removeStyle (const gchar * szName) { UT_return_val_if_fail (szName, false); UT_ASSERT_HARMLESS(sizeof(char) == sizeof(gchar)); UT_DEBUGMSG(("DOM: remove the style, maybe recode the hash-table\n")); PD_Style * pStyle; if (getStyle(szName,&pStyle)) { if (!pStyle->isUserDefined()) return false; // can't destroy a builtin style delete pStyle; m_hashStyles.remove (szName, NULL); return true; } return false; } bool pt_PieceTable::getStyle(const char * szName, PD_Style ** ppStyle) const { //UT_ASSERT(szName && *szName); PD_Style * pStyle = m_hashStyles.pick (szName); if (!pStyle) return false; if (ppStyle) { *ppStyle = pStyle; } return true; } size_t pt_PieceTable::getStyleCount (void) const { return (size_t) m_hashStyles.size(); } #if 0 // currentl unused. suppress warning /////////////////////////////////////////////////////////////////////// /*! * compareStyleNames this function is used to compare the char * strings names * of the styles with the qsort method on UT_Vector. \param const void * vS1 - pointer to a PD_Style pointer \param const void * vS2 - pointer to a PD_Style pointer \returns -ve if sz1 < sz2, 0 if sz1 == sz2, +ve if sz1 > sz2 */ static UT_sint32 compareStyleNames(const void * vS1, const void * vS2) { const PD_Style ** pS1 = (const PD_Style **) vS1; const PD_Style ** pS2 = (const PD_Style **) vS2; const char * sz1 = (*pS1)->getName(); const char * sz2 = (*pS2)->getName(); return g_ascii_strcasecmp(sz1, sz2); } #endif /*! Do not use this function inside loops, used the other enumStyles() instead !!! */ bool pt_PieceTable::enumStyles(UT_uint32 k, const char ** pszName, const PD_Style ** ppStyle) const { // return the kth style. UT_uint32 kLimit = m_hashStyles.size(); if (k >= kLimit) return false; UT_GenericVector * vStyle = m_hashStyles.enumerate() ; //vStyle->qsort(compareStyleNames); PD_Style * pStyle = vStyle->getNthItem(k); UT_return_val_if_fail (pStyle,false); if (ppStyle) { *ppStyle = pStyle; } if (pszName) { *pszName = pStyle->getName(); } UT_ASSERT_HARMLESS(*pszName); delete vStyle; return true; } /*! generate vector of styles the caller has to delete pStyle when done ... */ bool pt_PieceTable::enumStyles(UT_GenericVector *& pStyles) const { pStyles = m_hashStyles.enumerate() ; return true; }