plaintext/plugin_impl/document_impl.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: document_impl.cpp
00003  */
00004 
00005 /*
00006  * This file is part of uds-plugin-plaintext.
00007  *
00008  * uds-plugin-plaintext 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-plaintext 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 <cassert>
00028 #include "log.h"
00029 #include "document_impl.h"
00030 #include "view_impl.h"
00031 #include "collection_impl.h"
00032 #include "string_impl.h"
00033 #include "search_criteria_impl.h"
00034 #include "text_base_types.h"
00035 
00036 namespace text
00037 {
00038 
00039 utils::ObjectTable<PluginDocImpl> PluginDocImpl::g_instances_table;
00040 
00041 PluginDocImpl::PluginDocImpl()
00042 : controller(0)
00043 {
00044     // IPluginUnknown
00045     query_interface = query_interface_impl;
00046     release         = release_impl;
00047 
00048     // IPluginDocument
00049     open        = open_impl;
00050     is_open     = is_open_impl;
00051     close       = close_impl;
00052     create_view = create_view_impl;
00053 
00054     // IPluginDocNavigator
00055     get_initial_anchor      = get_initial_anchor_impl;
00056     get_object_from_anchor  = get_object_from_anchor_impl;
00057     get_type_of_object      = get_type_of_object_impl;
00058     get_words_from_range    = get_words_from_range_impl;
00059     get_text_from_range     = get_text_from_range_impl;
00060     is_anchor_in_current_document = is_anchor_in_current_document_impl;
00061     get_file_name_from_anchor = get_file_name_from_anchor_impl;
00062     get_file_position_from_anchor = get_file_position_from_anchor_impl;
00063     compare_anchor_location = compare_anchor_location_impl;
00064 
00065     // IPluginDocAttributes
00066     get_attribute = get_attribute_impl;
00067     set_attribute = set_attribute_impl;
00068 
00069     // IPluginEventBroadcaster
00070     add_event_receiver      = add_event_receiver_impl;
00071     remove_event_receiver   = remove_event_receiver_impl;
00072 
00073     // IPluginDocHyperlink
00074     is_hyperlink                = is_hyperlink_impl;
00075     get_target_from_hyperlink   = get_target_from_hyperlink_impl;
00076 
00077     // IPluginDocDictionary
00078     is_dictionary = is_dictionary_impl;
00079 
00080     // IPluginDocMarker
00081     // get_supported_marker_types  = get_supported_marker_types_impl;
00082     request_marker_trees    = request_marker_trees_impl;
00083 
00084     // IPluginDocSearch
00085     create_search_criteria  = create_search_criteria_impl;
00086     request_search_next     = request_search_next_impl;
00087     request_search_all      = request_search_all_impl;
00088     abort_search            = abort_search_impl;
00089 
00090     // Initialize interface and object table.
00091     g_instances_table.add_interface<IPluginUnknown>(this);
00092     g_instances_table.add_interface<IPluginDocument>(this);
00093     g_instances_table.add_interface<IPluginDocNavigator>(this);
00094     g_instances_table.add_interface<IPluginDocAttributes>(this);
00095     g_instances_table.add_interface<IPluginEventBroadcaster>(this);
00096     g_instances_table.add_interface<IPluginDocHyperlink>(this);
00097     g_instances_table.add_interface<IPluginDocDictionary>(this);
00098     g_instances_table.add_interface<IPluginDocSearch>(this);
00099 
00100     document.search_done_signal.add_slot(this,
00101         &PluginDocImpl::on_search_done);
00102 
00103     // Initialize document attributes map.
00104     init_doc_attributes();
00105 }
00106 
00107 void PluginDocImpl::init_doc_attributes()
00108 {
00109     doc_attr_map.insert(std::make_pair("fixed-page", "no"));
00110     doc_attr_map.insert(std::make_pair("reflowable", "yes"));
00111 }
00112 
00113 PluginDocImpl::~PluginDocImpl()
00114 {
00115     g_instances_table.remove(this);
00116 }
00117 
00118 PluginStatus 
00119 PluginDocImpl::query_interface_impl(IPluginUnknown    *thiz,
00120                                     const UDSString   *id, 
00121                                     void              **ptr )
00122 {
00123     // check object. 
00124     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00125 
00126     // check interface.
00127     if (g_instances_table.query_interface(instance, id->get_buffer(id), ptr))
00128     {
00129         return PLUGIN_OK;
00130     }
00131     return PLUGIN_FAIL;
00132 }
00133 
00134 int 
00135 PluginDocImpl::release_impl(IPluginUnknown  *thiz )
00136 {
00137     // Check object. 
00138     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00139     instance->release_signal.safe_broadcast(instance);
00140     return 0;
00141 }
00142 
00143 
00144 PluginStatus
00145 PluginDocImpl::open_impl(IPluginUnknown    *thiz, 
00146                          const UDSString   *path)
00147 {
00148     // Check object. 
00149     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00150     
00151     // Check document has been opened or not.
00152     assert(!instance->document.is_open());
00153 
00154     // Open it.
00155     return instance->document.open(path->get_buffer(path));
00156 }
00157 
00158 PluginBool
00159 PluginDocImpl::is_open_impl(IPluginUnknown    *thiz)
00160 {
00161     // Check object. 
00162     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00163     
00164     // Check document has been opened or not.
00165     if (instance->document.is_open())
00166     {
00167         return PLUGIN_TRUE;
00168     }
00169     return PLUGIN_FALSE;
00170 }
00171 
00172 PluginStatus
00173 PluginDocImpl::close_impl(IPluginUnknown   *thiz)
00174 {
00175     // Check object. 
00176     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00177     
00178     // Check document has been opened or not.
00179     assert(instance->document.is_open());
00180 
00181     // Stop working thread before clear document since pagination task may be running.
00182     instance->controller->stop();
00183     instance->document.close();
00184     return PLUGIN_OK;
00185 }
00186 
00187 IPluginUnknown *
00188 PluginDocImpl::create_view_impl(IPluginUnknown   *thiz)
00189 {
00190     // Check object. 
00191     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00192     
00193     // Check if the controller is ready or not.
00194 
00195     // Create the view. 
00196     ViewPtr ptr = new PluginViewImpl(instance);
00197     assert(ptr);
00198 
00199     if (instance->controller == 0)
00200     {
00201         instance->controller = ptr->get_text_controller();
00202         instance->controller->start();
00203     }
00204 
00205     return static_cast<IPluginUnknown *>(ptr);
00206 }
00207 
00208 PluginStatus 
00209 PluginDocImpl::get_initial_anchor_impl(IPluginUnknown   *thiz,
00210                                        UDSString        *anchor)
00211 {
00212     // Use first page as the initial anchor.
00213     Position pos;
00214     std::string temp = pos.to_string();
00215     anchor->assign(anchor, temp.c_str());
00216     return PLUGIN_OK;
00217 }
00218 
00219 PluginStatus 
00220 PluginDocImpl::get_object_from_anchor_impl(IPluginUnknown  *thiz,
00221                                            const UDSString *anchor, 
00222                                            PluginRange     *range)
00223 {
00224     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00225 
00226     Position object_start_pos, object_end_pos;
00227     Position anchor_pos(anchor->get_buffer(anchor));
00228 
00229     if (!instance->document.get_word_from_anchor(anchor_pos,
00230                                                  object_start_pos,
00231                                                  object_end_pos))
00232     {
00233         return PLUGIN_FAIL;
00234     }
00235     
00236     range->start_anchor->assign(range->start_anchor,
00237         object_start_pos.to_string().c_str());
00238     range->end_anchor->assign(range->end_anchor,
00239         object_end_pos.to_string().c_str());
00240 
00241     return PLUGIN_OK;
00242 }
00243 
00244 PluginDocObjectType 
00245 PluginDocImpl::get_type_of_object_impl(IPluginUnknown      *thiz,
00246                                        const PluginRange   *range)
00247 {
00248     return PLUGIN_DOC_OBJECT_TEXT;
00249 }
00250 
00251 PluginStatus 
00252 PluginDocImpl::get_words_from_range_impl(IPluginUnknown      *thiz, 
00253                                         const PluginRange    *char_range, 
00254                                         PluginRange          *words_range )
00255 {
00256     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00257 
00258     Position char_start_pos(char_range->start_anchor->get_buffer(char_range->start_anchor));
00259     Position char_end_pos(char_range->end_anchor->get_buffer(char_range->end_anchor));
00260 
00261     if (char_start_pos > char_end_pos)
00262     {
00263         ERRORPRINTF("Invalid range, range_start = %s, range_end = %s",
00264             char_start_pos.to_string().c_str(),
00265             char_end_pos.to_string().c_str());
00266         return PLUGIN_FAIL;
00267     }
00268 
00269     Position words_start, words_end;
00270     if (!instance->document.get_words_from_range(char_start_pos, char_end_pos, words_start, words_end))
00271     {
00272         return PLUGIN_FAIL;
00273     }
00274 
00275     words_range->start_anchor->assign(words_range->start_anchor, words_start.to_string().c_str());
00276     words_range->end_anchor->assign(words_range->end_anchor, words_end.to_string().c_str());
00277     return PLUGIN_OK;
00278 }
00279 
00280 PluginStatus 
00281 PluginDocImpl::get_text_from_range_impl(IPluginUnknown        *thiz, 
00282                                         const PluginRange     *range, 
00283                                         UDSString             *result)
00284 {
00285     // Get instance.
00286     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00287 
00288     Position text_start_pos(range->start_anchor->get_buffer(range->start_anchor));
00289     Position text_end_pos(range->end_anchor->get_buffer(range->end_anchor));
00290 
00291     if (text_start_pos > text_end_pos)
00292     {
00293         ERRORPRINTF("Invalid range, range_start = %s, range_end = %s",
00294             text_start_pos.to_string().c_str(),
00295             text_end_pos.to_string().c_str());
00296         return PLUGIN_FAIL;
00297     }
00298 
00299     std::string result_string;
00300     instance->document.get_text_from_range(result_string, text_start_pos, text_end_pos);
00301     result->assign(result, result_string.c_str());
00302     
00303     return PLUGIN_OK;
00304 }
00305 
00306 PluginBool 
00307 PluginDocImpl::is_anchor_in_current_document_impl(IPluginUnknown    *thiz,
00308                                                   const UDSString   *anchor)
00309 {
00310     // check object. 
00311     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00312     Position pos(anchor->get_buffer(anchor));
00313     if (instance->document.has_anchor(pos))
00314     {
00315         return PLUGIN_TRUE;
00316     }
00317     return PLUGIN_FALSE;
00318 }
00319 
00320 PluginStatus
00321 PluginDocImpl::get_file_name_from_anchor_impl(IPluginUnknown    *thiz,
00322                                               const UDSString   *anchor,
00323                                               UDSString         *file_name )
00324 {
00325     // Get instance object.
00326     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00327 
00328     // Get absolute file path.
00329     const std::string& file_path = instance->document.get_path();
00330 
00331     // Get basename for file path.
00332     char* basename = g_path_get_basename(file_path.c_str());
00333     file_name->assign(file_name, basename);
00334     g_free(basename);
00335 
00336     return PLUGIN_OK;
00337 }
00338 
00339 PluginStatus
00340 PluginDocImpl::get_file_position_from_anchor_impl(IPluginUnknown    *thiz,
00341                                                   const UDSString   *anchor,
00342                                                   signed long long  *position )
00343 {
00344     Position internal_anchor(anchor->get_buffer(anchor));
00345     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00346 
00347     size_t pos;
00348     if (instance->document.get_file_pos_from_anchor(pos, internal_anchor))
00349     {
00350         *position = pos;
00351         return PLUGIN_OK;
00352     }
00353     
00354     return PLUGIN_FAIL;
00355 }
00356 
00357 int 
00358 PluginDocImpl::compare_anchor_location_impl(IPluginUnknown   *thiz,
00359                                             const UDSString  *anchor_a,
00360                                             const UDSString  *anchor_b)
00361 {
00362     // check object. 
00363     Position a(anchor_a->get_buffer(anchor_a));
00364     Position b(anchor_b->get_buffer(anchor_b));
00365 
00366     if (a > b)
00367     {
00368         return 1;
00369     }
00370     else if (a == b)
00371     {
00372         return 0;
00373     }
00374     else
00375     {
00376         return -1;
00377     }
00378 }
00379 
00380 // Define plain text attribute. Seems only support the encoding.
00381 PluginStatus
00382 PluginDocImpl::get_attribute_impl(IPluginUnknown     *thiz,
00383                                   const UDSString    *key, 
00384                                   UDSString          *value )
00385 {
00386     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00387 
00388     // Check whether the key exists or not.
00389     if (instance->doc_attr_map.find(key->get_buffer(key)) 
00390             == instance->doc_attr_map.end())
00391     {
00392         return PLUGIN_NOT_SUPPORTED;
00393     }
00394 
00395     value->assign(value, instance->doc_attr_map[key->get_buffer(key)].c_str());
00396     return PLUGIN_OK;
00397 }
00398 
00399 PluginStatus 
00400 PluginDocImpl::set_attribute_impl(IPluginUnknown     *thiz,
00401                                   const UDSString    *key,
00402                                   const UDSString    *value )
00403 {
00404     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00405 
00406     const char* key_cstr = key->get_buffer(key);
00407     DocAttrMapIter iter = instance->doc_attr_map.find(key_cstr);
00408     if (iter == instance->doc_attr_map.end())
00409     {
00410         return PLUGIN_NOT_SUPPORTED;
00411     }
00412 
00413     iter->second = value->get_buffer(value);
00414     return PLUGIN_OK;
00415 }
00416     
00417 PluginStatus 
00418 PluginDocImpl::add_event_receiver_impl(IPluginUnknown     *thiz,
00419                                        const PluginEvent  plugin_event,
00420                                        EventFunc          callback,
00421                                        void               *user_data,
00422                                        unsigned long      *handler_id)
00423 {
00424     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00425     assert(handler_id);
00426     *handler_id = 
00427         instance->listeners.add_listener(plugin_event, callback, user_data);
00428     return PLUGIN_OK;
00429 }
00430 
00431 PluginStatus 
00432 PluginDocImpl::remove_event_receiver_impl(IPluginUnknown  *thiz,
00433                                           unsigned long   handler_id )
00434 {
00435     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00436     if (instance->listeners.remove_listener(handler_id))
00437     {
00438         return PLUGIN_OK;
00439     }
00440     return PLUGIN_FAIL;
00441 }
00442 
00443 PluginBool 
00444 PluginDocImpl::is_hyperlink_impl(IPluginUnknown    *thiz,
00445                                  const PluginRange *range )
00446 {
00447     // No hyperlink for plain text.
00448     return PLUGIN_FALSE;
00449 }
00450 
00451 PluginStatus 
00452 PluginDocImpl::get_target_from_hyperlink_impl(IPluginUnknown     *thiz,
00453                                               const PluginRange  *range, 
00454                                               UDSString          *anchor )
00455 {
00456     return PLUGIN_FAIL;
00457 }
00458     
00459 PluginBool 
00460 PluginDocImpl::is_dictionary_impl(IPluginUnknown  *thiz )
00461 {
00462     return PLUGIN_FALSE;
00463 }
00464 
00465 // The text document does not support table of content.
00466 IPluginUnknown* 
00467 PluginDocImpl::get_supported_marker_types_impl(IPluginUnknown  *thiz )
00468 {
00469     return 0;
00470 }
00471 
00472 // For text document, there is no marker tree.
00473 PluginStatus 
00474 PluginDocImpl::request_marker_trees_impl(IPluginUnknown     *thiz, 
00475                                          const unsigned int uds_private_size )
00476 {
00477     return PLUGIN_FAIL;
00478 }
00479 
00480 IPluginUnknown *
00481 PluginDocImpl::create_search_criteria_impl(IPluginUnknown  *thiz )
00482 {
00483     return new PluginSearchCriteria;
00484 }
00485 
00486 // Call controller to search.
00487 PluginStatus
00488 PluginDocImpl::request_search_next_impl(IPluginUnknown      *thiz,
00489                                         IPluginUnknown      *criteria,
00490                                         const UDSString     *from_anchor,
00491                                         const unsigned int  search_id)
00492 {
00493     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00494 
00495     // Clear the aborting search task id.
00496     instance->document.set_aborting_search_task_id(0);
00497 
00498     PluginSearchCriteria* search_criteria = 
00499         static_cast<PluginSearchCriteria *>(criteria);
00500     SearchContext& sc = search_criteria->get_search_context();
00501     sc.search_id = search_id;
00502     sc.search_type = SEARCH_NEXT;
00503     sc.from = Position(from_anchor->get_buffer(from_anchor));
00504     instance->controller->search(&sc);
00505     return PLUGIN_OK;
00506 }
00507 
00508 // Call controller to search.
00509 PluginStatus
00510 PluginDocImpl::request_search_all_impl(IPluginUnknown *thiz,
00511                                        IPluginUnknown *criteria,
00512                                        const unsigned int  search_id)
00513 {
00514     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00515 
00516     // Clear the aborting search task id.
00517     instance->document.set_aborting_search_task_id(0);
00518 
00519     PluginSearchCriteria* search_criteria = 
00520         static_cast<PluginSearchCriteria *>(criteria);
00521     SearchContext& sc = search_criteria->get_search_context();
00522     sc.search_id = search_id;
00523     sc.search_type = SEARCH_ALL;
00524     instance->controller->search(&sc);
00525     return PLUGIN_OK;
00526 }
00527 
00528 PluginStatus PluginDocImpl::abort_search_impl(
00529     IPluginUnknown     *thiz, 
00530     const unsigned int search_id)
00531 {
00532     PluginDocImpl *instance = g_instances_table.get_object(thiz);
00533     instance->document.set_aborting_search_task_id(search_id);
00534     return PLUGIN_OK;
00535 }
00536 
00537 void PluginDocImpl::on_search_done(const std::vector<Range>& result,
00538                                    const SearchContext* sc)
00539 {
00540     PluginCollectionImpl *coll_p = new PluginCollectionImpl();
00541     coll_p->create<RangeImpl *>();
00542     std::vector<RangeImpl *>& data = coll_p->take_data_ref<RangeImpl *>();
00543     
00544     for (unsigned int i=0; i<result.size(); i++)
00545     {
00546         data.push_back(new RangeImpl(result[i]));
00547     }
00548 
00549     PluginEventAttrs attrs;
00550     attrs.search_end.search_id = sc->search_id;
00551     attrs.search_end.result = coll_p;
00552     listeners.broadcast(this, EVENT_SEARCH_END, &attrs);
00553 }
00554 
00555 }   // namespace text
00556 
Generated by  doxygen 1.6.2-20100208