Root/src/vido.cc

1/***************************************************************************
2 * Copyright (C) 2009 by Mirko Lindner,,, *
3 * vegyraupe@mira *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21
22#include <gtkmm.h>
23#include <zim/file.h>
24#include <zim/search.h>
25#include <iostream>
26#include <string>
27#include <vector>
28
29
30#include "config.h"
31#include "message_dialog.hh"
32#include "vido.hh"
33#include "main_window.hh"
34#include "search_dialog.hh"
35
36#include <cxxtools/loginit.h>
37
38log_define("vido.main")
39
40extern "C" {
41   #include "gtkhtml/gtkhtml.h"
42 }
43
44// std::string content;
45std::string fileName;
46
47//TODO this can't be right
48main_window *window2;
49Gtk::ScrolledWindow *scrolled_window2;
50
51
52Gtk::Widget *html;
53GtkWidget *html_wg;
54std::vector < std::pair< std::string, std::string > > history;
55int position;
56bool historyCall = false;
57// variable to keep url of currently displayed article
58std::string current_url = "";
59
60// // // misc functions
61// get zimFile, if not already opened, open file
62const zim::File& get_file()
63{
64  static zim::File zimFile;
65
66  if (!zimFile.good())
67  {
68// log_debug("file not initialized:" << fileName);
69    zimFile = zim::File(fileName);
70// log_debug("number of articles: " << zimFile.getCountArticles());
71  }
72
73// log_debug("returning file.");
74  return zimFile;
75}
76
77
78void screenblock(int val){
79
80        if (val == 1){
81                scrolled_window2->remove();
82                scrolled_window2->add_label("loading");
83        }else if(val == 0){
84                scrolled_window2->remove();
85                scrolled_window2->add(*html);
86        }
87        while( Gtk::Main::events_pending() ){
88                Gtk::Main::iteration();
89        }
90}
91
92// display message in gtk window
93void show_message(std::string title, std::string txt)
94{
95    message_dialog(window2, title, txt);
96}
97
98void show_help()
99{
100        log_debug("displaying help");
101        std::string title = "Help";
102        std::string txt = "Usage: \n";
103        txt += "Ctrl + R = Display random article\n";
104        txt += "Ctrl + S = Search for article\n";
105        txt += "Ctrl + T = Go to articles top\n";
106        txt += "Tab = Rotate through links\n";
107        txt += "Enter = Activate link\n";
108        txt += "Ctrl + H = Display history\n";
109        txt += "Ctrl + B = Go back in history\n";
110        txt += "Ctrl + F = Go forward in history\n";
111        txt += "Ctrl + Q = Quit Vido\n";
112        txt += "F1 = Display this help\n";
113        show_message(title, txt);
114}
115
116// fill gtkhtml widget with new content
117
118void fill_gtkhtml(std::string& html_str, std::string url, std::string title){
119    log_debug("fill gtkhtml called with " << position << " " << url << " and " << title);
120    std::string ccontent;
121    ccontent = "<a name=\"top\"></a>" + html_str;
122    gtk_html_flush(GTK_HTML(html_wg));
123    gtk_html_load_from_string(GTK_HTML(html_wg), ccontent.c_str(), -1);
124    current_url = url;
125    if ((url != "") && title != ""){
126      if ((!historyCall)){
127        if(position != 0){
128                    std::vector < std::pair< std::string, std::string > >::iterator iterator = history.begin();
129          log_debug("history size: " << history.size());
130                    for (int d=0; d < history.size(); d++){
131                        log_debug("history entry: " << d << " " << history[d].first);
132                    }
133                    for (int m=history.size()+position; m <= history.size(); m++){
134            log_debug("erasing history: number: "<< m << "title: " << history[m].first);
135                        history.erase(iterator+m);
136            }
137                }
138                log_debug("adding " << title << " to history \n" << "position: " << position);
139        history.push_back( std::make_pair( url, title ) );
140                if (history.size() == 11){
141          history.erase(history.begin());
142          }
143                log_debug("history size after stuff: " << history.size());
144      }else{
145// if (!historyCall){
146// log_debug("clearing history");
147// std::vector < std::pair< std::string, std::string > >::iterator iterator = history.begin();
148// for (int m=0; m < position; m++){
149// history.erase(iterator+m);
150// }
151// }else{
152          historyCall = false;
153// }
154      }
155      
156    }
157// gtk_html_get_selection_html(GTK_HTML(html_wg), )
158        while( Gtk::Main::events_pending() ){
159                Gtk::Main::iteration();
160        }
161        screenblock(0);
162        
163        window2->connect_all();
164    
165}
166
167void show_history()
168{
169    screenblock(1);
170  std::string res, url, title;
171  res += "<ul style=\"list-style-type:none;\">";
172    log_debug("history size: " << history.size());
173    for (int d=0; d < history.size(); d++){
174        log_debug("history entry: " << d << " " << history[d].first);
175    }
176  for(int i=history.size()-1; i >= 0; i--)
177  {
178    log_debug("entry: " << i);
179#if HAVE_ZIM_QUNICODE_H
180    res += "<li><a href=" + history[i].first + ">" + history[i].second + "</a></li>";
181#else
182    res += "<li><a href='" + history[i].first + "'>" + history[i].second + "</a>";
183    if (position == i){
184      res += "<--";
185    }
186    res += "</li>";
187#endif
188    
189  }
190  res += "</ul>";
191  url = "";
192  title = "";
193  
194  fill_gtkhtml(res, url, title);
195  
196}
197
198void history_jump(int jumper){
199  int new_rel_pos = position + jumper;
200  log_debug("new_rel_pos = " << new_rel_pos);
201  int new_pos = history.size() + new_rel_pos;
202  log_debug("new_pos = " << new_pos);
203  log_debug("history size = " << history.size());
204  if ((new_pos > 0) && (new_pos <= history.size())){
205// position = new_rel_pos;
206    historyCall = true;
207    std::string url = history[new_pos-1].first;
208    log_debug("url is = " << url);
209// const char* uri = url.c_str();
210// getArticleFromUrl(const_cast<char*>(url.c_str()), 1);
211    const char* uri = url.c_str();
212    getArticleFromUrl(uri, new_rel_pos);
213    position = new_rel_pos;
214  }else{
215        log_debug("jump not possible");
216        window2->connect_all();
217    }
218}
219
220//UNUSED
221// // copy article html from while loop into global variable
222// void set_article(const std::string& txt)
223// {
224// content = txt;
225// }
226
227// // // externally called functions
228
229
230// // display random article
231void show_random()
232{
233// window2->disconnect_all();
234        
235        screenblock(1);
236// log_debug("random called. window all disconnected");
237    zim::File m = get_file();
238        zim::Article article;
239    do
240        {
241                unsigned int seed = static_cast<unsigned int>(time(0));
242                zim::size_type idx = static_cast<zim::size_type>(static_cast<double>(m.getCountArticles()) * rand_r(&seed) / RAND_MAX);
243                
244                article = m.getArticle(idx);
245                
246                //loop in case article is redirect
247                do
248                {
249                        article = article.getRedirectArticle();
250                }while(article.isRedirect());
251    
252        }while(article.getUrl() == current_url);
253        
254    std::string res = article.getPage();
255
256// log_debug("article size=" << res.size());
257// log_debug("article title=" << article.getTitle());
258// log_debug("article namespace=" << article.getNamespace());
259// position = 0;
260    fill_gtkhtml(res, article.getUrl(), article.getTitle());
261// log_debug("random called. window all connected");
262
263}
264
265// // display search dialog
266void search_window(main_window *window_x)
267{
268// html_color = html_color_new_from_rgb('255','0','0');
269// gtk_html_set_color(GTK_HTML(html_wg),html_color);
270    search_dialog(window_x, " ");
271        
272}
273
274// //
275void GoToTop()
276{
277    log_debug("go to top called");
278    std::string term = "top";
279    bool success = gtk_html_jump_to_anchor(GTK_HTML(html_wg), const_cast<char*>(term.c_str()));
280}
281
282// // // meta functions
283
284// // set displayed html to given url
285// // FIXME: returns several articles and displays on one page ... why?
286void getArticleFromUrl(const gchar *url, int pos)
287{
288    // TODO unescape url
289
290// // create ZIM file accessor
291    zim::File m = get_file();
292// // convert url to string
293    std::string term;
294        term.assign(url);
295// log_debug("str url" << term << "\n");
296    std::string content;
297// // replace '+' signs with spaces in url
298    std::replace(term.begin(), term.end(), '+', ' ');
299    
300// // find and declare namespace
301    size_t found;
302    size_t found2;
303    char ns;
304
305    found=term.find("/");
306    if (found != std::string::npos)
307    {
308        if (found)
309        {
310            ns = term[0];
311            term.erase(found + 1);
312        }
313        else
314        {
315            term.erase(1);
316            ns = term[0];
317            found2 = term.find("/");
318            term.erase(found2 + 1);
319        }
320    }
321    else
322    {
323        ns = 'A';
324    }
325
326// // try to retrieve article
327    try
328    {
329// #if HAVE_ZIM_QUNICODE_H
330// zim::Article article = m.getArticle(ns, zim::QUnicodeString(term));
331// #else
332        zim::Article article = m.getArticle(ns, term);
333// #endif
334
335        if (article.good()) // check if article is really found
336        {
337            content = article.getPage();
338                        position = pos;
339            fill_gtkhtml(content, article.getUrl(), article.getTitle());
340        }
341        else
342        {
343            std::cerr << "article \"" << url << "\" not found" << std::endl;
344            show_message("Error", "The article you requested (" + term + ") was not found.");
345        }
346    }
347    catch (const std::exception& e)
348    {
349        std::cerr << e.what() << std::endl;
350    }
351}
352
353
354// // test functions
355void getArticleFromTitle(const gchar *phrase)
356{
357        historyCall = false;
358    screenblock(1);
359        char ns;
360    ns = 'A';
361    zim::File z = get_file();
362    
363    zim::Search::Results result;
364    zim::Search search(z);
365    std::string term(phrase);
366    std::string res, url, title;
367    search.setSearchLimit(25);
368    search.find(result, ns, term);
369    if( result.size() == 0)
370    {
371        show_message("Error", "The article you requested (" + term + ") was not found.");
372                screenblock(0);
373    }else{
374      
375      if (result.size() == 1){
376        log_debug("one article in result");
377        
378        zim::Article article = z.getArticle(result[0].getArticle().getIndex());
379        
380        //loop in case article is redirect
381        do
382        {
383            article = article.getRedirectArticle();
384        }while(article.isRedirect());
385        
386        res = article.getPage(false, 10);
387        url = article.getUrl();
388        title = article.getTitle();
389                log_debug("set article from title position = 0");
390        position = 0;
391      }
392      else
393      {
394        log_debug("more than one article in result");
395        for (unsigned i = 0; i < result.size(); ++i)
396        {
397// #if HAVE_ZIM_QUNICODE_H
398// res += "<li><a href=" + result[i].getArticle().getLongUrl().toXML() + ">" + result[i].getArticle().getLongUrl().toXML() + "</a></li>";
399// #else
400          res += "<li><a href='" + result[i].getArticle().getUrl() + "'>" + result[i].getArticle().getUrl() + "</a></li>";
401// #endif
402        }
403        url = "";
404        title = "";
405    
406      }
407      
408      fill_gtkhtml(res, url, title);
409    }
410}
411
412// // // window response functions
413
414// // open requested link
415// FIXME show error window when dead-link requested
416bool on_link_clicked(GtkHTML *html, const gchar *url)
417{
418    std::string term(url);
419    size_t found;
420    found=term.find("#");
421    if (found != std::string::npos){
422    
423      if (found == 0){
424        term.erase(0, 1);
425        bool success = gtk_html_jump_to_anchor(GTK_HTML(html_wg), const_cast<char*>(term.c_str()));
426        log_debug("jump to " << term << "worked: " << success);
427      }else{
428        term = term.substr(0, found);
429        //TODO make "set_html" func accept anchor name
430        const char* uri = term.c_str();
431        getArticleFromUrl(uri, position);
432      }
433      
434    }else{
435      getArticleFromUrl(url,position);
436    }
437    
438    return true;
439}
440
441void motion( GdkEventMotion *event)
442{
443  log_debug("motion");
444}
445
446bool scrolled(GtkHTML *cb_html, GtkOrientation orientation, GtkScrollType scroll_type, gfloat position)
447{
448  log_debug("scrolled");
449  // TODO on any scroll adjust cursor, maybe with:
450  //static void gtk_html_adjust_cursor_position (GtkHTML *html)
451}
452
453// // main function
454int main(int argc, char **argv)
455{
456  try
457  {
458    log_init();
459
460    if (argc == 2)
461    {
462      fileName = argv[1];
463
464      log_debug("vido is here file: " << fileName);
465      
466      Gtk::Main kit(argc, argv);
467
468      main_window window;
469            window.add_modal_grab();
470      window.set_title("Vido");
471  // window.set_border_width(0);
472      window.set_default_size(220, 240);
473  // window.set_resizable(0);
474            window.connect_all();
475      html_wg = gtk_html_new();
476      window2 = &window;
477      html = Glib::wrap(html_wg);
478      g_signal_connect( G_OBJECT( html_wg ), "link_clicked", G_CALLBACK( on_link_clicked ), NULL );
479      g_signal_connect( G_OBJECT( html_wg ), "scroll", G_CALLBACK( scrolled ), NULL );
480      gtk_html_set_caret_mode(GTK_HTML(html_wg),false);
481// gtk_html_adjust_cursor_position(GTK_HTML(html_wg));
482            gtk_widget_set_events(html_wg, 0x3FFFFE);
483            gtk_signal_connect (GTK_OBJECT (html_wg), "motion_notify_event",
484                        GTK_SIGNAL_FUNC (motion), NULL);
485      Gtk::ScrolledWindow scrolled_window;
486            scrolled_window2 = &scrolled_window;
487            scrolled_window.set_resize_mode(Gtk::RESIZE_PARENT);
488      scrolled_window.add(*html);
489      scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
490      
491      window.add(scrolled_window);
492      window.show_all();
493            position = 0;
494      show_random();
495      gtk_html_edit_make_cursor_visible(GTK_HTML(html_wg));
496      Gtk::Main::run(window);
497    }
498    else
499    {
500      std::cout << "usage: " << argv[0] << " [PATH TO ZIM FILE]" << std::endl;
501    }
502
503  }
504  catch (const std::exception& e)
505  {
506    std::cerr << e.what() << std::endl;
507    return -1;
508  }
509
510}
511
512

Archive Download this file

Branches:
development
master



interactive