summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorAlex Valavanis <valavanisalex@gmail.com>2012-02-27 23:49:20 +0000
committerAlex Valavanis <valavanisalex@gmail.com>2012-02-27 23:49:20 +0000
commit6c5b23c3d3eff317c770c52cf47ca9955be7caba (patch)
tree91f6b3f9d70089226ef546a9c9a9580c7e59d4d2 /src/ui
parentgseal fix (diff)
parentfixed crash! (diff)
downloadinkscape-6c5b23c3d3eff317c770c52cf47ca9955be7caba.tar.gz
inkscape-6c5b23c3d3eff317c770c52cf47ca9955be7caba.zip
Merge Andrew's new OCAL dialog and clean headers. Please test
(bzr r11027)
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/clipboard.cpp2
-rw-r--r--src/ui/dialog/ocaldialogs.cpp1160
-rw-r--r--src/ui/dialog/ocaldialogs.h310
3 files changed, 1079 insertions, 393 deletions
diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp
index 534f57a57..e32f59fa3 100644
--- a/src/ui/clipboard.cpp
+++ b/src/ui/clipboard.cpp
@@ -23,6 +23,7 @@
// TODO: reduce header bloat if possible
+#include "file.h" // for file_import, used in _pasteImage
#include <list>
#include <algorithm>
#include <gtkmm/clipboard.h>
@@ -70,7 +71,6 @@
#include "live_effects/parameter/path.h"
#include "svg/svg.h" // for sp_svg_transform_write, used in _copySelection
#include "svg/css-ostringstream.h" // used in _parseColor
-#include "file.h" // for file_import, used in _pasteImage
#include "text-context.h"
#include "text-editing.h"
#include "tools-switch.h"
diff --git a/src/ui/dialog/ocaldialogs.cpp b/src/ui/dialog/ocaldialogs.cpp
index 2a386b003..b890739fb 100644
--- a/src/ui/dialog/ocaldialogs.cpp
+++ b/src/ui/dialog/ocaldialogs.cpp
@@ -5,6 +5,7 @@
/* Authors:
* Bruno Dilly
* Other dudes from The Inkscape Organization
+ * Andrew Higginson
*
* Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>
*
@@ -20,6 +21,7 @@
#include <errno.h> // errno
#include <string.h> // strerror()
+#include "path-prefix.h"
#include "ocaldialogs.h"
#include "filedialogimpl-gtkmm.h"
#include "interface.h"
@@ -28,8 +30,12 @@
#include "io/sys.h"
#include "preferences.h"
+#include <gtkmm/notebook.h>
+#include <gtkmm/spinner.h>
#include <gtkmm/stock.h>
#include <glibmm/i18n.h>
+#include <gdkmm/general.h>
+#include <libxml/tree.h>
namespace Inkscape
{
@@ -37,6 +43,8 @@ namespace UI
{
namespace Dialog
{
+namespace OCAL
+{
//########################################################################
//# F I L E E X P O R T T O O C A L
@@ -46,7 +54,7 @@ namespace Dialog
* Callback for fileNameEntry widget
*/
/*
-void FileExportToOCALDialog::fileNameEntryChangedCallback()
+void ExportDialog::fileNameEntryChangedCallback()
{
if (!fileNameEntry)
return;
@@ -63,10 +71,10 @@ void FileExportToOCALDialog::fileNameEntryChangedCallback()
* Constructor
*/
/*
-FileExportToOCALDialog::FileExportToOCALDialog(Gtk::Window &parentWindow,
+ExportDialog::ExportDialog(Gtk::Window &parentWindow,
FileDialogType fileTypes,
const Glib::ustring &title) :
- FileDialogOCALBase(title, parentWindow)
+ FileDialogBase(title, parentWindow)
{
*/
/*
@@ -106,7 +114,7 @@ FileExportToOCALDialog::FileExportToOCALDialog(Gtk::Window &parentWindow,
//Catch when user hits [return] on the text field
fileNameEntry = entries[0];
fileNameEntry->signal_activate().connect(
- sigc::mem_fun(*this, &FileExportToOCALDialog::fileNameEntryChangedCallback) );
+ sigc::mem_fun(*this, &ExportDialog::fileNameEntryChangedCallback) );
}
add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
@@ -119,7 +127,7 @@ FileExportToOCALDialog::FileExportToOCALDialog(Gtk::Window &parentWindow,
* Destructor
*/
/*
-FileExportToOCALDialog::~FileExportToOCALDialog()
+ExportDialog::~ExportDialog()
{
}
*/
@@ -128,7 +136,7 @@ FileExportToOCALDialog::~FileExportToOCALDialog()
*/
/*
bool
-FileExportToOCALDialog::show()
+ExportDialog::show()
{
set_modal (TRUE); //Window
sp_transientize((GtkWidget *)gobj()); //Make transient
@@ -150,7 +158,7 @@ FileExportToOCALDialog::show()
*/
/*
Glib::ustring
-FileExportToOCALDialog::getFilename()
+ExportDialog::get_filename()
{
myFilename = fileNameEntry->get_text();
if (!Glib::get_charset()) //If we are not utf8
@@ -161,7 +169,7 @@ FileExportToOCALDialog::getFilename()
void
-FileExportToOCALDialog::change_title(const Glib::ustring& title)
+ExportDialog::change_title(const Glib::ustring& title)
{
this->set_title(title);
}
@@ -176,8 +184,8 @@ FileExportToOCALDialog::change_title(const Glib::ustring& title)
* Constructor
*/
/*
-FileExportToOCALPasswordDialog::FileExportToOCALPasswordDialog(Gtk::Window &parentWindow,
- const Glib::ustring &title) : FileDialogOCALBase(title, parentWindow)
+ExportPasswordDialog::ExportPasswordDialog(Gtk::Window &parentWindow,
+ const Glib::ustring &title) : FileDialogBase(title, parentWindow)
{
*/
/*
@@ -224,7 +232,7 @@ FileExportToOCALPasswordDialog::FileExportToOCALPasswordDialog(Gtk::Window &pare
* Destructor
*/
/*
-FileExportToOCALPasswordDialog::~FileExportToOCALPasswordDialog()
+ExportPasswordDialog::~ExportPasswordDialog()
{
}
*/
@@ -233,7 +241,7 @@ FileExportToOCALPasswordDialog::~FileExportToOCALPasswordDialog()
*/
/*
bool
-FileExportToOCALPasswordDialog::show()
+ExportPasswordDialog::show()
{
set_modal (TRUE); //Window
sp_transientize((GtkWidget *)gobj()); //Make transient
@@ -255,7 +263,7 @@ FileExportToOCALPasswordDialog::show()
*/
/*
Glib::ustring
-FileExportToOCALPasswordDialog::getUsername()
+ExportPasswordDialog::getUsername()
{
myUsername = usernameEntry->get_text();
return myUsername;
@@ -266,14 +274,14 @@ FileExportToOCALPasswordDialog::getUsername()
*/
/*
Glib::ustring
-FileExportToOCALPasswordDialog::getPassword()
+ExportPasswordDialog::getPassword()
{
myPassword = passwordEntry->get_text();
return myPassword;
}
void
-FileExportToOCALPasswordDialog::change_title(const Glib::ustring& title)
+ExportPasswordDialog::change_title(const Glib::ustring& title)
{
this->set_title(title);
}
@@ -283,416 +291,948 @@ FileExportToOCALPasswordDialog::change_title(const Glib::ustring& title)
//### F I L E I M P O R T F R O M O C A L
//#########################################################################
-/*
- * Calalback for cursor chage
- */
-void FileListViewText::on_cursor_changed()
+WrapLabel::WrapLabel() : Gtk::Label()
{
- std::vector<Gtk::TreeModel::Path> pathlist;
- pathlist = this->get_selection()->get_selected_rows();
- std::vector<int> posArray(1);
- posArray = pathlist[0].get_indices();
+ signal_size_allocate().connect(sigc::mem_fun(*this, &WrapLabel::_on_size_allocate));
+}
-#ifdef WITH_GNOME_VFS
- gnome_vfs_init();
- GnomeVFSHandle *from_handle = NULL;
- GnomeVFSHandle *to_handle = NULL;
- GnomeVFSFileSize bytes_read;
- GnomeVFSFileSize bytes_written;
- GnomeVFSResult result;
- guint8 buffer[8192];
- Glib::ustring fileUrl;
-
- // FIXME: this would be better as a per-user OCAL cache of files
- // instead of filling /tmp with downloads.
- //
- // create file path
- const std::string tmptemplate = "ocal-";
- std::string tmpname;
- int fd = Inkscape::IO::file_open_tmp(tmpname, tmptemplate);
- if (fd<0) {
- g_warning("Error creating temp file");
- return;
+void WrapLabel::_on_size_allocate(Gtk::Allocation& allocation)
+{
+ set_size_request(allocation.get_width(), -1);
+}
+
+
+LoadingBox::LoadingBox() : Gtk::EventBox()
+{
+ set_visible_window(false);
+ draw_spinner = false;
+ spinner_step = 0;
+ signal_expose_event().connect(sigc::mem_fun(*this, &LoadingBox::_on_expose_event), false);
+}
+
+bool LoadingBox::_on_expose_event(GdkEventExpose* event)
+{
+ Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
+
+ // Draw shadow
+ int x = get_allocation().get_x();
+ int y = get_allocation().get_y();
+ int width = get_allocation().get_width();
+ int height = get_allocation().get_height();
+
+ get_style()->paint_shadow(get_window(), get_state(), Gtk::SHADOW_IN,
+ Gdk::Rectangle(x, y, width, height),
+ *this, Glib::ustring("viewport"), x, y, width, height);
+
+ if (draw_spinner) {
+ int spinner_size = 16;
+ int spinner_x = x + (width - spinner_size) / 2;
+ int spinner_y = y + (height - spinner_size) / 2;
+
+ // FIXME: Gtk::Style::paint_spinner not yet in gtkmm
+ gtk_paint_spinner(gtk_widget_get_style(GTK_WIDGET(gobj())),
+ gtk_widget_get_window(GTK_WIDGET(gobj())),
+ gtk_widget_get_state(GTK_WIDGET(gobj())), NULL, GTK_WIDGET(gobj()),
+ NULL, spinner_step, spinner_x, spinner_y, spinner_size, spinner_size);
}
- close(fd);
- // make sure we don't collide with other users on the same machine
- myFilename = tmpname;
- myFilename.append("-");
- myFilename.append(get_text(posArray[0], 2));
- // rename based on original image's name, retaining extension
- if (rename(tmpname.c_str(),myFilename.c_str())<0) {
- unlink(tmpname.c_str());
- g_warning("Error creating destination file '%s': %s", myFilename.c_str(), strerror(errno));
- goto failquit;
- }
-
- //get file url
- fileUrl = get_text(posArray[0], 1); //http url
-
- //Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- //Glib::ustring fileUrl = "dav://"; //dav url
- //fileUrl.append(prefs->getString("/options/ocalurl/str"));
- //fileUrl.append("/dav.php/");
- //fileUrl.append(get_text(posArray[0], 3)); //author dir
- //fileUrl.append("/");
- //fileUrl.append(get_text(posArray[0], 2)); //filename
- if (!Glib::get_charset()) //If we are not utf8
- fileUrl = Glib::filename_to_utf8(fileUrl);
+ return false;
+}
- {
- // open the temp file to receive
- result = gnome_vfs_open (&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_WRITE);
- if (result == GNOME_VFS_ERROR_NOT_FOUND){
- result = gnome_vfs_create (&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL);
- }
- if (result != GNOME_VFS_OK) {
- g_warning("Error creating temp file '%s': %s", myFilename.c_str(), gnome_vfs_result_to_string(result));
- goto fail;
- }
- result = gnome_vfs_open (&from_handle, fileUrl.c_str(), GNOME_VFS_OPEN_READ);
- if (result != GNOME_VFS_OK) {
- g_warning("Could not find the file in Open Clip Art Library.");
- goto fail;
- }
- // copy the file
- while (1) {
- result = gnome_vfs_read (from_handle, buffer, 8192, &bytes_read);
- if ((result == GNOME_VFS_ERROR_EOF) &&(!bytes_read)){
- result = gnome_vfs_close (from_handle);
- result = gnome_vfs_close (to_handle);
- break;
- }
- if (result != GNOME_VFS_OK) {
- g_warning("%s", gnome_vfs_result_to_string(result));
- goto fail;
- }
- result = gnome_vfs_write (to_handle, buffer, bytes_read, &bytes_written);
- if (result != GNOME_VFS_OK) {
- g_warning("%s", gnome_vfs_result_to_string(result));
- goto fail;
- }
- if (bytes_read != bytes_written){
- g_warning("Bytes read not equal to bytes written");
- goto fail;
- }
+void LoadingBox::start()
+{
+ // Timeout hasn't been stopped, so must be disconnected
+ if ((draw_spinner != false) & (timeout != NULL)) {
+ timeout.disconnect();
+ }
+
+ draw_spinner = true;
+ timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &LoadingBox::on_timeout), 80);
+}
+
+void LoadingBox::stop()
+{
+ draw_spinner = false;
+}
+
+bool LoadingBox::on_timeout() {
+ if (draw_spinner) {
+
+ if (spinner_step == 11) {
+ spinner_step = 0;
+ } else {
+ spinner_step ++;
}
+
+ queue_draw();
+ return true;
}
- myPreview->showImage(myFilename);
- myLabel->set_text(get_text(posArray[0], 4));
-#endif
- return;
-fail:
- unlink(myFilename.c_str());
-failquit:
- myFilename = "";
+ return false;
+}
+
+PreviewWidget::PreviewWidget() : Gtk::VBox(false, 12)
+{
+ box_loading = new LoadingBox();
+ image = new Gtk::Image();
+
+ label_title = new WrapLabel();
+ label_description = new WrapLabel();
+ label_time = new WrapLabel();
+
+ pack_start(*box_loading, false, false);
+ pack_start(*image, false, false);
+ pack_start(*label_title, false, false);
+ pack_start(*label_description, false, false);
+ pack_start(*label_time, false, false);
+
+ label_title->set_line_wrap(true);
+ label_title->set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
+ label_title->set_justify(Gtk::JUSTIFY_CENTER);
+ label_description->set_line_wrap(true);
+ label_description->set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
+ label_description->set_justify(Gtk::JUSTIFY_CENTER);
+ label_time->set_line_wrap(true);
+ label_time->set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
+ label_time->set_justify(Gtk::JUSTIFY_CENTER);
+
+ box_loading->set_no_show_all(true);
+ image->set_no_show_all(true);
+ label_title->set_size_request(90, -1);
+ label_description->set_size_request(90, -1);
+ label_time->set_size_request(90, -1);
+ box_loading->set_size_request(90, 90);
+ set_border_width(12);
+
+ signal_expose_event().connect(sigc::mem_fun(*this, &PreviewWidget::_on_expose_event), false);
+
+ clear();
}
+void PreviewWidget::set_metadata(Glib::ustring description, Glib::ustring creator,
+ Glib::ustring time)
+{
+ label_title->set_markup(g_markup_printf_escaped("<b>%s</b>", description.c_str()));
+ label_description->set_markup(g_markup_printf_escaped("%s", creator.c_str()));
+ label_time->set_markup(g_markup_printf_escaped("<small>%s</small>", time.c_str()));
-/*
- * Callback for row activated
- */
-void FileListViewText::on_row_activated(const Gtk::TreeModel::Path& /*path*/, Gtk::TreeViewColumn* /*column*/)
+ show_box_loading();
+}
+
+void PreviewWidget::show_box_loading()
{
- this->on_cursor_changed();
- myButton->activate();
+ box_loading->show();
+ box_loading->start();
}
+void PreviewWidget::hide_box_loading()
+{
+ box_loading->hide();
+ box_loading->stop();
+}
-/*
- * Returns the selected filename
- */
-Glib::ustring FileListViewText::getFilename()
+void PreviewWidget::set_image(std::string path)
{
- return myFilename;
+ image->set(path);
+ hide_box_loading();
+ image->show();
}
+void PreviewWidget::clear()
+{
+ label_title->set_markup("");
+ label_description->set_markup("");
+ label_time->set_markup("");
-#ifdef WITH_GNOME_VFS
-/**
- * Read callback for xmlReadIO(), used below
- */
-static int vfs_read_callback (GnomeVFSHandle *handle, char* buf, int nb)
+ box_loading->hide();
+ image->hide();
+}
+
+bool PreviewWidget::_on_expose_event(GdkEventExpose* event)
{
- GnomeVFSFileSize ndone;
- GnomeVFSResult result;
+ Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
+
+ // Draw background
+ int x = get_allocation().get_x();
+ int y = get_allocation().get_y();
+ int width = get_allocation().get_width();
+ int height = get_allocation().get_height();
+ Gdk::Color background_fill = get_style()->get_base(get_state());
- result = gnome_vfs_read (handle, buf, nb, &ndone);
+ cr->rectangle(x, y, width, height);
+ Gdk::Cairo::set_source_color(cr, background_fill);
+ cr->fill();
- if (result == GNOME_VFS_OK) {
- return (int)ndone;
+ return false;
+}
+
+StatusWidget::StatusWidget() : Gtk::HBox(false, 6)
+{
+ image = new Gtk::Image(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU);
+ spinner = new Gtk::Spinner();
+ label = new Gtk::Label();
+
+ image->set_no_show_all(true);
+ spinner->set_no_show_all(true);
+ label->set_no_show_all(true);
+
+ pack_start(*image, false, false);
+ pack_start(*spinner, false, false);
+ pack_start(*label, false, false);
+}
+
+void StatusWidget::clear()
+{
+ spinner->hide();
+ image->hide();
+ label->hide();
+}
+
+void StatusWidget::set_info(Glib::ustring text)
+{
+ spinner->hide();
+ image->show();
+ label->show();
+ image->set(Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_MENU);
+ label->set_text(text);
+}
+
+void StatusWidget::set_error(Glib::ustring text)
+{
+ spinner->hide();
+ image->show();
+ label->show();
+ image->set(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU);
+ label->set_text(text);
+}
+
+void StatusWidget::start_process(Glib::ustring text)
+{
+ image->hide();
+ spinner->show();
+ label->show();
+ label->set_text(text);
+ spinner->start();
+ show_all();
+}
+
+void StatusWidget::end_process()
+{
+ spinner->stop();
+ spinner->hide();
+ label->hide();
+ clear();
+}
+
+SearchEntry::SearchEntry() : Gtk::Entry()
+{
+ signal_changed().connect(sigc::mem_fun(*this, &SearchEntry::_on_changed));
+ signal_icon_press().connect(sigc::mem_fun(*this, &SearchEntry::_on_icon_pressed));
+
+ set_icon_from_stock(Gtk::Stock::FIND, Gtk::ENTRY_ICON_PRIMARY);
+ gtk_entry_set_icon_from_stock(gobj(), GTK_ENTRY_ICON_SECONDARY, NULL);
+}
+
+void SearchEntry::_on_icon_pressed(Gtk::EntryIconPosition icon_position, const GdkEventButton* event)
+{
+ if (icon_position == Gtk::ENTRY_ICON_SECONDARY) {
+ grab_focus();
+ set_text("");
+ } else if (icon_position == Gtk::ENTRY_ICON_PRIMARY) {
+ select_region(0, -1);
+ grab_focus();
+ }
+}
+
+void SearchEntry::_on_changed()
+{
+ if (get_text().empty()) {
+ gtk_entry_set_icon_from_stock(gobj(), GTK_ENTRY_ICON_SECONDARY, NULL);
} else {
- if (result != GNOME_VFS_ERROR_EOF) {
- sp_ui_error_dialog(_("Error while reading the Open Clip Art RSS feed"));
- g_warning("%s\n", gnome_vfs_result_to_string(result));
+ set_icon_from_stock(Gtk::Stock::CLEAR, Gtk::ENTRY_ICON_SECONDARY);
+ }
+}
+
+BaseBox::BaseBox() : Gtk::EventBox()
+{
+ signal_expose_event().connect(sigc::mem_fun(*this, &BaseBox::_on_expose_event), false);
+ set_visible_window(false);
+}
+
+bool BaseBox::_on_expose_event(GdkEventExpose* event)
+{
+ Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
+
+ // Draw background and shadow
+ int x = get_allocation().get_x();
+ int y = get_allocation().get_y();
+ int width = get_allocation().get_width();
+ int height = get_allocation().get_height();
+ Gdk::Color background_fill = get_style()->get_base(get_state());
+
+ cr->rectangle(x, y, width, height);
+ Gdk::Cairo::set_source_color(cr, background_fill);
+ cr->fill();
+
+ get_style()->paint_shadow(get_window(), get_state(), Gtk::SHADOW_IN,
+ Gdk::Rectangle(x, y, width, height),
+ *this, Glib::ustring("viewport"), x, y, width, height);
+
+ return false;
+}
+
+LogoArea::LogoArea() : Gtk::EventBox()
+{
+ // Try to load the OCAL logo, but if the file is not found, degrade gracefully
+ try {
+ std::string logo_path = Glib::build_filename(INKSCAPE_PIXMAPDIR, "OCAL.png");
+ logo_mask = Cairo::ImageSurface::create_from_png(logo_path);
+ draw_logo = true;
+ } catch(Cairo::logic_error) {
+ logo_mask = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 1,1);
+ draw_logo = false;
+ }
+ signal_expose_event().connect(sigc::mem_fun(*this, &LogoArea::_on_expose_event));
+ set_visible_window(false);
+}
+
+bool LogoArea::_on_expose_event(GdkEventExpose* event)
+{
+ if (draw_logo) {
+ int x = get_allocation().get_x();
+ int y = get_allocation().get_y();
+ int width = get_allocation().get_width();
+ int height = get_allocation().get_height();
+ int x_logo = x + (width - 220) / 2;
+ int y_logo = y + (height - 76) / 2;
+
+ Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
+
+ // Draw logo, we mask [read fill] it with the mid colour from the
+ // user's GTK theme
+ Gdk::Color logo_fill = get_style()->get_mid(get_state());
+
+ Gdk::Cairo::set_source_color(cr, logo_fill);
+ cr->mask(logo_mask, x_logo, y_logo);
+ }
+
+ return false;
+}
+
+SearchResultList::SearchResultList(guint columns_count) : ListViewText(columns_count)
+{
+ set_headers_visible(false);
+ set_column_title(RESULTS_COLUMN_MARKUP, _("Clipart found"));
+
+ Gtk::CellRenderer* cr_markup = get_column_cell_renderer(RESULTS_COLUMN_MARKUP);
+ cr_markup->set_property("ellipsize", Pango::ELLIPSIZE_END);
+ get_column(RESULTS_COLUMN_MARKUP)->clear_attributes(*cr_markup);
+ get_column(RESULTS_COLUMN_MARKUP)->add_attribute(*cr_markup,
+ "markup", RESULTS_COLUMN_MARKUP);
+
+ // Hide all columns except for the MARKUP column
+ for (int i = 0; i < RESULTS_COLUMN_LENGTH; i++) {
+ if (i != RESULTS_COLUMN_MARKUP) {
+ get_column(i)->set_visible(false);
}
- return -1;
}
}
-#endif
+void ImportDialog::on_list_results_selection_changed()
+{
+ std::vector<Gtk::TreeModel::Path> pathlist;
+ pathlist = list_results->get_selection()->get_selected_rows();
+ std::vector<int> posArray(1);
+
+ // If nothing is selected, then return
+ if (((int) pathlist.size()) < 1) {
+ return;
+ }
+ posArray = pathlist[0].get_indices();
+ int row = posArray[0];
+
+ Glib::ustring guid = list_results->get_text(row, RESULTS_COLUMN_GUID);
+
+ bool item_selected = (!guid.empty());
+ button_import->set_sensitive(item_selected);
+}
-/**
- * Callback for user input into searchTagEntry
+
+void ImportDialog::on_button_import_clicked() {
+ std::vector<Gtk::TreeModel::Path> pathlist;
+ pathlist = list_results->get_selection()->get_selected_rows();
+ std::vector<int> posArray(1);
+
+ // If nothing is selected, then return
+ if (((int) pathlist.size()) < 1) {
+ return;
+ }
+ posArray = pathlist[0].get_indices();
+ int row = posArray[0];
+
+ button_import->set_sensitive(false);
+ button_close->hide();
+ button_cancel->show();
+ widget_status->start_process(_("Downloading image..."));
+ download_resource(TYPE_IMAGE, row);
+}
+
+/*
+ * Callback for cursor change
*/
-void FileImportFromOCALDialog::searchTagEntryChangedCallback()
+void ImportDialog::on_list_results_cursor_changed()
{
- if (!searchTagEntry)
+ std::vector<Gtk::TreeModel::Path> pathlist;
+ pathlist = list_results->get_selection()->get_selected_rows();
+ std::vector<int> posArray(1);
+
+ // If nothing is selected, then return
+ if (((int) pathlist.size()) < 1) {
return;
+ }
+ posArray = pathlist[0].get_indices();
+ int row = posArray[0];
- notFoundLabel->hide();
- descriptionLabel->set_text("");
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ if (downloading_thumbnail) {
+ cancellable_thumbnail->cancel();
+ cancelled_thumbnail = true;
+ }
- Glib::ustring searchTag = searchTagEntry->get_text();
- // create the ocal uri to get rss feed
- Glib::ustring uri = "http://";
- uri.append(prefs->getString("/options/ocalurl/str"));
- uri.append("/media/feed/rss/");
- uri.append(searchTag);
- if (!Glib::get_charset()) //If we are not utf8
- uri = Glib::filename_to_utf8(uri);
+ update_preview(row);
+ downloading_thumbnail = true;
+ download_resource(TYPE_THUMBNAIL, row);
+}
+void ImportDialog::update_preview(int row)
+{
+ Glib::ustring description = list_results->get_text(row, RESULTS_COLUMN_DESCRIPTION);
+ Glib::ustring creator = list_results->get_text(row, RESULTS_COLUMN_CREATOR);
+ Glib::ustring date = list_results->get_text(row, RESULTS_COLUMN_DATE);
+
+ preview_files->clear();
+ preview_files->set_metadata(description, creator, date);
+}
-#ifdef WITH_GNOME_VFS
- // open the rss feed
- gnome_vfs_init();
- GnomeVFSHandle *from_handle = NULL;
- GnomeVFSResult result;
+std::string ImportDialog::get_temporary_dir(ResourceType type)
+{
+ std::string ocal_tmp_dir = Glib::build_filename(Glib::get_tmp_dir(),
+ "openclipart");
- result = gnome_vfs_open (&from_handle, uri.c_str(), GNOME_VFS_OPEN_READ);
- if (result != GNOME_VFS_OK) {
- sp_ui_error_dialog(_("Failed to receive the Open Clip Art Library RSS feed. Verify if the server name is correct in Configuration->Import/Export (e.g.: openclipart.org)"));
- return;
+ if (type == TYPE_THUMBNAIL) {
+ return Glib::build_filename(ocal_tmp_dir, "thumbnails");
+ } else {
+ return Glib::build_filename(ocal_tmp_dir, "images");
}
+}
- // create the resulting xml document tree
- // this initialize the library and test mistakes between compiled and shared library used
- LIBXML_TEST_VERSION
- xmlDoc *doc = NULL;
- xmlNode *root_element = NULL;
+void ImportDialog::create_temporary_dirs()
+{
+ // Make sure the temporary directories exists, if not, create them
+ std::string ocal_tmp_thumbnail_dir = get_temporary_dir(TYPE_THUMBNAIL);
+ std::string ocal_tmp_image_dir = get_temporary_dir(TYPE_IMAGE);
- doc = xmlReadIO ((xmlInputReadCallback) vfs_read_callback,
- (xmlInputCloseCallback) gnome_vfs_close, from_handle, uri.c_str(), NULL,
- XML_PARSE_RECOVER + XML_PARSE_NOWARNING + XML_PARSE_NOERROR);
- if (doc == NULL) {
- sp_ui_error_dialog(_("Server supplied malformed Clip Art feed"));
- g_warning("Failed to parse %s\n", uri.c_str());
+ if (!Glib::file_test(ocal_tmp_thumbnail_dir, Glib::FILE_TEST_EXISTS)) {
+ Glib::RefPtr<Gio::File> directory = Gio::File::create_for_path(ocal_tmp_thumbnail_dir);
+ directory->make_directory_with_parents();
+ }
+
+ if (!Glib::file_test(ocal_tmp_image_dir, Glib::FILE_TEST_EXISTS)) {
+ Glib::RefPtr<Gio::File> directory = Gio::File::create_for_path(ocal_tmp_image_dir);
+ directory->make_directory_with_parents();
+ }
+}
+
+void ImportDialog::download_resource(ResourceType type, int row)
+{
+ // Get Temporary Directory
+ std::string ocal_tmp_dir = get_temporary_dir(type);
+
+ // Make a unique filename for the clipart, in the form 'GUID.extension'
+ Glib::ustring guid = list_results->get_text(row, RESULTS_COLUMN_GUID);
+ Glib::ustring original_filename;
+
+ if (type == TYPE_IMAGE) {
+ original_filename = list_results->get_text(row, RESULTS_COLUMN_FILENAME);
+ } else {
+ original_filename = list_results->get_text(row, RESULTS_COLUMN_THUMBNAIL_FILENAME);
+ }
+ Glib::ustring extension = Inkscape::IO::get_file_extension(original_filename);
+
+ Glib::ustring filename = Glib::ustring::compose("%1%2", guid, extension);
+ std::string path = Glib::build_filename(ocal_tmp_dir, filename.c_str());
+ Glib::RefPtr<Gio::File> file_local = Gio::File::create_for_path(path);
+
+ // If the file has already been downloaded, use it
+ if (Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
+ if (type == TYPE_IMAGE) {
+ on_image_downloaded(path, true);
+ } else {
+ on_thumbnail_downloaded(path, true);
+ }
return;
}
- // get the root element node
- root_element = xmlDocGetRootElement(doc);
+ // Get Remote File URL and get the respective cancellable object
+ Glib::ustring url;
+ Glib::RefPtr<Gio::Cancellable> cancellable;
- // clear the fileslist
- filesList->clear_items();
- filesList->set_sensitive(false);
+ if (type == TYPE_IMAGE) {
+ url = list_results->get_text(row, RESULTS_COLUMN_URL);
+ cancellable_image = Gio::Cancellable::create();
+ cancellable = cancellable_image;
+ } else {
+ url = list_results->get_text(row, RESULTS_COLUMN_THUMBNAIL_URL);
+ cancellable_thumbnail = Gio::Cancellable::create();
+ cancellable = cancellable_thumbnail;
+ }
+
+ Glib::RefPtr<Gio::File> file_remote = Gio::File::create_for_uri(url);
+
+ // Download it asynchronously
+ file_remote->copy_async(file_local,
+ sigc::bind<Glib::RefPtr<Gio::File>, Glib::ustring, ResourceType>(
+ sigc::mem_fun(*this, &ImportDialog::on_resource_downloaded),
+ file_remote, path, type), cancellable,
+ Gio::FILE_COPY_OVERWRITE);
+}
- // print all xml the element names
- print_xml_element_names(root_element);
+void ImportDialog::on_resource_downloaded(const Glib::RefPtr<Gio::AsyncResult>& result,
+ Glib::RefPtr<Gio::File> file_remote, Glib::ustring path, ResourceType resource)
+{
+ bool success;
+
+ try {
+ success = file_remote->copy_finish(result);
+ } catch(Glib::Error) {
+ success = false;
+ }
- if (filesList->size() == 0)
- {
- notFoundLabel->show();
- filesList->set_sensitive(false);
+ if (resource == TYPE_IMAGE) {
+ on_image_downloaded(path, success);
+ } else {
+ on_thumbnail_downloaded(path, success);
}
- else
- filesList->set_sensitive(true);
+}
- // free the document
- xmlFreeDoc(doc);
- // free the global variables that may have been allocated by the parser
- xmlCleanupParser();
- return;
-#endif
+void ImportDialog::on_image_downloaded(Glib::ustring path, bool success)
+{
+ button_import->set_sensitive(true);
+ button_close->show();
+ button_cancel->hide();
+
+ // If anything went wrong, show an error message if the user didn't do it
+ if (!success && !cancelled_image) {
+ widget_status->set_error(_("Could not download image"));
+ }
+ if (!success) {
+ widget_status->clear();
+ return;
+ }
+
+ try {
+ widget_status->clear();
+ m_signal_response.emit(path);
+ widget_status->set_info(_("Clipart downloaded successfully"));
+ } catch(Glib::Error) {
+ success = false;
+ }
+
+ cancelled_image = false;
+}
+
+void ImportDialog::on_thumbnail_downloaded(Glib::ustring path, bool success)
+{
+ downloading_thumbnail = false;
+
+ // If anything went wrong, show an error message if the user didn't do it
+ if (!success && !cancelled_thumbnail) {
+ widget_status->set_error(_("Could not download thumbnail file"));
+ return;
+ }
+ if (!success) {
+ widget_status->clear();
+ return;
+ }
+
+ try {
+ widget_status->clear();
+ preview_files->set_image(path);
+ } catch(Glib::Error) {
+ success = false;
+ }
+
+ cancelled_thumbnail = false;
}
+/*
+ * Callback for row activated
+ */
+void ImportDialog::on_list_results_row_activated(const Gtk::TreeModel::Path& path,
+ Gtk::TreeViewColumn* column)
+{
+ on_list_results_cursor_changed();
+ button_import->signal_clicked();
+}
/**
* Prints the names of the all the xml elements
* that are siblings or children of a given xml node
*/
-void FileImportFromOCALDialog::print_xml_element_names(xmlNode * a_node)
+void SearchResultList::populate_from_xml(xmlNode * a_node)
{
-#ifdef WITH_GNOME_VFS
guint row_num = 0;
-#endif
+
for (xmlNode *cur_node = a_node; cur_node; cur_node = cur_node->next) {
- // get itens information
- if (strcmp((const char*)cur_node->name, "rss")) //avoid the root
+ // Get items information
+ if (strcmp((const char*)cur_node->name, "rss")) // Avoid the root
if (cur_node->type == XML_ELEMENT_NODE && !strcmp((const char*)cur_node->parent->name, "item"))
{
if (!strcmp((const char*)cur_node->name, "title"))
{
- xmlChar *title = xmlNodeGetContent(cur_node);
-#ifdef WITH_GNOME_VFS
- row_num =
-#endif
#if WITH_GTKMM_2_24
- filesList->append(reinterpret_cast<const char*>(title));
+ row_num = append("");
#else
- filesList->append_text(reinterpret_cast<const char*>(title));
+ row_num = append_text("");
#endif
+ xmlChar *xml_title = xmlNodeGetContent(cur_node);
+ char* title = (char*) xml_title;
+
+ set_text(row_num, RESULTS_COLUMN_TITLE, title);
xmlFree(title);
}
-#ifdef WITH_GNOME_VFS
- else if (!strcmp((const char*)cur_node->name, "enclosure"))
+ else if (!strcmp((const char*)cur_node->name, "pubDate"))
{
- xmlChar *urlattribute = xmlGetProp(cur_node, (xmlChar*)"url");
- filesList->set_text(row_num, 1, (const char*)urlattribute);
- gchar *tmp_file;
- tmp_file = gnome_vfs_uri_extract_short_path_name(gnome_vfs_uri_new((const char*)urlattribute));
- filesList->set_text(row_num, 2, (const char*)tmp_file);
- xmlFree(urlattribute);
+ xmlChar *xml_date = xmlNodeGetContent(cur_node);
+ char* date = (char*) xml_date;
+
+ set_text(row_num, RESULTS_COLUMN_DATE, date);
+ xmlFree(xml_date);
}
else if (!strcmp((const char*)cur_node->name, "creator"))
{
- filesList->set_text(row_num, 3, (const char*)xmlNodeGetContent(cur_node));
+ xmlChar *xml_creator = xmlNodeGetContent(cur_node);
+ char* creator = (char*) xml_creator;
+
+ set_text(row_num, RESULTS_COLUMN_CREATOR, creator);
+ xmlFree(xml_creator);
}
else if (!strcmp((const char*)cur_node->name, "description"))
{
- filesList->set_text(row_num, 4, (const char*)xmlNodeGetContent(cur_node));
+ xmlChar *xml_description = xmlNodeGetContent(cur_node);
+ //char* final_description;
+ char* stripped_description = g_strstrip((char*) xml_description);
+
+ if (!strcmp(stripped_description, "")) {
+ stripped_description = _("No description");
+ }
+
+ //GRegex* regex = g_regex_new(g_regex_escape_string(stripped_description, -1));
+ //final_description = g_regex_replace_literal(regex, "\n", -1, 0, " ");
+
+ set_text(row_num, RESULTS_COLUMN_DESCRIPTION, stripped_description);
+ xmlFree(xml_description);
+ }
+ else if (!strcmp((const char*)cur_node->name, "enclosure"))
+ {
+ xmlChar *xml_url = xmlGetProp(cur_node, (xmlChar*) "url");
+ char* url = (char*) xml_url;
+ char* filename = g_path_get_basename(url);
+
+ set_text(row_num, RESULTS_COLUMN_URL, url);
+ set_text(row_num, RESULTS_COLUMN_FILENAME, filename);
+ xmlFree(xml_url);
+ }
+ else if (!strcmp((const char*)cur_node->name, "thumbnail"))
+ {
+ xmlChar *xml_thumbnail_url = xmlGetProp(cur_node, (xmlChar*) "url");
+ char* thumbnail_url = (char*) xml_thumbnail_url;
+ char* thumbnail_filename = g_path_get_basename(thumbnail_url);
+
+ set_text(row_num, RESULTS_COLUMN_THUMBNAIL_URL, thumbnail_url);
+ set_text(row_num, RESULTS_COLUMN_THUMBNAIL_FILENAME, thumbnail_filename);
+ xmlFree(xml_thumbnail_url);
+ }
+ else if (!strcmp((const char*)cur_node->name, "guid"))
+ {
+ xmlChar *xml_guid = xmlNodeGetContent(cur_node);
+ char* guid_url = (char*) xml_guid;
+ char* guid = g_path_get_basename(guid_url);
+
+ set_text(row_num, RESULTS_COLUMN_GUID, guid);
+ xmlFree(xml_guid);
}
-#endif
}
- print_xml_element_names(cur_node->children);
+ populate_from_xml(cur_node->children);
}
}
/**
- * Constructor. Not called directly. Use the factory.
+ * Callback for user input into entry_search
*/
-FileImportFromOCALDialog::FileImportFromOCALDialog(Gtk::Window& parentWindow,
- const Glib::ustring &/*dir*/,
- FileDialogType fileTypes,
- const Glib::ustring &title) :
- FileDialogOCALBase(title, parentWindow)
+void ImportDialog::on_button_search_clicked()
{
- // Initalize to Autodetect
- extension = NULL;
- // No filename to start out with
- Glib::ustring searchTag = "";
+ on_entry_search_activated();
+}
- dialogType = fileTypes;
- Gtk::VBox *vbox = get_vbox();
- Gtk::Label *tagLabel = new Gtk::Label(_("Search for:"));
- notFoundLabel = new Gtk::Label(_("No files matched your search"));
- descriptionLabel = new Gtk::Label();
- descriptionLabel->set_max_width_chars(260);
- descriptionLabel->set_size_request(500, -1);
- descriptionLabel->set_single_line_mode(false);
- descriptionLabel->set_line_wrap(true);
- messageBox.pack_start(*notFoundLabel);
- descriptionBox.pack_start(*descriptionLabel);
- searchTagEntry = new Gtk::Entry();
- searchTagEntry->set_text(searchTag);
- searchTagEntry->set_max_length(255);
- searchButton = new Gtk::Button(_("Search"));
- tagBox.pack_start(*tagLabel);
- tagBox.pack_start(*searchTagEntry, Gtk::PACK_EXPAND_WIDGET, 3);
- tagBox.pack_start(*searchButton);
- filesPreview = new SVGPreview();
- filesPreview->showNoPreview();
- // add the buttons in the bottom of the dialog
- add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- okButton = add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
- // sets the okbutton to default
- set_default(*okButton);
- filesList = new FileListViewText(5, *filesPreview, *descriptionLabel, *okButton);
- filesList->set_sensitive(false);
- // add the listview inside a ScrolledWindow
- listScrolledWindow.add(*filesList);
- // only show the scrollbars when they are necessary:
- listScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
- filesList->set_column_title(0, _("Files found"));
- listScrolledWindow.set_size_request(400, 180);
- filesList->get_column(1)->set_visible(false); // file url
- filesList->get_column(2)->set_visible(false); // tmp file path
- filesList->get_column(3)->set_visible(false); // author dir
- filesList->get_column(4)->set_visible(false); // file description
- filesBox.pack_start(listScrolledWindow);
- filesBox.pack_start(*filesPreview);
- vbox->pack_start(tagBox, false, false);
- vbox->pack_start(messageBox);
- vbox->pack_start(filesBox);
- vbox->pack_start(descriptionBox);
+void ImportDialog::on_button_close_clicked()
+{
+ hide();
+}
- //Let's do some customization
- searchTagEntry = NULL;
- Gtk::Container *cont = get_toplevel();
- std::vector<Gtk::Entry *> entries;
- findEntryWidgets(cont, entries);
- if (entries.size() >=1 )
- {
- //Catch when user hits [return] on the text field
- searchTagEntry = entries[0];
- searchTagEntry->signal_activate().connect(
- sigc::mem_fun(*this, &FileImportFromOCALDialog::searchTagEntryChangedCallback));
+void ImportDialog::on_button_cancel_clicked()
+{
+ cancellable_image->cancel();
+ cancelled_image = true;
+}
+
+/**
+ * Callback for user input into entry_search
+ */
+void ImportDialog::on_entry_search_activated()
+{
+ preview_files->clear();
+ widget_status->start_process(_("Searching clipart..."));
+
+ notebook_content->set_current_page(NOTEBOOK_PAGE_LOGO);
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ Glib::ustring search_keywords = entry_search->get_text();
+
+ // Create the URI to the OCAL RSS feed
+ Glib::ustring xml_uri = Glib::ustring::compose("http://%1/media/feed/rss/%2",
+ prefs->getString("/options/ocalurl/str"), search_keywords);
+ // If we are not UTF8
+ if (!Glib::get_charset()) {
+ xml_uri = Glib::filename_to_utf8(xml_uri);
}
- searchButton->signal_clicked().connect(
- sigc::mem_fun(*this, &FileImportFromOCALDialog::searchTagEntryChangedCallback));
+ // Open the RSS feed
+ Glib::RefPtr<Gio::File> xml_file = Gio::File::create_for_uri(xml_uri);
+
+ xml_file->load_contents_async(
+ sigc::bind<Glib::RefPtr<Gio::File> , Glib::ustring>(
+ sigc::mem_fun(*this, &ImportDialog::on_xml_file_read),
+ xml_file, xml_uri)
+ );
+}
- show_all_children();
- notFoundLabel->hide();
+void ImportDialog::on_xml_file_read(const Glib::RefPtr<Gio::AsyncResult>& result,
+ Glib::RefPtr<Gio::File> xml_file, Glib::ustring xml_uri)
+{
+ widget_status->end_process();
+
+ char* data;
+ gsize length;
+
+ bool sucess = xml_file->load_contents_finish(result, data, length);
+ if (!sucess) {
+ widget_status->set_error(_("Could not connect to the Open Clip Art Library"));
+ return;
+ }
+
+ // Create the resulting xml document tree
+ // Initialize libxml and test mistakes between compiled and shared library used
+ LIBXML_TEST_VERSION
+ xmlDoc *doc = NULL;
+ xmlNode *root_element = NULL;
+
+ doc = xmlReadMemory(data, (int) length, xml_uri.c_str(), NULL,
+ XML_PARSE_RECOVER + XML_PARSE_NOWARNING + XML_PARSE_NOERROR);
+
+ if (doc == NULL) {
+ // If nothing is returned, no results could be found
+ if (length == 0) {
+ notebook_content->set_current_page(NOTEBOOK_PAGE_NOT_FOUND);
+ update_label_no_search_results();
+ } else {
+ widget_status->set_error(_("Could not parse search results"));
+ }
+ return;
+ }
+
+ // Get the root element node
+ root_element = xmlDocGetRootElement(doc);
+
+ // Clear and populate the list_results
+ list_results->clear_items();
+ list_results->populate_from_xml(root_element);
+
+ // Populate the MARKUP column with the title & description of the clipart
+ for (guint i = 0; i <= list_results->size() - 1; i++) {
+ Glib::ustring title = list_results->get_text(i, RESULTS_COLUMN_TITLE);
+ Glib::ustring description = list_results->get_text(i, RESULTS_COLUMN_DESCRIPTION);
+ char* markup = g_markup_printf_escaped("<b>%s</b>\n<span size=\"small\">%s</span>",
+ title.c_str(), description.c_str());
+ list_results->set_text(i, RESULTS_COLUMN_MARKUP, markup);
+ }
+ notebook_content->set_current_page(NOTEBOOK_PAGE_RESULTS);
+
+ // free the document
+ xmlFreeDoc(doc);
+ // free the global variables that may have been allocated by the parser
+ xmlCleanupParser();
+}
+
+
+void ImportDialog::update_label_no_search_results()
+{
+ Glib::ustring keywords = Glib::Markup::escape_text(entry_search->get_text());
+ Gdk::Color grey = entry_search->get_style()->get_text_aa(entry_search->get_state());
+
+ Glib::ustring markup = Glib::ustring::compose(
+ "<span size=\"large\">%1 <b>%2</b> %3</span>\n<span color=\"%4\">%5</span>",
+ _("No clipart named"), keywords, _("was found."), grey.to_string(),
+ _("Please make sure all keywords are spelled correctly, or try again with different keywords."));
+
+ label_not_found->set_markup(markup);
}
/**
- * Destructor
+ * Constructor. Not called directly. Use the factory.
*/
-FileImportFromOCALDialog::~FileImportFromOCALDialog()
+ImportDialog::ImportDialog(Gtk::Window& parent_window, FileDialogType file_types,
+ const Glib::ustring &title) :
+ FileDialogBase(title, parent_window)
{
+ // Initalize to Autodetect
+ extension = NULL;
+ // No filename to start out with
+ Glib::ustring search_keywords = "";
+
+ dialogType = file_types;
+
+ // Creation
+ Gtk::VBox *vbox = new Gtk::VBox(false, 0);
+ Gtk::HButtonBox *hbuttonbox_bottom = new Gtk::HButtonBox();
+ Gtk::HBox *hbox_bottom = new Gtk::HBox(false, 12);
+ BaseBox *basebox_logo = new BaseBox();
+ BaseBox *basebox_no_search_results = new BaseBox();
+ label_not_found = new Gtk::Label();
+ label_description = new Gtk::Label();
+ entry_search = new SearchEntry();
+ button_search = new Gtk::Button(_("Search"));
+ Gtk::HButtonBox* hbuttonbox_search = new Gtk::HButtonBox();
+ Gtk::ScrolledWindow* scrolledwindow_preview = new Gtk::ScrolledWindow();
+ preview_files = new PreviewWidget();
+ /// Add the buttons in the bottom of the dialog
+ button_cancel = new Gtk::Button(Gtk::Stock::CANCEL);
+ button_close = new Gtk::Button(_("Close"));
+ button_import = new Gtk::Button(_("Import"));
+ list_results = new SearchResultList(RESULTS_COLUMN_LENGTH);
+ drawingarea_logo = new LogoArea();
+ notebook_content = new Gtk::Notebook();
+ widget_status = new StatusWidget();
+
+ downloading_thumbnail = false;
+ cancelled_thumbnail = false;
+ cancelled_image = false;
+
+ // Packing
+ add(*vbox);
+ vbox->pack_start(hbox_tags, false, false);
+ vbox->pack_start(hbox_files, true, true);
+ vbox->pack_start(*hbox_bottom, false, false);
+ basebox_logo->add(*drawingarea_logo);
+ basebox_no_search_results->add(*label_not_found);
+ hbox_bottom->pack_start(*widget_status, true, true);
+ hbox_bottom->pack_start(*hbuttonbox_bottom, true, true);
+ hbuttonbox_bottom->pack_start(*button_cancel, false, false);
+ hbuttonbox_bottom->pack_start(*button_close, false, false);
+ hbuttonbox_bottom->pack_start(*button_import, false, false);
+ hbuttonbox_search->pack_start(*button_search, false, false);
+ hbox_tags.pack_start(*entry_search, true, true);
+ hbox_tags.pack_start(*hbuttonbox_search, false, false);
+ hbox_files.pack_start(*notebook_content, true, true);
+ scrolledwindow_preview->add(*preview_files);
+ hbox_files.pack_start(*scrolledwindow_preview, true, true);
+
+ notebook_content->insert_page(*basebox_logo, NOTEBOOK_PAGE_LOGO);
+ notebook_content->insert_page(scrolledwindow_list, NOTEBOOK_PAGE_RESULTS);
+ notebook_content->insert_page(*basebox_no_search_results, NOTEBOOK_PAGE_NOT_FOUND);
+
+ // Properties
+ set_border_width(12);
+ set_default_size(480, 330);
+ vbox->set_spacing(12);
+ hbuttonbox_bottom->set_spacing(6);
+ hbuttonbox_bottom->set_layout(Gtk::BUTTONBOX_END);
+ button_import->set_sensitive(false);
+ entry_search->set_max_length(255);
+ hbox_tags.set_spacing(6);
+ preview_files->clear();
+ notebook_content->set_current_page(NOTEBOOK_PAGE_LOGO);
+ /// Add the listview inside a ScrolledWindow
+ scrolledwindow_list.add(*list_results);
+ scrolledwindow_list.set_shadow_type(Gtk::SHADOW_IN);
+ /// Only show the scrollbars when they are necessary
+ scrolledwindow_list.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+ preview_files->set_size_request(120, -1);
+ hbox_files.set_spacing(12);
+ label_not_found->set_line_wrap(true);
+ label_not_found->set_line_wrap_mode(Pango::WRAP_WORD);
+ label_not_found->set_justify(Gtk::JUSTIFY_CENTER);
+ label_not_found->set_size_request(260, -1);
+ scrolledwindow_preview->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+ notebook_content->set_show_tabs(false);
+ notebook_content->set_show_border(false);
+ button_cancel->set_no_show_all(true);
+ button_close->set_no_show_all(true);
+ button_close->show();
+ button_cancel->hide();
+
+ // Signals
+ entry_search->signal_activate().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_entry_search_activated));
+ button_import->signal_clicked().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_button_import_clicked));
+ button_close->signal_clicked().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_button_close_clicked));
+ button_cancel->signal_clicked().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_button_cancel_clicked));
+ button_search->signal_clicked().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_button_search_clicked));
+ list_results->signal_cursor_changed().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_list_results_cursor_changed));
+ list_results->signal_row_activated().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_list_results_row_activated));
+ list_results->get_selection()->signal_changed().connect(
+ sigc::mem_fun(*this, &ImportDialog::on_list_results_selection_changed));
+ show_all_children();
+ entry_search->grab_focus();
+
+ // Create the temporary directories that will be needed later
+ create_temporary_dirs();
}
/**
- * Show this dialog modally. Return true if user hits [OK]
+ * Destructor
*/
-bool
-FileImportFromOCALDialog::show()
+ImportDialog::~ImportDialog()
{
- set_modal (TRUE); //Window
- sp_transientize((GtkWidget *)gobj()); //Make transient
- gint b = run(); //Dialog
- hide();
- if (b == Gtk::RESPONSE_OK)
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
}
-
/**
* Get the file extension type that was selected by the user. Valid after an [OK]
*/
Inkscape::Extension::Extension *
-FileImportFromOCALDialog::getSelectionType()
+ImportDialog::get_selection_type()
{
return extension;
}
-
-/**
- * Get the file name chosen by the user. Valid after an [OK]
- */
-Glib::ustring
-FileImportFromOCALDialog::getFilename (void)
+ImportDialog::type_signal_response ImportDialog::signal_response()
{
- return filesList->getFilename();
+ return m_signal_response;
}
+} //namespace OCAL
} //namespace Dialog
} //namespace UI
} //namespace Inkscape
-
-
/*
Local Variables:
mode:c++
diff --git a/src/ui/dialog/ocaldialogs.h b/src/ui/dialog/ocaldialogs.h
index 3679e6acb..5d4ac43ad 100644
--- a/src/ui/dialog/ocaldialogs.h
+++ b/src/ui/dialog/ocaldialogs.h
@@ -4,6 +4,7 @@
/* Authors:
* Bruno Dilly <bruno.dilly@gmail.com>
* Inkscape Guys
+ * Andrew Higginson
*
* Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -12,28 +13,26 @@
#ifndef __OCAL_DIALOG_H__
#define __OCAL_DIALOG_H__
-//General includes
-#include <libxml/tree.h>
-
//Gtk includes
-#include <gtkmm/dialog.h>
+#include <gtkmm/box.h>
+#include <gtkmm/eventbox.h>
#include <gtkmm/listviewtext.h>
#include <gtkmm/scrolledwindow.h>
-
-//Temporary ugly hack
-//Remove this after the get_filter() calls in
-//show() on both classes are fixed
-#include <gtk/gtk.h>
-
-//Another hack
-#ifdef WITH_GNOME_VFS
-#include <libgnomevfs/gnome-vfs-init.h> // gnome_vfs_initialized
-#include<libgnomevfs/gnome-vfs.h>
-#endif
+#include <gtkmm/window.h>
+#include <giomm/file.h>
//Inkscape includes
#include "ui/dialog/filedialog.h"
+#include <dialogs/dialog-events.h>
+
+struct _xmlNode;
+typedef _xmlNode xmlNode;
+
+namespace Gtk {
+class Notebook;
+class Spinner;
+}
namespace Inkscape
{
@@ -44,6 +43,8 @@ namespace Dialog
class SVGPreview;
+namespace OCAL
+{
/*#########################################################################
### F I L E D I A L O G O C A L B A S E C L A S S
#########################################################################*/
@@ -51,20 +52,32 @@ class SVGPreview;
/**
* This class is the base implementation for export to OCAL.
*/
-class FileDialogOCALBase : public Gtk::Dialog
+class FileDialogBase : public Gtk::Window
{
public:
/**
* Constructor
*/
- FileDialogOCALBase(const Glib::ustring &title, Gtk::Window& parent) : Gtk::Dialog(title, parent, true)
- {}
+ FileDialogBase(const Glib::ustring &title, Gtk::Window& parent) : Gtk::Window(Gtk::WINDOW_TOPLEVEL)
+ {
+ set_title(title);
+ sp_transientize((GtkWidget*) gobj());
+
+ // Allow shrinking of window so labels wrap correctly
+ set_resizable(true);
+
+ Gdk::Geometry geom;
+ geom.min_width = 480;
+ geom.min_height = 320;
+
+ set_geometry_hints(*this, geom, Gdk::HINT_MIN_SIZE);
+ }
/*
* Destructor
*/
- virtual ~FileDialogOCALBase()
+ virtual ~FileDialogBase()
{}
protected:
@@ -85,10 +98,10 @@ protected:
/**
- * Our implementation of the FileExportToOCALDialog interface.
+ * Our implementation of the ExportDialog interface.
*/
/*
-class FileExportToOCALDialog : public FileDialogOCALBase
+class ExportDialog : public FileDialogBase
{
public:
@@ -100,7 +113,7 @@ public:
* @param key a list of file types from which the user can select
*/
/*
- FileExportToOCALDialog(Gtk::Window& parentWindow,
+ ExportDialog(Gtk::Window& parentWindow,
FileDialogType fileTypes,
const Glib::ustring &title);
*/
@@ -109,7 +122,7 @@ public:
* Perform any necessary cleanups.
*/
/*
- ~FileExportToOCALDialog();
+ ~ExportDialog();
*/
/**
* Show an SaveAs file selector.
@@ -165,7 +178,7 @@ private:
/*
std::set<Glib::ustring> knownExtensions;
-}; //FileExportToOCAL
+}; //ExportDialog
*/
//########################################################################
@@ -174,10 +187,10 @@ private:
/**
- * Our implementation of the FileExportToOCALPasswordDialog interface.
+ * Our implementation of the ExportPasswordDialog interface.
*/
/*
-class FileExportToOCALPasswordDialog : public FileDialogOCALBase
+class ExportPasswordDialog : public FileDialogBase
{
public:
@@ -187,7 +200,7 @@ public:
* @param title the title of the dialog
*/
/*
- FileExportToOCALPasswordDialog(Gtk::Window& parentWindow,
+ ExportPasswordDialog(Gtk::Window& parentWindow,
const Glib::ustring &title);
*/
/**
@@ -195,7 +208,7 @@ public:
* Perform any necessary cleanups.
*/
/*
- ~FileExportToOCALPasswordDialog();
+ ~ExportPasswordDialog();
*/
/**
@@ -230,7 +243,7 @@ private:
Gtk::HBox userBox;
Gtk::HBox passBox;
-}; //FileExportToOCALPassword
+}; //ExportPasswordDialog
*/
@@ -238,34 +251,147 @@ private:
//### F I L E I M P O R T F R O M O C A L
//#########################################################################
+class WrapLabel : public Gtk::Label
+{
+public:
+ WrapLabel();
+
+private:
+ void _on_size_allocate(Gtk::Allocation& allocation);
+};
+
+class LoadingBox : public Gtk::EventBox
+{
+public:
+ LoadingBox();
+
+ void start();
+ void stop();
+
+private:
+ unsigned int spinner_step;
+ sigc::connection timeout;
+ bool draw_spinner;
+ bool _on_expose_event(GdkEventExpose* event);
+ bool on_timeout();
+};
+
+class PreviewWidget : public Gtk::VBox
+{
+public:
+ PreviewWidget();
+
+ void set_metadata(Glib::ustring description, Glib::ustring creator, Glib::ustring time);
+ void show_box_loading();
+ void hide_box_loading();
+ void set_image(std::string path);
+ void clear();
+ bool _on_expose_event(GdkEventExpose* event);
+
+private:
+ LoadingBox* box_loading;
+ Gtk::Image* image;
+
+ WrapLabel* label_title;
+ WrapLabel* label_description;
+ WrapLabel* label_time;
+};
+
/**
- * Our implementation class for filesListView
+ * A Widget that contains an status icon and a message
*/
-class FileListViewText : public Gtk::ListViewText
+class StatusWidget : public Gtk::HBox
{
public:
- FileListViewText(guint columns_count, SVGPreview& filesPreview, Gtk::Label& description, Gtk::Button& okButton)
- :ListViewText(columns_count)
- {
- myPreview = &filesPreview;
- myLabel = &description;
- myButton = &okButton;
- }
- Glib::ustring getFilename();
-protected:
- void on_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);
- void on_cursor_changed();
+ StatusWidget();
+
+ void clear();
+ void set_error(Glib::ustring text);
+ void set_info(Glib::ustring text);
+ void start_process(Glib::ustring text);
+ void end_process();
+
+ Gtk::Spinner* spinner;
+ Gtk::Image* image;
+ Gtk::Label* label;
+};
+
+/**
+ * A Gtk::Entry with search & clear icons
+ */
+class SearchEntry : public Gtk::Entry
+{
+public:
+ SearchEntry();
+
private:
- Glib::ustring myFilename;
- SVGPreview *myPreview;
- Gtk::Label *myLabel;
- Gtk::Button *myButton;
+ void _on_icon_pressed(Gtk::EntryIconPosition icon_position, const GdkEventButton* event);
+ void _on_changed();
+};
+
+/**
+ * A box which paints an overlay of the OCAL logo
+ */
+class LogoArea : public Gtk::EventBox
+{
+public:
+ LogoArea();
+private:
+ bool _on_expose_event(GdkEventExpose* event);
+ bool draw_logo;
+ Cairo::RefPtr<Cairo::ImageSurface> logo_mask;
+};
+
+/**
+ * A box filled with the Base colour from the user's GTK theme, and a border
+ */
+class BaseBox : public Gtk::EventBox
+{
+public:
+ BaseBox();
+private:
+ bool _on_expose_event(GdkEventExpose* event);
+};
+
+enum {
+ RESULTS_COLUMN_MARKUP,
+ RESULTS_COLUMN_TITLE,
+ RESULTS_COLUMN_DESCRIPTION,
+ RESULTS_COLUMN_CREATOR,
+ RESULTS_COLUMN_DATE,
+ RESULTS_COLUMN_FILENAME,
+ RESULTS_COLUMN_THUMBNAIL_FILENAME,
+ RESULTS_COLUMN_URL,
+ RESULTS_COLUMN_THUMBNAIL_URL,
+ RESULTS_COLUMN_GUID,
+ RESULTS_COLUMN_LENGTH,
+};
+
+enum {
+ NOTEBOOK_PAGE_LOGO,
+ NOTEBOOK_PAGE_RESULTS,
+ NOTEBOOK_PAGE_NOT_FOUND,
+};
+
+enum ResourceType {
+ TYPE_THUMBNAIL,
+ TYPE_IMAGE,
};
/**
- * Our implementation class for the FileImportFromOCALDialog interface..
+ * The TreeView which holds the search results
*/
-class FileImportFromOCALDialog : public FileDialogOCALBase
+class SearchResultList : public Gtk::ListViewText
+{
+public:
+ SearchResultList(guint columns_count);
+ void populate_from_xml(xmlNode* a_node);
+};
+
+/**
+ * The Import Dialog
+ */
+class ImportDialog : public FileDialogBase
{
public:
/**
@@ -274,16 +400,14 @@ public:
* @param fileTypes one of FileDialogTypes
* @param title the title of the dialog
*/
- FileImportFromOCALDialog(Gtk::Window& parentWindow,
- const Glib::ustring &dir,
- FileDialogType fileTypes,
- const Glib::ustring &title);
+ ImportDialog(Gtk::Window& parent_window, FileDialogType file_types,
+ const Glib::ustring &title);
/**
* Destructor.
* Perform any necessary cleanups.
*/
- ~FileImportFromOCALDialog();
+ ~ImportDialog();
/**
* Show an OpenFile file selector.
@@ -296,51 +420,73 @@ public:
* @return a pointer to a string if successful (which must
* be later freed with g_free(), else NULL.
*/
- Inkscape::Extension::Extension *getSelectionType();
-
- Glib::ustring getFilename();
+ Inkscape::Extension::Extension *get_selection_type();
+
+ typedef sigc::signal<void, Glib::ustring> type_signal_response;
+ type_signal_response signal_response();
+
+protected:
+ type_signal_response m_signal_response;
private:
-
- /**
- * Allow the user to type the tag to be searched
- */
- Gtk::Entry *searchTagEntry;
- FileListViewText *filesList;
- SVGPreview *filesPreview;
- Gtk::Label *notFoundLabel;
- Gtk::Label *descriptionLabel;
- Gtk::Button *searchButton;
- Gtk::Button *okButton;
+ Glib::ustring filename_image;
+ Glib::ustring filename_thumbnail;
+ SearchEntry *entry_search;
+ LogoArea *drawingarea_logo;
+ SearchResultList *list_results;
+ PreviewWidget *preview_files;
+ Gtk::Label *label_not_found;
+ Gtk::Label *label_description;
+ Gtk::Button *button_search;
+ Gtk::Button *button_import;
+ Gtk::Button *button_close;
+ Gtk::Button *button_cancel;
+ StatusWidget *widget_status;
// Child widgets
- Gtk::HBox tagBox;
- Gtk::HBox filesBox;
- Gtk::HBox messageBox;
- Gtk::HBox descriptionBox;
- Gtk::ScrolledWindow listScrolledWindow;
+ Gtk::Notebook *notebook_content;
+ Gtk::HBox hbox_tags;
+ Gtk::HBox hbox_files;
+ Gtk::ScrolledWindow scrolledwindow_list;
Glib::RefPtr<Gtk::TreeSelection> selection;
- /**
- * Callback for user input into searchTagEntry
- */
- void searchTagEntryChangedCallback();
+ Glib::RefPtr<Gio::Cancellable> cancellable_image;
+ Glib::RefPtr<Gio::Cancellable> cancellable_thumbnail;
+ bool downloading_thumbnail;
+ bool cancelled_thumbnail;
+ bool cancelled_image;
+ void update_label_no_search_results();
+ void update_preview(int row);
+ void on_list_results_cursor_changed();
+
+ void download_resource(ResourceType type, int row);
+ void on_resource_downloaded(const Glib::RefPtr<Gio::AsyncResult>& result,
+ Glib::RefPtr<Gio::File> file_remote, Glib::ustring path, ResourceType resource);
+ void on_image_downloaded(Glib::ustring path, bool success);
+ void on_thumbnail_downloaded(Glib::ustring path, bool success);
+ void on_list_results_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);
+ void on_button_import_clicked();
+ void on_button_close_clicked();
+ void on_button_cancel_clicked();
+ void on_button_search_clicked();
+ void on_entry_search_activated();
+ void on_list_results_selection_changed();
+ void on_xml_file_read(const Glib::RefPtr<Gio::AsyncResult>& result,
+ Glib::RefPtr<Gio::File> xml_file, Glib::ustring xml_uri);
+ void create_temporary_dirs();
+ std::string get_temporary_dir(ResourceType type);
- /**
- * Prints the names of the all the xml elements
- * that are siblings or children of a given xml node
- */
- void print_xml_element_names(xmlNode * a_node);
/**
* The extension to use to write this file
*/
Inkscape::Extension::Extension *extension;
-}; //FileImportFromOCALDialog
+}; //ImportDialog
+} //namespace OCAL
} //namespace Dialog
} //namespace UI
} //namespace Inkscape