Root/
Source at commit 9387c0dd58913fda7211152214fc69e884f7da22 created 14 years 2 months ago. By Mirko Lindner, add history and "go to top" functions | |
---|---|
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 | main_window *window; |
48 | Gtk::Widget *html; |
49 | GtkWidget *html_wg; |
50 | std::vector < std::pair< std::string, std::string > > history; |
51 | |
52 | |
53 | // // // misc functions |
54 | // get zimFile, if not already opened, open file |
55 | const zim::File& get_file() |
56 | { |
57 | static zim::File zimFile; |
58 | if (!zimFile.good()) |
59 | { |
60 | log_debug("file not initialized:" << fileName); |
61 | zimFile = zim::File(fileName); |
62 | log_debug("number of articles: " << zimFile.getCountArticles()); |
63 | } |
64 | |
65 | log_debug("returning file."); |
66 | return zimFile; |
67 | } |
68 | |
69 | // display message in gtk window |
70 | void show_message(std::string title, std::string txt) |
71 | { |
72 | message_dialog(window, title, txt); |
73 | } |
74 | |
75 | // fill gtkhtml widget with new content |
76 | //TODO prepend "top" anchor on html |
77 | void fill_gtkhtml(std::string& html, std::string url, std::string title){ |
78 | log_debug("fill gtkhtml called"); |
79 | std::string ccontent; |
80 | ccontent = "<a name=\"top\"></a>" + html; |
81 | gtk_html_flush(GTK_HTML(html_wg)); |
82 | gtk_html_load_from_string(GTK_HTML(html_wg), ccontent.c_str(), -1); |
83 | |
84 | if ((url != "") && title != ""){ |
85 | log_debug("adding " << title << " to history"); |
86 | history.push_back( std::make_pair( url, title ) ); |
87 | if (history.size() == 11){ |
88 | history.erase(history.begin()); |
89 | } |
90 | |
91 | } |
92 | |
93 | } |
94 | |
95 | void show_history() |
96 | { |
97 | std::string res, url, title; |
98 | res += "<ul style=\"list-style-type:none;\">"; |
99 | |
100 | for(unsigned i=history.size(); i > 0; --i) |
101 | { |
102 | |
103 | #if HAVE_ZIM_QUNICODE_H |
104 | res += "<li><a href=" + history[i-1].first + ">" + history[i-1].second + "</a></li>"; |
105 | #else |
106 | res += "<li><a href='" + history[i-1].first + "'>" + history[i-1].second + "</a></li>"; |
107 | #endif |
108 | |
109 | } |
110 | res += "</ul>"; |
111 | url = ""; |
112 | title = ""; |
113 | |
114 | fill_gtkhtml(res, url, title); |
115 | |
116 | } |
117 | |
118 | //UNUSED |
119 | // // copy article html from while loop into global variable |
120 | // void set_article(const std::string& txt) |
121 | // { |
122 | // content = txt; |
123 | // } |
124 | |
125 | // // // externally called functions |
126 | |
127 | // // display random article |
128 | void show_random() |
129 | { |
130 | |
131 | log_debug("random called."); |
132 | zim::File m = get_file(); |
133 | |
134 | unsigned int seed = static_cast<unsigned int>(time(0)); |
135 | zim::size_type idx = static_cast<zim::size_type>(static_cast<double>(m.getCountArticles()) * rand_r(&seed) / RAND_MAX); |
136 | zim::Article article; |
137 | |
138 | article = m.getArticle(idx); |
139 | |
140 | //loop in case article is redirect |
141 | do |
142 | { |
143 | article = article.getRedirectArticle(); |
144 | }while(article.isRedirect()); |
145 | |
146 | std::string res = article.getPage(); |
147 | |
148 | log_debug("article size=" << res.size()); |
149 | log_debug("article title=" << article.getTitle()); |
150 | log_debug("article namespace=" << article.getNamespace()); |
151 | |
152 | fill_gtkhtml(res, article.getUrl(), article.getTitle()); |
153 | } |
154 | |
155 | // // display search dialog |
156 | void search_window(main_window *window_x) |
157 | { |
158 | search_dialog(window_x, " "); |
159 | } |
160 | |
161 | // // |
162 | void GoToTop() |
163 | { |
164 | log_debug("go to top called"); |
165 | std::string term = "top"; |
166 | bool success = gtk_html_jump_to_anchor(GTK_HTML(html_wg), const_cast<char*>(term.c_str())); |
167 | } |
168 | |
169 | // // // meta functions |
170 | |
171 | // // set displayed html to given url |
172 | // // FIXME: returns several articles and displays on one page ... why? |
173 | void getArticleFromUrl(const gchar *url) |
174 | { |
175 | // TODO unescape url |
176 | |
177 | // // create ZIM file accessor |
178 | zim::File m = get_file(); |
179 | |
180 | // // convert url to string |
181 | std::string term(url); |
182 | std::string content; |
183 | // // replace '+' signs with spaces in url |
184 | std::replace(term.begin(), term.end(), '+', ' '); |
185 | |
186 | // // find and declare namespace |
187 | size_t found; |
188 | size_t found2; |
189 | char ns; |
190 | |
191 | found=term.find("/"); |
192 | if (found != std::string::npos) |
193 | { |
194 | if (found) |
195 | { |
196 | ns = term[0]; |
197 | term.erase(found + 1); |
198 | } |
199 | else |
200 | { |
201 | term.erase(1); |
202 | ns = term[0]; |
203 | found2 = term.find("/"); |
204 | term.erase(found2 + 1); |
205 | } |
206 | } |
207 | else |
208 | { |
209 | ns = 'A'; |
210 | } |
211 | |
212 | // // try to retrieve article |
213 | try |
214 | { |
215 | #if HAVE_ZIM_QUNICODE_H |
216 | zim::Article article = m.getArticle(ns, zim::QUnicodeString(term)); |
217 | #else |
218 | zim::Article article = m.getArticle(ns, term); |
219 | #endif |
220 | |
221 | if (article.good()) // check if article is really found |
222 | { |
223 | content = article.getPage(); |
224 | |
225 | fill_gtkhtml(content, article.getUrl(), article.getTitle()); |
226 | } |
227 | else |
228 | { |
229 | std::cerr << "article \"" << url << "\" not found" << std::endl; |
230 | show_message("Error", "The article you requested (" + term + ") was not found."); |
231 | } |
232 | } |
233 | catch (const std::exception& e) |
234 | { |
235 | std::cerr << e.what() << std::endl; |
236 | } |
237 | } |
238 | |
239 | |
240 | // // test functions |
241 | void getArticleFromTitle(const gchar *phrase) |
242 | { |
243 | char ns; |
244 | ns = 'A'; |
245 | zim::File z = get_file(); |
246 | |
247 | zim::Search::Results result; |
248 | zim::Search search(z); |
249 | std::string term(phrase); |
250 | std::string res; |
251 | std::string url; |
252 | std::string title; |
253 | search.setSearchLimit(25); |
254 | search.find(result, ns, term); |
255 | if( result.size() == 0) |
256 | { |
257 | show_message("Error", "The article you requested (" + term + ") was not found."); |
258 | |
259 | }else{ |
260 | |
261 | if (result.size() == 1){ |
262 | log_debug("one article in result"); |
263 | |
264 | zim::Article article = z.getArticle(result[0].getArticle().getIndex()); |
265 | |
266 | //loop in case article is redirect |
267 | do |
268 | { |
269 | article = article.getRedirectArticle(); |
270 | }while(article.isRedirect()); |
271 | |
272 | res = article.getPage(false, 10); |
273 | url = article.getUrl(); |
274 | title = article.getTitle(); |
275 | } |
276 | else |
277 | { |
278 | log_debug("more than one article in result"); |
279 | for (unsigned i = 0; i < result.size(); ++i) |
280 | { |
281 | #if HAVE_ZIM_QUNICODE_H |
282 | res += "<li><a href=" + result[i].getArticle().getLongUrl().toXML() + ">" + result[i].getArticle().getLongUrl().toXML() + "</a></li>"; |
283 | #else |
284 | res += "<li><a href='" + result[i].getArticle().getUrl() + "'>" + result[i].getArticle().getUrl() + "</a></li>"; |
285 | #endif |
286 | } |
287 | url = ""; |
288 | title = ""; |
289 | |
290 | } |
291 | |
292 | fill_gtkhtml(res, url, title); |
293 | } |
294 | } |
295 | |
296 | // // // window response functions |
297 | |
298 | // // open requested link |
299 | // FIXME show error window when dead-link requested |
300 | bool on_link_clicked(GtkHTML *html, const gchar *url) |
301 | { |
302 | std::string term(url); |
303 | size_t found; |
304 | found=term.find("#"); |
305 | if (found != std::string::npos){ |
306 | |
307 | if (found == 0){ |
308 | term.erase(0, 1); |
309 | bool success = gtk_html_jump_to_anchor(GTK_HTML(html_wg), const_cast<char*>(term.c_str())); |
310 | log_debug("jump to " << term << "worked: " << success); |
311 | }else{ |
312 | term = term.substr(0, found); |
313 | //TODO make "set_html" func accept anchor name |
314 | getArticleFromUrl(const_cast<char*>(term.c_str())); |
315 | } |
316 | |
317 | }else{ |
318 | getArticleFromUrl(url); |
319 | } |
320 | |
321 | return true; |
322 | } |
323 | |
324 | bool scrolled(GtkHTML *cb_html, GtkOrientation orientation, GtkScrollType scroll_type, gfloat position) |
325 | { |
326 | log_debug("scrolled"); |
327 | // TODO on any scroll adjust cursor, maybe with: |
328 | //static void gtk_html_adjust_cursor_position (GtkHTML *html) |
329 | } |
330 | |
331 | // // main function |
332 | int main(int argc, char **argv) |
333 | { |
334 | try |
335 | { |
336 | log_init(); |
337 | |
338 | if (argc == 2) |
339 | { |
340 | fileName = argv[1]; |
341 | |
342 | log_debug("vido is here file: " << fileName); |
343 | |
344 | Gtk::Main kit(argc, argv); |
345 | |
346 | main_window window; |
347 | window.set_title("Vido"); |
348 | // window.set_border_width(0); |
349 | window.set_default_size(220, 240); |
350 | // window.set_resizable(0); |
351 | |
352 | html_wg = gtk_html_new(); |
353 | |
354 | html = Glib::wrap(html_wg); |
355 | g_signal_connect( G_OBJECT( html_wg ), "link_clicked", G_CALLBACK( on_link_clicked ), NULL ); |
356 | g_signal_connect( G_OBJECT( html_wg ), "scroll", G_CALLBACK( scrolled ), NULL ); |
357 | gtk_html_set_caret_mode(GTK_HTML(html_wg),false); |
358 | // gtk_html_adjust_cursor_position(GTK_HTML(html_wg)); |
359 | static Gtk::ScrolledWindow scrolled_window; |
360 | scrolled_window.add(*html); |
361 | scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); |
362 | |
363 | window.add(scrolled_window); |
364 | window.show_all(); |
365 | |
366 | show_random(); |
367 | gtk_html_edit_make_cursor_visible(GTK_HTML(html_wg)); |
368 | Gtk::Main::run(window); |
369 | } |
370 | else |
371 | { |
372 | std::cout << "usage: " << argv[0] << " [PATH TO ZIM FILE]" << std::endl; |
373 | } |
374 | |
375 | } |
376 | catch (const std::exception& e) |
377 | { |
378 | std::cerr << e.what() << std::endl; |
379 | return -1; |
380 | } |
381 | |
382 | } |
383 | |
384 |
Branches:
development
master