1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_starmath.hxx" 30 31 32 #include <vector> 33 #include <osl/mutex.hxx> 34 #include <ucbhelper/content.hxx> 35 #include <vcl/msgbox.hxx> 36 37 #include <sfx2/dispatch.hxx> 38 #include <sfx2/docfile.hxx> 39 40 #include <map> 41 #include <vector> 42 #include <iterator> 43 44 #include "symbol.hxx" 45 #include "view.hxx" 46 #include "utility.hxx" 47 #include "dialog.hxx" 48 #include "config.hxx" 49 #include "cfgitem.hxx" 50 #include "smmod.hxx" 51 #include "starmath.hrc" 52 53 54 using namespace ::com::sun::star; 55 using namespace ::com::sun::star::ucb; 56 using namespace ::com::sun::star::uno; 57 using namespace ::rtl; 58 59 60 /**************************************************************************/ 61 62 SmSym::SmSym() : 63 m_aName(C2S("unknown")), 64 m_aSetName(C2S("unknown")), 65 m_cChar('\0'), 66 m_bPredefined(sal_False), 67 m_bDocSymbol(sal_False) 68 { 69 m_aExportName = m_aName; 70 m_aFace.SetTransparent(sal_True); 71 m_aFace.SetAlign(ALIGN_BASELINE); 72 } 73 74 75 SmSym::SmSym(const SmSym& rSymbol) 76 { 77 *this = rSymbol; 78 } 79 80 81 SmSym::SmSym(const String& rName, const Font& rFont, sal_UCS4 cChar, 82 const String& rSet, sal_Bool bIsPredefined) 83 { 84 m_aName = m_aExportName = rName; 85 86 m_aFace = rFont; 87 m_aFace.SetTransparent(sal_True); 88 m_aFace.SetAlign(ALIGN_BASELINE); 89 90 m_cChar = cChar; 91 //! according to HDU this should not be used anymore now 92 //! since this was necessary in the early days but should 93 //! not be done now since this is handled now at a more 94 //! bottom layer by HDU. 95 //! He can still imagine scenarios where this will be wrong 96 //! now though, for example when importing *some* old documents. 97 //! But overall it should be a large improvement, and 98 //! likely everything will still work... #_- (eyes shut and "go"!) 99 // 100 // if (RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet()) 101 // Character |= 0xF000; 102 m_aSetName = rSet; 103 m_bPredefined = bIsPredefined; 104 m_bDocSymbol = sal_False; 105 } 106 107 108 SmSym& SmSym::operator = (const SmSym& rSymbol) 109 { 110 m_aName = rSymbol.m_aName; 111 m_aExportName = rSymbol.m_aExportName; 112 m_cChar = rSymbol.m_cChar; 113 m_aFace = rSymbol.m_aFace; 114 m_aSetName = rSymbol.m_aSetName; 115 m_bPredefined = rSymbol.m_bPredefined; 116 m_bDocSymbol = rSymbol.m_bDocSymbol; 117 118 SmSymbolManager * pSymSetManager = &SM_MOD()->GetSymbolManager(); 119 if (pSymSetManager) 120 pSymSetManager->SetModified(true); 121 122 return *this; 123 } 124 125 126 bool SmSym::IsEqualInUI( const SmSym& rSymbol ) const 127 { 128 return m_aName == rSymbol.m_aName && 129 m_aFace == rSymbol.m_aFace && 130 m_cChar == rSymbol.m_cChar; 131 } 132 133 /**************************************************************************/ 134 135 void SmSymbolManager::SFX_NOTIFY(SfxBroadcaster& /*rBC*/, const TypeId& rBCType, 136 const SfxHint& /*rHint*/, const TypeId& rHintType) 137 { 138 } 139 140 141 void SmSymbolManager::Init() 142 { 143 SmModule *pp = SM_MOD(); 144 StartListening(*pp->GetConfig()); 145 } 146 147 148 void SmSymbolManager::Exit() 149 { 150 SmModule *pp = SM_MOD(); 151 EndListening(*pp->GetConfig()); 152 } 153 154 155 SmSymbolManager::SmSymbolManager() 156 { 157 m_bModified = false; 158 } 159 160 161 SmSymbolManager::SmSymbolManager(const SmSymbolManager& rSymbolSetManager) : 162 SfxListener() 163 { 164 m_aSymbols = rSymbolSetManager.m_aSymbols; 165 m_bModified = true; 166 } 167 168 169 SmSymbolManager::~SmSymbolManager() 170 { 171 } 172 173 174 SmSymbolManager& SmSymbolManager::operator = (const SmSymbolManager& rSymbolSetManager) 175 { 176 m_aSymbols = rSymbolSetManager.m_aSymbols; 177 m_bModified = true; 178 return *this; 179 } 180 181 182 SmSym *SmSymbolManager::GetSymbolByName(const String& rSymbolName) 183 { 184 SmSym *pRes = NULL; 185 SymbolMap_t::iterator aIt( m_aSymbols.find( rSymbolName ) ); 186 if (aIt != m_aSymbols.end()) 187 pRes = &aIt->second; 188 return pRes; 189 } 190 191 192 const SymbolPtrVec_t SmSymbolManager::GetSymbols() const 193 { 194 SymbolPtrVec_t aRes; 195 SymbolMap_t::const_iterator aIt( m_aSymbols.begin() ); 196 for ( ; aIt != m_aSymbols.end(); ++aIt) 197 aRes.push_back( &aIt->second ); 198 // DBG_ASSERT( sSymbols.size() == m_aSymbols.size(), "number of symbols mismatch " ); 199 return aRes; 200 } 201 202 203 bool SmSymbolManager::AddOrReplaceSymbol( const SmSym &rSymbol, bool bForceChange ) 204 { 205 bool bAdded = false; 206 207 const String aSymbolName( rSymbol.GetName() ); 208 if (aSymbolName.Len() > 0 && rSymbol.GetSymbolSetName().Len() > 0) 209 { 210 const SmSym *pFound = GetSymbolByName( aSymbolName ); 211 const bool bSymbolConflict = pFound && !pFound->IsEqualInUI( rSymbol ); 212 213 // avoid having the same symbol name twice but with different symbols in use 214 if (!pFound || bForceChange) 215 { 216 m_aSymbols[ aSymbolName ] = rSymbol; 217 bAdded = true; 218 } 219 else if (pFound && !bForceChange && bSymbolConflict) 220 { 221 // TODO: to solve this a document owned symbol manager would be required ... 222 // But for now we have a global one to easily support availability of all 223 // symbols in all formulas. A copy of the global one would be needed here 224 // and then the new symbol has to be forcefully applied. This would keep 225 // the current formula intact but will leave the set of symbols in the 226 // global symbol manager somewhat to chance. 227 DBG_ASSERT( 0, "symbol conflict, different symbol with same name found!" ); 228 } 229 230 if (bAdded) 231 m_bModified = true; 232 DBG_ASSERT( bAdded || (pFound && !bSymbolConflict), "AddOrReplaceSymbol: unresolved symbol conflict" ); 233 } 234 235 return bAdded; 236 } 237 238 239 void SmSymbolManager::RemoveSymbol( const String & rSymbolName ) 240 { 241 if (rSymbolName.Len() > 0) 242 { 243 size_t nOldSize = m_aSymbols.size(); 244 m_aSymbols.erase( rSymbolName ); 245 m_bModified = nOldSize != m_aSymbols.size(); 246 } 247 } 248 249 250 std::set< String > SmSymbolManager::GetSymbolSetNames() const 251 { 252 std::set< String > aRes; 253 SymbolMap_t::const_iterator aIt( m_aSymbols.begin() ); 254 for ( ; aIt != m_aSymbols.end(); ++aIt ) 255 aRes.insert( aIt->second.GetSymbolSetName() ); 256 return aRes; 257 } 258 259 260 const SymbolPtrVec_t SmSymbolManager::GetSymbolSet( const String& rSymbolSetName ) 261 { 262 SymbolPtrVec_t aRes; 263 if (rSymbolSetName.Len() > 0) 264 { 265 SymbolMap_t::const_iterator aIt( m_aSymbols.begin() ); 266 for ( ; aIt != m_aSymbols.end(); ++aIt ) 267 { 268 if (aIt->second.GetSymbolSetName() == rSymbolSetName) 269 aRes.push_back( &aIt->second ); 270 } 271 } 272 return aRes; 273 } 274 275 276 void SmSymbolManager::Load() 277 { 278 std::vector< SmSym > aSymbols; 279 SmMathConfig &rCfg = *SM_MOD()->GetConfig(); 280 rCfg.GetSymbols( aSymbols ); 281 size_t nSymbolCount = aSymbols.size(); 282 283 m_aSymbols.clear(); 284 for (size_t i = 0; i < nSymbolCount; ++i) 285 { 286 const SmSym &rSym = aSymbols[i]; 287 DBG_ASSERT( rSym.GetName().Len() > 0, "symbol without name!" ); 288 if (rSym.GetName().Len() > 0) 289 AddOrReplaceSymbol( rSym ); 290 } 291 m_bModified = true; 292 293 if (0 == nSymbolCount) 294 { 295 DBG_ERROR( "no symbol set found" ); 296 m_bModified = false; 297 } 298 299 // now add a %i... symbol to the 'iGreek' set for every symbol found in the 'Greek' set. 300 SmLocalizedSymbolData aLocalizedData; 301 const String aGreekSymbolSetName( aLocalizedData.GetUiSymbolSetName( A2OU("Greek") ) ); 302 const SymbolPtrVec_t aGreekSymbols( GetSymbolSet( aGreekSymbolSetName ) ); 303 String aSymbolSetName( (sal_Unicode) 'i' ); 304 aSymbolSetName += aGreekSymbolSetName; 305 size_t nSymbols = aGreekSymbols.size(); 306 for (size_t i = 0; i < nSymbols; ++i) 307 { 308 // make the new symbol a copy but with ITALIC_NORMAL, and add it to iGreek 309 const SmSym &rSym = *aGreekSymbols[i]; 310 Font aFont( rSym.GetFace() ); 311 DBG_ASSERT( aFont.GetItalic() == ITALIC_NONE, "expected Font with ITALIC_NONE, failed." ); 312 aFont.SetItalic( ITALIC_NORMAL ); 313 String aSymbolName( (sal_Unicode)'i' ); 314 aSymbolName += rSym.GetName(); 315 SmSym aSymbol( aSymbolName, aFont, rSym.GetCharacter(), 316 aSymbolSetName, sal_True /*bIsPredefined*/ ); 317 318 AddOrReplaceSymbol( aSymbol ); 319 } 320 } 321 322 void SmSymbolManager::Save() 323 { 324 if (m_bModified) 325 { 326 SmMathConfig &rCfg = *SM_MOD()->GetConfig(); 327 328 #if 0 329 sal_uInt16 nSymbolCount = GetSymbolCount(); 330 sal_uInt16 nSaveSymbolCnt = 0; 331 const SmSym **pSymbols = new const SmSym* [ nSymbolCount ]; 332 const SmSym **pSym = pSymbols; 333 for (sal_uInt16 j = 0; j < nSymbolCount; ++j) 334 { 335 const SmSym &rSym = *pSymSet->GetSymbol( j ); 336 if (!rSym.IsDocSymbol()) 337 { 338 *pSym++ = &rSym; 339 ++nSaveSymbolCnt; 340 } 341 } 342 DBG_ASSERT(pSym - pSymbols == nSaveSymbolCnt, "wrong number of symbols" ); 343 #endif 344 345 // prepare to skip symbols from iGreek on saving 346 SmLocalizedSymbolData aLocalizedData; 347 String aSymbolSetName( (sal_Unicode) 'i' ); 348 aSymbolSetName += aLocalizedData.GetUiSymbolSetName( A2OU("Greek") ); 349 350 SymbolPtrVec_t aTmp( GetSymbols() ); 351 std::vector< SmSym > aSymbols; 352 for (size_t i = 0; i < aTmp.size(); ++i) 353 { 354 // skip symbols from iGreek set since those symbols always get added 355 // by computational means in SmSymbolManager::Load 356 if (aTmp[i]->GetSymbolSetName() != aSymbolSetName) 357 aSymbols.push_back( *aTmp[i] ); 358 } 359 rCfg.SetSymbols( aSymbols ); 360 #if 0 361 delete [] pSymbols; 362 #endif 363 364 m_bModified = false; 365 } 366 } 367 368 369