#前回のまとめ
なんかいい感じのフォルダを見つけた。
#inputhdl.cxxに辿り着くまで
##関数の引数の説明を出す関数
前回読んでいた/sc/source/core/data/funcdesk.cxx
の中身を目で追っていると、こんな関数を発見。
OUString ScFuncDesc::getSignature() const
{
OUStringBuffer aSig;
if(pFuncName)
{
aSig.append(*pFuncName);
OUString aParamList = GetParamList();
if( !aParamList.isEmpty() )
{
aSig.appendAscii( "( " );
aSig.append(aParamList);
// U+00A0 (NBSP) prevents automatic line break
aSig.append( static_cast< sal_Unicode >(0xA0) );
aSig.appendAscii( ")" );
}
else
aSig.appendAscii( "()" );
}
return aSig.makeStringAndClear();
}
pFuncNameを足して、(を足して、aParamListを足して、)を足す…。これって、もしかして関数の引数の説明では?
というわけで、ちょっと内容を改変して実行してみる。
if(pFuncName)
{
aSig.append(*pFuncName);
OUString aParamList = GetParamList();
if( !aParamList.isEmpty() )
{
aSig.appendAscii( "( " );
// added
aSig.appendAscii( "!" );
aSig.appendAscii( "t" );
aSig.appendAscii( "!" );
// end added
aSig.append(aParamList);
// U+00A0 (NBSP) prevents automatic line break
aSig.append( static_cast< sal_Unicode >(0xA0) );
aSig.appendAscii( ")" );
}
else
aSig.appendAscii( "()" );
}
実行してみると、
うまくいった!やはり関数の引数の説明はここで作っていたようだ。
##バックトレースの旅
ここにブレークポイントを挟んで、この関数を呼び出している元を見てみる。
// The other types are defined in ScDocument::GetFormulaEntries
void ScInputHandler::GetFormulaData()
{
if ( pActiveViewSh )
{
ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
if ( pFormulaData )
pFormulaData->clear();
else
{
pFormulaData = new ScTypedCaseStrSet;
}
if( pFormulaDataPara )
pFormulaDataPara->clear();
else
pFormulaDataPara = new ScTypedCaseStrSet;
const OUString aParenthesesReplacement( cParenthesesReplacement);
const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
sal_uLong nListCount = pFuncList->GetCount();
for(sal_uLong i=0;i<nListCount;i++)
{
const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
if ( pDesc->pFuncName )
{
const sal_Unicode* pName = pDesc->pFuncName->getStr();
const sal_Int32 nLen = pDesc->pFuncName->getLength();
// fdo#75264 fill maFormulaChar with all characters used in formula names
for ( sal_Int32 j = 0; j < nLen; j++ )
{
sal_Unicode c = pName[ j ];
maFormulaChar.insert( c );
}
OUString aFuncName = *pDesc->pFuncName + aParenthesesReplacement;
pFormulaData->insert(ScTypedStrData(aFuncName, 0.0, ScTypedStrData::Standard));
pDesc->initArgumentInfo();
OUString aEntry = pDesc->getSignature();
pFormulaDataPara->insert(ScTypedStrData(aEntry, 0.0, ScTypedStrData::Standard));
}
}
miAutoPosFormula = pFormulaData->end();
rDoc.GetFormulaEntries( *pFormulaData );
rDoc.GetFormulaEntries( *pFormulaDataPara );
}
}
どうやら、これらの処理は起動して最初に=を押した時だけ発動するようだ。うーむ、それだと目的と違うなあ。
pFormulaDataPara->insert(ScTypedStrData(aEntry, 0.0, ScTypedStrData::Standard));
という一文に着目。ここにデータが入っているようなので、このデータを呼び出している関数を探す。
// ScInputHandler
class ScInputHandler : boost::noncopyable
{
private:
ScInputWindow* pInputWin;
ScEditEngineDefaulter* pEngine; // edited data in the sheet
EditView* pTableView; // associated active EditView
EditView* pTopView; // EditView in dthe input row
ScTypedCaseStrSet* pColumnData;
ScTypedCaseStrSet* pFormulaData;
ScTypedCaseStrSet* pFormulaDataPara;
ScTypedCaseStrSet::const_iterator miAutoPosColumn;
ScTypedCaseStrSet::const_iterator miAutoPosFormula;
// 以下、無関係なので略
ScTypedCaseStrSetクラスの定義はこれ。
typedef std::set<ScTypedStrData, ScTypedStrData::LessCaseSensitive> ScTypedCaseStrSet;
setはC++のSTL(標準コンテナ、配列のすごいやつ)の一つで、有限集合を扱うクラス。なんだけど、普通型のとこ(<>の中)にはクラス名を1個だけ指定するよね?なんでコンマ区切りで2個あるんだ…?
調べてみて解決。なんとなく想像ついてはいたけど、比較関数を指定できるのね。
で、肝心の「ScTypedStrData(おなまえ, 0.0, ScTypedStrData::Standard)」がわからないとどうしようもないので、ScTypedStrDataクラスの定義を探した。
class ScTypedStrData
{
public:
enum StringType {
Value = 0,
Standard = 1,
Name = 2,
DbName = 3,
Header = 4
};
ScTypedStrData( const OUString& rStr, double nVal = 0.0,
StringType eType = Standard, bool bDate = false );
ScTypedStrData( const ScTypedStrData& rCpy );
bool IsStrData() const;
bool IsDate() const { return mbIsDate;}
const OUString& GetString() const { return maStrValue;}
StringType GetStringType() const { return meStrType;}
double GetValue() const { return mfValue; }
struct LessCaseSensitive : std::binary_function<ScTypedStrData, ScTypedStrData, bool>
{
bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const;
};
struct LessCaseInsensitive : std::binary_function<ScTypedStrData, ScTypedStrData, bool>
{
bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const;
};
struct EqualCaseSensitive : std::binary_function<ScTypedStrData, ScTypedStrData, bool>
{
bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const;
};
struct EqualCaseInsensitive : std::binary_function<ScTypedStrData, ScTypedStrData, bool>
{
bool operator() (const ScTypedStrData& left, const ScTypedStrData& right) const;
};
bool operator== (const ScTypedStrData& r) const;
bool operator< (const ScTypedStrData& r) const;
private:
OUString maStrValue;
double mfValue;
StringType meStrType;
bool mbIsDate;
};
無難に比較演算子とかがオーバーロードされてるだけ。
コンストラクタを見てみる。
ScTypedStrData::ScTypedStrData(
const OUString& rStr, double nVal, StringType nType, bool bDate ) :
maStrValue(rStr),
mfValue(nVal),
meStrType(nType),
mbIsDate( bDate ) {}
ScTypedStrData::ScTypedStrData( const ScTypedStrData& rCpy ) :
maStrValue(rCpy.maStrValue),
mfValue(rCpy.mfValue),
meStrType(rCpy.meStrType),
mbIsDate( rCpy.mbIsDate ) {}
boolなんか指定してなかったような…?まあでも、とりあえず文字列はmaStrValueに保存されるらしい。あんまり収穫なさそうだな…。
##ついに発見、関数候補を見つける関数
というわけで、ScInputHandlerオブジェクトがどこで呼び出されているのか、を見に行くことに。もちろんpFormulaDataで検索。すると…
void ScInputHandler::UseFormulaData()
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
// Formulas may only have 1 paragraph
if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
{
OUString aParagraph = pEngine->GetText( 0 );
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
// Due to differences between table and input cell (e.g clipboard with line breaks),
// the selection may not be in line with the EditEngine anymore.
// Just return without any indication as to why.
if ( aSel.nEndPos > aParagraph.getLength() )
return;
// Is the cursor at the end of a word?
if ( aSel.nEndPos > 0 )
{
OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
OUString aText;
if ( GetFuncName( aSelText, aText ) )
{
// function name is incomplete:
// show first matching function name as tip above cell
OUString aNew;
miAutoPosFormula = pFormulaData->end();
miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
if (miAutoPosFormula != pFormulaData->end())
{
if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
ShowTip( aNew );
aAutoSearch = aText;
}
return;
}
// function name is complete:
// show tip below the cell with function name and arguments of function
ShowArgumentsTip( aParagraph, aSelText, aSel, false);
}
}
}
// function name is incomplete:
// show first matching function name as tip above cell
これ、まさに私が今回やりたかったことですよ!!!!!
このプログラムから色々なことがわかるけど、大きい収穫は
- GetFuncName()関数で関数名の一部から関数名を取得し、オートコンプリートまでした上で完全一致かどうかまで調べてくれる。
- ShowTip()関数で上にTipsが表示できる。ShowArgumentTip()関数で下にTipsが表示できる。
いや、これまでで一番大きい収穫ですね。間違いなく。
findText(arg1, arg2, arg3, arg4, arg5)関数は、文字列arg1からポインタarg2を使って文字列arg3を検索して、見つかった単語をarg4に格納する関数…かな?細かいことは定義をみてみないとわかんないけど。
まずはGetFuncName()関数を見てみよう。
bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
{
if ( aStart.isEmpty() )
return false;
aStart = ScGlobal::pCharClass->uppercase( aStart );
sal_Int32 nPos = aStart.getLength() - 1;
sal_Unicode c = aStart[ nPos ];
// fdo#75264 use maFormulaChar to check if characters are used in function names
::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
if ( p == maFormulaChar.end() )
return false; // last character is not part of any function name, quit
::std::vector<sal_Unicode> aTemp;
while ( nPos >= 0 && p != maFormulaChar.end() )
{
aTemp.push_back( c );
c = aStart[ --nPos ];
p = maFormulaChar.find( c );
}
::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
aResult = OUString( *rIt++ );
while ( rIt != aTemp.rend() )
aResult += OUString( *rIt++ );
return true;
}
setオブジェクトのfind(key)関数は、現在のセットから key に一致する要素を検索し、 その要素へのイテレータを返す関数。maFormulaCharは
::std::set< sal_Unicode > maFormulaChar; //fdo 75264
と、Unicodeの集合。中身は以下の通り、ちょっと前に紹介したGetFormulaData()関数内で作られてる。
const sal_Unicode* pName = pDesc->pFuncName->getStr();
const sal_Int32 nLen = pDesc->pFuncName->getLength();
// fdo#75264 fill maFormulaChar with all characters used in formula names
for ( sal_Int32 j = 0; j < nLen; j++ )
{
sal_Unicode c = pName[ j ];
maFormulaChar.insert( c );
}
関数名を1文字ずつ登録しまくったもの(ただしsetなので重複は無視、かつ並べ替え済み)。
一応maFormulaCharがちゃんと思ったとおりに動作してるか確認。
Breakpoint 22, ScInputHandler::GetFormulaData (this=0x167aa40)
at /home/denjo/[pass]/team_babumi_project/libreoffice-4.4.5.2/sc/source/ui/app/inputhdl.cxx:750
(gdb) p /x (sal_Unicode [10])(*pName)
$38 = {0x49, 0x46, 0x0, 0x1000, 0x18, 0x0, 0x0, 0x0, 0x2, 0x0}
(gdb) p maFormulaChar
$36 = {(中略)
_M_parent = 0x1c1e490, _M_left = 0x1b55090, _M_right = 0x1c1e490}, _M_node_count = 2}}},
(中略)}
(gdb) c
Continuing.
Breakpoint 22, ScInputHandler::GetFormulaData (this=0x167aa40)
at /home/denjo/Documents/[pass]/team_babumi_project/libreoffice-4.4.5.2/sc/source/ui/app/inputhdl.cxx:750
(gdb) p /x (sal_Unicode [10])(*pName)
$39 = {0x49, 0x46, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x0, 0x6e, 0x6a}
(gdb) p maFormulaChar
$36 = {(中略)
_M_node_count = 5}}},
(中略)}
0x49はI、0x46はF、0x45はE、0x52はR、0x4fはO。0x00はヌルポインタ。
ちゃんと、文字の種類数だけノードの数が増えていることがわかる。
長くなったが、結局GetFuncName(aStart, aResult)関数はaStartを大文字に変換して後ろから1文字ずつ読んでいき、関数の一部としてはあり得ないような文字(括弧とか、数字とか、記号とか?)にぶつかったらぶつかる手前までの文字列をaResultに代入する関数だった。この関数がtrueを返すということは、aStartの最後の1文字が関数っぽい文字だったということで、つまり括弧が開いたり閉じたりしてないということなので、// function name is incomplete:というわけ。
で、その際の処理を再掲。
if ( GetFuncName( aSelText, aText ) )
{
// function name is incomplete:
// show first matching function name as tip above cell
OUString aNew;
miAutoPosFormula = pFormulaData->end();
miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
if (miAutoPosFormula != pFormulaData->end())
{
if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
ShowTip( aNew );
aAutoSearch = aText;
}
return;
}
aTextには、aSelText(セルに実際に入力されている文字列)のうち後半の関数部分だけが入ってる(例えば、aSelTextが”IF(SUM()=0, AVERAGE(SUMI”だった場合、aTextは”SUMI”)。で、findText。おそらくaNewにaTextから始まる関数(この例だと”SUMIF”)が代入されてるはず。それを表示してShowTip。
さて、じゃあfindText()関数を見てみよう。
ScTypedCaseStrSet::const_iterator findText(
const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
const OUString& rStart, OUString& rResult, bool bBack)
{
if (bBack) // Backwards
{
// 今回使わないので省略
}
else // Forwards
{
ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
if (itPos != rDataSet.end())
{
it = itPos;
++it;
}
for (; it != itEnd; ++it)
{
const ScTypedStrData& rData = *it;
if (rData.GetStringType() == ScTypedStrData::Value)
// skip values
continue;
if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
// not a match
continue;
rResult = rData.GetString();
return it;
}
}
return rDataSet.end(); // no matching text found
}
思ってたよりだいぶ長い関数だったけど、ForwardsとBackWardsで分かれてたので、今回使わないBackwardsは思い切ってカット。
関数の中身は、第一引数rDataSetのなかで第二引数のイテレータitPosから前進しつつ第三引数rStartを探して、isMatch()関数にrDataSet[i]とrStartをぶちこんだ答えがtrueになるようなiがあったらそのrDataSet[i]を第四引数rResultに代入してそこのイテレータを返すって感じ。
#関数候補表示の実装
##とりあえず作ってみる
とりあえず、これまでわかったことだけでもやりたい機能はそれなりに?作れる、ような、気がする。
ので、作ってみた。
ScTypedCaseStrSet::const_iterator findText(
const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
// exchange
// const OUString& rStart, OUString& rResult, bool bBack)
// exchange to
const OUString& rStart, OUString& rResult, bool bBack, int findnumber)
// end exchange
{
if (bBack) // Backwards
{
// 関係ないので略
}
else // Forwards
{
ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
if (itPos != rDataSet.end())
{
it = itPos;
++it;
}
// added
int nCount = 0;
// end added
for (; it != itEnd; ++it)
{
const ScTypedStrData& rData = *it;
if (rData.GetStringType() == ScTypedStrData::Value)
// skip values
continue;
if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
// not a match
continue;
// added
if(nCount < findnumber) { // not yet
nCount ++;
continue;
}
// end added
rResult = rData.GetString();
return it;
}
}
return rDataSet.end(); // no matching text found
}
//
// 1000行くらい省略
//
void ScInputHandler::UseFormulaData()
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
// Formulas may only have 1 paragraph
if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
{
// 長いので省略
if ( aSel.nEndPos > 0 )
{
OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
OUString aText;
if ( GetFuncName( aSelText, aText ) )
{
// function name is incomplete:
// show first matching function name as tip above cell
OUString aNew;
miAutoPosFormula = pFormulaData->end();
// exchange
// miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
// exchange to
miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false, 0);
// exchange end
if (miAutoPosFormula != pFormulaData->end())
{
if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
// added
OUString aNew2;
ScTypedCaseStrSet::const_iterator it = pFormulaData->end();
it = findText(*pFormulaData, miAutoPosFormula, aText, aNew2, false, 1);
if (it != pFormulaData->end())
{
if (aNew2[aNew2.getLength()-1] == cParenthesesReplacement)
aNew2 = aNew2.copy( 0, aNew2.getLength()-1) + "()";
aNew = aNew.copy( 0, aNew.getLength()-1) + "), " + aNew2.copy( 0, aNew2.getLength()-1) + ")";
}
// end added
ShowTip( aNew );
aAutoSearch = aText;
}
return;
}
// これまた長いので省略
}
}
}
後々たくさん表示することも考慮しつつ、findText()関数に「n番目に見つかったものを返却」する機能を追加。それに伴っていろんなところにあるfindText関数の呼び出し部分を全て修正し(ちょっと頭わるかったかも。反省)、UseFormulaData()関数には「1番目の次に2番目の関数も表示」する機能を追加(したつもり)
さあ、makeしてみるぞ…。
##集合で返すように修正
findText()を、文字列の集合を返すように拡張したfindTextAll()関数を作りたいなあ、と思ったので、作ってみる。
集合の表現にはstd::vector<>を使う。OUStringの代わりにstd::vectorを渡すように修正。で、集合を返して、読む側ではイテレータを使ってぶん回す。
作ったものがこちら。
// added
ScTypedCaseStrSet::const_iterator findTextAll(
const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack, int findnumber)
{
rResultVec.clear(); // clear contents
if (bBack) // Backwards
{
ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
if (itPos != rDataSet.end())
{
size_t nPos = std::distance(rDataSet.begin(), itPos);
size_t nRPos = rDataSet.size() - 1 - nPos;
std::advance(it, nRPos);
++it;
}
ScTypedCaseStrSet::const_iterator retit = rDataSet.begin();
int nCount = 0;
for (; it != itEnd; ++it) {
const ScTypedStrData& rData = *it;
if (rData.GetStringType() == ScTypedStrData::Value)
// skip values
continue;
if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
// not a match
continue;
rResultVec.push_back(rData.GetString()); // set the match data
if(nCount == 0)
retit = it.base(); // convert the reverse iterator back to iterator.
nCount ++;
if(nCount >= findnumber)
return retit;
}
}
else // Forwards
{
ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
if (itPos != rDataSet.end())
{
it = itPos;
++it;
}
ScTypedCaseStrSet::const_iterator retit = rDataSet.begin();
int nCount = 0;
for (; it != itEnd; ++it)
{
const ScTypedStrData& rData = *it;
if (rData.GetStringType() == ScTypedStrData::Value)
// skip values
continue;
if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
// not a match
continue;
rResultVec.push_back(rData.GetString()); // set the match data
if(nCount == 0)
retit = it; // remember first match iterator
nCount ++;
if(nCount >= findnumber)
return retit;
}
}
return rDataSet.end(); // no matching text found
}
// end added
で、読み出す方はこう。
void ScInputHandler::UseFormulaData()
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
// Formulas may only have 1 paragraph
if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
{
OUString aParagraph = pEngine->GetText( 0 );
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
// Due to differences between table and input cell (e.g clipboard with line breaks),
// the selection may not be in line with the EditEngine anymore.
// Just return without any indication as to why.
if ( aSel.nEndPos > aParagraph.getLength() )
return;
// Is the cursor at the end of a word?
if ( aSel.nEndPos > 0 )
{
OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
OUString aText;
if ( GetFuncName( aSelText, aText ) )
{
// exchange
// // function name is incomplete:
// // show first matching function name as tip above cell
// OUString aNew;
// miAutoPosFormula = pFormulaData->end();
// miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
// if (miAutoPosFormula != pFormulaData->end())
// {
// if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
// aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
// ShowTip( aNew );
// aAutoSearch = aText;
// }
// return;
// exchange for
// function name is incomplete:
// show matching functions name as tip above cell
int maxFindNumber = 4;
::std::vector<OUString> aNewVec;
miAutoPosFormula = pFormulaData->end();
miAutoPosFormula = findTextAll(*pFormulaData, miAutoPosFormula, aText, aNewVec, false, maxFindNumber);
if (miAutoPosFormula != pFormulaData->end())
{
OUString tipStr;
::std::vector<OUString>::iterator itStr = aNewVec.begin();
for( ; itStr != aNewVec.end(); ++itStr ) {
if(itStr != aNewVec.begin())
tipStr = tipStr.copy(0, tipStr.getLength()) + ", ";
tipStr = tipStr.copy(0, tipStr.getLength()) + (*itStr).copy(0, (*itStr).getLength()-1); // tipStr += *itStr without last character
if ((*itStr)[(*itStr).getLength()-1] == cParenthesesReplacement) {
tipStr = tipStr.copy(0, tipStr.getLength()) + "()";
} else {
tipStr = tipStr.copy(0, (*itStr).getLength()) + (*itStr).copy((*itStr).getLength()-1, (*itStr).getLength());
}
}
ShowTip( tipStr );
aAutoSearch = aText;
}
return;
// end exchange
}
// function name is complete:
// show tip below the cell with function name and arguments of function
ShowArgumentsTip( aParagraph, aSelText, aSel, false);
}
}
}
maxFindNumberで、検索する最大数を指定できる(はず)。
で、実行してみたらこうなった。
う、うーん…これはあれかな、maxFindNumber未満しか見つからなかった時の処理がしょぼいのかな。…で、読みなおしてみたら処理が下手くそだった。やり直し…
ScTypedCaseStrSet::const_iterator findTextAll(
const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack)
{
rResultVec.clear(); // clear contents
int nCount = 0;
ScTypedCaseStrSet::const_iterator retit = rDataSet.begin();
if (bBack) // Backwards
{
// 中略
}
else // Forwards
{
// 中略
}
if(nCount > 0) // at least one function has matched
return retit;
return rDataSet.end(); // no matching text found
}
// end added
void ScInputHandler::UseFormulaData()
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
// Formulas may only have 1 paragraph
if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
{
// 中略
if (miAutoPosFormula != pFormulaData->end())
{
OUString tipStr;
::std::vector<OUString>::iterator itStr = aNewVec.begin();
int maxFindNumber = 4;
for( ; itStr != aNewVec.end(); ++itStr ) {
// 中略
if(--maxFindNumber <= 0)
break;
}
ShowTip( tipStr );
aAutoSearch = aText;
}
return;
// 中略
}
}
ついでに、findTextAll()関数が該当する関数を全て返すように仕様を変更。
これで、無事うまくいった。
#今回のまとめ
ついに目的を半分くらい達成した。やったね。
#次回予告
次回、いよいよ大詰め!やりたいことをどんどん実装していきます。
#リンク
##LibreOfficeCalcに関数候補表示機能を付けるまで