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        window2->connect_all();
115}
116
117// fill gtkhtml widget with new content
118
119void fill_gtkhtml(std::string& html_str, std::string url, std::string title){
120    log_debug("fill gtkhtml called with " << position << " " << url << " and " << title);
121    std::string ccontent;
122    ccontent = "<a name=\"top\"></a>" + html_str;
123    gtk_html_flush(GTK_HTML(html_wg));
124    gtk_html_load_from_string(GTK_HTML(html_wg), ccontent.c_str(), -1);
125    current_url = url;
126    if ((url != "") && title != ""){
127      if ((!historyCall)){
128        if(position != 0){
129                    std::vector < std::pair< std::string, std::string > >::iterator iterator = history.begin();
130          log_debug("history size: " << history.size());
131                    for (int d=0; d < history.size(); d++){
132                        log_debug("history entry: " << d << " " << history[d].first);
133                    }
134                    for (int m=history.size()+position; m <= history.size(); m++){
135            log_debug("erasing history: number: "<< m << "title: " << history[m].first);
136                        history.erase(iterator+m);
137            }
138                }
139                log_debug("adding " << title << " to history \n" << "position: " << position);
140        history.push_back( std::make_pair( url, title ) );
141                if (history.size() == 11){
142          history.erase(history.begin());
143          }
144                log_debug("history size after stuff: " << history.size());
145      }else{
146// if (!historyCall){
147// log_debug("clearing history");
148// std::vector < std::pair< std::string, std::string > >::iterator iterator = history.begin();
149// for (int m=0; m < position; m++){
150// history.erase(iterator+m);
151// }
152// }else{
153          historyCall = false;
154// }
155      }
156      
157    }
158// gtk_html_get_selection_html(GTK_HTML(html_wg), )
159        while( Gtk::Main::events_pending() ){
160                Gtk::Main::iteration();
161        }
162        screenblock(0);
163        
164        window2->connect_all();
165    
166}
167
168void show_history()
169{
170    screenblock(1);
171  std::string res, url, title;
172  res += "<ul style=\"list-style-type:none;\">";
173    log_debug("history size: " << history.size());
174    for (int d=0; d < history.size(); d++){
175        log_debug("history entry: " << d << " " << history[d].first);
176    }
177  for(int i=history.size()-1; i >= 0; i--)
178  {
179    log_debug("entry: " << i);
180#if HAVE_ZIM_QUNICODE_H
181    res += "<li><a href=" + history[i].first + ">" + history[i].second + "</a></li>";
182#else
183    res += "<li><a href='" + history[i].first + "'>" + history[i].second + "</a>";
184    if (position == i){
185      res += "<--";
186    }
187    res += "</li>";
188#endif
189    
190  }
191  res += "</ul>";
192  url = "";
193  title = "";
194  
195  fill_gtkhtml(res, url, title);
196  
197}
198
199void history_jump(int jumper){
200  int new_rel_pos = position + jumper;
201  log_debug("new_rel_pos = " << new_rel_pos);
202  int new_pos = history.size() + new_rel_pos;
203  log_debug("new_pos = " << new_pos);
204  log_debug("history size = " << history.size());
205  if ((new_pos > 0) && (new_pos <= history.size())){
206// position = new_rel_pos;
207    historyCall = true;
208    std::string url = history[new_pos-1].first;
209    log_debug("url is = " << url);
210// const char* uri = url.c_str();
211// getArticleFromUrl(const_cast<char*>(url.c_str()), 1);
212    const char* uri = url.c_str();
213    getArticleFromUrl(uri, new_rel_pos);
214    position = new_rel_pos;
215  }else{
216        log_debug("jump not possible");
217        window2->connect_all();
218    }
219}
220
221//UNUSED
222// // copy article html from while loop into global variable
223// void set_article(const std::string& txt)
224// {
225// content = txt;
226// }
227
228// // // externally called functions
229
230
231// // display random article
232void show_random()
233{
234// window2->disconnect_all();
235        
236        screenblock(1);
237// log_debug("random called. window all disconnected");
238    zim::File m = get_file();
239        zim::Article article;
240    do
241        {
242                unsigned int seed = static_cast<unsigned int>(time(0));
243                zim::size_type idx = static_cast<zim::size_type>(static_cast<double>(m.getCountArticles()) * rand_r(&seed) / RAND_MAX);
244                
245                article = m.getArticle(idx);
246                
247                //loop in case article is redirect
248                do
249                {
250                        article = article.getRedirectArticle();
251                }while(article.isRedirect());
252    
253        }while(article.getUrl() == current_url);
254        
255    std::string res = article.getPage();
256
257// log_debug("article size=" << res.size());
258// log_debug("article title=" << article.getTitle());
259// log_debug("article namespace=" << article.getNamespace());
260// position = 0;
261    fill_gtkhtml(res, article.getUrl(), article.getTitle());
262// log_debug("random called. window all connected");
263
264}
265
266// // display search dialog
267void search_window(main_window *window_x)
268{
269// html_color = html_color_new_from_rgb('255','0','0');
270// gtk_html_set_color(GTK_HTML(html_wg),html_color);
271    search_dialog(window_x, " ");
272        
273}
274
275// //
276void GoToTop()
277{
278    log_debug("go to top called");
279    std::string term = "top";
280    bool success = gtk_html_jump_to_anchor(GTK_HTML(html_wg), const_cast<char*>(term.c_str()));
281        window2->connect_all();
282}
283
284// // // meta functions
285
286// // set displayed html to given url
287// // FIXME: returns several articles and displays on one page ... why?
288void getArticleFromUrl(const gchar *url, int pos)
289{
290    // TODO unescape url
291
292// // create ZIM file accessor
293    zim::File m = get_file();
294// // convert url to string
295    std::string term;
296        term.assign(url);
297// log_debug("str url" << term << "\n");
298    std::string content;
299// // replace '+' signs with spaces in url
300    std::replace(term.begin(), term.end(), '+', ' ');
301    
302// // find and declare namespace
303    size_t found;
304    size_t found2;
305    char ns;
306
307    found=term.find("/");
308    if (found != std::string::npos)
309    {
310        if (found)
311        {
312            ns = term[0];
313            term.erase(found + 1);
314        }
315        else
316        {
317            term.erase(1);
318            ns = term[0];
319            found2 = term.find("/");
320            term.erase(found2 + 1);
321        }
322    }
323    else
324    {
325        ns = 'A';
326    }
327
328// // try to retrieve article
329    try
330    {
331// #if HAVE_ZIM_QUNICODE_H
332// zim::Article article = m.getArticle(ns, zim::QUnicodeString(term));
333// #else
334        zim::Article article = m.getArticle(ns, term);
335// #endif
336
337        if (article.good()) // check if article is really found
338        {
339            content = article.getPage();
340                        position = pos;
341            fill_gtkhtml(content, article.getUrl(), article.getTitle());
342        }
343        else
344        {
345            std::cerr << "article \"" << url << "\" not found" << std::endl;
346            show_message("Error", "The article you requested (" + term + ") was not found.");
347        }
348    }
349    catch (const std::exception& e)
350    {
351        std::cerr << e.what() << std::endl;
352    }
353}
354
355
356// // test functions
357void getArticleFromTitle(const gchar *phrase)
358{
359        historyCall = false;
360    screenblock(1);
361        char ns;
362    ns = 'A';
363    zim::File z = get_file();
364    
365    zim::Search::Results result;
366    zim::Search search(z);
367    std::string term(phrase);
368    std::string res, url, title;
369    search.setSearchLimit(25);
370    search.find(result, ns, term);
371    if( result.size() == 0)
372    {
373        show_message("Error", "The article you requested (" + term + ") was not found.");
374                screenblock(0);
375    }else{
376      
377      if (result.size() == 1){
378        log_debug("one article in result");
379        
380        zim::Article article = z.getArticle(result[0].getArticle().getIndex());
381        
382        //loop in case article is redirect
383        do
384        {
385            article = article.getRedirectArticle();
386        }while(article.isRedirect());
387        
388        res = article.getPage(false, 10);
389        url = article.getUrl();
390        title = article.getTitle();
391                log_debug("set article from title position = 0");
392        position = 0;
393      }
394      else
395      {
396        log_debug("more than one article in result");
397        for (unsigned i = 0; i < result.size(); ++i)
398        {
399// #if HAVE_ZIM_QUNICODE_H
400// res += "<li><a href=" + result[i].getArticle().getLongUrl().toXML() + ">" + result[i].getArticle().getLongUrl().toXML() + "</a></li>";
401// #else
402          res += "<li><a href='" + result[i].getArticle().getUrl() + "'>" + result[i].getArticle().getUrl() + "</a></li>";
403// #endif
404        }
405        url = "";
406        title = "";
407    
408      }
409      
410      fill_gtkhtml(res, url, title);
411    }
412}
413
414// // // window response functions
415
416// // open requested link
417// FIXME show error window when dead-link requested
418bool on_link_clicked(GtkHTML *html, const gchar *url)
419{
420    std::string term(url);
421    size_t found;
422    found=term.find("#");
423    if (found != std::string::npos){
424    
425      if (found == 0){
426        term.erase(0, 1);
427        bool success = gtk_html_jump_to_anchor(GTK_HTML(html_wg), const_cast<char*>(term.c_str()));
428        log_debug("jump to " << term << "worked: " << success);
429      }else{
430        term = term.substr(0, found);
431        //TODO make "set_html" func accept anchor name
432        const char* uri = term.c_str();
433        getArticleFromUrl(uri, position);
434      }
435      
436    }else{
437      getArticleFromUrl(url,position);
438    }
439    
440    return true;
441}
442
443bool scrolled(GtkHTML *cb_html, GtkOrientation orientation, GtkScrollType scroll_type, gfloat position)
444{
445  log_debug("scrolled");
446  // TODO on any scroll adjust cursor, maybe with:
447  //static void gtk_html_adjust_cursor_position (GtkHTML *html)
448}
449
450// // main function
451int main(int argc, char **argv)
452{
453  try
454  {
455    log_init();
456
457    if (argc == 2)
458    {
459      fileName = argv[1];
460
461      log_debug("vido is here file: " << fileName);
462      
463      Gtk::Main kit(argc, argv);
464
465      main_window window;
466      window.set_title("Vido");
467  // window.set_border_width(0);
468      window.set_default_size(220, 240);
469  // window.set_resizable(0);
470            window.connect_all();
471      html_wg = gtk_html_new();
472      window2 = &window;
473      html = Glib::wrap(html_wg);
474      g_signal_connect( G_OBJECT( html_wg ), "link_clicked", G_CALLBACK( on_link_clicked ), NULL );
475      g_signal_connect( G_OBJECT( html_wg ), "scroll", G_CALLBACK( scrolled ), NULL );
476      gtk_html_set_caret_mode(GTK_HTML(html_wg),false);
477// gtk_html_adjust_cursor_position(GTK_HTML(html_wg));
478      Gtk::ScrolledWindow scrolled_window;
479            scrolled_window2 = &scrolled_window;
480      scrolled_window.add(*html);
481      scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
482      
483      window.add(scrolled_window);
484      window.show_all();
485            position = 0;
486      show_random();
487      gtk_html_edit_make_cursor_visible(GTK_HTML(html_wg));
488      Gtk::Main::run(window);
489    }
490    else
491    {
492      std::cout << "usage: " << argv[0] << " [PATH TO ZIM FILE]" << std::endl;
493    }
494
495  }
496  catch (const std::exception& e)
497  {
498    std::cerr << e.what() << std::endl;
499    return -1;
500  }
501
502}
503
504

Archive Download this file

Branches:
development
master



interactive