Merge lp:~and471/inkscape/ocal-dialog-improvements into lp:~inkscape.dev/inkscape/trunk

Proposed by jazzynico
Status: Merged
Merged at revision: 11027
Proposed branch: lp:~and471/inkscape/ocal-dialog-improvements
Merge into: lp:~inkscape.dev/inkscape/trunk
Diff against target: 2095 lines (+1171/-481)
9 files modified
share/icons/Makefile.am (+2/-1)
src/file.cpp (+28/-45)
src/file.h (+6/-0)
src/io/sys.cpp (+9/-0)
src/io/sys.h (+2/-0)
src/menus-skeleton.h (+0/-2)
src/ui/dialog/ocaldialogs.cpp (+892/-350)
src/ui/dialog/ocaldialogs.h (+229/-81)
src/verbs.cpp (+3/-2)
To merge this branch: bzr merge lp:~and471/inkscape/ocal-dialog-improvements
Reviewer Review Type Date Requested Status
Alex Valavanis Approve
Andrew (community) Needs Resubmitting
jazzynico (community) Needs Fixing
Review via email: mp+56234@code.launchpad.net
To post a comment you must log in.
Revision history for this message
jazzynico (jazzynico) wrote :
Download full text (3.3 KiB)

Patched and compiled with no problem on Ubuntu 10.10 with the current trunk (10145).
Seems to work very well. Nice dialog design, image search is rather fast and download time very short compared to the older (current...) implementation. I really like it!

But a crasher, when selecting an image in the result list while another one is still downloading. Backtrace:

-----
Program received signal SIGSEGV, Segmentation fault.
0x007b6545 in Gio::Cancellable::is_cancelled() const () from /usr/lib/libgiomm-2.4.so.1
(gdb) bt
#0 0x007b6545 in Gio::Cancellable::is_cancelled() const () from /usr/lib/libgiomm-2.4.so.1
#1 0x08639326 in Inkscape::UI::Dialog::OCAL::ImportDialog::on_thumbnail_downloaded (this=0xa9edc10, path=..., success=false)
    at ui/dialog/ocaldialogs.cpp:822
#2 0x08639411 in Inkscape::UI::Dialog::OCAL::ImportDialog::on_resource_downloaded (this=0xa9edc10, result=..., file_remote=..., path=...,
    resource=Inkscape::UI::Dialog::OCAL::TYPE_THUMBNAIL) at ui/dialog/ocaldialogs.cpp:788
#3 0x08640a4d in operator() (rep=0xaa097c0, a_1=...) at /usr/include/sigc++-2.0/sigc++/functors/mem_fun.h:2055
#4 operator()<Glib::RefPtr<Gio::AsyncResult>&, Glib::RefPtr<Gio::File>&, Glib::ustring&, Inkscape::UI::Dialog::OCAL::ResourceType&> (rep=0xaa097c0,
    a_1=...) at /usr/include/sigc++-2.0/sigc++/adaptors/adaptor_trait.h:144
#5 operator()<Glib::RefPtr<Gio::AsyncResult>&> (rep=0xaa097c0, a_1=...) at /usr/include/sigc++-2.0/sigc++/adaptors/bind.h:1523
#6 sigc::internal::slot_call1<sigc::bind_functor<-0x00000000000000001, sigc::bound_mem_functor4<void, Inkscape::UI::Dialog::OCAL::ImportDialog, Glib::RefPtr<Gio::AsyncResult> const&, Glib::RefPtr<Gio::File>, Glib::ustring, Inkscape::UI::Dialog::OCAL::ResourceType>, Glib::RefPtr<Gio::File>, Glib::ustring, Inkscape::UI::Dialog::OCAL::ResourceType, sigc::nil, sigc::nil, sigc::nil, sigc::nil>, void, Glib::RefPtr<Gio::AsyncResult>&>::call_it (rep=0xaa097c0, a_1=...)
    at /usr/include/sigc++-2.0/sigc++/functors/slot.h:137
#7 0x007ffa01 in Gio::SignalProxy_async_callback(_GObject*, _GAsyncResult*, void*) () from /usr/lib/libgiomm-2.4.so.1
#8 0x00d1857f in g_simple_async_result_complete (simple=0xaa3bc18) at /build/buildd/glib2.0-2.26.1/gio/gsimpleasyncresult.c:692
#9 0x00d185ed in complete_in_idle_cb (data=0xaa3bc18) at /build/buildd/glib2.0-2.26.1/gio/gsimpleasyncresult.c:702
#10 0x01d3e841 in g_idle_dispatch (source=0xa9dcf68, callback=0, user_data=0xaa3bc18) at /build/buildd/glib2.0-2.26.1/glib/gmain.c:4254
#11 0x01d40855 in g_main_dispatch (context=0x8c7e7e8) at /build/buildd/glib2.0-2.26.1/glib/gmain.c:2149
#12 g_main_context_dispatch (context=0x8c7e7e8) at /build/buildd/glib2.0-2.26.1/glib/gmain.c:2702
#13 0x01d44668 in g_main_context_iterate (context=0x8c7e7e8, block=<value optimised out>, dispatch=1, self=0x8c2c9b8)
    at /build/buildd/glib2.0-2.26.1/glib/gmain.c:2780
#14 0x01d44ba7 in g_main_loop_run (loop=0x994a330) at /build/buildd/glib2.0-2.26.1/glib/gmain.c:2988
#15 0x00a051d9 in IA__gtk_main () at /build/buildd/gtk+2.0-2.22.0/gtk/gtkmain.c:1237
#16 0x005593b7 in Gtk::Main::run_impl() () from /usr/lib/libgtkmm-2.4.so.1
#17 0x005591b2 in Gtk::Main::run() () from /usr/lib/libgtkmm-2.4.s...

Read more...

review: Needs Fixing
Revision history for this message
su_v (suv-lp) wrote :

Testing the branch on OS X 10.5.8 (i386), I get this error when trying to search:

(inkscape:54403): glibmm-CRITICAL **:
unhandled exception (type Glib::Error) in signal handler:
domain: g-io-error-quark
code : 15
what : Operation not supported

Dependencies:
  glib2 @2.28.4_0 (active)
  glibmm @2.24.2_0 (active)
  gtk2 @2.24.3_0+x11 (active)
  gtkmm @2.22.0_1 (active)

Revision history for this message
su_v (suv-lp) wrote :

Clarification: on OS X 10.5.8, the dialog is not functional (no search). Do I need to install additional dependencies, or are there other configure options needed for either Inkscape or the external libraries?

Revision history for this message
Andrew (and471) wrote :

> Clarification: on OS X 10.5.8, the dialog is not functional (no search). Do I
> need to install additional dependencies, or are there other configure options
> needed for either Inkscape or the external libraries?

I am not entirely sure. The new dialog uses GIO for its file handling stuff, that is what you see in the message, and the only operations it uses are copy and load_contents.

Revision history for this message
Andrew (and471) wrote :

Possibly you need GVFS (for remote file stuff)? That is the only other thing I can think of

Revision history for this message
jazzynico (jazzynico) wrote :

On Windows XP, I get some make errors:

-----
src/ui/dialog/ocaldialogs.h:82: warning: unused parameter 'parent'
src/ui/dialog/ocaldialogs.h:292: error: 'uint' does not name a type
src/ui/dialog/ocaldialogs.h:334: error: ISO C++ forbids declaration of 'Spinner' with no type
src/ui/dialog/ocaldialogs.h:334: error: invalid use of '::'
src/ui/dialog/ocaldialogs.h:334: error: expected ';' before '*' token
-----

Note that Gtk::Spinner is not available in the current Windows devlibs (gtk 2.18...).

review: Needs Fixing
Revision history for this message
jazzynico (jazzynico) wrote :

With the spinner related code commented out, uint (ocaldialogs.h:292) replaced with unsigned int and the OCAL import menu entry uncommented in menus-skeleton.h, it compiles correctly on Windows XP. More tests later...

Revision history for this message
su_v (suv-lp) wrote :

> Possibly you need GVFS (for remote file stuff)?
> That is the only other thing I can think of

I did not uninstall gvfs (1.6.6) as I need it for the regular builds of lp:inkscape (and it does get linked to inkscape if present).

Could it be related to having gconf configured/installed with '--disable-defaults-service' (i.e. no policykit installed)? This is specific to my local setup/build environment - otherwise I can't install the required dependencies (everything that depends on gconf in MacPorts) without having made system-wide changes as root (for policykit) (which I avoid, as long as possible, to still have a system comparable to the 'normal' user on Mac OS X).

Possibly using Gio requires additional configuration on Mac OS X (maybe Michael can investigate, once the branch has been merged into trunk), or I definitely have to give up on avoiding to install additional (gnome or glib/gtk2-based) system-wide services as root - I'm wondering though how that will impact packaging as osxapp.

Revision history for this message
su_v (suv-lp) wrote :

Correction (I do have gnome-vfs installed, not gvfs):

- gvfs (1.6.6)
+ gnome-vfs @2.24.4_0

Revision history for this message
jazzynico (jazzynico) wrote :

Good news, it works on Windows XP (conditions mentioned earlier...). Without the spinner, but at least I can search an import images.

Revision history for this message
Andrew (and471) wrote :

On 5 April 2011 11:37, ~suv <email address hidden> wrote:
> Correction (I do have gnome-vfs installed, not gvfs):
>
> - gvfs (1.6.6)
> + gnome-vfs @2.24.4_0
> --
> https://code.launchpad.net/~and471/inkscape/ocal-dialog-improvements/+merge/56234
> You are the owner of lp:~and471/inkscape/ocal-dialog-improvements.
>

Ah, they are not the same though. GNOMEVFS is depreciated and has just
been removed.

--
Andrew

Revision history for this message
Jon A. Cruz (jon-joncruz) wrote :

On Apr 5, 2011, at 7:39 AM, Andrew wrote:

> On 5 April 2011 11:37, ~suv <email address hidden> wrote:
>> Correction (I do have gnome-vfs installed, not gvfs):
>>
>> - gvfs (1.6.6)
>> + gnome-vfs @2.24.4_0
>> --
>> https://code.launchpad.net/~and471/inkscape/ocal-dialog-improvements/+merge/56234
>> You are the owner of lp:~and471/inkscape/ocal-dialog-improvements.
>>
>
> Ah, they are not the same though. GNOMEVFS is depreciated and has just
> been removed.

We probably need to note and track that dependency

http://wiki.inkscape.org/wiki/index.php/Tracking_Dependencies#Functions_Used

http://wiki.inkscape.org/wiki/index.php/Tracking_Dependencies#Distros

Revision history for this message
su_v (suv-lp) wrote :

> Possibly you need GVFS (for remote file stuff)?

Are you sure about gvfs as required dependency? It is not part of the Windows devlibs either [1], only libgsf (which I already had installed from the beginning).

From the README of gvfs:

<quote>
gvfs is a userspace virtual filesystem designed to work with the i/o
abstractions of gio (a library availible in glib >= 2.15.1). It
installs several modules that are automatically used by applications
using the APIs of libgio. There is also fuse support that allows
applications not using gio to access the gvfs filesystems.

The gvfs model differs from e.g. gnome-vfs in that filesystems must
be mounted before they are used. There is a central daemon (gvfsd)
that handles coordinting mounts, and then each mount is (typically)
in its own daemon process (although mounts can share daemon process).

</quote>

