pdf_toc.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "log.h"
00028
00029 #include "pdf_toc.h"
00030 #include "pdf_doc_controller.h"
00031
00032 namespace pdf
00033 {
00034
00035 static const char * unicode_to_utf8(const Unicode * uni_str, int len)
00036 {
00037 gsize bytes_read;
00038 gsize bytes_written;
00039 GError *error = NULL;
00040
00041 gchar * utf8_str = g_convert((const gchar *)uni_str, len * 4,
00042 "UTF-8", "UCS-4LE",
00043 &bytes_read,
00044 &bytes_written,
00045 &error);
00046
00047
00048
00049 return utf8_str;
00050 }
00051
00052 TocItem::TocItem()
00053 : anchor()
00054 , text()
00055 , goto_anchor()
00056 , sibling(0)
00057 , first_child(0)
00058 {
00059 }
00060
00061 TocItem::~TocItem()
00062 {
00063 if (first_child != 0)
00064 {
00065 delete first_child;
00066 }
00067
00068 if (sibling != 0)
00069 {
00070 delete sibling;
00071 }
00072 }
00073
00074 bool TocItem::is_invisible_root()
00075 {
00076 return anchor.empty();
00077 }
00078
00079 void TocItem::disconnect()
00080 {
00081 sibling = 0;
00082 first_child = 0;
00083 }
00084
00085 PDFToc::PDFToc(PDFController *doc)
00086 : doc_ctrl(doc)
00087 , toc(0)
00088 {
00089 }
00090
00091 PDFToc::~PDFToc(void)
00092 {
00093 free_toc(toc);
00094 }
00095
00096 bool PDFToc::has_toc()
00097 {
00098 Outline * outline = doc_ctrl->get_pdf_doc()->getOutline();
00099 if (!outline)
00100 {
00101 LOGPRINTF("No table of content.");
00102 return false;
00103 }
00104
00105 GooList * items = outline->getItems();
00106 if (!items || items->getLength() < 1)
00107 {
00108 LOGPRINTF("No table of content.");
00109 return false;
00110 }
00111
00112 return true;
00113 }
00114
00115 TocItem * PDFToc::get_toc(void)
00116 {
00117 if (toc)
00118 {
00119
00120 return toc;
00121 }
00122
00123 if (!has_toc())
00124 {
00125 return 0;
00126 }
00127
00128
00129 if (doc_ctrl == 0)
00130 {
00131 return 0;
00132 }
00133
00134 Outline * outline = doc_ctrl->get_pdf_doc()->getOutline();
00135 GooList * items = outline->getItems();
00136
00137 int idx = 0;
00138
00139 TocItem root;
00140
00141 append_toc_children(&root, idx, items);
00142 toc = root.first_child;
00143
00144
00145 root.disconnect();
00146 return toc;
00147 }
00148
00149 TocItem * PDFToc::create_new_item(OutlineItem * data, int idx)
00150 {
00151
00152 int dst_page = 0;
00153 get_dest_page_of_toc_item(data, dst_page);
00154
00155
00156 PDFAnchor goto_anchor;
00157 if (dst_page > 0)
00158 {
00159 goto_anchor.page_num = dst_page;
00160
00161 }
00162 else
00163 {
00164 ERRORPRINTF("Wrong TOC item:%d", idx);
00165 return 0;
00166 }
00167
00168 Unicode * uni_char = data->getTitle();
00169 int title_length = data->getTitleLength();
00170 const char * text = unicode_to_utf8(uni_char, title_length);
00171
00172 if (!text || !strlen(text))
00173 {
00174 WARNPRINTF("Can't get [%d]th TOC item.", idx);
00175 return 0;
00176 }
00177
00178
00179 PDFAnchor param;
00180 param.toc_idx = idx;
00181 param.page_num = dst_page;
00182
00183
00184 TocItem * item = new TocItem;
00185
00186 item->anchor = param.get_string();
00187 item->text = string(text);
00188 item->goto_anchor = goto_anchor.get_string();
00189 item->sibling = 0;
00190 item->first_child = 0;
00191
00192 g_free((gpointer)text);
00193 return item;
00194 }
00195
00196 void PDFToc::append_toc_children(TocItem * parent, int & idx, GooList * items)
00197 {
00198 int numItems = items->getLength();
00199 for ( int i = 0; i < numItems; ++i )
00200 {
00201
00202 OutlineItem * item = (OutlineItem *)items->get(i);
00203 TocItem * toc_item = create_new_item(item, idx++);
00204
00205 if (toc_item != 0)
00206 {
00207
00208 if (parent->first_child == 0)
00209 {
00210 parent->first_child = toc_item;
00211 }
00212 else
00213 {
00214 TocItem * cur = parent->first_child;
00215 while (cur->sibling != 0)
00216 {
00217 cur = cur->sibling;
00218 }
00219 cur->sibling = toc_item;
00220 }
00221
00222
00223 item->open();
00224 GooList * children = item->getKids();
00225 if (children)
00226 {
00227 append_toc_children(toc_item, idx, children);
00228 }
00229 item->close();
00230 }
00231 }
00232 }
00233
00234 bool PDFToc::get_dest_page_of_toc_item(OutlineItem * item, int & page_num)
00235 {
00236
00237 LinkAction * action = item->getAction();
00238 if (action && (action->getKind() == actionGoTo))
00239 {
00240
00241 LinkDest * dest;
00242 #ifdef WIN32
00243 UGooString *named_dest;
00244 #else
00245 GooString *named_dest;
00246 #endif
00247 page_num = 0;
00248
00249 dest = ((LinkGoTo *)action)->getDest();
00250 named_dest = ((LinkGoTo *)action)->getNamedDest();
00251
00252 if (dest && dest->isPageRef())
00253 {
00254 Ref pageRef = dest->getPageRef();
00255 page_num = doc_ctrl->get_pdf_doc()->findPage(pageRef.num, pageRef.gen);
00256 }
00257 else if (named_dest)
00258 {
00259 dest = doc_ctrl->get_pdf_doc()->findDest(named_dest);
00260 if (dest)
00261 {
00262 Ref pageRef = dest->getPageRef();
00263 page_num = doc_ctrl->get_pdf_doc()->findPage(pageRef.num, pageRef.gen);
00264 }
00265 }
00266
00267 if (page_num > 0)
00268 {
00269 return true;
00270 }
00271 }
00272
00273 return false;
00274 }
00275
00276 void PDFToc::free_toc(TocItem * p_toc)
00277 {
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 if (p_toc != 0)
00296 {
00297 delete p_toc;
00298 }
00299 }
00300
00301
00302
00303 bool PDFToc::get_goto_anchor_of_toc_idx(int idx, string & anchor)
00304 {
00305 int i = -1;
00306
00307 typedef list<TocItem *> Stack;
00308 Stack stack;
00309
00310 TocItem * cur = toc;
00311 stack.push_back(cur);
00312
00313 while (!stack.empty())
00314 {
00315
00316 cur = stack.back();
00317 while (cur)
00318 {
00319
00320 i++;
00321
00322
00323 if (i == idx)
00324 {
00325
00326 anchor = cur->goto_anchor.c_str();
00327 return true;
00328 }
00329
00330 stack.push_back(cur->first_child);
00331 cur = stack.back();
00332 }
00333
00334
00335 stack.pop_back();
00336
00337
00338 if (!stack.empty())
00339 {
00340 cur = stack.back();
00341 stack.pop_back();
00342 stack.push_back(cur->sibling);
00343 }
00344 }
00345
00346 return false;
00347 }
00348
00349 };
00350
00351