diff options
Diffstat (limited to 'starmath/source/symbol.cxx')
-rw-r--r-- | starmath/source/symbol.cxx | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/starmath/source/symbol.cxx b/starmath/source/symbol.cxx new file mode 100644 index 0000000000..4bb854f123 --- /dev/null +++ b/starmath/source/symbol.cxx @@ -0,0 +1,309 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <symbol.hxx> +#include <utility.hxx> +#include <cfgitem.hxx> +#include <smmod.hxx> +#include <format.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> + + +SmSym::SmSym() : + m_aUiName(OUString("unknown")), + m_aSetName(OUString("unknown")), + m_cChar('\0'), + m_bPredefined(false) +{ + m_aExportName = m_aUiName; + m_aFace.SetTransparent(true); + m_aFace.SetAlignment(ALIGN_BASELINE); +} + + +SmSym::SmSym(const SmSym& rSymbol) +{ + *this = rSymbol; +} + + +SmSym::SmSym(const OUString& rName, const vcl::Font& rFont, sal_UCS4 cChar, + const OUString& rSet, bool bIsPredefined) +{ + m_aUiName = m_aExportName = rName; + + m_aFace = rFont; + m_aFace.SetTransparent(true); + m_aFace.SetAlignment(ALIGN_BASELINE); + + m_cChar = cChar; + m_aSetName = rSet; + m_bPredefined = bIsPredefined; +} + + +SmSym& SmSym::operator = (const SmSym& rSymbol) +{ + m_aUiName = rSymbol.m_aUiName; + m_aExportName = rSymbol.m_aExportName; + m_cChar = rSymbol.m_cChar; + m_aFace = rSymbol.m_aFace; + m_aSetName = rSymbol.m_aSetName; + m_bPredefined = rSymbol.m_bPredefined; + + SM_MOD()->GetSymbolManager().SetModified(true); + + return *this; +} + + +bool SmSym::IsEqualInUI( const SmSym& rSymbol ) const +{ + return m_aUiName == rSymbol.m_aUiName && + m_aFace == rSymbol.m_aFace && + m_cChar == rSymbol.m_cChar; +} + +const vcl::Font& SmSym::GetFace(const SmFormat* pFormat) const +{ + if (m_aFace.GetFamilyName().isEmpty()) + { + if (!pFormat) + pFormat = &SM_MOD()->GetConfig()->GetStandardFormat(); + return pFormat->GetFont(FNT_VARIABLE); + } + return m_aFace; +} + +/**************************************************************************/ + + +SmSymbolManager::SmSymbolManager() +{ + m_bModified = false; +} + + +SmSymbolManager::SmSymbolManager(const SmSymbolManager& rSymbolSetManager) +{ + m_aSymbols = rSymbolSetManager.m_aSymbols; + m_bModified = true; +} + + +SmSymbolManager::~SmSymbolManager() +{ +} + + +SmSymbolManager& SmSymbolManager::operator = (const SmSymbolManager& rSymbolSetManager) +{ + m_aSymbols = rSymbolSetManager.m_aSymbols; + m_bModified = true; + return *this; +} + +SmSym* SmSymbolManager::GetSymbolByName(std::u16string_view rSymbolName) +{ + SmSym* pRes = GetSymbolByUiName(rSymbolName); + if (!pRes) + pRes = GetSymbolByExportName(rSymbolName); + return pRes; +} + +SmSym *SmSymbolManager::GetSymbolByUiName(std::u16string_view rSymbolName) +{ + OUString aSymbolName(rSymbolName); + SmSym *pRes = nullptr; + SymbolMap_t::iterator aIt( m_aSymbols.find( aSymbolName ) ); + if (aIt != m_aSymbols.end()) + pRes = &aIt->second; + return pRes; +} + +SmSym* SmSymbolManager::GetSymbolByExportName(std::u16string_view rSymbolName) +{ + SmSym* pRes = nullptr; + for (auto& rPair : m_aSymbols) + { + SmSym& rSymbol = rPair.second; + if (rSymbol.GetExportName() == rSymbolName) + { + pRes = &rSymbol; + break; + } + } + return pRes; +} + + +SymbolPtrVec_t SmSymbolManager::GetSymbols() const +{ + SymbolPtrVec_t aRes; + aRes.reserve(m_aSymbols.size()); + for (const auto& rEntry : m_aSymbols) + aRes.push_back( &rEntry.second ); +// OSL_ENSURE( sSymbols.size() == m_aSymbols.size(), "number of symbols mismatch " ); + return aRes; +} + + +bool SmSymbolManager::AddOrReplaceSymbol( const SmSym &rSymbol, bool bForceChange ) +{ + bool bAdded = false; + + const OUString& aSymbolName( rSymbol.GetUiName() ); + if (!aSymbolName.isEmpty() && !rSymbol.GetSymbolSetName().isEmpty()) + { + const SmSym *pFound = GetSymbolByUiName( aSymbolName ); + const bool bSymbolConflict = pFound && !pFound->IsEqualInUI( rSymbol ); + + // avoid having the same symbol name twice but with different symbols in use + if (!pFound || bForceChange) + { + m_aSymbols[ aSymbolName ] = rSymbol; + bAdded = true; + } + else if (bSymbolConflict) + { + // TODO: to solve this a document owned symbol manager would be required ... + SAL_WARN("starmath", "symbol conflict, different symbol with same name found!"); + // symbols in all formulas. A copy of the global one would be needed here + // and then the new symbol has to be forcefully applied. This would keep + // the current formula intact but will leave the set of symbols in the + // global symbol manager somewhat to chance. + } + + OSL_ENSURE( bAdded, "failed to add symbol" ); + if (bAdded) + m_bModified = true; + OSL_ENSURE( bAdded || (pFound && !bSymbolConflict), "AddOrReplaceSymbol: unresolved symbol conflict" ); + } + + return bAdded; +} + + +void SmSymbolManager::RemoveSymbol( const OUString & rSymbolName ) +{ + if (!rSymbolName.isEmpty()) + { + size_t nOldSize = m_aSymbols.size(); + m_aSymbols.erase( rSymbolName ); + m_bModified = nOldSize != m_aSymbols.size(); + } +} + + +std::set< OUString > SmSymbolManager::GetSymbolSetNames() const +{ + std::set< OUString > aRes; + for (const auto& rEntry : m_aSymbols) + aRes.insert( rEntry.second.GetSymbolSetName() ); + return aRes; +} + + +SymbolPtrVec_t SmSymbolManager::GetSymbolSet( std::u16string_view rSymbolSetName ) +{ + SymbolPtrVec_t aRes; + if (!rSymbolSetName.empty()) + { + for (const auto& rEntry : m_aSymbols) + { + if (rEntry.second.GetSymbolSetName() == rSymbolSetName) + aRes.push_back( &rEntry.second ); + } + } + return aRes; +} + + +void SmSymbolManager::Load() +{ + std::vector< SmSym > aSymbols; + SmMathConfig &rCfg = *SM_MOD()->GetConfig(); + rCfg.GetSymbols( aSymbols ); + size_t nSymbolCount = aSymbols.size(); + + m_aSymbols.clear(); + for (size_t i = 0; i < nSymbolCount; ++i) + { + const SmSym &rSym = aSymbols[i]; + OSL_ENSURE( !rSym.GetUiName().isEmpty(), "symbol without name!" ); + if (!rSym.GetUiName().isEmpty()) + AddOrReplaceSymbol( rSym ); + } + m_bModified = true; + + if (0 == nSymbolCount) + { + SAL_WARN("starmath", "no symbol set found"); + m_bModified = false; + } + + // now add a %i... symbol to the 'iGreek' set for every symbol found in the 'Greek' set. + const OUString aGreekSymbolSetName(SmLocalizedSymbolData::GetUiSymbolSetName(u"Greek")); + const SymbolPtrVec_t aGreekSymbols( GetSymbolSet( aGreekSymbolSetName ) ); + OUString aSymbolSetName = "i" + aGreekSymbolSetName; + size_t nSymbols = aGreekSymbols.size(); + for (size_t i = 0; i < nSymbols; ++i) + { + // make the new symbol a copy but with ITALIC_NORMAL, and add it to iGreek + const SmSym &rSym = *aGreekSymbols[i]; + vcl::Font aFont( rSym.GetFace() ); + OSL_ENSURE( aFont.GetItalic() == ITALIC_NONE, "expected Font with ITALIC_NONE, failed." ); + aFont.SetItalic( ITALIC_NORMAL ); + OUString aSymbolName = "i" + rSym.GetUiName(); + SmSym aSymbol( aSymbolName, aFont, rSym.GetCharacter(), + aSymbolSetName, true /*bIsPredefined*/ ); + aSymbol.SetExportName("i" + rSym.GetExportName()); + + AddOrReplaceSymbol( aSymbol ); + } +} + +void SmSymbolManager::Save() +{ + if (!m_bModified) + return; + + SmMathConfig &rCfg = *SM_MOD()->GetConfig(); + + // prepare to skip symbols from iGreek on saving + OUString aSymbolSetName = "i" + + SmLocalizedSymbolData::GetUiSymbolSetName(u"Greek"); + + SymbolPtrVec_t aTmp( GetSymbols() ); + std::vector< SmSym > aSymbols; + for (const SmSym* i : aTmp) + { + // skip symbols from iGreek set since those symbols always get added + // by computational means in SmSymbolManager::Load + if (i->GetSymbolSetName() != aSymbolSetName) + aSymbols.push_back( *i ); + } + rCfg.SetSymbols( aSymbols ); + + m_bModified = false; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |