1 /**
2 * Implementation of the ocal dialog interfaces defined in ocaldialog.h
3 *
4 * Authors:
5 * Bruno Dilly
6 * Other dudes from The Inkscape Organization
7 *
8 * Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>
9 *
10 * Released under GNU GPL, read the file 'COPYING' for more information
11 */
13 #ifdef HAVE_CONFIG_H
14 # include <config.h>
15 #endif
17 #include "ocaldialogs.h"
18 #include "filedialogimpl-gtkmm.h"
19 #include "interface.h"
20 #include "gc-core.h"
21 #include <dialogs/dialog-events.h>
23 namespace Inkscape
24 {
25 namespace UI
26 {
27 namespace Dialog
28 {
30 //########################################################################
31 //# F I L E E X P O R T T O O C A L
32 //########################################################################
35 /**
36 * Public factory method. Used in file.cpp
37 */
39 FileExportToOCALDialog *FileExportToOCALDialog::create(Gtk::Window& parentWindow,
40 FileDialogType fileTypes,
41 const Glib::ustring &title)
42 {
43 FileExportToOCALDialog *dialog = new FileExportToOCALDialogImpl(parentWindow, fileTypes, title);
44 return dialog;
45 }
47 //########################################################################
48 //# F I L E E X P O R T T O O C A L P A S S W O R D
49 //########################################################################
52 /**
53 * Public factory method. Used in file.cpp
54 */
56 FileExportToOCALPasswordDialog *FileExportToOCALPasswordDialog::create(Gtk::Window& parentWindow,
57 const Glib::ustring &title)
58 {
59 FileExportToOCALPasswordDialog *dialog = new FileExportToOCALPasswordDialogImpl(parentWindow, title);
60 return dialog;
61 }
64 //#########################################################################
65 //### F I L E I M P O R T F R O M O C A L
66 //#########################################################################
68 /**
69 * Public factory. Called by file.cpp.
70 */
71 FileImportFromOCALDialog *FileImportFromOCALDialog::create(Gtk::Window &parentWindow,
72 const Glib::ustring &path,
73 FileDialogType fileTypes,
74 const Glib::ustring &title)
75 {
76 FileImportFromOCALDialog *dialog = new FileImportFromOCALDialogImplGtk(parentWindow, path, fileTypes, title);
77 return dialog;
78 }
81 //########################################################################
82 //# F I L E E X P O R T T O O C A L
83 //########################################################################
87 /**
88 * Callback for fileNameEntry widget
89 */
90 void FileExportToOCALDialogImpl::fileNameEntryChangedCallback()
91 {
92 if (!fileNameEntry)
93 return;
95 Glib::ustring fileName = fileNameEntry->get_text();
96 if (!Glib::get_charset()) //If we are not utf8
97 fileName = Glib::filename_to_utf8(fileName);
99 myFilename = fileName;
100 response(Gtk::RESPONSE_OK);
101 }
106 /**
107 * Constructor
108 */
109 FileExportToOCALDialogImpl::FileExportToOCALDialogImpl(Gtk::Window &parentWindow,
110 FileDialogType fileTypes,
111 const Glib::ustring &title) :
112 FileDialogOCALBase(title)
113 {
114 /*
115 * Start Taking the vertical Box and putting a Label
116 * and a Entry to take the filename
117 * Later put the extension selection and checkbox (?)
118 */
119 /* Initalize to Autodetect */
120 extension = NULL;
121 /* No filename to start out with */
122 myFilename = "";
124 /* Set our dialog type (save, export, etc...)*/
125 dialogType = fileTypes;
126 Gtk::VBox *vbox = get_vbox();
128 Gtk::Label *fileLabel = new Gtk::Label(_("File"));
130 fileNameEntry = new Gtk::Entry();
131 fileNameEntry->set_text(myFilename);
132 fileNameEntry->set_max_length(252); // I am giving the extension approach.
133 fileBox.pack_start(*fileLabel);
134 fileBox.pack_start(*fileNameEntry, Gtk::PACK_EXPAND_WIDGET, 3);
135 vbox->pack_start(fileBox);
137 //Let's do some customization
138 fileNameEntry = NULL;
139 Gtk::Container *cont = get_toplevel();
140 std::vector<Gtk::Entry *> entries;
141 findEntryWidgets(cont, entries);
142 if (entries.size() >=1 )
143 {
144 //Catch when user hits [return] on the text field
145 fileNameEntry = entries[0];
146 fileNameEntry->signal_activate().connect(
147 sigc::mem_fun(*this, &FileExportToOCALDialogImpl::fileNameEntryChangedCallback) );
148 }
150 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
151 set_default(*add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK));
153 show_all_children();
154 }
158 /**
159 * Destructor
160 */
161 FileExportToOCALDialogImpl::~FileExportToOCALDialogImpl()
162 {
163 }
165 /**
166 * Show this dialog modally. Return true if user hits [OK]
167 */
168 bool
169 FileExportToOCALDialogImpl::show()
170 {
171 set_modal (TRUE); //Window
172 sp_transientize((GtkWidget *)gobj()); //Make transient
173 gint b = run(); //Dialog
174 hide();
176 if (b == Gtk::RESPONSE_OK)
177 {
178 return TRUE;
179 }
180 else
181 {
182 return FALSE;
183 }
184 }
186 /**
187 * Get the file name chosen by the user. Valid after an [OK]
188 */
189 Glib::ustring
190 FileExportToOCALDialogImpl::getFilename()
191 {
192 myFilename = fileNameEntry->get_text();
193 if (!Glib::get_charset()) //If we are not utf8
194 myFilename = Glib::filename_to_utf8(myFilename);
196 return myFilename;
197 }
200 void
201 FileExportToOCALDialogImpl::change_title(const Glib::ustring& title)
202 {
203 this->set_title(title);
204 }
207 //########################################################################
208 //# F I L E E X P O R T T O O C A L P A S S W O R D
209 //########################################################################
212 /**
213 * Constructor
214 */
215 FileExportToOCALPasswordDialogImpl::FileExportToOCALPasswordDialogImpl(Gtk::Window &parentWindow,
216 const Glib::ustring &title) : FileDialogOCALBase(title)
217 {
218 /*
219 * Start Taking the vertical Box and putting 2 Labels
220 * and 2 Entries to take the username and password
221 */
222 /* No username and password to start out with */
223 myUsername = "";
224 myPassword = "";
226 Gtk::VBox *vbox = get_vbox();
228 Gtk::Label *userLabel = new Gtk::Label(_("Username:"));
229 Gtk::Label *passLabel = new Gtk::Label(_("Password:"));
231 usernameEntry = new Gtk::Entry();
232 usernameEntry->set_text(myUsername);
233 usernameEntry->set_max_length(255);
235 passwordEntry = new Gtk::Entry();
236 passwordEntry->set_text(myPassword);
237 passwordEntry->set_max_length(255);
238 passwordEntry->set_invisible_char('*');
239 passwordEntry->set_visibility(false);
240 passwordEntry->set_activates_default(true);
242 userBox.pack_start(*userLabel);
243 userBox.pack_start(*usernameEntry, Gtk::PACK_EXPAND_WIDGET, 3);
244 vbox->pack_start(userBox);
246 passBox.pack_start(*passLabel);
247 passBox.pack_start(*passwordEntry, Gtk::PACK_EXPAND_WIDGET, 3);
248 vbox->pack_start(passBox);
250 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
251 set_default(*add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK));
253 show_all_children();
254 }
257 /**
258 * Destructor
259 */
260 FileExportToOCALPasswordDialogImpl::~FileExportToOCALPasswordDialogImpl()
261 {
262 }
264 /**
265 * Show this dialog modally. Return true if user hits [OK]
266 */
267 bool
268 FileExportToOCALPasswordDialogImpl::show()
269 {
270 set_modal (TRUE); //Window
271 sp_transientize((GtkWidget *)gobj()); //Make transient
272 gint b = run(); //Dialog
273 hide();
275 if (b == Gtk::RESPONSE_OK)
276 {
277 return TRUE;
278 }
279 else
280 {
281 return FALSE;
282 }
283 }
285 /**
286 * Get the username. Valid after an [OK]
287 */
288 Glib::ustring
289 FileExportToOCALPasswordDialogImpl::getUsername()
290 {
291 myUsername = usernameEntry->get_text();
292 return myUsername;
293 }
295 /**
296 * Get the password. Valid after an [OK]
297 */
298 Glib::ustring
299 FileExportToOCALPasswordDialogImpl::getPassword()
300 {
301 myPassword = passwordEntry->get_text();
302 return myPassword;
303 }
305 void
306 FileExportToOCALPasswordDialogImpl::change_title(const Glib::ustring& title)
307 {
308 this->set_title(title);
309 }
312 //#########################################################################
313 //### F I L E I M P O R T F R O M O C A L
314 //#########################################################################
316 /*
317 * Calalback for cursor chage
318 */
319 void FileListViewText::on_cursor_changed()
320 {
321 // create file path
322 myFilename = Glib::get_tmp_dir();
323 myFilename.append(G_DIR_SEPARATOR_S);
324 std::vector<Gtk::TreeModel::Path> pathlist;
325 pathlist = this->get_selection()->get_selected_rows();
326 std::vector<int> posArray(1);
327 posArray = pathlist[0].get_indices();
328 myFilename.append(get_text(posArray[0], 2));
330 #ifdef WITH_GNOME_VFS
331 gnome_vfs_init();
332 GnomeVFSHandle *from_handle = NULL;
333 GnomeVFSHandle *to_handle = NULL;
334 GnomeVFSFileSize bytes_read;
335 GnomeVFSFileSize bytes_written;
336 GnomeVFSResult result;
337 guint8 buffer[8192];
339 //get file url
340 Glib::ustring fileUrl = get_text(posArray[0], 1); //http url
342 //Glib::ustring fileUrl = "dav://"; //dav url
343 //fileUrl.append(prefs_get_string_attribute("options.ocalurl", "str"));
344 //fileUrl.append("/dav.php/");
345 //fileUrl.append(get_text(posArray[0], 3)); //author dir
346 //fileUrl.append("/");
347 //fileUrl.append(get_text(posArray[0], 2)); //filename
349 if (!Glib::get_charset()) //If we are not utf8
350 fileUrl = Glib::filename_to_utf8(fileUrl);
352 // verifies if the file wasn't previously downloaded
353 if(gnome_vfs_open(&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_READ) == GNOME_VFS_ERROR_NOT_FOUND)
354 {
355 // open the temp file to receive
356 result = gnome_vfs_open (&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_WRITE);
357 if (result == GNOME_VFS_ERROR_NOT_FOUND){
358 result = gnome_vfs_create (&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL);
359 }
360 if (result != GNOME_VFS_OK) {
361 g_warning("Error creating temp file: %s", gnome_vfs_result_to_string(result));
362 return;
363 }
364 result = gnome_vfs_open (&from_handle, fileUrl.c_str(), GNOME_VFS_OPEN_READ);
365 if (result != GNOME_VFS_OK) {
366 g_warning("Could not find the file in Open Clip Art Library.");
367 return;
368 }
369 // copy the file
370 while (1) {
371 result = gnome_vfs_read (from_handle, buffer, 8192, &bytes_read);
372 if ((result == GNOME_VFS_ERROR_EOF) &&(!bytes_read)){
373 result = gnome_vfs_close (from_handle);
374 result = gnome_vfs_close (to_handle);
375 break;
376 }
377 if (result != GNOME_VFS_OK) {
378 g_warning("%s", gnome_vfs_result_to_string(result));
379 return;
380 }
381 result = gnome_vfs_write (to_handle, buffer, bytes_read, &bytes_written);
382 if (result != GNOME_VFS_OK) {
383 g_warning("%s", gnome_vfs_result_to_string(result));
384 return;
385 }
386 if (bytes_read != bytes_written){
387 g_warning("Bytes read not equal to bytes written");
388 return;
389 }
390 }
391 }
392 else
393 {
394 gnome_vfs_close(to_handle);
395 }
396 myPreview->showImage(myFilename);
397 myLabel->set_text(get_text(posArray[0], 4));
398 #endif
399 }
402 /*
403 * Callback for row activated
404 */
405 void FileListViewText::on_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column)
406 {
407 this->on_cursor_changed();
408 myButton->activate();
409 }
412 /*
413 * Returns the selected filename
414 */
415 Glib::ustring FileListViewText::getFilename()
416 {
417 return myFilename;
418 }
420 /**
421 * Callback for user input into searchTagEntry
422 */
423 void FileImportFromOCALDialogImplGtk::searchTagEntryChangedCallback()
424 {
425 if (!searchTagEntry)
426 return;
428 notFoundLabel->hide();
429 descriptionLabel->set_text("");
431 Glib::ustring searchTag = searchTagEntry->get_text();
432 // create the ocal uri to get rss feed
433 Glib::ustring uri = "http://";
434 uri.append(prefs_get_string_attribute("options.ocalurl", "str"));
435 uri.append("/media/feed/rss/");
436 uri.append(searchTag);
437 if (!Glib::get_charset()) //If we are not utf8
438 uri = Glib::filename_to_utf8(uri);
440 #ifdef WITH_GNOME_VFS
442 // get the rss feed
443 gnome_vfs_init();
444 GnomeVFSHandle *from_handle = NULL;
445 GnomeVFSHandle *to_handle = NULL;
446 GnomeVFSFileSize bytes_read;
447 GnomeVFSFileSize bytes_written;
448 GnomeVFSResult result;
449 guint8 buffer[8192];
451 // create the temp file name
452 Glib::ustring fileName = Glib::get_tmp_dir ();
453 fileName.append(G_DIR_SEPARATOR_S);
454 fileName.append("ocalfeed.xml");
456 // open the temp file to receive
457 result = gnome_vfs_open (&to_handle, fileName.c_str(), GNOME_VFS_OPEN_WRITE);
458 if (result == GNOME_VFS_ERROR_NOT_FOUND){
459 result = gnome_vfs_create (&to_handle, fileName.c_str(), GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL);
460 }
461 if (result != GNOME_VFS_OK) {
462 g_warning("Error creating temp file: %s", gnome_vfs_result_to_string(result));
463 return;
464 }
466 // open the rss feed
467 result = gnome_vfs_open (&from_handle, uri.c_str(), GNOME_VFS_OPEN_READ);
468 if (result != GNOME_VFS_OK) {
469 sp_ui_error_dialog(_("Failed to receive the Open Clip Art Library RSS feed. Verify if the server name is correct in Configuration->Misc (e.g.: openclipart.org)"));
470 return;
471 }
473 // copy the file
474 while (1) {
476 result = gnome_vfs_read (from_handle, buffer, 8192, &bytes_read);
478 if ((result == GNOME_VFS_ERROR_EOF) &&(!bytes_read)){
479 result = gnome_vfs_close (from_handle);
480 result = gnome_vfs_close (to_handle);
481 break;
482 }
484 if (result != GNOME_VFS_OK) {
485 g_warning("%s", gnome_vfs_result_to_string(result));
486 return;
487 }
488 result = gnome_vfs_write (to_handle, buffer, bytes_read, &bytes_written);
489 if (result != GNOME_VFS_OK) {
490 g_warning("%s", gnome_vfs_result_to_string(result));
491 return;
492 }
494 if (bytes_read != bytes_written){
495 g_warning("Bytes read not equal to bytes written");
496 return;
497 }
499 }
501 // create the resulting xml document tree
502 // this initialize the library and test mistakes between compiled and shared library used
503 LIBXML_TEST_VERSION
504 xmlDoc *doc = NULL;
505 xmlNode *root_element = NULL;
506 doc = xmlReadFile(fileName.c_str(), NULL, 0);
507 if (doc == NULL) {
508 g_warning("Failed to parse %s\n", fileName.c_str());
509 return;
510 }
512 // get the root element node
513 root_element = xmlDocGetRootElement(doc);
515 // clear the fileslist
516 filesList->clear_items();
517 filesList->set_sensitive(false);
519 // print all xml the element names
520 print_xml_element_names(root_element);
522 if (filesList->size() == 0)
523 {
524 notFoundLabel->show();
525 filesList->set_sensitive(false);
526 }
527 else
528 filesList->set_sensitive(true);
530 // free the document
531 xmlFreeDoc(doc);
532 // free the global variables that may have been allocated by the parser
533 xmlCleanupParser();
534 return;
535 #endif
536 }
538 /**
539 * Prints the names of the all the xml elements
540 * that are siblings or children of a given xml node
541 */
542 void FileImportFromOCALDialogImplGtk::print_xml_element_names(xmlNode * a_node)
543 {
544 xmlNode *cur_node = NULL;
545 guint row_num = 0;
546 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
547 // get itens information
548 if (strcmp((const char*)cur_node->name, "rss")) //avoid the root
549 if (cur_node->type == XML_ELEMENT_NODE && !strcmp((const char*)cur_node->parent->name, "item"))
550 {
551 if (!strcmp((const char*)cur_node->name, "title"))
552 {
553 xmlChar *title = xmlNodeGetContent(cur_node);
554 row_num = filesList->append_text((const char*)title);
555 xmlFree(title);
556 }
557 #ifdef WITH_GNOME_VFS
558 else if (!strcmp((const char*)cur_node->name, "enclosure"))
559 {
560 xmlChar *urlattribute = xmlGetProp(cur_node, (xmlChar*)"url");
561 filesList->set_text(row_num, 1, (const char*)urlattribute);
562 gchar *tmp_file;
563 tmp_file = gnome_vfs_uri_extract_short_path_name(gnome_vfs_uri_new((const char*)urlattribute));
564 filesList->set_text(row_num, 2, (const char*)tmp_file);
565 xmlFree(urlattribute);
566 }
567 else if (!strcmp((const char*)cur_node->name, "creator"))
568 {
569 filesList->set_text(row_num, 3, (const char*)xmlNodeGetContent(cur_node));
570 }
571 else if (!strcmp((const char*)cur_node->name, "description"))
572 {
573 filesList->set_text(row_num, 4, (const char*)xmlNodeGetContent(cur_node));
574 }
575 #endif
576 }
577 print_xml_element_names(cur_node->children);
578 }
579 }
581 /**
582 * Constructor. Not called directly. Use the factory.
583 */
584 FileImportFromOCALDialogImplGtk::FileImportFromOCALDialogImplGtk(Gtk::Window& parentWindow,
585 const Glib::ustring &dir,
586 FileDialogType fileTypes,
587 const Glib::ustring &title) :
588 FileDialogOCALBase(title)
589 {
590 // Initalize to Autodetect
591 extension = NULL;
592 // No filename to start out with
593 Glib::ustring searchTag = "";
595 dialogType = fileTypes;
596 Gtk::VBox *vbox = get_vbox();
597 Gtk::Label *tagLabel = new Gtk::Label(_("Search Tag"));
598 notFoundLabel = new Gtk::Label(_("No files matched your search"));
599 descriptionLabel = new Gtk::Label();
600 descriptionLabel->set_max_width_chars(60);
601 descriptionLabel->set_single_line_mode(false);
602 messageBox.pack_start(*notFoundLabel);
603 descriptionBox.pack_start(*descriptionLabel);
604 searchTagEntry = new Gtk::Entry();
605 searchTagEntry->set_text(searchTag);
606 searchTagEntry->set_max_length(255);
607 searchButton = new Gtk::Button(_("Search"));
608 tagBox.pack_start(*tagLabel);
609 tagBox.pack_start(*searchTagEntry, Gtk::PACK_EXPAND_WIDGET, 3);
610 tagBox.pack_start(*searchButton);
611 filesPreview = new SVGPreview();
612 filesPreview->showNoPreview();
613 // add the buttons in the bottom of the dialog
614 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
615 okButton = add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
616 // sets the okbutton to default
617 set_default(*okButton);
618 filesList = new FileListViewText(5, *filesPreview, *descriptionLabel, *okButton);
619 filesList->set_sensitive(false);
620 // add the listview inside a ScrolledWindow
621 listScrolledWindow.add(*filesList);
622 // only show the scrollbars when they are necessary:
623 listScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
624 filesList->set_column_title(0, _("Files Found"));
625 listScrolledWindow.set_size_request(400, 180);
626 filesList->get_column(1)->set_visible(false); // file url
627 filesList->get_column(2)->set_visible(false); // tmp file path
628 filesList->get_column(3)->set_visible(false); // author dir
629 filesList->get_column(4)->set_visible(false); // file description
630 filesBox.pack_start(listScrolledWindow);
631 filesBox.pack_start(*filesPreview);
632 vbox->pack_start(tagBox);
633 vbox->pack_start(messageBox);
634 vbox->pack_start(filesBox);
635 vbox->pack_start(descriptionBox);
637 //Let's do some customization
638 searchTagEntry = NULL;
639 Gtk::Container *cont = get_toplevel();
640 std::vector<Gtk::Entry *> entries;
641 findEntryWidgets(cont, entries);
642 if (entries.size() >=1 )
643 {
644 //Catch when user hits [return] on the text field
645 searchTagEntry = entries[0];
646 searchTagEntry->signal_activate().connect(
647 sigc::mem_fun(*this, &FileImportFromOCALDialogImplGtk::searchTagEntryChangedCallback));
648 }
650 searchButton->signal_clicked().connect(
651 sigc::mem_fun(*this, &FileImportFromOCALDialogImplGtk::searchTagEntryChangedCallback));
653 show_all_children();
654 notFoundLabel->hide();
655 }
657 /**
658 * Destructor
659 */
660 FileImportFromOCALDialogImplGtk::~FileImportFromOCALDialogImplGtk()
661 {
663 }
665 /**
666 * Show this dialog modally. Return true if user hits [OK]
667 */
668 bool
669 FileImportFromOCALDialogImplGtk::show()
670 {
671 set_modal (TRUE); //Window
672 sp_transientize((GtkWidget *)gobj()); //Make transient
673 gint b = run(); //Dialog
674 hide();
676 if (b == Gtk::RESPONSE_OK)
677 {
678 return TRUE;
679 }
680 else
681 {
682 return FALSE;
683 }
684 }
687 /**
688 * Get the file extension type that was selected by the user. Valid after an [OK]
689 */
690 Inkscape::Extension::Extension *
691 FileImportFromOCALDialogImplGtk::getSelectionType()
692 {
693 return extension;
694 }
697 /**
698 * Get the file name chosen by the user. Valid after an [OK]
699 */
700 Glib::ustring
701 FileImportFromOCALDialogImplGtk::getFilename (void)
702 {
703 return filesList->getFilename();
704 }
707 } //namespace Dialog
708 } //namespace UI
709 } //namespace Inkscape
713 /*
714 Local Variables:
715 mode:c++
716 c-file-style:"stroustrup"
717 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
718 indent-tabs-mode:nil
719 fill-column:99
720 End:
721 */
722 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :