对前面的文章:数据结构树节点深度和广度关系递归记录进行了延伸,下面给出演示代码:
typedef struct NODEINFO {
NODEINFO() {
pParent = nullptr;
pBefore = nullptr;
pAfter = nullptr;
pChild = nullptr;
}
NODEINFO(FPD_Object Parent, FPD_Object Before, FPD_Object After,
FPD_Object Child)
{
pParent = Parent;
pBefore = Before;
pAfter = After;
pChild = Child;
}
FPD_Object pParent;
FPD_Object pBefore;
FPD_Object pAfter;
FPD_Object pChild;
}*LPNODEINFO;
void GetTreeTopologyInfo(FPD_Bookmark pCurrentBM);
void InsertNode(FPD_Bookmark pCurrentBM);
void SetParent(FPD_Bookmark pCurrentBM, FPD_Bookmark pParent);
FPD_Object GetParent(FPD_Object fpdObject);
void SetPrevSibling(FPD_Bookmark pCurrentBM, FPD_Bookmark pBefore);
FPD_Object GetPrevSibling(FPD_Object fpdObject);
FPD_Object GetNextSibling(FPD_Object fpdObject);
.......
std::map<FPD_Object, NODEINFO>m_mapTreeData;
//获得上层的父节点,父节点可能没有直接指向子节点
//是为了UI的便捷性
void CPDF_Bookmark::InsertNode(FPD_Bookmark pCurrentBM)
{
FPD_Object fpdCurrentBM = FPDBookmarkGetDictionary(pCurrentBM);
if (!fpdCurrentBM)return;
NODEINFO nodeInfo;
m_mapTreeData.insert(std::pair<FPD_Object, NODEINFO>(fpdCurrentBM, nodeInfo));
}
void CPDF_Bookmark::SetParent(FPD_Bookmark pCurrentBM, FPD_Bookmark pParent)
{
FPD_Object fpdCurrentBM = FPDBookmarkGetDictionary(pCurrentBM);
if (!fpdCurrentBM)return;
FPD_Object fpdParentBM = nullptr;
if (pParent)
fpdParentBM = FPDBookmarkGetDictionary(pParent);
m_mapTreeData[fpdCurrentBM].pParent = fpdParentBM;
}
FPD_Object CPDF_Bookmark::GetParent(FPD_Object fpdObject)
{
if (!fpdObject)
return nullptr;
return m_mapTreeData[fpdObject].pParent;
}
void CPDF_Bookmark::SetPrevSibling(FPD_Bookmark pCurrentBM, FPD_Bookmark pBefore)
{
FPD_Object fpdCurrentBM = FPDBookmarkGetDictionary(pCurrentBM);
if (!fpdCurrentBM)return;
FPD_Object fpdBeforeBM = nullptr;
if (pBefore)
fpdBeforeBM = FPDBookmarkGetDictionary(pBefore);
m_mapTreeData[fpdCurrentBM].pBefore = fpdBeforeBM;
}
FPD_Object CPDF_Bookmark::GetPrevSibling(FPD_Object fpdObject)
{
if (!fpdObject)
return nullptr;
return m_mapTreeData[fpdObject].pBefore;
}
FPD_Object CPDF_Bookmark::GetNextSibling(FPD_Object fpdObject)
{
FPD_Bookmark bmPrev = FPDBookmarkNew(fpdObject);
FPD_Bookmark bmNext = FPDBookmarkNew(nullptr);
FPDBookmarkGetNextSibling(m_fpdDoc, bmPrev, &bmNext);
FPD_Object pNext = FPDBookmarkGetDictionary(bmNext);
FPDBookmarkDestroy(bmNext);
FPDBookmarkDestroy(bmPrev);
return pNext;
}
void CPDF_Bookmark::GetTreeTopologyInfo(FPD_Bookmark pCurrentBM)
{
if (pCurrentBM)
{
InsertNode(pCurrentBM);
}
FPD_Bookmark pdf_BM1 = FPDBookmarkNew(nullptr);
FPDBookmarkGetFirstChild(m_fpdDoc, pCurrentBM, &pdf_BM1);
if (!FPDBookmarkGetDictionary(pdf_BM1))
{
FPDBookmarkDestroy(pdf_BM1);
return;
}
else
{
SetParent(pdf_BM1, pCurrentBM);
GetTreeTopologyInfo(pdf_BM1);
}
FPD_Bookmark temp1 = pdf_BM1;
while (1)
{
FPD_Bookmark pdf_BM2 = FPDBookmarkNew(nullptr);
FPDBookmarkGetNextSibling(m_fpdDoc, temp1, &pdf_BM2);
if (!FPDBookmarkGetDictionary(pdf_BM2))
{
FPDBookmarkDestroy(pdf_BM2);
FPDBookmarkDestroy(pdf_BM1);
return;
}
else {
SetParent(pdf_BM2, pCurrentBM);
SetPrevSibling(pdf_BM2, temp1);
if (temp1&&temp1 != pdf_BM1)
{
FPDBookmarkDestroy(temp1);
}
GetTreeTopologyInfo(pdf_BM2);
temp1 = pdf_BM2;
}
}
FPDBookmarkDestroy(pdf_BM1);
}
//查找部分
typedef struct BMInfo {
explicit BMInfo(FS_LPCWSTR title) {
if (title)
{
m_title = FSWideStringNew3(title, -1);
}
else {
m_title = nullptr;
}
m_flagEnd = false;
m_resultBm = nullptr;
}
~BMInfo() {
if (m_title)
FSWideStringDestroy(m_title);
}
FS_WideString m_title;
bool m_flagEnd;
FPD_Object m_resultBm;
}*LPBMInfo;
struct DeleterFPDBookmark
{
inline void operator() (FPD_Bookmark pValue)
{
if (pValue)
{
FPDBookmarkDestroy(pValue);
}
}
};
struct DeleterFSWideString
{
inline void operator() (FS_WideString pValue)
{
if (pValue)
{
FSWideStringDestroy(pValue);
}
}
};
void GetBookmarkByName(FPD_Bookmark pCurrentBM, BMInfo& bmInfo)
{
if (pCurrentBM)
{
FS_WideString wStrTitle = FSWideStringNew();
FPDBookmarkGetTitle(pCurrentBM,&wStrTitle);
auto strTitle = FSWideStringCastToLPCWSTR(wStrTitle);
if (FSWideStringCompare2(wStrTitle, bmInfo.m_title) == 0)
{
FSWideStringDestroy(wStrTitle);
bmInfo.m_resultBm=FPDBookmarkGetDictionary(pCurrentBM);
bmInfo.m_flagEnd = true;
return;
}
FSWideStringDestroy(wStrTitle);
}
FPD_Bookmark pdf_BM1 = FPDBookmarkNew(nullptr);
FPDBookmarkGetFirstChild(m_fpdDoc, pCurrentBM, &pdf_BM1);
if (!FPDBookmarkGetDictionary(pdf_BM1))
{
FPDBookmarkDestroy(pdf_BM1);
return;
}
else
{
GetBookmarkByName(pdf_BM1, bmInfo);
}
while (!bmInfo.m_flagEnd)
{
if (FPDBookmarkGetNextSibling(m_fpdDoc, pdf_BM1, &pdf_BM1))
{
GetBookmarkByName(pdf_BM1, bmInfo);
}
else {
break;
}
}
FPDBookmarkDestroy(pdf_BM1);
}
TEST_F(BookmarkTest, MoveNode)
{
//doucument operation.
FS_LPCWSTR title_bookmark = L"Untitled4";
FS_LPCWSTR titleMove = L"Untitled3";
{
m_fpdDoc = FPDDocOpen(m_pathIn, "");
ASSERT_NE(m_fpdDoc, nullptr);
BMInfo bmInfo(title_bookmark);
GetBookmarkByName(nullptr, bmInfo);
ASSERT_NE(bmInfo.m_resultBm, nullptr);
BMInfo bmInfoMove(titleMove);
GetBookmarkByName(nullptr, bmInfoMove);
ASSERT_NE(bmInfoMove.m_resultBm, nullptr);
std::unique_ptr<IPDF_Bookmark> pBookmark = FX_CreateBookmark(m_fpdDoc);
pBookmark->MoveNode(bmInfoMove.m_resultBm, bmInfo.m_resultBm);
bool saved = FPDDocSave2(m_fpdDoc, m_pathOut, FPD_SAVE_DEFAULT, false);
FPDDocClose(m_fpdDoc);
}
//Read file.
{
m_fpdDoc = FPDDocOpen(m_pathOut, "");
BMInfo bmInfo(title_bookmark);
GetBookmarkByName(nullptr, bmInfo);
ASSERT_NE(bmInfo.m_resultBm, nullptr);
std::unique_ptr< _t_FPD_Bookmark, DeleterFPDBookmark>unique_bm1 =
std::unique_ptr< _t_FPD_Bookmark, DeleterFPDBookmark>(FPDBookmarkNew(bmInfo.m_resultBm));
std::unique_ptr< _t_FPD_Bookmark, DeleterFPDBookmark>unique_bm2 =
std::unique_ptr< _t_FPD_Bookmark, DeleterFPDBookmark>(FPDBookmarkNew(nullptr));
auto pBookmark2 = unique_bm2.get();
FPDBookmarkGetNextSibling(m_fpdDoc, unique_bm1.get(), &pBookmark2);
FS_WideString wTitle = FSWideStringNew();
FPDBookmarkGetTitle(unique_bm2.get(), &wTitle);
FS_INT32 compareResult =FSWideStringCompare(wTitle, titleMove);
ASSERT_EQ(compareResult, 0);
FPDDocClose(m_fpdDoc);
}
}
需要注意的是在进行遍历查找的时候,递归传递一个引用值,如果找到Targer Node,则通过修改循环中的Flag而使之前的栈都退出掉,以此达到及时退出的目的;