1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
11 #include <SearchResultLocator.hxx>
13 #include <drawdoc.hxx>
17 #include <IDocumentDrawModelAccess.hxx>
18 #include <IDocumentLayoutAccess.hxx>
20 #include <tools/XmlWalker.hxx>
21 #include <tools/stream.hxx>
23 #include <boost/property_tree/json_parser.hpp>
25 #include <svx/svdpage.hxx>
26 #include <svx/svdobj.hxx>
30 void SearchResultLocator::findOne(LocationResult
& rResult
, SearchIndexData
const& rSearchIndexData
)
32 if (rSearchIndexData
.meType
== NodeType::WriterNode
)
34 SwNodes
const& rNodes
= mpDocument
->GetNodes();
35 if (rSearchIndexData
.mnNodeIndex
>= rNodes
.Count())
37 SwNode
* pNode
= rNodes
[rSearchIndexData
.mnNodeIndex
];
39 auto* pContentNode
= pNode
->GetContentNode();
40 auto* pShell
= mpDocument
->getIDocumentLayoutAccess().GetCurrentViewShell();
42 if (pContentNode
&& pShell
)
45 = pContentNode
->getLayoutFrame(pShell
->GetLayout(), nullptr, nullptr);
46 SwRect
const& rArea
= pFrame
->getFrameArea();
48 rResult
.mbFound
= true;
49 rResult
.maRectangles
.emplace_back(rArea
.Left(), rArea
.Top(),
50 rArea
.Left() + rArea
.Width(),
51 rArea
.Top() + rArea
.Height());
54 else if (rSearchIndexData
.meType
== NodeType::CommonNode
)
56 IDocumentDrawModelAccess
& rDrawModelAccess
= mpDocument
->getIDocumentDrawModelAccess();
57 auto* pModel
= rDrawModelAccess
.GetDrawModel();
58 for (sal_uInt16 nPage
= 0; nPage
< pModel
->GetPageCount(); ++nPage
)
60 SdrPage
* pPage
= pModel
->GetPage(nPage
);
61 for (size_t nObject
= 0; nObject
< pPage
->GetObjCount(); ++nObject
)
63 SdrObject
* pObject
= pPage
->GetObj(nObject
);
66 if (pObject
->GetName() == rSearchIndexData
.maObjectName
)
68 auto aRect
= pObject
->GetLogicRect();
69 rResult
.mbFound
= true;
70 rResult
.maRectangles
.emplace_back(aRect
.Left(), aRect
.Top(),
71 aRect
.Left() + aRect
.GetWidth(),
72 aRect
.Top() + aRect
.GetHeight());
80 LocationResult
SearchResultLocator::find(std::vector
<SearchIndexData
> const& rSearchIndexDataVector
)
82 LocationResult aResult
;
83 for (auto const& rSearchIndexData
: rSearchIndexDataVector
)
84 findOne(aResult
, rSearchIndexData
);
89 /** Trying to parse the payload as JSON
91 * Returns true if parsing was successful and the payload was identified as JSON, else false
93 bool SearchResultLocator::tryParseJSON(const char* pPayload
,
94 std::vector
<sw::search::SearchIndexData
>& rDataVector
)
96 boost::property_tree::ptree aTree
;
97 std::stringstream
aStream(pPayload
);
100 boost::property_tree::read_json(aStream
, aTree
);
102 catch (const boost::property_tree::json_parser_error
& /*exception*/)
107 for (const auto& rEachNode
: boost::make_iterator_range(aTree
.equal_range("")))
109 auto const& rEach
= rEachNode
.second
;
111 std::string sType
= rEach
.get
<std::string
>("node_type", "");
113 auto eNodeType
= sw::search::NodeType::Undefined
;
114 if (sType
== "writer")
115 eNodeType
= sw::search::NodeType::WriterNode
;
116 else if (sType
== "common")
117 eNodeType
= sw::search::NodeType::CommonNode
;
119 std::string sJsonObjectName
= rEach
.get
<std::string
>("object_name", "");
121 SwNodeOffset
nIndex(rEach
.get
<sal_Int32
>("index", -1));
123 // Don't add search data elements that don't have valid data
124 if (eNodeType
!= sw::search::NodeType::Undefined
&& nIndex
>= SwNodeOffset(0))
126 OUString sObjectName
;
127 if (!sJsonObjectName
.empty())
129 OString
sObjectNameOString(sJsonObjectName
);
130 sObjectName
= OStringToOUString(sObjectNameOString
, RTL_TEXTENCODING_UTF8
);
133 rDataVector
.emplace_back(eNodeType
, nIndex
, sObjectName
);
140 /** Trying to parse the payload as XML
142 * Returns true if parsing was successful and the payload was identified as XML, else false
144 bool SearchResultLocator::tryParseXML(const char* pPayload
,
145 std::vector
<sw::search::SearchIndexData
>& rDataVector
)
147 const OString
aPayloadString(pPayload
);
149 SvMemoryStream
aStream(const_cast<char*>(aPayloadString
.getStr()), aPayloadString
.getLength(),
152 tools::XmlWalker aWalker
;
154 if (!aWalker
.open(&aStream
))
157 if (aWalker
.name() != "indexing")
161 while (aWalker
.isValid())
163 if (aWalker
.name() == "paragraph")
165 OString sType
= aWalker
.attribute("node_type");
166 OString sIndex
= aWalker
.attribute("index");
167 OString sObjectName
= aWalker
.attribute("object_name");
169 if (!sType
.isEmpty() && !sIndex
.isEmpty())
171 sw::search::SearchIndexData aData
;
172 aData
.mnNodeIndex
= SwNodeOffset(sIndex
.toInt32());
173 auto eNodeType
= sw::search::NodeType::Undefined
;
174 if (sType
== "writer")
175 eNodeType
= sw::search::NodeType::WriterNode
;
176 else if (sType
== "common")
177 eNodeType
= sw::search::NodeType::CommonNode
;
179 aData
.meType
= eNodeType
;
180 if (!sObjectName
.isEmpty())
181 aData
.maObjectName
= OStringToOUString(sObjectName
, RTL_TEXTENCODING_UTF8
);
182 rDataVector
.push_back(aData
);
191 LocationResult
SearchResultLocator::findForPayload(const char* pPayload
)
193 std::vector
<sw::search::SearchIndexData
> aDataVector
;
195 // Try parse the payload as JSON, if not recognised as JSON, try parse
197 tryParseJSON(pPayload
, aDataVector
) || tryParseXML(pPayload
, aDataVector
);
199 return find(aDataVector
);
202 } // end sw namespace
204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */