xref: /aoo41x/main/starmath/source/symbol.cxx (revision cdf0e10c)
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