I did try and installed gvfs (without gnome support, because I don't run gnome), and rebuilt your branch - with no improvement: same error as before.

(with regard to gvfs (gnome-vfs): note that I don't have the daemon running. Also, it seems an odd dependency to me for the ocal dialog because the README mainly talks about mounting a file system before using it... we don't mount the ocal site, do we?)

[1] <http://bazaar.launchpad.net/~inkscape.dev/inkscape-devlibs/trunk/view/head:/readme.txt>

Revision history for this message
Andrew (and471) wrote :

I am not sure about this, can anyone else shed some light on it?

Revision history for this message
Andrew (and471) wrote :

Related to OSX:
  After speaking with su-v on IRC, I was able to find out that the issue was with the load_contents_async method, however something like copy_async still works. Therefore I will continue to look at this.

Revision history for this message
su_v (suv-lp) wrote :

JFTR (since it briefly came up on #inkscape): today glibmm was updated in MacPorts to 2.28.0 (from 2.24.2). I rebuilt the ocal-dialog-improvements branch, but still get the same error.

Revision history for this message
su_v (suv-lp) wrote :

As was reported on #inkscape: 'src/menus-skeleton.h' still checks for gnome-vfs as requirement for the OCAL import dialog (#ifdef WITH_GNOME_VFS). As far as I understand, one of the goals for the refactoring is to remove the dependency on gnome-vfs?

Revision history for this message
Splex (splex) wrote :

Yes, please remove the gnome dependency.

I just tried building inkscape with this diff applied, and get the following errors:

ui/dialog/ocaldialogs.cpp: In member function ‘bool Inkscape::UI::Dialog::OCAL::LoadingBox::_on_expose_event(GdkEventExpose*)’:
ui/dialog/ocaldialogs.cpp:317:49: error: cannot call constructor ‘Glib::ustring::ustring’ directly
ui/dialog/ocaldialogs.cpp:317:49: error: for a function-style cast, remove the redundant ‘::ustring’
ui/dialog/ocaldialogs.cpp: In member function ‘void Inkscape::UI::Dialog::OCAL::LoadingBox::start()’:
ui/dialog/ocaldialogs.cpp:337:47: warning: converting to non-pointer type ‘long int’ from NULL
ui/dialog/ocaldialogs.cpp: In member function ‘bool Inkscape::UI::Dialog::OCAL::BaseBox::_on_expose_event(GdkEventExpose*)’:
ui/dialog/ocaldialogs.cpp:570:49: error: cannot call constructor ‘Glib::ustring::ustring’ directly
ui/dialog/ocaldialogs.cpp:570:49: error: for a function-style cast, remove the redundant ‘::ustring’
make[3]: *** [ui/dialog/ocaldialogs.o] Error 1

10122. By Andrew <email address hidden>

uint > unsigned int (so windows builds work)

10123. By Andrew <email address hidden>

Remove some GNOME_VFS checks
Try to use read_async instead of load_contents_async, not working at the moment :(

10124. By Andrew <email address hidden>

Revert changing to read_async

10125. By Andrew <email address hidden>

Correct ustring syntax

Revision history for this message
Andrew (and471) wrote :

Hi can I get a merge now? Otherwise I fear that this will never get merged.

Revision history for this message
Andrew (and471) :
review: Needs Resubmitting
Revision history for this message
ScislaC (scislac) wrote :

Have you been able to address all issues brought up? Trust me, we want it merged just as bad as you. :)

Revision history for this message
jazzynico (jazzynico) wrote :

Now that the devlibs are updated, the Gtk::Spinner use is no longer a problem on Windows.

But as for now, it compiles correctly on Ubuntu 10.10, inkscape trunk revision 10371 (except that I had to download the OCAL.png manually). And I still have the crash reported in the very first comment, when selecting an image in the result list while the preview of another one is still loading.

review: Needs Fixing
Revision history for this message
su_v (suv-lp) wrote :

I did update the checkout of the ocal branch (r10125) and rebuilt it with the same configure and compile options as I use for current trunk (and 0.48.x): at least in my local builds of the Mac OS X port of Inkscape, the new ocal dialog is a major regression i.e. it completely fails, whereas the current version (in stable and trunk) allows to search for and import images from openclipart.org. [1]

I will not vote against the merge (Inkscape users on Mac OS X are still a far smaller number than Windows & Linux), but it might be appreciated if - for the next major release - e.g. the old version could be maintained ifdef'd for darwin/osx (unless of course the migration to gtk+ 3 as well as supporting the upcoming release of Lion will prohibit maintaining parts of the old code base or offer an easier fix/port of GIO-based implementations - upstream or in Inkscape.)

[1] tested on Mac OS X 10.5.8 Leopard (i386)

10126. By Andrew <email address hidden>

Fixed issues with cancelling downloading of thumbnails and images, all should be well now :)

Revision history for this message
Andrew (and471) wrote :

Okay I have fixed the problem JazzyNico described. All should be ready to merge now.

review: Needs Resubmitting
Revision history for this message
Andrew (and471) wrote :

Just one issue is there, that the Ocal.png needs to be put into the Makefile so it is installed, however I am not experienced with Make so could someone do this when they merge?

Revision history for this message
jazzynico (jazzynico) wrote :

It would be more consistent to add the icon in the general share/icons/icons.svg file as we do with all the other icons. Would you be willing to take a look?

Revision history for this message
ScislaC (scislac) wrote :

If there is any modification to the icons.svg file, please be sure to read this first:

http://wiki.inkscape.org/wiki/index.php/Icons#Themes

Revision history for this message
jazzynico (jazzynico) wrote :

Hum, please forget my previous stupid comment. I just didn't remember the OCAL.png file is not an icon...

Revision history for this message
jazzynico (jazzynico) wrote :

Tested again on Ubuntu 10.10, Inkscape trunk revision 10495.
Crash fix confirmed. Thanks!
Tests on Windows XP planned later...

Ah, just a small diff error with verbs.cpp. Could you please fix it?

Revision history for this message
jazzynico (jazzynico) wrote :

Found another crasher, reproduced on Ubuntu 10.10 and Windows XP.

Steps:
1. Launch OCAL import.
2. Search something (used "skull").
3. Select the first result in the search list.
4. Search something else (used "pirate").

Backtrace:
Program received signal SIGSEGV, Segmentation fault.
0x005d3430 in Gtk::TreePath::get_indices() const () from /usr/lib/libgtkmm-2.4.so.1
(gdb) bt
#0 0x005d3430 in Gtk::TreePath::get_indices() const () from /usr/lib/libgtkmm-2.4.so.1
#1 0x0853b32f in Inkscape::UI::Dialog::OCAL::ImportDialog::on_list_results_selection_changed() ()
#2 0x08547ce7 in sigc::bound_mem_functor0<void, Inkscape::UI::Dialog::OCAL::ImportDialog>::operator()() const ()
#3 0x085472c9 in sigc::adaptor_functor<sigc::bound_mem_functor0<void, Inkscape::UI::Dialog::OCAL::ImportDialog> >::operator()() const ()
#4 0x0854617b in sigc::internal::slot_call0<sigc::bound_mem_functor0<void, Inkscape::UI::Dialog::OCAL::ImportDialog>, void>::call_it(sigc::internal::slot_rep*) ()
#5 0x00c6d19b in Glib::SignalProxyNormal::slot0_void_callback(_GObject*, void*) () from /usr/lib/libglibmm-2.4.so.1
#6 0x019fef2c in g_cclosure_marshal_VOID__VOID (closure=0xaa6ed88, return_value=0x0, n_param_values=1, param_values=0xab25508,
    invocation_hint=0xbfffe610, marshal_data=0x8083d10) at /build/buildd/glib2.0-2.26.1/gobject/gmarshal.c:79
#7 0x019ef412 in g_closure_invoke (closure=0xaa6ed88, return_value=0x0, n_param_values=1, param_values=0xab25508,
    invocation_hint=0xbfffe610) at /build/buildd/glib2.0-2.26.1/gobject/gclosure.c:766
#8 0x01a05f78 in signal_emit_unlocked_R (node=<value optimised out>, detail=<value optimised out>, instance=0xaa84220,
    emission_return=0x0, instance_and_params=0xab25508) at /build/buildd/glib2.0-2.26.1/gobject/gsignal.c:3322
#9 0x01a06fac in g_signal_emit_valist (instance=0xaa84220, signal_id=318, detail=0, var_args=0xbfffe848 "P\aA\n")
    at /build/buildd/glib2.0-2.26.1/gobject/gsignal.c:2983
#10 0x01a07275 in g_signal_emit_by_name (instance=0xaa84220, detailed_signal=0xbce996 "changed")
    at /build/buildd/glib2.0-2.26.1/gobject/gsignal.c:3077

review: Needs Fixing
10127. By Andrew

try to fix bug

10128. By Andrew

merged with trunk so I can build again...

10129. By Andrew

fixed crash!

Revision history for this message
Andrew (and471) wrote :

Hi, sorry for my long absense form this but I have just fixed the issue that JazzyNico reported above.

The branch is ready for merging into trunk. Please someone do it quickly! :)

Revision history for this message
Andrew (and471) :
review: Needs Resubmitting
Revision history for this message
su_v (suv-lp) wrote :

> The branch is ready for merging into trunk. Please someone do it quickly!

I repeat my concerns expressed earlier: if doable, please maintain the old dialog in Inkscape's sources for osx users: the new GIO-based dialog fails on OS X and merging the branch as is removes a long-supported feature from that port of Inkscape.

This comment is based on building inkscape from a local branch of 'ocal-dialog-improvements' with up-to-date MacPorts tree required for Inkscape's dependencies, on OS X 10.7.2 Lion (compiler: llvm-gcc-4.2.1):

Chillida:bin su_v$ ./inkscape -V
Inkscape 0.48+devel r10129 (Dec 28 2011)
Chillida:bin su_v$ ./inkscape
Hi!

(inkscape:40831): glibmm-CRITICAL **:
unhandled exception (type Glib::Error) in signal handler:
domain: g-io-error-quark
code : 15
what : Operation not supported

Chillida:bin su_v$ port installed glib2 glibmm gtk2 gtkmm
The following ports are currently installed:
  glib2 @2.30.2_2 (active)
  glibmm @2.28.2_0 (active)
  gtk2 @2.24.8_1+x11 (active)
  gtkmm @2.24.2_0 (active)
Chillida:bin su_v$

Revision history for this message
Andrew (and471) wrote :

I am not sure how to do the above/whether the main devs want that sort of thing. Decision please?

Revision history for this message
su_v (suv-lp) wrote :

@ScislaC - any comments?

Revision history for this message
ScislaC (scislac) wrote :

Andrew: For all intensive purposes, ~suv is as much of a main dev as the rest of us regular contributors. We have a long standing policy of not breaking features on a platform that has previously supported them if it can be avoided.

As ~suv mentioned, supporting the old dialog on osx is an option (make it conditional based on platform during compile time), however, this is still somewhat kludgy because different platforms will have different experiences... but nothing "breaks".

Either way, it's a good idea to find out why glibmm on OSX has this issue and to file an upstream bug report or add to one if it already exists. If we're possibly sitting on an unknown issue, we're only hurting ourselves. Likewise, if we're possibly another "me too", that could be extra motivation for upstream to fix it.

Revision history for this message
Andrew (and471) wrote :

Essentially I had given up on this for 6 months, as I didn't have the time for it, and I have finally managed to fix it for most platforms.

I have no idea how to fix the issue that ~suv describes and wouldn't even know where to begin. I did ask for help on the mailing list 6 months ago but got no help.

I don't have the time now to devote to fixing this and I really do fear that this will forever remain unmerged. If I am truly honest, this experience has made it seems like it is really hard to contribute to Inkscape, which sucks because I love the program and wanted to make it better.

Revision history for this message
su_v (suv-lp) wrote :

As mentioned earlier, "I will not vote against the merge", and I'm sorry if my tests have slowed down the process of getting highly appreciated new contributions merged into trunk.

I was speaking up a) because I was eager to test the new improvements ;) and b) because it might otherwise go unnoticed (and will potentially only get back on the radar with later efforts to migrate Inkscape from the deprecated (?) gnome-vfs to gio - bug #715215).

Revision history for this message
ScislaC (scislac) wrote :

Andrew: We definitely don't want you to have a bad experience contributing to the project. ~suv did bump the thread on the mailing list again today and if we're lucky, maybe we can get Jon Cruz to help us merge this in a way that is still OSX friendly. I'll be honest that this is a more unusual case than most contributions as it has issues that are platform specific, while most aspects of Inkscape are usually more platform agnostic. Please don't be discouraged by this, we will see what we can do to get this merged in the near future. :)

Revision history for this message
jazzynico (jazzynico) wrote :

Just tested the latest version, and the dialog no longer crashes on Ubuntu 11.04.
There are still two very minor "bugs":
1. Is printf("%s\n", "Hi!"); in ocaldialogs.cpp absolutely necessary? ;)
2. When testing multi-images import with Ctrl (that doesn't work, but it's not really a bug, just a missing feature), the preview window always show the n-1 image.

Thanks for your efforts. The new dialog is a real improvement. I'm sure we'll find a solution so that it's merged before 0.49 is out.

Revision history for this message
jazzynico (jazzynico) wrote :

Andrew, it would be very disappointing to see all your work lost just because you don't have time to investigate more. Would you mind giving write access to your branches (OCAL and gallery) to the Inkscape Developers group, so that we can work on it?

Revision history for this message
Andrew (and471) wrote :

I would love to but as I am not in that group, I cannot change it in Launchpad to be so

Revision history for this message
su_v (suv-lp) wrote :

> Andrew, it would be very disappointing to see all your work lost just because
> you don't have time to investigate more. Would you mind giving write access to
> your branches (OCAL and gallery) to the Inkscape Developers group, so that we
> can work on it?

As mentioned before, I'm not "voting against" the merge - I just want to make sure the issue on OS X is known.

Proposing to merge the ocal branch as is (as long as the two branches haven't diverged too much) and deal with the GIO issues on OS X in trunk (maybe disable the dialog on darwin platforms for the next release if not solved in time).

@ScislaC - would you agree to this?

For the gallery dialog, could the compromise to keep the version with the update button and not rely on monitoring the directory for changes (which failed on OS X, also due to features in GIO apparently not (yet) supported in GTK2 on Mac OS X) be agreed on?
<http://thread.gmane.org/gmane.comp.graphics.inkscape.devel/36401>

Revision history for this message
Alex Valavanis (valavanisalex) wrote :

OK, I've gone ahead and merged this. It seems like a massive improvement for linux, and it would be a shame to lose all this excellent work. I suggest that we thoroughly test the merged version and try to work out the remaining issues together in trunk as suv proposed.

If anyone disagrees strongly with this, we can always revert.

review: Approve
Revision history for this message
Andrew (and471) wrote :

Thankyou! :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'share/icons/Makefile.am'
--- share/icons/Makefile.am 2010-02-05 18:41:32 +0000
+++ share/icons/Makefile.am 2011-12-27 21:09:25 +0000
@@ -38,7 +38,8 @@
38 feSpecularLighting-icon.png \38 feSpecularLighting-icon.png \
39 feSpecularLighting-icon.svg \39 feSpecularLighting-icon.svg \
40 feTurbulence-icon.png \40 feTurbulence-icon.png \
41 feTurbulence-icon.svg41 feTurbulence-icon.svg \
42 OCAL.png
4243
43icons_DATA = \44icons_DATA = \
44 $(pixmaps) \45 $(pixmaps) \
4546
=== added file 'share/icons/OCAL.png'
46Binary files share/icons/OCAL.png 1970-01-01 00:00:00 +0000 and share/icons/OCAL.png 2011-12-27 21:09:25 +0000 differ47Binary files share/icons/OCAL.png 1970-01-01 00:00:00 +0000 and share/icons/OCAL.png 2011-12-27 21:09:25 +0000 differ
=== modified file 'src/file.cpp'
--- src/file.cpp 2011-12-08 11:53:54 +0000
+++ src/file.cpp 2011-12-27 21:09:25 +0000
@@ -1125,7 +1125,7 @@
1125 return;1125 return;
1126 }1126 }
11271127
1128 //# Get file name and extension type1128 // Get file name and extension type
1129 Glib::ustring fileName = importDialogInstance->getFilename();1129 Glib::ustring fileName = importDialogInstance->getFilename();
1130 Inkscape::Extension::Extension *selection = importDialogInstance->getSelectionType();1130 Inkscape::Extension::Extension *selection = importDialogInstance->getSelectionType();
11311131
@@ -1340,8 +1340,8 @@
1340 export_path = export_path_local;1340 export_path = export_path_local;
13411341
1342 // Show the Export To OCAL dialog1342 // Show the Export To OCAL dialog
1343 Inkscape::UI::Dialog::FileExportToOCALDialog *exportDialogInstance =1343 Inkscape::UI::Dialog::OCAL:ExportDialog *exportDialogInstance =
1344 new Inkscape::UI::Dialog::FileExportToOCALDialog(1344 new Inkscape::UI::Dialog::OCAL:ExportDialog
1345 parentWindow,1345 parentWindow,
1346 Inkscape::UI::Dialog::EXPORT_TYPES,1346 Inkscape::UI::Dialog::EXPORT_TYPES,
1347 (char const *) _("Select file to export to")1347 (char const *) _("Select file to export to")
@@ -1452,11 +1452,23 @@
1452## I M P O R T F R O M O C A L1452## I M P O R T F R O M O C A L
1453######################*/1453######################*/
14541454
1455Inkscape::UI::Dialog::OCAL::ImportDialog* import_ocal_dialog = NULL;
1456
1455/**1457/**
1456 * Display an ImportToOcal Dialog, and the selected document from OCAL1458 * Display an ImportFromOcal Dialog, and the selected document from OCAL
1457 */1459 */
1460void on_import_from_ocal_response(Glib::ustring filename)
1461{
1462 SPDocument *doc = SP_ACTIVE_DOCUMENT;
1463
1464 if (!filename.empty()) {
1465 Inkscape::Extension::Extension *selection = import_ocal_dialog->get_selection_type();
1466 file_import(doc, filename, selection);
1467 }
1468}
1469
1458void1470void
1459sp_file_import_from_ocal(Gtk::Window &parentWindow)1471sp_file_import_from_ocal(Gtk::Window &parent_window)
1460{1472{
1461 static Glib::ustring import_path;1473 static Glib::ustring import_path;
14621474
@@ -1464,47 +1476,18 @@
1464 if (!doc)1476 if (!doc)
1465 return;1477 return;
14661478
1467 Inkscape::UI::Dialog::FileImportFromOCALDialog *importDialogInstance = NULL;1479 if (import_ocal_dialog == NULL) {
14681480 import_ocal_dialog = new
1469 if (!importDialogInstance) {1481 Inkscape::UI::Dialog::OCAL::ImportDialog(
1470 importDialogInstance = new1482 parent_window,
1471 Inkscape::UI::Dialog::FileImportFromOCALDialog(
1472 parentWindow,
1473 import_path,
1474 Inkscape::UI::Dialog::IMPORT_TYPES,1483 Inkscape::UI::Dialog::IMPORT_TYPES,
1475 (char const *)_("Import From Open Clip Art Library"));1484 (char const *)_("Import Clip Art"));
1476 }1485
14771486 import_ocal_dialog->signal_response().connect(
1478 bool success = importDialogInstance->show();1487 sigc::ptr_fun(&on_import_from_ocal_response));
1479 if (!success) {1488 }
1480 delete importDialogInstance;1489
1481 return;1490 import_ocal_dialog->show_all();
1482 }
1483
1484 // Get file name and extension type
1485 Glib::ustring fileName = importDialogInstance->getFilename();
1486 Inkscape::Extension::Extension *selection = importDialogInstance->getSelectionType();
1487
1488 delete importDialogInstance;
1489 importDialogInstance = NULL;
1490
1491 if (fileName.size() > 0) {
1492
1493 Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
1494
1495 if ( newFileName.size() > 0)
1496 fileName = newFileName;
1497 else
1498 g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
1499
1500 import_path = fileName;
1501 if (import_path.size()>0)
1502 import_path.append(G_DIR_SEPARATOR_S);
1503
1504 file_import(doc, fileName, selection);
1505 }
1506
1507 return;
1508}1491}
15091492
1510/*######################1493/*######################
15111494
=== modified file 'src/file.h'
--- src/file.h 2011-12-08 11:53:54 +0000
+++ src/file.h 2011-12-27 21:09:25 +0000
@@ -20,6 +20,7 @@
20#include <gtk/gtk.h>20#include <gtk/gtk.h>
2121
22#include "extension/system.h"22#include "extension/system.h"
23#include "ui/dialog/ocaldialogs.h"
2324
24struct SPDesktop;25struct SPDesktop;
25struct SPDocument;26struct SPDocument;
@@ -166,6 +167,11 @@
166/**167/**
167 * Import a document from OCAL168 * Import a document from OCAL
168 */169 */
170void on_import_from_ocal_response(Glib::ustring filename);
171
172/**
173 * Import a document from OCAL
174 */
169void sp_file_import_from_ocal (Gtk::Window &parentWindow );175void sp_file_import_from_ocal (Gtk::Window &parentWindow );
170176
171177
172178
=== modified file 'src/io/sys.cpp'
--- src/io/sys.cpp 2011-12-08 11:53:54 +0000
+++ src/io/sys.cpp 2011-12-27 21:09:25 +0000
@@ -355,6 +355,15 @@
355 return result;355 return result;
356}356}
357357
358/*
359 * Returns the file extension of a path/filename
360 */
361Glib::ustring Inkscape::IO::get_file_extension(Glib::ustring path)
362{
363 Glib::ustring::size_type period_location = path.find_last_of(".");
364 return path.substr(period_location);
365}
366
358/*367/*
359 Local Variables:368 Local Variables:
360 mode:c++369 mode:c++
361370
=== modified file 'src/io/sys.h'
--- src/io/sys.h 2011-12-08 11:53:54 +0000
+++ src/io/sys.h 2011-12-27 21:09:25 +0000
@@ -59,6 +59,8 @@
59 int* standard_output,59 int* standard_output,
60 int* standard_error);60 int* standard_error);
6161
62Glib::ustring get_file_extension(Glib::ustring path);
63
62}64}
63}65}
6466
6567
=== modified file 'src/menus-skeleton.h'
--- src/menus-skeleton.h 2011-06-22 21:40:59 +0000
+++ src/menus-skeleton.h 2011-12-27 21:09:25 +0000
@@ -27,10 +27,8 @@
27" <separator/>\n"27" <separator/>\n"
28" <verb verb-id=\"FileImport\" />\n"28" <verb verb-id=\"FileImport\" />\n"
29" <verb verb-id=\"FileExport\" />\n"29" <verb verb-id=\"FileExport\" />\n"
30#ifdef WITH_GNOME_VFS
31" <verb verb-id=\"FileImportFromOCAL\" />\n"30" <verb verb-id=\"FileImportFromOCAL\" />\n"
32//" <verb verb-id=\"FileExportToOCAL\" />\n"31//" <verb verb-id=\"FileExportToOCAL\" />\n"
33#endif
34" <separator/>\n"32" <separator/>\n"
35" <verb verb-id=\"FilePrint\" />\n"33" <verb verb-id=\"FilePrint\" />\n"
36" <separator/>\n"34" <separator/>\n"
3735
=== modified file 'src/ui/dialog/ocaldialogs.cpp'
--- src/ui/dialog/ocaldialogs.cpp 2011-10-03 07:24:15 +0000
+++ src/ui/dialog/ocaldialogs.cpp 2011-12-27 21:09:25 +0000
@@ -5,6 +5,7 @@
5/* Authors:5/* Authors:
6 * Bruno Dilly6 * Bruno Dilly
7 * Other dudes from The Inkscape Organization7 * Other dudes from The Inkscape Organization
8 * Andrew Higginson
8 *9 *
9 * Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>10 * Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>
10 *11 *
@@ -20,6 +21,7 @@
20#include <errno.h> // errno21#include <errno.h> // errno
21#include <string.h> // strerror()22#include <string.h> // strerror()
2223
24#include "path-prefix.h"
23#include "ocaldialogs.h"25#include "ocaldialogs.h"
24#include "filedialogimpl-gtkmm.h"26#include "filedialogimpl-gtkmm.h"
25#include "interface.h"27#include "interface.h"
@@ -34,6 +36,8 @@
34{36{
35namespace Dialog37namespace Dialog
36{38{
39namespace OCAL
40{
3741
38//########################################################################42//########################################################################
39//# F I L E E X P O R T T O O C A L43//# F I L E E X P O R T T O O C A L
@@ -43,7 +47,7 @@
43 * Callback for fileNameEntry widget47 * Callback for fileNameEntry widget
44 */48 */
45/*49/*
46void FileExportToOCALDialog::fileNameEntryChangedCallback()50void ExportDialog::fileNameEntryChangedCallback()
47{51{
48 if (!fileNameEntry)52 if (!fileNameEntry)
49 return;53 return;
@@ -60,10 +64,10 @@
60 * Constructor64 * Constructor
61 */65 */
62/*66/*
63FileExportToOCALDialog::FileExportToOCALDialog(Gtk::Window &parentWindow,67ExportDialog::ExportDialog(Gtk::Window &parentWindow,
64 FileDialogType fileTypes,68 FileDialogType fileTypes,
65 const Glib::ustring &title) :69 const Glib::ustring &title) :
66 FileDialogOCALBase(title, parentWindow)70 FileDialogBase(title, parentWindow)
67{71{
68*/72*/
69 /*73 /*
@@ -103,7 +107,7 @@
103 //Catch when user hits [return] on the text field107 //Catch when user hits [return] on the text field
104 fileNameEntry = entries[0];108 fileNameEntry = entries[0];
105 fileNameEntry->signal_activate().connect(109 fileNameEntry->signal_activate().connect(
106 sigc::mem_fun(*this, &FileExportToOCALDialog::fileNameEntryChangedCallback) );110 sigc::mem_fun(*this, &ExportDialog::fileNameEntryChangedCallback) );
107 }111 }
108112
109 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);113 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
@@ -116,7 +120,7 @@
116 * Destructor120 * Destructor
117 */121 */
118/*122/*
119FileExportToOCALDialog::~FileExportToOCALDialog()123ExportDialog::~ExportDialog()
120{124{
121}125}
122*/126*/
@@ -125,7 +129,7 @@
125 */129 */
126/*130/*
127bool131bool
128FileExportToOCALDialog::show()132ExportDialog::show()
129{133{
130 set_modal (TRUE); //Window134 set_modal (TRUE); //Window
131 sp_transientize((GtkWidget *)gobj()); //Make transient135 sp_transientize((GtkWidget *)gobj()); //Make transient
@@ -147,7 +151,7 @@
147 */151 */
148/*152/*
149Glib::ustring153Glib::ustring
150FileExportToOCALDialog::getFilename()154ExportDialog::get_filename()
151{155{
152 myFilename = fileNameEntry->get_text();156 myFilename = fileNameEntry->get_text();
153 if (!Glib::get_charset()) //If we are not utf8157 if (!Glib::get_charset()) //If we are not utf8
@@ -158,7 +162,7 @@
158162
159163
160void164void
161FileExportToOCALDialog::change_title(const Glib::ustring& title)165ExportDialog::change_title(const Glib::ustring& title)
162{166{
163 this->set_title(title);167 this->set_title(title);
164}168}
@@ -173,8 +177,8 @@
173 * Constructor177 * Constructor
174 */178 */
175/*179/*
176FileExportToOCALPasswordDialog::FileExportToOCALPasswordDialog(Gtk::Window &parentWindow,180ExportPasswordDialog::ExportPasswordDialog(Gtk::Window &parentWindow,
177 const Glib::ustring &title) : FileDialogOCALBase(title, parentWindow)181 const Glib::ustring &title) : FileDialogBase(title, parentWindow)
178{182{
179*/183*/
180 /*184 /*
@@ -221,7 +225,7 @@
221 * Destructor225 * Destructor
222 */226 */
223/*227/*
224FileExportToOCALPasswordDialog::~FileExportToOCALPasswordDialog()228ExportPasswordDialog::~ExportPasswordDialog()
225{229{
226}230}
227*/231*/
@@ -230,7 +234,7 @@
230 */234 */
231/*235/*
232bool236bool
233FileExportToOCALPasswordDialog::show()237ExportPasswordDialog::show()
234{238{
235 set_modal (TRUE); //Window239 set_modal (TRUE); //Window
236 sp_transientize((GtkWidget *)gobj()); //Make transient240 sp_transientize((GtkWidget *)gobj()); //Make transient
@@ -252,7 +256,7 @@
252 */256 */
253/*257/*
254Glib::ustring258Glib::ustring
255FileExportToOCALPasswordDialog::getUsername()259ExportPasswordDialog::getUsername()
256{260{
257 myUsername = usernameEntry->get_text();261 myUsername = usernameEntry->get_text();
258 return myUsername;262 return myUsername;
@@ -263,14 +267,14 @@
263 */267 */
264/*268/*
265Glib::ustring269Glib::ustring
266FileExportToOCALPasswordDialog::getPassword()270ExportPasswordDialog::getPassword()
267{271{
268 myPassword = passwordEntry->get_text();272 myPassword = passwordEntry->get_text();
269 return myPassword;273 return myPassword;
270}274}
271275
272void276void
273FileExportToOCALPasswordDialog::change_title(const Glib::ustring& title)277ExportPasswordDialog::change_title(const Glib::ustring& title)
274{278{
275 this->set_title(title);279 this->set_title(title);
276}280}
@@ -280,408 +284,946 @@
280//### F I L E I M P O R T F R O M O C A L284//### F I L E I M P O R T F R O M O C A L
281//#########################################################################285//#########################################################################
282286
287WrapLabel::WrapLabel() : Gtk::Label()
288{
289 signal_size_allocate().connect(sigc::mem_fun(*this, &WrapLabel::_on_size_allocate));
290}
291
292void WrapLabel::_on_size_allocate(Gtk::Allocation& allocation)
293{
294 set_size_request(allocation.get_width(), -1);
295}
296
297
298LoadingBox::LoadingBox() : Gtk::EventBox()
299{
300 set_visible_window(false);
301 draw_spinner = false;
302 spinner_step = 0;
303 signal_expose_event().connect(sigc::mem_fun(*this, &LoadingBox::_on_expose_event), false);
304}
305
306bool LoadingBox::_on_expose_event(GdkEventExpose* event)
307{
308 Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
309
310 // Draw shadow
311 int x = get_allocation().get_x();
312 int y = get_allocation().get_y();
313 int width = get_allocation().get_width();
314 int height = get_allocation().get_height();
315
316 get_style()->paint_shadow(get_window(), get_state(), Gtk::SHADOW_IN,
317 Gdk::Rectangle(x, y, width, height),
318 *this, Glib::ustring("viewport"), x, y, width, height);
319
320 if (draw_spinner) {
321 int spinner_size = 16;
322 int spinner_x = x + (width - spinner_size) / 2;
323 int spinner_y = y + (height - spinner_size) / 2;
324
325 // FIXME: Gtk::Style::paint_spinner not yet in gtkmm
326 gtk_paint_spinner(gtk_widget_get_style(GTK_WIDGET(gobj())),
327 gtk_widget_get_window(GTK_WIDGET(gobj())),
328 gtk_widget_get_state(GTK_WIDGET(gobj())), NULL, GTK_WIDGET(gobj()),
329 NULL, spinner_step, spinner_x, spinner_y, spinner_size, spinner_size);
330 }
331
332 return false;
333}
334
335void LoadingBox::start()
336{
337 // Timeout hasn't been stopped, so must be disconnected
338 if ((draw_spinner != false) & (timeout != NULL)) {
339 timeout.disconnect();
340 }
341
342 draw_spinner = true;
343 timeout = Glib::signal_timeout().connect(sigc::mem_fun(*this, &LoadingBox::on_timeout), 80);
344}
345
346void LoadingBox::stop()
347{
348 draw_spinner = false;
349}
350
351bool LoadingBox::on_timeout() {
352 if (draw_spinner) {
353
354 if (spinner_step == 11) {
355 spinner_step = 0;
356 } else {
357 spinner_step ++;
358 }
359
360 queue_draw();
361 return true;
362 }
363 return false;
364}
365
366PreviewWidget::PreviewWidget() : Gtk::VBox(false, 12)
367{
368 box_loading = new LoadingBox();
369 image = new Gtk::Image();
370
371 label_title = new WrapLabel();
372 label_description = new WrapLabel();
373 label_time = new WrapLabel();
374
375 pack_start(*box_loading, false, false);
376 pack_start(*image, false, false);
377 pack_start(*label_title, false, false);
378 pack_start(*label_description, false, false);
379 pack_start(*label_time, false, false);
380
381 label_title->set_line_wrap(true);
382 label_title->set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
383 label_title->set_justify(Gtk::JUSTIFY_CENTER);
384 label_description->set_line_wrap(true);
385 label_description->set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
386 label_description->set_justify(Gtk::JUSTIFY_CENTER);
387 label_time->set_line_wrap(true);
388 label_time->set_line_wrap_mode(Pango::WRAP_WORD_CHAR);
389 label_time->set_justify(Gtk::JUSTIFY_CENTER);
390
391 box_loading->set_no_show_all(true);
392 image->set_no_show_all(true);
393 label_title->set_size_request(90, -1);
394 label_description->set_size_request(90, -1);
395 label_time->set_size_request(90, -1);
396 box_loading->set_size_request(90, 90);
397 set_border_width(12);
398
399 signal_expose_event().connect(sigc::mem_fun(*this, &PreviewWidget::_on_expose_event), false);
400
401 clear();
402}
403
404void PreviewWidget::set_metadata(Glib::ustring description, Glib::ustring creator,
405 Glib::ustring time)
406{
407 label_title->set_markup(g_markup_printf_escaped("<b>%s</b>", description.c_str()));
408 label_description->set_markup(g_markup_printf_escaped("%s", creator.c_str()));
409 label_time->set_markup(g_markup_printf_escaped("<small>%s</small>", time.c_str()));
410
411 show_box_loading();
412}
413
414void PreviewWidget::show_box_loading()
415{
416 box_loading->show();
417 box_loading->start();
418}
419
420void PreviewWidget::hide_box_loading()
421{
422 box_loading->hide();
423 box_loading->stop();
424}
425
426void PreviewWidget::set_image(std::string path)
427{
428 image->set(path);
429 hide_box_loading();
430 image->show();
431}
432
433void PreviewWidget::clear()
434{
435 label_title->set_markup("");
436 label_description->set_markup("");
437 label_time->set_markup("");
438
439 box_loading->hide();
440 image->hide();
441}
442
443bool PreviewWidget::_on_expose_event(GdkEventExpose* event)
444{
445 Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
446
447 // Draw background
448 int x = get_allocation().get_x();
449 int y = get_allocation().get_y();
450 int width = get_allocation().get_width();
451 int height = get_allocation().get_height();
452 Gdk::Color background_fill = get_style()->get_base(get_state());
453
454 cr->rectangle(x, y, width, height);
455 Gdk::Cairo::set_source_color(cr, background_fill);
456 cr->fill();
457
458 return false;
459}
460
461StatusWidget::StatusWidget() : Gtk::HBox(false, 6)
462{
463 image = new Gtk::Image(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU);
464 spinner = new Gtk::Spinner();
465 label = new Gtk::Label();
466
467 image->set_no_show_all(true);
468 spinner->set_no_show_all(true);
469 label->set_no_show_all(true);
470
471 pack_start(*image, false, false);
472 pack_start(*spinner, false, false);
473 pack_start(*label, false, false);
474}
475
476void StatusWidget::clear()
477{
478 spinner->hide();
479 image->hide();
480 label->hide();
481}
482
483void StatusWidget::set_info(Glib::ustring text)
484{
485 spinner->hide();
486 image->show();
487 label->show();
488 image->set(Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_MENU);
489 label->set_text(text);
490}
491
492void StatusWidget::set_error(Glib::ustring text)
493{
494 spinner->hide();
495 image->show();
496 label->show();
497 image->set(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU);
498 label->set_text(text);
499}
500
501void StatusWidget::start_process(Glib::ustring text)
502{
503 image->hide();
504 spinner->show();
505 label->show();
506 label->set_text(text);
507 spinner->start();
508 show_all();
509}
510
511void StatusWidget::end_process()
512{
513 spinner->stop();
514 spinner->hide();
515 label->hide();
516 clear();
517}
518
519SearchEntry::SearchEntry() : Gtk::Entry()
520{
521 signal_changed().connect(sigc::mem_fun(*this, &SearchEntry::_on_changed));
522 signal_icon_press().connect(sigc::mem_fun(*this, &SearchEntry::_on_icon_pressed));
523
524 set_icon_from_stock(Gtk::Stock::FIND, Gtk::ENTRY_ICON_PRIMARY);
525 gtk_entry_set_icon_from_stock(gobj(), GTK_ENTRY_ICON_SECONDARY, NULL);
526}
527
528void SearchEntry::_on_icon_pressed(Gtk::EntryIconPosition icon_position, const GdkEventButton* event)
529{
530 if (icon_position == Gtk::ENTRY_ICON_SECONDARY) {
531 grab_focus();
532 set_text("");
533 } else if (icon_position == Gtk::ENTRY_ICON_PRIMARY) {
534 select_region(0, -1);
535 grab_focus();
536 }
537}
538
539void SearchEntry::_on_changed()
540{
541 if (get_text().empty()) {
542 gtk_entry_set_icon_from_stock(gobj(), GTK_ENTRY_ICON_SECONDARY, NULL);
543 } else {
544 set_icon_from_stock(Gtk::Stock::CLEAR, Gtk::ENTRY_ICON_SECONDARY);
545 }
546}
547
548BaseBox::BaseBox() : Gtk::EventBox()
549{
550 signal_expose_event().connect(sigc::mem_fun(*this, &BaseBox::_on_expose_event), false);
551 set_visible_window(false);
552}
553
554bool BaseBox::_on_expose_event(GdkEventExpose* event)
555{
556 Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
557
558 // Draw background and shadow
559 int x = get_allocation().get_x();
560 int y = get_allocation().get_y();
561 int width = get_allocation().get_width();
562 int height = get_allocation().get_height();
563 Gdk::Color background_fill = get_style()->get_base(get_state());
564
565 cr->rectangle(x, y, width, height);
566 Gdk::Cairo::set_source_color(cr, background_fill);
567 cr->fill();
568
569 get_style()->paint_shadow(get_window(), get_state(), Gtk::SHADOW_IN,
570 Gdk::Rectangle(x, y, width, height),
571 *this, Glib::ustring("viewport"), x, y, width, height);
572
573 return false;
574}
575
576LogoArea::LogoArea() : Gtk::EventBox()
577{
578 // Try to load the OCAL logo, but if the file is not found, degrade gracefully
579 try {
580 std::string logo_path = Glib::build_filename(INKSCAPE_PIXMAPDIR, "OCAL.png");
581 logo_mask = Cairo::ImageSurface::create_from_png(logo_path);
582 draw_logo = true;
583 } catch(Cairo::logic_error) {
584 logo_mask = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 1,1);
585 draw_logo = false;
586 }
587 signal_expose_event().connect(sigc::mem_fun(*this, &LogoArea::_on_expose_event));
588 set_visible_window(false);
589}
590
591bool LogoArea::_on_expose_event(GdkEventExpose* event)
592{
593 if (draw_logo) {
594 int x = get_allocation().get_x();
595 int y = get_allocation().get_y();
596 int width = get_allocation().get_width();
597 int height = get_allocation().get_height();
598 int x_logo = x + (width - 220) / 2;
599 int y_logo = y + (height - 76) / 2;
600
601 Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
602
603 // Draw logo, we mask [read fill] it with the mid colour from the
604 // user's GTK theme
605 Gdk::Color logo_fill = get_style()->get_mid(get_state());
606
607 Gdk::Cairo::set_source_color(cr, logo_fill);
608 cr->mask(logo_mask, x_logo, y_logo);
609 }
610
611 return false;
612}
613
614SearchResultList::SearchResultList(guint columns_count) : ListViewText(columns_count)
615{
616 set_headers_visible(false);
617 set_column_title(RESULTS_COLUMN_MARKUP, _("Clipart found"));
618
619 Gtk::CellRenderer* cr_markup = get_column_cell_renderer(RESULTS_COLUMN_MARKUP);
620 cr_markup->set_property("ellipsize", Pango::ELLIPSIZE_END);
621 get_column(RESULTS_COLUMN_MARKUP)->clear_attributes(*cr_markup);
622 get_column(RESULTS_COLUMN_MARKUP)->add_attribute(*cr_markup,
623 "markup", RESULTS_COLUMN_MARKUP);
624
625 // Hide all columns except for the MARKUP column
626 for (int i = 0; i < RESULTS_COLUMN_LENGTH; i++) {
627 if (i != RESULTS_COLUMN_MARKUP) {
628 get_column(i)->set_visible(false);
629 }
630 }
631}
632
633void ImportDialog::on_list_results_selection_changed()
634{
635 std::vector<Gtk::TreeModel::Path> pathlist;
636 pathlist = list_results->get_selection()->get_selected_rows();
637 std::vector<int> posArray(1);
638
639 // If nothing is selected, then return
640 if (((int) pathlist.size()) < 1) {
641 return;
642 }
643 posArray = pathlist[0].get_indices();
644 int row = posArray[0];
645
646 Glib::ustring guid = list_results->get_text(row, RESULTS_COLUMN_GUID);
647
648 bool item_selected = (!guid.empty());
649 button_import->set_sensitive(item_selected);
650}
651
652
653void ImportDialog::on_button_import_clicked() {
654 std::vector<Gtk::TreeModel::Path> pathlist;
655 pathlist = list_results->get_selection()->get_selected_rows();
656 std::vector<int> posArray(1);
657
658 // If nothing is selected, then return
659 if (((int) pathlist.size()) < 1) {
660 return;
661 }
662 posArray = pathlist[0].get_indices();
663 int row = posArray[0];
664
665 button_import->set_sensitive(false);
666 button_close->hide();
667 button_cancel->show();
668 widget_status->start_process(_("Downloading image..."));
669 download_resource(TYPE_IMAGE, row);
670}
671
283/*672/*
284 * Calalback for cursor chage673 * Callback for cursor change
285 */674 */
286void FileListViewText::on_cursor_changed()675void ImportDialog::on_list_results_cursor_changed()
287{676{
288 std::vector<Gtk::TreeModel::Path> pathlist;677 std::vector<Gtk::TreeModel::Path> pathlist;
289 pathlist = this->get_selection()->get_selected_rows();678 pathlist = list_results->get_selection()->get_selected_rows();
290 std::vector<int> posArray(1);679 std::vector<int> posArray(1);
680
681 // If nothing is selected, then return
682 if (((int) pathlist.size()) < 1) {
683 return;
684 }
291 posArray = pathlist[0].get_indices();685 posArray = pathlist[0].get_indices();
292686 int row = posArray[0];
293#ifdef WITH_GNOME_VFS687
294 gnome_vfs_init();688 if (downloading_thumbnail) {
295 GnomeVFSHandle *from_handle = NULL;689 cancellable_thumbnail->cancel();
296 GnomeVFSHandle *to_handle = NULL;690 cancelled_thumbnail = true;
297 GnomeVFSFileSize bytes_read;691 }
298 GnomeVFSFileSize bytes_written;692
299 GnomeVFSResult result;693 update_preview(row);
300 guint8 buffer[8192];694 downloading_thumbnail = true;
301 Glib::ustring fileUrl;695 download_resource(TYPE_THUMBNAIL, row);
302696}
303 // FIXME: this would be better as a per-user OCAL cache of files697void ImportDialog::update_preview(int row)
304 // instead of filling /tmp with downloads.698{
305 //699 Glib::ustring description = list_results->get_text(row, RESULTS_COLUMN_DESCRIPTION);
306 // create file path700 Glib::ustring creator = list_results->get_text(row, RESULTS_COLUMN_CREATOR);
307 const std::string tmptemplate = "ocal-";701 Glib::ustring date = list_results->get_text(row, RESULTS_COLUMN_DATE);
308 std::string tmpname;702
309 int fd = Inkscape::IO::file_open_tmp(tmpname, tmptemplate);703 preview_files->clear();
310 if (fd<0) {704 preview_files->set_metadata(description, creator, date);
311 g_warning("Error creating temp file");705}
312 return;706
313 }707
314 close(fd);708std::string ImportDialog::get_temporary_dir(ResourceType type)
315 // make sure we don't collide with other users on the same machine709{
316 myFilename = tmpname;710 std::string ocal_tmp_dir = Glib::build_filename(Glib::get_tmp_dir(),
317 myFilename.append("-");711 "openclipart");
318 myFilename.append(get_text(posArray[0], 2));712
319 // rename based on original image's name, retaining extension713 if (type == TYPE_THUMBNAIL) {
320 if (rename(tmpname.c_str(),myFilename.c_str())<0) {714 return Glib::build_filename(ocal_tmp_dir, "thumbnails");
321 unlink(tmpname.c_str());715 } else {
322 g_warning("Error creating destination file '%s': %s", myFilename.c_str(), strerror(errno));716 return Glib::build_filename(ocal_tmp_dir, "images");
323 goto failquit;717 }
324 }718}
325719
326 //get file url720void ImportDialog::create_temporary_dirs()
327 fileUrl = get_text(posArray[0], 1); //http url721{
328722 // Make sure the temporary directories exists, if not, create them
329 //Inkscape::Preferences *prefs = Inkscape::Preferences::get();723 std::string ocal_tmp_thumbnail_dir = get_temporary_dir(TYPE_THUMBNAIL);
330 //Glib::ustring fileUrl = "dav://"; //dav url724 std::string ocal_tmp_image_dir = get_temporary_dir(TYPE_IMAGE);
331 //fileUrl.append(prefs->getString("/options/ocalurl/str"));725
332 //fileUrl.append("/dav.php/");726 if (!Glib::file_test(ocal_tmp_thumbnail_dir, Glib::FILE_TEST_EXISTS)) {
333 //fileUrl.append(get_text(posArray[0], 3)); //author dir727 Glib::RefPtr<Gio::File> directory = Gio::File::create_for_path(ocal_tmp_thumbnail_dir);
334 //fileUrl.append("/");728 directory->make_directory_with_parents();
335 //fileUrl.append(get_text(posArray[0], 2)); //filename729 }
336730
337 if (!Glib::get_charset()) //If we are not utf8731 if (!Glib::file_test(ocal_tmp_image_dir, Glib::FILE_TEST_EXISTS)) {
338 fileUrl = Glib::filename_to_utf8(fileUrl);732 Glib::RefPtr<Gio::File> directory = Gio::File::create_for_path(ocal_tmp_image_dir);
339733 directory->make_directory_with_parents();
340 {734 }
341 // open the temp file to receive735}
342 result = gnome_vfs_open (&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_WRITE);736
343 if (result == GNOME_VFS_ERROR_NOT_FOUND){737void ImportDialog::download_resource(ResourceType type, int row)
344 result = gnome_vfs_create (&to_handle, myFilename.c_str(), GNOME_VFS_OPEN_WRITE, FALSE, GNOME_VFS_PERM_USER_ALL);738{
345 }739 // Get Temporary Directory
346 if (result != GNOME_VFS_OK) {740 std::string ocal_tmp_dir = get_temporary_dir(type);
347 g_warning("Error creating temp file '%s': %s", myFilename.c_str(), gnome_vfs_result_to_string(result));741
348 goto fail;742 // Make a unique filename for the clipart, in the form 'GUID.extension'
349 }743 Glib::ustring guid = list_results->get_text(row, RESULTS_COLUMN_GUID);
350 result = gnome_vfs_open (&from_handle, fileUrl.c_str(), GNOME_VFS_OPEN_READ);744 Glib::ustring original_filename;
351 if (result != GNOME_VFS_OK) {745
352 g_warning("Could not find the file in Open Clip Art Library.");746 if (type == TYPE_IMAGE) {
353 goto fail;747 original_filename = list_results->get_text(row, RESULTS_COLUMN_FILENAME);
354 }748 } else {
355 // copy the file749 original_filename = list_results->get_text(row, RESULTS_COLUMN_THUMBNAIL_FILENAME);
356 while (1) {750 }
357 result = gnome_vfs_read (from_handle, buffer, 8192, &bytes_read);751 Glib::ustring extension = Inkscape::IO::get_file_extension(original_filename);
358 if ((result == GNOME_VFS_ERROR_EOF) &&(!bytes_read)){752
359 result = gnome_vfs_close (from_handle);753 Glib::ustring filename = Glib::ustring::compose("%1%2", guid, extension);
360 result = gnome_vfs_close (to_handle);754 std::string path = Glib::build_filename(ocal_tmp_dir, filename.c_str());
361 break;755 Glib::RefPtr<Gio::File> file_local = Gio::File::create_for_path(path);
362 }756
363 if (result != GNOME_VFS_OK) {757 // If the file has already been downloaded, use it
364 g_warning("%s", gnome_vfs_result_to_string(result));758 if (Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
365 goto fail;759 if (type == TYPE_IMAGE) {
366 }760 on_image_downloaded(path, true);
367 result = gnome_vfs_write (to_handle, buffer, bytes_read, &bytes_written);761 } else {
368 if (result != GNOME_VFS_OK) {762 on_thumbnail_downloaded(path, true);
369 g_warning("%s", gnome_vfs_result_to_string(result));763 }
370 goto fail;764 return;
371 }765 }
372 if (bytes_read != bytes_written){766
373 g_warning("Bytes read not equal to bytes written");767 // Get Remote File URL and get the respective cancellable object
374 goto fail;768 Glib::ustring url;
375 }769 Glib::RefPtr<Gio::Cancellable> cancellable;
376 }770
377 }771 if (type == TYPE_IMAGE) {
378 myPreview->showImage(myFilename);772 url = list_results->get_text(row, RESULTS_COLUMN_URL);
379 myLabel->set_text(get_text(posArray[0], 4));773 cancellable_image = Gio::Cancellable::create();
380#endif774 cancellable = cancellable_image;
381 return;775 } else {
382fail:776 url = list_results->get_text(row, RESULTS_COLUMN_THUMBNAIL_URL);
383 unlink(myFilename.c_str());777 cancellable_thumbnail = Gio::Cancellable::create();
384failquit:778 cancellable = cancellable_thumbnail;
385 myFilename = "";779 }
386}780
387781 Glib::RefPtr<Gio::File> file_remote = Gio::File::create_for_uri(url);
782
783 // Download it asynchronously
784 file_remote->copy_async(file_local,
785 sigc::bind<Glib::RefPtr<Gio::File>, Glib::ustring, ResourceType>(
786 sigc::mem_fun(*this, &ImportDialog::on_resource_downloaded),
787 file_remote, path, type), cancellable,
788 Gio::FILE_COPY_OVERWRITE);
789}
790
791void ImportDialog::on_resource_downloaded(const Glib::RefPtr<Gio::AsyncResult>& result,
792 Glib::RefPtr<Gio::File> file_remote, Glib::ustring path, ResourceType resource)
793{
794 bool success;
795
796 try {
797 success = file_remote->copy_finish(result);
798 } catch(Glib::Error) {
799 success = false;
800 }
801
802 if (resource == TYPE_IMAGE) {
803 on_image_downloaded(path, success);
804 } else {
805 on_thumbnail_downloaded(path, success);
806 }
807}
808
809void ImportDialog::on_image_downloaded(Glib::ustring path, bool success)
810{
811 button_import->set_sensitive(true);
812 button_close->show();
813 button_cancel->hide();
814
815 // If anything went wrong, show an error message if the user didn't do it
816 if (!success && !cancelled_image) {
817 widget_status->set_error(_("Could not download image"));
818 }
819 if (!success) {
820 widget_status->clear();
821 return;
822 }
823
824 try {
825 widget_status->clear();
826 m_signal_response.emit(path);
827 widget_status->set_info(_("Clipart downloaded successfully"));
828 } catch(Glib::Error) {
829 success = false;
830 }
831
832 cancelled_image = false;
833}
834
835void ImportDialog::on_thumbnail_downloaded(Glib::ustring path, bool success)
836{
837 downloading_thumbnail = false;
838
839 // If anything went wrong, show an error message if the user didn't do it
840 if (!success && !cancelled_thumbnail) {
841 widget_status->set_error(_("Could not download thumbnail file"));
842 return;
843 }
844 if (!success) {
845 widget_status->clear();
846 return;
847 }
848
849 try {
850 widget_status->clear();
851 preview_files->set_image(path);
852 } catch(Glib::Error) {
853 success = false;
854 }
855
856 cancelled_thumbnail = false;
857}
388858
389/*859/*
390 * Callback for row activated860 * Callback for row activated
391 */861 */
392void FileListViewText::on_row_activated(const Gtk::TreeModel::Path& /*path*/, Gtk::TreeViewColumn* /*column*/)862void ImportDialog::on_list_results_row_activated(const Gtk::TreeModel::Path& path,
393{863 Gtk::TreeViewColumn* column)
394 this->on_cursor_changed();864{
395 myButton->activate();865 on_list_results_cursor_changed();
396}866 button_import->signal_clicked();
397867}
398
399/*
400 * Returns the selected filename
401 */
402Glib::ustring FileListViewText::getFilename()
403{
404 return myFilename;
405}
406
407
408#ifdef WITH_GNOME_VFS
409/**
410 * Read callback for xmlReadIO(), used below
411 */
412static int vfs_read_callback (GnomeVFSHandle *handle, char* buf, int nb)
413{
414 GnomeVFSFileSize ndone;
415 GnomeVFSResult result;
416
417 result = gnome_vfs_read (handle, buf, nb, &ndone);
418
419 if (result == GNOME_VFS_OK) {
420 return (int)ndone;
421 } else {
422 if (result != GNOME_VFS_ERROR_EOF) {
423 sp_ui_error_dialog(_("Error while reading the Open Clip Art RSS feed"));
424 g_warning("%s\n", gnome_vfs_result_to_string(result));
425 }
426 return -1;
427 }
428}
429#endif
430
431
432/**
433 * Callback for user input into searchTagEntry
434 */
435void FileImportFromOCALDialog::searchTagEntryChangedCallback()
436{
437 if (!searchTagEntry)
438 return;
439
440 notFoundLabel->hide();
441 descriptionLabel->set_text("");
442 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
443
444 Glib::ustring searchTag = searchTagEntry->get_text();
445 // create the ocal uri to get rss feed
446 Glib::ustring uri = "http://";
447 uri.append(prefs->getString("/options/ocalurl/str"));
448 uri.append("/media/feed/rss/");
449 uri.append(searchTag);
450 if (!Glib::get_charset()) //If we are not utf8
451 uri = Glib::filename_to_utf8(uri);
452
453#ifdef WITH_GNOME_VFS
454
455 // open the rss feed
456 gnome_vfs_init();
457 GnomeVFSHandle *from_handle = NULL;
458 GnomeVFSResult result;
459
460 result = gnome_vfs_open (&from_handle, uri.c_str(), GNOME_VFS_OPEN_READ);
461 if (result != GNOME_VFS_OK) {
462 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)"));
463 return;
464 }
465
466 // create the resulting xml document tree
467 // this initialize the library and test mistakes between compiled and shared library used
468 LIBXML_TEST_VERSION
469 xmlDoc *doc = NULL;
470 xmlNode *root_element = NULL;
471
472 doc = xmlReadIO ((xmlInputReadCallback) vfs_read_callback,
473 (xmlInputCloseCallback) gnome_vfs_close, from_handle, uri.c_str(), NULL,
474 XML_PARSE_RECOVER + XML_PARSE_NOWARNING + XML_PARSE_NOERROR);
475 if (doc == NULL) {
476 sp_ui_error_dialog(_("Server supplied malformed Clip Art feed"));
477 g_warning("Failed to parse %s\n", uri.c_str());
478 return;
479 }
480
481 // get the root element node
482 root_element = xmlDocGetRootElement(doc);
483
484 // clear the fileslist
485 filesList->clear_items();
486 filesList->set_sensitive(false);
487
488 // print all xml the element names
489 print_xml_element_names(root_element);
490
491 if (filesList->size() == 0)
492 {
493 notFoundLabel->show();
494 filesList->set_sensitive(false);
495 }
496 else
497 filesList->set_sensitive(true);
498
499 // free the document
500 xmlFreeDoc(doc);
501 // free the global variables that may have been allocated by the parser
502 xmlCleanupParser();
503 return;
504#endif
505}
506
507868
508/**869/**
509 * Prints the names of the all the xml elements870 * Prints the names of the all the xml elements
510 * that are siblings or children of a given xml node871 * that are siblings or children of a given xml node
511 */872 */
512void FileImportFromOCALDialog::print_xml_element_names(xmlNode * a_node)873void SearchResultList::populate_from_xml(xmlNode * a_node)
513{874{
514 xmlNode *cur_node = NULL;875 xmlNode *cur_node = NULL;
515 guint row_num = 0;876 guint row_num = 0;
877
516 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {878 for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
517 // get itens information879 // Get items information
518 if (strcmp((const char*)cur_node->name, "rss")) //avoid the root880 if (strcmp((const char*)cur_node->name, "rss")) // Avoid the root
519 if (cur_node->type == XML_ELEMENT_NODE && !strcmp((const char*)cur_node->parent->name, "item"))881 if (cur_node->type == XML_ELEMENT_NODE && !strcmp((const char*)cur_node->parent->name, "item"))
520 {882 {
521 if (!strcmp((const char*)cur_node->name, "title"))883 if (!strcmp((const char*)cur_node->name, "title"))
522 {884 {
523 xmlChar *title = xmlNodeGetContent(cur_node);885 row_num = append_text("");
524 row_num = filesList->append_text((const char*)title);886 xmlChar *xml_title = xmlNodeGetContent(cur_node);
887 char* title = (char*) xml_title;
888
889 set_text(row_num, RESULTS_COLUMN_TITLE, title);
525 xmlFree(title);890 xmlFree(title);
526 }891 }
527#ifdef WITH_GNOME_VFS892 else if (!strcmp((const char*)cur_node->name, "pubDate"))
528 else if (!strcmp((const char*)cur_node->name, "enclosure"))
529 {893 {
530 xmlChar *urlattribute = xmlGetProp(cur_node, (xmlChar*)"url");894 xmlChar *xml_date = xmlNodeGetContent(cur_node);
531 filesList->set_text(row_num, 1, (const char*)urlattribute);895 char* date = (char*) xml_date;
532 gchar *tmp_file;896
533 tmp_file = gnome_vfs_uri_extract_short_path_name(gnome_vfs_uri_new((const char*)urlattribute));897 set_text(row_num, RESULTS_COLUMN_DATE, date);
534 filesList->set_text(row_num, 2, (const char*)tmp_file);898 xmlFree(xml_date);
535 xmlFree(urlattribute);
536 }899 }
537 else if (!strcmp((const char*)cur_node->name, "creator"))900 else if (!strcmp((const char*)cur_node->name, "creator"))
538 {901 {
539 filesList->set_text(row_num, 3, (const char*)xmlNodeGetContent(cur_node));902 xmlChar *xml_creator = xmlNodeGetContent(cur_node);
903 char* creator = (char*) xml_creator;
904
905 set_text(row_num, RESULTS_COLUMN_CREATOR, creator);
906 xmlFree(xml_creator);
540 }907 }
541 else if (!strcmp((const char*)cur_node->name, "description"))908 else if (!strcmp((const char*)cur_node->name, "description"))
542 {909 {
543 filesList->set_text(row_num, 4, (const char*)xmlNodeGetContent(cur_node));910 xmlChar *xml_description = xmlNodeGetContent(cur_node);
544 }911 //char* final_description;
545#endif912 char* stripped_description = g_strstrip((char*) xml_description);
913
914 if (!strcmp(stripped_description, "")) {
915 stripped_description = _("No description");
916 }
917
918 //GRegex* regex = g_regex_new(g_regex_escape_string(stripped_description, -1));
919 //final_description = g_regex_replace_literal(regex, "\n", -1, 0, " ");
920
921 set_text(row_num, RESULTS_COLUMN_DESCRIPTION, stripped_description);
922 xmlFree(xml_description);
923 }
924 else if (!strcmp((const char*)cur_node->name, "enclosure"))
925 {
926 xmlChar *xml_url = xmlGetProp(cur_node, (xmlChar*) "url");
927 char* url = (char*) xml_url;
928 char* filename = g_path_get_basename(url);
929
930 set_text(row_num, RESULTS_COLUMN_URL, url);
931 set_text(row_num, RESULTS_COLUMN_FILENAME, filename);
932 xmlFree(xml_url);
933 }
934 else if (!strcmp((const char*)cur_node->name, "thumbnail"))
935 {
936 xmlChar *xml_thumbnail_url = xmlGetProp(cur_node, (xmlChar*) "url");
937 char* thumbnail_url = (char*) xml_thumbnail_url;
938 char* thumbnail_filename = g_path_get_basename(thumbnail_url);
939
940 set_text(row_num, RESULTS_COLUMN_THUMBNAIL_URL, thumbnail_url);
941 set_text(row_num, RESULTS_COLUMN_THUMBNAIL_FILENAME, thumbnail_filename);
942 xmlFree(xml_thumbnail_url);
943 }
944 else if (!strcmp((const char*)cur_node->name, "guid"))
945 {
946 xmlChar *xml_guid = xmlNodeGetContent(cur_node);
947 char* guid_url = (char*) xml_guid;
948 char* guid = g_path_get_basename(guid_url);
949
950 set_text(row_num, RESULTS_COLUMN_GUID, guid);
951 xmlFree(xml_guid);
952 }
546 }953 }
547 print_xml_element_names(cur_node->children);954 populate_from_xml(cur_node->children);
548 }955 }
956}
957
958/**
959 * Callback for user input into entry_search
960 */
961void ImportDialog::on_button_search_clicked()
962{
963 on_entry_search_activated();
964}
965
966void ImportDialog::on_button_close_clicked()
967{
968 hide();
969}
970
971void ImportDialog::on_button_cancel_clicked()
972{
973 cancellable_image->cancel();
974 cancelled_image = true;
975}
976
977/**
978 * Callback for user input into entry_search
979 */
980void ImportDialog::on_entry_search_activated()
981{
982 preview_files->clear();
983 widget_status->start_process(_("Searching clipart..."));
984
985 notebook_content->set_current_page(NOTEBOOK_PAGE_LOGO);
986
987 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
988
989 Glib::ustring search_keywords = entry_search->get_text();
990
991 // Create the URI to the OCAL RSS feed
992 Glib::ustring xml_uri = Glib::ustring::compose("http://%1/media/feed/rss/%2",
993 prefs->getString("/options/ocalurl/str"), search_keywords);
994 // If we are not UTF8
995 if (!Glib::get_charset()) {
996 xml_uri = Glib::filename_to_utf8(xml_uri);
997 }
998
999 // Open the RSS feed
1000 Glib::RefPtr<Gio::File> xml_file = Gio::File::create_for_uri(xml_uri);
1001
1002 xml_file->load_contents_async(
1003 sigc::bind<Glib::RefPtr<Gio::File> , Glib::ustring>(
1004 sigc::mem_fun(*this, &ImportDialog::on_xml_file_read),
1005 xml_file, xml_uri)
1006 );
1007}
1008
1009void ImportDialog::on_xml_file_read(const Glib::RefPtr<Gio::AsyncResult>& result,
1010 Glib::RefPtr<Gio::File> xml_file, Glib::ustring xml_uri)
1011{
1012 widget_status->end_process();
1013
1014 char* data;
1015 gsize length;
1016
1017 bool sucess = xml_file->load_contents_finish(result, data, length);
1018 if (!sucess) {
1019 widget_status->set_error(_("Could not connect to the Open Clip Art Library"));
1020 return;
1021 }
1022
1023 // Create the resulting xml document tree
1024 // Initialize libxml and test mistakes between compiled and shared library used
1025 LIBXML_TEST_VERSION
1026 xmlDoc *doc = NULL;
1027 xmlNode *root_element = NULL;
1028
1029 doc = xmlReadMemory(data, (int) length, xml_uri.c_str(), NULL,
1030 XML_PARSE_RECOVER + XML_PARSE_NOWARNING + XML_PARSE_NOERROR);
1031
1032 if (doc == NULL) {
1033 // If nothing is returned, no results could be found
1034 if (length == 0) {
1035 notebook_content->set_current_page(NOTEBOOK_PAGE_NOT_FOUND);
1036 update_label_no_search_results();
1037 } else {
1038 widget_status->set_error(_("Could not parse search results"));
1039 }
1040 return;
1041 }
1042
1043 // Get the root element node
1044 root_element = xmlDocGetRootElement(doc);
1045
1046 // Clear and populate the list_results
1047 list_results->clear_items();
1048 list_results->populate_from_xml(root_element);
1049
1050 // Populate the MARKUP column with the title & description of the clipart
1051 for (guint i = 0; i <= list_results->size() - 1; i++) {
1052 Glib::ustring title = list_results->get_text(i, RESULTS_COLUMN_TITLE);
1053 Glib::ustring description = list_results->get_text(i, RESULTS_COLUMN_DESCRIPTION);
1054 char* markup = g_markup_printf_escaped("<b>%s</b>\n<span size=\"small\">%s</span>",
1055 title.c_str(), description.c_str());
1056 list_results->set_text(i, RESULTS_COLUMN_MARKUP, markup);
1057 }
1058 notebook_content->set_current_page(NOTEBOOK_PAGE_RESULTS);
1059
1060 // free the document
1061 xmlFreeDoc(doc);
1062 // free the global variables that may have been allocated by the parser
1063 xmlCleanupParser();
1064}
1065
1066
1067void ImportDialog::update_label_no_search_results()
1068{
1069 Glib::ustring keywords = Glib::Markup::escape_text(entry_search->get_text());
1070 Gdk::Color grey = entry_search->get_style()->get_text_aa(entry_search->get_state());
1071
1072 Glib::ustring markup = Glib::ustring::compose(
1073 "<span size=\"large\">%1 <b>%2</b> %3</span>\n<span color=\"%4\">%5</span>",
1074 _("No clipart named"), keywords, _("was found."), grey.to_string(),
1075 _("Please make sure all keywords are spelled correctly, or try again with different keywords."));
1076
1077 label_not_found->set_markup(markup);
549}1078}
5501079
551/**1080/**
552 * Constructor. Not called directly. Use the factory.1081 * Constructor. Not called directly. Use the factory.
553 */1082 */
554FileImportFromOCALDialog::FileImportFromOCALDialog(Gtk::Window& parentWindow,1083ImportDialog::ImportDialog(Gtk::Window& parent_window, FileDialogType file_types,
555 const Glib::ustring &/*dir*/,
556 FileDialogType fileTypes,
557 const Glib::ustring &title) :1084 const Glib::ustring &title) :
558 FileDialogOCALBase(title, parentWindow)1085 FileDialogBase(title, parent_window)
559{1086{
1087 printf("%s\n", "Hi!");
560 // Initalize to Autodetect1088 // Initalize to Autodetect
561 extension = NULL;1089 extension = NULL;
562 // No filename to start out with1090 // No filename to start out with
563 Glib::ustring searchTag = "";1091 Glib::ustring search_keywords = "";
5641092
565 dialogType = fileTypes;1093 dialogType = file_types;
566 Gtk::VBox *vbox = get_vbox();1094
567 Gtk::Label *tagLabel = new Gtk::Label(_("Search for:"));1095 // Creation
568 notFoundLabel = new Gtk::Label(_("No files matched your search"));1096 Gtk::VBox *vbox = new Gtk::VBox(false, 0);
569 descriptionLabel = new Gtk::Label();1097 Gtk::HButtonBox *hbuttonbox_bottom = new Gtk::HButtonBox();
570 descriptionLabel->set_max_width_chars(260);1098 Gtk::HBox *hbox_bottom = new Gtk::HBox(false, 12);
571 descriptionLabel->set_size_request(500, -1);1099 BaseBox *basebox_logo = new BaseBox();
572 descriptionLabel->set_single_line_mode(false);1100 BaseBox *basebox_no_search_results = new BaseBox();
573 descriptionLabel->set_line_wrap(true);1101 label_not_found = new Gtk::Label();
574 messageBox.pack_start(*notFoundLabel);1102 label_description = new Gtk::Label();
575 descriptionBox.pack_start(*descriptionLabel);1103 entry_search = new SearchEntry();
576 searchTagEntry = new Gtk::Entry();1104 button_search = new Gtk::Button(_("Search"));
577 searchTagEntry->set_text(searchTag);1105 Gtk::HButtonBox* hbuttonbox_search = new Gtk::HButtonBox();
578 searchTagEntry->set_max_length(255);1106 Gtk::ScrolledWindow* scrolledwindow_preview = new Gtk::ScrolledWindow();
579 searchButton = new Gtk::Button(_("Search"));1107 preview_files = new PreviewWidget();
580 tagBox.pack_start(*tagLabel);1108 /// Add the buttons in the bottom of the dialog
581 tagBox.pack_start(*searchTagEntry, Gtk::PACK_EXPAND_WIDGET, 3);1109 button_cancel = new Gtk::Button(Gtk::Stock::CANCEL);
582 tagBox.pack_start(*searchButton);1110 button_close = new Gtk::Button(_("Close"));
583 filesPreview = new SVGPreview();1111 button_import = new Gtk::Button(_("Import"));
584 filesPreview->showNoPreview();1112 list_results = new SearchResultList(RESULTS_COLUMN_LENGTH);
585 // add the buttons in the bottom of the dialog1113 drawingarea_logo = new LogoArea();
586 add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);1114 notebook_content = new Gtk::Notebook();
587 okButton = add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);1115 widget_status = new StatusWidget();
588 // sets the okbutton to default1116
589 set_default(*okButton);1117 downloading_thumbnail = false;
590 filesList = new FileListViewText(5, *filesPreview, *descriptionLabel, *okButton);1118 cancelled_thumbnail = false;
591 filesList->set_sensitive(false);1119 cancelled_image = false;
592 // add the listview inside a ScrolledWindow1120
593 listScrolledWindow.add(*filesList);1121 // Packing
594 // only show the scrollbars when they are necessary:1122 add(*vbox);
595 listScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);1123 vbox->pack_start(hbox_tags, false, false);
596 filesList->set_column_title(0, _("Files found"));1124 vbox->pack_start(hbox_files, true, true);
597 listScrolledWindow.set_size_request(400, 180);1125 vbox->pack_start(*hbox_bottom, false, false);
598 filesList->get_column(1)->set_visible(false); // file url1126 basebox_logo->add(*drawingarea_logo);
599 filesList->get_column(2)->set_visible(false); // tmp file path1127 basebox_no_search_results->add(*label_not_found);
600 filesList->get_column(3)->set_visible(false); // author dir1128 hbox_bottom->pack_start(*widget_status, true, true);
601 filesList->get_column(4)->set_visible(false); // file description1129 hbox_bottom->pack_start(*hbuttonbox_bottom, true, true);
602 filesBox.pack_start(listScrolledWindow);1130 hbuttonbox_bottom->pack_start(*button_cancel, false, false);
603 filesBox.pack_start(*filesPreview);1131 hbuttonbox_bottom->pack_start(*button_close, false, false);
604 vbox->pack_start(tagBox, false, false);1132 hbuttonbox_bottom->pack_start(*button_import, false, false);
605 vbox->pack_start(messageBox);1133 hbuttonbox_search->pack_start(*button_search, false, false);
606 vbox->pack_start(filesBox);1134 hbox_tags.pack_start(*entry_search, true, true);
607 vbox->pack_start(descriptionBox);1135 hbox_tags.pack_start(*hbuttonbox_search, false, false);
6081136 hbox_files.pack_start(*notebook_content, true, true);
609 //Let's do some customization1137 scrolledwindow_preview->add(*preview_files);
610 searchTagEntry = NULL;1138 hbox_files.pack_start(*scrolledwindow_preview, true, true);
611 Gtk::Container *cont = get_toplevel();1139
612 std::vector<Gtk::Entry *> entries;1140 notebook_content->insert_page(*basebox_logo, NOTEBOOK_PAGE_LOGO);
613 findEntryWidgets(cont, entries);1141 notebook_content->insert_page(scrolledwindow_list, NOTEBOOK_PAGE_RESULTS);
614 if (entries.size() >=1 )1142 notebook_content->insert_page(*basebox_no_search_results, NOTEBOOK_PAGE_NOT_FOUND);
615 {1143
616 //Catch when user hits [return] on the text field1144 // Properties
617 searchTagEntry = entries[0];1145 set_border_width(12);
618 searchTagEntry->signal_activate().connect(1146 set_default_size(480, 330);
619 sigc::mem_fun(*this, &FileImportFromOCALDialog::searchTagEntryChangedCallback));1147 vbox->set_spacing(12);
620 }1148 hbuttonbox_bottom->set_spacing(6);
6211149 hbuttonbox_bottom->set_layout(Gtk::BUTTONBOX_END);
622 searchButton->signal_clicked().connect(1150 button_import->set_sensitive(false);
623 sigc::mem_fun(*this, &FileImportFromOCALDialog::searchTagEntryChangedCallback));1151 entry_search->set_max_length(255);
1152 hbox_tags.set_spacing(6);
1153 preview_files->clear();
1154 notebook_content->set_current_page(NOTEBOOK_PAGE_LOGO);
1155 /// Add the listview inside a ScrolledWindow
1156 scrolledwindow_list.add(*list_results);
1157 scrolledwindow_list.set_shadow_type(Gtk::SHADOW_IN);
1158 /// Only show the scrollbars when they are necessary
1159 scrolledwindow_list.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
1160 preview_files->set_size_request(120, -1);
1161 hbox_files.set_spacing(12);
1162 label_not_found->set_line_wrap(true);
1163 label_not_found->set_line_wrap_mode(Pango::WRAP_WORD);
1164 label_not_found->set_justify(Gtk::JUSTIFY_CENTER);
1165 label_not_found->set_size_request(260, -1);
1166 scrolledwindow_preview->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1167 notebook_content->set_show_tabs(false);
1168 notebook_content->set_show_border(false);
1169 button_cancel->set_no_show_all(true);
1170 button_close->set_no_show_all(true);
1171 button_close->show();
1172 button_cancel->hide();
1173
1174 // Signals
1175 entry_search->signal_activate().connect(
1176 sigc::mem_fun(*this, &ImportDialog::on_entry_search_activated));
1177 button_import->signal_clicked().connect(
1178 sigc::mem_fun(*this, &ImportDialog::on_button_import_clicked));
1179 button_close->signal_clicked().connect(
1180 sigc::mem_fun(*this, &ImportDialog::on_button_close_clicked));
1181 button_cancel->signal_clicked().connect(
1182 sigc::mem_fun(*this, &ImportDialog::on_button_cancel_clicked));
1183 button_search->signal_clicked().connect(
1184 sigc::mem_fun(*this, &ImportDialog::on_button_search_clicked));
1185 list_results->signal_cursor_changed().connect(
1186 sigc::mem_fun(*this, &ImportDialog::on_list_results_cursor_changed));
1187 list_results->signal_row_activated().connect(
1188 sigc::mem_fun(*this, &ImportDialog::on_list_results_row_activated));
1189 list_results->get_selection()->signal_changed().connect(
1190 sigc::mem_fun(*this, &ImportDialog::on_list_results_selection_changed));
6241191
625 show_all_children();1192 show_all_children();
626 notFoundLabel->hide();1193 entry_search->grab_focus();
1194
1195 // Create the temporary directories that will be needed later
1196 create_temporary_dirs();
627}1197}
6281198
629/**1199/**
630 * Destructor1200 * Destructor
631 */1201 */
632FileImportFromOCALDialog::~FileImportFromOCALDialog()1202ImportDialog::~ImportDialog()
633{1203{
6341204
635}1205}
636
637/**
638 * Show this dialog modally. Return true if user hits [OK]
639 */
640bool
641FileImportFromOCALDialog::show()
642{
643 set_modal (TRUE); //Window
644 sp_transientize((GtkWidget *)gobj()); //Make transient
645 gint b = run(); //Dialog
646 hide();
647
648 if (b == Gtk::RESPONSE_OK)
649 {
650 return TRUE;
651 }
652 else
653 {
654 return FALSE;
655 }
656}
657
6581206
659/**1207/**
660 * Get the file extension type that was selected by the user. Valid after an [OK]1208 * Get the file extension type that was selected by the user. Valid after an [OK]
661 */1209 */
662Inkscape::Extension::Extension *1210Inkscape::Extension::Extension *
663FileImportFromOCALDialog::getSelectionType()1211ImportDialog::get_selection_type()
664{1212{
665 return extension;1213 return extension;
666}1214}
6671215
6681216ImportDialog::type_signal_response ImportDialog::signal_response()
669/**
670 * Get the file name chosen by the user. Valid after an [OK]
671 */
672Glib::ustring
673FileImportFromOCALDialog::getFilename (void)
674{1217{
675 return filesList->getFilename();1218 return m_signal_response;
676}1219}
6771220
6781221
1222} //namespace OCAL
679} //namespace Dialog1223} //namespace Dialog
680} //namespace UI1224} //namespace UI
681} //namespace Inkscape1225} //namespace Inkscape
6821226
683
684
685/*1227/*
686 Local Variables:1228 Local Variables:
687 mode:c++1229 mode:c++
6881230
=== modified file 'src/ui/dialog/ocaldialogs.h'
--- src/ui/dialog/ocaldialogs.h 2011-06-03 10:44:52 +0000
+++ src/ui/dialog/ocaldialogs.h 2011-12-27 21:09:25 +0000
@@ -4,6 +4,7 @@
4/* Authors:4/* Authors:
5 * Bruno Dilly <bruno.dilly@gmail.com>5 * Bruno Dilly <bruno.dilly@gmail.com>
6 * Inkscape Guys6 * Inkscape Guys
7 * Andrew Higginson
7 *8 *
8 * Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>9 * Copyright (C) 2007 Bruno Dilly <bruno.dilly@gmail.com>
9 * Released under GNU GPL, read the file 'COPYING' for more information10 * Released under GNU GPL, read the file 'COPYING' for more information
@@ -52,6 +53,7 @@
52//For export dialog53//For export dialog
53#include "ui/widget/scalar-unit.h"54#include "ui/widget/scalar-unit.h"
5455
56#include <dialogs/dialog-events.h>
5557
56namespace Inkscape58namespace Inkscape
57{59{
@@ -59,7 +61,8 @@
59{ 61{
60namespace Dialog62namespace Dialog
61{ 63{
62 64namespace OCAL
65{
63/*#########################################################################66/*#########################################################################
64### F I L E D I A L O G O C A L B A S E C L A S S67### F I L E D I A L O G O C A L B A S E C L A S S
65#########################################################################*/68#########################################################################*/
@@ -67,20 +70,32 @@
67/**70/**
68 * This class is the base implementation for export to OCAL.71 * This class is the base implementation for export to OCAL.
69 */72 */
70class FileDialogOCALBase : public Gtk::Dialog73class FileDialogBase : public Gtk::Window
71{74{
72public:75public:
7376
74 /**77 /**
75 * Constructor78 * Constructor
76 */79 */
77 FileDialogOCALBase(const Glib::ustring &title, Gtk::Window& parent) : Gtk::Dialog(title, parent, true)80 FileDialogBase(const Glib::ustring &title, Gtk::Window& parent) : Gtk::Window(Gtk::WINDOW_TOPLEVEL)
78 {}81 {
82 set_title(title);
83 sp_transientize((GtkWidget*) gobj());
84
85 // Allow shrinking of window so labels wrap correctly
86 set_resizable(true);
87
88 Gdk::Geometry geom;
89 geom.min_width = 480;
90 geom.min_height = 320;
91
92 set_geometry_hints(*this, geom, Gdk::HINT_MIN_SIZE);
93 }
7994
80 /*95 /*
81 * Destructor96 * Destructor
82 */97 */
83 virtual ~FileDialogOCALBase()98 virtual ~FileDialogBase()
84 {}99 {}
85100
86protected:101protected:
@@ -101,10 +116,10 @@
101116
102117
103/**118/**
104 * Our implementation of the FileExportToOCALDialog interface.119 * Our implementation of the ExportDialog interface.
105 */120 */
106/*121/*
107class FileExportToOCALDialog : public FileDialogOCALBase122class ExportDialog : public FileDialogBase
108{123{
109124
110public:125public:
@@ -116,7 +131,7 @@
116 * @param key a list of file types from which the user can select131 * @param key a list of file types from which the user can select
117 */132 */
118/*133/*
119 FileExportToOCALDialog(Gtk::Window& parentWindow, 134 ExportDialog(Gtk::Window& parentWindow,
120 FileDialogType fileTypes,135 FileDialogType fileTypes,
121 const Glib::ustring &title);136 const Glib::ustring &title);
122*/137*/
@@ -125,7 +140,7 @@
125 * Perform any necessary cleanups.140 * Perform any necessary cleanups.
126 */141 */
127/*142/*
128 ~FileExportToOCALDialog();143 ~ExportDialog();
129*/144*/
130 /**145 /**
131 * Show an SaveAs file selector.146 * Show an SaveAs file selector.
@@ -181,7 +196,7 @@
181/*196/*
182 std::set<Glib::ustring> knownExtensions;197 std::set<Glib::ustring> knownExtensions;
183198
184}; //FileExportToOCAL199}; //ExportDialog
185*/200*/
186201
187//########################################################################202//########################################################################
@@ -190,10 +205,10 @@
190205
191206
192/**207/**
193 * Our implementation of the FileExportToOCALPasswordDialog interface.208 * Our implementation of the ExportPasswordDialog interface.
194 */209 */
195/*210/*
196class FileExportToOCALPasswordDialog : public FileDialogOCALBase211class ExportPasswordDialog : public FileDialogBase
197{212{
198213
199public:214public:
@@ -203,7 +218,7 @@
203 * @param title the title of the dialog218 * @param title the title of the dialog
204 */219 */
205/*220/*
206 FileExportToOCALPasswordDialog(Gtk::Window& parentWindow, 221 ExportPasswordDialog(Gtk::Window& parentWindow,
207 const Glib::ustring &title);222 const Glib::ustring &title);
208*/223*/
209 /**224 /**
@@ -211,7 +226,7 @@
211 * Perform any necessary cleanups.226 * Perform any necessary cleanups.
212 */227 */
213/*228/*
214 ~FileExportToOCALPasswordDialog();229 ~ExportPasswordDialog();
215*/230*/
216231
217 /**232 /**
@@ -246,7 +261,7 @@
246 Gtk::HBox userBox;261 Gtk::HBox userBox;
247 Gtk::HBox passBox;262 Gtk::HBox passBox;
248 263
249}; //FileExportToOCALPassword264}; //ExportPasswordDialog
250*/265*/
251266
252267
@@ -254,34 +269,147 @@
254//### F I L E I M P O R T F R O M O C A L269//### F I L E I M P O R T F R O M O C A L
255//#########################################################################270//#########################################################################
256271
257/**272class WrapLabel : public Gtk::Label
258 * Our implementation class for filesListView273{
259 */274public:
260class FileListViewText : public Gtk::ListViewText275 WrapLabel();
261{276
262public:277private:
263 FileListViewText(guint columns_count, SVGPreview& filesPreview, Gtk::Label& description, Gtk::Button& okButton)278 void _on_size_allocate(Gtk::Allocation& allocation);
264 :ListViewText(columns_count)279};
265 {280
266 myPreview = &filesPreview;281class LoadingBox : public Gtk::EventBox
267 myLabel = &description;282{
268 myButton = &okButton;283public:
269 }284 LoadingBox();
270 Glib::ustring getFilename();285
271protected:286 void start();
272 void on_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);287 void stop();
273 void on_cursor_changed();288
274private:289private:
275 Glib::ustring myFilename;290 unsigned int spinner_step;
276 SVGPreview *myPreview;291 sigc::connection timeout;
277 Gtk::Label *myLabel;292 bool draw_spinner;
278 Gtk::Button *myButton;293 bool _on_expose_event(GdkEventExpose* event);
279};294 bool on_timeout();
280295};
281/**296
282 * Our implementation class for the FileImportFromOCALDialog interface..297class PreviewWidget : public Gtk::VBox
283 */298{
284class FileImportFromOCALDialog : public FileDialogOCALBase299public:
300 PreviewWidget();
301
302 void set_metadata(Glib::ustring description, Glib::ustring creator, Glib::ustring time);
303 void show_box_loading();
304 void hide_box_loading();
305 void set_image(std::string path);
306 void clear();
307 bool _on_expose_event(GdkEventExpose* event);
308
309private:
310 LoadingBox* box_loading;
311 Gtk::Image* image;
312
313 WrapLabel* label_title;
314 WrapLabel* label_description;
315 WrapLabel* label_time;
316};
317
318/**
319 * A Widget that contains an status icon and a message
320 */
321class StatusWidget : public Gtk::HBox
322{
323public:
324 StatusWidget();
325
326 void clear();
327 void set_error(Glib::ustring text);
328 void set_info(Glib::ustring text);
329 void start_process(Glib::ustring text);
330 void end_process();
331
332 Gtk::Spinner* spinner;
333 Gtk::Image* image;
334 Gtk::Label* label;
335};
336
337/**
338 * A Gtk::Entry with search & clear icons
339 */
340class SearchEntry : public Gtk::Entry
341{
342public:
343 SearchEntry();
344
345private:
346 void _on_icon_pressed(Gtk::EntryIconPosition icon_position, const GdkEventButton* event);
347 void _on_changed();
348};
349
350/**
351 * A box which paints an overlay of the OCAL logo
352 */
353class LogoArea : public Gtk::EventBox
354{
355public:
356 LogoArea();
357private:
358 bool _on_expose_event(GdkEventExpose* event);
359 bool draw_logo;
360 Cairo::RefPtr<Cairo::ImageSurface> logo_mask;
361};
362
363/**
364 * A box filled with the Base colour from the user's GTK theme, and a border
365 */
366class BaseBox : public Gtk::EventBox
367{
368public:
369 BaseBox();
370private:
371 bool _on_expose_event(GdkEventExpose* event);
372};
373
374enum {
375 RESULTS_COLUMN_MARKUP,
376 RESULTS_COLUMN_TITLE,
377 RESULTS_COLUMN_DESCRIPTION,
378 RESULTS_COLUMN_CREATOR,
379 RESULTS_COLUMN_DATE,
380 RESULTS_COLUMN_FILENAME,
381 RESULTS_COLUMN_THUMBNAIL_FILENAME,
382 RESULTS_COLUMN_URL,
383 RESULTS_COLUMN_THUMBNAIL_URL,
384 RESULTS_COLUMN_GUID,
385 RESULTS_COLUMN_LENGTH,
386};
387
388enum {
389 NOTEBOOK_PAGE_LOGO,
390 NOTEBOOK_PAGE_RESULTS,
391 NOTEBOOK_PAGE_NOT_FOUND,
392};
393
394enum ResourceType {
395 TYPE_THUMBNAIL,
396 TYPE_IMAGE,
397};
398
399/**
400 * The TreeView which holds the search results
401 */
402class SearchResultList : public Gtk::ListViewText
403{
404public:
405 SearchResultList(guint columns_count);
406 void populate_from_xml(xmlNode* a_node);
407};
408
409/**
410 * The Import Dialog
411 */
412class ImportDialog : public FileDialogBase
285{413{
286public:414public:
287 /**415 /**
@@ -290,16 +418,14 @@
290 * @param fileTypes one of FileDialogTypes418 * @param fileTypes one of FileDialogTypes
291 * @param title the title of the dialog419 * @param title the title of the dialog
292 */420 */
293 FileImportFromOCALDialog(Gtk::Window& parentWindow,421 ImportDialog(Gtk::Window& parent_window, FileDialogType file_types,
294 const Glib::ustring &dir,422 const Glib::ustring &title);
295 FileDialogType fileTypes,
296 const Glib::ustring &title);
297423
298 /**424 /**
299 * Destructor.425 * Destructor.
300 * Perform any necessary cleanups.426 * Perform any necessary cleanups.
301 */427 */
302 ~FileImportFromOCALDialog();428 ~ImportDialog();
303429
304 /**430 /**
305 * Show an OpenFile file selector.431 * Show an OpenFile file selector.
@@ -312,51 +438,73 @@
312 * @return a pointer to a string if successful (which must438 * @return a pointer to a string if successful (which must
313 * be later freed with g_free(), else NULL.439 * be later freed with g_free(), else NULL.
314 */440 */
315 Inkscape::Extension::Extension *getSelectionType();441 Inkscape::Extension::Extension *get_selection_type();
316442
317 Glib::ustring getFilename();443 typedef sigc::signal<void, Glib::ustring> type_signal_response;
444 type_signal_response signal_response();
445
446protected:
447 type_signal_response m_signal_response;
318448
319private:449private:
320450 Glib::ustring filename_image;
321 /**451 Glib::ustring filename_thumbnail;
322 * Allow the user to type the tag to be searched452 SearchEntry *entry_search;
323 */453 LogoArea *drawingarea_logo;
324 Gtk::Entry *searchTagEntry;454 SearchResultList *list_results;
325 FileListViewText *filesList;455 PreviewWidget *preview_files;
326 SVGPreview *filesPreview;456 Gtk::Label *label_not_found;
327 Gtk::Label *notFoundLabel;457 Gtk::Label *label_description;
328 Gtk::Label *descriptionLabel;458 Gtk::Button *button_search;
329 Gtk::Button *searchButton;459 Gtk::Button *button_import;
330 Gtk::Button *okButton;460 Gtk::Button *button_close;
461 Gtk::Button *button_cancel;
462 StatusWidget *widget_status;
331463
332 // Child widgets464 // Child widgets
333 Gtk::HBox tagBox;465 Gtk::Notebook *notebook_content;
334 Gtk::HBox filesBox;466 Gtk::HBox hbox_tags;
335 Gtk::HBox messageBox;467 Gtk::HBox hbox_files;
336 Gtk::HBox descriptionBox;468 Gtk::ScrolledWindow scrolledwindow_list;
337 Gtk::ScrolledWindow listScrolledWindow;
338 Glib::RefPtr<Gtk::TreeSelection> selection;469 Glib::RefPtr<Gtk::TreeSelection> selection;
339470
340 /**471 Glib::RefPtr<Gio::Cancellable> cancellable_image;
341 * Callback for user input into searchTagEntry472 Glib::RefPtr<Gio::Cancellable> cancellable_thumbnail;
342 */473 bool downloading_thumbnail;
343 void searchTagEntryChangedCallback();474 bool cancelled_thumbnail;
344475 bool cancelled_image;
345476
346 /**477 void update_label_no_search_results();
347 * Prints the names of the all the xml elements 478 void update_preview(int row);
348 * that are siblings or children of a given xml node479 void on_list_results_cursor_changed();
349 */480
350 void print_xml_element_names(xmlNode * a_node);481 void download_resource(ResourceType type, int row);
482 void on_resource_downloaded(const Glib::RefPtr<Gio::AsyncResult>& result,
483 Glib::RefPtr<Gio::File> file_remote, Glib::ustring path, ResourceType resource);
484 void on_image_downloaded(Glib::ustring path, bool success);
485 void on_thumbnail_downloaded(Glib::ustring path, bool success);
486 void on_list_results_row_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);
487 void on_button_import_clicked();
488 void on_button_close_clicked();
489 void on_button_cancel_clicked();
490 void on_button_search_clicked();
491 void on_entry_search_activated();
492 void on_list_results_selection_changed();
493 void on_xml_file_read(const Glib::RefPtr<Gio::AsyncResult>& result,
494 Glib::RefPtr<Gio::File> xml_file, Glib::ustring xml_uri);
495 void create_temporary_dirs();
496 std::string get_temporary_dir(ResourceType type);
497
351498
352 /**499 /**
353 * The extension to use to write this file500 * The extension to use to write this file
354 */501 */
355 Inkscape::Extension::Extension *extension;502 Inkscape::Extension::Extension *extension;
356503
357}; //FileImportFromOCALDialog504}; //ImportDialog
358505
359506
507} //namespace OCAL
360} //namespace Dialog508} //namespace Dialog
361} //namespace UI509} //namespace UI
362} //namespace Inkscape510} //namespace Inkscape
363511
=== modified file 'src/verbs.cpp'
--- src/verbs.cpp 2011-10-03 03:44:17 +0000
+++ src/verbs.cpp 2011-12-27 21:09:25 +0000
@@ -2192,8 +2192,9 @@
2192 N_("Import a bitmap or SVG image into this document"), INKSCAPE_ICON("document-import")),2192 N_("Import a bitmap or SVG image into this document"), INKSCAPE_ICON("document-import")),
2193 new FileVerb(SP_VERB_FILE_EXPORT, "FileExport", N_("_Export Bitmap..."),2193 new FileVerb(SP_VERB_FILE_EXPORT, "FileExport", N_("_Export Bitmap..."),
2194 N_("Export this document or a selection as a bitmap image"), INKSCAPE_ICON("document-export")),2194 N_("Export this document or a selection as a bitmap image"), INKSCAPE_ICON("document-export")),
2195 new FileVerb(SP_VERB_FILE_IMPORT_FROM_OCAL, "FileImportFromOCAL", N_("Import From Open Clip Art Library"), N_("Import a document from Open Clip Art Library"), INKSCAPE_ICON("document-import-ocal")),2195 new FileVerb(SP_VERB_FILE_IMPORT_FROM_OCAL, "FileImportFromOCAL", N_("Import Clip Art..."),
2196// new FileVerb(SP_VERB_FILE_EXPORT_TO_OCAL, "FileExportToOCAL", N_("Export To Open Clip Art Library"), N_("Export this document to Open Clip Art Library"), INKSCAPE_ICON("document-export-ocal")),2196 N_("Import clipart from Open Clip Art Library"), INKSCAPE_ICON("document-import-ocal")),
2197// new FileVerb(SP_VERB_FILE_EXPORT_TO_OCAL, "FileExportToOCAL", N_("Export To Open Clip Art Library"), N_("Export this document to Open Clip Art Library"), INKSCAPE_ICON_DOCUMENT_EXPORT_OCAL),
2197 new FileVerb(SP_VERB_FILE_NEXT_DESKTOP, "NextWindow", N_("N_ext Window"),2198 new FileVerb(SP_VERB_FILE_NEXT_DESKTOP, "NextWindow", N_("N_ext Window"),
2198 N_("Switch to the next document window"), INKSCAPE_ICON("window-next")),2199 N_("Switch to the next document window"), INKSCAPE_ICON("window-next")),
2199 new FileVerb(SP_VERB_FILE_PREV_DESKTOP, "PrevWindow", N_("P_revious Window"),2200 new FileVerb(SP_VERB_FILE_PREV_DESKTOP, "PrevWindow", N_("P_revious Window"),