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