Root/
Source at commit c544a52e18c5aae130002d05aca62940ba744597 created 14 years 2 days ago. By Mirko Lindner, fix commands | |
---|---|
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 | |
38 | log_define("vido.main") |
39 | |
40 | extern "C" { |
41 | #include "gtkhtml/gtkhtml.h" |
42 | } |
43 | |
44 | // std::string content; |
45 | std::string fileName; |
46 | |
47 | //TODO this can't be right |
48 | main_window *window2; |
49 | Gtk::ScrolledWindow *scrolled_window2; |
50 | |
51 | |
52 | Gtk::Widget *html; |
53 | GtkWidget *html_wg; |
54 | std::vector < std::pair< std::string, std::string > > history; |
55 | int position; |
56 | bool historyCall = false; |
57 | // variable to keep url of currently displayed article |
58 | std::string current_url = ""; |
59 | |
60 | // // // misc functions |
61 | // get zimFile, if not already opened, open file |
62 | const 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 | |
78 | void 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 |
93 | void show_message(std::string title, std::string txt) |
94 | { |
95 | message_dialog(window2, title, txt); |
96 | } |
97 | |
98 | void 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 | |
119 | void 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 | |
168 | void 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 | |
199 | void 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 |
232 | void 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 |
267 | void 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 | // // |
276 | void 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? |
288 | void 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 |
357 | void 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 |
418 | bool 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 | |
443 | bool 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 |
451 | int 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 |
Branches:
development
master