1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <scitems.hxx>
21 
22 #include <com/sun/star/i18n/BreakIterator.hpp>
23 #include <com/sun/star/i18n/ScriptType.hpp>
24 #include <comphelper/processfactory.hxx>
25 
26 #include <document.hxx>
27 #include <cellform.hxx>
28 #include <patattr.hxx>
29 #include <scrdata.hxx>
30 #include <poolhelp.hxx>
31 #include <attrib.hxx>
32 #include <columnspanset.hxx>
33 #include <table.hxx>
34 
35 using namespace com::sun::star;
36 
37 //  this file is compiled with exceptions enabled
38 //  put functions here that need exceptions!
39 
GetBreakIterator()40 const uno::Reference< i18n::XBreakIterator >& ScDocument::GetBreakIterator()
41 {
42     if ( !pScriptTypeData )
43         pScriptTypeData.reset( new ScScriptTypeData );
44     if ( !pScriptTypeData->xBreakIter.is() )
45     {
46         pScriptTypeData->xBreakIter = i18n::BreakIterator::create( comphelper::getProcessComponentContext() );
47     }
48     return pScriptTypeData->xBreakIter;
49 }
50 
HasStringWeakCharacters(const OUString & rString)51 bool ScDocument::HasStringWeakCharacters( const OUString& rString )
52 {
53     if (!rString.isEmpty())
54     {
55         uno::Reference<i18n::XBreakIterator> xBreakIter = GetBreakIterator();
56         if ( xBreakIter.is() )
57         {
58             sal_Int32 nLen = rString.getLength();
59 
60             sal_Int32 nPos = 0;
61             do
62             {
63                 sal_Int16 nType = xBreakIter->getScriptType( rString, nPos );
64                 if ( nType == i18n::ScriptType::WEAK )
65                     return true;                            // found
66 
67                 nPos = xBreakIter->endOfScript( rString, nPos, nType );
68             }
69             while ( nPos >= 0 && nPos < nLen );
70         }
71     }
72 
73     return false;       // none found
74 }
75 
GetStringScriptType(const OUString & rString)76 SvtScriptType ScDocument::GetStringScriptType( const OUString& rString )
77 {
78     SvtScriptType nRet = SvtScriptType::NONE;
79     if (!rString.isEmpty())
80     {
81         uno::Reference<i18n::XBreakIterator> xBreakIter = GetBreakIterator();
82         if ( xBreakIter.is() )
83         {
84             sal_Int32 nLen = rString.getLength();
85 
86             sal_Int32 nPos = 0;
87             do
88             {
89                 sal_Int16 nType = xBreakIter->getScriptType( rString, nPos );
90                 switch ( nType )
91                 {
92                     case i18n::ScriptType::LATIN:
93                         nRet |= SvtScriptType::LATIN;
94                         break;
95                     case i18n::ScriptType::ASIAN:
96                         nRet |= SvtScriptType::ASIAN;
97                         break;
98                     case i18n::ScriptType::COMPLEX:
99                         nRet |= SvtScriptType::COMPLEX;
100                         break;
101                     // WEAK is ignored
102                 }
103                 nPos = xBreakIter->endOfScript( rString, nPos, nType );
104             }
105             while ( nPos >= 0 && nPos < nLen );
106         }
107     }
108     return nRet;
109 }
110 
GetCellScriptType(const ScAddress & rPos,sal_uInt32 nNumberFormat,const ScRefCellValue * pCell)111 SvtScriptType ScDocument::GetCellScriptType( const ScAddress& rPos, sal_uInt32 nNumberFormat,
112                                              const ScRefCellValue* pCell )
113 {
114     SvtScriptType nStored = GetScriptType(rPos);
115     if ( nStored != SvtScriptType::UNKNOWN )         // stored value valid?
116         return nStored;                             // use stored value
117 
118     const Color* pColor;
119     OUString aStr;
120     if( pCell )
121         ScCellFormat::GetString(*pCell, nNumberFormat, aStr, &pColor, *mxPoolHelper->GetFormTable(), *this);
122     else
123         aStr = ScCellFormat::GetString(*this, rPos, nNumberFormat, &pColor, *mxPoolHelper->GetFormTable());
124 
125     SvtScriptType nRet = GetStringScriptType( aStr );
126 
127     SetScriptType(rPos, nRet);       // store for later calls
128 
129     return nRet;
130 }
131 
GetScriptType(SCCOL nCol,SCROW nRow,SCTAB nTab,const ScRefCellValue * pCell)132 SvtScriptType ScDocument::GetScriptType( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScRefCellValue* pCell )
133 {
134     // if script type is set, don't have to get number formats
135 
136     ScAddress aPos(nCol, nRow, nTab);
137     SvtScriptType nStored = GetScriptType(aPos);
138     if ( nStored != SvtScriptType::UNKNOWN )         // stored value valid?
139         return nStored;                             // use stored value
140 
141     // include number formats from conditional formatting
142 
143     const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
144     if (!pPattern) return SvtScriptType::NONE;
145     const SfxItemSet* pCondSet = nullptr;
146     if ( !pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty() )
147         pCondSet = GetCondResult( nCol, nRow, nTab );
148 
149     sal_uInt32 nFormat = pPattern->GetNumberFormat( mxPoolHelper->GetFormTable(), pCondSet );
150 
151     return GetCellScriptType(aPos, nFormat, pCell);
152 }
153 
154 namespace {
155 
156 class ScriptTypeAggregator : public sc::ColumnSpanSet::Action
157 {
158     ScDocument& mrDoc;
159     sc::ColumnBlockPosition maBlockPos;
160     SvtScriptType mnScriptType;
161 
162 public:
ScriptTypeAggregator(ScDocument & rDoc)163     explicit ScriptTypeAggregator(ScDocument& rDoc) : mrDoc(rDoc), mnScriptType(SvtScriptType::NONE) {}
164 
startColumn(SCTAB nTab,SCCOL nCol)165     virtual void startColumn(SCTAB nTab, SCCOL nCol) override
166     {
167         mrDoc.InitColumnBlockPosition(maBlockPos, nTab, nCol);
168     }
169 
execute(const ScAddress & rPos,SCROW nLength,bool bVal)170     virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal) override
171     {
172         if (!bVal)
173             return;
174 
175         mnScriptType |= mrDoc.GetRangeScriptType(maBlockPos, rPos, nLength);
176     };
177 
getScriptType() const178     SvtScriptType getScriptType() const { return mnScriptType; }
179 };
180 
181 }
182 
GetRangeScriptType(sc::ColumnBlockPosition & rBlockPos,const ScAddress & rPos,SCROW nLength)183 SvtScriptType ScDocument::GetRangeScriptType(
184     sc::ColumnBlockPosition& rBlockPos, const ScAddress& rPos, SCROW nLength )
185 {
186     if (!TableExists(rPos.Tab()))
187         return SvtScriptType::NONE;
188 
189     return maTabs[rPos.Tab()]->GetRangeScriptType(rBlockPos, rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
190 }
191 
GetRangeScriptType(const ScRangeList & rRanges)192 SvtScriptType ScDocument::GetRangeScriptType( const ScRangeList& rRanges )
193 {
194     sc::ColumnSpanSet aSet;
195     for (size_t i = 0, n = rRanges.size(); i < n; ++i)
196     {
197         const ScRange& rRange = rRanges[i];
198         SCTAB nTab = rRange.aStart.Tab();
199         SCROW nRow1 = rRange.aStart.Row();
200         SCROW nRow2 = rRange.aEnd.Row();
201         for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
202             aSet.set(*this, nTab, nCol, nRow1, nRow2, true);
203     }
204 
205     ScriptTypeAggregator aAction(*this);
206     aSet.executeAction(aAction);
207     return aAction.getScriptType();
208 }
209 
210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
211