pdf_toc.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: pdf_toc.cpp
00003  */
00004 
00005 /*
00006  * This file is part of uds-plugin-pdf.
00007  *
00008  * uds-plugin-pdf is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * uds-plugin-pdf is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
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     //LOGPRINTF("%s", utf8_str);
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         // return the toc if it exists.
00120         return toc;
00121     }
00122 
00123     if (!has_toc())
00124     {
00125         return 0;
00126     }
00127 
00128     //assert(doc_ctrl != 0);
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     // construct the invisible root node.
00139     TocItem root;
00140 
00141     append_toc_children(&root, idx, items);
00142     toc = root.first_child;
00143 
00144     // disconnect the root node
00145     root.disconnect();
00146     return toc;
00147 }
00148 
00149 TocItem * PDFToc::create_new_item(OutlineItem * data, int idx)
00150 {
00151     // Get goto anchor
00152     int dst_page = 0;
00153     get_dest_page_of_toc_item(data, dst_page);
00154 
00155     // Get the anchor of destination page
00156     PDFAnchor goto_anchor;
00157     if (dst_page > 0)
00158     {
00159         goto_anchor.page_num = dst_page;
00160         //goto_anchor.file_name = document()->name();
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     // Get anchor
00179     PDFAnchor param;
00180     param.toc_idx   = idx;
00181     param.page_num  = dst_page;
00182     //param.file_name = document()->name();
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         // Iterate over every object in 'items'
00202         OutlineItem * item = (OutlineItem *)items->get(i);
00203         TocItem * toc_item = create_new_item(item, idx++);
00204 
00205         if (toc_item != 0)
00206         {
00207             // the invalid toc item should not be displayed
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             // Recursively descend over children
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     // Find the page the link refers to
00237     LinkAction * action = item->getAction();
00238     if (action && (action->getKind() == actionGoTo))
00239     {
00240         // Caculate the page number of destination of this link.
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     //if (!p_toc)
00279     //{
00280     //    return;
00281     //}
00282 
00283     //if (p_toc->first_child)
00284     //{
00285     //    free_toc(p_toc->first_child);
00286     //}
00287     //else if (p_toc->sibling)
00288     //{
00289     //    free_toc(p_toc->sibling);
00290     //}
00291     //else 
00292     //{
00293     //    delete p_toc;
00294     //}
00295     if (p_toc != 0)
00296     {
00297         delete p_toc;
00298     }
00299 }
00300 
00301 // Notes, preorder algorithm which is same as the algorithm
00302 // when calculating the toc_idx.
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         // Go down to the highest level.
00316         cur = stack.back();
00317         while (cur) 
00318         {
00319             // Visit cur
00320             i++;
00321 
00322             // Condition judgement.
00323             if (i == idx)
00324             {
00325                 /*LOGPRINTF("%d %s", idx, cur->goto_anchor.c_str());*/
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         // Popup the empty pointer.
00335         stack.pop_back();
00336 
00337         // Go to the next sibling.
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 
Generated by  doxygen 1.6.2-20100208