diff options
Diffstat (limited to 'rapid')
32 files changed, 8438 insertions, 3187 deletions
diff --git a/rapid/ChangeLog b/rapid/ChangeLog index 96f3d4f..552c77d 100644 --- a/rapid/ChangeLog +++ b/rapid/ChangeLog @@ -1,3 +1,134 @@ +Version 0.3.0 +------------- + +2010-07-10 + +The major new feature of this release is the generation of previews before +a download takes place. You can now select which photos and videos you wish to +download. + +You can now assign different Job Codes to photos and videos in the same +download. Simply select photos and videos, and from the main window choose a Job +Code for them. You can select a new Job Code,or enter a new one (press Enter +to apply it). + +The errors and warnings reported have been completely overhauled, and are now +more concise. + +Now that you can select photos and videos to download, the "Report an error" +option in case of filename conflicts has been removed. If you try to download a +photo or video that already exists, an error will be reported. If you backup a +photo or video that already exists in the backup location, a warning will be +reported (regardless of whether overwriting or skipping of backups with +conflicting filenames is chosen). + +Likewise, the option of whether to report an error or warning in case of missing +backup devices has been removed. If you have chosen to backup your photos and +videos, and a backup device or location is not found, the files will be +downloaded with warnings. + +For each device in the main window, the progress bar is now updated much more +smoothly than before. This is useful when downloading and backing up large files +such as videos. (Note this is only the case on moderately up-to-date Linux +distributions that use GVFS, such as Ubuntu 8.10 or higher). + +The minimum version of python-gtk2 (pygtk) required to run the program is now +2.12. This will affect only outdated Linux distributions. + + +Version 0.3.0 beta 6 +-------------------- + +2010-07-06 + +Fixed bug #598736: don't allow file to jump to the bottom when it has a Job Code +assigned to it. + +Fixed bug #601993: don't prompt for a Job Code when downloading file of one type +(photo or video), and it's only a file of the other type that needs it. + +Log error messages are now cleaned up where a file already exists and there were +problems generating the file / subfolder name. + +Fixed crash on startup when using an old version of GIO. + +Fix crash in updating the time remaining in when downloading from extremely +slow devices. + +Set the default height to be 50 pixels taller. + +Bug fix: don't download from device that has been inserted after program starts +unless device auto detection is enabled. + +Updated German translation. + + +Version 0.3.0 beta 5 +-------------------- + +2010-07-04 + +Added warning dialog if attempting to download directly from a camera. + +Add backup errors details to error log window. + +Fixed program notifications. + +Fixed corner cases with problematic file and subfolder names. + +Disabled Download All button if all files that have not been downloaded have +errors. + +Enabled and disabled Download All button, depending on status, after subfolder +or filename preferences are modified after device has been scanned. + +Don't stop a file being downloaded if a valid subfolder or filename can be +generated using a Job Code. + +Bug fix: don't automatically exit if there were errors or warnings and a +download was occuring from more than one device. + +Auto start now works correctly again. + +Job Codes are now assigned correctly when multiple downloads occur. + +Default column sorting is by date, unless a warning or error occurs when +doing the initial scan of the devices, in which case it is set to status (unless +you have already clicked on a column heading yourself, in which case it will +not change). + +Use the command xdg-user-dir to get default download directories. + +Updated Czech, Dutch, Finnish, French, Italian, Polish, Russian and Ukrainian +translations. + + +Version 0.3.0 beta 4 +-------------------- + +2010-06-25 + +Fixed bug in Job Code addition in the preferences window. + +Made Job Code entry completion case insensitive. + +Update preview to be the most recently selected photo / video when +multiple files are selected. + +Don't crash when user selects a row that has its status set to be +download pending. + +Improve error log status messages and problem notifications. + + +Version 0.3.0 beta 3 +-------------------- + +2010-06-23 + +First beta release of 0.3.0. + + Version 0.2.3 ------------- diff --git a/rapid/INSTALL b/rapid/INSTALL index 144568d..3967608 100644 --- a/rapid/INSTALL +++ b/rapid/INSTALL @@ -3,18 +3,22 @@ Rapid Photo Downloader depends on the following software: - GNOME 2.18 or higher - GTK+ 2.10 or higher - Python 2.5 or 2.6 -- pygtk 2.10 or higher +- pygtk 2.12 or higher - python-gconf 2.18 or higher -- python-glade2 2.10 or higher -- gnome-python 2.10 or higher +- python-glade2 2.12 or higher +- gnome-python 2.12 or higher - libexiv2 0.15 or higher - pyexiv2 0.1.1 or higher To run Rapid Photo Downloader you will need all the software mentioned above. -A recommended package is exiv2 (not just the library libexiv2), so Rapid Photo -Downloader can determine if it can download additional types of RAW files -(some early versions of exiv2 and pyexiv2 segfault on certain RAW file types). +If you want to see dropshadows around thumbnail images, install python-imaging. +This is optional but recommended. + +A strongly recommended package is exiv2 (not just the library libexiv2), so +Rapid Photo Downloader can determine if it can download additional types of RAW +files (some early versions of exiv2 and pyexiv2 segfault on certain RAW file +types). If you want to download videos, you can install: diff --git a/rapid/common.py b/rapid/common.py index d687049..a55d835 100644 --- a/rapid/common.py +++ b/rapid/common.py @@ -22,6 +22,11 @@ import sys import gc import distutils.version import gtk.gdk as gdk +import gtk +try: + import gio +except: + pass import config @@ -173,6 +178,45 @@ def scale2pixbuf(width_max, height_max, pixbuf, return_size=False): return pixbuf, width_orig, height_orig return pixbuf +def get_icon_pixbuf(using_gio, icon, size, fallback='gtk-harddisk'): + """ returns icon for the volume, or None if not available""" + + icontheme = gtk.icon_theme_get_default() + + if using_gio: + f = None + if isinstance(icon, gio.ThemedIcon): + try: + # on some user's systems, themes do not have icons associated with them + iconinfo = icontheme.choose_icon(icon.get_names(), size, gtk.ICON_LOOKUP_USE_BUILTIN) + f = iconinfo.get_filename() + v = gtk.gdk.pixbuf_new_from_file_at_size(f, size, size) + except: + f = None + if not f: + v = icontheme.load_icon(fallback, size, gtk.ICON_LOOKUP_USE_BUILTIN) + else: + v = icontheme.load_icon(icon, size, gtk.ICON_LOOKUP_USE_BUILTIN) + return v + +def register_iconsets(icon_info): + """ + Register icons in the icon set if they're not already used + + From http://faq.pygtk.org/index.py?req=show&file=faq08.012.htp + """ + + iconfactory = gtk.IconFactory() + stock_ids = gtk.stock_list_ids() + for stock_id, file in icon_info: + # only load image files when our stock_id is not present + if stock_id not in stock_ids: + pixbuf = gtk.gdk.pixbuf_new_from_file(file) + iconset = gtk.IconSet(pixbuf) + iconfactory.add(stock_id, iconset) + iconfactory.add_default() + + if __name__ == '__main__': diff --git a/rapid/config.py b/rapid/config.py index cafcc16..2f0e1e3 100644 --- a/rapid/config.py +++ b/rapid/config.py @@ -15,7 +15,7 @@ ### along with this program; if not, write to the Free Software ### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -version = '0.2.3' +version = '0.3.0' GCONF_KEY="/apps/rapid-photo-downloader" GLADE_FILE = "glade3/rapid.glade" @@ -30,11 +30,9 @@ MEDIA_LOCATION = "/media" SKIP_DOWNLOAD = "skip download" ADD_UNIQUE_IDENTIFIER = "add unique identifier" -REPORT_WARNING = "warning" -REPORT_ERROR = "error" -IGNORE = "ignore" - -DEFAULT_PHOTO_LOCATIONS = ['Pictures', 'Photos'] +# These next three values are fall back values that are used only +# if calls to xdg-user-dir fail +DEFAULT_PHOTO_LOCATIONS = ['Pictures', 'Photos'] DEFAULT_BACKUP_LOCATION = 'Pictures' DEFAULT_VIDEO_BACKUP_LOCATION = 'Videos' @@ -47,8 +45,14 @@ SERIOUS_ERROR = 2 WARNING = 3 MAX_LENGTH_DEVICE_NAME = 15 - -#logging - to be implemented -#LOGFILE_DIRECTORY = '.rapidPhotoDownloader' # relative to home directory -#MAX_LOGFILE_SIZE = 100 * 1024 # bytes -#MAX_LOGFILES = 5 +MAX_THUMBNAIL_SIZE = 160 + +STATUS_DOWNLOAD_PENDING = 0 # going to try to download it +STATUS_DOWNLOADED = 1 # downloaded successfully +STATUS_DOWNLOADED_WITH_WARNING = 2 # downloaded ok but there was a warning +STATUS_BACKUP_PROBLEM = 3 # downloaded ok, but the file was not backed up, or had a problem (overwrite or duplicate) +STATUS_NOT_DOWNLOADED = 4 # has not yet been downloaded (but might be if the user chooses) +STATUS_DOWNLOAD_AND_BACKUP_FAILED = 5 # tried to download but failed, and the backup failed or had an error +STATUS_DOWNLOAD_FAILED = 6 # tried to download but failed +STATUS_WARNING = 7 # warning (shown in pre-download preview) +STATUS_CANNOT_DOWNLOAD = 8 # cannot be downloaded diff --git a/rapid/dropshadow.py b/rapid/dropshadow.py new file mode 100755 index 0000000..fd7cf99 --- /dev/null +++ b/rapid/dropshadow.py @@ -0,0 +1,174 @@ +#!/usr/bin/python + + +import StringIO +import gtk +from PIL import Image, ImageFilter + +def image_to_pixbuf(image): + # this one handles transparency, unlike the default example in the pygtk FAQ + # this is also from the pygtk FAQ + IS_RGBA = image.mode=='RGBA' + return gtk.gdk.pixbuf_new_from_data( + image.tostring(), # data + gtk.gdk.COLORSPACE_RGB, # color mode + IS_RGBA, # has alpha + 8, # bits + image.size[0], # width + image.size[1], # height + (IS_RGBA and 4 or 3) * image.size[0] # rowstride + ) + + +def image_to_pixbuf_no_transparency(image): + fd = StringIO.StringIO() + image.save(fd, "ppm") + contents = fd.getvalue() + fd.close() + loader = gtk.gdk.PixbufLoader("pnm") + loader.write(contents, len(contents)) + pixbuf = loader.get_pixbuf() + loader.close() + return pixbuf + +def pixbuf_to_image(pb): + assert(pb.get_colorspace() == gtk.gdk.COLORSPACE_RGB) + dimensions = pb.get_width(), pb.get_height() + stride = pb.get_rowstride() + pixels = pb.get_pixels() + mode = pb.get_has_alpha() and "RGBA" or "RGB" + return Image.frombuffer(mode, dimensions, pixels, + "raw", mode, stride, 1) + + +class DropShadow(): + """ + Adds a gaussian blur drop shadow to a PIL image. + + Caches backgrounds of particular sizes for improved performance. + + Backgrounds can be made transparent. + + Modification of code from Kevin Schluff and Matimus + License: Python license + See: + http://code.activestate.com/recipes/474116/ (r2) + http://bytes.com/topic/python/answers/606952-pil-paste-image-top-other-dropshadow + + """ + + def __init__(self, offset=(5,5), background_color=0xffffff, shadow = (0x44, 0x44, 0x44, 0xff), + border=8, iterations=3, trim_border=False): + """ + offset - Offset of the shadow from the image as an (x,y) tuple. Can be + positive or negative. + background_color - Background colour behind the image. + shadow - Shadow colour (darkness). + border - Width of the border around the image. This must be wide + enough to account for the blurring of the shadow. + trim_border - If true, the border will only be created on the + sides it needs to be (i.e. only on two sides) + iterations - Number of times to apply the filter. More iterations + produce a more blurred shadow, but increase processing time. + + To make backgrounds transparent, ensure the alpha value of the shadow color is the + same as the background color, e.g. if background_color is 0xffffff, shadow's alpha should be 0xff + """ + self.backgrounds = {} + self.offset = offset + self.background_color = background_color + self.shadow = shadow + self.border = border + self.trim_border = trim_border + self.iterations = iterations + + if self.offset[0] < 0 or not self.trim_border: + self.left_spacing = self.border + else: + self.left_spacing = 0 + + if self.offset[1] < 0 or not self.trim_border: + self.top_spacing = self.border + else: + self.top_spacing = 0 + + + def dropShadow(self, image): + """ + image - The image to overlay on top of the shadow. + """ + dimensions = (image.size[0], image.size[1]) + if not dimensions in self.backgrounds: + + # Create the backdrop image -- a box in the background colour with a + # shadow on it. + + if self.trim_border: + totalWidth = image.size[0] + abs(self.offset[0]) + self.border + totalHeight = image.size[1] + abs(self.offset[1]) + self.border + else: + totalWidth = image.size[0] + abs(self.offset[0]) + 2 * self.border + totalHeight = image.size[1] + abs(self.offset[1]) + 2 * self.border + + back = Image.new("RGBA", (totalWidth, totalHeight), self.background_color) + + # Place the shadow, taking into account the offset from the image + if self.offset[0] > 0 and self.trim_border: + shadowLeft = max(self.offset[0], 0) + else: + shadowLeft = self.border + max(self.offset[0], 0) + if self.offset[1] > 0 and self.trim_border: + shadowTop = max(self.offset[1], 0) + else: + shadowTop = self.border + max(self.offset[1], 0) + + back.paste(self.shadow, [shadowLeft, shadowTop, shadowLeft + image.size[0], + shadowTop + image.size[1]] ) + + # Apply the filter to blur the edges of the shadow. Since a small kernel + # is used, the filter must be applied repeatedly to get a decent blur. + n = 0 + while n < self.iterations: + back = back.filter(ImageFilter.BLUR) + n += 1 + + self.backgrounds[dimensions] = back + + # Paste the input image onto the shadow backdrop + imageLeft = self.left_spacing - min(self.offset[0], 0) + imageTop = self.top_spacing - min(self.offset[1], 0) + + back = self.backgrounds[dimensions].copy() + back.paste(image, (imageLeft, imageTop)) + + return back + + + +if __name__ == "__main__": + import sys + import os + import common + + + # create another file with a drop shadow + f = sys.argv[1] + + image = Image.open(f) + image.thumbnail((60,36), Image.ANTIALIAS) + image2 = image.copy() + + path, name = os.path.split(f) + name, ext = os.path.splitext(name) + + #image = dropShadow(image, shadow = (0x44, 0x44, 0x44, 0xff)) + dropShadow = DropShadow(offset=(3,3), shadow = (0x34, 0x34, 0x34, 0xff), border=6) + image = dropShadow.dropShadow(image) + image2 = dropShadow.dropShadow(image2) + + nf = os.path.join(path, "%s_small_shadow%s" % (name, ext)) + nf2 = os.path.join(path, "%s_small_shadow2%s" % (name, ext)) + image.save(nf) + image2.save(nf2) + print "wrote %s , %s" % (nf, nf2) + diff --git a/rapid/filmstrip.py b/rapid/filmstrip.py new file mode 100755 index 0000000..275fd1d --- /dev/null +++ b/rapid/filmstrip.py @@ -0,0 +1,117 @@ +#!/usr/bin/python +# -*- coding: latin1 -*- + +### Copyright (C) 2010 Damon Lynch <damonlynch@gmail.com> + +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. + +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. + +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software +### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Adds a filmstrip to the left and right of a file +""" + +import gtk + + +xpm_data = [ +"12 10 27 1", +" c #000000", +". c #232323", +"+ c #7A7A7A", +"@ c #838383", +"# c #8C8C8C", +"$ c #909090", +"% c #8E8E8E", +"& c #525252", +"* c #6E6E6E", +"= c #939393", +"- c #A3A3A3", +"; c #ABABAB", +"> c #A8A8A8", +", c #9B9B9B", +"' c #727272", +") c #A4A4A4", +"! c #BBBBBB", +"~ c #C4C4C4", +"{ c #C1C1C1", +"] c #AFAFAF", +"^ c #3E3E3E", +"/ c #A6A6A6", +"( c #BEBEBE", +"_ c #C8C8C8", +": c #070707", +"< c #090909", +"[ c #0A0A0A", +" ", +" ", +" ", +" .+@#$%& ", +" *@=-;>, ", +" '%)!~{] ", +" ^$/(_~% ", +" :<[[[ ", +" ", +" "] + + +def add_filmstrip(pixbuf): + """ + Adds a filmstrip to the left and right of a pixbuf + + Returns a pixbuf + + """ + filmstrip = gtk.gdk.pixbuf_new_from_xpm_data(xpm_data) + filmstrip_width = filmstrip.get_width() + filmstrip_height = filmstrip.get_height() + filmstrip_right = filmstrip.flip(True) + + + original = pixbuf + original_height = original.get_height() + thumbnail_width = original.get_width() + filmstrip_width * 2 + thumbnail_right_col = original.get_width() + filmstrip_width + + thumbnail = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, thumbnail_width, original.get_height()) + + #add filmstrips to left and right + for i in range(original_height / filmstrip_height): + filmstrip.copy_area(0, 0, filmstrip_width, filmstrip_height, thumbnail, 0, i * filmstrip_height) + filmstrip_right.copy_area(0, 0, filmstrip_width, filmstrip_height, thumbnail, thumbnail_right_col, i * filmstrip_height) + + #now do the remainder, at the bottom + remaining_height = original_height % filmstrip_height + if remaining_height: + filmstrip.copy_area(0, 0, filmstrip_width, remaining_height, thumbnail, 0, original_height-remaining_height) + filmstrip_right.copy_area(0, 0, filmstrip_width, remaining_height, thumbnail, thumbnail_right_col, original_height-remaining_height) + + if original.get_has_alpha(): + thumbnail = thumbnail.add_alpha(False, 0,0,0) + #copy in the original image + original.copy_area(0, 0, original.get_width(), original_height, thumbnail, filmstrip_width, 0) + + return thumbnail + + +if __name__ == '__main__': + import sys + + + if (len(sys.argv) != 2): + print 'Usage: ' + sys.argv[0] + ' path/to/photo/image' + + else: + p = gtk.gdk.pixbuf_new_from_file(sys.argv[1]) + p2 = add_filmstrip(p) + p2.save('testing.png', 'png') diff --git a/rapid/glade3/filmstrip-100x75.xpm b/rapid/glade3/filmstrip-100x75.xpm deleted file mode 100644 index 5e3428e..0000000 --- a/rapid/glade3/filmstrip-100x75.xpm +++ /dev/null @@ -1,106 +0,0 @@ -/* XPM */ -static char * thumbnail_100x75_xpm[] = { -"100 75 28 1", -" c None", -". c #000000", -"+ c #232323", -"@ c #7A7A7A", -"# c #838383", -"$ c #8C8C8C", -"% c #909090", -"& c #8E8E8E", -"* c #525252", -"= c #6E6E6E", -"- c #939393", -"; c #A3A3A3", -"> c #ABABAB", -", c #A8A8A8", -"' c #9B9B9B", -") c #727272", -"! c #A4A4A4", -"~ c #BBBBBB", -"{ c #C4C4C4", -"] c #C1C1C1", -"^ c #AFAFAF", -"/ c #3E3E3E", -"( c #A6A6A6", -"_ c #BEBEBE", -": c #C8C8C8", -"< c #070707", -"[ c #090909", -"} c #0A0A0A", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+....", -"....=#-;>,'. .',>;-#=....", -"....)&!~{]^. .^]{~!&)....", -"..../%(_:{&. .&{:_(%/....", -".....<[}}}.. ..}}}[<.....", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"............ ............", -"....+@#$%&*. .*&%$#@+...."}; diff --git a/rapid/glade3/image-missing.svg b/rapid/glade3/image-missing.svg deleted file mode 100644 index 4351feb..0000000 --- a/rapid/glade3/image-missing.svg +++ /dev/null @@ -1,94 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="48px" height="48px" id="svg1306" sodipodi:version="0.32" inkscape:version="0.45" sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/status" sodipodi:docname="image-missing.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs id="defs1308"> - <linearGradient inkscape:collect="always" id="linearGradient6346"> - <stop style="stop-color: rgb(85, 87, 83); stop-opacity: 1;" offset="0" id="stop6348"/> - <stop style="stop-color: rgb(46, 52, 54); stop-opacity: 1;" offset="1" id="stop6350"/> - </linearGradient> - <linearGradient inkscape:collect="always" id="linearGradient5060"> - <stop style="stop-color: black; stop-opacity: 1;" offset="0" id="stop5062"/> - <stop style="stop-color: black; stop-opacity: 0;" offset="1" id="stop5064"/> - </linearGradient> - <linearGradient id="linearGradient5048"> - <stop style="stop-color: black; stop-opacity: 0;" offset="0" id="stop5050"/> - <stop id="stop5056" offset="0.5" style="stop-color: black; stop-opacity: 1;"/> - <stop style="stop-color: black; stop-opacity: 0;" offset="1" id="stop5052"/> - </linearGradient> - <linearGradient inkscape:collect="always" id="linearGradient6431"> - <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop6433"/> - <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop6435"/> - </linearGradient> - <linearGradient inkscape:collect="always" id="linearGradient6390"> - <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop6392"/> - <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop6394"/> - </linearGradient> - <linearGradient id="linearGradient6374"> - <stop style="stop-color: rgb(85, 87, 83); stop-opacity: 1;" offset="0" id="stop6376"/> - <stop style="stop-color: rgb(136, 138, 133); stop-opacity: 1;" offset="1" id="stop6378"/> - </linearGradient> - <linearGradient id="linearGradient6366"> - <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop6368"/> - <stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop6370"/> - </linearGradient> - <linearGradient id="linearGradient6327"> - <stop style="stop-color: rgb(136, 138, 133); stop-opacity: 1;" offset="0" id="stop6329"/> - <stop style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" offset="1" id="stop6331"/> - </linearGradient> - <linearGradient inkscape:collect="always" xlink:href="#linearGradient6327" id="linearGradient6333" x1="42.999424" y1="36.811924" x2="40.621296" y2="34.433796" gradientUnits="userSpaceOnUse"/> - <linearGradient inkscape:collect="always" xlink:href="#linearGradient6327" id="linearGradient6360" x1="61.18124" y1="137.97644" x2="20.420683" y2="2.6749926" gradientUnits="userSpaceOnUse"/> - <linearGradient inkscape:collect="always" xlink:href="#linearGradient6366" id="linearGradient6372" x1="38.908649" y1="35.960426" x2="35.032925" y2="30.679369" gradientUnits="userSpaceOnUse"/> - <radialGradient inkscape:collect="always" xlink:href="#linearGradient6374" id="radialGradient6382" cx="39.437065" cy="34.33852" fx="39.437065" fy="34.33852" r="6" gradientTransform="matrix(0.1875, -1.05343, 0.718081, 0.127811, 7.82271, 71.0304)" gradientUnits="userSpaceOnUse"/> - <radialGradient inkscape:collect="always" xlink:href="#linearGradient6390" id="radialGradient6396" cx="20.236877" cy="25.043303" fx="20.236877" fy="25.043303" r="22" gradientTransform="matrix(0.940906, -0.20665, 0.109821, 0.50003, -1.55441, 13.2196)" gradientUnits="userSpaceOnUse"/> - <radialGradient inkscape:collect="always" xlink:href="#linearGradient6431" id="radialGradient6437" cx="40.179535" cy="34.080399" fx="40.179535" fy="34.080399" r="4.125" gradientTransform="matrix(1, 0, 0, 0.935606, 0, 2.30711)" gradientUnits="userSpaceOnUse"/> - <radialGradient inkscape:collect="always" xlink:href="#linearGradient5060" id="radialGradient6909" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.0160648, 0, 0, 0.0741176, 11.6816, -1.17508)" cx="605.71429" cy="486.64789" fx="605.71429" fy="486.64789" r="117.14286"/> - <radialGradient inkscape:collect="always" xlink:href="#linearGradient5060" id="radialGradient6912" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.104421, 0, 0, 0.0741176, -27.9305, -1.17508)" cx="605.71429" cy="486.64789" fx="605.71429" fy="486.64789" r="117.14286"/> - <linearGradient inkscape:collect="always" xlink:href="#linearGradient5048" id="linearGradient6915" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.0683432, 0, 0, 0.0741176, -6.20118, -1.17508)" x1="302.85715" y1="366.64789" x2="302.85715" y2="609.50507"/> - <radialGradient inkscape:collect="always" xlink:href="#linearGradient6346" id="radialGradient6352" cx="24.013514" cy="39.717846" fx="24.013514" fy="39.717846" r="20.013513" gradientTransform="matrix(2.00322, 0, 0, 1.45136, -24.0909, -22.3947)" gradientUnits="userSpaceOnUse"/> - </defs> - <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1" inkscape:cx="50.321592" inkscape:cy="19.160509" inkscape:current-layer="layer1" showgrid="false" inkscape:grid-bbox="true" inkscape:document-units="px" fill="#fcaf3e" stroke="#555753" showguides="true" inkscape:guide-bbox="false" inkscape:window-width="895" inkscape:window-height="760" inkscape:window-x="208" inkscape:window-y="229" inkscape:showpageshadow="false" showborder="false" gridspacingx="0.5px" gridspacingy="0.5px" gridempspacing="2" inkscape:grid-points="false" gridtolerance="50" inkscape:object-paths="false"/> - <metadata id="metadata1311"> - <rdf:RDF> - <cc:Work rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> - <dc:title>Generic Image</dc:title> - <dc:creator> - <cc:Agent> - <dc:title>Lapo Calamandrei</dc:title> - </cc:Agent> - </dc:creator> - <dc:source>http://www.gnome.org</dc:source> - <dc:contributor> - <cc:Agent> - <dc:title>Jakub Steiner, Andreas Nilsson</dc:title> - </cc:Agent> - </dc:contributor> - <cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/"/> - </cc:Work> - <cc:License rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> - <cc:permits rdf:resource="http://web.resource.org/cc/Reproduction"/> - <cc:permits rdf:resource="http://web.resource.org/cc/Distribution"/> - <cc:requires rdf:resource="http://web.resource.org/cc/Notice"/> - <cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/> - <cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike"/> - <cc:requires rdf:resource="http://web.resource.org/cc/SourceCode"/> - </cc:License> - </rdf:RDF> - </metadata> - <g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer"> - <g id="g6917"> - <rect y="26" x="2" height="18" width="33" id="rect6057" style="overflow: visible; marker: none; opacity: 0.39196; color: rgb(0, 0, 0); fill: url(#linearGradient6915) rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 1; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1; visibility: visible; display: inline;"/> - <path sodipodi:nodetypes="ccscc" id="path6059" d="M 35,26.00062 C 35,26.00062 35,43.999627 35,43.999627 C 37.30962,44.01418 40.033409,43.272315 42.389531,42.027493 C 45.519106,40.37403 48.000002,37.833194 48,34.998965 C 48,30.030967 41.999197,26.000621 35,26.00062 z " style="overflow: visible; marker: none; opacity: 0.402062; color: rgb(0, 0, 0); fill: url(#radialGradient6912) rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 1; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1; visibility: visible; display: inline;"/> - <path style="overflow: visible; marker: none; opacity: 0.402062; color: rgb(0, 0, 0); fill: url(#radialGradient6909) rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 1; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1; visibility: visible; display: inline;" d="M 2,26.00062 C 2,26.00062 2,43.999627 2,43.999627 C 1.172704,44.03351 1.3577825e-06,39.966963 1.3577825e-06,34.998965 C 1.3577825e-06,30.030967 0.92320113,26.000621 2,26.00062 z " id="path6061" sodipodi:nodetypes="cccc"/> - </g> - <path style="fill: url(#linearGradient6360) rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(136, 138, 133); stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1;" d="M 2.767767,6.5 L 45.232237,6.5 C 45.93458,6.5 46.500004,7.0654241 46.500004,7.767767 L 46.5,30.5 C 46.5,31.202343 36.202343,40.5 35.5,40.5 L 2.767767,40.5 C 2.0654241,40.5 1.5,39.934576 1.5,39.232233 L 1.5,7.767767 C 1.5,7.0654241 2.0654241,6.5 2.767767,6.5 z " id="rect5350" sodipodi:nodetypes="ccccccccc"/> - <path style="fill: url(#radialGradient6352) rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(136, 138, 133); stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1;" d="M 4.9874617,9.5 L 43.039565,9.5 C 43.309619,9.5 43.527027,9.7276458 43.527027,10.010417 L 43.527027,33.989583 L 40.039565,37.5 L 4.9874617,37.5 C 4.7174079,37.5 4.5,37.272354 4.5,36.989583 L 4.5,10.010417 C 4.5,9.7276458 4.7174079,9.5 4.9874617,9.5 z " id="rect2063" sodipodi:nodetypes="ccccccccc"/> - <path style="opacity: 0.172414; fill: url(#linearGradient6372) rgb(0, 0, 0); fill-opacity: 1; stroke: none; stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1;" d="M 14.78125,40 L 35.40625,40 C 35.41645,39.995518 35.423208,39.996022 35.46875,39.96875 C 35.559833,39.914206 35.707858,39.809986 35.875,39.6875 C 36.209283,39.442528 36.659837,39.093896 37.1875,38.65625 C 38.242827,37.780957 39.61066,36.608491 40.9375,35.40625 C 42.26434,34.204009 43.563777,32.96157 44.53125,32 C 45.014987,31.519215 45.417906,31.118778 45.6875,30.8125 C 45.822297,30.659361 45.910802,30.519277 45.96875,30.4375 C 45.983237,30.417056 45.991685,30.419536 46,30.40625 L 46,13.78125 L 14.78125,40 z " id="path6364" sodipodi:nodetypes="ccsssssssccc"/> - <path style="fill: none; fill-opacity: 1; stroke: rgb(255, 255, 255); stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1;" d="M 2.78125,7.5 C 2.6253137,7.5 2.5,7.6253137 2.5,7.78125 L 2.5,39.21875 C 2.5,39.374686 2.6253136,39.5 2.78125,39.5 L 37.28125,39.5 C 40.921301,36.704635 42.365769,35.606734 45.5,32.25 L 45.5,7.78125 C 45.5,7.6253155 45.374683,7.5 45.21875,7.5 L 2.78125,7.5 z " id="path6351" sodipodi:nodetypes="ccccccccc"/> - <path style="fill: url(#linearGradient6333) rgb(0, 0, 0); fill-rule: evenodd; stroke: url(#radialGradient6382) rgb(0, 0, 0); stroke-width: 1px; stroke-linecap: butt; stroke-linejoin: round; stroke-opacity: 1; fill-opacity: 1;" d="M 46.5,30.5 C 46.5,35.5 40.5,40.5 35.5,40.5 C 35.5,40.5 39.932134,38.33738 39.5,33.5 C 43.879686,33.916135 46.5,30.5 46.5,30.5 z " id="path6322" sodipodi:nodetypes="cccc"/> - <path style="fill: url(#radialGradient6437) rgb(0, 0, 0); fill-opacity: 1; fill-rule: evenodd; stroke: none; stroke-width: 1px; stroke-linecap: butt; stroke-linejoin: round; stroke-opacity: 1; opacity: 0.732759;" d="M 45.71875 31.96875 C 44.577589 32.932531 42.679856 34.08934 40.03125 34.03125 C 40.059733 36.774444 38.699098 38.58751 37.46875 39.6875 C 38.953141 38.706251 40.825166 37.371805 41.03125 35.03125 C 43.192381 35.027997 44.619214 33.310655 45.6875 32.03125 C 45.693038 32.009581 45.713422 31.990426 45.71875 31.96875 z " id="path6339"/> - <path style="fill: url(#radialGradient6396) rgb(0, 0, 0); fill-opacity: 1; stroke: none; stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1; opacity: 0.344828;" d="M 2.78125,7 C 2.3536576,7 2,7.3536576 2,7.78125 L 2,31.09375 C 14.714701,22.184679 34.055102,15.625228 46,19.3125 L 46,7.78125 C 46,7.3536585 45.64634,7 45.21875,7 L 2.78125,7 z " id="path6384" sodipodi:nodetypes="ccccccc"/> - <path sodipodi:type="inkscape:offset" inkscape:radius="-1" inkscape:original="M 2.78125 6.5 C 2.0789071 6.5 1.5 7.0789071 1.5 7.78125 L 1.5 39.21875 C 1.5 39.921093 2.0789071 40.5 2.78125 40.5 L 35.5 40.5 C 40.5 40.5 46.5 35.5 46.5 30.5 L 46.5 7.78125 C 46.5 7.0789071 45.921091 6.5 45.21875 6.5 L 2.78125 6.5 z " style="fill: none; fill-opacity: 1; stroke: rgb(255, 255, 255); stroke-width: 1; stroke-linecap: round; stroke-linejoin: round; stroke-miterlimit: 4; stroke-dashoffset: 0pt; stroke-opacity: 1; opacity: 0.418103;" id="path6427" d="M 2.78125,7.5 C 2.628408,7.5 2.5,7.628408 2.5,7.78125 L 2.5,39.21875 C 2.5,39.371592 2.6284079,39.5 2.78125,39.5 L 35.5,39.5 C 37.666667,39.5 40.249358,38.362698 42.21875,36.625 C 44.188142,34.887302 45.5,32.6 45.5,30.5 L 45.5,7.78125 C 45.5,7.6284098 45.371589,7.5 45.21875,7.5 L 2.78125,7.5 z "/> - </g> -</svg>
\ No newline at end of file diff --git a/rapid/glade3/photo.png b/rapid/glade3/photo.png Binary files differnew file mode 100644 index 0000000..87cfc2a --- /dev/null +++ b/rapid/glade3/photo.png diff --git a/rapid/glade3/photo24.png b/rapid/glade3/photo24.png Binary files differnew file mode 100644 index 0000000..53b2271 --- /dev/null +++ b/rapid/glade3/photo24.png diff --git a/rapid/glade3/photo_shadow.png b/rapid/glade3/photo_shadow.png Binary files differnew file mode 100644 index 0000000..0053ba0 --- /dev/null +++ b/rapid/glade3/photo_shadow.png diff --git a/rapid/glade3/photo_small_shadow.png b/rapid/glade3/photo_small_shadow.png Binary files differnew file mode 100644 index 0000000..fe85cd9 --- /dev/null +++ b/rapid/glade3/photo_small_shadow.png diff --git a/rapid/glade3/rapid-photo-downloader-about.png b/rapid/glade3/rapid-photo-downloader-about.png Binary files differdeleted file mode 100644 index 0aefb1d..0000000 --- a/rapid/glade3/rapid-photo-downloader-about.png +++ /dev/null diff --git a/rapid/glade3/rapid-photo-downloader-download-pending.svg b/rapid/glade3/rapid-photo-downloader-download-pending.svg new file mode 100644 index 0000000..d6127b7 --- /dev/null +++ b/rapid/glade3/rapid-photo-downloader-download-pending.svg @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="16" + height="16" + id="svg4136" + inkscape:version="0.47 r22583" + sodipodi:docname="rapid-photo-downloader-image-loading.svg"> + <metadata + id="metadata33"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1089" + id="namedview31" + showgrid="false" + inkscape:zoom="9.8333333" + inkscape:cx="12" + inkscape:cy="12" + inkscape:window-x="0" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:current-layer="svg4136" /> + <defs + id="defs4138"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 12 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="24 : 12 : 1" + inkscape:persp3d-origin="12 : 8 : 1" + id="perspective35" /> + <linearGradient + id="linearGradient8838"> + <stop + id="stop8840" + style="stop-color:black;stop-opacity:1" + offset="0" /> + <stop + id="stop8842" + style="stop-color:black;stop-opacity:0" + offset="1" /> + </linearGradient> + <radialGradient + cx="62.625" + cy="4.625" + r="10.625" + fx="62.625" + fy="4.625" + id="radialGradient5323" + xlink:href="#linearGradient8838" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.341176,0,3.047059)" /> + <linearGradient + id="linearGradient5354"> + <stop + id="stop5356" + style="stop-color:#3f3f3f;stop-opacity:1" + offset="0" /> + <stop + id="stop5358" + style="stop-color:black;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + x1="19.176617" + y1="13.479795" + x2="19.176617" + y2="45.358662" + id="linearGradient5130" + xlink:href="#linearGradient5354" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.4916775,0,0,0.4916774,0.6986745,-0.3018277)" /> + <linearGradient + id="linearGradient37935"> + <stop + id="stop37937" + style="stop-color:#929292;stop-opacity:1" + offset="0" /> + <stop + id="stop37939" + style="stop-color:#4a4a4a;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + x1="28.771276" + y1="12.91806" + x2="28.771276" + y2="45.347591" + id="linearGradient5128" + xlink:href="#linearGradient37935" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.4916775,0,0,0.4916774,0.6986745,-0.3018277)" /> + <linearGradient + id="linearGradient2145"> + <stop + id="stop2147" + style="stop-color:#fffffd;stop-opacity:1" + offset="0" /> + <stop + id="stop2149" + style="stop-color:#cbcbc9;stop-opacity:1" + offset="1" /> + </linearGradient> + <radialGradient + cx="11.901996" + cy="10.045444" + r="29.292715" + fx="11.901996" + fy="10.045444" + id="radialGradient5350" + xlink:href="#linearGradient2145" + gradientUnits="userSpaceOnUse" /> + </defs> + <g + id="layer1" + transform="matrix(0.652174,0,0,0.65491337,-0.15217376,0.2820791)"> + <path + d="m 73.25,4.625 a 10.625,3.625 0 1 1 -21.25,0 10.625,3.625 0 1 1 21.25,0 z" + transform="matrix(1.0823528,0,0,1.2906765,-55.282346,13.351919)" + id="path2774" + style="opacity:0.56043958;fill:url(#radialGradient5323);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;marker:none;visibility:visible;display:inline;overflow:visible" /> + <path + d="m 12.492145,1.4999735 c -5.5190685,0 -9.9921705,4.473101 -9.9921705,9.9921715 0,5.519069 4.473102,10.007882 9.9921705,10.007881 5.519068,0 10.007887,-4.488812 10.007882,-10.007881 0,-5.5190705 -4.488814,-9.9921715 -10.007882,-9.9921715 z" + id="path2555" + style="fill:url(#linearGradient5128);fill-opacity:1;stroke:url(#linearGradient5130);stroke-width:0.99994898;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" /> + <path + d="m 31.160714,16.910715 a 14.910714,14.910714 0 1 1 -29.8214281,0 14.910714,14.910714 0 1 1 29.8214281,0 z" + transform="matrix(0.5700599,0,0,0.5700599,3.2365269,1.8598792)" + id="path35549" + style="fill:url(#radialGradient5350);fill-opacity:1;fill-rule:evenodd;stroke:none" /> + <path + d="m 12.5,6.4999999 c 0,-1.3926725 0,-1.5690116 0,-1.5690116" + id="path2308" + style="fill:#1f1f1f;fill-opacity:1;fill-rule:evenodd;stroke:#727272;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="M 12.194529,11.713855 17.596253,6.3122524" + id="path2312" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="M 13.071561,11.753718 9.4637681,8.1460064" + id="path2314" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="M 12.314125,11.434805 18.465311,9.7866365" + id="path2316" + style="fill:#ff0000;fill-rule:evenodd;stroke:#ff0000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 12.5,18.284507 c 0,-1.392673 0,-1.569012 0,-1.569012" + id="path5368" + style="fill:#121212;fill-opacity:1;fill-rule:evenodd;stroke:#121212;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 17.5,11.5 c 1.392673,0 1.569013,0 1.569013,0" + id="path5370" + style="fill:#1f1f1f;fill-opacity:1;fill-rule:evenodd;stroke:#1f1f1f;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + <path + d="m 5.7331351,11.5 c 1.3613563,0 1.5337301,0 1.5337301,0" + id="path5372" + style="fill:#1f1f1f;fill-opacity:1;fill-rule:evenodd;stroke:#5f5f5f;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + </g> +</svg> diff --git a/rapid/glade3/rapid-photo-downloader-downloaded-with-error.svg b/rapid/glade3/rapid-photo-downloader-downloaded-with-error.svg new file mode 100644 index 0000000..74f13e3 --- /dev/null +++ b/rapid/glade3/rapid-photo-downloader-downloaded-with-error.svg @@ -0,0 +1,350 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="16" + height="16" + id="svg2" + inkscape:version="0.47 r22583" + sodipodi:docname="downloaded-with-error.svg"> + <metadata + id="metadata64"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1089" + id="namedview62" + showgrid="false" + inkscape:zoom="51.5" + inkscape:cx="4.0485437" + inkscape:cy="8" + inkscape:window-x="0" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /> + <defs + id="defs4"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="16 : 8 : 1" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + id="perspective66" /> + <linearGradient + id="linearGradient4168"> + <stop + id="stop3652" + style="stop-color:#ee8b68;stop-opacity:1;" + offset="0" /> + <stop + id="stop4172" + style="stop-color:#a71d3a;stop-opacity:1;" + offset="1" /> + </linearGradient> + <linearGradient + x1="28.314739" + y1="20.709501" + x2="0.81572169" + y2="20.709501" + id="linearGradient3374" + xlink:href="#linearGradient4168" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,-0.319447,-0.313352,0,15.561474,13.08587)" /> + <linearGradient + x1="53.99139" + y1="87.89592" + x2="53.99139" + y2="104.28131" + id="linearGradient8226" + xlink:href="#linearGradient2215-9-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.1242128,0,0,0.1863981,0.233129,-3.9907482)" /> + <linearGradient + x1="7.0625" + y1="35.28125" + x2="24.6875" + y2="35.28125" + id="linearGradient8223" + xlink:href="#linearGradient6309-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.5545779,0,0,0.35955055,-1.6911436,1.3146057)" /> + <linearGradient + x1="12.277412" + y1="37.205811" + x2="12.221823" + y2="33.758667" + id="linearGradient8220" + xlink:href="#linearGradient4236-0-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.5545779,0,0,0.35955055,-2.132306,1.7913054)" /> + <linearGradient + x1="4.6104097" + y1="11.320717" + x2="2.2246289" + y2="6.8646717" + id="linearGradient8217" + xlink:href="#linearGradient3484-2-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.6451613,0,0,0.9797594,0.258064,-6.7257265)" /> + <radialGradient + cx="4.1993008" + cy="2.3117516" + r="7.9999995" + fx="4.1993008" + fy="2.3117516" + id="radialGradient8215" + xlink:href="#linearGradient7056-0-9" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1767008,1.0376968,-0.76927742,0.87232541,1.0363585,-3.2771526)" /> + <radialGradient + cx="141.74666" + cy="206.42612" + r="78.728165" + fx="141.74666" + fy="206.42612" + id="radialGradient8211" + xlink:href="#linearGradient4035-5" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.12708936,-0.00212891,9.4059438e-4,0.12249323,-10.298148,-14.500064)" /> + <radialGradient + cx="142.62215" + cy="191.85428" + r="78.728165" + fx="142.62215" + fy="191.85428" + id="radialGradient8208" + xlink:href="#linearGradient4035-5" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.06165082,0,0,-0.0653716,-1.0370648,17.524179)" /> + <radialGradient + cx="24" + cy="42" + r="21" + fx="24" + fy="42" + id="radialGradient8201" + xlink:href="#linearGradient6310-8-2" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.33333332,0,0,0.14285711,6.5e-7,8.0000015)" /> + <radialGradient + cx="127.31733" + cy="143.82751" + r="78.728165" + fx="127.31733" + fy="143.82751" + id="radialGradient8198" + xlink:href="#linearGradient8105" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.04179653,-0.01388393,0.00338688,0.03797545,-0.54190607,-0.79595187)" /> + <linearGradient + id="linearGradient6310-8-2"> + <stop + id="stop6312-6-2" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop6314-6-0" + style="stop-color:#ffffff;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3484-2-0"> + <stop + id="stop3486-2-4" + style="stop-color:#969696;stop-opacity:1" + offset="0" /> + <stop + id="stop3488-0-2" + style="stop-color:#b4b4b4;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient7056-0-9"> + <stop + id="stop7064-4-6" + style="stop-color:#e6e6e6;stop-opacity:1" + offset="0" /> + <stop + id="stop7060-2-1" + style="stop-color:#c8c8c8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient2215-9-0"> + <stop + id="stop2223-6-4" + style="stop-color:#7a7a7a;stop-opacity:1" + offset="0" /> + <stop + id="stop2219-1-2" + style="stop-color:#474747;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient4035-5"> + <stop + id="stop4037-8" + style="stop-color:#f5f5f5;stop-opacity:1" + offset="0" /> + <stop + id="stop4039-7" + style="stop-color:#e7e7e7;stop-opacity:1" + offset="0.47025558" /> + <stop + id="stop4041-0" + style="stop-color:#8c8c8c;stop-opacity:1" + offset="0.69348532" /> + <stop + id="stop4043-4" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.83542866" /> + <stop + id="stop4045-8" + style="stop-color:#a8a8a8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient6309-1"> + <stop + id="stop6311-0" + style="stop-color:#000000;stop-opacity:1" + offset="0" /> + <stop + id="stop6313-7" + style="stop-color:#bbbbbb;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient4236-0-1"> + <stop + id="stop4238-4-4" + style="stop-color:#eeeeee;stop-opacity:1" + offset="0" /> + <stop + id="stop4240-3-9" + style="stop-color:#eeeeee;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient8105"> + <stop + id="stop8107" + style="stop-color:#f5f5f5;stop-opacity:1" + offset="0" /> + <stop + id="stop8109" + style="stop-color:#e7e7e7;stop-opacity:1" + offset="0.25027597" /> + <stop + id="stop8111" + style="stop-color:#8c8c8c;stop-opacity:1" + offset="0.69348532" /> + <stop + id="stop8113" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.83542866" /> + <stop + id="stop8115" + style="stop-color:#a8a8a8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4168" + id="linearGradient3656" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,-0.319447,-0.313352,0,15.561474,13.08587)" + x1="28.314739" + y1="20.709501" + x2="0.81572169" + y2="20.709501" /> + </defs> + <g + id="g3119"> + <path + d="m 15.49723,12.5 c -0.304165,2.535038 -0.22639,2.983925 -0.777167,2.983925 -0.21573,0.03617 -8.698317,0 -13.470165,0 -0.598135,0 -0.447005,0.04932 -0.749898,-2.983925 4.8141597,0.139771 10.032192,-0.370561 14.99723,0 z" + id="rect2992-5" + style="fill:url(#linearGradient8226);fill-opacity:1;fill-rule:nonzero;stroke:#353537;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + d="m 2,13 10,0 0,2 L 2.2255647,15 2,13 z" + id="rect9146-5" + style="fill:url(#linearGradient8223);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.40899992;marker:none;visibility:visible;display:inline;overflow:visible" /> + <path + d="m 2.2255639,14.999999 c 0,0 -0.1503759,-1.442332 -0.1503759,-1.442332 1.0179428,1.143093 4.7514263,1.442332 7.3252263,1.442332 0,0 -7.1748504,0 -7.1748504,0 z" + id="path9148-2" + style="opacity:0.81142853;fill:url(#linearGradient8220);fill-opacity:1;fill-rule:evenodd;stroke:none" /> + <path + d="M 1.4897093,1.4657632 0.514749,12.488885 C 0.505,12.488885 0.5,12.491788 0.5,12.499999 l 14.999999,0 c 0,-0.0082 -0.005,-0.01111 -0.01475,-0.01111 L 14.479867,1.2478485 c 0,0 -0.187746,-0.74340135 -0.909635,-0.74340135 -0.688148,0 -10.5350353,-0.004447 -11.2600103,-0.004447 -0.75868,0 -0.8205124,0.96576325 -0.8205124,0.96576325 z" + id="rect2990-9" + style="fill:url(#radialGradient8215);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8217);stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + d="m 1.4762913,12.5 13.0474177,0" + id="path2215-0" + style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> + <path + d="M 9.875,1.03125 C 9.5425325,1.03125 9.2896361,1.1933561 9.28125,1.4375 7.5462296,4.2547045 3.7159646,3.3310272 2.1875,6.6875 2.107281,7.5502069 2.3133647,8.6701052 3.09375,9.375 4.23596,10.40677 6.1379859,11.041207 8.15625,11 12.321615,10.914959 15.990924,8.1997572 12.8125,4.65625 12.794904,4.4114056 12.5625,1.4375 12.5625,1.4375 12.545264,1.1967161 12.267601,1.03125 11.9375,1.03125 l -2.0625,0 z m -0.03125,0.4375 2.0625,0 c 0.119904,0 0.214005,0.027064 0.21875,0.09375 L 11.6875,4.65625 C 15.160987,7.4613605 11.945518,9.7796633 8.25,9.90625 4.8918537,10.021279 2.9699492,8.847871 3.15625,6.84375 4.3344434,3.466723 8.863656,5.0817755 9.625,1.5625 9.6054609,1.4997867 9.7265155,1.46875 9.84375,1.46875 z" + id="path8117" + style="fill:url(#radialGradient8211);fill-opacity:1" /> + <path + d="M 7.9999249,8.9999497 C 7.3338259,9.003979 6.6178906,8.7647964 6.2182574,8.2045172 5.8878761,7.7376942 5.9413392,7.042109 6.3494314,6.63805 6.8327879,6.1198432 7.5866528,5.9505056 8.2718727,6.0129013 8.8789744,6.0691126 9.5104356,6.3443475 9.8353698,6.8829643 10.086844,7.3170303 10.047208,7.9041627 9.7164741,8.2868807 9.3098043,8.7947936 8.6299115,8.9998014 7.9999249,8.9999497 z m 0.033529,-2.05954 C 7.5676631,6.950996 7.0685483,6.9372219 6.6531228,7.1810992 6.3786983,7.3719617 6.3550571,7.7834456 6.5399472,8.0446579 6.791609,8.4367198 7.2662569,8.6084808 7.7086272,8.6682148 8.2791121,8.7399813 8.9061994,8.6113728 9.334753,8.2097584 9.5762055,7.9697526 9.6865747,7.5362831 9.4461096,7.2585712 9.2078802,7.0082999 8.8377224,6.985091 8.5141086,6.9541818 8.3541203,6.9436237 8.1937276,6.9420228 8.0334539,6.9404097 z" + id="path9400" + style="fill:url(#radialGradient8208);fill-opacity:1;fill-rule:nonzero;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <g + transform="matrix(-0.04685826,0,0,0.07750161,4.3055193,-2.991086)" + id="g9436"> + <path + d="m 37.925296,187.15033 c 0.31446,3.45855 5.02375,6.27902 10.51419,6.27902 5.48794,0 9.6432,-2.82047 9.27634,-6.27902 -0.36437,-3.44025 -5.07117,-6.21806 -10.5067,-6.21806 -5.43803,0.002 -9.59329,2.77781 -9.28383,6.21806 l 0,0 z" + id="path9438" + style="fill:#535353;fill-opacity:1" /> + </g> + <g + transform="matrix(-0.04685826,0,0,0.07750161,16.205519,-2.991086)" + id="g9496"> + <path + d="m 37.925296,187.15033 c 0.31446,3.45855 5.02375,6.27902 10.51419,6.27902 5.48794,0 9.6432,-2.82047 9.27634,-6.27902 -0.36437,-3.44025 -5.07117,-6.21806 -10.5067,-6.21806 -5.43803,0.002 -9.59329,2.77781 -9.28383,6.21806 l 0,0 z" + id="path9498" + style="fill:#535353;fill-opacity:1" /> + </g> + <rect + width="14" + height="2" + x="1" + y="13" + id="rect6300-3-2" + style="opacity:0.2;fill:url(#radialGradient8201);fill-opacity:1;stroke:none" /> + <path + d="M 3.5490052,1.2794204 C 3.5821222,1.4638603 3.5033392,1.668064 3.4765882,1.8577602 3.3642225,2.4379547 3.248083,3.0174209 3.1387788,3.5982061 3.0364568,3.976483 3.4034434,3.822574 3.4487925,3.8610185 3.9285086,3.6778743 4.4037673,3.4775049 4.8813544,3.2862237 5.3796101,3.0823738 5.8809457,2.8849464 6.3772748,2.677079 6.6902572,2.4909307 6.7820665,2.323762 6.8635898,2.0428768 6.9084532,1.7990145 6.9138614,1.5262921 6.7919595,1.3034032 6.7139126,1.1493881 6.5435087,1.0841579 6.379809,1.1073783 c -0.8675476,0 -1.7350953,0 -2.6026429,0 L 3.5490052,1.2794204 z m 0.588988,0.4439693 c 0.5921265,0 1.184253,-1e-7 1.7763795,-1e-7 0.1871044,0.070513 0.054625,0.2194806 -0.083295,0.2325189 C 5.229708,2.1997992 4.6283387,2.4436898 4.0269694,2.6875804 3.8824333,2.7420385 3.8720481,2.5203138 3.9157358,2.4262942 c 0.037079,-0.2075185 0.074157,-0.415037 0.1112359,-0.6225555 0.041217,-0.021125 0.065659,-0.065363 0.1110215,-0.080349 z" + id="path8125" + style="fill:url(#radialGradient8198);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + </g> + <path + style="fill:url(#linearGradient3656);fill-opacity:1;fill-rule:nonzero;stroke:#ac272e;stroke-width:0.99800000000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + d="M 12.5,5.4999998 8.0596782,10.5 3.5,5.4999998 l 2,0 L 5.5,0.5 l 5,0 0,4.9999998 2,0 z" + id="path3288" /> +</svg> diff --git a/rapid/glade3/rapid-photo-downloader-downloaded-with-warning.svg b/rapid/glade3/rapid-photo-downloader-downloaded-with-warning.svg new file mode 100644 index 0000000..8065ac2 --- /dev/null +++ b/rapid/glade3/rapid-photo-downloader-downloaded-with-warning.svg @@ -0,0 +1,351 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.0" + width="16" + height="16" + id="svg2" + inkscape:version="0.47 r22583" + sodipodi:docname="document-save.svg"> + <metadata + id="metadata64"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1089" + id="namedview62" + showgrid="false" + inkscape:zoom="51.5" + inkscape:cx="4.0485437" + inkscape:cy="8" + inkscape:window-x="0" + inkscape:window-y="24" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /> + <defs + id="defs4"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 8 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="16 : 8 : 1" + inkscape:persp3d-origin="8 : 5.3333333 : 1" + id="perspective66" /> + <linearGradient + id="linearGradient4168"> + <stop + id="stop3652" + style="stop-color:#edd563;stop-opacity:1;" + offset="0" /> + <stop + id="stop4172" + style="stop-color:#e08223;stop-opacity:1;" + offset="1" /> + </linearGradient> + <linearGradient + x1="28.314739" + y1="20.709501" + x2="0.81572169" + y2="20.709501" + id="linearGradient3374" + xlink:href="#linearGradient4168" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,-0.319447,-0.313352,0,15.561474,13.08587)" /> + <linearGradient + x1="53.99139" + y1="87.89592" + x2="53.99139" + y2="104.28131" + id="linearGradient8226" + xlink:href="#linearGradient2215-9-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.1242128,0,0,0.1863981,0.233129,-3.9907482)" /> + <linearGradient + x1="7.0625" + y1="35.28125" + x2="24.6875" + y2="35.28125" + id="linearGradient8223" + xlink:href="#linearGradient6309-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.5545779,0,0,0.35955055,-1.6911436,1.3146057)" /> + <linearGradient + x1="12.277412" + y1="37.205811" + x2="12.221823" + y2="33.758667" + id="linearGradient8220" + xlink:href="#linearGradient4236-0-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.5545779,0,0,0.35955055,-2.132306,1.7913054)" /> + <linearGradient + x1="4.6104097" + y1="11.320717" + x2="2.2246289" + y2="6.8646717" + id="linearGradient8217" + xlink:href="#linearGradient3484-2-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.6451613,0,0,0.9797594,0.258064,-6.7257265)" /> + <radialGradient + cx="4.1993008" + cy="2.3117516" + r="7.9999995" + fx="4.1993008" + fy="2.3117516" + id="radialGradient8215" + xlink:href="#linearGradient7056-0-9" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1767008,1.0376968,-0.76927742,0.87232541,1.0363585,-3.2771526)" /> + <radialGradient + cx="141.74666" + cy="206.42612" + r="78.728165" + fx="141.74666" + fy="206.42612" + id="radialGradient8211" + xlink:href="#linearGradient4035-5" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.12708936,-0.00212891,9.4059438e-4,0.12249323,-10.298148,-14.500064)" /> + <radialGradient + cx="142.62215" + cy="191.85428" + r="78.728165" + fx="142.62215" + fy="191.85428" + id="radialGradient8208" + xlink:href="#linearGradient4035-5" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.06165082,0,0,-0.0653716,-1.0370648,17.524179)" /> + <radialGradient + cx="24" + cy="42" + r="21" + fx="24" + fy="42" + id="radialGradient8201" + xlink:href="#linearGradient6310-8-2" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.33333332,0,0,0.14285711,6.5e-7,8.0000015)" /> + <radialGradient + cx="127.31733" + cy="143.82751" + r="78.728165" + fx="127.31733" + fy="143.82751" + id="radialGradient8198" + xlink:href="#linearGradient8105" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.04179653,-0.01388393,0.00338688,0.03797545,-0.54190607,-0.79595187)" /> + <linearGradient + id="linearGradient6310-8-2"> + <stop + id="stop6312-6-2" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop6314-6-0" + style="stop-color:#ffffff;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3484-2-0"> + <stop + id="stop3486-2-4" + style="stop-color:#969696;stop-opacity:1" + offset="0" /> + <stop + id="stop3488-0-2" + style="stop-color:#b4b4b4;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient7056-0-9"> + <stop + id="stop7064-4-6" + style="stop-color:#e6e6e6;stop-opacity:1" + offset="0" /> + <stop + id="stop7060-2-1" + style="stop-color:#c8c8c8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient2215-9-0"> + <stop + id="stop2223-6-4" + style="stop-color:#7a7a7a;stop-opacity:1" + offset="0" /> + <stop + id="stop2219-1-2" + style="stop-color:#474747;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient4035-5"> + <stop + id="stop4037-8" + style="stop-color:#f5f5f5;stop-opacity:1" + offset="0" /> + <stop + id="stop4039-7" + style="stop-color:#e7e7e7;stop-opacity:1" + offset="0.47025558" /> + <stop + id="stop4041-0" + style="stop-color:#8c8c8c;stop-opacity:1" + offset="0.69348532" /> + <stop + id="stop4043-4" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.83542866" /> + <stop + id="stop4045-8" + style="stop-color:#a8a8a8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient6309-1"> + <stop + id="stop6311-0" + style="stop-color:#000000;stop-opacity:1" + offset="0" /> + <stop + id="stop6313-7" + style="stop-color:#bbbbbb;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient4236-0-1"> + <stop + id="stop4238-4-4" + style="stop-color:#eeeeee;stop-opacity:1" + offset="0" /> + <stop + id="stop4240-3-9" + style="stop-color:#eeeeee;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient8105"> + <stop + id="stop8107" + style="stop-color:#f5f5f5;stop-opacity:1" + offset="0" /> + <stop + id="stop8109" + style="stop-color:#e7e7e7;stop-opacity:1" + offset="0.25027597" /> + <stop + id="stop8111" + style="stop-color:#8c8c8c;stop-opacity:1" + offset="0.69348532" /> + <stop + id="stop8113" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.83542866" /> + <stop + id="stop8115" + style="stop-color:#a8a8a8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4168" + id="linearGradient3656" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,-0.319447,-0.313352,0,15.561474,13.08587)" + x1="28.314739" + y1="20.709501" + x2="0.81572169" + y2="20.709501" /> + </defs> + <g + id="g3119"> + <path + d="m 15.49723,12.5 c -0.304165,2.535038 -0.22639,2.983925 -0.777167,2.983925 -0.21573,0.03617 -8.698317,0 -13.470165,0 -0.598135,0 -0.447005,0.04932 -0.749898,-2.983925 4.8141597,0.139771 10.032192,-0.370561 14.99723,0 z" + id="rect2992-5" + style="fill:url(#linearGradient8226);fill-opacity:1;fill-rule:nonzero;stroke:#353537;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + d="m 2,13 10,0 0,2 L 2.2255647,15 2,13 z" + id="rect9146-5" + style="fill:url(#linearGradient8223);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.40899992;marker:none;visibility:visible;display:inline;overflow:visible" /> + <path + d="m 2.2255639,14.999999 c 0,0 -0.1503759,-1.442332 -0.1503759,-1.442332 1.0179428,1.143093 4.7514263,1.442332 7.3252263,1.442332 0,0 -7.1748504,0 -7.1748504,0 z" + id="path9148-2" + style="opacity:0.81142853;fill:url(#linearGradient8220);fill-opacity:1;fill-rule:evenodd;stroke:none" /> + <path + d="M 1.4897093,1.4657632 0.514749,12.488885 C 0.505,12.488885 0.5,12.491788 0.5,12.499999 l 14.999999,0 c 0,-0.0082 -0.005,-0.01111 -0.01475,-0.01111 L 14.479867,1.2478485 c 0,0 -0.187746,-0.74340135 -0.909635,-0.74340135 -0.688148,0 -10.5350353,-0.004447 -11.2600103,-0.004447 -0.75868,0 -0.8205124,0.96576325 -0.8205124,0.96576325 z" + id="rect2990-9" + style="fill:url(#radialGradient8215);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8217);stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + d="m 1.4762913,12.5 13.0474177,0" + id="path2215-0" + style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> + <path + d="M 9.875,1.03125 C 9.5425325,1.03125 9.2896361,1.1933561 9.28125,1.4375 7.5462296,4.2547045 3.7159646,3.3310272 2.1875,6.6875 2.107281,7.5502069 2.3133647,8.6701052 3.09375,9.375 4.23596,10.40677 6.1379859,11.041207 8.15625,11 12.321615,10.914959 15.990924,8.1997572 12.8125,4.65625 12.794904,4.4114056 12.5625,1.4375 12.5625,1.4375 12.545264,1.1967161 12.267601,1.03125 11.9375,1.03125 l -2.0625,0 z m -0.03125,0.4375 2.0625,0 c 0.119904,0 0.214005,0.027064 0.21875,0.09375 L 11.6875,4.65625 C 15.160987,7.4613605 11.945518,9.7796633 8.25,9.90625 4.8918537,10.021279 2.9699492,8.847871 3.15625,6.84375 4.3344434,3.466723 8.863656,5.0817755 9.625,1.5625 9.6054609,1.4997867 9.7265155,1.46875 9.84375,1.46875 z" + id="path8117" + style="fill:url(#radialGradient8211);fill-opacity:1" /> + <path + d="M 7.9999249,8.9999497 C 7.3338259,9.003979 6.6178906,8.7647964 6.2182574,8.2045172 5.8878761,7.7376942 5.9413392,7.042109 6.3494314,6.63805 6.8327879,6.1198432 7.5866528,5.9505056 8.2718727,6.0129013 8.8789744,6.0691126 9.5104356,6.3443475 9.8353698,6.8829643 10.086844,7.3170303 10.047208,7.9041627 9.7164741,8.2868807 9.3098043,8.7947936 8.6299115,8.9998014 7.9999249,8.9999497 z m 0.033529,-2.05954 C 7.5676631,6.950996 7.0685483,6.9372219 6.6531228,7.1810992 6.3786983,7.3719617 6.3550571,7.7834456 6.5399472,8.0446579 6.791609,8.4367198 7.2662569,8.6084808 7.7086272,8.6682148 8.2791121,8.7399813 8.9061994,8.6113728 9.334753,8.2097584 9.5762055,7.9697526 9.6865747,7.5362831 9.4461096,7.2585712 9.2078802,7.0082999 8.8377224,6.985091 8.5141086,6.9541818 8.3541203,6.9436237 8.1937276,6.9420228 8.0334539,6.9404097 z" + id="path9400" + style="fill:url(#radialGradient8208);fill-opacity:1;fill-rule:nonzero;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <g + transform="matrix(-0.04685826,0,0,0.07750161,4.3055193,-2.991086)" + id="g9436"> + <path + d="m 37.925296,187.15033 c 0.31446,3.45855 5.02375,6.27902 10.51419,6.27902 5.48794,0 9.6432,-2.82047 9.27634,-6.27902 -0.36437,-3.44025 -5.07117,-6.21806 -10.5067,-6.21806 -5.43803,0.002 -9.59329,2.77781 -9.28383,6.21806 l 0,0 z" + id="path9438" + style="fill:#535353;fill-opacity:1" /> + </g> + <g + transform="matrix(-0.04685826,0,0,0.07750161,16.205519,-2.991086)" + id="g9496"> + <path + d="m 37.925296,187.15033 c 0.31446,3.45855 5.02375,6.27902 10.51419,6.27902 5.48794,0 9.6432,-2.82047 9.27634,-6.27902 -0.36437,-3.44025 -5.07117,-6.21806 -10.5067,-6.21806 -5.43803,0.002 -9.59329,2.77781 -9.28383,6.21806 l 0,0 z" + id="path9498" + style="fill:#535353;fill-opacity:1" /> + </g> + <rect + width="14" + height="2" + x="1" + y="13" + id="rect6300-3-2" + style="opacity:0.2;fill:url(#radialGradient8201);fill-opacity:1;stroke:none" /> + <path + d="M 3.5490052,1.2794204 C 3.5821222,1.4638603 3.5033392,1.668064 3.4765882,1.8577602 3.3642225,2.4379547 3.248083,3.0174209 3.1387788,3.5982061 3.0364568,3.976483 3.4034434,3.822574 3.4487925,3.8610185 3.9285086,3.6778743 4.4037673,3.4775049 4.8813544,3.2862237 5.3796101,3.0823738 5.8809457,2.8849464 6.3772748,2.677079 6.6902572,2.4909307 6.7820665,2.323762 6.8635898,2.0428768 6.9084532,1.7990145 6.9138614,1.5262921 6.7919595,1.3034032 6.7139126,1.1493881 6.5435087,1.0841579 6.379809,1.1073783 c -0.8675476,0 -1.7350953,0 -2.6026429,0 L 3.5490052,1.2794204 z m 0.588988,0.4439693 c 0.5921265,0 1.184253,-1e-7 1.7763795,-1e-7 0.1871044,0.070513 0.054625,0.2194806 -0.083295,0.2325189 C 5.229708,2.1997992 4.6283387,2.4436898 4.0269694,2.6875804 3.8824333,2.7420385 3.8720481,2.5203138 3.9157358,2.4262942 c 0.037079,-0.2075185 0.074157,-0.415037 0.1112359,-0.6225555 0.041217,-0.021125 0.065659,-0.065363 0.1110215,-0.080349 z" + id="path8125" + style="fill:url(#radialGradient8198);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + </g> + <path + style="fill:url(#linearGradient3656);fill-opacity:1;fill-rule:nonzero;stroke:#bb5e12;stroke-width:0.99800000000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + d="M 12.5,5.4999998 8.0596782,10.5 3.5,5.4999998 l 2,0 L 5.5,0.5 l 5,0 0,4.9999998 2,0 z" + id="path3288" /> +</svg> diff --git a/rapid/glade3/rapid-photo-downloader-downloaded.svg b/rapid/glade3/rapid-photo-downloader-downloaded.svg new file mode 100644 index 0000000..378927e --- /dev/null +++ b/rapid/glade3/rapid-photo-downloader-downloaded.svg @@ -0,0 +1,295 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.0" + width="16" + height="16" + id="svg2"> + <defs + id="defs4"> + <linearGradient + id="linearGradient4168"> + <stop + id="stop3652" + style="stop-color:#d0e08f;stop-opacity:1" + offset="0" /> + <stop + id="stop4172" + style="stop-color:#9fba48;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + x1="28.314739" + y1="20.709501" + x2="0.81572169" + y2="20.709501" + id="linearGradient3374" + xlink:href="#linearGradient4168" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0,-0.319447,-0.313352,0,15.561474,13.08587)" /> + <linearGradient + x1="53.99139" + y1="87.89592" + x2="53.99139" + y2="104.28131" + id="linearGradient8226" + xlink:href="#linearGradient2215-9-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.1242128,0,0,0.1863981,0.233129,-3.9907482)" /> + <linearGradient + x1="7.0625" + y1="35.28125" + x2="24.6875" + y2="35.28125" + id="linearGradient8223" + xlink:href="#linearGradient6309-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.5545779,0,0,0.35955055,-1.6911436,1.3146057)" /> + <linearGradient + x1="12.277412" + y1="37.205811" + x2="12.221823" + y2="33.758667" + id="linearGradient8220" + xlink:href="#linearGradient4236-0-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.5545779,0,0,0.35955055,-2.132306,1.7913054)" /> + <linearGradient + x1="4.6104097" + y1="11.320717" + x2="2.2246289" + y2="6.8646717" + id="linearGradient8217" + xlink:href="#linearGradient3484-2-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.6451613,0,0,0.9797594,0.258064,-6.7257265)" /> + <radialGradient + cx="4.1993008" + cy="2.3117516" + r="7.9999995" + fx="4.1993008" + fy="2.3117516" + id="radialGradient8215" + xlink:href="#linearGradient7056-0-9" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.1767008,1.0376968,-0.76927742,0.87232541,1.0363585,-3.2771526)" /> + <radialGradient + cx="141.74666" + cy="206.42612" + r="78.728165" + fx="141.74666" + fy="206.42612" + id="radialGradient8211" + xlink:href="#linearGradient4035-5" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.12708936,-0.00212891,9.4059438e-4,0.12249323,-10.298148,-14.500064)" /> + <radialGradient + cx="142.62215" + cy="191.85428" + r="78.728165" + fx="142.62215" + fy="191.85428" + id="radialGradient8208" + xlink:href="#linearGradient4035-5" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.06165082,0,0,-0.0653716,-1.0370648,17.524179)" /> + <radialGradient + cx="24" + cy="42" + r="21" + fx="24" + fy="42" + id="radialGradient8201" + xlink:href="#linearGradient6310-8-2" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.33333332,0,0,0.14285711,6.5e-7,8.0000015)" /> + <radialGradient + cx="127.31733" + cy="143.82751" + r="78.728165" + fx="127.31733" + fy="143.82751" + id="radialGradient8198" + xlink:href="#linearGradient8105" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.04179653,-0.01388393,0.00338688,0.03797545,-0.54190607,-0.79595187)" /> + <linearGradient + id="linearGradient6310-8-2"> + <stop + id="stop6312-6-2" + style="stop-color:#ffffff;stop-opacity:1" + offset="0" /> + <stop + id="stop6314-6-0" + style="stop-color:#ffffff;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient3484-2-0"> + <stop + id="stop3486-2-4" + style="stop-color:#969696;stop-opacity:1" + offset="0" /> + <stop + id="stop3488-0-2" + style="stop-color:#b4b4b4;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient7056-0-9"> + <stop + id="stop7064-4-6" + style="stop-color:#e6e6e6;stop-opacity:1" + offset="0" /> + <stop + id="stop7060-2-1" + style="stop-color:#c8c8c8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient2215-9-0"> + <stop + id="stop2223-6-4" + style="stop-color:#7a7a7a;stop-opacity:1" + offset="0" /> + <stop + id="stop2219-1-2" + style="stop-color:#474747;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient4035-5"> + <stop + id="stop4037-8" + style="stop-color:#f5f5f5;stop-opacity:1" + offset="0" /> + <stop + id="stop4039-7" + style="stop-color:#e7e7e7;stop-opacity:1" + offset="0.47025558" /> + <stop + id="stop4041-0" + style="stop-color:#8c8c8c;stop-opacity:1" + offset="0.69348532" /> + <stop + id="stop4043-4" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.83542866" /> + <stop + id="stop4045-8" + style="stop-color:#a8a8a8;stop-opacity:1" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient6309-1"> + <stop + id="stop6311-0" + style="stop-color:#000000;stop-opacity:1" + offset="0" /> + <stop + id="stop6313-7" + style="stop-color:#bbbbbb;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient4236-0-1"> + <stop + id="stop4238-4-4" + style="stop-color:#eeeeee;stop-opacity:1" + offset="0" /> + <stop + id="stop4240-3-9" + style="stop-color:#eeeeee;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient8105"> + <stop + id="stop8107" + style="stop-color:#f5f5f5;stop-opacity:1" + offset="0" /> + <stop + id="stop8109" + style="stop-color:#e7e7e7;stop-opacity:1" + offset="0.25027597" /> + <stop + id="stop8111" + style="stop-color:#8c8c8c;stop-opacity:1" + offset="0.69348532" /> + <stop + id="stop8113" + style="stop-color:#dddddd;stop-opacity:1" + offset="0.83542866" /> + <stop + id="stop8115" + style="stop-color:#a8a8a8;stop-opacity:1" + offset="1" /> + </linearGradient> + </defs> + <g + id="g3119"> + <path + d="m 15.49723,12.5 c -0.304165,2.535038 -0.22639,2.983925 -0.777167,2.983925 -0.21573,0.03617 -8.698317,0 -13.470165,0 -0.598135,0 -0.447005,0.04932 -0.749898,-2.983925 4.8141597,0.139771 10.032192,-0.370561 14.99723,0 z" + id="rect2992-5" + style="fill:url(#linearGradient8226);fill-opacity:1;fill-rule:nonzero;stroke:#353537;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + d="m 2,13 10,0 0,2 L 2.2255647,15 2,13 z" + id="rect9146-5" + style="fill:url(#linearGradient8223);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.40899992;marker:none;visibility:visible;display:inline;overflow:visible" /> + <path + d="m 2.2255639,14.999999 c 0,0 -0.1503759,-1.442332 -0.1503759,-1.442332 1.0179428,1.143093 4.7514263,1.442332 7.3252263,1.442332 0,0 -7.1748504,0 -7.1748504,0 z" + id="path9148-2" + style="opacity:0.81142853;fill:url(#linearGradient8220);fill-opacity:1;fill-rule:evenodd;stroke:none" /> + <path + d="M 1.4897093,1.4657632 0.514749,12.488885 C 0.505,12.488885 0.5,12.491788 0.5,12.499999 l 14.999999,0 c 0,-0.0082 -0.005,-0.01111 -0.01475,-0.01111 L 14.479867,1.2478485 c 0,0 -0.187746,-0.74340135 -0.909635,-0.74340135 -0.688148,0 -10.5350353,-0.004447 -11.2600103,-0.004447 -0.75868,0 -0.8205124,0.96576325 -0.8205124,0.96576325 z" + id="rect2990-9" + style="fill:url(#radialGradient8215);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8217);stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <path + d="m 1.4762913,12.5 13.0474177,0" + id="path2215-0" + style="opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" /> + <path + d="M 9.875,1.03125 C 9.5425325,1.03125 9.2896361,1.1933561 9.28125,1.4375 7.5462296,4.2547045 3.7159646,3.3310272 2.1875,6.6875 2.107281,7.5502069 2.3133647,8.6701052 3.09375,9.375 4.23596,10.40677 6.1379859,11.041207 8.15625,11 12.321615,10.914959 15.990924,8.1997572 12.8125,4.65625 12.794904,4.4114056 12.5625,1.4375 12.5625,1.4375 12.545264,1.1967161 12.267601,1.03125 11.9375,1.03125 l -2.0625,0 z m -0.03125,0.4375 2.0625,0 c 0.119904,0 0.214005,0.027064 0.21875,0.09375 L 11.6875,4.65625 C 15.160987,7.4613605 11.945518,9.7796633 8.25,9.90625 4.8918537,10.021279 2.9699492,8.847871 3.15625,6.84375 4.3344434,3.466723 8.863656,5.0817755 9.625,1.5625 9.6054609,1.4997867 9.7265155,1.46875 9.84375,1.46875 z" + id="path8117" + style="fill:url(#radialGradient8211);fill-opacity:1" /> + <path + d="M 7.9999249,8.9999497 C 7.3338259,9.003979 6.6178906,8.7647964 6.2182574,8.2045172 5.8878761,7.7376942 5.9413392,7.042109 6.3494314,6.63805 6.8327879,6.1198432 7.5866528,5.9505056 8.2718727,6.0129013 8.8789744,6.0691126 9.5104356,6.3443475 9.8353698,6.8829643 10.086844,7.3170303 10.047208,7.9041627 9.7164741,8.2868807 9.3098043,8.7947936 8.6299115,8.9998014 7.9999249,8.9999497 z m 0.033529,-2.05954 C 7.5676631,6.950996 7.0685483,6.9372219 6.6531228,7.1810992 6.3786983,7.3719617 6.3550571,7.7834456 6.5399472,8.0446579 6.791609,8.4367198 7.2662569,8.6084808 7.7086272,8.6682148 8.2791121,8.7399813 8.9061994,8.6113728 9.334753,8.2097584 9.5762055,7.9697526 9.6865747,7.5362831 9.4461096,7.2585712 9.2078802,7.0082999 8.8377224,6.985091 8.5141086,6.9541818 8.3541203,6.9436237 8.1937276,6.9420228 8.0334539,6.9404097 z" + id="path9400" + style="fill:url(#radialGradient8208);fill-opacity:1;fill-rule:nonzero;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <g + transform="matrix(-0.04685826,0,0,0.07750161,4.3055193,-2.991086)" + id="g9436"> + <path + d="m 37.925296,187.15033 c 0.31446,3.45855 5.02375,6.27902 10.51419,6.27902 5.48794,0 9.6432,-2.82047 9.27634,-6.27902 -0.36437,-3.44025 -5.07117,-6.21806 -10.5067,-6.21806 -5.43803,0.002 -9.59329,2.77781 -9.28383,6.21806 l 0,0 z" + id="path9438" + style="fill:#535353;fill-opacity:1" /> + </g> + <g + transform="matrix(-0.04685826,0,0,0.07750161,16.205519,-2.991086)" + id="g9496"> + <path + d="m 37.925296,187.15033 c 0.31446,3.45855 5.02375,6.27902 10.51419,6.27902 5.48794,0 9.6432,-2.82047 9.27634,-6.27902 -0.36437,-3.44025 -5.07117,-6.21806 -10.5067,-6.21806 -5.43803,0.002 -9.59329,2.77781 -9.28383,6.21806 l 0,0 z" + id="path9498" + style="fill:#535353;fill-opacity:1" /> + </g> + <rect + width="14" + height="2" + x="1" + y="13" + id="rect6300-3-2" + style="opacity:0.2;fill:url(#radialGradient8201);fill-opacity:1;stroke:none" /> + <path + d="M 3.5490052,1.2794204 C 3.5821222,1.4638603 3.5033392,1.668064 3.4765882,1.8577602 3.3642225,2.4379547 3.248083,3.0174209 3.1387788,3.5982061 3.0364568,3.976483 3.4034434,3.822574 3.4487925,3.8610185 3.9285086,3.6778743 4.4037673,3.4775049 4.8813544,3.2862237 5.3796101,3.0823738 5.8809457,2.8849464 6.3772748,2.677079 6.6902572,2.4909307 6.7820665,2.323762 6.8635898,2.0428768 6.9084532,1.7990145 6.9138614,1.5262921 6.7919595,1.3034032 6.7139126,1.1493881 6.5435087,1.0841579 6.379809,1.1073783 c -0.8675476,0 -1.7350953,0 -2.6026429,0 L 3.5490052,1.2794204 z m 0.588988,0.4439693 c 0.5921265,0 1.184253,-1e-7 1.7763795,-1e-7 0.1871044,0.070513 0.054625,0.2194806 -0.083295,0.2325189 C 5.229708,2.1997992 4.6283387,2.4436898 4.0269694,2.6875804 3.8824333,2.7420385 3.8720481,2.5203138 3.9157358,2.4262942 c 0.037079,-0.2075185 0.074157,-0.415037 0.1112359,-0.6225555 0.041217,-0.021125 0.065659,-0.065363 0.1110215,-0.080349 z" + id="path8125" + style="fill:url(#radialGradient8198);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + </g> + <path + d="M 12.5,5.4999998 8.0596782,10.5 3.5,5.4999998 l 2,0 L 5.5,0.5 l 5,0 0,4.9999998 2,0 z" + id="path3288" + style="fill:url(#linearGradient3374);fill-opacity:1;fill-rule:nonzero;stroke:#699536;stroke-width:0.99829447;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> +</svg> diff --git a/rapid/glade3/rapid-photo-downloader-jobcode.svg b/rapid/glade3/rapid-photo-downloader-jobcode.svg new file mode 100644 index 0000000..3096ee2 --- /dev/null +++ b/rapid/glade3/rapid-photo-downloader-jobcode.svg @@ -0,0 +1,265 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://web.resource.org/cc/" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="48" + height="48" + id="svg1306" + sodipodi:version="0.32" + inkscape:version="0.45" + sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/actions" + sodipodi:docname="insert-text.svg" + inkscape:export-filename="/home/lapo/Desktop/insert-link-16.png" + inkscape:export-xdpi="90.000031" + inkscape:export-ydpi="90.000031" + version="1.0" + inkscape:output_extension="org.inkscape.output.svg.inkscape"> + <defs + id="defs1308"> + <linearGradient + id="linearGradient3384"> + <stop + style="stop-color:white;stop-opacity:1" + offset="0" + id="stop3386" /> + <stop + style="stop-color:#eeeeec;stop-opacity:1" + offset="1" + id="stop3388" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3284"> + <stop + style="stop-color:#ce5c00;stop-opacity:1;" + offset="0" + id="stop3286" /> + <stop + style="stop-color:#f57900;stop-opacity:1" + offset="1" + id="stop3288" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3276"> + <stop + style="stop-color:white;stop-opacity:1;" + offset="0" + id="stop3278" /> + <stop + style="stop-color:white;stop-opacity:0;" + offset="1" + id="stop3280" /> + </linearGradient> + <linearGradient + id="linearGradient3269"> + <stop + id="stop3271" + offset="0" + style="stop-color:#fecb81;stop-opacity:1" /> + <stop + id="stop3273" + offset="1" + style="stop-color:#fcaf3e;stop-opacity:1" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient3188"> + <stop + style="stop-color:black;stop-opacity:1;" + offset="0" + id="stop3190" /> + <stop + style="stop-color:black;stop-opacity:0;" + offset="1" + id="stop3192" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3188" + id="radialGradient3368" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.194656,0,34.62977)" + cx="23.8125" + cy="43" + fx="23.8125" + fy="43" + r="16.375" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3269" + id="linearGradient3370" + gradientUnits="userSpaceOnUse" + x1="22.750002" + y1="40.000755" + x2="22.750002" + y2="37.409679" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3284" + id="linearGradient3372" + gradientUnits="userSpaceOnUse" + x1="17.25" + y1="41.147343" + x2="17.25" + y2="36.103439" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3276" + id="linearGradient3374" + gradientUnits="userSpaceOnUse" + x1="18.875" + y1="35.183414" + x2="18.875" + y2="43.978611" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient3384" + id="radialGradient3390" + cx="24.842901" + cy="30.77803" + fx="24.842901" + fy="30.77803" + r="22.999998" + gradientTransform="matrix(1.48996,0,0,0.657586,-13.01493,5.2238)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666" + borderopacity="1" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="-71.544452" + inkscape:cy="31.751968" + inkscape:current-layer="layer1" + showgrid="true" + inkscape:grid-bbox="true" + inkscape:document-units="px" + fill="#fcaf3e" + stroke="#555753" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="1085" + inkscape:window-height="760" + inkscape:window-x="214" + inkscape:window-y="175" + inkscape:showpageshadow="false" + showborder="true" + gridspacingx="0.5px" + gridspacingy="0.5px" + gridempspacing="2" + inkscape:grid-points="true" + width="48px" + height="48px" /> + <metadata + id="metadata1311"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Insert Text</dc:title> + <dc:creator> + <cc:Agent> + <dc:title>Lapo Calamandrei</dc:title> + </cc:Agent> + </dc:creator> + <dc:source>http://www.gnome.org</dc:source> + <dc:contributor> + <cc:Agent> + <dc:title /> + </cc:Agent> + </dc:contributor> + <cc:license + rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> + <dc:subject> + <rdf:Bag> + <rdf:li>insert</rdf:li> + <rdf:li>text</rdf:li> + <rdf:li>generic</rdf:li> + </rdf:Bag> + </dc:subject> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> + <cc:permits + rdf:resource="http://web.resource.org/cc/Reproduction" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/Distribution" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/Notice" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/ShareAlike" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/SourceCode" /> + </cc:License> + </rdf:RDF> + </metadata> + <g + id="layer1" + inkscape:label="Layer 1" + inkscape:groupmode="layer"> + <path + sodipodi:type="arc" + style="opacity:0.2;color:black;fill:url(#radialGradient3368);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + id="path3360" + sodipodi:cx="23.8125" + sodipodi:cy="43" + sodipodi:rx="16.375" + sodipodi:ry="3.1875" + d="M 40.1875 43 A 16.375 3.1875 0 1 1 7.4375,43 A 16.375 3.1875 0 1 1 40.1875 43 z" + transform="matrix(1.068703,0,0,1.411765,-2.9485,-18.2059)" /> + <g + id="g3362"> + <path + sodipodi:nodetypes="cccc" + id="path3364" + d="M 15.500002,35.500004 L 32.500012,35.500004 L 24.000007,44.499996 L 15.500002,35.500004 z " + style="color:black;fill:url(#linearGradient3370);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3372);stroke-width:1.00000048;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> + <path + transform="translate(0,2)" + d="M 17.8125,34.5 L 24,41.0625 L 30.1875,34.5 L 17.8125,34.5 z " + id="path3366" + style="opacity:0.7;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3374);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" + inkscape:original="M 15.5 33.5 L 24 42.5 L 32.5 33.5 L 15.5 33.5 z " + inkscape:radius="-1" + sodipodi:type="inkscape:offset" /> + </g> + <rect + style="opacity:1;fill:url(#radialGradient3390);fill-opacity:1;stroke:#888a85;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1" + id="rect3376" + width="44.999996" + height="24.000004" + x="1.5" + y="6.5" + rx="1.03125" + ry="1.03125" /> + <path + style="font-size:17.50059891px;font-style:normal;font-weight:bold;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + d="M 15.64186,22.622828 L 10.612,22.622828 L 9.81825,24.999972 L 6.58477,24.999972 L 11.20522,11.951901 L 15.04028,11.951901 L 19.66073,24.999972 L 16.42725,24.999972 L 15.64186,22.622828 M 11.4141,19.983237 L 14.8314,19.983237 L 13.12692,15.010725 L 11.4141,19.983237 M 26.15275,22.981148 C 26.79332,22.98115 27.2807,22.736444 27.61492,22.24703 C 27.95469,21.757621 28.12458,21.046809 28.12459,20.114592 C 28.12458,19.182385 27.95469,18.471573 27.61492,17.982154 C 27.2807,17.49275 26.79332,17.248045 26.15275,17.248037 C 25.51218,17.248045 24.83172,17.495663 24.48638,17.990894 C 24.14659,18.480313 23.9767,19.188211 23.97671,20.114592 C 23.9767,21.040983 24.14659,21.751795 24.48638,22.24703 C 24.83172,22.736444 25.51218,22.98115 26.15275,22.981148 M 23.97671,16.645011 C 24.38889,16.07404 25.03315,15.654544 25.53447,15.386523 C 26.03577,15.112696 26.61228,14.975777 27.264,14.975767 C 28.41702,14.975777 29.36394,15.456449 30.10479,16.417785 C 30.84561,17.373311 31.21602,18.605579 31.21603,20.114592 C 31.21602,21.623615 30.84561,22.858797 30.10479,23.820139 C 29.36394,24.775658 28.41702,25.253417 27.264,25.253417 C 26.61228,25.253417 26.03577,25.119412 25.53447,24.851401 C 25.03315,24.577563 24.38889,24.155155 23.97671,23.584172 L 23.97671,24.999972 L 20.98553,24.999972 L 20.98553,12.088812 L 23.97671,12.088812 L 23.97671,16.645011 M 41.00002,15.517616 L 41.00002,18.069549 C 40.59339,17.77824 40.18399,17.562666 39.7718,17.422826 C 39.36517,17.283002 38.94184,17.213087 38.50181,17.213078 C 37.66628,17.213087 37.01457,17.469445 36.54668,17.982154 C 36.08435,18.489052 35.85319,19.199864 35.85319,20.114592 C 35.85319,21.02933 36.08435,21.743055 36.54668,22.255769 C 37.01457,22.762662 37.66628,23.016107 38.50181,23.016105 C 38.96969,23.016107 39.41252,22.943278 39.83029,22.797618 C 40.25361,22.651962 40.64353,22.436388 41.00002,22.150895 L 41.00002,24.711568 C 40.53212,24.892184 40.05587,25.02619 39.57128,25.113585 C 39.09224,25.206807 38.61042,25.253417 38.12582,25.253417 C 36.43806,25.253417 35.11793,24.801877 34.16543,23.898795 C 33.21294,22.989889 32.73669,21.72849 32.73669,20.114592 C 32.73669,18.500704 33.21294,17.242218 34.16543,16.339129 C 35.11793,15.430231 36.43806,14.975777 38.12582,14.975767 C 38.61599,14.975777 39.09781,15.022388 39.57128,15.115599 C 40.0503,15.203003 40.52655,15.337009 41.00002,15.517616" + id="text3378" + sodipodi:nodetypes="ccccccccccccccsssssssccsssssssccccccccsssssssccsssssssc" /> + <rect + style="opacity:1;fill:none;fill-opacity:1;stroke:white;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1" + id="rect3382" + width="42.97773" + height="22.000011" + x="2.5" + y="7.5" + rx="0" + ry="0" /> + </g> +</svg> diff --git a/rapid/glade3/rapid-photo-downloader.svg b/rapid/glade3/rapid-photo-downloader.svg new file mode 100644 index 0000000..a1e9885 --- /dev/null +++ b/rapid/glade3/rapid-photo-downloader.svg @@ -0,0 +1,2673 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="128" + height="128" + id="svg7854" + sodipodi:version="0.32" + inkscape:version="0.47 r22583" + version="1.0" + sodipodi:docname="rapid-photo-downloader.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="/home/damon/rapid/data/icons/16x16/apps/rapid-photo-downloader.png" + inkscape:export-xdpi="30" + inkscape:export-ydpi="30" + sodipodi:modified="TRUE"> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#e0e0e0" + borderopacity="1" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="7.7132076" + inkscape:cx="62.076472" + inkscape:cy="102.31383" + inkscape:document-units="px" + inkscape:current-layer="layer2" + width="48px" + height="48px" + inkscape:showpageshadow="false" + inkscape:window-width="1920" + inkscape:window-height="1089" + inkscape:window-x="0" + inkscape:window-y="24" + showgrid="false" + inkscape:window-maximized="1" /> + <defs + id="defs7856"> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 24 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="48 : 24 : 1" + inkscape:persp3d-origin="24 : 16 : 1" + id="perspective3324" /> + <linearGradient + inkscape:collect="always" + id="linearGradient8954"> + <stop + offset="0" + id="stop8956" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop8958" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient8940"> + <stop + offset="0" + id="stop8942" + style="stop-color:#72776c;stop-opacity:1;" /> + <stop + offset="0.5" + id="stop8944" + style="stop-color:#e0e0e0;stop-opacity:1;" /> + <stop + offset="0.75" + id="stop8946" + style="stop-color:#8f9587;stop-opacity:1;" /> + <stop + offset="1" + id="stop8948" + style="stop-color:#c1c1c1;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8928"> + <stop + offset="0" + id="stop8930" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + offset="1" + id="stop8932" + style="stop-color:#cccccc;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8895"> + <stop + offset="0" + id="stop8899" + style="stop-color:#204a87;stop-opacity:0;" /> + <stop + offset="0.5" + id="stop8905" + style="stop-color:#204a87;stop-opacity:0;" /> + <stop + offset="1" + id="stop8897" + style="stop-color:#204a87;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8735"> + <stop + offset="0" + id="stop8737" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + offset="1" + id="stop8739" + style="stop-color:#8b8b8b;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8700"> + <stop + offset="0" + id="stop8702" + style="stop-color:#babdb6;stop-opacity:1;" /> + <stop + offset="0.5" + id="stop8704" + style="stop-color:#e0e0e0;stop-opacity:1;" /> + <stop + offset="0.75" + id="stop8706" + style="stop-color:#c0c3bb;stop-opacity:1;" /> + <stop + offset="1" + id="stop8708" + style="stop-color:#dbdbdb;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8680"> + <stop + offset="0" + id="stop8682" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="0.5" + id="stop8688" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop8684" + style="stop-color:#afafaf;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8670"> + <stop + offset="0" + id="stop8672" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + offset="0.32142857" + id="stop8950" + style="stop-color:#ebebeb;stop-opacity:1;" /> + <stop + offset="0.5" + id="stop8678" + style="stop-color:#909090;stop-opacity:1;" /> + <stop + offset="1" + id="stop8674" + style="stop-color:#fafafa;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8658"> + <stop + offset="0" + id="stop8660" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + offset="1" + id="stop8662" + style="stop-color:#a5a5a5;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8644"> + <stop + offset="0" + id="stop8646" + style="stop-color:#717171;stop-opacity:1;" /> + <stop + offset="1" + id="stop8648" + style="stop-color:#000000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient8632"> + <stop + offset="0" + id="stop8634" + style="stop-color:#2e3436;stop-opacity:1;" /> + <stop + offset="0.5" + id="stop8640" + style="stop-color:#6b797d;stop-opacity:1;" /> + <stop + offset="1" + id="stop8636" + style="stop-color:#2e3436;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient2230"> + <stop + offset="0" + id="stop2232" + style="stop-color:#eeeeee;stop-opacity:1;" /> + <stop + offset="1.0000000" + id="stop2234" + style="stop-color:#a2a2a2;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient3301"> + <stop + offset="0.0000000" + id="stop3303" + style="stop-color:#ffffff;stop-opacity:1.0000000;" /> + <stop + offset="1.0000000" + id="stop3305" + style="stop-color:#cbcbcb;stop-opacity:1.0000000;" /> + </linearGradient> + <linearGradient + id="linearGradient5895"> + <stop + offset="0" + id="stop5897" + style="stop-color:#888a85;stop-opacity:1;" /> + <stop + offset="1" + id="stop5899" + style="stop-color:#ffffff;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient5819"> + <stop + offset="0" + id="stop5821" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + offset="1" + id="stop5823" + style="stop-color:#a5a5a5;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient5776"> + <stop + offset="0" + id="stop5778" + style="stop-color:#babdb6;stop-opacity:1;" /> + <stop + offset="0.5" + id="stop5784" + style="stop-color:#ffffff;stop-opacity:1;" /> + <stop + offset="0.75" + id="stop5786" + style="stop-color:#c0c3bb;stop-opacity:1;" /> + <stop + offset="1" + id="stop5780" + style="stop-color:#ffffff;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient5759"> + <stop + offset="0" + id="stop5761" + style="stop-color:#898b86;stop-opacity:1;" /> + <stop + offset="0.16071428" + id="stop5767" + style="stop-color:#b3b3b0;stop-opacity:1;" /> + <stop + offset="0.56037414" + id="stop5769" + style="stop-color:#71746f;stop-opacity:1;" /> + <stop + offset="1" + id="stop5763" + style="stop-color:#555753;stop-opacity:1;" /> + </linearGradient> + <clipPath + id="clipPath8924" + clipPathUnits="userSpaceOnUse"> + <rect + id="rect8926" + x="28.475426" + y="29" + width="8.17838" + height="5" + ry="1.1324512" + rx="1.1324512" + style="color:#000000;fill:none;stroke:#ffffff;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + </clipPath> + <radialGradient + inkscape:collect="always" + id="radialGradient8960" + r="11.5" + gradientTransform="matrix(1,0,0,0.5,0,17.9375)" + cx="7.375" + cy="35.875" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient8954" + fy="35.875" + fx="7.375" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4140" + x1="19.864109" + x2="37.166458" + y1="17.906694" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4134" + y2="41.594772" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4131" + x1="19.500004" + x2="19.500004" + y1="10.687498" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4125" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4123" + x1="19.500004" + x2="19.500004" + y1="10.687498" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4117" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4107" + x1="25.044359" + x2="25.791954" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + y1="20.624216" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4109" + y2="28.863333" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4103" + x1="22.937496" + x2="22.937496" + y1="29.93535" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4097" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4085" + x1="9.1648445" + x2="9.125" + gradientTransform="translate(20,0)" + y1="4.4145103" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4081" + x1="9.1648445" + x2="9.125" + gradientTransform="translate(16,0)" + y1="4.4145103" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4077" + x1="9.1648445" + x2="9.125" + gradientTransform="translate(12,0)" + y1="4.4145103" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4073" + x1="9.1648445" + x2="9.125" + gradientTransform="translate(8,0)" + y1="4.4145103" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4069" + x1="9.1648445" + x2="9.125" + gradientTransform="translate(4,0)" + y1="4.4145103" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4065" + x1="9.1648445" + x2="9.125" + y1="4.4145103" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4057" + x1="22.509596" + x2="31.603951" + gradientTransform="translate(-2.2e-6,0)" + y1="1.9792649" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4051" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5027" + x1="302.85715" + x2="302.85715" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + y1="366.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5048" + y2="609.50507" /> + <linearGradient + id="linearGradient5048"> + <stop + offset="0" + id="stop5050" + style="stop-color:black;stop-opacity:0;" /> + <stop + offset="0.5" + id="stop5056" + style="stop-color:black;stop-opacity:1;" /> + <stop + offset="1" + id="stop5052" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + id="radialGradient5029" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5060"> + <stop + offset="0" + id="stop5062" + style="stop-color:black;stop-opacity:1;" /> + <stop + offset="1" + id="stop5064" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + id="radialGradient5031" + r="117.14286" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4051"> + <stop + offset="0" + id="stop4053" + style="stop-color:white;stop-opacity:1;" /> + <stop + offset="1" + id="stop4055" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4059"> + <stop + offset="0" + id="stop4061" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop4063" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4097"> + <stop + offset="0" + id="stop4099" + style="stop-color:black;stop-opacity:1;" /> + <stop + offset="1" + id="stop4101" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4109"> + <stop + offset="0" + id="stop4111" + style="stop-color:white;stop-opacity:1;" /> + <stop + offset="1" + id="stop4113" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient4117"> + <stop + offset="0" + id="stop4119" + style="stop-color:white;stop-opacity:1;" /> + <stop + offset="1" + id="stop4121" + style="stop-color:white;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient4125"> + <stop + offset="0" + id="stop4127" + style="stop-color:black;stop-opacity:1;" /> + <stop + offset="1" + id="stop4129" + style="stop-color:black;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4134"> + <stop + offset="0" + id="stop4136" + style="stop-color:#3465a4;stop-opacity:1;" /> + <stop + offset="1" + id="stop4138" + style="stop-color:#2d578e;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13444" + x1="302.85715" + y1="366.64789" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x2="302.85715" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5048" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + id="radialGradient13446" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <radialGradient + inkscape:collect="always" + id="radialGradient13448" + r="117.14286" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13450" + x1="19.864109" + y1="17.906694" + x2="37.166458" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4134" + y2="41.594772" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13452" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4125" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13454" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4117" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13456" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13458" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(4,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13460" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(8,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13462" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(12,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13464" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(16,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13466" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(20,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13468" + x1="22.509596" + y1="1.9792649" + gradientTransform="translate(-2.2e-6,0)" + x2="31.603951" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4051" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13470" + x1="22.937496" + y1="29.93535" + x2="22.937496" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4097" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13472" + x1="25.044359" + y1="20.624216" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x2="25.791954" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4109" + y2="28.863333" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13512" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(16,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13556" + x1="302.85715" + y1="366.64789" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x2="302.85715" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5048" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + id="radialGradient13558" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <radialGradient + inkscape:collect="always" + id="radialGradient13560" + r="117.14286" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13562" + x1="19.864109" + y1="17.906694" + x2="37.166458" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4134" + y2="41.594772" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13564" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4125" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13566" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4117" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13568" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13570" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(4,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13572" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(8,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13574" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(12,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13576" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(16,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13578" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(20,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13580" + x1="22.509596" + y1="1.9792649" + gradientTransform="translate(-2.2e-6,0)" + x2="31.603951" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4051" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13582" + x1="22.937496" + y1="29.93535" + x2="22.937496" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4097" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + id="linearGradient13584" + x1="25.044359" + y1="20.624216" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x2="25.791954" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4109" + y2="28.863333" /> + <linearGradient + id="linearGradient5048-553"> + <stop + offset="0" + id="stop22302" + style="stop-color:#000000;stop-opacity:0;" /> + <stop + offset="0.5" + id="stop22304" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop22306" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4134-983"> + <stop + offset="0" + id="stop22322" + style="stop-color:#346500;stop-opacity:1;" /> + <stop + offset="1" + id="stop22324" + style="stop-color:#2d5700;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-435"> + <stop + offset="0" + id="stop22340" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop22342" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-801"> + <stop + offset="0" + id="stop22346" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop22348" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-394"> + <stop + offset="0" + id="stop22352" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop22354" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-756"> + <stop + offset="0" + id="stop22358" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop22360" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-158"> + <stop + offset="0" + id="stop22364" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop22366" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-607"> + <stop + offset="0" + id="stop22370" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop22372" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4097-506"> + <stop + offset="0" + id="stop22382" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop22384" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4109-629"> + <stop + offset="0" + id="stop22388" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + offset="1" + id="stop22390" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13444-386" + y2="609.50507" + y1="366.64789" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x2="302.85715" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5048-640" + x1="302.85715" /> + <linearGradient + id="linearGradient5048-640"> + <stop + offset="0" + id="stop22977" + style="stop-color:#000000;stop-opacity:0;" /> + <stop + offset="0.5" + id="stop22979" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop22981" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + id="radialGradient13446-878" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060-189" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5060-189"> + <stop + offset="0" + id="stop22985" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop22987" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + id="radialGradient13448-893" + r="117.14286" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060-614" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5060-614"> + <stop + offset="0" + id="stop22991" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop22993" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13450-291" + y2="41.594772" + y1="17.906694" + x2="37.166458" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4134-263" + x1="19.864109" /> + <linearGradient + id="linearGradient4134-263"> + <stop + offset="0" + id="stop22997" + style="stop-color:#346500;stop-opacity:1;" /> + <stop + offset="1" + id="stop22999" + style="stop-color:#2d5700;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13452-630" + y2="2.1249981" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4125-44" + x1="19.500004" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4125-44"> + <stop + offset="0" + id="stop23003" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23005" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13454-799" + y2="2.1249981" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4117-937" + x1="19.500004" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4117-937"> + <stop + offset="0" + id="stop23009" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + offset="1" + id="stop23011" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13456-439" + y2="11.352011" + y1="4.4145103" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059-765" + x1="9.1648445" /> + <linearGradient + id="linearGradient4059-765"> + <stop + offset="0" + id="stop23015" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop23017" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13458-70" + y2="11.352011" + y1="4.4145103" + gradientTransform="translate(4,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059-23" + x1="9.1648445" /> + <linearGradient + id="linearGradient4059-23"> + <stop + offset="0" + id="stop23021" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop23023" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13460-46" + y2="11.352011" + y1="4.4145103" + gradientTransform="translate(8,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059-602" + x1="9.1648445" /> + <linearGradient + id="linearGradient4059-602"> + <stop + offset="0" + id="stop23027" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop23029" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13462-772" + y2="11.352011" + y1="4.4145103" + gradientTransform="translate(12,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059-683" + x1="9.1648445" /> + <linearGradient + id="linearGradient4059-683"> + <stop + offset="0" + id="stop23033" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop23035" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13464-861" + y2="11.352011" + y1="4.4145103" + gradientTransform="translate(16,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059-588" + x1="9.1648445" /> + <linearGradient + id="linearGradient4059-588"> + <stop + offset="0" + id="stop23039" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop23041" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13466-479" + y2="11.352011" + y1="4.4145103" + gradientTransform="translate(20,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059-524" + x1="9.1648445" /> + <linearGradient + id="linearGradient4059-524"> + <stop + offset="0" + id="stop23045" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop23047" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13468-669" + y2="58.909889" + y1="1.9792649" + gradientTransform="translate(-2.2e-6,0)" + x2="31.603951" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4051-546" + x1="22.509596" /> + <linearGradient + inkscape:collect="always" + id="linearGradient4051-546"> + <stop + offset="0" + id="stop23051" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + offset="1" + id="stop23053" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13470-480" + y2="40.689152" + y1="29.93535" + x2="22.937496" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4097-418" + x1="22.937496" /> + <linearGradient + id="linearGradient4097-418"> + <stop + offset="0" + id="stop23057" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23059" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient13472-992" + y2="28.863333" + y1="20.624216" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x2="25.791954" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4109-10" + x1="25.044359" /> + <linearGradient + id="linearGradient4109-10"> + <stop + offset="0" + id="stop23063" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + offset="1" + id="stop23065" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient5048-640-390"> + <stop + offset="0" + id="stop23773" + style="stop-color:#000000;stop-opacity:0;" /> + <stop + offset="0.5" + id="stop23775" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23777" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4134-263-738"> + <stop + offset="0" + id="stop23793" + style="stop-color:#340000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23795" + style="stop-color:#2d0000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-765-0"> + <stop + offset="0" + id="stop23811" + style="stop-color:#ed0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23813" + style="stop-color:#b10000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-23-198"> + <stop + offset="0" + id="stop23817" + style="stop-color:#ed0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23819" + style="stop-color:#b10000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-602-642"> + <stop + offset="0" + id="stop23823" + style="stop-color:#ed0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23825" + style="stop-color:#b10000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-683-70"> + <stop + offset="0" + id="stop23829" + style="stop-color:#ed0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23831" + style="stop-color:#b10000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-588-551"> + <stop + offset="0" + id="stop23835" + style="stop-color:#ed0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23837" + style="stop-color:#b10000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-524-838"> + <stop + offset="0" + id="stop23841" + style="stop-color:#ed0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23843" + style="stop-color:#b10000;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4097-418-303"> + <stop + offset="0" + id="stop23853" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23855" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4109-10-161"> + <stop + offset="0" + id="stop23859" + style="stop-color:#ff0000;stop-opacity:1;" /> + <stop + offset="1" + id="stop23861" + style="stop-color:#ff0000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient24431" + x1="302.85715" + y1="366.64789" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x2="302.85715" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5048" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + id="radialGradient24433" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <radialGradient + inkscape:collect="always" + id="radialGradient24435" + r="117.14286" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24437" + x1="19.864109" + y1="17.906694" + x2="37.166458" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4134" + y2="41.594772" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24439" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4125" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24441" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4117" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24443" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24445" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(4,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24447" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(8,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24449" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(12,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24451" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(16,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24453" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(20,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24455" + x1="22.509596" + y1="1.9792649" + gradientTransform="translate(-2.2e-6,0)" + x2="31.603951" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4051" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24457" + x1="22.937496" + y1="29.93535" + x2="22.937496" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4097" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24459" + x1="25.044359" + y1="20.624216" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x2="25.791954" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4109" + y2="28.863333" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24559" + x1="302.85715" + y1="366.64789" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x2="302.85715" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5048" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + id="radialGradient24561" + r="117.14286" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <radialGradient + inkscape:collect="always" + id="radialGradient24563" + r="117.14286" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient5060" + fy="486.64789" + fx="605.71429" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24565" + x1="19.864109" + y1="17.906694" + x2="37.166458" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4134" + y2="41.594772" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24567" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4125" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24569" + x1="19.500004" + y1="10.687498" + x2="19.500004" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4117" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24571" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24573" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(4,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24575" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(8,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24577" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(12,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24579" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(16,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24581" + x1="9.1648445" + y1="4.4145103" + gradientTransform="translate(20,0)" + x2="9.125" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4059" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24583" + x1="22.509596" + y1="1.9792649" + gradientTransform="translate(-2.2e-6,0)" + x2="31.603951" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4051" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24585" + x1="22.937496" + y1="29.93535" + x2="22.937496" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4097" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + id="linearGradient24587" + x1="25.044359" + y1="20.624216" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x2="25.791954" + gradientUnits="userSpaceOnUse" + xlink:href="#linearGradient4109" + y2="28.863333" /> + <linearGradient + id="linearGradient5048-597"> + <stop + offset="0" + id="stop24888" + style="stop-color:#000000;stop-opacity:0;" /> + <stop + offset="0.5" + id="stop24890" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop24892" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5060-848"> + <stop + offset="0" + id="stop24896" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop24898" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient5060-139"> + <stop + offset="0" + id="stop24902" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop24904" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4134-168"> + <stop + offset="0" + id="stop24908" + style="stop-color:#346500;stop-opacity:1;" /> + <stop + offset="1" + id="stop24910" + style="stop-color:#2d5700;stop-opacity:1;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient4125-691"> + <stop + offset="0" + id="stop24914" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop24916" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + id="linearGradient4117-994"> + <stop + offset="0" + id="stop24920" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + offset="1" + id="stop24922" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-309"> + <stop + offset="0" + id="stop24926" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop24928" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-684"> + <stop + offset="0" + id="stop24932" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop24934" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-264"> + <stop + offset="0" + id="stop24938" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop24940" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-61"> + <stop + offset="0" + id="stop24944" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop24946" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-351"> + <stop + offset="0" + id="stop24950" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop24952" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4059-254"> + <stop + offset="0" + id="stop24956" + style="stop-color:#edd400;stop-opacity:1;" /> + <stop + offset="1" + id="stop24958" + style="stop-color:#b19e00;stop-opacity:1;" /> + </linearGradient> + <linearGradient + id="linearGradient4051-764"> + <stop + offset="0" + id="stop24962" + style="stop-color:#9a9a93;stop-opacity:1;" /> + <stop + offset="1" + id="stop24964" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4097-965"> + <stop + offset="0" + id="stop24968" + style="stop-color:#000000;stop-opacity:1;" /> + <stop + offset="1" + id="stop24970" + style="stop-color:#000000;stop-opacity:0;" /> + </linearGradient> + <linearGradient + id="linearGradient4109-735"> + <stop + offset="0" + id="stop24974" + style="stop-color:#ffff00;stop-opacity:1;" /> + <stop + offset="1" + id="stop24976" + style="stop-color:#ffff00;stop-opacity:0;" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5048" + id="linearGradient25463" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x1="302.85715" + y1="366.64789" + x2="302.85715" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient25465" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient25467" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4134" + id="linearGradient25469" + gradientUnits="userSpaceOnUse" + x1="19.864109" + y1="17.906694" + x2="37.166458" + y2="41.594772" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4125" + id="linearGradient25471" + gradientUnits="userSpaceOnUse" + x1="19.500004" + y1="10.687498" + x2="19.500004" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4117" + id="linearGradient25473" + gradientUnits="userSpaceOnUse" + x1="19.500004" + y1="10.687498" + x2="19.500004" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25475" + gradientUnits="userSpaceOnUse" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25477" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(4,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25479" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(8,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25481" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(12,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25483" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(16,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25485" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(20,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4051" + id="linearGradient25487" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-2.2e-6,0)" + x1="22.509596" + y1="1.9792649" + x2="31.603951" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4097" + id="linearGradient25489" + gradientUnits="userSpaceOnUse" + x1="22.937496" + y1="29.93535" + x2="22.937496" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4109" + id="linearGradient25491" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x1="25.044359" + y1="20.624216" + x2="25.791954" + y2="28.863333" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5048" + id="linearGradient25739" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x1="302.85715" + y1="366.64789" + x2="302.85715" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient25741" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060" + id="radialGradient25743" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4125" + id="linearGradient25747" + gradientUnits="userSpaceOnUse" + x1="19.500004" + y1="10.687498" + x2="19.500004" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4117" + id="linearGradient25749" + gradientUnits="userSpaceOnUse" + x1="19.500004" + y1="10.687498" + x2="19.500004" + y2="2.1249981" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25751" + gradientUnits="userSpaceOnUse" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25753" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(4,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25755" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(8,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25757" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(12,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25759" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(16,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059" + id="linearGradient25761" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(20,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4051" + id="linearGradient25763" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-2.2e-6,0)" + x1="22.509596" + y1="1.9792649" + x2="31.603951" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4097" + id="linearGradient25765" + gradientUnits="userSpaceOnUse" + x1="22.937496" + y1="29.93535" + x2="22.937496" + y2="40.689152" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4109" + id="linearGradient25767" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.919614,0,0,0.919598,1.768501,2.487437)" + x1="25.044359" + y1="20.624216" + x2="25.791954" + y2="28.863333" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5048-597" + id="linearGradient26827" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)" + x1="302.85715" + y1="366.64789" + x2="302.85715" + y2="609.50507" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060-848" + id="radialGradient26829" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5060-139" + id="radialGradient26831" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)" + cx="605.71429" + cy="486.64789" + fx="605.71429" + fy="486.64789" + r="117.14286" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059-309" + id="linearGradient26839" + gradientUnits="userSpaceOnUse" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059-684" + id="linearGradient26841" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(4,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059-264" + id="linearGradient26843" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(8,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059-61" + id="linearGradient26845" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(12,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059-351" + id="linearGradient26847" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(16,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4059-254" + id="linearGradient26849" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(20,0)" + x1="9.1648445" + y1="4.4145103" + x2="9.125" + y2="11.352011" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4109-735" + id="linearGradient26858" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.6203552,0,0,0.6494232,9.344411,8.7449428)" + x1="25.044359" + y1="20.624216" + x2="25.791954" + y2="28.863333" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4097-965" + id="linearGradient26861" + gradientUnits="userSpaceOnUse" + x1="22.937496" + y1="29.93535" + x2="22.937496" + y2="40.689152" + gradientTransform="matrix(0.6745822,0,0,0.7062034,8.1514117,6.9883063)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4051-764" + id="linearGradient26864" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.6745822,0,0,0.7062034,8.1514102,6.9883063)" + x1="22.509596" + y1="1.9792649" + x2="31.603951" + y2="58.909889" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4125-691" + id="linearGradient26874" + gradientUnits="userSpaceOnUse" + x1="19.500004" + y1="10.687498" + x2="19.500004" + y2="2.1249981" + gradientTransform="matrix(0.6745822,0,0,0.7062034,8.1514117,6.9883063)" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient4117-994" + id="linearGradient26876" + gradientUnits="userSpaceOnUse" + x1="19.500004" + y1="10.687498" + x2="19.500004" + y2="2.1249981" + gradientTransform="matrix(0.6745822,0,0,0.7062034,8.1514117,6.9883063)" /> + </defs> + <metadata + id="metadata7859"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:creator> + <cc:Agent> + <dc:title>Jakub Steiner</dc:title> + </cc:Agent> + </dc:creator> + <dc:source>http://jimmac.musichall.cz</dc:source> + <cc:license + rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> + <dc:title /> + <dc:subject> + <rdf:Bag> + <rdf:li>snapshot</rdf:li> + <rdf:li>camera</rdf:li> + <rdf:li>photo</rdf:li> + <rdf:li>compact</rdf:li> + <rdf:li>snap</rdf:li> + </rdf:Bag> + </dc:subject> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> + <cc:permits + rdf:resource="http://web.resource.org/cc/Reproduction" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/Distribution" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/Notice" /> + <cc:permits + rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/ShareAlike" /> + <cc:requires + rdf:resource="http://web.resource.org/cc/SourceCode" /> + </cc:License> + </rdf:RDF> + </metadata> + <g + inkscape:groupmode="layer" + id="layer2" + inkscape:label="bottom" + style="display:inline" + transform="translate(0,80)"> + <g + id="g25705" + transform="matrix(1.8666694,0,0,1.95417,40.803984,-77.285467)" + inkscape:label="Layer 1"> + <g + transform="matrix(0.02268614,0,0,0.01568626,43.42786,42.48706)" + id="g25707" + style="opacity:0.58730164;display:inline"> + <rect + id="rect25709" + x="-1559.2523" + y="-150.69685" + width="1339.6335" + height="478.35718" + style="opacity:0.40206185;color:#000000;fill:url(#linearGradient25739);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /> + <path + d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z" + id="path25711" + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient25741);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="cccc" /> + <path + id="path25713" + d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z" + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient25743);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="cccc" /> + </g> + <path + id="path25715" + d="m 39.494883,43.500017 0,-27.009746 -1.191582,0 0,-2.828281 1.191582,0 0,-7.7357849 -5.468964,-4.4204484 -28.4801477,0 -0.030906,41.9942603 3.047634,0 0.9375,-0.9375 1.1250007,0.9375 22.874999,0 0.875,-0.9375 1.125,0.9375 3.994884,0 z" + style="fill:#d40000;fill-opacity:1;fill-rule:evenodd;stroke:#c32934;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + sodipodi:nodetypes="cccccccccccccccc" /> + <path + id="path25717" + d="m 32.500005,2.5937499 0,8.6874971 c 0,1.229187 -0.989563,2.218749 -2.21875,2.218749 l -21.5625038,0 c -1.2291876,0 -2.2187502,-0.989562 -2.2187502,-2.218749 l 0,-8.6874971 c 0,0 26.000004,0 26.000004,0 z" + style="opacity:0.18592966;color:#000000;fill:url(#linearGradient25747);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient25749);stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccccccc" /> + <g + id="g25719"> + <path + d="m 11,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.8199629,0 -1.4800775,-0.660115 -1.4800775,-1.480078 l 0,-8.5415156 c 0,0 2.9601555,0 2.9601555,0 z" + id="path25721" + style="color:#000000;fill:url(#linearGradient25751);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + id="path25723" + d="m 15,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + style="color:#000000;fill:url(#linearGradient25753);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + d="m 19,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path25725" + style="color:#000000;fill:url(#linearGradient25755);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + id="path25727" + d="m 23,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + style="color:#000000;fill:url(#linearGradient25757);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + d="m 27,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path25729" + style="color:#000000;fill:url(#linearGradient25759);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + id="path25731" + d="m 31,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + style="color:#000000;fill:url(#linearGradient25761);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + </g> + <path + id="path25733" + d="m 38.528573,42.499985 0,-25.062124 -1.050532,0 0,-4.730225 1.050532,0 -0.07295,-6.2869785 -4.864604,-3.941393 -27.0712672,0 -0.029139,40.0207205 1.6411132,0 1.3258248,-1.237437 1.6793792,1.237437 21.831922,0 1.325826,-1.149049 1.59099,1.149049 2.642903,0 z" + style="fill:none;stroke:url(#linearGradient25763);stroke-width:0.99999934px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.453125" + sodipodi:nodetypes="cccccccccccccccc" /> + <rect + id="rect25735" + x="9.4999981" + y="18.500008" + width="25" + height="24.875011" + ry="1.4800782" + rx="1.4800774" + style="opacity:0.18592966;color:#000000;fill:none;stroke:url(#linearGradient25765);stroke-width:1.00000048;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.453125;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> + <rect + id="rect25737" + x="10.504832" + y="19.500008" + width="22.990351" + height="22.875011" + ry="0.46875" + rx="0.46875" + style="opacity:0.18592966;color:#000000;fill:none;stroke:url(#linearGradient25767);stroke-width:1.00000072;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.453125;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> + </g> + </g> + <g + inkscape:groupmode="layer" + id="layer3" + inkscape:label="middle" + style="display:none" + transform="translate(0,80)"> + <g + style="opacity:0.58730164;display:inline" + id="g24399" + transform="matrix(0.01530367,0,0,0.01107769,37.447073,36.992813)"> + <rect + style="opacity:0.40206185;color:#000000;fill:url(#linearGradient26827);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + height="478.35718" + width="1339.6335" + y="-150.69685" + x="-1559.2523" + id="rect24401" /> + <path + sodipodi:nodetypes="cccc" + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient26829);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + id="path24403" + d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z" /> + <path + sodipodi:nodetypes="cccc" + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient26831);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z" + id="path24405" /> + </g> + <path + sodipodi:nodetypes="cccccccccccccccc" + style="fill:#ac9d93;fill-opacity:1;fill-rule:evenodd;stroke:#a9a9ac;stroke-width:0.69021165px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 34.793957,37.708166 0,-19.074374 -0.80382,0 0,-1.997342 0.80382,0 0,-5.463038 -3.689266,-3.1217352 -19.212201,0 -0.02085,29.6564892 2.05588,0 0.63242,-0.662065 0.758906,0.662065 15.431067,0 0.590259,-0.662065 0.758905,0.662065 2.694878,0 z" + id="path24407" /> + <path + sodipodi:nodetypes="ccccccc" + style="opacity:0.18592966;color:#000000;fill:url(#linearGradient26874);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient26876);stroke-width:0.69021189;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + d="m 30.075337,8.8200213 0,6.1351397 c 0,0.868056 -0.667542,1.566888 -1.49673,1.566888 l -14.545681,0 c -0.829188,0 -1.496729,-0.698832 -1.496729,-1.566888 l 0,-6.1351397 c 0,0 17.53914,0 17.53914,0 z" + id="path24409" /> + <g + id="g24411" + transform="matrix(0.6745822,0,0,0.7062034,8.1514117,6.9883063)"> + <path + sodipodi:nodetypes="ccsccc" + style="color:#000000;fill:url(#linearGradient26839);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + id="path24413" + d="m 11,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.8199629,0 -1.4800775,-0.660115 -1.4800775,-1.480078 l 0,-8.5415156 c 0,0 2.9601555,0 2.9601555,0 z" /> + <path + sodipodi:nodetypes="ccsccc" + style="color:#000000;fill:url(#linearGradient26841);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + d="m 15,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path24415" /> + <path + sodipodi:nodetypes="ccsccc" + style="color:#000000;fill:url(#linearGradient26843);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + id="path24417" + d="m 19,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" /> + <path + sodipodi:nodetypes="ccsccc" + style="color:#000000;fill:url(#linearGradient26845);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + d="m 23,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path24419" /> + <path + sodipodi:nodetypes="ccsccc" + style="color:#000000;fill:url(#linearGradient26847);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + id="path24421" + d="m 27,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" /> + <path + sodipodi:nodetypes="ccsccc" + style="color:#000000;fill:url(#linearGradient26849);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + d="m 31,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path24423" /> + </g> + <path + sodipodi:nodetypes="cccccccccccccccc" + style="fill:none;stroke:url(#linearGradient26864);stroke-width:0.6902113px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.453125" + d="m 34.142101,37.00194 0,-17.698957 -0.70867,0 0,-3.340501 0.70867,0 -0.04921,-4.439886 -3.281575,-2.7834247 -18.261795,0 -0.01966,28.2627687 1.107066,0 0.894377,-0.873882 1.13288,0.873882 14.727426,0 0.894378,-0.811462 1.073254,0.811462 1.782855,0 z" + id="path24425" /> + <rect + style="opacity:0.18592966;color:#000000;fill:none;stroke:url(#linearGradient26861);stroke-width:0.69021207;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.453125;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + rx="0.99843389" + ry="1.0452362" + height="17.566818" + width="16.864555" + y="20.053074" + x="14.559941" + id="rect24427" /> + <rect + style="opacity:0.18592966;color:#000000;fill:none;stroke:url(#linearGradient26858);stroke-width:0.69021225;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.453125;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + rx="0.31621042" + ry="0.33103284" + height="16.154411" + width="15.508882" + y="20.759277" + x="15.237784" + id="rect24429" /> + </g> + <g + inkscape:groupmode="layer" + id="layer1" + inkscape:label="Layer 1" + style="display:inline" + transform="translate(0,80)"> + <path + id="path8952" + sodipodi:cx="7.375" + sodipodi:cy="35.875" + transform="matrix(2.541,0,0,2.541,11.285653,-76.240557)" + d="m 18.875,35.875 a 11.5,5.75 0 1 1 -23,0 11.5,5.75 0 1 1 23,0 z" + sodipodi:type="arc" + style="opacity:0.24117647;color:#000000;fill:url(#radialGradient8960);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + sodipodi:ry="5.75" + sodipodi:rx="11.5" /> + <g + id="g2655" + transform="matrix(1.8666694,0,0,1.95417,2.2680351,-49.772991)" + inkscape:label="Layer 1"> + <g + transform="matrix(0.02268614,0,0,0.01568626,43.42786,42.48706)" + id="g5022" + style="opacity:0.58730164;display:inline"> + <rect + id="rect4173" + x="-1559.2523" + y="-150.69685" + width="1339.6335" + height="478.35718" + style="opacity:0.40206185;color:#000000;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" /> + <path + d="m -219.61876,-150.68038 c 0,0 0,478.33079 0,478.33079 142.874166,0.90045 345.40022,-107.16966 345.40014,-239.196175 0,-132.026537 -159.436816,-239.134595 -345.40014,-239.134615 z" + id="path5058" + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="cccc" /> + <path + id="path5018" + d="m -1559.2523,-150.68038 c 0,0 0,478.33079 0,478.33079 -142.8742,0.90045 -345.4002,-107.16966 -345.4002,-239.196175 0,-132.026537 159.4368,-239.134595 345.4002,-239.134615 z" + style="opacity:0.40206185;color:#000000;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="cccc" /> + </g> + <path + id="path1333" + d="m 39.494883,43.500017 0,-27.009746 -1.191582,0 0,-2.828281 1.191582,0 0,-7.7357849 -5.468964,-4.4204484 -28.4801477,0 -0.030906,41.9942603 3.047634,0 0.9375,-0.9375 1.1250007,0.9375 22.874999,0 0.875,-0.9375 1.125,0.9375 3.994884,0 z" + style="fill:url(#linearGradient4140);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + sodipodi:nodetypes="cccccccccccccccc" /> + <path + id="rect4115" + d="m 32.500005,2.5937499 0,8.6874971 c 0,1.229187 -0.989563,2.218749 -2.21875,2.218749 l -21.5625038,0 c -1.2291876,0 -2.2187502,-0.989562 -2.2187502,-2.218749 l 0,-8.6874971 c 0,0 26.000004,0 26.000004,0 z" + style="opacity:0.18592966;color:#000000;fill:url(#linearGradient4131);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4123);stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccccccc" /> + <g + id="g4087"> + <path + d="m 11,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.8199629,0 -1.4800775,-0.660115 -1.4800775,-1.480078 l 0,-8.5415156 c 0,0 2.9601555,0 2.9601555,0 z" + id="rect3163" + style="color:#000000;fill:url(#linearGradient4065);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + id="path4067" + d="m 15,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + style="color:#000000;fill:url(#linearGradient4069);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + d="m 19,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path4071" + style="color:#000000;fill:url(#linearGradient4073);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + id="path4075" + d="m 23,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + style="color:#000000;fill:url(#linearGradient4077);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + d="m 27,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + id="path4079" + style="color:#000000;fill:url(#linearGradient4081);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + <path + id="path4083" + d="m 31,1.9662134 0,8.5415156 c 0,0.819963 -0.660115,1.480078 -1.480078,1.480078 -0.819963,0 -1.480078,-0.660115 -1.480078,-1.480078 l 0,-8.5415156 c 0,0 2.960156,0 2.960156,0 z" + style="color:#000000;fill:url(#linearGradient4085);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;marker:none;visibility:visible;display:inline;overflow:visible" + sodipodi:nodetypes="ccsccc" /> + </g> + <path + id="path2208" + d="m 38.528573,42.499985 0,-25.062124 -1.050532,0 0,-4.730225 1.050532,0 -0.07295,-6.2869785 -4.864604,-3.941393 -27.0712672,0 -0.029139,40.0207205 1.6411132,0 1.3258248,-1.237437 1.6793792,1.237437 21.831922,0 1.325826,-1.149049 1.59099,1.149049 2.642903,0 z" + style="fill:none;stroke:url(#linearGradient4057);stroke-width:0.99999934px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.453125" + sodipodi:nodetypes="cccccccccccccccc" /> + <rect + id="rect4095" + x="9.4999981" + y="18.500008" + width="25" + height="24.875011" + ry="1.4800782" + rx="1.4800774" + style="opacity:0.18592966;color:#000000;fill:none;stroke:url(#linearGradient4103);stroke-width:1.00000048;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.453125;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> + <rect + id="rect4105" + x="10.504832" + y="19.500008" + width="22.990351" + height="22.875011" + ry="0.46875" + rx="0.46875" + style="opacity:0.18592966;color:#000000;fill:none;stroke:url(#linearGradient4107);stroke-width:1.00000072;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.453125;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" /> + </g> + </g> +</svg> diff --git a/rapid/glade3/rapid.glade b/rapid/glade3/rapid.glade index 539ac9c..0954b5c 100644 --- a/rapid/glade3/rapid.glade +++ b/rapid/glade3/rapid.glade @@ -9,7 +9,7 @@ <property name="modal">True</property> <property name="window_position">center-on-parent</property> <property name="default_height">500</property> - <property name="icon">rapid-photo-downloader-about.png</property> + <property name="icon">rapid-photo-downloader.svg</property> <property name="type_hint">dialog</property> <property name="has_separator">False</property> <signal name="destroy" handler="on_preferencesdialog_destroy"/> @@ -1432,7 +1432,7 @@ <child> <widget class="GtkImage" id="image77"> <property name="visible">True</property> - <property name="icon_name">emblem-photos</property> + <property name="stock">rapid-photo-downloader-jobcode</property> </widget> <packing> <property name="expand">False</property> @@ -2561,81 +2561,6 @@ You can download photos from multiple devices simultaneously, or you can specify </packing> </child> <child> - <widget class="GtkRadioButton" id="backup_ignore_radiobutton"> - <property name="label" translatable="yes">Ignore</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> - <property name="group">backup_error_radiobutton</property> - <signal name="toggled" handler="on_backup_ignore_radiobutton_toggled"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">13</property> - <property name="bottom_attach">14</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkRadioButton" id="backup_warning_radiobutton"> - <property name="label" translatable="yes">Report a warning</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> - <property name="group">backup_error_radiobutton</property> - <signal name="toggled" handler="on_backup_warning_radiobutton_toggled"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">12</property> - <property name="bottom_attach">13</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkRadioButton" id="backup_error_radiobutton"> - <property name="label" translatable="yes">Report an error</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_backup_error_radiobutton_toggled"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">11</property> - <property name="bottom_attach">12</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="missing_backup_label"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="ypad">12</property> - <property name="label" translatable="yes"><b>Missing Backup Devices</b></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">9</property> - <property name="bottom_attach">10</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> <widget class="GtkRadioButton" id="add_identifier_radiobutton"> <property name="label" translatable="yes">Add unique identifier</property> <property name="visible">True</property> @@ -2650,8 +2575,8 @@ You can download photos from multiple devices simultaneously, or you can specify <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> <property name="y_options">GTK_FILL</property> </packing> </child> @@ -2668,51 +2593,17 @@ You can download photos from multiple devices simultaneously, or you can specify <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label13"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="ypad">12</property> - <property name="label" translatable="yes">Choose whether to skip downloading the file, or to add a unique indentifier.</property> - <property name="wrap">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkCheckButton" id="indicate_download_error_checkbutton"> - <property name="label" translatable="yes">Report an error</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_indicate_download_error_checkbutton_toggled"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">2</property> <property name="bottom_attach">3</property> <property name="y_options">GTK_FILL</property> </packing> </child> <child> - <widget class="GtkLabel" id="label19"> + <widget class="GtkLabel" id="label13"> <property name="visible">True</property> <property name="xalign">0</property> <property name="ypad">12</property> - <property name="label" translatable="yes">Specify what to do when a photo or video of the same name has already been downloaded or backed up.</property> + <property name="label" translatable="yes">When a photo or video of the same name has already been downloaded, choose whether to skip downloading the file, or to add a unique indentifier.</property> <property name="wrap">True</property> </widget> <packing> @@ -2724,21 +2615,6 @@ You can download photos from multiple devices simultaneously, or you can specify </packing> </child> <child> - <widget class="GtkLabel" id="label3"> - <property name="xalign">0</property> - <property name="ypad">12</property> - <property name="label" translatable="yes">Specify what to do when there are no backup devices.</property> - <property name="wrap">True</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">10</property> - <property name="bottom_attach">11</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> <widget class="GtkLabel" id="label6"> <property name="visible">True</property> <property name="xalign">0</property> @@ -2749,8 +2625,8 @@ You can download photos from multiple devices simultaneously, or you can specify <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> <property name="y_options">GTK_FILL</property> </packing> </child> @@ -2768,8 +2644,8 @@ You can download photos from multiple devices simultaneously, or you can specify <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">7</property> - <property name="bottom_attach">8</property> + <property name="top_attach">5</property> + <property name="bottom_attach">6</property> </packing> </child> <child> @@ -2785,8 +2661,8 @@ You can download photos from multiple devices simultaneously, or you can specify <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">8</property> - <property name="bottom_attach">9</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> </packing> </child> <child> @@ -2822,6 +2698,30 @@ You can download photos from multiple devices simultaneously, or you can specify <child> <placeholder/> </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> </widget> <packing> <property name="position">1</property> @@ -2925,7 +2825,7 @@ You can download photos from multiple devices simultaneously, or you can specify <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="border_width">5</property> <property name="destroy_with_parent">True</property> - <property name="icon">rapid-photo-downloader-about.png</property> + <property name="icon">rapid-photo-downloader.svg</property> <property name="type_hint">normal</property> <property name="program_name">Rapid Photo Downloader</property> <property name="copyright" translatable="yes">Copyright Damon Lynch 2007-10</property> @@ -2937,7 +2837,8 @@ Rapid Photo Downloader is distributed in the hope that it will be useful, but WI You should have received a copy of the GNU General Public License along with Rapid Photo Downloader; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</property> <property name="authors">Damon Lynch <damonlynch@gmail.com></property> - <property name="translator_credits">Lőrincz András <level.andrasnak@gmail.com> + <property name="translator_credits">Anton Alyab'ev <subeditor@dolgopa.org> +Lőrincz András <level.andrasnak@gmail.com> Michel Ange <michelange@wanadoo.fr> Alain J. Baudrez <a.baudrez@gmail.com> Martin Egger <martin.egger@gmx.net> @@ -2957,7 +2858,7 @@ Marco Solari <marcosolari@gmail.com> Toni Lähdekorpi <toni@lygon.net> Ulf Urdén <ulf.urden@purplescout.com> Julien Valroff <julien@kirya.net></property> - <property name="logo">rapid-photo-downloader-about.png</property> + <property name="logo">rapid-photo-downloader.svg</property> <property name="wrap_license">True</property> <child internal-child="vbox"> <widget class="GtkVBox" id="dialog-vbox1"> @@ -2981,11 +2882,12 @@ Julien Valroff <julien@kirya.net></property> </child> </widget> <widget class="GtkWindow" id="rapidapp"> - <property name="width_request">600</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="title" translatable="yes">Rapid Photo Downloader</property> - <property name="icon">rapid-photo-downloader-about.png</property> + <property name="default_width">650</property> + <property name="icon">rapid-photo-downloader.svg</property> <signal name="destroy" handler="on_rapidapp_destroy"/> + <signal name="window_state_event" handler="on_rapidapp_window_state_event"/> <child> <widget class="GtkVBox" id="vbox10"> <property name="visible">True</property> @@ -2996,7 +2898,7 @@ Julien Valroff <julien@kirya.net></property> <child> <widget class="GtkMenuItem" id="menuitem7"> <property name="visible">True</property> - <property name="label" translatable="yes">_Photos</property> + <property name="label" translatable="yes">_File</property> <property name="use_underline">True</property> <child> <widget class="GtkMenu" id="menuitem7_menu"> @@ -3016,6 +2918,16 @@ Julien Valroff <julien@kirya.net></property> </widget> </child> <child> + <widget class="GtkImageMenuItem" id="menu_refresh"> + <property name="label">gtk-refresh</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="on_menu_refresh_activate"/> + <accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> <widget class="GtkImageMenuItem" id="menu_preferences"> <property name="label">gtk-preferences</property> <property name="visible">True</property> @@ -3039,6 +2951,76 @@ Julien Valroff <julien@kirya.net></property> </widget> </child> <child> + <widget class="GtkMenuItem" id="select_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Select</property> + <property name="use_underline">True</property> + <child> + <widget class="GtkMenu" id="select_menu"> + <child> + <widget class="GtkMenuItem" id="menu_select_all"> + <property name="visible">True</property> + <property name="label" translatable="yes">Select _All</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_menu_select_all_activate"/> + <accelerator key="a" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menu_select_all_photos"> + <property name="visible">True</property> + <property name="label" translatable="yes">Select All Pho_tos</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_menu_select_all_photos_activate"/> + <accelerator key="t" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menu_select_all_videos"> + <property name="visible">True</property> + <property name="label" translatable="yes">Select All Vi_deos</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_menu_select_all_videos_activate"/> + <accelerator key="d" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menu_select_none"> + <property name="visible">True</property> + <property name="label" translatable="yes">Se_lect None</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_menu_select_none_activate"/> + <accelerator key="l" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="menu_select_sep"> + <property name="visible">True</property> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menu_select_all_without_job_code"> + <property name="visible">True</property> + <property name="label" translatable="yes">Select All Without _Job Code</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_menu_select_all_without_job_code_activate"/> + <accelerator key="j" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + <child> + <widget class="GtkMenuItem" id="menu_select_all_with_job_code"> + <property name="visible">True</property> + <property name="label" translatable="yes">Select All Wit_h Job Code</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_menu_select_all_with_job_code_activate"/> + <accelerator key="h" signal="activate" modifiers="GDK_CONTROL_MASK"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + <child> <widget class="GtkMenuItem" id="menuitem10"> <property name="visible">True</property> <property name="label" translatable="yes">_View</property> @@ -3046,27 +3028,87 @@ Julien Valroff <julien@kirya.net></property> <child> <widget class="GtkMenu" id="menuitem10_menu"> <child> - <widget class="GtkCheckMenuItem" id="menu_display_thumbnails"> + <widget class="GtkCheckMenuItem" id="menu_display_selection"> <property name="visible">True</property> - <property name="label" translatable="yes">_Thumbnails</property> + <property name="label" translatable="yes">_Preview</property> <property name="use_underline">True</property> - <signal name="toggled" handler="on_menu_display_thumbnails_toggled"/> + <signal name="toggled" handler="on_menu_display_selection_toggled"/> </widget> </child> <child> - <widget class="GtkCheckMenuItem" id="menu_log_window"> + <widget class="GtkMenuItem" id="menu_preview_columns"> <property name="visible">True</property> - <property name="label" translatable="yes">_Error Log</property> + <property name="label" translatable="yes">P_review Columns</property> <property name="use_underline">True</property> - <signal name="toggled" handler="on_menu_log_window_toggled"/> + <child> + <widget class="GtkMenu" id="menu1"> + <property name="visible">True</property> + <child> + <widget class="GtkCheckMenuItem" id="menu_type_column"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Type</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_type_column_toggled"/> + </widget> + </child> + <child> + <widget class="GtkCheckMenuItem" id="menu_size_column"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Size</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_size_column_toggled"/> + </widget> + </child> + <child> + <widget class="GtkCheckMenuItem" id="menu_device_column"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Device</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_device_column_toggled"/> + </widget> + </child> + <child> + <widget class="GtkCheckMenuItem" id="menu_filename_column"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Filename</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_filename_column_toggled"/> + </widget> + </child> + <child> + <widget class="GtkCheckMenuItem" id="menu_path_column"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Path</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_path_column_toggled"/> + </widget> + </child> + </widget> + </child> </widget> </child> <child> - <widget class="GtkSeparatorMenuItem" id="separator5"> + <widget class="GtkCheckMenuItem" id="menu_preview_folders"> + <property name="visible">True</property> + <property name="label" translatable="yes">Preview _Folders</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_preview_folders_toggled"/> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="seperator20"> <property name="visible">True</property> </widget> </child> <child> + <widget class="GtkCheckMenuItem" id="menu_log_window"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Error Log</property> + <property name="use_underline">True</property> + <signal name="toggled" handler="on_menu_log_window_toggled"/> + </widget> + </child> + <child> <widget class="GtkMenuItem" id="menu_clear"> <property name="visible">True</property> <property name="label" translatable="yes">_Clear Completed Downloads</property> @@ -3074,6 +3116,11 @@ Julien Valroff <julien@kirya.net></property> <signal name="activate" handler="on_menu_clear_activate"/> </widget> </child> + <child> + <widget class="GtkSeparatorMenuItem" id="separator5"> + <property name="visible">True</property> + </widget> + </child> </widget> </child> </widget> @@ -3086,12 +3133,19 @@ Julien Valroff <julien@kirya.net></property> <child> <widget class="GtkMenu" id="help_menu"> <child> - <widget class="GtkMenuItem" id="menu_get_help_online"> - <property name="visible">True</property> + <widget class="GtkImageMenuItem" id="menu_get_help_online"> <property name="label" translatable="yes">_Get Help Online...</property> + <property name="visible">True</property> <property name="use_underline">True</property> + <property name="use_stock">False</property> <signal name="activate" handler="on_menu_get_help_online_activate"/> <accelerator key="F1" signal="activate"/> + <child internal-child="image"> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="icon_name">help</property> + </widget> + </child> </widget> </child> <child> @@ -3147,67 +3201,83 @@ Julien Valroff <julien@kirya.net></property> <property name="visible">True</property> <property name="spacing">12</property> <child> - <widget class="GtkHBox" id="hbox6"> + <widget class="GtkVPaned" id="main_vpaned"> <property name="visible">True</property> + <property name="can_focus">True</property> <child> - <widget class="GtkScrolledWindow" id="media_collection_scrolledwindow"> + <widget class="GtkVBox" id="device_vbox"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">automatic</property> - <property name="vscrollbar_policy">automatic</property> <child> - <widget class="GtkViewport" id="media_collection_viewport"> + <widget class="GtkHBox" id="media_collection_area_hbox"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">6</property> <child> - <widget class="GtkVBox" id="media_collection_vbox"> + <widget class="GtkScrolledWindow" id="media_collection_scrolledwindow"> <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> <child> - <placeholder/> + <widget class="GtkViewport" id="media_collection_viewport"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="resize_mode">queue</property> + <child> + <widget class="GtkVBox" id="media_collection_vbox"> + <property name="visible">True</property> + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> </child> </widget> + <packing> + <property name="padding">12</property> + <property name="position">0</property> + </packing> </child> </widget> + <packing> + <property name="position">0</property> + </packing> </child> </widget> <packing> - <property name="padding">12</property> - <property name="position">0</property> + <property name="resize">False</property> + <property name="shrink">False</property> </packing> </child> - </widget> - <packing> - <property name="position">0</property> - </packing> - </child> - <child> - <widget class="GtkHBox" id="hbox8"> - <property name="visible">True</property> <child> - <widget class="GtkScrolledWindow" id="image_scrolledwindow"> + <widget class="GtkTable" id="selection_table"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="vscrollbar_policy">never</property> + <property name="n_rows">2</property> + <property name="row_spacing">3</property> <child> - <widget class="GtkViewport" id="image_viewport"> - <property name="height_request">112</property> + <widget class="GtkHBox" id="selection_hbox"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <child> <placeholder/> </child> </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <placeholder/> </child> </widget> <packing> - <property name="padding">12</property> - <property name="position">0</property> + <property name="resize">True</property> + <property name="shrink">False</property> </packing> </child> </widget> <packing> - <property name="expand">False</property> - <property name="position">1</property> + <property name="position">0</property> </packing> </child> <child> @@ -3220,7 +3290,7 @@ Julien Valroff <julien@kirya.net></property> <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="position">2</property> + <property name="position">1</property> </packing> </child> </widget> @@ -3389,7 +3459,7 @@ Julien Valroff <julien@kirya.net></property> <property name="default_width">600</property> <property name="default_height">400</property> <property name="destroy_with_parent">True</property> - <property name="icon">rapid-photo-downloader-about.png</property> + <property name="icon">rapid-photo-downloader.svg</property> <property name="type_hint">dialog</property> <property name="has_separator">False</property> <signal name="close" handler="on_logdialog_close"/> diff --git a/rapid/glade3/video.png b/rapid/glade3/video.png Binary files differnew file mode 100644 index 0000000..ac1086b --- /dev/null +++ b/rapid/glade3/video.png diff --git a/rapid/glade3/video.svg b/rapid/glade3/video.svg deleted file mode 100644 index a03c672..0000000 --- a/rapid/glade3/video.svg +++ /dev/null @@ -1,1638 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://web.resource.org/cc/" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="48px" - height="48px" - id="svg4417" - sodipodi:version="0.32" - inkscape:version="0.45" - sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/mimetypes" - sodipodi:docname="video-x-generic.svg" - inkscape:export-filename="/home/andreas/project/gnome-icon-theme/scalable/categories/applications-multimedia.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" - inkscape:output_extension="org.inkscape.output.svg.inkscape"> - <defs - id="defs4419"> - <linearGradient - id="linearGradient2998"> - <stop - style="stop-color:white;stop-opacity:0;" - offset="0" - id="stop3001" /> - <stop - id="stop3007" - offset="0.5" - style="stop-color:white;stop-opacity:1;" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop3003" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient2996"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop2998" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop3000" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient2992"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop2994" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop2996" /> - </linearGradient> - <linearGradient - id="linearGradient6593"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop6595" /> - <stop - id="stop6601" - offset="0.5" - style="stop-color:#424a4d;stop-opacity:1;" /> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="1" - id="stop6597" /> - </linearGradient> - <linearGradient - id="linearGradient3010"> - <stop - id="stop3012" - offset="0" - style="stop-color:white;stop-opacity:1;" /> - <stop - id="stop3014" - offset="1" - style="stop-color:white;stop-opacity:0.4269006;" /> - </linearGradient> - <linearGradient - id="linearGradient3002"> - <stop - id="stop3004" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - id="stop3006" - offset="1" - style="stop-color:#2e3436;stop-opacity:1" /> - </linearGradient> - <linearGradient - id="linearGradient5737"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop5739" /> - <stop - style="stop-color:white;stop-opacity:0.32163742;" - offset="1" - id="stop5741" /> - </linearGradient> - <linearGradient - id="linearGradient5683"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop5685" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="1" - id="stop5687" /> - </linearGradient> - <linearGradient - id="linearGradient4790"> - <stop - style="stop-color:#555753;stop-opacity:1" - offset="0" - id="stop4792" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="1" - id="stop4794" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3897"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop3899" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop3901" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3209"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop3211" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop3213" /> - </linearGradient> - <linearGradient - id="linearGradient3202"> - <stop - id="stop3204" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - id="stop3206" - offset="1" - style="stop-color:#555753;stop-opacity:1" /> - </linearGradient> - <linearGradient - id="linearGradient3101"> - <stop - style="stop-color:#2e3436;stop-opacity:1;" - offset="0" - id="stop3103" /> - <stop - id="stop3109" - offset="0.12824793" - style="stop-color:#555753;stop-opacity:1;" /> - <stop - style="stop-color:#555753;stop-opacity:1;" - offset="0.56024098" - id="stop3111" /> - <stop - style="stop-color:#2e3436;stop-opacity:1" - offset="1" - id="stop3105" /> - </linearGradient> - <linearGradient - id="linearGradient3089"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop3092" /> - <stop - style="stop-color:#2e3436;stop-opacity:1" - offset="1" - id="stop3094" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3032"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop3034" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop3036" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3169"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop3171" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop3173" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3116"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop3118" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop3120" /> - </linearGradient> - <linearGradient - id="linearGradient3093"> - <stop - style="stop-color:#555753;stop-opacity:1;" - offset="0" - id="stop3095" /> - <stop - id="stop2022" - offset="0.72289157" - style="stop-color:#888a85;stop-opacity:1;" /> - <stop - style="stop-color:#71736e;stop-opacity:1;" - offset="1" - id="stop3097" /> - </linearGradient> - <linearGradient - id="linearGradient3041"> - <stop - style="stop-color:#555753;stop-opacity:1;" - offset="0" - id="stop3043" /> - <stop - id="stop3049" - offset="0.32630172" - style="stop-color:#898b86;stop-opacity:1;" /> - <stop - style="stop-color:#525450;stop-opacity:1;" - offset="0.62983823" - id="stop3051" /> - <stop - id="stop3053" - offset="0.85847878" - style="stop-color:#535551;stop-opacity:1;" /> - <stop - style="stop-color:#3e3f3d;stop-opacity:1;" - offset="1" - id="stop3045" /> - </linearGradient> - <linearGradient - id="linearGradient2982"> - <stop - style="stop-color:black;stop-opacity:0;" - offset="0" - id="stop2984" /> - <stop - id="stop2990" - offset="0.0547975" - style="stop-color:black;stop-opacity:1;" /> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0.90963858" - id="stop2992" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop2986" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient2927"> - <stop - style="stop-color:#ddd;stop-opacity:1;" - offset="0" - id="stop2929" /> - <stop - style="stop-color:#ddd;stop-opacity:0;" - offset="1" - id="stop2931" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient2919"> - <stop - style="stop-color:#646464;stop-opacity:1;" - offset="0" - id="stop2921" /> - <stop - style="stop-color:#646464;stop-opacity:0;" - offset="1" - id="stop2923" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient2911"> - <stop - style="stop-color:#464f52;stop-opacity:1;" - offset="0" - id="stop2913" /> - <stop - style="stop-color:#464f52;stop-opacity:0;" - offset="1" - id="stop2915" /> - </linearGradient> - <linearGradient - id="aigrd6" - gradientUnits="userSpaceOnUse" - x1="-1.2432" - y1="-3.2012" - x2="26.5278" - y2="28.3922"> - <stop - offset="0" - style="stop-color:#FFFFFF" - id="stop6468" /> - <stop - offset="1" - style="stop-color:#959595" - id="stop6470" /> - </linearGradient> - <radialGradient - id="aigrd3" - cx="23.1567" - cy="29.0337" - r="26.966" - fx="23.1567" - fy="29.0337" - gradientUnits="userSpaceOnUse"> - <stop - offset="0" - style="stop-color:#767676" - id="stop6443" /> - <stop - offset="1" - style="stop-color:#484848" - id="stop6445" /> - </radialGradient> - <radialGradient - id="aigrd2" - cx="13.5024" - cy="12.3457" - r="10.8808" - fx="13.5024" - fy="12.3457" - gradientUnits="userSpaceOnUse"> - <stop - offset="0" - style="stop-color:#454545" - id="stop6436" /> - <stop - offset="1" - style="stop-color:#333333" - id="stop6438" /> - </radialGradient> - <linearGradient - y2="248.6311" - x2="153.0005" - y1="15.4238" - x1="99.7773" - gradientUnits="userSpaceOnUse" - id="aigrd1"> - <stop - id="stop53300" - style="stop-color:#707070;stop-opacity:1;" - offset="0" /> - <stop - id="stop53302" - style="stop-color:#cdcdcd;stop-opacity:1;" - offset="1" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#aigrd3" - id="radialGradient4553" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.101263,0,0,1.101263,-57.56432,3.17435)" - cx="23.1567" - cy="29.0337" - fx="23.1567" - fy="29.0337" - r="26.966" /> - <radialGradient - inkscape:collect="always" - xlink:href="#aigrd2" - id="radialGradient4556" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.101263,0,0,1.101263,-57.56432,3.17435)" - cx="13.5024" - cy="12.3457" - fx="13.5024" - fy="12.3457" - r="10.8808" /> - <linearGradient - inkscape:collect="always" - xlink:href="#aigrd6" - id="linearGradient6380" - x1="0.88337302" - y1="-37.643921" - x2="30.994286" - y2="-0.67233789" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-57.87868,40.00204)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#aigrd1" - id="linearGradient2001" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(3.505583,42.36313)" - x1="4.6333733" - y1="-33.518921" - x2="34.056786" - y2="2.1401622" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2911" - id="linearGradient2917" - x1="29.75" - y1="38.420128" - x2="29.75" - y2="43.9375" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2919" - id="linearGradient2925" - x1="34.25" - y1="38.804165" - x2="34.25" - y2="44.380974" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2927" - id="linearGradient2933" - x1="35.625" - y1="38.874573" - x2="35.625" - y2="43.444958" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2982" - id="linearGradient2988" - x1="61.933079" - y1="31.25" - x2="106.09679" - y2="31.25" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2982" - id="linearGradient3000" - x1="62.3125" - y1="40" - x2="106.06924" - y2="40" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3041" - id="linearGradient3047" - x1="63.5" - y1="29.4375" - x2="104.79548" - y2="29.4375" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3093" - id="linearGradient3099" - x1="91.339241" - y1="19.333946" - x2="105.30366" - y2="19.333946" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3116" - id="linearGradient3122" - x1="75.875" - y1="28.625" - x2="77.375" - y2="39.40625" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3202" - id="linearGradient3072" - x1="73.337959" - y1="25.384384" - x2="76.955917" - y2="12.306049" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,-1)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3032" - id="linearGradient3087" - gradientUnits="userSpaceOnUse" - x1="77.000015" - y1="13.524997" - x2="80.39064" - y2="-5.0196266" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3089" - id="linearGradient3096" - x1="87.5" - y1="13.75" - x2="90.249092" - y2="14.446928" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3101" - id="linearGradient3107" - x1="76.937096" - y1="15.875" - x2="93.063683" - y2="15.875" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-60,0)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2982" - id="linearGradient3060" - x1="18.738331" - y1="16.695379" - x2="44.680313" - y2="23.499962" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2982" - id="linearGradient3062" - x1="18.738331" - y1="15.695379" - x2="44.680313" - y2="22.499962" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3169" - id="radialGradient3143" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.970504,0,0,0.407216,-56.50939,11.32708)" - cx="85.500011" - cy="16.999587" - fx="85.500011" - fy="16.999587" - r="22.249191" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3209" - id="linearGradient3215" - x1="82.489655" - y1="14.582699" - x2="80.921646" - y2="5.6930151" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3897" - id="linearGradient3903" - x1="76.781258" - y1="15.414051" - x2="81.75782" - y2="2.0453157" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4790" - id="linearGradient4796" - x1="-26.853115" - y1="10.70663" - x2="-29.875" - y2="24.003584" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient5683" - id="radialGradient5689" - cx="13.67201" - cy="7.8948545" - fx="13.67201" - fy="7.8948545" - r="17.503583" - gradientTransform="matrix(2.396145,0,0,1.213358,-19.88512,-7.579285)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5737" - id="linearGradient5743" - x1="81.92186" - y1="14.49374" - x2="81.690651" - y2="3.1698563" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3002" - id="radialGradient3907" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(2.03989,0,0,1.032958,-64.86939,-4.409191)" - cx="13.171977" - cy="21.697666" - fx="13.171977" - fy="21.697666" - r="17.503583" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3010" - id="linearGradient3909" - gradientUnits="userSpaceOnUse" - x1="80.992172" - y1="15.317177" - x2="84.55397" - y2="5.7076802" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6593" - id="linearGradient6599" - x1="26.641592" - y1="8.5011101" - x2="24.358414" - y2="10.498891" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient2992" - id="radialGradient2998" - cx="25.546875" - cy="10" - fx="25.546875" - fy="10" - r="8.453125" - gradientTransform="matrix(1,0,0,0.469501,0,5.304991)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2996" - id="linearGradient3003" - x1="25.5" - y1="15.453269" - x2="24.942444" - y2="1.2227453" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2998" - id="linearGradient3005" - x1="22.4375" - y1="32.25" - x2="28.25" - y2="31.75" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(14.75,-0.75)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2998" - id="linearGradient3017" - x1="44.331707" - y1="22.49238" - x2="46.908863" - y2="22.693205" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#d8d8d8" - borderopacity="1" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="1" - inkscape:cx="61.621338" - inkscape:cy="29.26585" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:grid-bbox="true" - inkscape:document-units="px" - showguides="false" - inkscape:guide-bbox="true" - inkscape:window-width="997" - inkscape:window-height="743" - inkscape:window-x="628" - inkscape:window-y="223" - inkscape:showpageshadow="false" - showborder="true" - inkscape:object-nodes="false" - inkscape:object-paths="false" - inkscape:grid-points="true"> - <sodipodi:guide - orientation="vertical" - position="13.5" - id="guide2099" /> - <sodipodi:guide - orientation="vertical" - position="21.4375" - id="guide2101" /> - <sodipodi:guide - orientation="vertical" - position="29.4375" - id="guide2103" /> - <sodipodi:guide - orientation="vertical" - position="37.375" - id="guide2105" /> - <sodipodi:guide - orientation="horizontal" - position="47" - id="guide2107" /> - <sodipodi:guide - orientation="vertical" - position="9.9878833" - id="guide2133" /> - <sodipodi:guide - orientation="vertical" - position="20.32932" - id="guide2135" /> - <sodipodi:guide - orientation="vertical" - position="30.670757" - id="guide2137" /> - <sodipodi:guide - orientation="vertical" - position="40.967999" - id="guide2139" /> - <sodipodi:guide - orientation="horizontal" - position="47.729708" - id="guide3008" /> - </sodipodi:namedview> - <metadata - id="metadata4422"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title>Applications Multimedia</dc:title> - <dc:date>August 2006</dc:date> - <dc:creator> - <cc:Agent> - <dc:title>Lapo Calamandrei</dc:title> - </cc:Agent> - </dc:creator> - <dc:source>http://www.gnome.org</dc:source> - <dc:subject> - <rdf:Bag> - <rdf:li>multimedia</rdf:li> - <rdf:li>sound</rdf:li> - <rdf:li>video</rdf:li> - </rdf:Bag> - </dc:subject> - <cc:license - rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" /> - <dc:contributor> - <cc:Agent> - <dc:title>Jakub Steiner, Andreas Nilsson</dc:title> - </cc:Agent> - </dc:contributor> - </cc:Work> - <cc:License - rdf:about="http://creativecommons.org/licenses/GPL/2.0/"> - <cc:permits - rdf:resource="http://web.resource.org/cc/Reproduction" /> - <cc:permits - rdf:resource="http://web.resource.org/cc/Distribution" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/Notice" /> - <cc:permits - rdf:resource="http://web.resource.org/cc/DerivativeWorks" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/ShareAlike" /> - <cc:requires - rdf:resource="http://web.resource.org/cc/SourceCode" /> - </cc:License> - </rdf:RDF> - </metadata> - <g - id="layer1" - inkscape:label="Layer 1" - inkscape:groupmode="layer" - style="display:inline"> - <path - style="opacity:0.8;color:black;fill:url(#radialGradient3143);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 37.265718,10.402843 C 26.947159,7.9031525 13.725313,9.3896756 7.7678855,13.719266 C 1.8104576,18.048857 5.3532386,23.59664 15.671801,26.09633 C 25.990362,28.596021 39.212206,27.109496 45.16963,22.779906 C 51.127064,18.450317 47.584288,12.902533 37.265718,10.402843 z " - id="path3141" - sodipodi:nodetypes="csssc" /> - <path - style="opacity:1;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 26.513532,3.069333 C 27.494068,3.144641 27.625715,3.264127 27.593697,3.379126 L 25.353295,7.201505 C 25.241199,7.392753 24.858508,7.513819 24.307494,7.605839 C 23.749135,7.647763 23.314524,7.628665 23.015452,7.491943 L 16.895253,4.686457 C 16.661667,4.546046 16.821602,4.319954 19.490909,3.569783 C 20.984007,3.258201 22.590966,3.065644 24.257151,3 C 25.237216,3.014582 26.030543,3.032239 26.513532,3.069333 z M 31.282791,3.653536 C 31.750192,3.705773 32.579862,3.871181 33.795668,4.168406 C 35.16683,4.606105 36.347892,5.140176 37.300167,5.751299 C 38.791373,7.011106 38.682595,7.243464 38.326732,7.311671 L 29.958044,8.342364 C 29.523357,8.395612 29.110469,8.293131 28.640151,8.106981 C 28.310696,7.916013 28.145983,7.735758 28.251072,7.556464 L 30.491474,3.734084 C 30.569914,3.648554 30.74289,3.593199 31.282791,3.653536 z M 14.624127,5.635824 C 14.672763,5.642736 14.726595,5.654075 14.766964,5.66811 L 20.895251,8.459797 C 21.198262,8.598318 21.220027,8.804396 21.123149,9.064521 C 20.922542,9.31194 20.678301,9.485432 20.26438,9.536135 L 11.903779,10.553029 C 11.524573,10.575096 11.159907,10.395586 11.066412,9.001043 C 11.140424,8.627402 11.274477,8.259682 11.494076,7.885023 C 11.713674,7.510364 11.999766,7.161268 12.344331,6.820768 C 13.737443,5.79183 14.306188,5.590641 14.624127,5.635824 z M 39.255235,8.652972 C 39.579997,8.686515 39.852498,8.990752 39.933588,10.20027 C 39.859576,10.573911 39.725523,10.941631 39.505924,11.31629 C 39.286326,11.69095 39.000234,12.040045 38.655669,12.380545 C 37.04945,13.566883 36.537303,13.638989 36.233036,13.533203 L 30.104749,10.741516 C 29.81764,10.610264 29.776139,10.418878 29.852587,10.17819 C 29.862751,10.164742 29.866324,10.149776 29.876851,10.136792 C 29.881935,10.123141 29.895209,10.109364 29.901116,10.095394 C 30.098159,9.869478 30.343421,9.71322 30.73562,9.665178 L 39.096221,8.648284 C 39.146533,8.645356 39.205556,8.647841 39.255235,8.652972 z M 21.647827,10.874004 C 21.852925,10.908941 22.06662,10.973673 22.28547,11.055641 C 22.662017,11.261281 22.861024,11.453602 22.748928,11.644849 L 20.508526,15.467229 C 20.362179,15.626804 19.824526,15.673458 17.204332,15.032907 C 15.833169,14.595211 14.652109,14.061136 13.699833,13.450014 C 12.20863,12.190207 12.317406,11.957847 12.673268,11.889642 L 21.041956,10.858949 C 21.246227,10.833927 21.442729,10.839068 21.647827,10.874004 z M 27.473567,11.587619 C 27.677762,11.605656 27.840994,11.643744 27.984548,11.709371 L 34.104747,14.514857 C 34.338335,14.655265 34.1784,14.881358 31.509091,15.63153 C 30.015994,15.943111 28.409033,16.135671 26.742849,16.201313 C 23.773106,16.157133 23.358511,15.993835 23.406303,15.822188 L 25.646705,11.999808 C 25.763112,11.801204 26.173739,11.68218 26.760965,11.589069 C 27.024213,11.571596 27.269373,11.569582 27.473567,11.587619 z " - id="path2995" - sodipodi:nodetypes="cccccccccccccccccccccccccsccccscccsssccccccccccccccccccccc" /> - <g - id="g3901" - transform="matrix(0.976118,0,0,0.976118,49.41488,6.4418)"> - <path - sodipodi:nodetypes="cccccccccccccccccccccccccsccccscccsssccccccccccccccccccccc" - id="path2984" - d="M -23.486468,3.069333 C -22.505932,3.144641 -22.374285,3.264127 -22.406303,3.379126 L -24.646705,7.201505 C -24.758801,7.392753 -25.141492,7.513819 -25.692506,7.605839 C -26.250865,7.647763 -26.685476,7.628665 -26.984548,7.491943 L -33.104747,4.686457 C -33.338333,4.546046 -33.178398,4.319954 -30.509091,3.569783 C -29.015993,3.258201 -27.409034,3.065644 -25.742849,3 C -24.762784,3.014582 -23.969457,3.032239 -23.486468,3.069333 z M -18.717209,3.653536 C -18.249808,3.705773 -17.420138,3.871181 -16.204332,4.168406 C -14.83317,4.606105 -13.652108,5.140176 -12.699833,5.751299 C -11.208627,7.011106 -11.317405,7.243464 -11.673268,7.311671 L -20.041956,8.342364 C -20.476643,8.395612 -20.889531,8.293131 -21.359849,8.106981 C -21.689304,7.916013 -21.854017,7.735758 -21.748928,7.556464 L -19.508526,3.734084 C -19.430086,3.648554 -19.25711,3.593199 -18.717209,3.653536 z M -35.375873,5.635824 C -35.327237,5.642736 -35.273405,5.654075 -35.233036,5.66811 L -29.104749,8.459797 C -28.801738,8.598318 -28.779973,8.804396 -28.876851,9.064521 C -29.077458,9.31194 -29.321699,9.485432 -29.73562,9.536135 L -38.096221,10.553029 C -38.475427,10.575096 -38.840093,10.395586 -38.933588,9.001043 C -38.859576,8.627402 -38.725523,8.259682 -38.505924,7.885023 C -38.286326,7.510364 -38.000234,7.161268 -37.655669,6.820768 C -36.262557,5.79183 -35.693812,5.590641 -35.375873,5.635824 z M -10.744765,8.652972 C -10.420003,8.686515 -10.147502,8.990752 -10.066412,10.20027 C -10.140424,10.573911 -10.274477,10.941631 -10.494076,11.31629 C -10.713674,11.69095 -10.999766,12.040045 -11.344331,12.380545 C -12.95055,13.566883 -13.462697,13.638989 -13.766964,13.533203 L -19.895251,10.741516 C -20.18236,10.610264 -20.223861,10.418878 -20.147413,10.17819 C -20.137249,10.164742 -20.133676,10.149776 -20.123149,10.136792 C -20.118065,10.123141 -20.104791,10.109364 -20.098884,10.095394 C -19.901841,9.869478 -19.656579,9.71322 -19.26438,9.665178 L -10.903779,8.648284 C -10.853467,8.645356 -10.794444,8.647841 -10.744765,8.652972 z M -28.352173,10.874004 C -28.147075,10.908941 -27.93338,10.973673 -27.71453,11.055641 C -27.337983,11.261281 -27.138976,11.453602 -27.251072,11.644849 L -29.491474,15.467229 C -29.637821,15.626804 -30.175474,15.673458 -32.795668,15.032907 C -34.166831,14.595211 -35.347891,14.061136 -36.300167,13.450014 C -37.79137,12.190207 -37.682594,11.957847 -37.326732,11.889642 L -28.958044,10.858949 C -28.753773,10.833927 -28.557271,10.839068 -28.352173,10.874004 z M -22.526433,11.587619 C -22.322238,11.605656 -22.159006,11.643744 -22.015452,11.709371 L -15.895253,14.514857 C -15.661665,14.655265 -15.8216,14.881358 -18.490909,15.63153 C -19.984006,15.943111 -21.590967,16.135671 -23.257151,16.201313 C -26.226894,16.157133 -26.641489,15.993835 -26.593697,15.822188 L -24.353295,11.999808 C -24.236888,11.801204 -23.826261,11.68218 -23.239035,11.589069 C -22.975787,11.571596 -22.730627,11.569582 -22.526433,11.587619 z " - style="opacity:1;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:2.04893351;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <path - sodipodi:nodetypes="csssccccccccccccccccccccccccccsccccscccsssccccccccccccccccccccc" - id="path2998" - d="M -19.970667,2.274237 C -29.301506,1.13127 -38.90351,3.665589 -41.403702,7.931199 C -43.903895,12.196811 -38.360174,16.58638 -29.029333,17.729347 C -19.698494,18.872313 -10.096492,16.337996 -7.596298,12.072384 C -5.096106,7.806773 -10.639827,3.417203 -19.970667,2.274237 z M -23.486468,3 C -22.505932,3.075308 -22.374285,3.194794 -22.406303,3.309793 L -24.646705,7.132172 C -24.758801,7.32342 -25.141492,7.444486 -25.692506,7.536506 C -26.250865,7.57843 -26.685476,7.559332 -26.984548,7.42261 L -33.104747,4.617124 C -33.338333,4.476713 -33.178398,4.250621 -30.509091,3.50045 C -29.015993,3.188868 -27.409034,2.996311 -25.742849,2.930667 C -24.762784,2.945249 -23.969457,2.962906 -23.486468,3 z M -18.717209,3.584203 C -18.249808,3.63644 -17.420138,3.801848 -16.204332,4.099073 C -14.83317,4.536772 -13.652108,5.070843 -12.699833,5.681966 C -11.208627,6.941773 -11.317405,7.174131 -11.673268,7.242338 L -20.041956,8.273031 C -20.476643,8.326279 -20.889531,8.223798 -21.359849,8.037648 C -21.689304,7.84668 -21.854017,7.666425 -21.748928,7.487131 L -19.508526,3.664751 C -19.430086,3.579221 -19.25711,3.523866 -18.717209,3.584203 z M -35.375873,5.566491 C -35.327237,5.573403 -35.273405,5.584742 -35.233036,5.598777 L -29.104749,8.390464 C -28.801738,8.528985 -28.779973,8.735063 -28.876851,8.995188 C -29.077458,9.242607 -29.321699,9.416099 -29.73562,9.466802 L -38.096221,10.483696 C -38.475427,10.505763 -38.840093,10.326253 -38.933588,8.93171 C -38.859576,8.558069 -38.725523,8.190349 -38.505924,7.81569 C -38.286326,7.441031 -38.000234,7.091935 -37.655669,6.751435 C -36.262557,5.722497 -35.693812,5.521308 -35.375873,5.566491 z M -10.744765,8.583639 C -10.420003,8.617182 -10.147502,8.921419 -10.066412,10.130937 C -10.140424,10.504578 -10.274477,10.872298 -10.494076,11.246957 C -10.713674,11.621617 -10.999766,11.970712 -11.344331,12.311212 C -12.95055,13.49755 -13.462697,13.569656 -13.766964,13.46387 L -19.895251,10.672183 C -20.18236,10.540931 -20.223861,10.349545 -20.147413,10.108857 C -20.137249,10.095409 -20.133676,10.080443 -20.123149,10.067459 C -20.118065,10.053808 -20.104791,10.040031 -20.098884,10.026061 C -19.901841,9.800145 -19.656579,9.643887 -19.26438,9.595845 L -10.903779,8.578951 C -10.853467,8.576023 -10.794444,8.578508 -10.744765,8.583639 z M -28.352173,10.804671 C -28.147075,10.839608 -27.93338,10.90434 -27.71453,10.986308 C -27.337983,11.191948 -27.138976,11.384269 -27.251072,11.575516 L -29.491474,15.397896 C -29.637821,15.557471 -30.175474,15.604125 -32.795668,14.963574 C -34.166831,14.525878 -35.347891,13.991803 -36.300167,13.380681 C -37.79137,12.120874 -37.682594,11.888514 -37.326732,11.820309 L -28.958044,10.789616 C -28.753773,10.764594 -28.557271,10.769735 -28.352173,10.804671 z M -22.526433,11.518286 C -22.322238,11.536323 -22.159006,11.574411 -22.015452,11.640038 L -15.895253,14.445524 C -15.661665,14.585932 -15.8216,14.812025 -18.490909,15.562197 C -19.984006,15.873778 -21.590967,16.066338 -23.257151,16.13198 C -26.226894,16.0878 -26.641489,15.924502 -26.593697,15.752855 L -24.353295,11.930475 C -24.236888,11.731871 -23.826261,11.612847 -23.239035,11.519736 C -22.975787,11.502263 -22.730627,11.500249 -22.526433,11.518286 z " - style="opacity:1;color:black;fill:url(#radialGradient3907);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <path - transform="matrix(1.210083,0,0,1.462367,-127.7352,-5.811834)" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - sodipodi:ry="5.8125" - sodipodi:rx="14.875" - sodipodi:cy="10.8125" - sodipodi:cx="85.3125" - id="path2986" - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#555753;stroke-width:0.77012676;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(1.142856,0,0,1.290324,-121.9999,-3.951621)" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - sodipodi:ry="5.8125" - sodipodi:rx="14.875" - sodipodi:cy="10.8125" - sodipodi:cx="85.3125" - id="path2988" - style="opacity:0.5;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3909);stroke-width:0.84363157;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <path - style="color:black;fill:url(#linearGradient3107);fill-opacity:1;fill-rule:nonzero;stroke:black;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 25.5,5.5 C 20.536155,5.5 16.5,7.52016 16.5,10 L 16.5,16 C 16.5,18.47984 20.536157,20.5 25.5,20.5 C 30.463845,20.5 34.5,18.47984 34.5,16 L 34.5,10 C 34.5,7.52016 30.463848,5.5 25.5,5.5 z " - id="path2003" - sodipodi:nodetypes="csssssc" /> - <path - style="opacity:1;fill:url(#linearGradient3099);fill-opacity:1;stroke:url(#linearGradient3096);stroke-width:1.01100004;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - d="M 22.812512,20.28125 L 41.60134,24.28125 C 46.85523,25.399764 46.49128,29.361359 46.49128,29.361359 L 46.49128,21.486359 C 46.49128,21.486359 46.132703,17.663667 41.60134,16.8125 L 24,13.506282" - id="rect2953" - sodipodi:nodetypes="czcczc" /> - <path - sodipodi:type="arc" - style="opacity:1;color:black;fill:url(#linearGradient6599);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path5706" - sodipodi:cx="25.5" - sodipodi:cy="9.5" - sodipodi:rx="8.5" - sodipodi:ry="3.5" - d="M 34 9.5 A 8.5 3.5 0 1 1 17,9.5 A 8.5 3.5 0 1 1 34 9.5 z" - transform="matrix(1,0,0,1.142857,0,-0.857143)" /> - <path - transform="translate(0,-1)" - style="opacity:0.4;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3060);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0.7;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 17.5625,16 C 17.5625,16.536843 17.92744,17.18169 18.875,17.8125 C 19.82256,18.44331 21.26461,18.980918 22.96875,19.25 C 22.989579,19.249384 23.010421,19.249384 23.03125,19.25 L 41.8125,23.25 C 43.42996,23.594345 44.694406,24.079834 45.5625,24.8125" - id="path3043" - sodipodi:nodetypes="cssccc" /> - <path - style="opacity:0.39849626;color:black;fill:url(#radialGradient2998);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:1.96992087;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 26.34375,6.03125 L 25.28125,7.84375 C 25.169154,8.034998 24.801014,8.15798 24.25,8.25 C 23.691642,8.291924 23.267822,8.292972 22.96875,8.15625 L 20.21875,6.90625 C 19.435475,7.2019093 18.739204,7.5309064 18.21875,7.9375 L 20.84375,9.125 C 21.146761,9.2635209 21.159378,9.458625 21.0625,9.71875 C 20.861894,9.9661689 20.632671,10.136797 20.21875,10.1875 L 17.09375,10.5625 C 17.234387,11.031002 17.545294,11.473239 18,11.875 L 20.96875,11.5 C 21.173021,11.474978 21.388652,11.496314 21.59375,11.53125 C 21.798848,11.566187 21.9999,11.636782 22.21875,11.71875 C 22.595298,11.92439 22.799596,12.121253 22.6875,12.3125 L 21.90625,13.625 C 22.800402,13.822195 23.781767,13.929355 24.8125,13.96875 L 25.59375,12.65625 C 25.710156,12.457646 26.100274,12.343111 26.6875,12.25 C 26.950747,12.232527 27.202056,12.231963 27.40625,12.25 C 27.610446,12.268037 27.793946,12.309373 27.9375,12.375 L 30.09375,13.34375 C 30.931804,13.088908 31.680434,12.779683 32.28125,12.40625 L 30.03125,11.40625 C 29.74414,11.274998 29.704802,11.084438 29.78125,10.84375 C 29.791414,10.830302 29.801973,10.794234 29.8125,10.78125 C 29.817585,10.767599 29.837843,10.76397 29.84375,10.75 C 30.040793,10.524084 30.295301,10.360542 30.6875,10.3125 L 34,9.90625 C 33.97667,9.4345321 33.779459,8.9803565 33.4375,8.5625 L 29.90625,9 C 29.471563,9.0532484 29.064068,8.93615 28.59375,8.75 C 28.264296,8.5590324 28.082411,8.398044 28.1875,8.21875 L 29.25,6.4375 C 28.355889,6.2289546 27.381597,6.0799454 26.34375,6.03125 z " - id="path3099" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0574123" - inkscape:original="M 25.5 5.5 C 20.536155 5.5 16.5 7.52016 16.5 10 L 16.5 16 C 16.5 18.009253 19.166589 19.705564 22.8125 20.28125 L 41.59375 24.28125 C 46.847639 25.399764 46.5 29.375 46.5 29.375 L 46.5 21.5 C 46.5 21.5 46.14223 17.566861 41.59375 16.8125 L 34.5 15.625 L 34.5 10 C 34.5 7.52016 30.463848 5.5 25.5 5.5 z " - style="opacity:0.1;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:white;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3030" - d="M 25.5,6.5625 C 23.161524,6.5625 21.062537,7.0622517 19.625,7.78125 C 18.187463,8.5002483 17.5625,9.3337568 17.5625,10 L 17.5625,16 C 17.5625,16.536843 17.92744,17.18169 18.875,17.8125 C 19.82256,18.44331 21.26461,18.980918 22.96875,19.25 C 22.989579,19.249384 23.010421,19.249384 23.03125,19.25 L 41.8125,23.25 C 43.42996,23.594345 44.569406,24.236084 45.4375,24.96875 L 45.4375,21.59375 C 45.4375,21.59375 45.374858,20.869771 44.84375,20 C 44.312642,19.130229 43.392274,18.17313 41.40625,17.84375 L 34.3125,16.65625 C 33.810416,16.5683 33.442516,16.134704 33.4375,15.625 L 33.4375,10 C 33.4375,9.3337563 32.812537,8.5002482 31.375,7.78125 C 29.937463,7.0622518 27.838477,6.5625 25.5,6.5625 z " /> - <g - id="g3035"> - <path - sodipodi:nodetypes="cczcczccc" - id="rect2949" - d="M 1.50002,29.499973 C 1.50002,29.499973 3.532822,27.499973 8.506322,27.499973 L 31.512623,27.499973 C 44.18377,27.499973 46.50001,25.003118 46.50001,21.499973 C 46.50001,24.174151 46.50001,29.499986 46.50001,29.499986 C 46.50001,35.359796 44.22293,37.947515 31.512623,38.499986 L 8.506322,39.499986 C 3.847089,39.941928 1.50002,43.499986 1.50002,43.499986 L 1.50002,29.499973 z " - style="opacity:1;fill:url(#linearGradient3047);fill-opacity:1;stroke:#2e3436;stroke-width:0.99999952;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" /> - <path - sodipodi:nodetypes="cczc" - id="path2978" - d="M 2.12502,31.874973 C 2.12502,31.874973 3.532822,29.499973 8.506322,29.499973 L 31.512623,29.499973 C 44.18377,29.499973 46.50001,27.003118 46.50001,23.499973" - style="opacity:0.6;fill:none;fill-opacity:1;stroke:url(#linearGradient2988);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0.5;stroke-opacity:1" /> - <path - sodipodi:nodetypes="czcc" - id="path2980" - d="M 46.56251,25.968736 C 46.56251,31.828546 45.93712,36.499986 31.512623,36.499986 L 8.506322,37.499986 C 3.847089,37.941928 1.50002,41.499986 1.50002,41.499986" - style="opacity:0.6;fill:none;fill-opacity:1;stroke:url(#linearGradient3000);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0.9;stroke-opacity:1" /> - <path - id="path3004" - d="M 45.0625,28.71875 C 44.37308,29.200323 43.74836,29.777176 42,30.21875 L 42,33.4375 C 45.16645,32.177079 45.06242,30.62266 45.0625,30.59375 L 45.0625,28.71875 z M 41,30.40625 C 40.20657,30.55277 39.21189,30.683386 38,30.78125 L 38,34.46875 C 39.187273,34.27185 40.17881,34.037517 41,33.78125 L 41,30.40625 z M 37,30.84375 C 35.848926,30.914726 34.565444,30.981472 33,31 L 33,34.96875 C 34.511976,34.894324 35.84389,34.78099 37,34.625 L 37,30.84375 z M 32,31 L 28,31.03125 L 28,35.1875 L 32,35.03125 L 32,31 z M 27,31.03125 L 23,31.0625 L 23,35.375 L 27,35.21875 L 27,31.03125 z M 22,31.09375 L 18,31.125 L 18,35.59375 L 22,35.4375 L 22,31.09375 z M 17,31.125 L 13,31.15625 L 13,35.78125 L 17,35.625 L 17,31.125 z M 12,31.15625 L 8.34375,31.1875 C 8.225387,31.184386 8.117212,31.186035 8,31.1875 L 8,36.03125 C 8.163488,36.008835 8.337513,35.974104 8.46875,35.96875 L 12,35.8125 L 12,31.15625 z M 7,31.25 C 5.871329,31.386685 4.830104,31.709176 4,32.125 L 4,37.375 C 4.94283,36.868709 6.054189,36.456108 7,36.21875 L 7,31.25 z M 3,32.75 C 2.399986,33.209949 2.017888,33.69653 2,34.125 L 2,39.25 C 2.138532,38.805351 2.509781,38.379775 3,38 L 3,32.75 z " - style="opacity:0.3;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:0.99999952;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" /> - <path - transform="translate(-60,0)" - d="M 105.5,25.8125 C 105.11869,26.131585 104.70169,26.466625 104.1875,26.71875 C 101.75082,27.913525 97.901254,28.5 91.5,28.5 L 68.5,28.5 C 66.147294,28.5 64.53517,28.961373 63.53125,29.40625 C 62.760319,29.74788 62.632868,29.916333 62.5,30.03125 L 62.5,41.03125 C 63.789632,39.926876 65.68087,38.758511 68.40625,38.5 C 68.427078,38.499349 68.447922,38.499349 68.46875,38.5 L 91.46875,37.5 C 97.758835,37.226593 101.36312,36.399909 103.21875,35.15625 C 105.07438,33.912591 105.5,32.299656 105.5,29.5 C 105.5,29.5 105.5,27.294332 105.5,25.8125 z " - id="path3065" - style="opacity:0.2;fill:none;fill-opacity:1;stroke:url(#linearGradient3122);stroke-width:0.99999952;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" - inkscape:original="M 106.5 21.5 C 106.5 25.003145 104.17114 27.5 91.5 27.5 L 68.5 27.5 C 63.5265 27.5 61.500001 29.5 61.5 29.5 L 61.5 43.5 C 61.5 43.5 63.840764 39.941943 68.5 39.5 L 91.5 38.5 C 104.21031 37.947529 106.5 35.359809 106.5 29.5 C 106.5 29.5 106.5 24.174178 106.5 21.5 z " - inkscape:radius="-1" - sodipodi:type="inkscape:offset" /> - <rect - ry="0.47940475" - rx="0.42824069" - y="29.53125" - x="2.0182304" - height="12.03125" - width="0.96354169" - id="rect3114" - style="opacity:1;fill:#888a85;fill-opacity:1;stroke:none;stroke-width:1.01100004;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.9;stroke-opacity:1" /> - </g> - <path - style="opacity:0.4;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3062);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 44.84375,21 C 44.312642,20.130229 43.392274,19.17313 41.40625,18.84375 L 34.3125,17.65625 C 28.132886,16.621777 17.500893,15.478056 17.500893,11.390758" - id="path3046" - sodipodi:nodetypes="cczc" /> - <path - style="opacity:0.15;color:black;fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;marker:none;stroke-miterlimit:4;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 18,13.875 L 18,15.90625 L 20,16.65625 L 20,14.78125 C 19.159795,14.440675 18.469808,14.133901 18,13.875 z M 21,15.15625 L 21,17.03125 L 23,17.78125 L 23,15.75 C 22.445474,15.648993 21.73377,15.420922 21,15.15625 z M 24,15.96875 L 24,18 L 26,18.40625 L 26,16.375 L 24,15.96875 z M 27,16.5625 L 27,18.59375 L 29,19 L 29,16.96875 L 27,16.5625 z M 30,17.1875 L 30,19.21875 L 32,19.625 L 32,17.59375 L 30,17.1875 z M 33,17.78125 L 33,19.8125 L 35,20.21875 L 35,18.21875 L 33,17.78125 z M 36,18.40625 L 36,20.4375 L 38,20.84375 L 38,18.8125 L 36,18.40625 z M 39,19.03125 L 39,21.03125 L 41,21.4375 L 41,19.4375 L 39,19.03125 z M 42,19.625 L 42,21.6875 C 42.817262,21.904793 43.456287,22.197387 44,22.59375 L 44,20.3125 C 43.403373,20.028973 42.747736,19.784187 42,19.625 z M 45,20.875 L 45,23.46875 L 45.4375,23.90625 L 46,22.15625 L 46,21.6875 C 45.689896,21.392151 45.36,21.118532 45,20.875 z " - id="path3071" /> - <path - sodipodi:type="arc" - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3087);stroke-width:0.82348335;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2966" - sodipodi:cx="85.3125" - sodipodi:cy="10.8125" - sodipodi:rx="14.875" - sodipodi:ry="5.8125" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - transform="matrix(1.142857,0,0,1.290323,-72.00001,-3.95161)" /> - <path - sodipodi:type="arc" - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.75173426;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3165" - sodipodi:cx="85.3125" - sodipodi:cy="10.8125" - sodipodi:rx="14.875" - sodipodi:ry="5.8125" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - transform="matrix(1.210083,0,0,1.462367,-77.73519,-5.811834)" /> - <path - style="opacity:1;color:black;fill:url(#radialGradient5689);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 30.029333,2.274237 C 20.698494,1.13127 11.09649,3.665589 8.596298,7.931199 C 6.0961053,12.196811 11.639826,16.58638 20.970667,17.729347 C 30.301506,18.872313 39.903508,16.337996 42.403702,12.072384 C 44.903894,7.806773 39.360173,3.417203 30.029333,2.274237 z M 26.513532,3 C 27.494068,3.075308 27.625715,3.194794 27.593697,3.309793 L 25.353295,7.132172 C 25.241199,7.32342 24.858508,7.444486 24.307494,7.536506 C 23.749135,7.57843 23.314524,7.559332 23.015452,7.42261 L 16.895253,4.617124 C 16.661667,4.476713 16.821602,4.250621 19.490909,3.50045 C 20.984007,3.188868 22.590966,2.996311 24.257151,2.930667 C 25.237216,2.945249 26.030543,2.962906 26.513532,3 z M 31.282791,3.584203 C 31.750192,3.63644 32.579862,3.801848 33.795668,4.099073 C 35.16683,4.536772 36.347892,5.070843 37.300167,5.681966 C 38.791373,6.941773 38.682595,7.174131 38.326732,7.242338 L 29.958044,8.273031 C 29.523357,8.326279 29.110469,8.223798 28.640151,8.037648 C 28.310696,7.84668 28.145983,7.666425 28.251072,7.487131 L 30.491474,3.664751 C 30.569914,3.579221 30.74289,3.523866 31.282791,3.584203 z M 14.624127,5.566491 C 14.672763,5.573403 14.726595,5.584742 14.766964,5.598777 L 20.895251,8.390464 C 21.198262,8.528985 21.220027,8.735063 21.123149,8.995188 C 20.922542,9.242607 20.678301,9.416099 20.26438,9.466802 L 11.903779,10.483696 C 11.524573,10.505763 11.159907,10.326253 11.066412,8.93171 C 11.140424,8.558069 11.274477,8.190349 11.494076,7.81569 C 11.713674,7.441031 11.999766,7.091935 12.344331,6.751435 C 13.737443,5.722497 14.306188,5.521308 14.624127,5.566491 z M 39.255235,8.583639 C 39.579997,8.617182 39.852498,8.921419 39.933588,10.130937 C 39.859576,10.504578 39.725523,10.872298 39.505924,11.246957 C 39.286326,11.621617 39.000234,11.970712 38.655669,12.311212 C 37.04945,13.49755 36.537303,13.569656 36.233036,13.46387 L 30.104749,10.672183 C 29.81764,10.540931 29.776139,10.349545 29.852587,10.108857 C 29.862751,10.095409 29.866324,10.080443 29.876851,10.067459 C 29.881935,10.053808 29.895209,10.040031 29.901116,10.026061 C 30.098159,9.800145 30.343421,9.643887 30.73562,9.595845 L 39.096221,8.578951 C 39.146533,8.576023 39.205556,8.578508 39.255235,8.583639 z M 21.647827,10.804671 C 21.852925,10.839608 22.06662,10.90434 22.28547,10.986308 C 22.662017,11.191948 22.861024,11.384269 22.748928,11.575516 L 20.508526,15.397896 C 20.362179,15.557471 19.824526,15.604125 17.204332,14.963574 C 15.833169,14.525878 14.652109,13.991803 13.699833,13.380681 C 12.20863,12.120874 12.317406,11.888514 12.673268,11.820309 L 21.041956,10.789616 C 21.246227,10.764594 21.442729,10.769735 21.647827,10.804671 z M 27.473567,11.518286 C 27.677762,11.536323 27.840994,11.574411 27.984548,11.640038 L 34.104747,14.445524 C 34.338335,14.585932 34.1784,14.812025 31.509091,15.562197 C 30.015994,15.873778 28.409033,16.066338 26.742849,16.13198 C 23.773106,16.0878 23.358511,15.924502 23.406303,15.752855 L 25.646705,11.930475 C 25.763112,11.731871 26.173739,11.612847 26.760965,11.519736 C 27.024213,11.502263 27.269373,11.500249 27.473567,11.518286 z " - id="path2992" - sodipodi:nodetypes="csssccccccccccccccccccccccccccsccccscccsssccccccccccccccccccccc" /> - <path - sodipodi:type="arc" - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5743);stroke-width:0.82348359;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3882" - sodipodi:cx="85.3125" - sodipodi:cy="10.8125" - sodipodi:rx="14.875" - sodipodi:ry="5.8125" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - transform="matrix(1.142856,0,0,1.290324,-71.99989,-3.951621)" /> - <path - style="opacity:0.7;color:black;fill:url(#linearGradient3003);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 24.21875,2.46875 C 22.529463,2.535304 20.928347,2.713616 19.40625,3.03125 C 19.395836,3.030905 19.385414,3.030905 19.375,3.03125 C 18.030353,3.409144 17.31816,3.671511 16.90625,3.875 C 16.700295,3.976745 16.533745,4.024698 16.40625,4.3125 C 16.342503,4.456401 16.359638,4.683059 16.4375,4.8125 C 16.515362,4.941941 16.592126,4.992705 16.65625,5.03125 C 16.676283,5.043196 16.697173,5.053642 16.71875,5.0625 L 22.8125,7.875 C 23.277073,8.087382 23.766882,8.043314 24.34375,8 C 24.354164,8.000345 24.364586,8.000345 24.375,8 C 24.66736,7.951176 24.93252,7.897112 25.15625,7.8125 C 25.37998,7.727888 25.602277,7.627033 25.75,7.375 L 28,3.5625 C 28.02692,3.524165 28.047984,3.482037 28.0625,3.4375 C 28.10103,3.299111 28.051103,3.040171 27.9375,2.90625 C 27.823897,2.772329 27.713327,2.729453 27.59375,2.6875 C 27.354596,2.603594 27.039179,2.57026 26.53125,2.53125 C 26.016219,2.491695 25.229781,2.483328 24.25,2.46875 C 24.239586,2.468405 24.229164,2.468405 24.21875,2.46875 z M 24.25,2.9375 C 25.230065,2.952082 26.017011,2.962906 26.5,3 C 27.480535,3.075308 27.625768,3.197501 27.59375,3.3125 L 25.34375,7.125 C 25.231655,7.316248 24.863514,7.43923 24.3125,7.53125 C 23.754142,7.573174 23.299072,7.574222 23,7.4375 L 16.90625,4.625 C 16.672665,4.484589 16.830693,4.250171 19.5,3.5 C 20.993097,3.188418 22.583815,3.003144 24.25,2.9375 z M 30.65625,3.09375 C 30.474425,3.112971 30.282388,3.206211 30.15625,3.34375 C 30.133508,3.362583 30.112583,3.383508 30.09375,3.40625 L 27.84375,7.25 C 27.710285,7.477708 27.766317,7.846965 27.90625,8.03125 C 28.046183,8.215535 28.187487,8.328808 28.375,8.4375 C 28.395033,8.449446 28.415923,8.459892 28.4375,8.46875 C 28.938239,8.66694 29.475613,8.818064 30.03125,8.75 L 38.375,7.71875 C 38.385414,7.719095 38.395836,7.719095 38.40625,7.71875 C 38.538892,7.693327 38.708411,7.654058 38.875,7.4375 C 39.041589,7.220942 39.030807,6.912667 38.9375,6.71875 C 38.750886,6.330917 38.38701,5.956264 37.625,5.3125 C 37.604967,5.300554 37.584077,5.290108 37.5625,5.28125 C 36.56488,4.641027 35.340283,4.104044 33.9375,3.65625 C 33.927577,3.645351 33.917149,3.634923 33.90625,3.625 C 32.678785,3.324925 31.850309,3.181613 31.34375,3.125 C 31.057919,3.093057 30.838075,3.074529 30.65625,3.09375 z M 30.71875,3.5625 C 30.839287,3.545512 31.0113,3.563581 31.28125,3.59375 C 31.748651,3.645987 32.565444,3.796525 33.78125,4.09375 C 35.15241,4.531449 36.360225,5.076377 37.3125,5.6875 C 38.803706,6.947307 38.668363,7.181793 38.3125,7.25 L 29.96875,8.28125 C 29.534063,8.334498 29.095318,8.2174 28.625,8.03125 C 28.295546,7.840282 28.144911,7.679294 28.25,7.5 L 30.5,3.65625 C 30.53922,3.613485 30.598213,3.579488 30.71875,3.5625 z M 14.6875,5.09375 C 14.096019,5.009693 13.481171,5.327185 12.0625,6.375 C 12.040923,6.383858 12.020033,6.394304 12,6.40625 C 11.632082,6.769827 11.337374,7.14685 11.09375,7.5625 C 10.849839,7.978638 10.67867,8.415039 10.59375,8.84375 C 10.588209,8.885233 10.588209,8.927267 10.59375,8.96875 C 10.643206,9.706413 10.75471,10.158753 11,10.5 C 11.24529,10.841247 11.673435,10.952867 11.9375,10.9375 C 11.947914,10.937845 11.958336,10.937845 11.96875,10.9375 L 20.3125,9.9375 C 20.829557,9.874163 21.240367,9.632717 21.5,9.3125 C 21.530023,9.26458 21.551193,9.211656 21.5625,9.15625 C 21.628907,8.977942 21.693002,8.781478 21.625,8.53125 C 21.556998,8.281022 21.331424,8.046152 21.09375,7.9375 L 14.96875,5.15625 C 14.958336,5.155905 14.947914,5.155905 14.9375,5.15625 C 14.811235,5.112352 14.740824,5.101328 14.6875,5.09375 z M 14.625,5.5625 C 14.673636,5.569412 14.740881,5.579715 14.78125,5.59375 L 20.90625,8.375 C 21.209262,8.513521 21.221878,8.739875 21.125,9 C 20.924392,9.247419 20.663921,9.418047 20.25,9.46875 L 11.90625,10.46875 C 11.527044,10.490817 11.155995,10.332043 11.0625,8.9375 C 11.136512,8.563859 11.280401,8.187159 11.5,7.8125 C 11.719598,7.437841 11.999185,7.0905 12.34375,6.75 C 13.736862,5.721062 14.307061,5.517317 14.625,5.5625 z M 39.03125,8.125 L 30.6875,9.125 C 30.227736,9.181318 29.879783,9.392513 29.625,9.65625 C 29.623983,9.656939 29.598616,9.684777 29.59375,9.6875 C 29.584051,9.698064 29.571837,9.708045 29.5625,9.71875 C 29.551601,9.728673 29.541173,9.739101 29.53125,9.75 L 29.5,9.75 C 29.550744,9.687412 29.541034,9.716862 29.46875,9.8125 C 29.468405,9.822914 29.468405,9.833336 29.46875,9.84375 C 29.444249,9.872393 29.423266,9.903867 29.40625,9.9375 C 29.34829,10.119981 29.292723,10.361835 29.375,10.59375 C 29.457277,10.825665 29.678664,11.020959 29.90625,11.125 L 36.03125,13.90625 C 36.041664,13.906595 36.052086,13.906595 36.0625,13.90625 C 36.327468,13.998373 36.691653,13.992584 37.125,13.8125 C 37.558347,13.632416 38.118404,13.292476 38.9375,12.6875 C 38.959077,12.678642 38.979967,12.668196 39,12.65625 C 39.367917,12.292673 39.662626,11.915652 39.90625,11.5 C 40.150161,11.083863 40.321331,10.647464 40.40625,10.21875 C 40.411791,10.177268 40.411791,10.135232 40.40625,10.09375 C 40.363432,9.455094 40.270005,9.018395 40.09375,8.6875 C 39.917495,8.356605 39.598432,8.154532 39.3125,8.125 C 39.212859,8.114709 39.119476,8.121684 39.0625,8.125 C 39.052086,8.124655 39.041664,8.124655 39.03125,8.125 z M 39.09375,8.59375 C 39.144061,8.590822 39.200321,8.588619 39.25,8.59375 C 39.574763,8.627293 39.85641,8.915482 39.9375,10.125 C 39.86349,10.498641 39.719599,10.875341 39.5,11.25 C 39.280402,11.62466 39.000815,11.972 38.65625,12.3125 C 37.05003,13.498838 36.523017,13.574536 36.21875,13.46875 L 30.09375,10.6875 C 29.80664,10.556248 29.767302,10.334438 29.84375,10.09375 C 29.853914,10.080302 29.864473,10.075484 29.875,10.0625 C 29.880085,10.048849 29.900343,10.04522 29.90625,10.03125 C 30.103294,9.805334 30.357801,9.641792 30.75,9.59375 L 39.09375,8.59375 z M 20.96875,10.3125 L 12.625,11.34375 C 12.614586,11.343405 12.604164,11.343405 12.59375,11.34375 C 12.461108,11.369172 12.291589,11.408441 12.125,11.625 C 11.958411,11.841559 11.969193,12.149834 12.0625,12.34375 C 12.249114,12.731583 12.612992,13.106236 13.375,13.75 C 13.395033,13.761946 13.415923,13.772392 13.4375,13.78125 C 14.435119,14.421471 15.659713,14.958459 17.0625,15.40625 C 17.072423,15.417149 17.082851,15.427577 17.09375,15.4375 C 18.413166,15.760054 19.231179,15.914896 19.75,15.96875 C 20.00941,15.995677 20.199598,15.995126 20.375,15.96875 C 20.550402,15.942374 20.721219,15.852356 20.84375,15.71875 C 20.866492,15.699917 20.887417,15.678992 20.90625,15.65625 L 23.15625,11.8125 C 23.230934,11.685081 23.282536,11.503864 23.25,11.34375 C 23.217464,11.183636 23.110915,11.054933 23.03125,10.96875 C 22.87192,10.796385 22.70354,10.704907 22.5,10.59375 C 22.479967,10.581804 22.459077,10.571358 22.4375,10.5625 C 22.213091,10.47845 22.008525,10.387788 21.75,10.34375 C 21.522274,10.30496 21.244957,10.278666 20.96875,10.3125 z M 21.03125,10.78125 C 21.235521,10.756228 21.451152,10.777564 21.65625,10.8125 C 21.861348,10.847437 22.0624,10.918032 22.28125,11 C 22.657798,11.20564 22.862096,11.371253 22.75,11.5625 L 20.5,15.40625 C 20.353653,15.565825 19.838944,15.609301 17.21875,14.96875 C 15.847587,14.531054 14.639776,13.986122 13.6875,13.375 C 12.196297,12.115193 12.331638,11.880705 12.6875,11.8125 L 21.03125,10.78125 z M 26.6875,11.0625 C 26.380288,11.111212 26.108719,11.167973 25.875,11.25 C 25.641281,11.332027 25.404512,11.423882 25.25,11.6875 L 23,15.5 C 22.97308,15.538335 22.952016,15.580463 22.9375,15.625 C 22.904935,15.741959 22.920591,15.932646 23,16.0625 C 23.079409,16.192354 23.19427,16.237608 23.28125,16.28125 C 23.45521,16.368533 23.617124,16.400918 23.875,16.4375 C 24.390753,16.510664 25.25703,16.571539 26.75,16.59375 C 26.760414,16.594095 26.770836,16.594095 26.78125,16.59375 C 28.470537,16.527198 30.071654,16.348883 31.59375,16.03125 C 31.604164,16.031595 31.614586,16.031595 31.625,16.03125 C 32.969648,15.653356 33.681841,15.39099 34.09375,15.1875 C 34.299705,15.085755 34.466255,15.037804 34.59375,14.75 C 34.657497,14.606098 34.640364,14.37944 34.5625,14.25 C 34.484636,14.12056 34.407874,14.069795 34.34375,14.03125 C 34.323717,14.019304 34.302827,14.008858 34.28125,14 L 28.1875,11.1875 C 27.922241,11.066235 27.694869,11.079713 27.5,11.0625 C 27.261132,11.0414 27.001137,11.043757 26.71875,11.0625 C 26.708336,11.062155 26.697914,11.062155 26.6875,11.0625 z M 26.75,11.53125 C 27.013248,11.513777 27.264556,11.513213 27.46875,11.53125 C 27.672946,11.549287 27.856446,11.559373 28,11.625 L 34.09375,14.4375 C 34.327337,14.577908 34.169309,14.812328 31.5,15.5625 C 30.006904,15.874081 28.416184,16.059358 26.75,16.125 C 23.780257,16.080819 23.358458,15.921647 23.40625,15.75 L 25.65625,11.9375 C 25.772656,11.738896 26.162774,11.624361 26.75,11.53125 z " - id="path6550" /> - <path - style="opacity:0.29714286;fill:url(#linearGradient3005);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 32.75,28.125 C 36.665221,27.989041 39.663593,27.509264 42.25,26.875 L 44.6875,34.8125 C 41.143944,37.348492 36.537218,37.994406 31.5,37.875 L 32.75,28.125 z " - id="path2111" - sodipodi:nodetypes="ccccc" /> - <path - style="fill:url(#linearGradient3017);fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1.0;opacity:0.6" - d="M 41.100582,23.560622 C 42.545852,23.922695 43.601874,24.362619 44.459339,24.842253 C 45.66266,23.973241 47.054739,21.640304 44.724504,18.831845 C 44.97435,19.937288 45.182433,21.455139 41.100582,23.560622 z " - id="path3009" - sodipodi:nodetypes="cccc" /> - </g> - <g - inkscape:groupmode="layer" - id="layer3" - inkscape:label="troiai2" - style="display:none"> - <path - style="opacity:1;color:black;fill:url(#linearGradient4796);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -19.970667,8.274237 C -29.301506,7.13127 -38.90351,9.665589 -41.403702,13.931199 C -43.903895,18.196811 -38.360174,22.58638 -29.029333,23.729347 C -19.698494,24.872313 -10.096492,22.337996 -7.596298,18.072384 C -5.096106,13.806773 -10.639827,9.417203 -19.970667,8.274237 z M -23.486468,9.470468 C -22.505932,9.545776 -22.374285,9.665262 -22.406303,9.780261 L -24.646705,13.60264 C -24.758801,13.793888 -25.141492,13.914954 -25.692506,14.006974 C -26.250865,14.048898 -26.685476,14.0298 -26.984548,13.893078 L -33.104747,11.087592 C -33.338333,10.947181 -33.178398,10.721089 -30.509091,9.970918 C -29.015993,9.659336 -27.409034,9.466779 -25.742849,9.401135 C -24.762784,9.415717 -23.969457,9.433374 -23.486468,9.470468 z M -18.717209,10.054671 C -18.249808,10.106908 -17.420138,10.272316 -16.204332,10.569541 C -14.83317,11.00724 -13.652108,11.541311 -12.699833,12.152434 C -11.208627,13.412241 -11.317405,13.644599 -11.673268,13.712806 L -20.041956,14.743499 C -20.476643,14.796747 -20.889531,14.694266 -21.359849,14.508116 C -21.689304,14.317148 -21.854017,14.136893 -21.748928,13.957599 L -19.508526,10.135219 C -19.430086,10.049689 -19.25711,9.994334 -18.717209,10.054671 z M -35.375873,12.036959 C -35.327237,12.043871 -35.273405,12.05521 -35.233036,12.069245 L -29.104749,14.860932 C -28.801738,14.999453 -28.779973,15.205531 -28.876851,15.465656 C -29.077458,15.713075 -29.321699,15.886567 -29.73562,15.93727 L -38.096221,16.954164 C -38.475427,16.976231 -38.840093,16.796721 -38.933588,15.402178 C -38.859576,15.028537 -38.725523,14.660817 -38.505924,14.286158 C -38.286326,13.911499 -38.000234,13.562403 -37.655669,13.221903 C -36.262557,12.192965 -35.693812,11.991776 -35.375873,12.036959 z M -10.744765,15.054107 C -10.420003,15.08765 -10.147502,15.391887 -10.066412,16.601405 C -10.140424,16.975046 -10.274477,17.342766 -10.494076,17.717425 C -10.713674,18.092085 -10.999766,18.44118 -11.344331,18.78168 C -12.95055,19.968018 -13.462697,20.040124 -13.766964,19.934338 L -19.895251,17.142651 C -20.18236,17.011399 -20.223861,16.820013 -20.147413,16.579325 C -20.137249,16.565877 -20.133676,16.550911 -20.123149,16.537927 C -20.118065,16.524276 -20.104791,16.510499 -20.098884,16.496529 C -19.901841,16.270613 -19.656579,16.114355 -19.26438,16.066313 L -10.903779,15.049419 C -10.853467,15.046491 -10.794444,15.048976 -10.744765,15.054107 z M -28.352173,17.275139 C -28.147075,17.310076 -27.93338,17.374808 -27.71453,17.456776 C -27.337983,17.662416 -27.138976,17.854737 -27.251072,18.045984 L -29.491474,21.868364 C -29.637821,22.027939 -30.175474,22.074593 -32.795668,21.434042 C -34.166831,20.996346 -35.347891,20.462271 -36.300167,19.851149 C -37.79137,18.591342 -37.682594,18.358982 -37.326732,18.290777 L -28.958044,17.260084 C -28.753773,17.235062 -28.557271,17.240203 -28.352173,17.275139 z M -22.526433,17.988754 C -22.322238,18.006791 -22.159006,18.044879 -22.015452,18.110506 L -15.895253,20.915992 C -15.661665,21.0564 -15.8216,21.282493 -18.490909,22.032665 C -19.984006,22.344246 -21.590967,22.536806 -23.257151,22.602448 C -26.226894,22.558268 -26.641489,22.39497 -26.593697,22.223323 L -24.353295,18.400943 C -24.236888,18.202339 -23.826261,18.083315 -23.239035,17.990204 C -22.975787,17.972731 -22.730627,17.970717 -22.526433,17.988754 z " - id="path3888" /> - <g - style="display:inline" - id="g2992"> - <g - style="stroke:#2e3436" - id="g3891"> - <path - style="opacity:1;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -23.486468,9.470468 C -22.505932,9.545776 -22.374285,9.665262 -22.406303,9.780261 L -24.646705,13.60264 C -24.758801,13.793888 -25.141492,13.914954 -25.692506,14.006974 C -26.250865,14.048898 -26.685476,14.0298 -26.984548,13.893078 L -33.104747,11.087592 C -33.338333,10.947181 -33.178398,10.721089 -30.509091,9.970918 C -29.015993,9.659336 -27.409034,9.466779 -25.742849,9.401135 C -24.762784,9.415717 -23.969457,9.433374 -23.486468,9.470468 z M -18.717209,10.054671 C -18.249808,10.106908 -17.420138,10.272316 -16.204332,10.569541 C -14.83317,11.00724 -13.652108,11.541311 -12.699833,12.152434 C -11.208627,13.412241 -11.317405,13.644599 -11.673268,13.712806 L -20.041956,14.743499 C -20.476643,14.796747 -20.889531,14.694266 -21.359849,14.508116 C -21.689304,14.317148 -21.854017,14.136893 -21.748928,13.957599 L -19.508526,10.135219 C -19.430086,10.049689 -19.25711,9.994334 -18.717209,10.054671 z M -35.375873,12.036959 C -35.327237,12.043871 -35.273405,12.05521 -35.233036,12.069245 L -29.104749,14.860932 C -28.801738,14.999453 -28.779973,15.205531 -28.876851,15.465656 C -29.077458,15.713075 -29.321699,15.886567 -29.73562,15.93727 L -38.096221,16.954164 C -38.475427,16.976231 -38.840093,16.796721 -38.933588,15.402178 C -38.859576,15.028537 -38.725523,14.660817 -38.505924,14.286158 C -38.286326,13.911499 -38.000234,13.562403 -37.655669,13.221903 C -36.262557,12.192965 -35.693812,11.991776 -35.375873,12.036959 z M -10.744765,15.054107 C -10.420003,15.08765 -10.147502,15.391887 -10.066412,16.601405 C -10.140424,16.975046 -10.274477,17.342766 -10.494076,17.717425 C -10.713674,18.092085 -10.999766,18.44118 -11.344331,18.78168 C -12.95055,19.968018 -13.462697,20.040124 -13.766964,19.934338 L -19.895251,17.142651 C -20.18236,17.011399 -20.223861,16.820013 -20.147413,16.579325 C -20.137249,16.565877 -20.133676,16.550911 -20.123149,16.537927 C -20.118065,16.524276 -20.104791,16.510499 -20.098884,16.496529 C -19.901841,16.270613 -19.656579,16.114355 -19.26438,16.066313 L -10.903779,15.049419 C -10.853467,15.046491 -10.794444,15.048976 -10.744765,15.054107 z M -28.352173,17.275139 C -28.147075,17.310076 -27.93338,17.374808 -27.71453,17.456776 C -27.337983,17.662416 -27.138976,17.854737 -27.251072,18.045984 L -29.491474,21.868364 C -29.637821,22.027939 -30.175474,22.074593 -32.795668,21.434042 C -34.166831,20.996346 -35.347891,20.462271 -36.300167,19.851149 C -37.79137,18.591342 -37.682594,18.358982 -37.326732,18.290777 L -28.958044,17.260084 C -28.753773,17.235062 -28.557271,17.240203 -28.352173,17.275139 z M -22.526433,17.988754 C -22.322238,18.006791 -22.159006,18.044879 -22.015452,18.110506 L -15.895253,20.915992 C -15.661665,21.0564 -15.8216,21.282493 -18.490909,22.032665 C -19.984006,22.344246 -21.590967,22.536806 -23.257151,22.602448 C -26.226894,22.558268 -26.641489,22.39497 -26.593697,22.223323 L -24.353295,18.400943 C -24.236888,18.202339 -23.826261,18.083315 -23.239035,17.990204 C -22.975787,17.972731 -22.730627,17.970717 -22.526433,17.988754 z " - id="path3884" - sodipodi:nodetypes="cccccccccccccccccccccccccsccccscccsssccccccccccccccccccccc" /> - <path - sodipodi:type="arc" - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:0.75173426;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3886" - sodipodi:cx="85.3125" - sodipodi:cy="10.8125" - sodipodi:rx="14.875" - sodipodi:ry="5.8125" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - transform="matrix(1.210083,0,0,1.462367,-127.7352,0.188166)" /> - </g> - <path - sodipodi:type="arc" - style="opacity:0.90075187;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3903);stroke-width:0.82348335;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3895" - sodipodi:cx="85.3125" - sodipodi:cy="10.8125" - sodipodi:rx="14.875" - sodipodi:ry="5.8125" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - transform="matrix(1.142857,0,0,1.290324,-122,2.04838)" /> - </g> - <g - style="display:inline" - id="g3189" - transform="translate(50,0)"> - <path - id="path3152" - d="M 25.96875,8.002653 C 19.762261,7.929462 13.664379,9.373241 10.34375,12.00219 C 5.513746,15.826114 8.384206,20.721752 16.75,22.929496 C 25.115794,25.137239 35.826245,23.825188 40.65625,20.001263 C 45.48625,16.177339 42.61579,11.281701 34.25,9.073958 C 31.635689,8.384038 28.789881,8.035922 25.96875,8.002653 z M 29.6875,10.388091 C 30.5522,10.360109 31.443298,10.446598 32.25,10.659488 C 34.401203,11.227194 35.148253,12.490153 33.90625,13.473448 C 32.664247,14.456743 29.901206,14.783926 27.75,14.216219 C 25.598795,13.648513 24.851747,12.399839 26.09375,11.416543 C 26.87,10.801984 28.246333,10.434729 29.6875,10.388091 z M 17.40625,11.887917 C 18.27095,11.859935 19.162048,11.946425 19.96875,12.159315 C 22.119954,12.727021 22.835753,13.989977 21.59375,14.973274 C 20.351748,15.956572 17.619956,16.298036 15.46875,15.730329 C 13.317545,15.162623 12.570497,13.899667 13.8125,12.91637 C 14.588751,12.301809 15.965083,11.934556 17.40625,11.887917 z M 32.96875,16.001727 C 33.83345,15.973744 34.724548,16.060234 35.53125,16.273124 C 37.682456,16.84083 38.429503,18.103786 37.1875,19.087083 C 35.9455,20.070381 33.182456,20.411845 31.03125,19.844139 C 28.880048,19.276432 28.164247,18.013476 29.40625,17.030179 C 30.182502,16.415618 31.527584,16.048365 32.96875,16.001727 z M 20.6875,17.515837 C 21.5522,17.487854 22.443298,17.574344 23.25,17.787234 C 25.401203,18.35494 26.148253,19.603614 24.90625,20.58691 C 23.664247,21.570205 20.901206,21.911671 18.75,21.343965 C 16.598795,20.776258 15.851747,19.5133 17.09375,18.530005 C 17.87,17.915446 19.246333,17.562474 20.6875,17.515837 z " - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#555753;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <path - id="path2959" - d="M 25.96875,8.002653 C 19.762261,7.929462 13.664379,9.373241 10.34375,12.00219 C 5.513746,15.826114 8.384206,20.721752 16.75,22.929496 C 25.115794,25.137239 35.826245,23.825188 40.65625,20.001263 C 45.48625,16.177339 42.61579,11.281701 34.25,9.073958 C 31.635689,8.384038 28.789881,8.035922 25.96875,8.002653 z M 29.6875,10.388091 C 30.5522,10.360109 31.443298,10.446598 32.25,10.659488 C 34.401203,11.227194 35.148253,12.490153 33.90625,13.473448 C 32.664247,14.456743 29.901206,14.783926 27.75,14.216219 C 25.598795,13.648513 24.851747,12.399839 26.09375,11.416543 C 26.87,10.801984 28.246333,10.434729 29.6875,10.388091 z M 17.40625,11.887917 C 18.27095,11.859935 19.162048,11.946425 19.96875,12.159315 C 22.119954,12.727021 22.835753,13.989977 21.59375,14.973274 C 20.351748,15.956572 17.619956,16.298036 15.46875,15.730329 C 13.317545,15.162623 12.570497,13.899667 13.8125,12.91637 C 14.588751,12.301809 15.965083,11.934556 17.40625,11.887917 z M 32.96875,16.001727 C 33.83345,15.973744 34.724548,16.060234 35.53125,16.273124 C 37.682456,16.84083 38.429503,18.103786 37.1875,19.087083 C 35.9455,20.070381 33.182456,20.411845 31.03125,19.844139 C 28.880048,19.276432 28.164247,18.013476 29.40625,17.030179 C 30.182502,16.415618 31.527584,16.048365 32.96875,16.001727 z M 20.6875,17.515837 C 21.5522,17.487854 22.443298,17.574344 23.25,17.787234 C 25.401203,18.35494 26.148253,19.603614 24.90625,20.58691 C 23.664247,21.570205 20.901206,21.911671 18.75,21.343965 C 16.598795,20.776258 15.851747,19.5133 17.09375,18.530005 C 17.87,17.915446 19.246333,17.562474 20.6875,17.515837 z " - style="opacity:1;color:black;fill:url(#linearGradient3072);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <path - transform="matrix(1.142857,0,0,1.290323,-72.00001,2.048386)" - d="M 100.1875 10.8125 A 14.875 5.8125 0 1 1 70.4375,10.8125 A 14.875 5.8125 0 1 1 100.1875 10.8125 z" - sodipodi:ry="5.8125" - sodipodi:rx="14.875" - sodipodi:cy="10.8125" - sodipodi:cx="85.3125" - id="path2968" - style="opacity:0.6;color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3215);stroke-width:0.82348335;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <path - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -67.21875,4.0285714 C -66.228989,3.9852983 -66.03418,4.0851337 -66,4.2 L -66,7.7 C -66,7.8856183 -66.261153,8.0402377 -66.6875,8.1857143 C -66.734238,8.2040411 -66.791816,8.2143269 -66.84375,8.2285714 C -67.33252,8.3246217 -67.742113,8.349952 -68.09375,8.2571429 L -74.75,6.5 C -75.039409,6.3975771 -74.96304,6.16496 -73.125,5.2571429 C -73.114525,5.251968 -73.104347,5.2480777 -73.09375,5.2428571 C -71.886156,4.7872091 -70.474594,4.4285714 -68.96875,4.1857143 C -68.265233,4.1158903 -67.618098,4.0460297 -67.21875,4.0285714 z M -62.28125,4.0285714 C -61.862086,4.0243474 -61.083492,4.08128 -60.03125,4.1857143 C -58.525406,4.4285714 -57.113844,4.7872091 -55.90625,5.2428571 C -55.894767,5.2471909 -55.886451,5.2527909 -55.875,5.2571429 C -54.03696,6.16496 -53.960591,6.3975771 -54.25,6.5 L -60.90625,8.2571429 C -61.29598,8.3600091 -61.752818,8.3098697 -62.3125,8.1857143 C -62.738847,8.0402377 -63,7.8856137 -63,7.7 L -63,4.2 C -62.972656,4.1081051 -62.836914,4.0341714 -62.28125,4.0285714 z M -76.40625,7.6857143 C -76.356212,7.6866377 -76.29694,7.6912183 -76.25,7.7 L -69.59375,9.4428571 C -69.242114,9.5356617 -69.093676,9.715616 -69.03125,9.9571429 C -69.031344,9.9857006 -69.03125,10.014299 -69.03125,10.042857 C -69.093675,10.284384 -69.242113,10.464334 -69.59375,10.557143 L -76.25,12.3 C -76.583792,12.362437 -77.002186,12.230194 -77.78125,11.1 C -77.922377,10.742473 -78,10.376023 -78,10 C -78,9.6239771 -77.922377,9.2575269 -77.78125,8.9 C -77.111743,7.9287406 -76.71203,7.6800823 -76.40625,7.6857143 z M -52.59375,7.6857143 C -52.28797,7.6800823 -51.888257,7.9287406 -51.21875,8.9 C -51.077623,9.2575269 -51,9.6239771 -51,10 C -51,10.376023 -51.077623,10.742473 -51.21875,11.1 C -51.997814,12.230194 -52.416209,12.362437 -52.75,12.3 L -59.40625,10.557143 C -59.757886,10.464338 -59.906324,10.284384 -59.96875,10.042857 C -59.969649,10.014277 -59.96875,9.9857234 -59.96875,9.9571429 C -59.906325,9.715616 -59.757887,9.5356663 -59.40625,9.4428571 L -52.75,7.7 C -52.70306,7.6912183 -52.643788,7.6866377 -52.59375,7.6857143 z M -67.5,11.685714 C -67.282111,11.695195 -67.039049,11.732434 -66.78125,11.785714 C -66.301109,11.939794 -66,12.102011 -66,12.3 L -66,15.8 C -66.047971,15.961216 -66.521607,16.057161 -68.96875,15.814286 C -70.474594,15.571429 -71.886156,15.212791 -73.09375,14.757143 C -73.105233,14.752809 -73.113549,14.747209 -73.125,14.742857 C -74.96304,13.83504 -75.039409,13.602423 -74.75,13.5 L -68.09375,11.742857 C -67.910606,11.694519 -67.717889,11.676233 -67.5,11.685714 z M -61.46875,11.685714 C -61.261301,11.678976 -61.082069,11.696453 -60.90625,11.742857 L -54.25,13.5 C -53.960592,13.602423 -54.036961,13.83504 -55.875,14.742857 C -55.886451,14.747209 -55.894767,14.752809 -55.90625,14.757143 C -57.113845,15.212791 -58.525406,15.571429 -60.03125,15.814286 C -62.478393,16.057161 -62.952029,15.961216 -63,15.8 L -63,12.3 C -63,12.114382 -62.738847,11.959762 -62.3125,11.814286 C -62.266586,11.798619 -62.206271,11.786926 -62.15625,11.771429 C -61.911865,11.723406 -61.676199,11.692453 -61.46875,11.685714 z " - id="path5719" - sodipodi:nodetypes="cccssccssccccsscccccccccsscccsccccscccssccccccccssccccccsscccssc" /> - <path - style="color:black;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -64.5,2 C -74.159996,2 -82,5.584 -82,10 C -82,14.416 -74.159997,18.000005 -64.5,18 C -54.840004,18 -47.000001,14.416 -47,10 C -47,5.584 -54.840004,2 -64.5,2 z M -67.21875,4.0285714 C -66.228989,3.9852983 -66.03418,4.0851337 -66,4.2 L -66,7.7 C -66,7.8856183 -66.261153,8.0402377 -66.6875,8.1857143 C -66.734238,8.2040411 -66.791816,8.2143269 -66.84375,8.2285714 C -67.33252,8.3246217 -67.742113,8.349952 -68.09375,8.2571429 L -74.75,6.5 C -75.039409,6.3975771 -74.96304,6.16496 -73.125,5.2571429 C -73.114525,5.251968 -73.104347,5.2480777 -73.09375,5.2428571 C -71.886156,4.7872091 -70.474594,4.4285714 -68.96875,4.1857143 C -68.265233,4.1158903 -67.618098,4.0460297 -67.21875,4.0285714 z M -62.28125,4.0285714 C -61.862086,4.0243474 -61.083492,4.08128 -60.03125,4.1857143 C -58.525406,4.4285714 -57.113844,4.7872091 -55.90625,5.2428571 C -55.894767,5.2471909 -55.886451,5.2527909 -55.875,5.2571429 C -54.03696,6.16496 -53.960591,6.3975771 -54.25,6.5 L -60.90625,8.2571429 C -61.29598,8.3600091 -61.752818,8.3098697 -62.3125,8.1857143 C -62.738847,8.0402377 -63,7.8856137 -63,7.7 L -63,4.2 C -62.972656,4.1081051 -62.836914,4.0341714 -62.28125,4.0285714 z M -76.40625,7.6857143 C -76.356212,7.6866377 -76.29694,7.6912183 -76.25,7.7 L -69.59375,9.4428571 C -69.242114,9.5356617 -69.093676,9.715616 -69.03125,9.9571429 C -69.031344,9.9857006 -69.03125,10.014299 -69.03125,10.042857 C -69.093675,10.284384 -69.242113,10.464334 -69.59375,10.557143 L -76.25,12.3 C -76.583792,12.362437 -77.002186,12.230194 -77.78125,11.1 C -77.922377,10.742473 -78,10.376023 -78,10 C -78,9.6239771 -77.922377,9.2575269 -77.78125,8.9 C -77.111743,7.9287406 -76.71203,7.6800823 -76.40625,7.6857143 z M -52.59375,7.6857143 C -52.28797,7.6800823 -51.888257,7.9287406 -51.21875,8.9 C -51.077623,9.2575269 -51,9.6239771 -51,10 C -51,10.376023 -51.077623,10.742473 -51.21875,11.1 C -51.997814,12.230194 -52.416209,12.362437 -52.75,12.3 L -59.40625,10.557143 C -59.757886,10.464338 -59.906324,10.284384 -59.96875,10.042857 C -59.969649,10.014277 -59.96875,9.9857234 -59.96875,9.9571429 C -59.906325,9.715616 -59.757887,9.5356663 -59.40625,9.4428571 L -52.75,7.7 C -52.70306,7.6912183 -52.643788,7.6866377 -52.59375,7.6857143 z M -67.5,11.685714 C -67.282111,11.695195 -67.039049,11.732434 -66.78125,11.785714 C -66.301109,11.939794 -66,12.102011 -66,12.3 L -66,15.8 C -66.047971,15.961216 -66.521607,16.057161 -68.96875,15.814286 C -70.474594,15.571429 -71.886156,15.212791 -73.09375,14.757143 C -73.105233,14.752809 -73.113549,14.747209 -73.125,14.742857 C -74.96304,13.83504 -75.039409,13.602423 -74.75,13.5 L -68.09375,11.742857 C -67.910606,11.694519 -67.717889,11.676233 -67.5,11.685714 z M -61.46875,11.685714 C -61.261301,11.678976 -61.082069,11.696453 -60.90625,11.742857 L -54.25,13.5 C -53.960592,13.602423 -54.036961,13.83504 -55.875,14.742857 C -55.886451,14.747209 -55.894767,14.752809 -55.90625,14.757143 C -57.113845,15.212791 -58.525406,15.571429 -60.03125,15.814286 C -62.478393,16.057161 -62.952029,15.961216 -63,15.8 L -63,12.3 C -63,12.114382 -62.738847,11.959762 -62.3125,11.814286 C -62.266586,11.798619 -62.206271,11.786926 -62.15625,11.771429 C -61.911865,11.723406 -61.676199,11.692453 -61.46875,11.685714 z " - id="path5712" - sodipodi:nodetypes="csssccccssccssccccsscccccccccsscccsccccscccssccccccccssccccccsscccssc" /> - <path - style="color:black;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -23.745287,-14.087957 C -22.764752,-14.012649 -22.633104,-13.893164 -22.665122,-13.778165 L -24.646705,-10.39736 C -24.751796,-10.218063 -25.091591,-10.099609 -25.585775,-10.009532 C -25.641296,-9.997359 -25.702736,-9.9942358 -25.760965,-9.9866215 C -26.287461,-9.9516732 -26.697439,-9.9756686 -26.984548,-10.106922 L -32.419156,-12.591789 C -32.640716,-12.724967 -32.435249,-12.940626 -30.145863,-13.600051 C -30.132815,-13.60381 -30.120781,-13.606364 -30.107589,-13.610152 C -28.68317,-13.907401 -27.116658,-14.08681 -25.524626,-14.143226 C -24.805549,-14.127432 -24.140912,-14.118345 -23.745287,-14.087957 z M -18.976028,-13.503755 C -18.568755,-13.45824 -17.848925,-13.311123 -16.891664,-13.085744 C -15.574628,-12.672987 -14.414213,-12.159548 -13.505739,-11.576535 C -13.497101,-11.57099 -13.492239,-11.564597 -13.483642,-11.559038 C -12.222208,-10.464662 -12.280141,-10.230931 -12.617677,-10.166238 L -20.041956,-9.2565005 C -20.476646,-9.2032501 -20.889531,-9.3057348 -21.359849,-9.4918833 C -21.689305,-9.6828511 -21.854016,-9.8631088 -21.748928,-10.042401 L -19.767345,-13.423206 C -19.688905,-13.508737 -19.515929,-13.564091 -18.976028,-13.503755 z M -34.690283,-11.642422 C -34.642473,-11.635609 -34.587814,-11.624171 -34.547445,-11.610135 L -29.104749,-9.1390678 C -28.817638,-9.0078183 -28.776142,-8.8164294 -28.852587,-8.5757414 C -28.868846,-8.5481673 -28.884947,-8.5205319 -28.901116,-8.4929462 C -29.098158,-8.2670306 -29.34342,-8.1107727 -29.73562,-8.0627297 L -37.151812,-7.166791 C -37.50958,-7.145975 -37.838846,-7.323217 -37.951486,-8.5071006 C -37.885384,-8.8691505 -37.75289,-9.2323053 -37.539999,-9.5955223 C -37.327107,-9.9587393 -37.044657,-10.303526 -36.705919,-10.632179 C -35.50933,-11.491146 -34.982455,-11.684042 -34.690283,-11.642422 z M -11.689174,-8.8249375 C -11.390625,-8.7941981 -11.145314,-8.5067145 -11.048514,-7.489316 C -11.114616,-7.127266 -11.24711,-6.764111 -11.460001,-6.400894 C -11.672893,-6.037677 -11.955343,-5.692891 -12.294081,-5.364239 C -13.686477,-4.364712 -14.165487,-4.286478 -14.452555,-4.386282 L -19.895251,-6.857349 C -20.182362,-6.988598 -20.223858,-7.179988 -20.147413,-7.420675 C -20.1321,-7.448389 -20.115066,-7.475864 -20.098884,-7.503471 C -19.901842,-7.729386 -19.65658,-7.885644 -19.26438,-7.933687 L -11.848188,-8.829626 C -11.797876,-8.8325545 -11.73803,-8.8299661 -11.689174,-8.8249375 z M -28.352173,-6.724861 C -28.147076,-6.689922 -27.93338,-6.625193 -27.71453,-6.543224 C -27.337985,-6.337581 -27.138978,-6.145262 -27.251072,-5.954016 L -29.232655,-2.573211 C -29.370267,-2.42316 -29.882085,-2.386523 -32.108336,-2.910672 C -33.425372,-3.32343 -34.585787,-3.83687 -35.494261,-4.419882 C -35.502899,-4.425427 -35.507761,-4.43182 -35.516358,-4.437379 C -36.777792,-5.531755 -36.719859,-5.765486 -36.382323,-5.830178 L -28.958044,-6.739916 C -28.753773,-6.764939 -28.557269,-6.7598 -28.352173,-6.724861 z M -22.526433,-6.011246 C -22.322237,-5.99321 -22.159007,-5.955122 -22.015452,-5.889495 L -16.580844,-3.404627 C -16.359285,-3.271451 -16.564752,-3.055791 -18.854137,-2.396366 C -18.867662,-2.393517 -18.878865,-2.389092 -18.892411,-2.386264 C -20.316831,-2.089016 -21.883342,-1.909607 -23.475374,-1.853191 C -25.97664,-1.908132 -26.379817,-2.05685 -26.334878,-2.218252 L -24.353295,-5.599057 C -24.248204,-5.778354 -23.908409,-5.896808 -23.414225,-5.986885 C -23.361006,-5.996586 -23.296126,-6.000744 -23.239035,-6.009795 C -22.975788,-6.027268 -22.730628,-6.029283 -22.526433,-6.011246 z " - id="path5717" - sodipodi:nodetypes="cccssccssccccsscccccccccsscccsccccscccssccccccccssccccccsscccssc" /> - <path - style="color:black;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -19.970667,-15.725763 C -29.301506,-16.86873 -38.90351,-14.334411 -41.403702,-10.0688 C -43.903894,-5.80319 -38.360176,-1.413616 -29.029333,-0.270654 C -19.698494,0.872312 -10.096491,-1.662006 -7.596298,-5.927617 C -5.096106,-10.193227 -10.639827,-14.582797 -19.970667,-15.725763 z M -23.745287,-14.087957 C -22.764752,-14.012649 -22.633104,-13.893164 -22.665122,-13.778165 L -24.646705,-10.39736 C -24.751796,-10.218063 -25.091591,-10.099609 -25.585775,-10.009532 C -25.641296,-9.997359 -25.702736,-9.9942358 -25.760965,-9.9866215 C -26.287461,-9.9516732 -26.697439,-9.9756686 -26.984548,-10.106922 L -32.419156,-12.591789 C -32.640716,-12.724967 -32.435249,-12.940626 -30.145863,-13.600051 C -30.132815,-13.60381 -30.120781,-13.606364 -30.107589,-13.610152 C -28.68317,-13.907401 -27.116658,-14.08681 -25.524626,-14.143226 C -24.805549,-14.127432 -24.140912,-14.118345 -23.745287,-14.087957 z M -18.976028,-13.503755 C -18.568755,-13.45824 -17.848925,-13.311123 -16.891664,-13.085744 C -15.574628,-12.672987 -14.414213,-12.159548 -13.505739,-11.576535 C -13.497101,-11.57099 -13.492239,-11.564597 -13.483642,-11.559038 C -12.222208,-10.464662 -12.280141,-10.230931 -12.617677,-10.166238 L -20.041956,-9.2565005 C -20.476646,-9.2032501 -20.889531,-9.3057348 -21.359849,-9.4918833 C -21.689305,-9.6828511 -21.854016,-9.8631088 -21.748928,-10.042401 L -19.767345,-13.423206 C -19.688905,-13.508737 -19.515929,-13.564091 -18.976028,-13.503755 z M -34.690283,-11.642422 C -34.642473,-11.635609 -34.587814,-11.624171 -34.547445,-11.610135 L -29.104749,-9.1390678 C -28.817638,-9.0078183 -28.776142,-8.8164294 -28.852587,-8.5757414 C -28.868846,-8.5481673 -28.884947,-8.5205319 -28.901116,-8.4929462 C -29.098158,-8.2670306 -29.34342,-8.1107727 -29.73562,-8.0627297 L -37.151812,-7.166791 C -37.50958,-7.145975 -37.838846,-7.323217 -37.951486,-8.5071006 C -37.885384,-8.8691505 -37.75289,-9.2323053 -37.539999,-9.5955223 C -37.327107,-9.9587393 -37.044657,-10.303526 -36.705919,-10.632179 C -35.50933,-11.491146 -34.982455,-11.684042 -34.690283,-11.642422 z M -11.689174,-8.8249375 C -11.390625,-8.7941981 -11.145314,-8.5067145 -11.048514,-7.489316 C -11.114616,-7.127266 -11.24711,-6.764111 -11.460001,-6.400894 C -11.672893,-6.037677 -11.955343,-5.692891 -12.294081,-5.364239 C -13.686477,-4.364712 -14.165487,-4.286478 -14.452555,-4.386282 L -19.895251,-6.857349 C -20.182362,-6.988598 -20.223858,-7.179988 -20.147413,-7.420675 C -20.1321,-7.448389 -20.115066,-7.475864 -20.098884,-7.503471 C -19.901842,-7.729386 -19.65658,-7.885644 -19.26438,-7.933687 L -11.848188,-8.829626 C -11.797876,-8.8325545 -11.73803,-8.8299661 -11.689174,-8.8249375 z M -28.352173,-6.724861 C -28.147076,-6.689922 -27.93338,-6.625193 -27.71453,-6.543224 C -27.337985,-6.337581 -27.138978,-6.145262 -27.251072,-5.954016 L -29.232655,-2.573211 C -29.370267,-2.42316 -29.882085,-2.386523 -32.108336,-2.910672 C -33.425372,-3.32343 -34.585787,-3.83687 -35.494261,-4.419882 C -35.502899,-4.425427 -35.507761,-4.43182 -35.516358,-4.437379 C -36.777792,-5.531755 -36.719859,-5.765486 -36.382323,-5.830178 L -28.958044,-6.739916 C -28.753773,-6.764939 -28.557269,-6.7598 -28.352173,-6.724861 z M -22.526433,-6.011246 C -22.322237,-5.99321 -22.159007,-5.955122 -22.015452,-5.889495 L -16.580844,-3.404627 C -16.359285,-3.271451 -16.564752,-3.055791 -18.854137,-2.396366 C -18.867662,-2.393517 -18.878865,-2.389092 -18.892411,-2.386264 C -20.316831,-2.089016 -21.883342,-1.909607 -23.475374,-1.853191 C -25.97664,-1.908132 -26.379817,-2.05685 -26.334878,-2.218252 L -24.353295,-5.599057 C -24.248204,-5.778354 -23.908409,-5.896808 -23.414225,-5.986885 C -23.361006,-5.996586 -23.296126,-6.000744 -23.239035,-6.009795 C -22.975788,-6.027268 -22.730628,-6.029283 -22.526433,-6.011246 z " - id="path5715" - sodipodi:nodetypes="csssccccssccssccccsscccccccccsscccsccccscccssccccccccssccccccsscccssc" /> - </g> - <g - inkscape:groupmode="layer" - id="layer2" - inkscape:label="troiai" - style="display:none"> - <rect - style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" - id="rect2947" - width="48" - height="48" - x="-60" - y="-1.3322676e-15" /> - <g - id="g1996" - transform="matrix(1,0,0,1.011094,-59.50013,-0.849162)"> - <path - id="path6409" - d="M 23.343751,6.7920654 C 19.276738,6.9662854 14.839018,8.953048 11.250001,12.542065 C 4.8695268,18.922539 3.6038088,28.020873 8.4375008,32.854566 C 13.271193,37.688258 22.369527,36.42254 28.750001,30.042065 C 35.130475,23.661591 36.396191,14.563256 31.562501,9.7295651 C 29.447761,7.614825 26.506983,6.6565614 23.343751,6.7920654 z M 26.281251,9.385815 C 27.385834,9.370233 28.341176,9.7585781 28.906251,10.542065 C 30.036398,12.109038 29.144776,14.67757 26.906251,16.292065 C 24.667727,17.906561 21.94265,17.952788 20.812501,16.385815 C 19.682351,14.818841 20.573976,12.25031 22.812501,10.635815 C 23.931764,9.8285671 25.176668,9.401397 26.281251,9.385815 z M 15.406251,11.823315 C 16.065529,11.818813 16.669136,12.0208 17.093751,12.448315 C 18.226056,13.588354 17.760962,15.894505 16.062501,17.604565 C 14.364039,19.314625 12.069806,19.775854 10.937501,18.635815 C 9.8051958,17.495776 10.23904,15.189625 11.937501,13.479565 C 12.999039,12.410777 14.307454,11.830818 15.406251,11.823315 z M 24.312501,20.292065 C 25.592364,20.164078 26.840524,20.507588 27.718751,21.385815 C 29.475205,23.142268 29.146778,26.332788 27.000001,28.479565 C 24.853222,30.626343 21.693954,30.923518 19.937501,29.167065 C 18.181049,27.410612 18.478224,24.251342 20.625001,22.104565 C 21.69839,21.031176 23.032638,20.420052 24.312501,20.292065 z M 13.531251,21.792065 C 14.025806,21.816698 14.502003,21.963359 14.906251,22.229565 C 16.523244,23.294391 16.540338,25.982012 14.968751,28.229565 C 13.397165,30.477119 10.835744,31.450641 9.2187508,30.385815 C 7.6017568,29.32099 7.5534138,26.633368 9.1250008,24.385815 C 10.303691,22.70015 12.047586,21.718166 13.531251,21.792065 z " - style="opacity:1;fill:url(#linearGradient2001);fill-opacity:1;stroke:none;stroke-width:0.9863953;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> - <path - transform="matrix(0.6512,0.648774,-0.68514,0.682587,21.74573,-2.442557)" - d="M 29.7995 18.629814 A 12.399623 15.884648 0 1 1 5.0002546,18.629814 A 12.399623 15.884648 0 1 1 29.7995 18.629814 z" - sodipodi:ry="15.884648" - sodipodi:rx="12.399623" - sodipodi:cy="18.629814" - sodipodi:cx="17.399878" - id="path7695" - style="opacity:0.45108696;fill:none;fill-opacity:1;stroke:white;stroke-width:1.05475736;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - sodipodi:type="arc" /> - <path - transform="matrix(0.702727,0.69577,-0.724088,0.716919,21.70497,-3.797766)" - d="M 29.7995 18.629814 A 12.399623 15.884648 0 1 1 5.0002546,18.629814 A 12.399623 15.884648 0 1 1 29.7995 18.629814 z" - sodipodi:ry="15.884648" - sodipodi:rx="12.399623" - sodipodi:cy="18.629814" - sodipodi:cx="17.399878" - id="path6407" - style="opacity:1;fill:none;fill-opacity:1;stroke:#898b86;stroke-width:0.99074221;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - sodipodi:type="arc" /> - </g> - <path - inkscape:r_cy="true" - inkscape:r_cx="true" - id="path4573" - d="M -38.579058,5.017711 C -39.575192,5.064032 -40.580718,5.225306 -41.617649,5.503883 C -47.935436,7.217172 -53.715475,13.011644 -55.321693,19.329399 C -56.562537,24.219761 -55.043694,27.333998 -52.681382,30.13706 L -38.427129,30.490613 C -34.532892,28.552395 -31.870353,25.873704 -30.027515,21.939981 L -30.027515,8.395851 C -32.178959,6.020531 -34.729135,4.838685 -38.579058,5.017711 z M -35.437213,7.543185 C -33.465593,7.415932 -32.00023,8.569575 -32.094763,10.460217 C -32.201842,12.708909 -34.447333,14.954386 -37.01728,15.382708 C -39.480147,15.811031 -41.075991,14.317893 -40.754746,12.283362 C -40.540584,10.14175 -38.506335,8.200131 -36.257632,7.664728 C -35.981564,7.601986 -35.698932,7.560077 -35.437213,7.543185 z M -46.075736,10.006159 C -45.362166,9.944214 -44.732045,10.137628 -44.282968,10.492331 C -43.699059,10.970164 -43.388065,11.777421 -43.553706,12.771262 C -43.874952,14.805795 -45.92512,16.825568 -47.959662,17.146811 C -48.878218,17.299902 -49.631695,17.06712 -50.117062,16.569481 C -50.632857,16.021808 -50.854477,15.16285 -50.633622,14.169007 C -50.205296,12.348638 -48.489372,10.525639 -46.561911,10.097317 C -46.396269,10.060507 -46.232722,10.019788 -46.075736,10.006159 z M -37.424394,18.113969 C -34.962414,17.924937 -32.945088,19.622687 -33.048823,22.216045 L -33.170367,22.337588 C -33.277449,25.121683 -35.85572,27.669557 -38.63983,27.776638 C -41.316859,27.883716 -43.109481,25.865404 -42.681156,23.188389 C -42.359913,20.725537 -40.130348,18.465596 -37.667481,18.144355 C -37.58717,18.134316 -37.503812,18.120067 -37.424394,18.113969 z M -48.018706,19.852871 C -46.046468,19.725568 -44.795474,21.405744 -45.101659,23.65109 L -45.223203,23.742247 C -45.651525,26.312182 -47.882552,28.466501 -50.024176,28.573581 C -52.1658,28.680661 -53.355085,26.766507 -52.819679,24.410733 C -52.284273,22.162039 -50.357107,20.127802 -48.322565,19.913642 C -48.222177,19.898584 -48.115702,19.859132 -48.018706,19.852871 z " - style="fill:none;fill-rule:nonzero;stroke:#333;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - sodipodi:nodetypes="ccccccccccccsccsccscsccccccsccccscsc" /> - <path - style="fill:url(#radialGradient4556);fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -31.134002,18.15152 C -31.134002,23.988211 -36.75044,29.60465 -42.697258,29.60465 C -47.652939,29.60465 -50.075717,25.419852 -48.864328,20.79455 C -47.763065,16.719879 -44.128899,12.975586 -40.054228,11.98445 C -35.428926,10.773061 -31.134002,13.195838 -31.134002,18.15152 z " - id="path6440" - inkscape:r_cx="true" - inkscape:r_cy="true" /> - <path - style="fill:url(#radialGradient4553);fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -32.785896,16.499626 C -32.785896,22.336317 -38.402334,27.952756 -44.349152,27.952756 C -49.304833,27.952756 -51.727611,23.767958 -50.516222,19.142656 C -49.414959,15.067985 -45.780793,11.323692 -41.706121,10.332556 C -37.08082,9.121167 -32.785896,11.543945 -32.785896,16.499626 z " - id="path6447" - inkscape:r_cx="true" - inkscape:r_cy="true" /> - <path - style="fill:#3b3b3b;fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -29.933771,7.80123 L -29.933771,7.89498 C -29.881074,7.947677 -29.797562,7.996739 -29.746271,8.05123 C -29.806239,7.964969 -29.870965,7.886406 -29.933771,7.80123 z M -29.621271,8.23873 C -29.599292,8.271684 -29.549097,8.299377 -29.527521,8.33248 C -29.555555,8.299773 -29.592772,8.270872 -29.621271,8.23873 z M -29.496271,8.39498 C -29.314768,8.677052 -29.18039,8.946614 -29.027521,9.23873 L -29.027521,9.01998 C -29.17723,8.802667 -29.329473,8.592905 -29.496271,8.39498 z M -29.027521,20.98873 C -30.905932,25.474179 -34.641465,29.540397 -39.183771,31.61373 L -37.715021,31.61373 C -35.635627,30.548069 -33.639287,29.044383 -31.902521,27.08248 C -30.71006,25.757523 -29.751545,24.332263 -29.027521,22.89498 L -29.027521,20.98873 z " - id="path6490" /> - <path - style="fill:url(#linearGradient2925);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2917);stroke-width:0.99999952px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" - d="M -39.696441,31.175733 C -39.696441,31.175733 -33.791399,25.669679 -25.063258,29.047517 C -16.396087,32.401758 -14.428591,44.571406 -14.428591,44.571406 L -30.455755,44.571406 C -30.455755,44.571406 -28.618268,36.71605 -29.849221,32.492131 C -31.080173,28.268212 -39.696441,31.175733 -39.696441,31.175733 z " - id="path6728" - sodipodi:nodetypes="czcczc" /> - <path - style="opacity:0.2;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:white;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M -35.812505,29.341692 C -35.812505,29.341692 -32.693178,26.844865 -25.326869,29.862872 C -18.012016,32.859795 -15.687497,43.50002 -15.687497,43.50002 L -29.02648,43.50002 C -29.02648,43.50002 -27.928705,35.945603 -28.967596,32.171645 C -30.006485,28.397688 -35.812505,29.341692 -35.812505,29.341692 z " - id="path7675" - sodipodi:nodetypes="czcczc" /> - <path - style="opacity:1;fill:url(#linearGradient6380);fill-opacity:1;stroke:none;stroke-width:0.9863953;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M -38.040516,4.4309723 C -42.107529,4.6051923 -46.545249,6.5919553 -50.134266,10.180972 C -56.51474,16.561446 -57.780458,25.65978 -52.946766,30.493473 C -48.113074,35.327165 -39.01474,34.061447 -32.634266,27.680972 C -26.253792,21.300498 -24.988076,12.202163 -29.821766,7.3684723 C -31.936506,5.2537323 -34.877284,4.2954683 -38.040516,4.4309723 z M -35.103016,7.0247223 C -33.998433,7.0091403 -33.043091,7.3974853 -32.478016,8.1809723 C -31.347869,9.7479453 -32.239491,12.316477 -34.478016,13.930972 C -36.71654,15.545468 -39.441617,15.591695 -40.571766,14.024722 C -41.701916,12.457748 -40.810291,9.8892173 -38.571766,8.2747223 C -37.452503,7.4674743 -36.207599,7.0403043 -35.103016,7.0247223 z M -45.978016,9.4622223 C -45.318738,9.4577203 -44.715131,9.6597073 -44.290516,10.087222 C -43.158211,11.227261 -43.623305,13.533412 -45.321766,15.243472 C -47.020228,16.953532 -49.314461,17.414761 -50.446766,16.274722 C -51.579071,15.134683 -51.145227,12.828532 -49.446766,11.118472 C -48.385228,10.049684 -47.076813,9.4697253 -45.978016,9.4622223 z M -37.071766,17.930972 C -35.791903,17.802985 -34.543743,18.146495 -33.665516,19.024722 C -31.909062,20.781175 -32.237489,23.971695 -34.384266,26.118472 C -36.531045,28.26525 -39.690313,28.562425 -41.446766,26.805972 C -43.203218,25.049519 -42.906043,21.890249 -40.759266,19.743472 C -39.685877,18.670083 -38.351629,18.058959 -37.071766,17.930972 z M -47.853016,19.430972 C -47.358461,19.455605 -46.882264,19.602266 -46.478016,19.868472 C -44.861023,20.933298 -44.843929,23.620919 -46.415516,25.868472 C -47.987102,28.116026 -50.548523,29.089548 -52.165516,28.024722 C -53.78251,26.959897 -53.830853,24.272275 -52.259266,22.024722 C -51.080576,20.339057 -49.336681,19.357073 -47.853016,19.430972 z " - id="path4541" /> - <path - sodipodi:type="arc" - style="opacity:1;fill:none;fill-opacity:1;stroke:#898b86;stroke-width:0.9863953;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path4539" - sodipodi:cx="17.399878" - sodipodi:cy="18.629814" - sodipodi:rx="12.399623" - sodipodi:ry="15.884648" - d="M 29.7995 18.629814 A 12.399623 15.884648 0 1 1 5.0002546,18.629814 A 12.399623 15.884648 0 1 1 29.7995 18.629814 z" - transform="matrix(0.706206,0.706206,-0.727673,0.727673,-40.48126,-6.884929)" /> - <path - style="fill:#e6e6e6;fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -50.357005,16.385341 C -49.576197,17.166149 -47.568402,17.500781 -45.337521,15.492988 C -43.887448,14.15446 -42.54892,11.365859 -44.445169,9.9157851 C -42.102745,12.25821 -47.23377,18.281589 -50.468549,16.385341 L -50.357005,16.385341 z " - id="path6480" - inkscape:r_cx="true" - inkscape:r_cy="true" /> - <path - style="fill:#e6e6e6;fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -39.556216,14.843811 C -38.788515,15.611511 -35.827386,15.721184 -33.633957,13.747096 C -31.659871,11.882682 -31.0758,9.5438664 -32.720871,8.0084664 C -29.869413,11.737296 -36.046729,16.488883 -39.446544,14.953483 L -39.556216,14.843811 z " - id="path6488" - inkscape:r_cx="true" - inkscape:r_cy="true" - sodipodi:nodetypes="ccccc" /> - <path - style="fill:#e6e6e6;fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -41.088696,27.153796 C -35.597743,30.851783 -29.322372,22.111085 -33.916841,18.861339 C -29.658552,23.231688 -36.158046,29.955302 -41.088696,27.153796 L -41.088696,27.153796 z " - id="path6476" - inkscape:r_cx="true" - inkscape:r_cy="true" /> - <path - style="fill:#e6e6e6;fill-rule:nonzero;stroke:none;stroke-miterlimit:4" - d="M -52.387455,28.305461 C -51.547401,29.145515 -49.267256,29.38553 -46.987113,27.3454 C -44.466952,24.945248 -44.106928,21.225012 -46.147059,19.784919 C -43.266875,23.505157 -48.547212,30.105576 -52.387455,28.425469 L -52.387455,28.305461 z " - id="path6484" - inkscape:r_cx="true" - inkscape:r_cy="true" /> - <path - sodipodi:type="arc" - style="opacity:0.45108696;fill:none;fill-opacity:1;stroke:white;stroke-width:1.06059182;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - id="path6401" - sodipodi:cx="17.399878" - sodipodi:cy="18.629814" - sodipodi:rx="12.399623" - sodipodi:ry="15.884648" - d="M 29.7995 18.629814 A 12.399623 15.884648 0 1 1 5.0002546,18.629814 A 12.399623 15.884648 0 1 1 29.7995 18.629814 z" - transform="matrix(0.6512,0.648774,-0.68514,0.682587,-40.31421,-5.005059)" /> - <path - style="opacity:0.3;fill:url(#linearGradient2933);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M -28,44 L -27.41815,37 L -19.297991,37.050508 L -17,44 L -28,44 z " - id="path6738" - sodipodi:nodetypes="ccccc" /> - <path - style="opacity:0.3;fill:#ddd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M -27.642397,35.0625 L -28.182068,31.244481 L -23.056464,31.118212 L -20.784826,35.0625 L -27.642397,35.0625 z " - id="path7629" - sodipodi:nodetypes="ccccc" /> - <path - style="opacity:0.3;fill:#ddd;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M -29.51056,30.094209 L -32.000539,29.067704 L -28.750304,29.088145 L -25.729598,30.129981 L -29.51056,30.094209 z " - id="path7631" - sodipodi:nodetypes="ccccc" /> - <g - id="g2872" - transform="translate(-110,-40)"> - <path - transform="matrix(0.992983,0,0,2.142753,48.71484,-19.0262)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2862" - style="opacity:1;color:black;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.275528,0,0,0.59456,65.90022,-8.860351)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2864" - style="opacity:1;color:black;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.275528,0,0,0.594561,56.9002,0.139637)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2866" - style="opacity:1;color:black;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.275528,0,0,0.594561,74.9002,0.139637)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2868" - style="opacity:1;color:black;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.275528,0,0,0.59456,65.90022,9.13965)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2870" - style="opacity:1;color:black;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <path - transform="matrix(0.496284,0,0,0.535015,0.6124,75.37678)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2005" - style="color:black;fill:#555753;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:1.96992087;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.496284,0,0,0.535015,0.6124,69.37678)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2007" - style="color:black;fill:#555753;fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:1.96992087;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <g - id="g2041" - transform="translate(-47,-50)"> - <path - transform="matrix(0.965804,0,0,2.084105,49.36585,-18.30016)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2043" - style="opacity:1;color:black;fill:yellow;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535913,66.55122,-8.134333)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2045" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535914,57.55119,0.865653)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2047" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535914,75.55119,0.865653)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2049" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535913,66.55122,9.865668)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2051" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <path - style="opacity:1;color:black;fill:navy;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M -20.3125,-55.625 C -21.753667,-55.578358 -23.13,-55.208382 -23.90625,-54.59375 C -25.148253,-53.610338 -24.401205,-52.349026 -22.25,-51.78125 C -20.098794,-51.213474 -17.335753,-51.547838 -16.09375,-52.53125 C -14.851747,-53.514662 -15.598797,-54.775974 -17.75,-55.34375 C -18.556702,-55.556666 -19.4478,-55.652985 -20.3125,-55.625 z M -32.59375,-54.09375 C -34.034917,-54.047106 -35.411249,-53.708385 -36.1875,-53.09375 C -37.429503,-52.110333 -36.682455,-50.849026 -34.53125,-50.28125 C -32.380044,-49.713474 -29.648252,-50.047833 -28.40625,-51.03125 C -27.164247,-52.014667 -27.880046,-53.275974 -30.03125,-53.84375 C -30.837952,-54.056666 -31.72905,-54.121736 -32.59375,-54.09375 z M -17.03125,-50 C -18.472416,-49.953356 -19.817498,-49.583385 -20.59375,-48.96875 C -21.835753,-47.985333 -21.119952,-46.724026 -18.96875,-46.15625 C -16.817544,-45.588474 -14.0545,-45.922833 -12.8125,-46.90625 C -11.570497,-47.889667 -12.317544,-49.150974 -14.46875,-49.71875 C -15.275452,-49.931666 -16.16655,-50.027986 -17.03125,-50 z M -29.3125,-48.5 C -30.753667,-48.453358 -32.13,-48.083383 -32.90625,-47.46875 C -34.148253,-46.485338 -33.401205,-45.224026 -31.25,-44.65625 C -29.098794,-44.088474 -26.335753,-44.422838 -25.09375,-45.40625 C -23.851747,-46.389662 -24.598797,-47.650974 -26.75,-48.21875 C -27.556702,-48.431666 -28.4478,-48.527985 -29.3125,-48.5 z " - id="path3013" /> - <g - id="g3055" - transform="translate(0,-20)"> - <path - transform="matrix(0.965804,0,0,0.952734,2.36585,-1.79436)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2052" - style="color:black;fill:yellow;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.23396,0,0,0.200025,19.89589,2.690751)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2054" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.244989,10.55119,5.654657)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2056" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.244989,28.55119,5.654657)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2058" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.268112,0,0,0.237961,19.07786,10.41845)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2060" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <g - style="display:inline" - id="g2087" - transform="matrix(0.885715,0,0,0.885715,1.28563,-23.14286)"> - <path - transform="matrix(0.965804,0,0,2.084105,49.36585,-18.30016)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2089" - style="opacity:1;color:black;fill:yellow;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535913,66.55122,-8.134333)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2091" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535914,57.55119,0.865653)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2093" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535914,75.55119,0.865653)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2095" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535913,66.55122,9.865668)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2097" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <g - id="g3041" - transform="translate(50,0)"> - <path - sodipodi:nodetypes="ccccc" - id="rect2067" - d="M 10.15625,2 L 5.84375,18 L 45.1875,17.96875 L 40.875,1.96875 L 10.15625,2 z " - style="opacity:0.8;color:black;fill:black;fill-opacity:1;fill-rule:nonzero;stroke:black;stroke-width:2.034971;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - <g - style="opacity:0.5" - id="g2149"> - <path - style="fill:none;fill-rule:evenodd;stroke:white;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 9.9878833,19.052816 L 13.5,1" - id="path2141" /> - <path - style="fill:none;fill-rule:evenodd;stroke:white;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 20.417708,19 L 21.4375,1" - id="path2143" /> - <path - style="fill:none;fill-rule:evenodd;stroke:white;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 30.670757,19.008622 L 29.43332,1" - id="path2145" /> - <path - style="fill:none;fill-rule:evenodd;stroke:white;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" - d="M 41,19 L 37.375,1" - id="path2147" /> - </g> - </g> - <g - id="g3070" - transform="translate(-50,0)"> - <path - sodipodi:type="arc" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3062" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.23396,0,0,0.200025,19.89589,2.69075)" /> - <path - sodipodi:type="arc" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3064" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.24835,0,0,0.244989,10.55119,5.65466)" /> - <path - sodipodi:type="arc" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3066" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.24835,0,0,0.244989,28.55119,5.65466)" /> - <path - sodipodi:type="arc" - style="color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path3068" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.268112,0,0,0.237961,19.07786,10.10595)" /> - </g> - <g - style="display:inline" - id="g2121" - transform="matrix(1.143947,0,0,1.143947,-57.43614,69.9204)"> - <path - transform="matrix(0.965804,0,0,2.084105,49.36585,-18.30016)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2123" - style="opacity:1;color:black;fill:yellow;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535913,66.55122,-8.134333)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2125" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535914,57.55119,0.865653)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2127" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535914,75.55119,0.865653)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2129" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50792766;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - <path - transform="matrix(0.24835,0,0,0.535913,66.55122,9.865668)" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - sodipodi:ry="8.3968925" - sodipodi:rx="18.119612" - sodipodi:cy="12.379497" - sodipodi:cx="23.953241" - id="path2131" - style="opacity:1;color:black;fill:#333;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.50793171;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - sodipodi:type="arc" /> - </g> - <path - style="opacity:1;color:black;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 25.5,-110 C 15.840004,-110 8,-102.16 8,-92.5 C 8,-82.839997 15.840003,-75.000001 25.5,-75 C 35.159996,-75 42.999999,-82.839996 43,-92.5 C 43,-102.16 35.159996,-110 25.5,-110 z M 22.78125,-106.5625 C 23.771011,-106.65716 23.96582,-106.43877 24,-106.1875 L 24,-97.53125 C 24,-97.098147 23.698891,-96.743295 23.21875,-96.40625 C 22.703153,-96.173154 22.272538,-96.101023 21.90625,-96.3125 L 14.40625,-100.65625 C 14.101129,-100.89247 14.127611,-101.41158 16.28125,-103.6875 C 17.547068,-104.73229 18.990254,-105.55506 20.5625,-106.125 C 21.517426,-106.34785 22.293718,-106.51587 22.78125,-106.5625 z M 27.71875,-106.5625 C 28.199799,-106.5731 29.094846,-106.43834 30.4375,-106.125 C 32.009746,-105.55506 33.452932,-104.73229 34.71875,-103.6875 C 36.872391,-101.41158 36.898871,-100.89247 36.59375,-100.65625 L 29.09375,-96.3125 C 28.704021,-96.087487 28.247182,-96.197159 27.6875,-96.46875 C 27.261153,-96.786983 27,-97.125216 27,-97.53125 L 27,-106.1875 C 27.027344,-106.38852 27.163086,-106.55025 27.71875,-106.5625 z M 12.75,-98.0625 C 12.800892,-98.060484 12.85931,-98.050457 12.90625,-98.03125 L 20.40625,-93.71875 C 20.777361,-93.504491 20.915056,-93.074699 20.96875,-92.5 C 20.915056,-91.925303 20.777362,-91.495512 20.40625,-91.28125 L 12.90625,-86.96875 C 12.552459,-86.823979 12.098588,-87.108887 11.21875,-90.03125 C 11.078701,-90.83988 11,-91.651538 11,-92.5 C 11,-93.348462 11.078701,-94.160121 11.21875,-94.96875 C 11.981853,-97.50338 12.417314,-98.075679 12.75,-98.0625 z M 38.25,-98.0625 C 38.582686,-98.075681 39.018147,-97.503381 39.78125,-94.96875 C 39.921299,-94.160121 40,-93.348462 40,-92.5 C 40,-91.651537 39.921299,-90.83988 39.78125,-90.03125 C 38.901414,-87.108889 38.447541,-86.823983 38.09375,-86.96875 L 30.59375,-91.28125 C 30.242115,-91.484265 30.093674,-91.877907 30.03125,-92.40625 C 30.033454,-92.437295 30.028432,-92.469841 30.03125,-92.5 C 30.028432,-92.530159 30.033454,-92.562704 30.03125,-92.59375 C 30.093675,-93.122092 30.242114,-93.515732 30.59375,-93.71875 L 38.09375,-98.03125 C 38.14069,-98.050458 38.199108,-98.060484 38.25,-98.0625 z M 22.5,-88.8125 C 22.717889,-88.791765 22.960951,-88.710299 23.21875,-88.59375 C 23.698891,-88.256705 24,-87.901854 24,-87.46875 L 24,-78.8125 C 23.948984,-78.437453 23.456065,-78.199723 20.5625,-78.875 C 18.990254,-79.444936 17.547068,-80.267713 16.28125,-81.3125 C 14.127611,-83.588422 14.101129,-84.107533 14.40625,-84.34375 L 21.90625,-88.6875 C 22.089394,-88.793239 22.282111,-88.833235 22.5,-88.8125 z M 28.53125,-88.8125 C 28.738699,-88.827238 28.917932,-88.789009 29.09375,-88.6875 L 36.59375,-84.34375 C 36.898872,-84.107536 36.87239,-83.588424 34.71875,-81.3125 C 33.452932,-80.267713 32.009746,-79.444936 30.4375,-78.875 C 27.543935,-78.199723 27.051016,-78.437453 27,-78.8125 L 27,-87.46875 C 27,-87.918512 27.329248,-88.27628 27.84375,-88.625 C 28.088135,-88.730054 28.323801,-88.797762 28.53125,-88.8125 z " - id="path2064" /> - <g - id="g2979" - transform="translate(0,-20)"> - <path - sodipodi:type="arc" - style="opacity:1;color:black;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2971" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.965804,0,0,2.084105,2.36585,-148.3002)" /> - <path - sodipodi:type="arc" - style="opacity:1;color:black;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2973" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.800238,0,0,1.726831,6.331715,-143.8773)" /> - <path - sodipodi:type="arc" - style="opacity:1;color:black;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - id="path2975" - sodipodi:cx="23.953241" - sodipodi:cy="12.379497" - sodipodi:rx="18.119612" - sodipodi:ry="8.3968925" - d="M 42.072853 12.379497 A 18.119612 8.3968925 0 1 1 5.8336296,12.379497 A 18.119612 8.3968925 0 1 1 42.072853 12.379497 z" - transform="matrix(0.248349,0,0,0.535911,19.55124,-129.1343)" /> - <path - sodipodi:nodetypes="ccccccccccccccccccccc" - id="path2977" - d="M 24,-137.15625 L 20,-136 C 23.5,-136.875 23.945312,-136.58954 24,-136.1875 L 24,-127.53125 C 24,-126.98987 23.563049,-126.57154 22.84375,-126.15625 L 22.84375,-118.84375 C 23.563049,-118.42846 24,-118.01013 24,-117.46875 L 24,-108.8125 C 23.945312,-108.41046 23.5,-108.125 20,-109 L 24,-107.84375 L 27,-107.84375 L 31,-109 C 27.5,-108.125 27.054688,-108.41046 27,-108.8125 L 27,-117.46875 C 27,-118.01013 27.436951,-118.42846 28.15625,-118.84375 L 28.15625,-126.15625 C 27.436951,-126.57154 27,-126.98987 27,-127.53125 L 27,-136.1875 C 27.054688,-136.58954 27.5,-136.875 31,-136 L 27,-137.15625 L 24,-137.15625 z " - style="opacity:0.49536671;color:black;fill:navy;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:1.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" /> - </g> - <path - style="color:black;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.69588834;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" - d="M 25.5,-200 C 15.840004,-200 8,-192.16 8,-182.5 C 8,-172.84 15.840003,-164.99999 25.5,-165 C 35.159996,-165 42.999999,-172.84 43,-182.5 C 43,-192.16 35.159996,-200 25.5,-200 z M 22.78125,-195.5625 C 23.771011,-195.65716 23.96582,-195.43877 24,-195.1875 L 24,-187.53125 C 24,-187.12521 23.738847,-186.78698 23.3125,-186.46875 C 23.265762,-186.42866 23.208184,-186.40616 23.15625,-186.375 C 22.66748,-186.16489 22.257887,-186.10948 21.90625,-186.3125 L 15.25,-190.15625 C 14.960591,-190.3803 15.03696,-190.88915 16.875,-192.875 C 16.885475,-192.88632 16.895653,-192.89483 16.90625,-192.90625 C 18.113844,-193.90298 19.525406,-194.6875 21.03125,-195.21875 C 21.734767,-195.37149 22.381902,-195.52431 22.78125,-195.5625 z M 27.71875,-195.5625 C 28.137914,-195.57174 28.916508,-195.4472 29.96875,-195.21875 C 31.474594,-194.6875 32.886156,-193.90298 34.09375,-192.90625 C 34.105233,-192.89677 34.113549,-192.88452 34.125,-192.875 C 35.96304,-190.88915 36.039409,-190.3803 35.75,-190.15625 L 29.09375,-186.3125 C 28.70402,-186.08748 28.247182,-186.19716 27.6875,-186.46875 C 27.261153,-186.78698 27,-187.12522 27,-187.53125 L 27,-195.1875 C 27.027344,-195.38852 27.163086,-195.55025 27.71875,-195.5625 z M 13.59375,-187.5625 C 13.643788,-187.56048 13.70306,-187.55046 13.75,-187.53125 L 20.40625,-183.71875 C 20.757886,-183.51574 20.906324,-183.12209 20.96875,-182.59375 C 20.968656,-182.53128 20.96875,-182.46872 20.96875,-182.40625 C 20.906325,-181.87791 20.757887,-181.48427 20.40625,-181.28125 L 13.75,-177.46875 C 13.416208,-177.33217 12.997814,-177.62145 12.21875,-180.09375 C 12.077623,-180.87584 12,-181.67745 12,-182.5 C 12,-183.32255 12.077623,-184.12416 12.21875,-184.90625 C 12.888257,-187.03088 13.28797,-187.57482 13.59375,-187.5625 z M 37.40625,-187.5625 C 37.71203,-187.57482 38.111743,-187.03088 38.78125,-184.90625 C 38.922377,-184.12416 39,-183.32255 39,-182.5 C 39,-181.67745 38.922377,-180.87584 38.78125,-180.09375 C 38.002186,-177.62145 37.583791,-177.33217 37.25,-177.46875 L 30.59375,-181.28125 C 30.242114,-181.48426 30.093676,-181.87791 30.03125,-182.40625 C 30.030351,-182.46877 30.03125,-182.53123 30.03125,-182.59375 C 30.093675,-183.12209 30.242113,-183.51573 30.59375,-183.71875 L 37.25,-187.53125 C 37.29694,-187.55046 37.356212,-187.56048 37.40625,-187.5625 z M 22.5,-178.8125 C 22.717889,-178.79176 22.960951,-178.7103 23.21875,-178.59375 C 23.698891,-178.2567 24,-177.90185 24,-177.46875 L 24,-169.8125 C 23.952029,-169.45984 23.478393,-169.24996 21.03125,-169.78125 C 19.525406,-170.3125 18.113844,-171.09702 16.90625,-172.09375 C 16.894767,-172.10323 16.886451,-172.11548 16.875,-172.125 C 15.03696,-174.11085 14.960591,-174.6197 15.25,-174.84375 L 21.90625,-178.6875 C 22.089394,-178.79324 22.282111,-178.83324 22.5,-178.8125 z M 28.53125,-178.8125 C 28.738699,-178.82724 28.917931,-178.78901 29.09375,-178.6875 L 35.75,-174.84375 C 36.039408,-174.6197 35.963039,-174.11085 34.125,-172.125 C 34.113549,-172.11548 34.105233,-172.10323 34.09375,-172.09375 C 32.886155,-171.09702 31.474594,-170.3125 29.96875,-169.78125 C 27.521607,-169.24996 27.047971,-169.45984 27,-169.8125 L 27,-177.46875 C 27,-177.87479 27.261153,-178.21302 27.6875,-178.53125 C 27.733414,-178.56552 27.793729,-178.5911 27.84375,-178.625 C 28.088135,-178.73005 28.323801,-178.79776 28.53125,-178.8125 z " - id="path5693" - sodipodi:nodetypes="csssccccssccssccccsscccccccccsscccsccccscccssccccccccssccccccsscccssc" /> - </g> -</svg> diff --git a/rapid/glade3/video24.png b/rapid/glade3/video24.png Binary files differnew file mode 100644 index 0000000..df8b22b --- /dev/null +++ b/rapid/glade3/video24.png diff --git a/rapid/glade3/video_shadow.png b/rapid/glade3/video_shadow.png Binary files differnew file mode 100644 index 0000000..9b66480 --- /dev/null +++ b/rapid/glade3/video_shadow.png diff --git a/rapid/glade3/video_small_shadow.png b/rapid/glade3/video_small_shadow.png Binary files differnew file mode 100644 index 0000000..eb42d92 --- /dev/null +++ b/rapid/glade3/video_small_shadow.png diff --git a/rapid/idletube.py b/rapid/idletube.py index 86ff1a4..0b07536 100644 --- a/rapid/idletube.py +++ b/rapid/idletube.py @@ -1,6 +1,8 @@ # Copyright (c) 2005 Antoon Pardon # +# Modified 2010 by Damon Lynch to use python's higher performance deque, rather than a regular list +# # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation @@ -18,6 +20,10 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import collections +from Queue import Queue + from threading import Lock from thread import get_ident @@ -25,26 +31,29 @@ from types import BooleanType as UnConnected UnRegistered, Registered = False, True + class EOInformation(Exception): pass class TubeAccess(Exception): pass + class Fifo: def __init__(self): - self.fifo = [] + self.fifo = collections.deque() def put(self, item): self.fifo.append(item) def get(self): - return self.fifo.pop(0) + return self.fifo.popleft() def size(self): return len(self.fifo) + class Tube: def __init__(self, maxsize, lck = Lock, container = None): @@ -90,18 +99,12 @@ class Tube: self.readers.discard(thrd) if 'w' in access: self.writers.discard(thrd) -## print "have", self.writers, "writers" if len(self.writers) == 0: if self.container.size() == 0: -## print "emptying container, as size is", self.container.size() self.empty.release() if self.cb_src is Registered and len(self.readers) > 0: -## print "adding callback" self.cb_src = gob.idle_add(self._idle_callback) -## else: -## print "container size not empty, is", self.container.size() for _ in self.readers: -## print "putting EOInformation" self.container.put(EOInformation) self.in_use.release() @@ -148,9 +151,7 @@ class Tube: if size == 0: self.empty.release() if self.cb_src is Registered: - #gdk.threads_enter() self.cb_src = gob.idle_add(self._idle_callback) - #gdk.threads_leave() self.container.put(item) if size + 1 < self.maxsize: self.full.release() @@ -185,9 +186,8 @@ class Tube: def tube_add_watch(tube, callback, *args): - global gob #, gdk + global gob import gobject as gob - #import gtk.gdk as gdk tube.in_use.acquire() tube.cb_arglst.append([callback] + list(args)) diff --git a/rapid/media.py b/rapid/media.py index d00855a..06ebb2e 100755 --- a/rapid/media.py +++ b/rapid/media.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: latin1 -*- -### Copyright (C) 2007 Damon Lynch <damonlynch@gmail.com> +### Copyright (C) 2007, 2008, 2009, 2010 Damon Lynch <damonlynch@gmail.com> ### This program is free software; you can redistribute it and/or modify ### it under the terms of the GNU General Public License as published by @@ -18,15 +18,30 @@ ### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import os +import sys +import types +import datetime +import subprocess import config +from config import MAX_THUMBNAIL_SIZE +from config import STATUS_NOT_DOWNLOADED, \ + STATUS_DOWNLOAD_PENDING, \ + STATUS_CANNOT_DOWNLOAD + + import common import metadata import videometadata +from common import Configi18n +global _ +_ = Configi18n._ + import operator +import gtk -def _getDefaultLocation(options, ignore_missing_dir=False): +def _getDefaultLocationLegacy(options, ignore_missing_dir=False): if ignore_missing_dir: return common.getFullPath(options[0]) for default in options: @@ -34,12 +49,29 @@ def _getDefaultLocation(options, ignore_missing_dir=False): if os.path.isdir(path): return path return common.getFullPath('') + +def _getDefaultLocationXDG(dir_type): + proc = subprocess.Popen(['xdg-user-dir', dir_type], stdout=subprocess.PIPE) + output = proc.communicate()[0].strip() + return output def getDefaultPhotoLocation(ignore_missing_dir=False): - return _getDefaultLocation(config.DEFAULT_PHOTO_LOCATIONS, ignore_missing_dir) + try: + return _getDefaultLocationXDG('PICTURES') + except: + return _getDefaultLocationLegacy(config.DEFAULT_PHOTO_LOCATIONS, ignore_missing_dir) def getDefaultVideoLocation(ignore_missing_dir=False): - return _getDefaultLocation(config.DEFAULT_VIDEO_LOCATIONS, ignore_missing_dir) + try: + return _getDefaultLocationXDG('VIDEOS') + except: + return _getDefaultLocationLegacy(config.DEFAULT_VIDEO_LOCATIONS, ignore_missing_dir) + +def getDefaultBackupPhotoIdentifier(): + return os.path.split(getDefaultPhotoLocation(ignore_missing_dir = True))[1] + +def getDefaultBackupVideoIdentifier(): + return os.path.split(getDefaultVideoLocation(ignore_missing_dir = True))[1] def is_DCIM_Media(path): """ Returns true if directory specifies some media with photos on it """ @@ -79,25 +111,119 @@ def isVideo(fileName): ext = os.path.splitext(fileName)[1].lower()[1:] return (ext in videometadata.VIDEO_FILE_EXTENSIONS) -def getVideoThumbnailFile(fullFileName): + +class MediaFile: """ - Checks to see if a thumbnail file is in the same directory as the - file. Expects a full path to be part of the file name. - - Returns the filename, including path, if found, else returns None. + A photo or video file, with metadata """ - f = None - name, ext = os.path.splitext(fullFileName) - for e in videometadata.VIDEO_THUMBNAIL_FILE_EXTENSIONS: - if os.path.exists(name + '.' + e): - f = name + '.' + e - break - if os.path.exists(name + '.' + e.upper()): - f = name + '.' + e.upper() - break + def __init__(self, thread_id, name, path, size, fileSystemModificationTime, deviceName, downloadFolder, volume, isPhoto = True): + self.thread_id = thread_id + self.path = path + self.name = name + self.fullFileName = os.path.join(path, name) + self.size = size # type int + self.modificationTime = fileSystemModificationTime + self.deviceName = deviceName + self.downloadFolder = downloadFolder + self.volume = volume + + self.jobcode = '' - return f + # a reference into the SelectionTreeView's liststore + self.treerowref = None + + # generated values + self.downloadSubfolder = '' + self.downloadPath = '' + self.downloadName = '' + self.downloadFullFileName = '' + + self.isImage = isPhoto + self.isVideo = not self.isImage + if isPhoto: + self.displayName = _("photo") + self.displayNameCap = _("Photo") + else: + self.displayName = _("video") + self.displayNameCap = _("Video") + + + self.metadata = None + self.thumbnail = None + self.genericThumbnail = False + self.sampleName = '' + self.sampleSubfolder = '' + self.samplePath = '' + + # whether the sample genereated name, subfolder and path need to be refreshed in a preview + self.sampleStale = False + + self.status = STATUS_NOT_DOWNLOADED + self.problem = None # class Problem in problemnotifcation.py + + def loadMetadata(self): + """ + Attempt to load the metadata for the photo or video + + Raises errors if unable to be loaded + """ + if not self.metadata: + if self.isImage: + self.metadata = metadata.MetaData(self.fullFileName) + self.metadata.read() + else: + self.metadata = videometadata.VideoMetaData(self.fullFileName) + + def dateTime(self, alternative_if_date_missing=None): + date = None + if self.metadata: + date = self.metadata.dateTime() + if not date: + if alternative_if_date_missing: + date = alternative_if_date_missing + else: + date = datetime.datetime.fromtimestamp(self.modificationTime) + return date + + + def generateThumbnail(self, tempWorkingDir): + """ + Attempts to generate or extract a thumnail and its orientation for the photo or video + """ + if self.metadata is None: + sys.stderr.write("metadata should not be empty!") + else: + if self.isImage: + try: + thumbnail = self.metadata.getThumbnailData(MAX_THUMBNAIL_SIZE) + if not isinstance(thumbnail, types.StringType): + self.thumbnail = None + else: + orientation = self.metadata.orientation(missing=None) + pbloader = gtk.gdk.PixbufLoader() + pbloader.write(thumbnail) + pbloader.close() + # Get the resulting pixbuf and build an image to be displayed + pixbuf = pbloader.get_pixbuf() + if orientation == 8: + pixbuf = pixbuf.rotate_simple(gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE) + elif orientation == 6: + pixbuf = pixbuf.rotate_simple(gtk.gdk.PIXBUF_ROTATE_CLOCKWISE) + elif orientation == 3: + pixbuf = pixbuf.rotate_simple(gtk.gdk.PIXBUF_ROTATE_UPSIDEDOWN) + + self.thumbnail = pixbuf + except: + pass + else: + # get thumbnail of video + # it may need to be generated + self.thumbnail = self.metadata.getThumbnailData(MAX_THUMBNAIL_SIZE, tempWorkingDir) + if self.thumbnail: + # scale to size + self.thumbnail = common.scale2pixbuf(MAX_THUMBNAIL_SIZE, MAX_THUMBNAIL_SIZE, self.thumbnail) + class Media: @@ -138,7 +264,7 @@ class Media: class CardMedia(Media): """Compact Flash cards, hard drives, etc.""" - def __init__(self, path, volume = None, doNotScan=True): + def __init__(self, path, volume = None): """ volume is a gnomevfs or gio volume, see class Volume in rapid.py """ @@ -146,7 +272,7 @@ class CardMedia(Media): def setMedia(self, imagesAndVideos, fileSizeSum, noFiles): - self.imagesAndVideos = imagesAndVideos + self.imagesAndVideos = imagesAndVideos # class MediaFile self.fileSizeSum = fileSizeSum self.noFiles = noFiles @@ -158,19 +284,55 @@ class CardMedia(Media): return common.formatSizeForUser(self.fileSizeSum) else: return self.fileSizeSum - - def _firstFile(self, function_to_check): + + def sizeAndNumberDownloadPending(self): + """ + Returns how many files have their status set to download pending, and their size + """ + v = s = 0 + fileIndex = [] + for i in range(len(self.imagesAndVideos)): + mediaFile = self.imagesAndVideos[i][0] + if mediaFile.status == STATUS_DOWNLOAD_PENDING: + v += 1 + s += mediaFile.size + fileIndex.append(i) + return (v, s, fileIndex) + + def numberOfFilesNotCannotDownload(self): + """ + Returns how many files whose status is not cannot download + """ + v = 0 + for i in range(len(self.imagesAndVideos)): + mediaFile = self.imagesAndVideos[i][0] + if mediaFile.status <> STATUS_CANNOT_DOWNLOAD: + v += 1 + + return v + def downloadPending(self): + """ + Returns true if there a mediaFile with status download pending on the device. + Inefficient. Not currently used. + """ + for i in range(len(self.imagesAndVideos)): + mediaFile = self.imagesAndVideos[i][0] + if mediaFile.status == config.STATUS_DOWNLOAD_PENDING: + return True + return False + + def _firstFile(self, isImage): if self.imagesAndVideos: for i in range(len(self.imagesAndVideos)): - if function_to_check(self.imagesAndVideos[i][0]): - return self.imagesAndVideos[i] + if self.imagesAndVideos[i][0].isImage == isImage: + return self.imagesAndVideos[i][0] else: return None def firstImage(self): - return self._firstFile(isImage) + return self._firstFile(True) def firstVideo(self): - return self._firstFile(isVideo) + return self._firstFile(False) diff --git a/rapid/metadata.py b/rapid/metadata.py index c116072..3077a61 100755 --- a/rapid/metadata.py +++ b/rapid/metadata.py @@ -23,6 +23,7 @@ import sys import subprocess import config import types +import time try: import pyexiv2 @@ -370,7 +371,24 @@ class MetaData(baseclass): return model else: return missing + + def filterMangledDates(self, d): + """ + Some EXIF dates are badly formed. Try to fix them + """ + _datetime = d.strip() + # remove any weird characters at the end of the string + while _datetime and not _datetime[-1].isdigit(): + _datetime = _datetime[:-1] + _date, _time = _datetime.split(' ') + _datetime = "%s %s" % (_date.replace(":", "-") , _time.replace("-", ":")) + try: + d = datetime.datetime.strptime(_datetime, '%Y-%m-%d %H:%M:%S') + except: + d = None + return d + def dateTime(self, missing=''): """ Returns in python datetime format the date and time the image was @@ -387,10 +405,26 @@ class MetaData(baseclass): v = self["Exif.Photo.DateTimeOriginal"] else: v = self["Exif.Image.DateTime"] + if isinstance(v, types.StringType): + v = self.filterMangledDates(v) + if v is None: + v = missing return v except: return missing + def timeStamp(self, missing=''): + dt = self.dateTime(missing=None) + if not dt is None: + try: + t = dt.timetuple() + ts = time.mktime(t) + except: + ts = missing + else: + ts = missing + return ts + def subSeconds(self, missing='00'): """ returns the subsecond the image was taken, as recorded by the camera""" try: diff --git a/rapid/problemnotification.py b/rapid/problemnotification.py new file mode 100755 index 0000000..8dc07d0 --- /dev/null +++ b/rapid/problemnotification.py @@ -0,0 +1,427 @@ +#!/usr/bin/python +# -*- coding: latin1 -*- + +### Copyright (C) 2010 Damon Lynch <damonlynch@gmail.com> + +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. + +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. + +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software +### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import sys +import types +from common import Configi18n +global _ +_ = Configi18n._ + + +# components +SUBFOLDER_COMPONENT = _('subfolder') +FILENAME_COMPONENT = _('filename') + +# problem categories +METADATA_PROBLEM = 1 +FILE_PROBLEM = 2 +GENERATION_PROBLEM = 3 +DOWNLOAD_PROBLEM = 4 +DOWNLOAD_PROBLEM_W_NO = 5 +DIFFERENT_EXIF = 6 +FILE_ALREADY_EXISTS = 7 +UNIQUE_IDENTIFIER_CAT = 8 +BACKUP_PROBLEM = 9 +BACKUP_OK = 10 +FILE_ALREADY_DOWN_CAT = 11 + +# problem text +MISSING_METADATA = 1 +INVALID_DATE_TIME = 2 +MISSING_FILE_EXTENSION = 3 +MISSING_IMAGE_NUMBER = 4 +ERROR_IN_GENERATION = 5 + +CANNOT_DOWNLOAD_BAD_METADATA = 6 + +ERROR_IN_NAME_GENERATION = 7 + +DOWNLOAD_COPYING_ERROR = 8 +DOWNLOAD_COPYING_ERROR_W_NO = 9 + +FILE_ALREADY_EXISTS_NO_DOWNLOAD = 10 +UNIQUE_IDENTIFIER_ADDED = 11 +BACKUP_EXISTS = 12 +BACKUP_EXISTS_OVERWRITTEN = 13 +NO_BACKUP_PERFORMED = 14 +BACKUP_ERROR = 15 +BACKUP_DIRECTORY_CREATION = 16 + +SAME_FILE_DIFFERENT_EXIF = 17 +NO_DOWNLOAD_WAS_BACKED_UP = 18 +FILE_ALREADY_DOWNLOADED = 19 + +#extra details +UNIQUE_IDENTIFIER = '__1' +EXISTING_FILE = '__2' +NO_DATA_TO_NAME = '__3' +DOWNLOAD_COPYING_ERROR_DETAIL = '__4' +DOWNLOAD_COPYING_ERROR_W_NO_DETAIL = '__5' +BACKUP_OK_TYPE = '__6' + +# category, text, duplicates allowed +problem_definitions = { + + MISSING_METADATA: (METADATA_PROBLEM, "%s", True), + INVALID_DATE_TIME: (METADATA_PROBLEM, _('Date time value %s appears invalid.'), False), + MISSING_FILE_EXTENSION: (METADATA_PROBLEM, _("Filename does not have an extension."), False), + # a number component is something like the 8346 in IMG_8346.JPG + MISSING_IMAGE_NUMBER: (METADATA_PROBLEM, _("Filename does not have a number component."), False), + ERROR_IN_GENERATION: (METADATA_PROBLEM, _("Error generating component %s."), False), # a generic problem + + CANNOT_DOWNLOAD_BAD_METADATA: (FILE_PROBLEM, _("%(filetype)s metadata cannot be read"), False), + + ERROR_IN_NAME_GENERATION: (GENERATION_PROBLEM, _("%(filetype)s %(area)s could not be generated"), False), + + DOWNLOAD_COPYING_ERROR: (DOWNLOAD_PROBLEM, _("An error occurred when copying the %(filetype)s"), False), + DOWNLOAD_COPYING_ERROR_W_NO: (DOWNLOAD_PROBLEM_W_NO, _("An error occurred when copying the %(filetype)s"), False), + + FILE_ALREADY_EXISTS_NO_DOWNLOAD:(FILE_ALREADY_EXISTS, _("%(filetype)s already exists"), False), + UNIQUE_IDENTIFIER_ADDED: (UNIQUE_IDENTIFIER_CAT, _("%(filetype)s already exists"), False), + BACKUP_EXISTS: (BACKUP_PROBLEM, "%s", True), + BACKUP_EXISTS_OVERWRITTEN: (BACKUP_PROBLEM, "%s", True), + NO_BACKUP_PERFORMED: (BACKUP_PROBLEM, _("%(filetype)s could not be backed up because no suitable backup locations were found."), False), + BACKUP_ERROR: (BACKUP_PROBLEM, "%s", True), + BACKUP_DIRECTORY_CREATION: (BACKUP_PROBLEM, "%s", True), + NO_DOWNLOAD_WAS_BACKED_UP: (BACKUP_OK, "%s", True), + + SAME_FILE_DIFFERENT_EXIF: (DIFFERENT_EXIF, _("%(image1)s was taken at on %(image1_date)s at %(image1_time)s, and %(image2)s on %(image2_date)s at %(image2_time)s."), False), + FILE_ALREADY_DOWNLOADED: (FILE_ALREADY_DOWN_CAT, _('%(filetype)s was already downloaded'), False), +} + +extra_detail_definitions = { + UNIQUE_IDENTIFIER: _("The existing %(filetype)s was last modified on %(date)s at %(time)s. Unique identifier '%(identifier)s' added."), + EXISTING_FILE: _("The existing %(filetype)s was last modified on %(date)s at %(time)s."), + NO_DATA_TO_NAME: _("There is no data with which to name the %(filetype)s."), + DOWNLOAD_COPYING_ERROR_DETAIL: "%s", + DOWNLOAD_COPYING_ERROR_W_NO_DETAIL: _("Error: %(errorno)s %(strerror)s"), + BACKUP_OK_TYPE: "%s", +} + +class Problem: + """ + Collect problems with subfolder and filename generation, download errors, and so forth + + Problems are human readable + """ + + def __init__(self): + self.problems = {} + self.categories = {} + self.components = [] + self.extra_detail = {} + + def add_problem(self, component, problem_definition, *args): + added = True + if problem_definition not in problem_definitions: + sys.stderr.write("FIXME: unknown problem definition!\n") + else: + category, problem, duplicates_ok = problem_definitions[problem_definition] + + if args: + # check for special case of named arguments in a dictionary + if isinstance(args[0], types.DictType): + problem_details = problem % args[0] + else: + problem_details = problem % args + else: + problem_details = problem + + if not duplicates_ok: + self.problems[problem_definition] = [problem_details] + else: + if problem_definition in self.problems: + if problem_details not in self.problems[problem_definition]: + self.problems[problem_definition].append(problem_details) + else: + added = False + else: + self.problems[problem_definition] = [problem_details] + + if category not in self.categories or not added: + self.categories[category] = 1 + else: + self.categories[category] += 1 + + if (component is not None) and (component not in self.components): + self.components.append(component) + + def add_extra_detail(self, extra_detail, *args): + if extra_detail not in extra_detail_definitions: + self.extra_detail[extra_detail] = args[0] + else: + detail = extra_detail_definitions[extra_detail] + + if args: + if isinstance(args[0], types.DictType): + extra_details = detail % args[0] + else: + extra_details = detail % args + else: + extra_details = detail + + self.extra_detail[extra_detail] = extra_details + + + def has_problem(self): + return len(self.problems) > 0 + + def get_problems(self): + """ + Returns a string with the problems encountered in downloading the file. + """ + + def get_backup_error_inst(volume): + if ('%s%s' % (BACKUP_ERROR, volume)) in self.extra_detail: + return self.extra_detail['%s%s' % (BACKUP_ERROR, volume)] + else: + return '' + + def get_dir_creation_inst(volume): + return self.extra_detail['%s%s' % (BACKUP_DIRECTORY_CREATION, volume)] + + v = '' + + # special cases + if FILE_PROBLEM in self.categories: + return _("The metadata might be corrupt.") + + if FILE_ALREADY_DOWN_CAT in self.categories: + return _("The filename, extension and Exif information indicate it has already been downloaded.") + + if FILE_ALREADY_EXISTS in self.categories: + if EXISTING_FILE in self.extra_detail: + v = self.extra_detail[EXISTING_FILE] + + + if UNIQUE_IDENTIFIER_CAT in self.categories: + v = self.extra_detail[UNIQUE_IDENTIFIER] + + if DOWNLOAD_PROBLEM in self.categories: + v = self.extra_detail[DOWNLOAD_COPYING_ERROR_DETAIL] + + if DOWNLOAD_PROBLEM_W_NO in self.categories: + v = self.extra_detail[DOWNLOAD_COPYING_ERROR_W_NO_DETAIL] + + if BACKUP_OK in self.categories: + details = self.problems[NO_DOWNLOAD_WAS_BACKED_UP] + if len(self.problems[NO_DOWNLOAD_WAS_BACKED_UP]) == 1: + vv = _(' It was backed up to %(volume)s') % {'volume': details[0]} + else: + vv = _(" It was backed up to these devices: ") + for d in details[:-1]: + vv += _("%s, ") % d + vv = _("%(volumes)s and %(final_volume)s.") % \ + {'volumes': vv[:-2], + 'final_volume': details[-1]} \ + + ' ' + v += vv + + if GENERATION_PROBLEM in self.categories: + v = self.extra_detail[NO_DATA_TO_NAME] + + if DIFFERENT_EXIF in self.categories: + v = self.problems[SAME_FILE_DIFFERENT_EXIF][0] + if METADATA_PROBLEM in self.categories: + v = _('Photos detected with the same filenames, but taken at different times: %(details)s' ) % {'details':v} + + # Problems backing up + if BACKUP_PROBLEM in self.categories: + vv = '' + for p in self.problems: + details = self.problems[p] + + if p == NO_BACKUP_PERFORMED: + vv = details[0] + + elif p == BACKUP_ERROR: + + if len(details) == 1: + volume = details[0] + inst = get_backup_error_inst(volume) + if inst: + vv += _("An error occurred when backing up on %(volume)s: %(inst)s.") % {'volume': volume, 'inst': inst} + ' ' + else: + vv += _("An error occurred when backing up on %(volume)s.") % {'volume': volume} + ' ' + else: + vv += _("Errors occurred when backing up on the following backup devices: ") + for volume in details[:-1]: + inst = get_backup_error_inst(volume) + if inst: + vv += _("%(volume)s (%(inst)s), ") % {'volume': volume, 'inst': inst} + else: + vv += _("%(volume)s, ") % {'volume': volume} + volume = details[-1] + inst = get_backup_error_inst(volume) + if inst: + vv = _("%(volumes)s and %(volume)s (%(inst)s).") % \ + {'volumes': vv[:-2], + 'volume': volume, + 'inst': get_inst(volume)} + else: + vv = _("%(volumes)s and %(volume)s.") % \ + {'volumes': vv[:-2], + 'volume': volume} \ + + ' ' + + + elif p == BACKUP_EXISTS: + if len(details) == 1: + vv += _("Backup already exists on %(volume)s.") % {'volume': details[0]} + ' ' + else: + vv += _("Backups already exist in these locations: ") + for d in details[:-1]: + vv += _("%s, ") % d + vv = _("%(volumes)s and %(final_volume)s.") % \ + {'volumes': vv[:-2], + 'final_volume': details[-1]} \ + + ' ' + + elif p == BACKUP_EXISTS_OVERWRITTEN: + if len(details) == 1: + vv += _("Backup overwritten on %(volume)s.") % {'volume': details[0]} + ' ' + else: + vv += _("Backups overwritten on these devices: ") + for d in details[:-1]: + vv += _("%s, ") % d + vv = _("%(volumes)s and %(final_volume)s.") % \ + {'volumes': vv[:-2], + 'final_volume': details[-1]} \ + + ' ' + + elif p == BACKUP_DIRECTORY_CREATION: + if len(details) == 1: + volume = details[0] + vv += _("An error occurred when creating directories on %(volume)s: %(inst)s.") % {'volume': volume, 'inst': get_dir_creation_inst(volume)} + ' ' + else: + vv += _("Errors occurred when creating directories on the following backup devices: ") + for volume in details[:-1]: + vv += _("%(volume)s (%(inst)s), ") % {'volume': volume, 'inst': get_dir_creation_inst(volume)} + volume = details[-1] + vv = _("%(volumes)s and %(volume)s (%(inst)s).") % \ + {'volumes': vv[:-2], + 'volume': volume, + 'inst': get_dir_creation_inst(volume)} \ + + ' ' + + if v: + v = _('%(previousproblem)s Additionally, %(newproblem)s') % {'previousproblem': v, 'newproblem': vv[0].lower() + vv[1:]} + else: + v = vv + + + if v and METADATA_PROBLEM in self.categories: + vv = self._get_generation_title() + if self.categories[METADATA_PROBLEM] > 1: + v += _(' Furthermore, there were %(problems)s.') % {'problems': vv[0].lower() + vv[1:]} + else: + v += _(' Furthermore, there was a %(problem)s.') % {'problem': vv[0].lower() + vv[1:]} + + # Problems generating file / subfolder names + if METADATA_PROBLEM in self.categories: + for p in self.problems: + vv = '' + details = self.problems[p] + if p == MISSING_METADATA: + if len(details) == 1: + vv = _("The %(type)s metadata is missing.") % {'type': details[0]} + else: + vv = _("The following metadata is missing: ") + for d in details[:-1]: + vv += ("%s, ") % d + vv = _("%(missing_metadata_elements)s and %(final_missing_metadata_element)s.") % \ + {'missing_metadata_elements': vv[:-2], + 'final_missing_metadata_element': details[-1]} + + + elif p in [MISSING_IMAGE_NUMBER, ERROR_IN_GENERATION, INVALID_DATE_TIME]: + vv = details[0] + + v += ' ' + vv + + v = v.strip() + return v + + def _get_generation_title(self): + if self.components: + if len(self.components) > 1: + if self.categories[METADATA_PROBLEM] > 1: + return _('Problems in subfolder and filename generation') + else: + return _('Problem in subfolder and filename generation') + else: + if self.categories[METADATA_PROBLEM] > 1: + return _('Problems in %s generation') % self.components[0] + else: + return _('Problem in %s generation') % self.components[0] + return '' + + + def get_title(self): + v = '' + + if BACKUP_OK in self.categories: + if FILE_ALREADY_EXISTS in self.categories: + v = _('%(filetype)s already exists, but it was backed up') % {'filetype': self.extra_detail[BACKUP_OK_TYPE]} + else: + v = _('An error occurred when copying the %(filetype)s, but it was backed up') % {'filetype': self.extra_detail[BACKUP_OK_TYPE]} + + # High priority problems + elif FILE_ALREADY_DOWN_CAT in self.categories: + v = self.problems[FILE_ALREADY_DOWNLOADED][0] + elif DOWNLOAD_PROBLEM in self.categories: + v = self.problems[DOWNLOAD_COPYING_ERROR][0] + elif DOWNLOAD_PROBLEM_W_NO in self.categories: + v = self.problems[DOWNLOAD_COPYING_ERROR_W_NO][0] + elif GENERATION_PROBLEM in self.categories: + v = self.problems[ERROR_IN_NAME_GENERATION][0] + elif FILE_ALREADY_EXISTS in self.categories: + v = self.problems[FILE_ALREADY_EXISTS_NO_DOWNLOAD][0] + elif UNIQUE_IDENTIFIER_CAT in self.categories: + v = self.problems[UNIQUE_IDENTIFIER_ADDED][0] + elif FILE_PROBLEM in self.categories: + v = self.problems[CANNOT_DOWNLOAD_BAD_METADATA][0] + + # Lesser priority + elif len(self.categories) > 1: + v = _('Multiple problems were encountered') + elif DIFFERENT_EXIF in self.categories: + v = _('Photos detected with the same filenames, but taken at different times') + elif METADATA_PROBLEM in self.categories: + v = self._get_generation_title() + + if BACKUP_PROBLEM in self.categories: + if self.categories[BACKUP_PROBLEM] >1: + vp = _("there were errors backing up") + vv = _("There were errors backing up") + else: + vp = _("there was an error backing up") + vv = _("There was an error backing up") + if v: + # e.g. + v = _("%(previousproblem)s, and %(backinguperror)s") % {'previousproblem': v, 'backinguperror':vp} + else: + v = vv + + return v + + + +if __name__ == '__main__': + pass diff --git a/rapid/rapid.py b/rapid/rapid.py index ddd0b95..6f5490d 100755 --- a/rapid/rapid.py +++ b/rapid/rapid.py @@ -43,11 +43,12 @@ from thread import get_ident import gtk.gdk as gdk import pango +import gobject try: import gio + import glib using_gio = True - import gobject except ImportError: import gnomevfs using_gio = False @@ -66,11 +67,24 @@ import ValidatedEntry import idletube as tube import config +from config import MAX_THUMBNAIL_SIZE +from config import STATUS_CANNOT_DOWNLOAD, STATUS_DOWNLOADED, \ + STATUS_DOWNLOADED_WITH_WARNING, \ + STATUS_DOWNLOAD_FAILED, \ + STATUS_DOWNLOAD_PENDING, \ + STATUS_BACKUP_PROBLEM, \ + STATUS_NOT_DOWNLOADED, \ + STATUS_DOWNLOAD_AND_BACKUP_FAILED, \ + STATUS_WARNING + import common import misc import higdefaults as hd -from media import getDefaultPhotoLocation, getDefaultVideoLocation +from media import getDefaultPhotoLocation, getDefaultVideoLocation, \ + getDefaultBackupPhotoIdentifier, \ + getDefaultBackupVideoIdentifier + from media import CardMedia import media @@ -79,7 +93,8 @@ import metadata import videometadata from videometadata import DOWNLOAD_VIDEO -import renamesubfolderprefs as rn +import renamesubfolderprefs as rn +import problemnotification as pn import tableplusminus as tpm @@ -96,6 +111,12 @@ try: except: sys.exit(1) +try: + from dropshadow import image_to_pixbuf, pixbuf_to_image, DropShadow + DROP_SHADOW = True +except: + DROP_SHADOW = False + from common import Configi18n global _ _ = Configi18n._ @@ -103,7 +124,7 @@ _ = Configi18n._ #Translators: if neccessary, for guidance in how to translate this program, you may see http://damonlynch.net/translate.html PROGRAM_NAME = _('Rapid Photo Downloader') -MAX_THUMBNAIL_SIZE = 100 + def today(): return datetime.date.today().strftime('%Y-%m-%d') @@ -151,12 +172,15 @@ class Queue(tube.Tube): # this is ugly but I don't know a better way :( display_queue = Queue() -media_collection_treeview = thumbnail_hbox = log_dialog = None +media_collection_treeview = selection_hbox = log_dialog = None job_code = None -need_job_code = False +need_job_code_for_renaming = False class ThreadManager: + """ + Manages the threads that actually download photos and videos + """ _workers = [] @@ -191,9 +215,15 @@ class ThreadManager: def _isReadyToDownload(self, w): return w.scanComplete and not w.downloadStarted and not w.doNotStart and w.isAlive() and not w.manuallyDisabled + def _isScanning(self, w): + return w.isAlive() and w.hasStarted and not w.scanComplete and not w.manuallyDisabled + def _isDownloading(self, w): return w.downloadStarted and w.isAlive() and not w.downloadComplete + def _isPaused(self, w): + return w.downloadStarted and not w.running and not w.downloadComplete and not w.manuallyDisabled and w.isAlive() + def _isFinished(self, w): """ Returns True if the worker has finished running @@ -222,11 +252,7 @@ class ThreadManager: for w in self.getReadyToStartWorkers(): #for some reason, very occassionally a thread that has been started shows up in this list, so must filter them out if not w.isAlive(): - w.start() - - def startDownloadingWorkers(self): - for w in self.getReadyToDownloadWorkers(): - w.startStop() + w.start() def quitAllWorkers(self): global exiting @@ -262,6 +288,12 @@ class ThreadManager: for w in self._workers: if w.hasStarted and not w.downloadStarted: yield w + + def getNotDownloadingAndNotFinishedWorkers(self): + for w in self._workers: + if w.hasStarted and not w.downloadStarted and not self._isFinished(w): + yield w + def noReadyToStartWorkers(self): n = 0 @@ -270,6 +302,27 @@ class ThreadManager: n += 1 return n + def noScanningWorkers(self): + n = 0 + for w in self._workers: + if self._isScanning(w): + n += 1 + return n + + def getScanningWorkers(self): + for w in self._workers: + if self._isScanning(w): + yield w + + def scanComplete(self, threads): + """ + Returns True only if the list of threads have completed their scan + """ + for thread_id in threads: + if not self[thread_id].scanComplete: + return False + return True + def noReadyToDownloadWorkers(self): n = 0 for w in self._workers: @@ -286,22 +339,21 @@ class ThreadManager: for w in self._workers: if self._isDownloading(w): yield w - - - def getPausedWorkers(self): - for w in self._workers: - if w.hasStarted and not w.running: - yield w def getPausedDownloadingWorkers(self): for w in self._workers: - if w.downloadStarted and not w.running: + if self._isPaused(w): yield w def getWaitingForJobCodeWorkers(self): for w in self._workers: if w.waitingForJobCode: yield w + + def getAutoStartWorkers(self): + for w in self._workers: + if w.autoStart: + yield w def getFinishedWorkers(self): for w in self._workers: @@ -322,6 +374,13 @@ class ThreadManager: i += 1 return i + def noPausedWorkers(self): + i = 0 + for w in self._workers: + if self._isPaused(w): + i += 1 + return i + def getNextThread_id(self): return len(self._workers) @@ -354,7 +413,7 @@ class RapidPreferences(prefs.Preferences): "download_folder": prefs.Value(prefs.STRING, getDefaultPhotoLocation()), "video_download_folder": prefs.Value(prefs.STRING, - getDefaultVideoLocation()), + getDefaultVideoLocation()), "subfolder": prefs.ListValue(prefs.STRING_LIST, rn.DEFAULT_SUBFOLDER_PREFS), "video_subfolder": prefs.ListValue(prefs.STRING_LIST, rn.DEFAULT_VIDEO_SUBFOLDER_PREFS), "image_rename": prefs.ListValue(prefs.STRING_LIST, [rn.FILENAME, @@ -371,9 +430,9 @@ class RapidPreferences(prefs.Preferences): "backup_images": prefs.Value(prefs.BOOL, False), "backup_device_autodetection": prefs.Value(prefs.BOOL, True), "backup_identifier": prefs.Value(prefs.STRING, - config.DEFAULT_BACKUP_LOCATION), + getDefaultBackupPhotoIdentifier()), "video_backup_identifier": prefs.Value(prefs.STRING, - config.DEFAULT_VIDEO_BACKUP_LOCATION), + getDefaultBackupVideoIdentifier()), "backup_location": prefs.Value(prefs.STRING, os.path.expanduser('~')), "strip_characters": prefs.Value(prefs.BOOL, True), "auto_download_at_startup": prefs.Value(prefs.BOOL, False), @@ -381,15 +440,19 @@ class RapidPreferences(prefs.Preferences): "auto_unmount": prefs.Value(prefs.BOOL, False), "auto_exit": prefs.Value(prefs.BOOL, False), "auto_delete": prefs.Value(prefs.BOOL, False), - "indicate_download_error": prefs.Value(prefs.BOOL, True), "download_conflict_resolution": prefs.Value(prefs.STRING, config.SKIP_DOWNLOAD), "backup_duplicate_overwrite": prefs.Value(prefs.BOOL, False), - "backup_missing": prefs.Value(prefs.STRING, config.IGNORE), - "display_thumbnails": prefs.Value(prefs.BOOL, True), + "display_selection": prefs.Value(prefs.BOOL, True), + "display_size_column": prefs.Value(prefs.BOOL, True), + "display_filename_column": prefs.Value(prefs.BOOL, False), + "display_type_column": prefs.Value(prefs.BOOL, True), + "display_path_column": prefs.Value(prefs.BOOL, False), + "display_device_column": prefs.Value(prefs.BOOL, False), + "display_preview_folders": prefs.Value(prefs.BOOL, True), "show_log_dialog": prefs.Value(prefs.BOOL, False), "day_start": prefs.Value(prefs.STRING, "03:00"), - "downloads_today": prefs.ListValue(prefs.STRING_LIST, [today(), '0']), + "downloads_today": prefs.ListValue(prefs.STRING_LIST, [today(), '0']), "stored_sequence_no": prefs.Value(prefs.INT, 0), "job_codes": prefs.ListValue(prefs.STRING_LIST, [_('New York'), _('Manila'), _('Prague'), _('Helsinki'), _('Wellington'), @@ -397,6 +460,12 @@ class RapidPreferences(prefs.Preferences): _('Budapest'), _('Rome'), _('Moscow'), _('Delhi'), _('Warsaw'), _('Jakarta'), _('Madrid'), _('Stockholm')]), "synchronize_raw_jpg": prefs.Value(prefs.BOOL, False), + "hpaned_pos": prefs.Value(prefs.INT, 0), + "vpaned_pos": prefs.Value(prefs.INT, 0), + "main_window_size_x": prefs.Value(prefs.INT, 0), + "main_window_size_y": prefs.Value(prefs.INT, 0), + "main_window_maximized": prefs.Value(prefs.INT, 0), + "show_warning_downloading_from_camera": prefs.Value(prefs.BOOL, True), } def __init__(self): @@ -503,7 +572,7 @@ class ImageRenameTable(tpm.TablePlusMinus): self.connect("remove", self.size_adjustment) # get scrollbar thickness from parent app scrollbar - very hackish, but what to do?? - self.bump = self.parentApp.parentApp.image_scrolledwindow.get_hscrollbar().allocation.height + self.bump = 16# self.parentApp.parentApp.image_scrolledwindow.get_hscrollbar().allocation.height self.haveVerticalScrollbar = False # vbar is '1' if there is not vertical scroll bar @@ -749,21 +818,19 @@ class PreferencesDialog(gnomeglade.Component): # get example photo and video data try: w = workers.firstWorkerReadyToDownload() - root, self.sampleImageName = w.firstImage() - image = os.path.join(root, self.sampleImageName) - - self.sampleImage = metadata.MetaData(image) - self.sampleImage.read() + mediaFile = w.firstImage() + self.sampleImageName = mediaFile.name + # assume the metadata is already read + self.sampleImage = mediaFile.metadata except: self.sampleImage = metadata.DummyMetaData() self.sampleImageName = 'IMG_0524.CR2' - try: - root, self.sampleVideoName, modificationTime = w.firstVideo() - video = os.path.join(root, self.sampleVideoName) - self.sampleVideo = videometadata.VideoMetaData(video) - self.videoFallBackDate = modificationTime + mediaFile = w.firstVideo() + self.sampleVideoName = mediaFile.name + self.sampleVideo = mediaFile.metadata + self.videoFallBackDate = mediaFile.modificationTime except: self.sampleVideo = videometadata.DummyMetaData() self.sampleVideoName = 'MVI_1379.MOV' @@ -861,7 +928,6 @@ class PreferencesDialog(gnomeglade.Component): self.compatibility_table.set_row_spacing(0, hd.VERTICAL_CONTROL_LABEL_SPACE) self._setupTableSpacing(self.error_table) - self.error_table.set_row_spacing(5, hd.VERTICAL_CONTROL_SPACE / 2) def _setupTableSpacing(self, table): @@ -1016,11 +1082,7 @@ class PreferencesDialog(gnomeglade.Component): self.video_backup_identifier_entry.set_text(self.prefs.video_backup_identifier) #setup controls for manipulating sensitivity - self._backupControls0 = [self.auto_detect_backup_checkbutton, - self.missing_backup_label, - self.backup_error_radiobutton, - self.backup_warning_radiobutton, - self.backup_ignore_radiobutton] + self._backupControls0 = [self.auto_detect_backup_checkbutton] self._backupControls1 = [self.backup_identifier_explanation_label, self.backup_identifier_label, self.backup_identifier_entry, @@ -1059,21 +1121,11 @@ class PreferencesDialog(gnomeglade.Component): def _setupErrorTab(self): - self.indicate_download_error_checkbutton.set_active( - self.prefs.indicate_download_error) - if self.prefs.download_conflict_resolution == config.SKIP_DOWNLOAD: self.skip_download_radiobutton.set_active(True) else: self.add_identifier_radiobutton.set_active(True) - if self.prefs.backup_missing == config.REPORT_ERROR: - self.backup_error_radiobutton.set_active(True) - elif self.prefs.backup_missing == config.REPORT_WARNING: - self.backup_warning_radiobutton.set_active(True) - else: - self.backup_ignore_radiobutton.set_active(True) - if self.prefs.backup_duplicate_overwrite: self.backup_duplicate_overwrite_radiobutton.set_active(True) else: @@ -1081,18 +1133,20 @@ class PreferencesDialog(gnomeglade.Component): def updateExampleFileName(self, display_table, rename_table, sample, sampleName, example_label, fallback_date = None): + problem = pn.Problem() if hasattr(self, display_table): rename_table.updateExampleJobCode() - name, problem = rename_table.prefsFactory.generateNameUsingPreferences( + rename_table.prefsFactory.initializeProblem(problem) + name = rename_table.prefsFactory.generateNameUsingPreferences( sample, sampleName, self.prefs.strip_characters, sequencesPreliminary=False, fallback_date=fallback_date) else: - name = problem = '' + name = '' # since this is markup, escape it text = "<i>%s</i>" % common.escape(name) - if problem: + if problem.has_problem(): text += "\n" # Translators: please do not modify or leave out html formatting tags like <i> and <b>. These are used to format the text the users sees text += _("<i><b>Warning:</b> There is insufficient metadata to fully generate the name. Please use other renaming options.</i>") @@ -1117,18 +1171,20 @@ class PreferencesDialog(gnomeglade.Component): Displays example subfolder name(s) to the user """ + problem = pn.Problem() if hasattr(self, display_table): subfolder_table.updateExampleJobCode() - path, problem = subfolder_table.prefsFactory.generateNameUsingPreferences( + subfolder_table.prefsFactory.initializeProblem(problem) + path = subfolder_table.prefsFactory.generateNameUsingPreferences( sample, sampleName, self.prefs.strip_characters, fallback_date = fallback_date) else: - path = problem = '' + path = '' text = os.path.join(download_folder, path) # since this is markup, escape it path = common.escape(text) - if problem: + if problem.has_problem(): warning = _("<i><b>Warning:</b> There is insufficient metadata to fully generate subfolders. Please use other subfolder naming options.</i>" ) else: warning = "" @@ -1235,10 +1291,10 @@ class PreferencesDialog(gnomeglade.Component): def on_add_job_code_button_clicked(self, button): - j = JobCodeDialog(self.widget, self.prefs.job_codes, None, self.add_job_code, False, True) + j = JobCodeDialog(self.widget, self.prefs.job_codes, None, self.add_job_code, False, True, True) - def add_job_code(self, dialog, userChoseCode, job_code, autoStart): + def add_job_code(self, dialog, userChoseCode, job_code, autoStart, downloadSelected): dialog.destroy() if userChoseCode: if job_code and job_code not in self.prefs.job_codes: @@ -1342,15 +1398,6 @@ class PreferencesDialog(gnomeglade.Component): def on_backup_duplicate_skip_radiobutton_toggled(self, widget): self.prefs.backup_duplicate_overwrite = not widget.get_active() - - def on_backup_error_radiobutton_toggled(self, widget): - self.prefs.backup_missing = config.REPORT_ERROR - - def on_backup_warning_radiobutton_toggled(self, widget): - self.prefs.backup_missing = config.REPORT_WARNING - - def on_backup_ignore_radiobutton_toggled(self, widget): - self.prefs.backup_missing = config.IGNORE def on_treeview_cursor_changed(self, tree): path, column = tree.get_cursor() @@ -1365,9 +1412,6 @@ class PreferencesDialog(gnomeglade.Component): self.updatePhotoDownloadFolderExample() self.updateVideoDownloadFolderExample() - def on_indicate_download_error_checkbutton_toggled(self, check_button): - self.prefs.indicate_download_error = check_button.get_active() - def on_add_identifier_radiobutton_toggled(self, widget): if widget.get_active(): self.prefs.download_conflict_resolution = config.ADD_UNIQUE_IDENTIFIER @@ -1512,12 +1556,88 @@ def file_types_by_number(noImages, noVideos): else: v = _('photo') return v + +def date_time_human_readable(date, with_line_break=True): + if with_line_break: + return _("%(date)s\n%(time)s") % {'date':date.strftime("%x"), 'time':date.strftime("%X")} + else: + return _("%(date)s %(time)s") % {'date':date.strftime("%x"), 'time':date.strftime("%X")} + +def time_subseconds_human_readable(date, subseconds): + return _("%(hour)s:%(minute)s:%(second)s:%(subsecond)s") % \ + {'hour':date.strftime("%H"), + 'minute':date.strftime("%M"), + 'second':date.strftime("%S"), + 'subsecond': subseconds} + +def date_time_subseconds_human_readable(date, subseconds): + return _("%(date)s %(hour)s:%(minute)s:%(second)s:%(subsecond)s") % \ + {'date':date.strftime("%x"), + 'hour':date.strftime("%H"), + 'minute':date.strftime("%M"), + 'second':date.strftime("%S"), + 'subsecond': subseconds} + +def generateSubfolderAndName(mediaFile, problem, subfolderPrefsFactory, + renamePrefsFactory, + nameUsesJobCode, subfolderUsesJobCode, + strip_characters, fallback_date): + + subfolderPrefsFactory.initializeProblem(problem) + mediaFile.sampleSubfolder = subfolderPrefsFactory.generateNameUsingPreferences( + mediaFile.metadata, mediaFile.name, + strip_characters, + fallback_date = fallback_date) + + mediaFile.samplePath = os.path.join(mediaFile.downloadFolder, mediaFile.sampleSubfolder) + + renamePrefsFactory.initializeProblem(problem) + mediaFile.sampleName = renamePrefsFactory.generateNameUsingPreferences( + mediaFile.metadata, mediaFile.name, strip_characters, + sequencesPreliminary=False, + fallback_date = fallback_date) + + if not (mediaFile.sampleName or nameUsesJobCode) or not (mediaFile.sampleSubfolder or subfolderUsesJobCode): + if not (mediaFile.sampleName or nameUsesJobCode) and not (mediaFile.sampleSubfolder or subfolderUsesJobCode): + area = _("subfolder and filename") + elif not (mediaFile.sampleName or nameUsesJobCode): + area = _("filename") + else: + area = _("subfolder") + problem.add_problem(None, pn.ERROR_IN_NAME_GENERATION, {'filetype': mediaFile.displayNameCap, 'area': area}) + problem.add_extra_detail(pn.NO_DATA_TO_NAME, {'filetype': area}) + mediaFile.problem = problem + mediaFile.status = STATUS_CANNOT_DOWNLOAD + elif problem.has_problem(): + mediaFile.problem = problem + mediaFile.status = STATUS_WARNING + else: + mediaFile.status = STATUS_NOT_DOWNLOADED + + +class NeedAJobCode(): + """ + Convenience class to check whether a job code is missing for a given + file type (photo or video) + """ + def __init__(self, prefs): + self.imageRenameUsesJobCode = rn.usesJobCode(prefs.image_rename) + self.imageSubfolderUsesJobCode = rn.usesJobCode(prefs.subfolder) + self.videoRenameUsesJobCode = rn.usesJobCode(prefs.video_rename) + self.videoSubfolderUsesJobCode = rn.usesJobCode(prefs.video_subfolder) + + def needAJobCode(self, job_code, is_image): + if is_image: + return not job_code and (self.imageRenameUsesJobCode or self.imageSubfolderUsesJobCode) + else: + return not job_code and (self.videoRenameUsesJobCode or self.videoSubfolderUsesJobCode) + class CopyPhotos(Thread): """Copies photos from source to destination, backing up if needed""" def __init__(self, thread_id, parentApp, fileRenameLock, fileSequenceLock, statsLock, downloadedFilesLock, - downloadStats, autoStart = False, cardMedia = None): + downloadStats, autoStart = False, cardMedia = None): self.parentApp = parentApp self.thread_id = thread_id self.ctrl = True @@ -1545,10 +1665,19 @@ class CopyPhotos(Thread): self.cardMedia = cardMedia self.initializeDisplay(thread_id, self.cardMedia) + + self.scanComplete = self.downloadStarted = self.downloadComplete = False - self.noErrors = self.noWarnings = 0 + # Need to account for situations where the user adjusts their preferences when the program is scanning + # Here the sample filenames and paths will be out of date, and they will need to be updated + # This flag indicates whether that is the case or not + self.scanResultsStale = False # name and subfolder + self.scanResultsStaleDownloadFolder = False #download folder only - self.scanComplete = self.downloadStarted = self.downloadComplete = False + if DOWNLOAD_VIDEO: + self.types_searched_for = _('photos or videos') + else: + self.types_searched_for = _('photos') Thread.__init__(self) @@ -1557,39 +1686,34 @@ class CopyPhotos(Thread): if self.cardMedia: media_collection_treeview.addCard(thread_id, self.cardMedia.prettyName(), - '', 0, progress=0.0, + '', progress=0.0, # This refers to when a device like a hard drive is having its contents scanned, # looking for photos or videos. It is visible initially in the progress bar for each device - # (which normally holds "x of y photos"). + # (which normally holds "x photos and videos"). # It maybe displayed only briefly if the contents of the device being scanned is small. progressBarText=_('scanning...')) - def firstImage(self): """ - returns name, path and size of the first image + returns class mediaFile of the first photo """ - - name, root, size, modificationTime = self.cardMedia.firstImage() + mediaFile = self.cardMedia.firstImage() + return mediaFile - return root, name - def firstVideo(self): """ - returns name, path and size of the first image + returns class mediaFile of the first video """ - - name, root, size, modificationTime = self.cardMedia.firstVideo() - - return root, name, modificationTime - + mediaFile = self.cardMedia.firstVideo() + return mediaFile + def handlePreferencesError(self, e, prefsFactory): sys.stderr.write(_("Sorry,these preferences contain an error:\n")) sys.stderr.write(prefsFactory.formatPreferencesForPrettyPrint() + "\n") msg = str(e) sys.stderr.write(msg + "\n") - def initializeFromPrefs(self, notifyOnError): + def initializeFromPrefs(self, notifyOnError): """ Setup thread so that user preferences are handled """ @@ -1605,7 +1729,6 @@ class CopyPhotos(Thread): self.prefs = self.parentApp.prefs - #Image and Video filename preferences self.imageRenamePrefsFactory = rn.ImageRenamePreferences(self.prefs.image_rename, self, @@ -1627,8 +1750,7 @@ class CopyPhotos(Thread): # copy this variable, as it is used heavily in the loop # and it is perhaps relatively expensive to read self.stripCharacters = self.prefs.strip_characters - - + def run(self): """ Copy photos from device to local drive, and if requested, backup @@ -1705,14 +1827,92 @@ class CopyPhotos(Thread): display_queue.close("rw") return False + + def scanMedia(): + """ + Scans media for photos and videos + """ + + # load images to display for when a thumbnail cannot be extracted or created + + if DROP_SHADOW: + self.photoThumbnail = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/photo_shadow.png')) + self.videoThumbnail = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/video_shadow.png')) + else: + self.photoThumbnail = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/photo.png')) + self.videoThumbnail = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/video.png')) + + imageRenameUsesJobCode = rn.usesJobCode(self.prefs.image_rename) + imageSubfolderUsesJobCode = rn.usesJobCode(self.prefs.subfolder) + videoRenameUsesJobCode = rn.usesJobCode(self.prefs.video_rename) + videoSubfolderUsesJobCode = rn.usesJobCode(self.prefs.video_subfolder) + + def loadFileMetadata(mediaFile): + """ + loads the metadate for the file, and additional information if required + """ + + problem = pn.Problem() + try: + mediaFile.loadMetadata() + except: + mediaFile.status = STATUS_CANNOT_DOWNLOAD + mediaFile.metadata = None + problem.add_problem(None, pn.CANNOT_DOWNLOAD_BAD_METADATA, {'filetype': mediaFile.displayNameCap}) + mediaFile.problem = problem + else: + # generate sample filename and subfolder + if mediaFile.isImage: + fallback_date = None + subfolderPrefsFactory = self.subfolderPrefsFactory + renamePrefsFactory = self.imageRenamePrefsFactory + nameUsesJobCode = imageRenameUsesJobCode + subfolderUsesJobCode = imageSubfolderUsesJobCode + else: + fallback_date = mediaFile.modificationTime + subfolderPrefsFactory = self.videoSubfolderPrefsFactory + renamePrefsFactory = self.videoRenamePrefsFactory + nameUsesJobCode = videoRenameUsesJobCode + subfolderUsesJobCode = videoSubfolderUsesJobCode + + generateSubfolderAndName(mediaFile, problem, subfolderPrefsFactory, renamePrefsFactory, + nameUsesJobCode, subfolderUsesJobCode, + self.prefs.strip_characters, fallback_date) + # generate thumbnail + mediaFile.generateThumbnail(self.videoTempWorkingDir) + + if mediaFile.thumbnail is None: + mediaFile.genericThumbnail = True + if mediaFile.isImage: + mediaFile.thumbnail = self.photoThumbnail + else: + mediaFile.thumbnail = self.videoThumbnail - def downloadFile(name): + def downloadable(name): isImage = media.isImage(name) isVideo = media.isVideo(name) download = (DOWNLOAD_VIDEO and (isImage or isVideo) or ((not DOWNLOAD_VIDEO) and isImage)) return (download, isImage, isVideo) + + def addFile(name, path, size, modificationTime, device, volume, isImage): + if isImage: + downloadFolder = self.prefs.download_folder + else: + downloadFolder = self.prefs.video_download_folder + + mediaFile = media.MediaFile(self.thread_id, name, path, size, modificationTime, device, downloadFolder, volume, isImage) + loadFileMetadata(mediaFile) + # modificationTime is very useful for quick sorting + imagesAndVideos.append((mediaFile, modificationTime)) + display_queue.put((self.parentApp.addFile, (mediaFile,))) + + if isImage: + self.noImages += 1 + else: + self.noVideos += 1 + def gio_scan(path, fileSizeSum): """recursive function to scan a directory and its subdirectories @@ -1726,9 +1926,6 @@ class CopyPhotos(Thread): self.running = True if not self.ctrl: - self.running = False - display_queue.put((media_collection_treeview.removeCard, (self.thread_id, ))) - display_queue.close("rw") return None if child.get_file_type() == gio.FILE_TYPE_DIRECTORY: @@ -1738,15 +1935,13 @@ class CopyPhotos(Thread): return None elif child.get_file_type() == gio.FILE_TYPE_REGULAR: name = child.get_name() - download, isImage, isVideo = downloadFile(name) + download, isImage, isVideo = downloadable(name) if download: size = child.get_size() - imagesAndVideos.append((name, path.get_path(), size, child.get_modification_time()),) + modificationTime = child.get_modification_time() + addFile(name, path.get_path(), size, modificationTime, self.cardMedia.prettyName(limit=0), self.cardMedia.volume, isImage) fileSizeSum += size - if isVideo: - self.noVideos += 1 - else: - self.noImages += 1 + return fileSizeSum @@ -1754,7 +1949,7 @@ class CopyPhotos(Thread): fileSizeSum = 0 self.noVideos = 0 self.noImages = 0 - + if not using_gio or not self.cardMedia.volume: for root, dirs, files in os.walk(self.cardMedia.getPath()): for name in files: @@ -1763,23 +1958,17 @@ class CopyPhotos(Thread): self.running = True if not self.ctrl: - self.running = False - display_queue.put((media_collection_treeview.removeCard, (self.thread_id, ))) - display_queue.close("rw") - return + return None - download, isImage, isVideo = downloadFile(name) + download, isImage, isVideo = downloadable(name) if download: - image = os.path.join(root, name) - size = os.path.getsize(image) - modificationTime = os.path.getmtime(image) - imagesAndVideos.append((name, root, size, modificationTime),) + fullFileName = os.path.join(root, name) + size = os.path.getsize(fullFileName) + modificationTime = os.path.getmtime(fullFileName) + addFile(name, root, size, modificationTime, self.cardMedia.prettyName(limit=0), self.cardMedia.volume, isImage) fileSizeSum += size - if isVideo: - self.noVideos += 1 - else: - self.noImages += 1 + else: # using gio and have a volume @@ -1787,19 +1976,15 @@ class CopyPhotos(Thread): fileSizeSum = gio_scan(self.cardMedia.volume.volume.get_root(), fileSizeSum) if fileSizeSum == None: # thread exiting - return + return None - imagesAndVideos.sort(key=operator.itemgetter(3)) + # sort in place based on modification time + imagesAndVideos.sort(key=operator.itemgetter(1)) noFiles = len(imagesAndVideos) self.scanComplete = True self.display_file_types = file_types_by_number(self.noImages, self.noVideos) - - if DOWNLOAD_VIDEO: - self.types_searched_for = _('photos or videos') - else: - self.types_searched_for = _('photos') if noFiles: @@ -1808,10 +1993,9 @@ class CopyPhotos(Thread): # It refers to the actual number of photos that can be copied. For example, the user might see the following: # '0 of 512 photos' or '0 of 10 videos' or '0 of 202 photos and videos'. # This particular text is displayed to the user before the download has started. - display = _("0 of %(number)s %(filetypes)s") % {'number':noFiles, 'filetypes':self.display_file_types} - display_queue.put((media_collection_treeview.updateCard, (self.thread_id, self.cardMedia.sizeOfImagesAndVideos(), noFiles))) + display = _("%(number)s %(filetypes)s") % {'number':noFiles, 'filetypes':self.display_file_types} + display_queue.put((media_collection_treeview.updateCard, (self.thread_id, self.cardMedia.sizeOfImagesAndVideos()))) display_queue.put((media_collection_treeview.updateProgress, (self.thread_id, 0.0, display, 0))) - display_queue.put((self.parentApp.timeRemaining.add, (self.thread_id, fileSizeSum))) display_queue.put((self.parentApp.setDownloadButtonSensitivity, ())) # Translators: as you have already seen, the text can contain values that should not be modified or left out by you, for example %s. @@ -1829,23 +2013,6 @@ class CopyPhotos(Thread): display_queue.put((media_collection_treeview.removeCard, (self.thread_id, ))) cmd_line(_("Device scan complete: no %(filetypes)s found on %(device)s") % {'device':self.cardMedia.prettyName(limit=0), 'filetypes':self.types_searched_for}) return False - - def cleanUp(): - """ - Cleanup functions that must be performed whether the thread exits - early or when it has completed its run. - """ - - - for tempWorkingDir in (videoTempWorkingDir, photoTempWorkingDir): - if tempWorkingDir: - # possibly delete any lingering files - tf = os.listdir(tempWorkingDir) - if tf: - for f in tf: - os.remove(os.path.join(tempWorkingDir, f)) - - os.rmdir(tempWorkingDir) def logError(severity, problem, details, resolution=None): @@ -1856,228 +2023,334 @@ class CopyPhotos(Thread): else: self.noErrors += 1 + def notifyAndUnmount(umountAttemptOK): + if not self.cardMedia.volume: + unmountMessage = "" + notificationName = PROGRAM_NAME + else: + notificationName = self.cardMedia.volume.get_name() + if self.prefs.auto_unmount and umountAttemptOK: + self.cardMedia.volume.unmount(self.on_volume_unmount) + # This message informs the user that the device (e.g. camera, hard drive or memory card) was automatically unmounted and they can now remove it + unmountMessage = _("The device can now be safely removed") + else: + unmountMessage = "" + + file_types = file_types_by_number(noImagesDownloaded, noVideosDownloaded) + file_types_skipped = file_types_by_number(noImagesSkipped, noVideosSkipped) + message = _("%(noFiles)s %(filetypes)s downloaded") % {'noFiles':noFilesDownloaded, 'filetypes': file_types} + noFilesSkipped = noImagesSkipped + noVideosSkipped + if noFilesSkipped: + message += "\n" + _("%(noFiles)s %(filetypes)s failed to download") % {'noFiles':noFilesSkipped, 'filetypes':file_types_skipped} + + if self.noWarnings: + message = "%s\n%s " % (message, self.noWarnings) + _("warnings") + if self.noErrors: + message = "%s\n%s " % (message, self.noErrors) + _("errors") + + if unmountMessage: + message = "%s\n%s" % (message, unmountMessage) + + n = pynotify.Notification(notificationName, message) + + if self.cardMedia.volume: + icon = self.cardMedia.volume.get_icon_pixbuf(self.parentApp.notification_icon_size) + else: + icon = self.parentApp.application_icon + + n.set_icon_from_pixbuf(icon) + n.show() - def checkProblemWithNameGeneration(newName, destination, source, problem, filetype): - if not newName: - # a serious problem - a filename should never be blank! - logError(config.SERIOUS_ERROR, - _("%(filetype)s filename could not be generated") % {'filetype': filetype}, - # '%(source)s' and '%(problem)s' are two more examples of text that should not be modified or left out - _("Source: %(source)s\nProblem: %(problem)s") % {'source': source, 'problem': problem}, - fileSkippedDisplay) - elif problem: - logError(config.WARNING, - _("%(filetype)s filename could not be properly generated. Check to ensure there is sufficient metadata.") % {'filetype': filetype}, - _("Source: %(source)s\nPartially generated filename: %(newname)s\nDestination: %(destination)s\nProblem: %(problem)s") % - {'source': source, 'destination': destination, 'newname': newName, 'problem': problem}) - - def fileAlreadyExists(source, fileSkippedDisplay, fileAlreadyExistsDisplay, destination=None, identifier=None): - """ Notify the user that the photo or video could not be downloaded because it already exists""" - if self.prefs.indicate_download_error: - if source and destination and identifier: - logError(config.SERIOUS_ERROR, fileAlreadyExistsDisplay, - _("Source: %(source)s\nDestination: %(destination)s") - % {'source': source, 'destination': newFile}, - _("Unique identifier '%s' added") % identifier) - elif source and destination: - logError(config.SERIOUS_ERROR, fileAlreadyExistsDisplay, - _("Source: %(source)s\nDestination: %(destination)s") - % {'source': source, 'destination': destination}, - fileSkippedDisplay) + def createTempDir(baseDir): + """ + Create a temporary directory in which to download the photos to. + + Returns the directory if it was created, else returns None. + + Don't want to put it in system temp folder, as that is likely + to be on another partition and hence copying files from it + to the actual download folder will be slow!""" + try: + t = tempfile.mkdtemp(prefix='rapid-tmp-', + dir=baseDir) + return t + except OSError, (errno, strerror): + if not self.cardMedia.volume: + image_device = _("Source: %s\n") % self.cardMedia.getPath() else: - logError(config.SERIOUS_ERROR, fileAlreadyExistsDisplay, - _("Source: %(source)s") - % {'source': source}, - fileSkippedDisplay) + _("Device: %s\n") % self.cardMedia.volume.get_name() + destination = _("Destination: %s") % baseDir + logError(config.CRITICAL_ERROR, _('Could not create temporary download directory'), + image_device + destination, + _("Download cannot proceed")) + cmd_line(_("Error:") + " " + _('Could not create temporary download directory')) + cmd_line(image_device + destination) + cmd_line(_("Download cannot proceed")) + display_queue.put((media_collection_treeview.removeCard, (self.thread_id, ))) + display_queue.put((self.parentApp.downloadFailed, (self.thread_id, ))) + display_queue.close("rw") + self.running = False + self.lock.release() + return None + + def setupBackup(): + """ + Check for presence of backup path or volumes, and return the number of devices being used (1 in case of a path) + """ + no_devices = 0 + if self.prefs.backup_images: + no_devices = len(self.parentApp.backupVolumes) + if not self.prefs.backup_device_autodetection: + if not os.path.isdir(self.prefs.backup_location): + # the user has manually specified a path, but it + # does not exist. This is a problem. + try: + os.makedirs(self.prefs.backup_location) + except: + logError(config.SERIOUS_ERROR, _("Backup path does not exist"), + _("The path %s could not be created") % path, + _("No backups can occur") + ) + no_devices = 0 + return no_devices + + def checkIfNeedAJobCode(): + needAJobCode = NeedAJobCode(self.prefs) + + for f in self.cardMedia.imagesAndVideos: + mediaFile = f[0] + if mediaFile.status in [STATUS_WARNING, STATUS_NOT_DOWNLOADED]: + if needAJobCode.needAJobCode(mediaFile.jobcode, mediaFile.isImage): + return True + return False + + def createBothTempDirs(): + self.photoTempWorkingDir = createTempDir(photoBaseDownloadDir) + created = self.photoTempWorkingDir is not None + if created and DOWNLOAD_VIDEO: + self.videoTempWorkingDir = createTempDir(videoBaseDownloadDir) + created = self.videoTempWorkingDir is not None + + return created + + def checkProblemWithNameGeneration(mediaFile): + if mediaFile.problem.has_problem(): + logError(config.WARNING, + mediaFile.problem.get_title(), + _("Source: %(source)s\nDestination: %(destination)s\n%(problem)s") % + {'source': mediaFile.fullFileName, 'destination': mediaFile.downloadFullFileName, 'problem': mediaFile.problem.get_problems()}) + mediaFile.status = STATUS_DOWNLOADED_WITH_WARNING - def downloadCopyingError(source, destination, filetype, errno=None, strerror=None): - """Notify the user that an error occurred when coyping an photo or video""" - if errno != None and strerror != None: - logError(config.SERIOUS_ERROR, _('Download copying error'), - _("Source: %(source)s\nDestination: %(destination)s\nError: %(errorno)s %(strerror)s") - % {'source': source, 'destination': destination, 'errorno': errno, 'strerror': strerror}, - _('The %(filetype)s was not copied.') % {'filetype': filetype}) + def fileAlreadyExists(mediaFile, identifier=None): + """ Notify the user that the photo or video could not be downloaded because it already exists""" + + # get information on when the existing file was last modified + try: + modificationTime = os.path.getmtime(mediaFile.downloadFullFileName) + dt = datetime.datetime.fromtimestamp(modificationTime) + date = dt.strftime("%x") + time = dt.strftime("%X") + except: + sys.stderr.write("WARNING: could not determine the file modification time of an existing file\n") + date = time = '' + + if not identifier: + mediaFile.problem.add_problem(None, pn.FILE_ALREADY_EXISTS_NO_DOWNLOAD, {'filetype':mediaFile.displayNameCap}) + mediaFile.problem.add_extra_detail(pn.EXISTING_FILE, {'filetype': mediaFile.displayName, 'date': date, 'time': time}) + mediaFile.status = STATUS_DOWNLOAD_FAILED + log_status = config.SERIOUS_ERROR + problem_text = pn.extra_detail_definitions[pn.EXISTING_FILE] % {'date':date, 'time':time, 'filetype': mediaFile.displayName} else: - logError(config.SERIOUS_ERROR, _('Download copying error'), - _("Source: %(source)s\nDestination: %(destination)s") - % {'source': source, 'destination': destination}, - _('The %(filetype)s was not copied.') % {'filetype': filetype}) + mediaFile.problem.add_problem(None, pn.UNIQUE_IDENTIFIER_ADDED, {'filetype':mediaFile.displayNameCap}) + mediaFile.problem.add_extra_detail(pn.UNIQUE_IDENTIFIER, {'identifier': identifier, 'filetype': mediaFile.displayName, 'date': date, 'time': time}) + mediaFile.status = STATUS_DOWNLOADED_WITH_WARNING + log_status = config.WARNING + problem_text = pn.extra_detail_definitions[pn.UNIQUE_IDENTIFIER] % {'identifier': identifier, 'filetype': mediaFile.displayName, 'date': date, 'time': time} - - def sameFileNameDifferentExif(image1, image1_date_time, image1_subseconds, image2, image2_date_time, image2_subseconds): - logError(config.WARNING, _('Photos detected with the same filenames, but taken at different times:'), - _("First photo: %(image1)s %(image1_date_time)s:%(image1_subseconds)s\nSecond photo: %(image2)s %(image2_date_time)s:%(image2_subseconds)s") % - {'image1': image1, 'image1_date_time': image1_date_time, 'image1_subseconds': image1_subseconds, - 'image2': image2, 'image2_date_time': image2_date_time, 'image2_subseconds': image2_subseconds}) - + logError(log_status, mediaFile.problem.get_title(), + _("Source: %(source)s\nDestination: %(destination)s") + % {'source': mediaFile.fullFileName, 'destination': mediaFile.downloadFullFileName}, + problem_text) + def downloadCopyingError(mediaFile, inst=None, errno=None, strerror=None): + """Notify the user that an error occurred (most likely at the OS / filesystem level) when coyping a photo or video""" + + if errno != None and strerror != None: + mediaFile.problem.add_problem(None, pn.DOWNLOAD_COPYING_ERROR_W_NO, {'filetype': mediaFile.displayName}) + mediaFile.problem.add_extra_detail(pn.DOWNLOAD_COPYING_ERROR_W_NO_DETAIL, {'errorno': errno, 'strerror': strerror}) - def generateSubfolderAndFileName(fullFileName, name, needMetaDataToCreateUniqueImageName, - needMetaDataToCreateUniqueSubfolderName, fallback_date): + else: + mediaFile.problem.add_problem(None, pn.DOWNLOAD_COPYING_ERROR, {'filetype': mediaFile.displayName}) + if not inst: + # hopefully inst will never be None, but just to be safe... + inst = _("Please check your system and try again.") + mediaFile.problem.add_extra_detail(pn.DOWNLOAD_COPYING_ERROR_DETAIL, inst) + + logError(config.SERIOUS_ERROR, mediaFile.problem.get_title(), mediaFile.problem.get_problems()) + mediaFile.status = STATUS_DOWNLOAD_FAILED + + def sameNameDifferentExif(image_name, mediaFile): + """Notify the user that a file was already downloaded with the same name, but the exif information was different""" + i1_ext, i1_date_time, i1_subseconds = downloaded_files.extExifDateTime(image_name) + detail = {'image1': "%s%s" % (image_name, i1_ext), + 'image1_date': i1_date_time.strftime("%x"), + 'image1_time': time_subseconds_human_readable(i1_date_time, i1_subseconds), + 'image2': mediaFile.name, + 'image2_date': mediaFile.metadata.dateTime().strftime("%x"), + 'image2_time': time_subseconds_human_readable( + mediaFile.metadata.dateTime(), + mediaFile.metadata.subSeconds())} + mediaFile.problem.add_problem(None, pn.SAME_FILE_DIFFERENT_EXIF, detail) + + msg = pn.problem_definitions[pn.SAME_FILE_DIFFERENT_EXIF][1] % detail + logError(config.WARNING,_('Photos detected with the same filenames, but taken at different times'), msg) + mediaFile.status = STATUS_DOWNLOADED_WITH_WARNING + + def generateSubfolderAndFileName(mediaFile): """ Generates subfolder and file names for photos and videos """ skipFile = alreadyDownloaded = False sequence_to_use = None - - if not self.isImage: - # file is a video file + + if mediaFile.isVideo: fileRenameFactory = self.videoRenamePrefsFactory subfolderFactory = self.videoSubfolderPrefsFactory - try: - # this step immedidately reads the metadata from the video file - # (which is different than pyexiv2) - fileMetadata = videometadata.VideoMetaData(fullFileName) - except: - logError(config.CRITICAL_ERROR, _("Could not open %(filetype)s") % {'filetype': fileBeingDownloadedDisplay}, - _("Source: %s") % fullFileName, - fileSkippedDisplay) - skipFile = True - fileMetadata = newName = newFile = path = subfolder = sequence_to_use = None - return (skipFile, fileMetadata, newName, newFile, path, subfolder, sequence_to_use) else: # file is an photo fileRenameFactory = self.imageRenamePrefsFactory subfolderFactory = self.subfolderPrefsFactory - try: - fileMetadata = metadata.MetaData(fullFileName) - except IOError: - logError(config.CRITICAL_ERROR, _("Could not open %(filetype)s") % {'filetype': fileBeingDownloadedDisplay}, - _("Source: %s") % fullFileName, - fileSkippedDisplay) - skipFile = True - fileMetadata = newName = newFile = path = subfolder = sequence_to_use = None - return (skipFile, fileMetadata, newName, newFile, path, subfolder, sequence_to_use) - else: - try: - # this step can fail if the source photo is corrupt - fileMetadata.read() - except: - skipFile = True + + fileRenameFactory.setJobCode(mediaFile.jobcode) + subfolderFactory.setJobCode(mediaFile.jobcode) - + mediaFile.problem = pn.Problem() + subfolderFactory.initializeProblem(mediaFile.problem) + fileRenameFactory.initializeProblem(mediaFile.problem) + + # Here we cannot assume that the subfolder value will contain something -- the user may have changed the preferences after the scan + mediaFile.downloadSubfolder = subfolderFactory.generateNameUsingPreferences( + mediaFile.metadata, mediaFile.name, + self.stripCharacters, fallback_date = mediaFile.modificationTime) + + + if self.prefs.synchronize_raw_jpg and usesImageSequenceElements and mediaFile.isImage: + #synchronizing RAW and JPEG only applies to photos, not videos + image_name, image_ext = os.path.splitext(mediaFile.name) + with self.downloadedFilesLock: + i, sequence_to_use = downloaded_files.matching_pair(image_name, image_ext, mediaFile.metadata.dateTime(), mediaFile.metadata.subSeconds()) + if i == -1: + # this exact file has already been downloaded (same extension, same filename, and same exif date time subsecond info) + if not addUniqueIdentifier: + logError(config.SERIOUS_ERROR,_('Photo has already been downloaded'), + _("Source: %(source)s") % {'source': mediaFile.fullFileName}) + mediaFile.problem.add_problem(None, pn.FILE_ALREADY_DOWNLOADED, {'filetype': mediaFile.displayNameCap}) + skipFile = True + + + # pass the subfolder the image will go into, as this is needed to determine subfolder sequence numbers + # indicate that sequences chosen should be queued + if not skipFile: - if self.isImage and not fileMetadata.rpd_keys() and (needMetaDataToCreateUniqueSubfolderName or - (needMetaDataToCreateUniqueImageName and - not addUniqueIdentifier)): + mediaFile.downloadName = fileRenameFactory.generateNameUsingPreferences( + mediaFile.metadata, mediaFile.name, self.stripCharacters, mediaFile.downloadSubfolder, + sequencesPreliminary = True, + sequence_to_use = sequence_to_use, + fallback_date = mediaFile.modificationTime) + + mediaFile.downloadPath = os.path.join(mediaFile.downloadFolder, mediaFile.downloadSubfolder) + mediaFile.downloadFullFileName = os.path.join(mediaFile.downloadPath, mediaFile.downloadName) + + if not mediaFile.downloadName or not mediaFile.downloadSubfolder: + if not mediaFile.downloadName and not mediaFile.downloadSubfolder: + area = _("subfolder and filename") + elif not mediaFile.downloadName: + area = _("filename") + else: + area = _("subfolder") + problem.add_problem(None, pn.ERROR_IN_NAME_GENERATION, {'filetype': mediaFile.displayNameCap, 'area': area}) + problem.add_extra_detail(pn.NO_DATA_TO_NAME, {'filetype': area}) skipFile = True - - #TODO similar checking for video - - if skipFile: - logError(config.SERIOUS_ERROR, _("%(filetype)s has no metadata") % {'filetype': fileBeingDownloadedDisplayCap}, - _("Metadata is essential for generating subfolder and/or file names.\nSource: %s") % fullFileName, - fileSkippedDisplay) - newName = newFile = path = subfolder = None + logError(config.SERIOUS_ERROR, pn.problem_definitions[ERROR_IN_NAME_GENERATION][1] % {'filetype': mediaFile.displayNameCap, 'area': area}) + + if not skipFile: + checkProblemWithNameGeneration(mediaFile) else: - # attempt to generate a subfolder name - subfolder, problem = subfolderFactory.generateNameUsingPreferences( - fileMetadata, name, - self.stripCharacters, fallback_date = fallback_date) - - if problem: - logError(config.WARNING, - _("Subfolder name could not be properly generated. Check to ensure there is sufficient metadata."), - _("Subfolder: %(subfolder)s\nFile: %(file)s\nProblem: %(problem)s") % - {'subfolder': subfolder, 'file': fullFileName, 'problem': problem}) - - if self.prefs.synchronize_raw_jpg and usesImageSequenceElements and self.isImage: - #synchronizing RAW and JPEG only applies to photos, not videos - image_name, image_ext = os.path.splitext(name) - with self.downloadedFilesLock: - i, sequence_to_use = downloaded_files.matching_pair(image_name, image_ext, fileMetadata.dateTime(), fileMetadata.subSeconds()) - if i == -1: - # this exact file has already been downloaded (same extension, same filename, and same exif date time subsecond info) - if not addUniqueIdentifier: - # there is no point to download it, as there is no way a unique filename will be generated - alreadyDownloaded = skipFile = True - elif i == -99: - i1_ext, i1_date_time, i1_subseconds = downloaded_files.extExifDateTime(image_name) - sameFileNameDifferentExif("%s%s" % (image_name, i1_ext), i1_date_time, i1_subseconds, name, fileMetadata.dateTime(), fileMetadata.subSeconds()) - - - # pass the subfolder the image will go into, as this is needed to determine subfolder sequence numbers - # indicate that sequences chosen should be queued + self.sizeDownloaded += mediaFile.size * (no_backup_devices + 1) + mediaFile.status = STATUS_DOWNLOAD_FAILED - # TODO check 'or alreadyDownloaded' is meant to be here - if not (skipFile or alreadyDownloaded): - newName, problem = fileRenameFactory.generateNameUsingPreferences( - fileMetadata, name, self.stripCharacters, subfolder, - sequencesPreliminary = True, - sequence_to_use = sequence_to_use, - fallback_date = fallback_date) - - path = os.path.join(baseDownloadDir, subfolder) - newFile = os.path.join(path, newName) - - if not newName: - skipFile = True - if not alreadyDownloaded: - checkProblemWithNameGeneration(newName, path, fullFileName, problem, fileBeingDownloadedDisplayCap) - else: - fileAlreadyExists(fullFileName, fileSkippedDisplay, fileAlreadyExistsDisplay, newFile) - newName = newFile = path = subfolder = None - - return (skipFile, fileMetadata, newName, newFile, path, subfolder, sequence_to_use) + return (skipFile, sequence_to_use) + + def progress_callback(amount_downloaded, total): + if (amount_downloaded - self.bytes_downloaded > 2097152) or (amount_downloaded == total): + chunk_downloaded = amount_downloaded - self.bytes_downloaded + self.bytes_downloaded = amount_downloaded + percentComplete = (float(self.sizeDownloaded + amount_downloaded) / sizeFiles) * 100 + + display_queue.put((media_collection_treeview.updateProgress, (self.thread_id, percentComplete, None, chunk_downloaded))) - def downloadFile(path, newFile, newName, originalName, image, fileMetadata, subfolder, sequence_to_use, modificationTime): + def downloadFile(mediaFile, sequence_to_use): """ Downloads the photo or video file to the specified subfolder """ - if not self.isImage: + if not mediaFile.isImage: renameFactory = self.videoRenamePrefsFactory else: renameFactory = self.imageRenamePrefsFactory - - def progress_callback(self, v): + + def progress_callback_no_update(amount_downloaded, total): pass try: fileDownloaded = False - if not os.path.isdir(path): - os.makedirs(path) + if not os.path.isdir(mediaFile.downloadPath): + os.makedirs(mediaFile.downloadPath) nameUniqueBeforeCopy = True downloadNonUniqueFile = True - + # do a preliminary check to see if a file with the same name already exists - if os.path.exists(newFile): + if os.path.exists(mediaFile.downloadFullFileName): nameUniqueBeforeCopy = False if not addUniqueIdentifier: downloadNonUniqueFile = False - if (usesVideoSequenceElements and not self.isImage) or (usesImageSequenceElements and self.isImage and not self.prefs.synchronize_raw_jpg): + if (usesVideoSequenceElements and not mediaFile.isImage) or (usesImageSequenceElements and mediaFile.isImage and not self.prefs.synchronize_raw_jpg): # potentially, a unique file name could still be generated # investigate this possibility with self.fileSequenceLock: - for possibleName, problem in renameFactory.generateNameSequencePossibilities(fileMetadata, - originalName, self.stripCharacters, subfolder): + for possibleName in renameFactory.generateNameSequencePossibilities( + mediaFile.metadata, + mediaFile.name, self.stripCharacters, mediaFile.downloadSubfolder): if possibleName: # no need to check for any problems here, it's just a temporary name - possibleFile = os.path.join(path, possibleName) - possibleTempFile = os.path.join(tempWorkingDir, possibleName) + possibleFile = os.path.join(mediaFile.downloadPath, possibleName) + possibleTempFile = os.path.join(tempWorkingDir, possibleName) if not os.path.exists(possibleFile) and not os.path.exists(possibleTempFile): downloadNonUniqueFile = True break if not downloadNonUniqueFile: - fileAlreadyExists(fullFileName, fileSkippedDisplay, fileAlreadyExistsDisplay, newFile) + fileAlreadyExists(mediaFile) copy_succeeded = False if nameUniqueBeforeCopy or downloadNonUniqueFile: - tempWorkingfile = os.path.join(tempWorkingDir, newName) + tempWorkingfile = os.path.join(tempWorkingDir, mediaFile.downloadName) if using_gio: g_dest = gio.File(path=tempWorkingfile) - g_src = gio.File(path=fullFileName) - if not g_src.copy(g_dest, progress_callback, cancellable=gio.Cancellable()): - downloadCopyingError(fullFileName, tempWorkingfile, fileBeingDownloadedDisplay) - else: - copy_succeeded = True + g_src = gio.File(path=mediaFile.fullFileName) + try: + if not g_src.copy(g_dest, progress_callback, cancellable=gio.Cancellable()): + downloadCopyingError(mediaFile) + else: + copy_succeeded = True + except glib.GError, inst: + downloadCopyingError(mediaFile, inst=inst) else: - shutil.copy2(fullFileName, tempWorkingfile) + shutil.copy2(mediaFile.fullFileName, tempWorkingfile) copy_succeeded = True if copy_succeeded: @@ -2086,333 +2359,364 @@ class CopyPhotos(Thread): if usesSequenceElements: with self.fileSequenceLock: # get a filename and use this as the "real" filename - if sequence_to_use is None and self.prefs.synchronize_raw_jpg and self.isImage: + if sequence_to_use is None and self.prefs.synchronize_raw_jpg and mediaFile.isImage: # must check again, just in case the matching pair has been downloaded in the meantime - image_name, image_ext = os.path.splitext(originalName) + image_name, image_ext = os.path.splitext(mediaFile.name) with self.downloadedFilesLock: - i, sequence_to_use = downloaded_files.matching_pair(image_name, image_ext, fileMetadata.dateTime(), fileMetadata.subSeconds()) + i, sequence_to_use = downloaded_files.matching_pair(image_name, image_ext, mediaFile.metadata.dateTime(), mediaFile.metadata.subSeconds()) if i == -99: - i1_ext, i1_date_time, i1_subseconds = downloaded_files.extExifDateTime(image_name) - sameFileNameDifferentExif("%s%s" % (image_name, i1_ext), i1_date_time, i1_subseconds, originalName, fileMetadata.dateTime(), fileMetadata.subSeconds()) - - + sameNameDifferentExif(image_name, mediaFile) - newName, problem = renameFactory.generateNameUsingPreferences( - fileMetadata, originalName, self.stripCharacters, subfolder, + mediaFile.downloadName = renameFactory.generateNameUsingPreferences( + mediaFile.metadata, mediaFile.name, self.stripCharacters, mediaFile.downloadSubfolder, sequencesPreliminary = False, sequence_to_use = sequence_to_use, - fallback_date = fallback_date) - checkProblemWithNameGeneration(newName, path, fullFileName, problem, fileBeingDownloadedDisplayCap) - if not newName: + fallback_date = mediaFile.modificationTime) + + if not mediaFile.downloadName: # there was a serious error generating the filename doRename = False else: - newFile = os.path.join(path, newName) + mediaFile.downloadFullFileName = os.path.join(mediaFile.downloadPath, mediaFile.downloadName) # check if the file exists again - if os.path.exists(newFile): + if os.path.exists(mediaFile.downloadFullFileName): if not addUniqueIdentifier: doRename = False - fileAlreadyExists(fullFileName, fileSkippedDisplay, fileAlreadyExistsDisplay, newFile) + fileAlreadyExists(mediaFile) else: # add basic suffix to make the filename unique - name = os.path.splitext(newName) + name = os.path.splitext(mediaFile.downloadName) suffixAlreadyUsed = True while suffixAlreadyUsed: - if newFile in duplicate_files: - duplicate_files[newFile] += 1 + if mediaFile.downloadFullFileName in duplicate_files: + duplicate_files[mediaFile.downloadFullFileName] += 1 else: - duplicate_files[newFile] = 1 - identifier = '_%s' % duplicate_files[newFile] - newName = name[0] + identifier + name[1] - possibleNewFile = os.path.join(path, newName) + duplicate_files[mediaFile.downloadFullFileName] = 1 + identifier = '_%s' % duplicate_files[mediaFile.downloadFullFileName] + mediaFile.downloadName = name[0] + identifier + name[1] + possibleNewFile = os.path.join(mediaFile.downloadPath, mediaFile.downloadName) suffixAlreadyUsed = os.path.exists(possibleNewFile) - fileAlreadyExists(fullFileName, fileSkippedDisplay, fileAlreadyExistsDisplay, newFile, identifier=identifier) - newFile = possibleNewFile + fileAlreadyExists(mediaFile, identifier) + mediaFile.downloadFullFileName = possibleNewFile if doRename: + rename_succeeded = False if using_gio: - g_dest = gio.File(path=newFile) + g_dest = gio.File(path=mediaFile.downloadFullFileName) g_src = gio.File(path=tempWorkingfile) - if not g_src.move(g_dest, progress_callback, cancellable=gio.Cancellable()): - downloadCopyingError(tempWorkingfile, newFile, fileBeingDownloadedDisplay) + try: + if not g_src.move(g_dest, progress_callback_no_update, cancellable=gio.Cancellable()): + downloadCopyingError(mediaFile) + else: + rename_succeeded = True + except glib.GError, inst: + downloadCopyingError(mediaFile, inst=inst) else: - os.rename(tempWorkingfile, newFile) + os.rename(tempWorkingfile, mediaFile.downloadFullFileName) + rename_succeeded = True - fileDownloaded = True - if usesImageSequenceElements: - if self.prefs.synchronize_raw_jpg and self.isImage: - name, ext = os.path.splitext(originalName) - if sequence_to_use is None: - with self.fileSequenceLock: - seq = self.imageRenamePrefsFactory.sequences.getFinalSequence() - else: - seq = sequence_to_use - with self.downloadedFilesLock: - downloaded_files.add_download(name, ext, fileMetadata.dateTime(), fileMetadata.subSeconds(), seq) + if rename_succeeded: + fileDownloaded = True + if mediaFile.status != STATUS_DOWNLOADED_WITH_WARNING: + mediaFile.status = STATUS_DOWNLOADED + if usesImageSequenceElements: + if self.prefs.synchronize_raw_jpg and mediaFile.isImage: + name, ext = os.path.splitext(mediaFile.name) + if sequence_to_use is None: + with self.fileSequenceLock: + seq = renameFactory.sequences.getFinalSequence() + else: + seq = sequence_to_use + with self.downloadedFilesLock: + downloaded_files.add_download(name, ext, mediaFile.metadata.dateTime(), mediaFile.metadata.subSeconds(), seq) - + + with self.fileSequenceLock: + if sequence_to_use is None: + renameFactory.sequences.imageCopySucceeded() + if usesStoredSequenceNo: + self.prefs.stored_sequence_no += 1 + with self.fileSequenceLock: if sequence_to_use is None: - renameFactory.sequences.imageCopySucceeded() - if usesStoredSequenceNo: - self.prefs.stored_sequence_no += 1 - - with self.fileSequenceLock: - if sequence_to_use is None: - if self.prefs.incrementDownloadsToday(): - # A new day, according the user's preferences of what time a day begins, has started - cmd_line(_("New day has started - resetting 'Downloads Today' sequence number")) - - sequences.setDownloadsToday(0) + if self.prefs.incrementDownloadsToday(): + # A new day, according the user's preferences of what time a day begins, has started + cmd_line(_("New day has started - resetting 'Downloads Today' sequence number")) + + sequences.setDownloadsToday(0) - except IOError, (errno, strerror): - downloadCopyingError(fullFileName, newFile, fileBeingDownloadedDisplay, errno, strerror) - - except OSError, (errno, strerror): - downloadCopyingError(fullFileName, newFile, fileBeingDownloadedDisplay, errno, strerror) + except (IOError, OSError), (errno, strerror): + downloadCopyingError(mediaFile, errno=errno, strerror=strerror) - if usesImageSequenceElements: + if usesSequenceElements: if not fileDownloaded and sequence_to_use is None: - self.imageRenamePrefsFactory.sequences.imageCopyFailed() - - - return (fileDownloaded, newName, newFile) + renameFactory.sequences.imageCopyFailed() + + #update record keeping using in tracking progress + self.sizeDownloaded += mediaFile.size + self.bytes_downloaded_in_download = self.bytes_downloaded + + return fileDownloaded - def backupFile(subfolder, newName, fileDownloaded, newFile, originalFile): + def backupFile(mediaFile, fileDownloaded, no_backup_devices): """ Backup photo or video to path(s) chosen by the user - there are two scenarios: + there are three scenarios: (1) file has just been downloaded and should now be backed up (2) file was already downloaded on some previous occassion and should still be backed up, because it hasn't been yet (3) file has been backed up already (or at least, a file with the same name already exists) A backup medium can be used to backup photos or videos, or both. """ - - #TODO convert to using GIO + backed_up = False fileNotBackedUpMessageDisplayed = False - try: + error_encountered = False + expected_bytes_downloaded = self.sizeDownloaded + no_backup_devices * mediaFile.size + + if no_backup_devices: for rootBackupDir in self.parentApp.backupVolumes: + self.bytes_downloaded = 0 if self.prefs.backup_device_autodetection: - if self.isImage: + volume = self.parentApp.backupVolumes[rootBackupDir].get_name() + if mediaFile.isImage: backupDir = os.path.join(rootBackupDir, self.prefs.backup_identifier) else: backupDir = os.path.join(rootBackupDir, self.prefs.video_backup_identifier) else: # photos and videos will be backed up into the same root folder, which the user has manually specified backupDir = rootBackupDir + volume = backupDir # os.path.split(backupDir)[1] + # if user has chosen auto detection, then: # photos should only be backed up to photo backup locations # videos should only be backed up to video backup locations # if user did not choose autodetection, and the backup path doesn't exist, then # will try to create it - if os.path.exists(backupDir) or not self.prefs.backup_device_autodetection: + if os.path.isdir(backupDir) or not self.prefs.backup_device_autodetection: - backupPath = os.path.join(backupDir, subfolder) - newBackupFile = os.path.join(backupPath, newName) + backupPath = os.path.join(backupDir, mediaFile.downloadSubfolder) + newBackupFile = os.path.join(backupPath, mediaFile.downloadName) copyBackup = True if os.path.exists(newBackupFile): # this check is of course not thread safe -- it doesn't need to be, because at this stage the file names are going to be unique # (the folder structure is the same as the actual download folders, and the file names are unique in them) - copyBackup = self.prefs.backup_duplicate_overwrite - if self.prefs.indicate_download_error: - severity = config.SERIOUS_ERROR - problem = _("Backup of %(file_type)s already exists") % {'file_type': fileBeingDownloadedDisplay} - details = _("Source: %(source)s\nDestination: %(destination)s") \ - % {'source': originalFile, 'destination': newBackupFile} - if copyBackup : - resolution = _("Backup %(file_type)s overwritten") % {'file_type': fileBeingDownloadedDisplay} + copyBackup = self.prefs.backup_duplicate_overwrite + + if copyBackup: + mediaFile.problem.add_problem(None, pn.BACKUP_EXISTS_OVERWRITTEN, volume) + else: + mediaFile.problem.add_problem(None, pn.BACKUP_EXISTS, volume) + severity = config.SERIOUS_ERROR + fileNotBackedUpMessageDisplayed = True + + title = _("Backup of %(file_type)s already exists") % {'file_type': mediaFile.displayName} + details = _("Source: %(source)s\nDestination: %(destination)s") \ + % {'source': mediaFile.fullFileName, 'destination': newBackupFile} + if copyBackup: + resolution = _("Backup %(file_type)s overwritten") % {'file_type': mediaFile.displayName} + else: + if self.prefs.backup_device_autodetection: + volume = self.parentApp.backupVolumes[rootBackupDir].get_name() + resolution = _("%(file_type)s not backed up to %(volume)s") % {'file_type': mediaFile.displayNameCap, 'volume': volume} else: - fileNotBackedUpMessageDisplayed = True - if self.prefs.backup_device_autodetection: - volume = self.parentApp.backupVolumes[rootBackupDir].get_name() - resolution = _("%(file_type)s not backed up to %(volume)s") % {'file_type': fileBeingDownloadedDisplayCap, 'volume': volume} - else: - resolution = _("%(file_type)s not backed up") % {'file_type': fileBeingDownloadedDisplayCap} - logError(severity, problem, details, resolution) + resolution = _("%(file_type)s not backed up") % {'file_type': mediaFile.displayNameCap} + logError(severity, title, details, resolution) if copyBackup: if fileDownloaded: - fileToCopy = newFile + fileToCopy = mediaFile.downloadFullFileName else: - fileToCopy = originalFile + fileToCopy = mediaFile.fullFileName if os.path.isdir(backupPath): pathExists = True else: - # recreate folder structure in backup location - # cannot do os.makedirs(backupPath) - it can give bad results when using external drives - # we know backupDir exists - # all the components of subfolder may not - folders = subfolder.split(os.path.sep) - folderToMake = backupDir - for f in folders: - if f: - folderToMake = os.path.join(folderToMake, f) - if not os.path.isdir(folderToMake): - try: - os.mkdir(folderToMake) - pathExists = True - except (IOError, OSError), (errno, strerror): - fileNotBackedUpMessageDisplayed = True - logError(config.SERIOUS_ERROR, _('Backing up error'), - _("Destination directory could not be created: %(directory)s\n") % - {'directory': folderToMake, } + - _("Source: %(source)s\nDestination: %(destination)s\n") % - {'source': originalFile, 'destination': newBackupFile} + - _("Error: %(errno)s %(strerror)s") % {'errno': errno, 'strerror': strerror}, - _('The %(file_type)s was not backed up.') % {'file_type': fileBeingDownloadedDisplay} - ) - pathExists = False - break + pathExists = False + # create the backup subfolders + if using_gio: + dirs = gio.File(backupPath) + try: + if dirs.make_directory_with_parents(cancellable=gio.Cancellable()): + pathExists = True + except glib.GError, inst: + fileNotBackedUpMessageDisplayed = True + mediaFile.problem.add_problem(None, pn.BACKUP_DIRECTORY_CREATION, volume) + mediaFile.problem.add_extra_detail('%s%s' % (pn.BACKUP_DIRECTORY_CREATION, volume), inst) + error_encountered = True + logError(config.SERIOUS_ERROR, _('Backing up error'), + _("Destination directory could not be created: %(directory)s\n") % + {'directory': backupPath, } + + _("Source: %(source)s\nDestination: %(destination)s") % + {'source': mediaFile.fullFileName, 'destination': newBackupFile} + "\n" + + _("Error: %(inst)s") % {'inst': inst}, + _('The %(file_type)s was not backed up.') % {'file_type': mediaFile.displayName} + ) + else: + # recreate folder structure in backup location + # cannot do os.makedirs(backupPath) - it can give bad results when using external drives + # we know backupDir exists + # all the components of subfolder may not + folders = mediaFile.downloadSubfolder.split(os.path.sep) + folderToMake = backupDir + for f in folders: + if f: + folderToMake = os.path.join(folderToMake, f) + if not os.path.isdir(folderToMake): + try: + os.mkdir(folderToMake) + pathExists = True + except (IOError, OSError), (errno, strerror): + fileNotBackedUpMessageDisplayed = True + inst = "%s: %s" % (errno, strerror) + mediaFile.problem.add_problem(None, pn.BACKUP_DIRECTORY_CREATION, volume) + mediaFile.problem.add_extra_detail('%s%s' % (pn.BACKUP_DIRECTORY_CREATION, volume), inst) + error_encountered = True + logError(config.SERIOUS_ERROR, _('Backing up error'), + _("Destination directory could not be created: %(directory)s\n") % + {'directory': backupPath, } + + _("Source: %(source)s\nDestination: %(destination)s") % + {'source': mediaFile.fullFileName, 'destination': newBackupFile} + "\n" + + _("Error: %(errno)s %(strerror)s") % {'errno': errno, 'strerror': strerror}, + _('The %(file_type)s was not backed up.') % {'file_type': mediaFile.displayName} + ) + + break if pathExists: - shutil.copy2(fileToCopy, newBackupFile) - backed_up = True - - except (IOError, OSError), (errno, strerror): - fileNotBackedUpMessageDisplayed = True - logError(config.SERIOUS_ERROR, _('Backing up error'), - _("Source: %(source)s\nDestination: %(destination)s\nError: %(errno)s %(strerror)s") - % {'source': originalFile, 'destination': newBackupFile, 'errno': errno, 'strerror': strerror}, - _('The %(file_type)s was not backed up.') % {'file_type': fileBeingDownloadedDisplay} - ) + if using_gio: + g_dest = gio.File(path=newBackupFile) + g_src = gio.File(path=fileToCopy) + if self.prefs.backup_duplicate_overwrite: + flags = gio.FILE_COPY_OVERWRITE + else: + flags = gio.FILE_COPY_NONE + try: + if not g_src.copy(g_dest, progress_callback, flags, cancellable=gio.Cancellable()): + fileNotBackedUpMessageDisplayed = True + mediaFile.problem.add_problem(None, pn.BACKUP_ERROR, volume) + error_encountered = True + else: + backed_up = True + if mediaFile.status == STATUS_DOWNLOAD_FAILED: + mediaFile.problem.add_problem(None, pn.NO_DOWNLOAD_WAS_BACKED_UP, volume) + except glib.GError, inst: + fileNotBackedUpMessageDisplayed = True + mediaFile.problem.add_problem(None, pn.BACKUP_ERROR, volume) + mediaFile.problem.add_extra_detail('%s%s' % (pn.BACKUP_ERROR, volume), inst) + error_encountered = True + logError(config.SERIOUS_ERROR, _('Backing up error'), + _("Source: %(source)s\nDestination: %(destination)s") % + {'source': fileToCopy, 'destination': newBackupFile} + "\n" + + _("Error: %(inst)s") % {'inst': inst}, + _('The %(file_type)s was not backed up.') % {'file_type': mediaFile.displayName} + ) + else: + try: + shutil.copy2(fileToCopy, newBackupFile) + backed_up = True + if mediaFile.status == STATUS_DOWNLOAD_FAILED: + mediaFile.problem.add_problem(None, pn.NO_DOWNLOAD_WAS_BACKED_UP, volume) + + except (IOError, OSError), (errno, strerror): + fileNotBackedUpMessageDisplayed = True + mediaFile.problem.add_problem(None, pn.BACKUP_ERROR, volume) + inst = "%s: %s" % (errno, strerror) + mediaFile.problem.add_extra_detail('%s%s' % (pn.BACKUP_ERROR, volume), inst) + error_encountered = True + logError(config.SERIOUS_ERROR, _('Backing up error'), + _("Source: %(source)s\nDestination: %(destination)s") % + {'source': fileToCopy, 'destination': newBackupFile} + "\n" + + _("Error: %(errno)s %(strerror)s") % {'errno': errno, 'strerror': strerror}, + _('The %(file_type)s was not backed up.') % {'file_type': mediaFile.displayName} + ) + + #update record keeping using in tracking progress + self.sizeDownloaded += mediaFile.size + self.bytes_downloaded_in_backup += self.bytes_downloaded if not backed_up and not fileNotBackedUpMessageDisplayed: # The file has not been backed up to any medium + mediaFile.problem.add_problem(None, pn.NO_BACKUP_PERFORMED, {'filetype': mediaFile.displayNameCap}) + severity = config.SERIOUS_ERROR - problem = _("%(file_type)s could not be backed up") % {'file_type': fileBeingDownloadedDisplayCap} - details = _("Source: %(source)s") % {'source': originalFile} + problem = _("%(file_type)s could not be backed up") % {'file_type': mediaFile.displayName} + details = _("Source: %(source)s") % {'source': mediaFile.fullFileName} if self.prefs.backup_device_autodetection: resolution = _("No suitable backup volume was found") else: resolution = _("A backup location was not found") logError(severity, problem, details, resolution) - - return backed_up - def notifyAndUnmount(): - if not self.cardMedia.volume: - unmountMessage = "" - notificationName = PROGRAM_NAME - else: - notificationName = self.cardMedia.volume.get_name() - if self.prefs.auto_unmount: - self.cardMedia.volume.unmount(self.on_volume_unmount) - # This message informs the user that the device (e.g. camera, hard drive or memory card) was automatically unmounted and they can now remove it - unmountMessage = _("The device can now be safely removed") - else: - unmountMessage = "" - - file_types = file_types_by_number(noImagesDownloaded, noVideosDownloaded) - file_types_skipped = file_types_by_number(noImagesSkipped, noVideosSkipped) - message = _("%(noFiles)s %(filetypes)s downloaded") % {'noFiles':noFilesDownloaded, 'filetypes': file_types} - noFilesSkipped = noImagesSkipped + noVideosSkipped - if noFilesSkipped: - message += "\n" + _("%(noFiles)s %(filetypes)s skipped") % {'noFiles':noFilesSkipped, 'filetypes':file_types_skipped} - - if unmountMessage: - message = "%s\n%s" % (message, unmountMessage) - - if self.noWarnings: - message = "%s\n%s " % (message, self.noWarnings) + _("warnings") - if self.noErrors: - message = "%s\n%s " % (message, self.noErrors) + _("errors") - - n = pynotify.Notification(notificationName, message) + if backed_up and mediaFile.status == STATUS_DOWNLOAD_FAILED: + mediaFile.problem.add_extra_detail(pn.BACKUP_OK_TYPE, mediaFile.displayNameCap) - if self.cardMedia.volume: - icon = self.cardMedia.volume.get_icon_pixbuf(self.parentApp.notification_icon_size) - else: - icon = self.parentApp.application_icon + if not backed_up: + if mediaFile.status == STATUS_DOWNLOAD_FAILED: + mediaFile.status = STATUS_DOWNLOAD_AND_BACKUP_FAILED + else: + mediaFile.status = STATUS_BACKUP_PROBLEM + elif error_encountered: + # it was backed up to at least one volume, but there was an error on another backup volume + if mediaFile.status != STATUS_DOWNLOAD_FAILED: + mediaFile.status = STATUS_BACKUP_PROBLEM - n.set_icon_from_pixbuf(icon) - n.show() - + # Take into account instances where a backup device has been removed part way through a download + # (thereby making self.parentApp.backupVolumes have less items than expected) + if self.sizeDownloaded < expected_bytes_downloaded: + self.sizeDownloaded = expected_bytes_downloaded + return backed_up - - def getThumbnail(fileMetadata): - thumbnail = orientation = None - if self.isImage: - try: - thumbnail = fileMetadata.getThumbnailData(MAX_THUMBNAIL_SIZE) - if not isinstance(thumbnail, types.StringType): - thumbnail = None - except: - thumbnail = None - - if thumbnail is None: - logError(config.WARNING, _("Photo thumbnail could not be extracted"), fullFileName) - orientation = None - else: - orientation = fileMetadata.orientation(missing=None) - else: - # get thumbnail of video - # it may need to be generated - thumbnail = fileMetadata.getThumbnailData(MAX_THUMBNAIL_SIZE, tempWorkingDir) - if thumbnail: - orientation = 1 - return thumbnail, orientation - - def createTempDir(baseDir): - """ - Create a temporary directory in which to download the photos to. - - Returns the directory if it was created, else returns None. - - Don't want to put it in system temp folder, as that is likely - to be on another partition and hence copying files from it - to the actual download folder will be slow!""" - try: - t = tempfile.mkdtemp(prefix='rapid-tmp-', - dir=baseDir) - return t - except OSError, (errno, strerror): - if not self.cardMedia.volume: - image_device = _("Source: %s\n") % self.cardMedia.getPath() - else: - _("Device: %s\n") % self.cardMedia.volume.get_name() - destination = _("Destination: %s") % baseDir - logError(config.CRITICAL_ERROR, _('Could not create temporary download directory'), - image_device + destination, - _("Download cannot proceed")) - cmd_line(_("Error:") + " " + _('Could not create temporary download directory')) - cmd_line(image_device + destination) - cmd_line(_("Download cannot proceed")) - display_queue.put((media_collection_treeview.removeCard, (self.thread_id, ))) - display_queue.put((self.parentApp.downloadFailed, (self.thread_id, ))) - display_queue.close("rw") - self.running = False - self.lock.release() - return None - self.hasStarted = True display_queue.open('w') #Do not try to handle any preference errors here getPrefs(False) - if not scanMedia(): + #Check photo and video download path, create if necessary + photoBaseDownloadDir = self.prefs.download_folder + if not checkDownloadPath(photoBaseDownloadDir): + return # cleanup already done + + if DOWNLOAD_VIDEO: + videoBaseDownloadDir = self.prefs.video_download_folder + if not checkDownloadPath(videoBaseDownloadDir): + return + else: + videoBaseDownloadDir = self.videoTempWorkingDir = None + + if not createBothTempDirs(): + return + + s = scanMedia() + if s is None: + if not self.ctrl: + self.running = False + display_queue.put((media_collection_treeview.removeCard, (self.thread_id, ))) + display_queue.close("rw") + return + else: + sys.stderr.write("FIXME: scan returned None, but the thread is not meant to be exiting\n") + if not s: cmd_line(_("This device has no %(types_searched_for)s to download from.") % {'types_searched_for': self.types_searched_for}) display_queue.put((self.parentApp.downloadFailed, (self.thread_id, ))) display_queue.close("rw") self.running = False - return - elif self.autoStart and need_job_code: - if job_code == None: - self.waitingForJobCode = True - display_queue.put((self.parentApp.getJobCode, ())) - self.running = False - self.lock.acquire() - self.running = True - self.waitingForJobCode = False - elif not self.autoStart: + return + + if self.scanResultsStale or self.scanResultsStaleDownloadFolder: + display_queue.put((self.parentApp.regenerateScannedDevices, (self.thread_id, ))) + all_files_downloaded = False + + totalNonErrorFiles = self.cardMedia.numberOfFilesNotCannotDownload() + + if not self.autoStart: # halt thread, waiting to be restarted so download proceeds + self.cleanUp() self.running = False self.lock.acquire() @@ -2425,233 +2729,229 @@ class CopyPhotos(Thread): return self.running = True - - if not getPrefs(True): - self.running = False - display_queue.close("rw") - return - - - self.downloadStarted = True - cmd_line(_("Download has started from %s") % self.cardMedia.prettyName(limit=0)) - - #check for presence of backup path or volumes - if self.prefs.backup_images: - can_backup = True - if self.prefs.backup_missing == config.REPORT_ERROR: - e = config.SERIOUS_ERROR - elif self.prefs.backup_missing == config.REPORT_WARNING: - e = config.WARNING - if not self.prefs.backup_device_autodetection: - if not os.path.isdir(self.prefs.backup_location): - # the user has manually specified a path, but it - # does not exist. This is a problem. - try: - os.makedirs(self.prefs.backup_location) - except: - if self.prefs.backup_missing <> config.IGNORE: - logError(e, _("Backup path does not exist"), - _("The path %s could not be created") % path, - _("No backups can occur") - ) - can_backup = False - - elif self.prefs.backup_missing <> config.IGNORE: - if not len(self.parentApp.backupVolumes): - logError(e, _("Backup device missing"), - _("No backup device was automatically detected"), - _("No backups can occur")) - can_backup = False - - if need_job_code and job_code == None: - sys.stderr.write(str(self.thread_id ) + ": job code should never be None\n") - self.imageRenamePrefsFactory.setJobCode('unknown-job-code') - self.subfolderPrefsFactory.setJobCode('unknown-job-code') - else: - self.imageRenamePrefsFactory.setJobCode(job_code) - self.videoRenamePrefsFactory.setJobCode(job_code) - self.subfolderPrefsFactory.setJobCode(job_code) - self.videoSubfolderPrefsFactory.setJobCode(job_code) - - # Some photos may not have metadata (this - # is unlikely for photos straight out of a - # camera, but it is possible for photos that have been edited). If - # only non-dynamic components make up the rest of an image name - # (e.g. text specified by the user), then relying on metadata will - # likely produce duplicate names. - - needMetaDataToCreateUniqueImageName = self.imageRenamePrefsFactory.needImageMetaDataToCreateUniqueName() - - # subfolder generation also need to be examined, but here the need is - # not so exacting, since subfolders contain photos, and naturally the - # requirement to be unique is far more relaxed. However if subfolder - # generation relies entirely on metadata, that is a problem worth - # looking for - needMetaDataToCreateUniqueSubfolderName = self.subfolderPrefsFactory.needMetaDataToCreateUniqueName() - - i = 0 - sizeDownloaded = noFilesDownloaded = noImagesDownloaded = noVideosDownloaded = noImagesSkipped = noVideosSkipped = 0 - filesDownloadedSuccessfully = [] - - sizeFiles = self.cardMedia.sizeOfImagesAndVideos(humanReadable = False) - display_queue.put((self.parentApp.addToTotalDownloadSize, (sizeFiles, ))) - display_queue.put((self.parentApp.setOverallDownloadMark, ())) - display_queue.put((self.parentApp.postStartDownloadTasks, ())) - - sizeFiles = float(sizeFiles) - noFiles = self.cardMedia.numberOfImagesAndVideos() - - if self.noImages > 0: - photoBaseDownloadDir = self.prefs.download_folder - if not checkDownloadPath(photoBaseDownloadDir): + if not createBothTempDirs(): return - photoTempWorkingDir = createTempDir(photoBaseDownloadDir) - if not photoTempWorkingDir: - return - else: - photoBaseDownloadDir = photoTempWorkingDir = None - if DOWNLOAD_VIDEO and self.noVideos > 0: - videoBaseDownloadDir = self.prefs.video_download_folder - if not checkDownloadPath(videoBaseDownloadDir): - return - videoTempWorkingDir = createTempDir(videoBaseDownloadDir) - if not videoTempWorkingDir: - return + else: - videoBaseDownloadDir = videoTempWorkingDir = None - - addUniqueIdentifier = self.prefs.download_conflict_resolution == config.ADD_UNIQUE_IDENTIFIER - usesImageSequenceElements = self.imageRenamePrefsFactory.usesSequenceElements() - usesVideoSequenceElements = self.videoRenamePrefsFactory.usesSequenceElements() - usesSequenceElements = usesVideoSequenceElements or usesImageSequenceElements - - usesStoredSequenceNo = (self.imageRenamePrefsFactory.usesTheSequenceElement(rn.STORED_SEQ_NUMBER) or - self.videoRenamePrefsFactory.usesTheSequenceElement(rn.STORED_SEQ_NUMBER)) - sequences.setUseOfSequenceElements( - self.imageRenamePrefsFactory.usesTheSequenceElement(rn.SESSION_SEQ_NUMBER), - self.imageRenamePrefsFactory.usesTheSequenceElement(rn.SEQUENCE_LETTER)) - + if need_job_code_for_renaming: + if checkIfNeedAJobCode(): + if job_code == None: + self.cleanUp() + self.waitingForJobCode = True + display_queue.put((self.parentApp.getJobCode, ())) + self.running = False + self.lock.acquire() + + if not self.ctrl: + # thread is exiting + display_queue.close("rw") + return - while i < noFiles: - if not self.running: + self.running = True + self.waitingForJobCode = False + if not createBothTempDirs(): + return + else: + # User has entered a job code, and it's in the global variable + # Assign it to all those files that do not have one + display_queue.put((self.parentApp.selection_vbox.selection_treeview.apply_job_code, (job_code, False, True, self.thread_id))) + + # auto start could be false if the user hit cancel when prompted for a job code + if self.autoStart: + # set all in this thread to download pending + display_queue.put((self.parentApp.selection_vbox.selection_treeview.set_status_to_download_pending, (False, self.thread_id))) + # wait until all the files have had their status set to download pending, and once that is done, restart + self.running = False self.lock.acquire() self.running = True + + while not all_files_downloaded: - if not self.ctrl: - self.running = False - cleanUp() - display_queue.close("rw") - return + self.noErrors = self.noWarnings = 0 - # get information about the image to deduce image name and path - name, root, size, modificationTime = self.cardMedia.imagesAndVideos[i] - fullFileName = os.path.join(root, name) - - self.isImage = media.isImage(name) - if self.isImage: - fileBeingDownloadedDisplay = _('photo') - fileBeingDownloadedDisplayCap = _('Photo') - fileSkippedDisplay = _("Photo skipped") - fileAlreadyExistsDisplay = _("Photo already exists") - fallback_date = None - tempWorkingDir = photoTempWorkingDir - baseDownloadDir = photoBaseDownloadDir - else: - fileBeingDownloadedDisplay = _('video') - fileBeingDownloadedDisplayCap = _('Video') - fileSkippedDisplay = _("Video skipped") - fileAlreadyExistsDisplay = _("Video already exists") - fallback_date = modificationTime - tempWorkingDir = videoTempWorkingDir - baseDownloadDir = videoBaseDownloadDir - - skipFile, fileMetadata, newName, newFile, path, subfolder, sequence_to_use = generateSubfolderAndFileName( - fullFileName, name, needMetaDataToCreateUniqueImageName, - needMetaDataToCreateUniqueSubfolderName, fallback_date) + if not getPrefs(True): + self.running = False + display_queue.close("rw") + return + + self.downloadStarted = True + cmd_line(_("Download has started from %s") % self.cardMedia.prettyName(limit=0)) + + noFiles, sizeFiles, fileIndex = self.cardMedia.sizeAndNumberDownloadPending() + cmd_line(_("Attempting to download %s files") % noFiles) + + + no_backup_devices = setupBackup() - if skipFile: - if self.isImage: - noImagesSkipped += 1 - else: - noVideosSkipped += 1 - else: - fileDownloaded, newName, newFile = downloadFile(path, newFile, newName, name, fullFileName, - fileMetadata, subfolder, sequence_to_use, fallback_date) + # include the time it takes to copy to the backup volumes + sizeFiles = sizeFiles * (no_backup_devices + 1) + + display_queue.put((self.parentApp.timeRemaining.set, (self.thread_id, sizeFiles))) + + i = 0 + self.sizeDownloaded = noFilesDownloaded = noImagesDownloaded = noVideosDownloaded = noImagesSkipped = noVideosSkipped = 0 + filesDownloadedSuccessfully = [] + self.bytes_downloaded_in_backup = 0 + + display_queue.put((self.parentApp.addToTotalDownloadSize, (sizeFiles, ))) + display_queue.put((self.parentApp.setOverallDownloadMark, ())) + display_queue.put((self.parentApp.postStartDownloadTasks, ())) + + sizeFiles = float(sizeFiles) - if self.prefs.backup_images: - if can_backup: - backed_up = backupFile(subfolder, newName, fileDownloaded, newFile, fullFileName) + addUniqueIdentifier = self.prefs.download_conflict_resolution == config.ADD_UNIQUE_IDENTIFIER + usesImageSequenceElements = self.imageRenamePrefsFactory.usesSequenceElements() + usesVideoSequenceElements = self.videoRenamePrefsFactory.usesSequenceElements() + usesSequenceElements = usesVideoSequenceElements or usesImageSequenceElements + + usesStoredSequenceNo = (self.imageRenamePrefsFactory.usesTheSequenceElement(rn.STORED_SEQ_NUMBER) or + self.videoRenamePrefsFactory.usesTheSequenceElement(rn.STORED_SEQ_NUMBER)) + sequences.setUseOfSequenceElements( + self.imageRenamePrefsFactory.usesTheSequenceElement(rn.SESSION_SEQ_NUMBER), + self.imageRenamePrefsFactory.usesTheSequenceElement(rn.SEQUENCE_LETTER)) + + # reset the progress bar to update the status of this download attempt + progressBarText = _("%(number)s of %(total)s %(filetypes)s") % {'number': 0, 'total': noFiles, 'filetypes':self.display_file_types} + display_queue.put((media_collection_treeview.updateProgress, (self.thread_id, 0.0, progressBarText, 0))) + + while i < noFiles: + # if the user pauses the download, then this will be triggered + if not self.running: + self.lock.acquire() + self.running = True + + if not self.ctrl: + self.running = False + self.cleanUp() + display_queue.close("rw") + return + + # get information about the image to deduce image name and path + mediaFile = self.cardMedia.imagesAndVideos[fileIndex[i]][0] + if not mediaFile.status == STATUS_DOWNLOAD_PENDING: + sys.stderr.write("FIXME: Thread %s is trying to download a file that it should not be!!" % self.thread_id) + else: + self.bytes_downloaded_in_download = self.bytes_downloaded_in_backup = self.bytes_downloaded = 0 + if mediaFile.isImage: + tempWorkingDir = self.photoTempWorkingDir + baseDownloadDir = photoBaseDownloadDir else: - backed_up = False + tempWorkingDir = self.videoTempWorkingDir + baseDownloadDir = videoBaseDownloadDir + + skipFile, sequence_to_use = generateSubfolderAndFileName(mediaFile) - if fileDownloaded: - noFilesDownloaded += 1 - if self.isImage: - noImagesDownloaded += 1 + if skipFile: + if mediaFile.isImage: + noImagesSkipped += 1 + else: + noVideosSkipped += 1 else: - noVideosDownloaded += 1 - if self.prefs.backup_images and backed_up: - filesDownloadedSuccessfully.append(fullFileName) - elif not self.prefs.backup_images: - filesDownloadedSuccessfully.append(fullFileName) + fileDownloaded = downloadFile(mediaFile, sequence_to_use) + + if self.prefs.backup_images: + backed_up = backupFile(mediaFile, fileDownloaded, no_backup_devices) + + if fileDownloaded: + noFilesDownloaded += 1 + if mediaFile.isImage: + noImagesDownloaded += 1 + else: + noVideosDownloaded += 1 + if self.prefs.backup_images and backed_up: + filesDownloadedSuccessfully.append(mediaFile.fullFileName) + elif not self.prefs.backup_images: + filesDownloadedSuccessfully.append(mediaFile.fullFileName) + else: + if mediaFile.isImage: + noImagesSkipped += 1 + else: + noVideosSkipped += 1 + + #update the selction treeview in the main window with the new status of the file + display_queue.put((self.parentApp.update_status_post_download, (mediaFile.treerowref, ))) + + percentComplete = (float(self.sizeDownloaded) / sizeFiles) * 100 + + if self.sizeDownloaded == sizeFiles and (totalNonErrorFiles - noFiles): + progressBarText = _("%(number)s of %(total)s %(filetypes)s (%(remaining)s remaining)") % { + 'number': i + 1, 'total': noFiles, 'filetypes':self.display_file_types, + 'remaining': totalNonErrorFiles - noFiles} else: - if self.isImage: - noImagesSkipped += 1 - else: - noVideosSkipped += 1 + progressBarText = _("%(number)s of %(total)s %(filetypes)s") % {'number': i + 1, 'total': noFiles, 'filetypes':self.display_file_types} - thumbnail, orientation = getThumbnail(fileMetadata) - - display_queue.put((thumbnail_hbox.addImage, (self.thread_id, thumbnail, orientation, fullFileName, fileDownloaded, self.isImage))) + if using_gio: + # do not want to update the progress bar any more than it has already been updated + size = mediaFile.size * (no_backup_devices + 1) - self.bytes_downloaded_in_download - self.bytes_downloaded_in_backup + else: + size = mediaFile.size * (no_backup_devices + 1) + display_queue.put((media_collection_treeview.updateProgress, (self.thread_id, percentComplete, progressBarText, size))) + + i += 1 - sizeDownloaded += size - percentComplete = (sizeDownloaded / sizeFiles) * 100 - if sizeDownloaded == sizeFiles: - self.downloadComplete = True - progressBarText = _("%(number)s of %(total)s %(filetypes)s") % {'number': i + 1, 'total': noFiles, 'filetypes':self.display_file_types} - display_queue.put((media_collection_treeview.updateProgress, (self.thread_id, percentComplete, progressBarText, size))) + with self.statsLock: + self.downloadStats.adjust(self.sizeDownloaded, noImagesDownloaded, noVideosDownloaded, noImagesSkipped, noVideosSkipped, self.noWarnings, self.noErrors) + + if self.prefs.auto_delete: + j = 0 + for imageOrVideo in filesDownloadedSuccessfully: + try: + os.unlink(imageOrVideo) + j += 1 + except OSError, (errno, strerror): + logError(config.SERIOUS_ERROR, _("Could not delete photo or video from device"), + _("Photo: %(source)s\nError: %(errno)s %(strerror)s") + % {'source': image, 'errno': errno, 'strerror': strerror}) + except: + logError(config.SERIOUS_ERROR, _("Could not delete photo or video from device"), + _("Photo: %(source)s")) + + cmd_line(_("Deleted %(number)i %(filetypes)s from device") % {'number':j, 'filetypes':self.display_file_types}) + + totalNonErrorFiles = totalNonErrorFiles - noFiles + if totalNonErrorFiles == 0: + all_files_downloaded = True + + # must manually delete these variables, or else the media cannot be unmounted (bug in some versions of pyexiv2 / exiv2) + # for some reason directories on the device remain open with read only access, even after these steps - I don't know why + del self.subfolderPrefsFactory, self.imageRenamePrefsFactory, self.videoSubfolderPrefsFactory, self.videoRenamePrefsFactory + for i in self.cardMedia.imagesAndVideos: + i[0].metadata = None + + notifyAndUnmount(umountAttemptOK = all_files_downloaded) + cmd_line(_("Download complete from %s") % self.cardMedia.prettyName(limit=0)) + display_queue.put((self.parentApp.notifyUserAllDownloadsComplete,())) + display_queue.put((self.parentApp.resetSequences,())) - i += 1 + if all_files_downloaded: + self.downloadComplete = True + else: + self.cleanUp() + self.downloadStarted = False + self.running = False + self.lock.acquire() + if not self.ctrl: + # thread will restart at this point, when the program is exiting + # so must exit if self.ctrl indicates this - with self.statsLock: - self.downloadStats.adjust(sizeDownloaded, noImagesDownloaded, noVideosDownloaded, noImagesSkipped, noVideosSkipped, self.noWarnings, self.noErrors) - - if self.prefs.auto_delete: - j = 0 - for imageOrVideo in filesDownloadedSuccessfully: - try: - os.unlink(imageOrVideo) - j += 1 - except OSError, (errno, strerror): - logError(config.SERIOUS_ERROR, _("Could not delete photo or video from device"), - _("Photo: %(source)s\nError: %(errno)s %(strerror)s") - % {'source': image, 'errno': errno, 'strerror': strerror}) - except: - logError(config.SERIOUS_ERROR, _("Could not delete photo or video from device"), - _("Photo: %(source)s")) - - cmd_line(_("Deleted %(number)i %(filetypes)s from device") % {'number':j, 'filetypes':self.display_file_types}) + self.running = False + display_queue.close("rw") + return + self.running = True + if not createBothTempDirs(): + return - # must manually delete these variables, or else the media cannot be unmounted (bug in some versions of pyexiv2 / exiv2) - del self.subfolderPrefsFactory, self.imageRenamePrefsFactory - try: - del fileMetadata - except: - pass - - notifyAndUnmount() - cmd_line(_("Download complete from %s") % self.cardMedia.prettyName(limit=0)) - display_queue.put((self.parentApp.notifyUserAllDownloadsComplete,())) - display_queue.put((self.parentApp.resetSequences,())) - cleanUp() display_queue.put((self.parentApp.exitOnDownloadComplete, ())) display_queue.close("rw") - + + self.cleanUp() + self.running = False if noFiles: self.lock.release() + def startStop(self): if self.isAlive(): if self.running: @@ -2663,6 +2963,21 @@ class CopyPhotos(Thread): except thread_error: sys.stderr.write(str(self.thread_id) + " thread error\n") + def cleanUp(self): + """ + Deletes temporary files and folders + """ + + for tempWorkingDir in (self.videoTempWorkingDir, self.photoTempWorkingDir): + if tempWorkingDir: + # possibly delete any lingering files + if os.path.isdir(tempWorkingDir): + tf = os.listdir(tempWorkingDir) + if tf: + for f in tf: + os.remove(os.path.join(tempWorkingDir, f)) + os.rmdir(tempWorkingDir) + def quit(self): """ Quits the thread @@ -2675,6 +2990,9 @@ class CopyPhotos(Thread): Completed (not alive, nothing to do) """ + # cleanup any temporary directories and files + self.cleanUp() + if self.hasStarted: if self.isAlive(): self.ctrl = False @@ -2697,15 +3015,15 @@ class CopyPhotos(Thread): class MediaTreeView(gtk.TreeView): """ - TreeView display of memory cards and associated copying progress. + TreeView display of devices and associated copying progress. Assumes a threaded environment. """ def __init__(self, parentApp): self.parentApp = parentApp - # card name, size of images, number of images, copy progress, copy text - self.liststore = gtk.ListStore(str, str, int, float, str) + # device name, size of images on the device (human readable), copy progress (%), copy text + self.liststore = gtk.ListStore(str, str, float, str) self.mapThreadToRow = {} gtk.TreeView.__init__(self, self.liststore) @@ -2725,16 +3043,14 @@ class MediaTreeView(gtk.TreeView): self.append_column(column1) column2 = gtk.TreeViewColumn(_("Download Progress"), - gtk.CellRendererProgress(), value=3, text=4) + gtk.CellRendererProgress(), value=2, text=3) self.append_column(column2) self.show_all() - def addCard(self, thread_id, cardName, sizeFiles, noFiles, progress = 0.0, - progressBarText = ''): + def addCard(self, thread_id, cardName, sizeFiles, progress = 0.0, progressBarText = ''): # add the row, and get a temporary pointer to the row - iter = self.liststore.append((cardName, sizeFiles, noFiles, - progress, progressBarText)) + iter = self.liststore.append((cardName, sizeFiles, progress, progressBarText)) self._setThreadMap(thread_id, iter) @@ -2747,11 +3063,13 @@ class MediaTreeView(gtk.TreeView): self.parentApp.media_collection_scrolledwindow.set_size_request(-1, height) - def updateCard(self, thread_id, sizeFiles, noFiles): + def updateCard(self, thread_id, totalSizeFiles): + """ + Updates the size of the photos and videos on the device, displayed to the user + """ if thread_id in self.mapThreadToRow: iter = self._getThreadMap(thread_id) - self.liststore.set_value(iter, 1, sizeFiles) - self.liststore.set_value(iter, 2, noFiles) + self.liststore.set_value(iter, 1, totalSizeFiles) else: sys.stderr.write("FIXME: this card is unknown") @@ -2777,19 +3095,23 @@ class MediaTreeView(gtk.TreeView): return the tree iter for this thread """ - treerowRef = self.mapThreadToRow[thread_id] - path = treerowRef.get_path() - iter = self.liststore.get_iter(path) - return iter + if thread_id in self.mapThreadToRow: + treerowRef = self.mapThreadToRow[thread_id] + path = treerowRef.get_path() + iter = self.liststore.get_iter(path) + return iter + else: + return None - def updateProgress(self, thread_id, percentComplete, progressBarText, imageSize): + def updateProgress(self, thread_id, percentComplete, progressBarText, bytesDownloaded): iter = self._getThreadMap(thread_id) - - self.liststore.set_value(iter, 3, percentComplete) - self.liststore.set_value(iter, 4, progressBarText) - if percentComplete or imageSize: - self.parentApp.updateOverallProgress(thread_id, imageSize, percentComplete) + if iter: + self.liststore.set_value(iter, 2, percentComplete) + if progressBarText: + self.liststore.set_value(iter, 3, progressBarText) + if percentComplete or bytesDownloaded: + self.parentApp.updateOverallProgress(thread_id, bytesDownloaded, percentComplete) def rowHeight(self): @@ -2799,90 +3121,69 @@ class MediaTreeView(gtk.TreeView): index = self.mapThreadToRow.keys()[0] path = self.mapThreadToRow[index].get_path() col = self.get_column(0) - return self.get_background_area(path, col)[3] + return self.get_background_area(path, col)[3] + 1 -class ThumbnailHBox(gtk.HBox): - """ - Displays thumbnails of the images being downloaded - """ - - def __init__(self, parentApp): - gtk.HBox.__init__(self) - self.parentApp = parentApp - self.padding = hd.CONTROL_IN_TABLE_SPACE / 2 - #create image used to lighten thumbnails - self.white = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, width=MAX_THUMBNAIL_SIZE, height=MAX_THUMBNAIL_SIZE) - #fill with white - self.white.fill(0xffffffff) - - #load missing image - self.missingThumbnail = gtk.gdk.pixbuf_new_from_file_at_size(paths.share_dir('glade3/image-missing.svg'), MAX_THUMBNAIL_SIZE, MAX_THUMBNAIL_SIZE) - self.videoThumbnail = gtk.gdk.pixbuf_new_from_file_at_size(paths.share_dir('glade3/video.svg'), MAX_THUMBNAIL_SIZE, MAX_THUMBNAIL_SIZE) +class ShowWarningDialog(gtk.Dialog): + """ + Displays a warning to the user that downloading directly from a + camera does not always work well + """ + def __init__(self, parent_window, postChoiceCB): + gtk.Dialog.__init__(self, _("Downloading From Cameras"), None, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_OK, gtk.RESPONSE_OK)) + + self.postChoiceCB = postChoiceCB - def addImage(self, thread_id, thumbnail, orientation, filename, fileDownloaded, isImage): - """ - Add thumbnail + primary_msg = _("Downloading directly from a camera may work poorly or not at all") + secondary_msg = _("Downloading from a card reader always works and is generally much faster. It is strongly recommended to use a card reader.") - Orientation indicates if the thumbnail needs to be rotated or not. - """ + self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader.svg')) + + primary_label = gtk.Label() + primary_label.set_markup("<b>%s</b>" % primary_msg) + primary_label.set_line_wrap(True) + primary_label.set_alignment(0, 0.5) + + secondary_label = gtk.Label() + secondary_label.set_text(secondary_msg) + secondary_label.set_line_wrap(True) + secondary_label.set_alignment(0, 0.5) + + self.show_again_checkbutton = gtk.CheckButton(_('_Show this message again'), True) + self.show_again_checkbutton.set_active(True) - if isImage: - if not thumbnail: - pixbuf = self.missingThumbnail - else: - try: - pbloader = gdk.PixbufLoader() - pbloader.write(thumbnail) - pbloader.close() - # Get the resulting pixbuf and build an image to be displayed - pixbuf = pbloader.get_pixbuf() - except: - log_dialog.addMessage(thread_id, config.WARNING, - _("Photo thumbnail could not be extracted"), filename, - _('It may be corrupted')) - pbloader = None - pixbuf = self.missingThumbnail - else: - # the file downloaded is a video, not a photo or image - # if thumbnail is passed in, it is already in pixbuf format - if thumbnail: - pixbuf = thumbnail - else: - pixbuf = self.videoThumbnail - - if not pixbuf: - # get_pixbuf() can return None if not could not render the image - log_dialog.addMessage(thread_id, config.WARNING, - _("Photo thumbnail could not be extracted"), filename, - _('It may be corrupted')) - pixbuf = self.missingThumbnail - else: - # rotate if necessary - if orientation == 8: - pixbuf = pixbuf.rotate_simple(gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE) - elif orientation == 6: - pixbuf = pixbuf.rotate_simple(gdk.PIXBUF_ROTATE_CLOCKWISE) - elif orientation == 3: - pixbuf = pixbuf.rotate_simple(gdk.PIXBUF_ROTATE_UPSIDEDOWN) - - # scale to size - pixbuf = common.scale2pixbuf(MAX_THUMBNAIL_SIZE, MAX_THUMBNAIL_SIZE, pixbuf) - if not fileDownloaded: - # lighten it - self.white.composite(pixbuf, 0, 0, pixbuf.props.width, pixbuf.props.height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 180) + msg_vbox = gtk.VBox() + msg_vbox.pack_start(primary_label, False, False, padding=6) + msg_vbox.pack_start(secondary_label, False, False, padding=6) + msg_vbox.pack_start(self.show_again_checkbutton) + icon = parent_window.render_icon(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) image = gtk.Image() - image.set_from_pixbuf(pixbuf) + image.set_from_pixbuf(icon) + image.set_alignment(0, 0) + + warning_hbox = gtk.HBox() + warning_hbox.pack_start(image, False, False, padding = 12) + warning_hbox.pack_start(msg_vbox, False, False, padding = 12) + + self.vbox.pack_start(warning_hbox, padding=6) + + self.set_border_width(6) + self.set_has_separator(False) - self.pack_start(image, expand=False, padding=self.padding) - image.show() + self.set_default_response(gtk.RESPONSE_OK) + + self.set_transient_for(parent_window) + self.show_all() - # move viewport to display the latest image - adjustment = self.parentApp.image_scrolledwindow.get_hadjustment() - adjustment.set_value(adjustment.upper) - + self.connect('response', self.on_response) + def on_response(self, device_dialog, response): + show_again = self.show_again_checkbutton.get_active() + self.postChoiceCB(self, show_again) + class UseDeviceDialog(gtk.Dialog): def __init__(self, parent_window, path, volume, autostart, postChoiceCB): gtk.Dialog.__init__(self, _('Device Detected'), None, @@ -2892,7 +3193,7 @@ class UseDeviceDialog(gtk.Dialog): self.postChoiceCB = postChoiceCB - self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader-about.png')) + self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader.svg')) # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#usedeviceprompt prompt_label = gtk.Label(_('Should this device or partition be used to download photos or videos from?')) prompt_label.set_line_wrap(True) @@ -2972,7 +3273,7 @@ class RemoveAllJobCodeDialog(gtk.Dialog): gtk.STOCK_YES, gtk.RESPONSE_OK)) self.postChoiceCB = postChoiceCB - self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader-about.png')) + self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader.svg')) prompt_hbox = gtk.HBox() @@ -3009,7 +3310,7 @@ class RemoveAllJobCodeDialog(gtk.Dialog): class JobCodeDialog(gtk.Dialog): """ Dialog prompting for a job code""" - def __init__(self, parent_window, job_codes, default_job_code, postJobCodeEntryCB, autoStart, entryOnly): + def __init__(self, parent_window, job_codes, default_job_code, postJobCodeEntryCB, autoStart, downloadSelected, entryOnly): # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#jobcode gtk.Dialog.__init__(self, _('Enter a Job Code'), None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, @@ -3017,9 +3318,10 @@ class JobCodeDialog(gtk.Dialog): gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader-about.png')) + self.set_icon_from_file(paths.share_dir('glade3/rapid-photo-downloader.svg')) self.postJobCodeEntryCB = postJobCodeEntryCB self.autoStart = autoStart + self.downloadSelected = downloadSelected self.combobox = gtk.combo_box_entry_new_text() for text in job_codes: @@ -3029,10 +3331,10 @@ class JobCodeDialog(gtk.Dialog): if len(job_codes) and not entryOnly: # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#jobcode - task_label = gtk.Label(_('Enter a new job code, or select a previous one.')) + task_label = gtk.Label(_('Enter a new Job Code, or select a previous one')) else: # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#jobcode - task_label = gtk.Label(_('Enter a new job code.')) + task_label = gtk.Label(_('Enter a new Job Code')) task_label.set_line_wrap(True) task_hbox = gtk.HBox() task_hbox.pack_start(task_label, False, False, padding=6) @@ -3071,7 +3373,7 @@ class JobCodeDialog(gtk.Dialog): def match_func(self, completion, key, iter): model = completion.get_model() - return model[iter][0].startswith(self.entry.get_text()) + return model[iter][0].lower().startswith(self.entry.get_text().lower()) def on_completion_match(self, completion, model, iter): self.entry.set_text(model[iter][0]) @@ -3087,8 +3389,1157 @@ class JobCodeDialog(gtk.Dialog): cmd_line(_("Job Code entered")) else: cmd_line(_("Job Code not entered")) - self.postJobCodeEntryCB(self, userChoseCode, self.get_job_code(), self.autoStart) + self.postJobCodeEntryCB(self, userChoseCode, self.get_job_code(), self.autoStart, self.downloadSelected) + + + +class SelectionTreeView(gtk.TreeView): + """ + TreeView display of photos and videos available for download + + Assumes a threaded environment. + """ + def __init__(self, parentApp): + + self.parentApp = parentApp + self.rapidApp = parentApp.parentApp + + self.liststore = gtk.ListStore( + gtk.gdk.Pixbuf, # 0 thumbnail icon + str, # 1 name (for sorting) + int, # 2 timestamp (for sorting), float converted into an int + str, # 3 date (human readable) + int, # 4 size (for sorting) + str, # 5 size (human readable) + int, # 6 isImage (for sorting) + gtk.gdk.Pixbuf, # 7 type (photo or video) + str, # 8 job code + gobject.TYPE_PYOBJECT, # 9 mediaFile (for data) + gtk.gdk.Pixbuf, # 10 status icon + int, # 11 status (downloaded, cannot download, etc, for sorting) + str, # 12 path (on the device) + str, # 13 device + int) # 14 thread id (worker the file is associated with) + + self.selected_rows = set() + + # sort by date (unless there is a problem) + self.liststore.set_sort_column_id(2, gtk.SORT_ASCENDING) + + gtk.TreeView.__init__(self, self.liststore) + + selection = self.get_selection() + selection.set_mode(gtk.SELECTION_MULTIPLE) + selection.connect('changed', self.on_selection_changed) + + self.set_rubber_banding(True) + + # Status Column + # Indicates whether file was downloaded, or a warning or error of some kind + cell = gtk.CellRendererPixbuf() + cell.set_property("yalign", 0.5) + status_column = gtk.TreeViewColumn(_("Status"), cell, pixbuf=10) + status_column.set_sort_column_id(11) + status_column.connect('clicked', self.header_clicked) + self.append_column(status_column) + + # Type of file column i.e. photo or video (displays at user request) + cell = gtk.CellRendererPixbuf() + cell.set_property("yalign", 0.5) + self.type_column = gtk.TreeViewColumn(_("Type"), cell, pixbuf=7) + self.type_column.set_sort_column_id(6) + self.type_column.set_clickable(True) + self.type_column.connect('clicked', self.header_clicked) + self.append_column(self.type_column) + self.display_type_column(self.rapidApp.prefs.display_type_column) + + #File thumbnail column + if not DOWNLOAD_VIDEO: + title = _("Photo") + else: + title = _("File") + thumbnail_column = gtk.TreeViewColumn(title) + cellpb = gtk.CellRendererPixbuf() + if not DROP_SHADOW: + cellpb.set_fixed_size(60,50) + thumbnail_column.pack_start(cellpb, False) + thumbnail_column.set_attributes(cellpb, pixbuf=0) + thumbnail_column.set_sort_column_id(1) + thumbnail_column.set_clickable(True) + thumbnail_column.connect('clicked', self.header_clicked) + self.append_column(thumbnail_column) + + # Job code column + cell = gtk.CellRendererText() + cell.set_property("yalign", 0) + self.job_code_column = gtk.TreeViewColumn(_("Job Code"), cell, text=8) + self.job_code_column.set_sort_column_id(8) + self.job_code_column.set_resizable(True) + self.job_code_column.set_clickable(True) + self.job_code_column.connect('clicked', self.header_clicked) + self.append_column(self.job_code_column) + + # Date column + cell = gtk.CellRendererText() + cell.set_property("yalign", 0) + date_column = gtk.TreeViewColumn(_("Date"), cell, text=3) + date_column.set_sort_column_id(2) + date_column.set_resizable(True) + date_column.set_clickable(True) + date_column.connect('clicked', self.header_clicked) + self.append_column(date_column) + + # Size column (displays at user request) + cell = gtk.CellRendererText() + cell.set_property("yalign", 0) + self.size_column = gtk.TreeViewColumn(_("Size"), cell, text=5) + self.size_column.set_sort_column_id(4) + self.size_column.set_resizable(True) + self.size_column.set_clickable(True) + self.size_column.connect('clicked', self.header_clicked) + self.append_column(self.size_column) + self.display_size_column(self.rapidApp.prefs.display_size_column) + + # Device column (displays at user request) + cell = gtk.CellRendererText() + cell.set_property("yalign", 0) + self.device_column = gtk.TreeViewColumn(_("Device"), cell, text=13) + self.device_column.set_sort_column_id(13) + self.device_column.set_resizable(True) + self.device_column.set_clickable(True) + self.device_column.connect('clicked', self.header_clicked) + self.append_column(self.device_column) + self.display_device_column(self.rapidApp.prefs.display_device_column) + + # Filename column (displays at user request) + cell = gtk.CellRendererText() + cell.set_property("yalign", 0) + self.filename_column = gtk.TreeViewColumn(_("Filename"), cell, text=1) + self.filename_column.set_sort_column_id(1) + self.filename_column.set_resizable(True) + self.filename_column.set_clickable(True) + self.filename_column.connect('clicked', self.header_clicked) + self.append_column(self.filename_column) + self.display_filename_column(self.rapidApp.prefs.display_filename_column) + + # Path column (displays at user request) + cell = gtk.CellRendererText() + cell.set_property("yalign", 0) + self.path_column = gtk.TreeViewColumn(_("Path"), cell, text=12) + self.path_column.set_sort_column_id(12) + self.path_column.set_resizable(True) + self.path_column.set_clickable(True) + self.path_column.connect('clicked', self.header_clicked) + self.append_column(self.path_column) + self.display_path_column(self.rapidApp.prefs.display_path_column) + + self.show_all() + + # flag used to determine if a preview should be generated or not + # there is no point generating a preview for each photo when + # select all photos is called, for instance + self.suspend_previews = False + + self.user_has_clicked_header = False + + # icons to be displayed in status column + + self.downloaded_icon = self.render_icon('rapid-photo-downloader-downloaded', gtk.ICON_SIZE_MENU) + self.download_failed_icon = self.render_icon(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_MENU) + self.error_icon = self.render_icon(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_MENU) + self.warning_icon = self.render_icon(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_MENU) + + self.download_pending_icon = self.render_icon('rapid-photo-downloader-download-pending', gtk.ICON_SIZE_MENU) + self.downloaded_with_warning_icon = self.render_icon('rapid-photo-downloader-downloaded-with-warning', gtk.ICON_SIZE_MENU) + self.downloaded_with_error_icon = self.render_icon('rapid-photo-downloader-downloaded-with-error', gtk.ICON_SIZE_MENU) + + # make the not yet downloaded icon a transparent square + self.not_downloaded_icon = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 16, 16) + self.not_downloaded_icon.fill(0xffffffff) + self.not_downloaded_icon = self.not_downloaded_icon.add_alpha(True, chr(255), chr(255), chr(255)) + # but make it be a tick in the preview pane + self.not_downloaded_icon_tick = self.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU) + + #preload generic icons + self.icon_photo = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/photo24.png')) + self.icon_video = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/video24.png')) + #with shadows + self.generic_photo_with_shadow = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/photo_small_shadow.png')) + self.generic_video_with_shadow = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/video_small_shadow.png')) + + if DROP_SHADOW: + self.iconDropShadow = DropShadow(offset=(3,3), shadow = (0x34, 0x34, 0x34, 0xff), border=6) + self.previewDropShadow = DropShadow(shadow = (0x44, 0x44, 0x44, 0xff), trim_border = True) + + self.previewed_file_treerowref = None + self.icontheme = gtk.icon_theme_get_default() + + + + def get_thread(self, iter): + """ + Returns the thread associated with the liststore's iter + """ + return self.liststore.get_value(iter, 14) + + def get_status(self, iter): + """ + Returns the status associated with the liststore's iter + """ + return self.liststore.get_value(iter, 11) + + def get_mediaFile(self, iter): + """ + Returns the mediaFile associated with the liststore's iter + """ + return self.liststore.get_value(iter, 9) + + def get_is_image(self, iter): + """ + Returns the file type (is image or video) associated with the liststore's iter + """ + return self.liststore.get_value(iter, 6) + + def get_type_icon(self, iter): + """ + Returns the file type's pixbuf associated with the liststore's iter + """ + return self.liststore.get_value(iter, 7) + + def get_job_code(self, iter): + """ + Returns the job code associated with the liststore's iter + """ + return self.liststore.get_value(iter, 8) + + def get_status_icon(self, status, preview=False): + """ + Returns the correct icon, based on the status + """ + if status == STATUS_WARNING: + status_icon = self.warning_icon + elif status == STATUS_CANNOT_DOWNLOAD: + status_icon = self.error_icon + elif status == STATUS_DOWNLOADED: + status_icon = self.downloaded_icon + elif status == STATUS_NOT_DOWNLOADED: + if preview: + status_icon = self.not_downloaded_icon_tick + else: + status_icon = self.not_downloaded_icon + elif status in [STATUS_DOWNLOADED_WITH_WARNING, STATUS_BACKUP_PROBLEM]: + status_icon = self.downloaded_with_warning_icon + elif status in [STATUS_DOWNLOAD_FAILED, STATUS_DOWNLOAD_AND_BACKUP_FAILED]: + status_icon = self.downloaded_with_error_icon + elif status == STATUS_DOWNLOAD_PENDING: + status_icon = self.download_pending_icon + else: + sys.stderr.write("FIXME: unknown status: %s\n" % status) + status_icon = self.not_downloaded_icon + return status_icon + + def get_tree_row_refs(self): + """ + Returns a list of all tree row references + """ + tree_row_refs = [] + iter = self.liststore.get_iter_first() + while iter: + tree_row_refs.append(self.get_mediaFile(iter).treerowref) + iter = self.liststore.iter_next(iter) + return tree_row_refs + + def get_selected_tree_row_refs(self): + """ + Returns a list of tree row references for the selected rows + """ + tree_row_refs = [] + selection = self.get_selection() + model, pathlist = selection.get_selected_rows() + for path in pathlist: + iter = self.liststore.get_iter(path) + tree_row_refs.append(self.get_mediaFile(iter).treerowref) + return tree_row_refs + + def get_tree_row_iters(self, selected_only=False): + """ + Yields tree row iters + + If selected_only is True, then only those from the selected + rows will be returned. + + This function is essential when modifying any content + in the list store (because rows can easily be moved when their + content changes) + """ + if selected_only: + tree_row_refs = self.get_selected_tree_row_refs() + else: + tree_row_refs = self.get_tree_row_refs() + for reference in tree_row_refs: + path = reference.get_path() + yield self.liststore.get_iter(path) + + def add_file(self, mediaFile): + if mediaFile.metadata: + date = mediaFile.dateTime() + timestamp = mediaFile.metadata.timeStamp(missing=None) + if timestamp is None: + timestamp = mediaFile.modificationTime + else: + timestamp = mediaFile.modificationTime + date = datetime.datetime.fromtimestamp(timestamp) + + timestamp = int(timestamp) + + date_human_readable = date_time_human_readable(date) + name = mediaFile.name + size = mediaFile.size + thumbnail = mediaFile.thumbnail + thumbnail_icon = common.scale2pixbuf(60, 36, mediaFile.thumbnail) + if DROP_SHADOW: + if not mediaFile.genericThumbnail: + pil_image = pixbuf_to_image(thumbnail_icon) + pil_image = self.iconDropShadow.dropShadow(pil_image) + thumbnail_icon = image_to_pixbuf(pil_image) + else: + if mediaFile.isImage: + thumbnail_icon = self.generic_photo_with_shadow + else: + thumbnail_icon = self.generic_video_with_shadow + + if mediaFile.isImage: + type_icon = self.icon_photo + else: + type_icon = self.icon_video + + status_icon = self.get_status_icon(mediaFile.status) + + iter = self.liststore.append((thumbnail_icon, name, timestamp, date_human_readable, size, common.formatSizeForUser(size), mediaFile.isImage, type_icon, '', mediaFile, status_icon, mediaFile.status, mediaFile.path, mediaFile.deviceName, mediaFile.thread_id)) + + #create a reference to this row and store it in the mediaFile + path = self.liststore.get_path(iter) + mediaFile.treerowref = gtk.TreeRowReference(self.liststore, path) + + if mediaFile.status in [STATUS_CANNOT_DOWNLOAD, STATUS_WARNING]: + if not self.user_has_clicked_header: + self.liststore.set_sort_column_id(11, gtk.SORT_DESCENDING) + + def no_selected_rows_available_for_download(self): + """ + Gets the number of rows the user has selected that can actually + be downloaded, and the threads they are found in + """ + v = 0 + threads = [] + model, paths = self.get_selection().get_selected_rows() + for path in paths: + iter = self.liststore.get_iter(path) + status = self.get_status(iter) + if status in [STATUS_NOT_DOWNLOADED, STATUS_WARNING]: + v += 1 + thread = self.get_thread(iter) + if thread not in threads: + threads.append(thread) + return v, threads + + def rows_available_for_download(self): + """ + Returns true if one or more rows has their status as STATUS_NOT_DOWNLOADED or STATUS_WARNING + """ + iter = self.liststore.get_iter_first() + while iter: + status = self.get_status(iter) + if status in [STATUS_NOT_DOWNLOADED, STATUS_WARNING]: + return True + iter = self.liststore.iter_next(iter) + return False + + def update_download_selected_button(self): + """ + Updates the text on the Download Selection button, and set its sensitivity + """ + no_available_for_download = 0 + selection = self.get_selection() + model, paths = selection.get_selected_rows() + if paths: + path = paths[0] + iter = self.liststore.get_iter(path) + + #update button text + no_available_for_download, threads = self.no_selected_rows_available_for_download() + + if no_available_for_download and workers.scanComplete(threads): + self.rapidApp.download_selected_button.set_label(self.rapidApp.DOWNLOAD_SELECTED_LABEL + " (%s)" % no_available_for_download) + self.rapidApp.download_selected_button.set_sensitive(True) + else: + #nothing was selected, or nothing is available from what the user selected, or should not download right now + self.rapidApp.download_selected_button.set_label(self.rapidApp.DOWNLOAD_SELECTED_LABEL) + self.rapidApp.download_selected_button.set_sensitive(False) + + def on_selection_changed(self, selection): + """ + Update download selected button and preview the most recently + selected row in the treeview + """ + self.update_download_selected_button() + size = selection.count_selected_rows() + if size == 0: + self.selected_rows = set() + self.show_preview(None) + else: + if size <= len(self.selected_rows): + # discard everything, start over + self.selected_rows = set() + self.selection_size = size + model, paths = selection.get_selected_rows() + for path in paths: + iter = self.liststore.get_iter(path) + ref = self.get_mediaFile(iter).treerowref + + if ref not in self.selected_rows: + self.show_preview(iter) + self.selected_rows.add(ref) + + def clear_all(self, thread_id = None): + if thread_id is None: + self.liststore.clear() + self.show_preview(None) + else: + iter = self.liststore.get_iter_first() + while iter: + t = self.get_thread(iter) + if t == thread_id: + if self.previewed_file_treerowref: + mediaFile = self.get_mediaFile(iter) + if mediaFile.treerowref == self.previewed_file_treerowref: + self.show_preview(None) + self.liststore.remove(iter) + # need to start over, or else bad things happen + iter = self.liststore.get_iter_first() + else: + iter = self.liststore.iter_next(iter) + + def refreshSampleDownloadFolders(self, thread_id = None): + """ + Refreshes the download folder of every file that has not yet been downloaded + + This is useful when the user updates the preferences, and the scan has already occurred (or is occurring) + + If thread_id is specified, will only update rows with that thread + """ + for iter in self.get_tree_row_iters(): + status = self.get_status(iter) + if status in [STATUS_NOT_DOWNLOADED, STATUS_WARNING, STATUS_CANNOT_DOWNLOAD]: + regenerate = True + if thread_id is not None: + t = self.get_thread(iter) + regenerate = t == thread_id + + if regenerate: + mediaFile = self.get_mediaFile(iter) + if mediaFile.isImage: + mediaFile.downloadFolder = self.rapidApp.prefs.download_folder + else: + mediaFile.downloadFolder = self.rapidApp.prefs.video_download_folder + mediaFile.samplePath = os.path.join(mediaFile.downloadFolder, mediaFile.sampleSubfolder) + if mediaFile.treerowref == self.previewed_file_treerowref: + self.show_preview(iter) + + def _refreshNameFactories(self): + self.imageRenamePrefsFactory = rn.ImageRenamePreferences(self.rapidApp.prefs.image_rename, self, + self.rapidApp.fileSequenceLock, sequences) + self.videoRenamePrefsFactory = rn.VideoRenamePreferences(self.rapidApp.prefs.video_rename, self, + self.rapidApp.fileSequenceLock, sequences) + self.subfolderPrefsFactory = rn.SubfolderPreferences(self.rapidApp.prefs.subfolder, self) + self.videoSubfolderPrefsFactory = rn.VideoSubfolderPreferences(self.rapidApp.prefs.video_subfolder, self) + self.strip_characters = self.rapidApp.prefs.strip_characters + + + def refreshGeneratedSampleSubfolderAndName(self, thread_id = None): + """ + Refreshes the name, subfolder and status of every file that has not yet been downloaded + + This is useful when the user updates the preferences, and the scan has already occurred (or is occurring) + + If thread_id is specified, will only update rows with that thread + """ + self._setUsesJobCode() + self._refreshNameFactories() + for iter in self.get_tree_row_iters(): + status = self.get_status(iter) + if status in [STATUS_NOT_DOWNLOADED, STATUS_WARNING, STATUS_CANNOT_DOWNLOAD]: + regenerate = True + if thread_id is not None: + t = self.get_thread(iter) + regenerate = t == thread_id + + if regenerate: + mediaFile = self.get_mediaFile(iter) + self.generateSampleSubfolderAndName(mediaFile, iter) + if mediaFile.treerowref == self.previewed_file_treerowref: + self.show_preview(iter) + + def generateSampleSubfolderAndName(self, mediaFile, iter): + problem = pn.Problem() + if mediaFile.isImage: + fallback_date = None + subfolderPrefsFactory = self.subfolderPrefsFactory + renamePrefsFactory = self.imageRenamePrefsFactory + nameUsesJobCode = self.imageRenameUsesJobCode + subfolderUsesJobCode = self.imageSubfolderUsesJobCode + else: + fallback_date = mediaFile.modificationTime + subfolderPrefsFactory = self.videoSubfolderPrefsFactory + renamePrefsFactory = self.videoRenamePrefsFactory + nameUsesJobCode = self.videoRenameUsesJobCode + subfolderUsesJobCode = self.videoSubfolderUsesJobCode + + renamePrefsFactory.setJobCode(self.get_job_code(iter)) + subfolderPrefsFactory.setJobCode(self.get_job_code(iter)) + + generateSubfolderAndName(mediaFile, problem, subfolderPrefsFactory, renamePrefsFactory, + nameUsesJobCode, subfolderUsesJobCode, + self.strip_characters, fallback_date) + if self.get_status(iter) != mediaFile.status: + self.liststore.set(iter, 11, mediaFile.status) + self.liststore.set(iter, 10, self.get_status_icon(mediaFile.status)) + mediaFile.sampleStale = False + + def _setUsesJobCode(self): + self.imageRenameUsesJobCode = rn.usesJobCode(self.rapidApp.prefs.image_rename) + self.imageSubfolderUsesJobCode = rn.usesJobCode(self.rapidApp.prefs.subfolder) + self.videoRenameUsesJobCode = rn.usesJobCode(self.rapidApp.prefs.video_rename) + self.videoSubfolderUsesJobCode = rn.usesJobCode(self.rapidApp.prefs.video_subfolder) + + def show_preview(self, iter): + + def status_human_readable(mediaFile): + if mediaFile.status == STATUS_DOWNLOADED: + v = _('%(filetype)s was downloaded successfully') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_DOWNLOAD_FAILED: + v = _('%(filetype)s was not downloaded') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_DOWNLOADED_WITH_WARNING: + v = _('%(filetype)s was downloaded with warnings') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_BACKUP_PROBLEM: + v = _('%(filetype)s was downloaded but there were problems backing up') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_DOWNLOAD_AND_BACKUP_FAILED: + v = _('%(filetype)s was neither downloaded nor backed up') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_NOT_DOWNLOADED: + v = _('%(filetype)s is ready to be downloaded') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_DOWNLOAD_PENDING: + v = _('%(filetype)s is about to be downloaded') % {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_WARNING: + v = _('%(filetype)s will be downloaded with warnings')% {'filetype': mediaFile.displayNameCap} + elif mediaFile.status == STATUS_CANNOT_DOWNLOAD: + v = _('%(filetype)s cannot be downloaded') % {'filetype': mediaFile.displayNameCap} + return v + + + if not iter: + # clear everything except the label Preview at the top + for widget in [self.parentApp.preview_original_name_label, + self.parentApp.preview_name_label, + self.parentApp.preview_status_label, + self.parentApp.preview_problem_title_label, + self.parentApp.preview_problem_label]: + widget.set_text('') + + for widget in [self.parentApp.preview_image, + self.parentApp.preview_name_label, + self.parentApp.preview_original_name_label, + self.parentApp.preview_status_label, + self.parentApp.preview_problem_title_label, + self.parentApp.preview_problem_label + ]: + widget.set_tooltip_text('') + + self.parentApp.preview_image.clear() + self.parentApp.preview_status_icon.clear() + self.parentApp.preview_destination_expander.hide() + self.parentApp.preview_device_expander.hide() + self.previewed_file_treerowref = None + + + elif not self.suspend_previews: + mediaFile = self.get_mediaFile(iter) + + self.previewed_file_treerowref = mediaFile.treerowref + + thumbnail = mediaFile.thumbnail + + if DROP_SHADOW and not mediaFile.genericThumbnail: + pil_image = pixbuf_to_image(thumbnail) + pil_image = self.previewDropShadow.dropShadow(pil_image) + thumbnail = image_to_pixbuf(pil_image) + + self.parentApp.preview_image.set_from_pixbuf(thumbnail) + + image_tool_tip = "%s\n%s" % (date_time_human_readable(mediaFile.dateTime(), False), common.formatSizeForUser(mediaFile.size)) + self.parentApp.preview_image.set_tooltip_text(image_tool_tip) + + if mediaFile.sampleStale and mediaFile.status in [STATUS_NOT_DOWNLOADED, STATUS_WARNING]: + self._refreshNameFactories() + self._setUsesJobCode() + self.generateSampleSubfolderAndName(mediaFile, iter) + + self.parentApp.preview_original_name_label.set_text(mediaFile.name) + self.parentApp.preview_original_name_label.set_tooltip_text(mediaFile.name) + if mediaFile.volume: + pixbuf = mediaFile.volume.get_icon_pixbuf(16) + else: + pixbuf = self.icontheme.load_icon('gtk-harddisk', 16, gtk.ICON_LOOKUP_USE_BUILTIN) + self.parentApp.preview_device_image.set_from_pixbuf(pixbuf) + self.parentApp.preview_device_label.set_text(mediaFile.deviceName) + self.parentApp.preview_device_path_label.set_text(mediaFile.path) + self.parentApp.preview_device_path_label.set_tooltip_text(mediaFile.path) + + if using_gio: + folder = gio.File(mediaFile.downloadFolder) + fileInfo = folder.query_info(gio.FILE_ATTRIBUTE_STANDARD_ICON) + icon = fileInfo.get_icon() + pixbuf = common.get_icon_pixbuf(using_gio, icon, 16, fallback='folder') + else: + pixbuf = self.icontheme.load_icon('folder', 16, gtk.ICON_LOOKUP_USE_BUILTIN) + + self.parentApp.preview_destination_image.set_from_pixbuf(pixbuf) + downloadFolderName = os.path.split(mediaFile.downloadFolder)[1] + self.parentApp.preview_destination_label.set_text(downloadFolderName) + + if mediaFile.status in [STATUS_WARNING, STATUS_CANNOT_DOWNLOAD, STATUS_NOT_DOWNLOADED, STATUS_DOWNLOAD_PENDING]: + + self.parentApp.preview_name_label.set_text(mediaFile.sampleName) + self.parentApp.preview_name_label.set_tooltip_text(mediaFile.sampleName) + self.parentApp.preview_destination_path_label.set_text(mediaFile.samplePath) + self.parentApp.preview_destination_path_label.set_tooltip_text(mediaFile.samplePath) + else: + self.parentApp.preview_name_label.set_text(mediaFile.downloadName) + self.parentApp.preview_name_label.set_tooltip_text(mediaFile.downloadName) + self.parentApp.preview_destination_path_label.set_text(mediaFile.downloadPath) + self.parentApp.preview_destination_path_label.set_tooltip_text(mediaFile.downloadPath) + + status_text = status_human_readable(mediaFile) + self.parentApp.preview_status_icon.set_from_pixbuf(self.get_status_icon(mediaFile.status, preview=True)) + self.parentApp.preview_status_label.set_markup('<b>' + status_text + '</b>') + self.parentApp.preview_status_label.set_tooltip_text(status_text) + + + if mediaFile.status in [STATUS_WARNING, STATUS_DOWNLOAD_FAILED, + STATUS_DOWNLOADED_WITH_WARNING, + STATUS_CANNOT_DOWNLOAD, + STATUS_BACKUP_PROBLEM, + STATUS_DOWNLOAD_AND_BACKUP_FAILED]: + problem_title = mediaFile.problem.get_title() + self.parentApp.preview_problem_title_label.set_markup('<i>' + problem_title + '</i>') + self.parentApp.preview_problem_title_label.set_tooltip_text(problem_title) + + problem_text = mediaFile.problem.get_problems() + self.parentApp.preview_problem_label.set_text(problem_text) + self.parentApp.preview_problem_label.set_tooltip_text(problem_text) + else: + self.parentApp.preview_problem_label.set_markup('') + self.parentApp.preview_problem_title_label.set_markup('') + for widget in [self.parentApp.preview_problem_title_label, + self.parentApp.preview_problem_label + ]: + widget.set_tooltip_text('') + + if self.rapidApp.prefs.display_preview_folders: + self.parentApp.preview_destination_expander.show() + self.parentApp.preview_device_expander.show() + + + def select_rows(self, range): + selection = self.get_selection() + if range == 'all': + selection.select_all() + elif range == 'none': + selection.unselect_all() + else: + # User chose to select all photos or all videos, + # or select all files with or without job codes. + + # Temporarily suspend previews while a large number of rows + # are being selected / unselected + self.suspend_previews = True + + iter = self.liststore.get_iter_first() + while iter is not None: + if range in ['photos', 'videos']: + type = self.get_is_image(iter) + select_row = (type and range == 'photos') or (not type and range == 'videos') + else: + job_code = self.get_job_code(iter) + select_row = (job_code and range == 'withjobcode') or (not job_code and range == 'withoutjobcode') + if select_row: + selection.select_iter(iter) + else: + selection.unselect_iter(iter) + iter = self.liststore.iter_next(iter) + + self.suspend_previews = False + # select the first photo / video + iter = self.liststore.get_iter_first() + while iter is not None: + type = self.get_is_image(iter) + if (type and range == 'photos') or (not type and range == 'videos'): + self.show_preview(iter) + break + iter = self.liststore.iter_next(iter) + + + def header_clicked(self, column): + self.user_has_clicked_header = True + + def display_filename_column(self, display): + """ + if display is true, the column will be shown + otherwise, it will not be shown + """ + self.filename_column.set_visible(display) + + def display_size_column(self, display): + self.size_column.set_visible(display) + + def display_type_column(self, display): + if not DOWNLOAD_VIDEO: + self.type_column.set_visible(False) + else: + self.type_column.set_visible(display) + + def display_path_column(self, display): + self.path_column.set_visible(display) + + def display_device_column(self, display): + self.device_column.set_visible(display) + + def apply_job_code(self, job_code, overwrite=True, to_all_rows=False, thread_id=None): + """ + Applies the Job code to the selected rows, or all rows if to_all_rows is True. + + If overwrite is True, then it will overwrite any existing job code. + """ + + def _apply_job_code(): + status = self.get_status(iter) + if status in [STATUS_DOWNLOAD_PENDING, STATUS_WARNING, STATUS_NOT_DOWNLOADED]: + + if mediaFile.isImage: + apply = rn.usesJobCode(self.rapidApp.prefs.image_rename) or rn.usesJobCode(self.rapidApp.prefs.subfolder) + else: + apply = rn.usesJobCode(self.rapidApp.prefs.video_rename) or rn.usesJobCode(self.rapidApp.prefs.video_subfolder) + if apply: + if overwrite: + self.liststore.set(iter, 8, job_code) + mediaFile.jobcode = job_code + mediaFile.sampleStale = True + else: + if not self.get_job_code(iter): + self.liststore.set(iter, 8, job_code) + mediaFile.jobcode = job_code + mediaFile.sampleStale = True + else: + pass + #if they got an existing job code, may as well keep it there in case the user + #reactivates job codes again in their prefs + + if to_all_rows or thread_id is not None: + for iter in self.get_tree_row_iters(): + apply = True + if thread_id is not None: + t = self.get_thread(iter) + apply = t == thread_id + + if apply: + mediaFile = self.get_mediaFile(iter) + _apply_job_code() + if mediaFile.treerowref == self.previewed_file_treerowref: + self.show_preview(iter) + else: + for iter in self.get_tree_row_iters(selected_only = True): + mediaFile = self.get_mediaFile(iter) + _apply_job_code() + if mediaFile.treerowref == self.previewed_file_treerowref: + self.show_preview(iter) + + def job_code_missing(self, selected_only): + """ + Returns True if any of the pending downloads do not have a + job code assigned. + + If selected_only is True, will only check in rows that the + user has selected. + """ + + def _job_code_missing(iter): + status = self.get_status(iter) + if status in [STATUS_WARNING, STATUS_NOT_DOWNLOADED]: + is_image = self.get_is_image(iter) + job_code = self.get_job_code(iter) + return needAJobCode.needAJobCode(job_code, is_image) + return False + + self._setUsesJobCode() + needAJobCode = NeedAJobCode(self.rapidApp.prefs) + + v = False + if selected_only: + selection = self.get_selection() + model, pathlist = selection.get_selected_rows() + for path in pathlist: + iter = self.liststore.get_iter(path) + v = _job_code_missing(iter) + if v: + break + else: + iter = self.liststore.get_iter_first() + while iter: + v = _job_code_missing(iter) + if v: + break + iter = self.liststore.iter_next(iter) + return v + + + def _set_download_pending(self, iter, threads): + existing_status = self.get_status(iter) + if existing_status in [STATUS_WARNING, STATUS_NOT_DOWNLOADED]: + self.liststore.set(iter, 11, STATUS_DOWNLOAD_PENDING) + self.liststore.set(iter, 10, self.download_pending_icon) + # this value is in a thread's list of files to download + mediaFile = self.get_mediaFile(iter) + # each thread will see this change in status + mediaFile.status = STATUS_DOWNLOAD_PENDING + thread = self.get_thread(iter) + if thread not in threads: + threads.append(thread) + + def set_status_to_download_pending(self, selected_only, thread_id=None): + """ + Sets status of files to be download pending, if they are waiting to be downloaded + if selected_only is true, only applies to selected rows + + If thread_id is not None, then after the statuses have been set, + the thread will be restarted (this is intended for the cases + where this method is called from a thread and auto start is True) + + Returns a list of threads which can be downloaded + """ + threads = [] + + if selected_only: + for iter in self.get_tree_row_iters(selected_only = True): + self._set_download_pending(iter, threads) + else: + for iter in self.get_tree_row_iters(): + apply = True + if thread_id is not None: + t = self.get_thread(iter) + apply = t == thread_id + if apply: + self._set_download_pending(iter, threads) + + if thread_id is not None: + # restart the thread + workers[thread_id].startStop() + return threads + + def update_status_post_download(self, treerowref): + path = treerowref.get_path() + if not path: + sys.stderr.write("FIXME: SelectionTreeView treerowref no longer refers to valid row\n") + else: + iter = self.liststore.get_iter(path) + mediaFile = self.get_mediaFile(iter) + status = mediaFile.status + self.liststore.set(iter, 11, status) + self.liststore.set(iter, 10, self.get_status_icon(status)) + + # If this row is currently previewed, then should update the preview + if mediaFile.treerowref == self.previewed_file_treerowref: + self.show_preview(iter) + + +class SelectionVBox(gtk.VBox): + """ + Dialog from which the user can select photos and videos to download + """ + + + def __init__(self, parentApp): + """ + Initialize values for log dialog, but do not display. + """ + + gtk.VBox.__init__(self) + self.parentApp = parentApp + + selection_scrolledwindow = gtk.ScrolledWindow() + selection_scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + selection_viewport = gtk.Viewport() + + + self.selection_treeview = SelectionTreeView(self) + + selection_scrolledwindow.add(self.selection_treeview) + + + # Job code controls + self.add_job_code_combo() + left_pane_vbox = gtk.VBox(spacing = 12) + left_pane_vbox.pack_start(selection_scrolledwindow, True, True) + left_pane_vbox.pack_start(self.job_code_hbox, False, True) + + # Window sizes + #selection_scrolledwindow.set_size_request(350, -1) + + + #Preview pane + + #Preview title + self.preview_title_label = gtk.Label() + self.preview_title_label.set_markup("<b>%s</b>" % _("Preview")) + self.preview_title_label.set_alignment(0, 0.5) + self.preview_title_label.set_padding(12, 0) + + #Preview image + self.preview_image = gtk.Image() + self.preview_image.set_alignment(0, 0.5) + #leave room for thumbnail shadow + if DROP_SHADOW: + shadow_size = 21 + else: + shadow_size = 0 + self.preview_image.set_size_request(MAX_THUMBNAIL_SIZE + shadow_size, MAX_THUMBNAIL_SIZE + shadow_size) + + #labels to display file information + + #Original filename + self.preview_original_name_label = gtk.Label() + self.preview_original_name_label.set_alignment(0, 0.5) + self.preview_original_name_label.set_ellipsize(pango.ELLIPSIZE_END) + + #Device (where it will be downloaded to) + self.preview_device_expander = gtk.Expander() + self.preview_device_label = gtk.Label() + self.preview_device_label.set_alignment(0, 0.5) + self.preview_device_image = gtk.Image() + + self.preview_device_path_label = gtk.Label() + self.preview_device_path_label.set_alignment(0, 0.5) + self.preview_device_path_label.set_ellipsize(pango.ELLIPSIZE_MIDDLE) + self.preview_device_path_label.set_padding(30, 0) + self.preview_device_expander.add(self.preview_device_path_label) + + device_hbox = gtk.HBox(False, spacing = 6) + device_hbox.pack_start(self.preview_device_image) + device_hbox.pack_start(self.preview_device_label, True, True) + + self.preview_device_expander.set_label_widget(device_hbox) + + #Filename that has been generated (path in tooltip) + self.preview_name_label = gtk.Label() + self.preview_name_label.set_alignment(0, 0.5) + self.preview_name_label.set_ellipsize(pango.ELLIPSIZE_END) + + #Download destination + self.preview_destination_expander = gtk.Expander() + self.preview_destination_label = gtk.Label() + self.preview_destination_label.set_alignment(0, 0.5) + self.preview_destination_image = gtk.Image() + + self.preview_destination_path_label = gtk.Label() + self.preview_destination_path_label.set_alignment(0, 0.5) + self.preview_destination_path_label.set_ellipsize(pango.ELLIPSIZE_MIDDLE) + self.preview_destination_path_label.set_padding(30, 0) + self.preview_destination_expander.add(self.preview_destination_path_label) + + destination_hbox = gtk.HBox(False, spacing = 6) + destination_hbox.pack_start(self.preview_destination_image) + destination_hbox.pack_start(self.preview_destination_label, True, True) + + self.preview_destination_expander.set_label_widget(destination_hbox) + + + #Status of the file + + self.preview_status_icon = gtk.Image() + self.preview_status_icon.set_size_request(16,16) + + self.preview_status_label = gtk.Label() + self.preview_status_label.set_alignment(0, 0.5) + self.preview_status_label.set_ellipsize(pango.ELLIPSIZE_END) + self.preview_status_label.set_padding(12, 0) + + #Title of problems encountered in generating the name / subfolder + self.preview_problem_title_label = gtk.Label() + self.preview_problem_title_label.set_alignment(0, 0.5) + self.preview_problem_title_label.set_ellipsize(pango.ELLIPSIZE_END) + self.preview_problem_title_label.set_padding(12, 0) + + #Details of what the problem(s) are + self.preview_problem_label = gtk.Label() + self.preview_problem_label.set_alignment(0, 0) + self.preview_problem_label.set_line_wrap(True) + self.preview_problem_label.set_padding(12, 0) + #Can't combine wrapping and ellipsize, sadly + #self.preview_problem_label.set_ellipsize(pango.ELLIPSIZE_END) + + #Put content into table + # Use a table so we can do the Gnome HIG layout more easily + self.preview_table = gtk.Table(10, 4) + self.preview_table.set_row_spacings(12) + left_spacer = gtk.Label('') + left_spacer.set_padding(12, 0) + right_spacer = gtk.Label('') + right_spacer.set_padding(6, 0) + + + spacer2 = gtk.Label('') + + self.preview_table.attach(left_spacer, 0, 1, 1, 2, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) + self.preview_table.attach(right_spacer, 3, 4, 1, 2, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) + + self.preview_table.attach(self.preview_title_label, 0, 3, 0, 1, yoptions=gtk.SHRINK) + self.preview_table.attach(self.preview_image, 1, 3, 1, 2, yoptions=gtk.SHRINK) + + self.preview_table.attach(self.preview_original_name_label, 1, 3, 2, 3, xoptions=gtk.EXPAND|gtk.FILL, yoptions=gtk.SHRINK) + self.preview_table.attach(self.preview_device_expander, 1, 3, 3, 4, xoptions=gtk.EXPAND|gtk.FILL, yoptions=gtk.SHRINK) + + self.preview_table.attach(self.preview_name_label, 1, 3, 5, 6, xoptions=gtk.EXPAND|gtk.FILL, yoptions=gtk.SHRINK) + self.preview_table.attach(self.preview_destination_expander, 1, 3, 6, 7, xoptions=gtk.EXPAND|gtk.FILL, yoptions=gtk.SHRINK) + + self.preview_table.attach(spacer2, 0, 7, 7, 8, yoptions=gtk.SHRINK) + + self.preview_table.attach(self.preview_status_icon, 1, 2, 8, 9, xoptions=gtk.SHRINK, yoptions=gtk.SHRINK) + self.preview_table.attach(self.preview_status_label, 2, 3, 8, 9, yoptions=gtk.SHRINK) + + self.preview_table.attach(self.preview_problem_title_label, 2, 3, 9, 10, yoptions=gtk.SHRINK) + self.preview_table.attach(self.preview_problem_label, 2, 4, 10, 11, xoptions=gtk.EXPAND|gtk.FILL, yoptions=gtk.EXPAND|gtk.FILL) + + self.file_hpaned = gtk.HPaned() + self.file_hpaned.pack1(left_pane_vbox, shrink=False) + #self.file_hpaned.pack2(self.preview_vbox, shrink=False) + self.file_hpaned.pack2(self.preview_table, resize=True, shrink=False) + self.pack_start(self.file_hpaned, True, True) + if self.parentApp.prefs.hpaned_pos > 0: + self.file_hpaned.set_position(self.parentApp.prefs.hpaned_pos) + else: + # this is what the user will see the first time they run the app + self.file_hpaned.set_position(300) + + self.show_all() + + + def set_display_preview_folders(self, value): + if value and self.selection_treeview.previewed_file_treerowref: + self.preview_destination_expander.show() + self.preview_device_expander.show() + + else: + self.preview_destination_expander.hide() + self.preview_device_expander.hide() + + def set_job_code_display(self): + """ + Shows or hides the job code entry + + If user is not using job codes in their file or subfolder names + then do not prompt for it + """ + + if self.parentApp.needJobCodeForRenaming(): + self.job_code_hbox.show() + self.job_code_label.show() + self.job_code_combo.show() + self.selection_treeview.job_code_column.set_visible(True) + else: + self.job_code_hbox.hide() + self.job_code_label.hide() + self.job_code_combo.hide() + self.selection_treeview.job_code_column.set_visible(False) + + def update_job_code_combo(self): + # delete existing rows + while len(self.job_code_combo.get_model()) > 0: + self.job_code_combo.remove_text(0) + # add new ones + for text in self.parentApp.prefs.job_codes: + self.job_code_combo.append_text(text) + # clear existing entry displayed in entry box + self.job_code_entry.set_text('') + + + + + def add_job_code_combo(self): + self.job_code_hbox = gtk.HBox(spacing = 12) + self.job_code_hbox.set_no_show_all(True) + self.job_code_label = gtk.Label(_("Job Code:")) + + self.job_code_combo = gtk.combo_box_entry_new_text() + for text in self.parentApp.prefs.job_codes: + self.job_code_combo.append_text(text) + + # make entry box have entry completion + self.job_code_entry = self.job_code_combo.child + + self.completion = gtk.EntryCompletion() + self.completion.set_match_func(self.job_code_match_func) + self.completion.connect("match-selected", + self.on_job_code_combo_completion_match) + self.completion.set_model(self.job_code_combo.get_model()) + self.completion.set_text_column(0) + self.job_code_entry.set_completion(self.completion) + + + self.job_code_combo.connect('changed', self.on_job_code_resp) + + self.job_code_entry.connect('activate', self.on_job_code_entry_resp) + + self.job_code_combo.set_tooltip_text(_("Enter a new Job Code and press Enter, or select an existing Job Code")) + + #add widgets + self.job_code_hbox.pack_start(self.job_code_label, False, False) + self.job_code_hbox.pack_start(self.job_code_combo, True, True) + self.set_job_code_display() + + def job_code_match_func(self, completion, key, iter): + model = completion.get_model() + return model[iter][0].lower().startswith(self.job_code_entry.get_text().lower()) + + def on_job_code_combo_completion_match(self, completion, model, iter): + self.job_code_entry.set_text(model[iter][0]) + self.job_code_entry.set_position(-1) + + def on_job_code_resp(self, widget): + """ + When the user has clicked on an existing job code + """ + + # ignore changes because the user is typing in a new value + if widget.get_active() >= 0: + self.job_code_chosen(widget.get_active_text()) + + def on_job_code_entry_resp(self, widget): + """ + When the user has hit enter after entering a new job code + """ + self.job_code_chosen(widget.get_text()) + + def job_code_chosen(self, job_code): + """ + The user has selected a Job code, apply it to selected images. + """ + self.selection_treeview.apply_job_code(job_code, overwrite = True) + self.completion.set_model(None) + self.parentApp.assignJobCode(job_code) + self.completion.set_model(self.job_code_combo.get_model()) + + def add_file(self, mediaFile): + self.selection_treeview.add_file(mediaFile) + class LogDialog(gnomeglade.Component): """ @@ -3167,8 +4618,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): gladefile = paths.share_dir(config.GLADE_FILE) gnomeglade.GnomeApp.__init__(self, "rapid", __version__, gladefile, "rapidapp") - - + # notifications self.displayDownloadSummaryNotification = False self.initPyNotify() @@ -3182,8 +4632,25 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): # sys.exit(0) + # remember the window size from the last time the program was run + if self.prefs.main_window_maximized: + self.rapidapp.maximize() + elif self.prefs.main_window_size_x > 0: + self.rapidapp.set_default_size(self.prefs.main_window_size_x, self.prefs.main_window_size_y) + else: + # set a default size + self.rapidapp.set_default_size(650, 650) + self.widget.show() + self._setupIcons() + + # this must come after the window is shown + if self.prefs.vpaned_pos > 0: + self.main_vpaned.set_position(self.prefs.vpaned_pos) + else: + self.main_vpaned.set_position(66) + self.checkIfFirstTimeProgramEverRun() displayPreferences = self.checkForUpgrade(__version__) @@ -3202,8 +4669,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): displayPreferences = not self.checkPreferencesOnStartup() # display download information using threads - global media_collection_treeview, thumbnail_hbox, log_dialog - global download_queue, image_queue, log_queue + global media_collection_treeview, log_dialog global workers #track files that should have a suffix added to them @@ -3216,13 +4682,13 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): global sequences # whether we need to prompt for a job code - global need_job_code + global need_job_code_for_renaming duplicate_files = {} downloaded_files = DownloadedFiles() downloadsToday = self.prefs.getAndMaybeResetDownloadsToday() - sequences = rn.Sequences(downloadsToday, self.prefs.stored_sequence_no) + sequences = rn.Sequences(downloadsToday, self.prefs.stored_sequence_no) self.downloadStats = DownloadStats() @@ -3247,7 +4713,21 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): # flag to indicate whether the user changed some preferences that # indicate the image and backup devices should be setup again - self.rerunSetupAvailableImageAndBackupMedia = False + self.rerunSetupAvailableImageAndVideoMedia = False + self.rerunSetupAvailableBackupMedia = False + + # flag to indicate the user changes some preferences and the display + # of sample names and subfolders needs to be refreshed + self.refreshGeneratedSampleSubfolderAndName = False + + # counter to indicate how many threads need their sample names and subfolders regenerated because the user + # changes their prefs at the same time as devices were being scanned + self.noAfterScanRefreshGeneratedSampleSubfolderAndName = 0 + + # flag to indicate the user changes some preferences and the display + # of sample download folders needs to be refreshed + self.refreshSampleDownloadFolder = False + self.noAfterScanRefreshSampleDownloadFolders = 0 # flag to indicate that the preferences dialog window is being # displayed to the user @@ -3258,15 +4738,16 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.media_collection_vbox.pack_start(media_collection_treeview) - #thumbnail display - thumbnail_hbox = ThumbnailHBox(self) - self.image_viewport.add(thumbnail_hbox) - self.image_viewport.modify_bg(gtk.STATE_NORMAL, gdk.color_parse("white")) - self.set_display_thumbnails(self.prefs.display_thumbnails) + #Selection display + self.selection_vbox = SelectionVBox(self) + self.selection_hbox.pack_start(self.selection_vbox, padding=12) + self.set_display_selection(self.prefs.display_selection) + self.set_display_preview_folders(self.prefs.display_preview_folders) self.backupVolumes = {} - self._setupDownloadbutton() + #Help button and download buttons + self._setupDownloadbuttons() #status bar progress bar self.download_progressbar = gtk.ProgressBar() @@ -3278,11 +4759,28 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): # menus - self.menu_display_thumbnails.set_active(self.prefs.display_thumbnails) + #preview panes + self.menu_display_selection.set_active(self.prefs.display_selection) + self.menu_preview_folders.set_active(self.prefs.display_preview_folders) + + #preview columns in pane + if not DOWNLOAD_VIDEO: + self.menu_type_column.set_active(False) + self.menu_type_column.set_sensitive(False) + else: + self.menu_type_column.set_active(self.prefs.display_type_column) + self.menu_size_column.set_active(self.prefs.display_size_column) + self.menu_filename_column.set_active(self.prefs.display_filename_column) + self.menu_device_column.set_active(self.prefs.display_device_column) + self.menu_path_column.set_active(self.prefs.display_path_column) + self.menu_clear.set_sensitive(False) + + need_job_code_for_renaming = self.needJobCodeForRenaming() + self.menu_select_all_without_job_code.set_sensitive(need_job_code_for_renaming) + self.menu_select_all_with_job_code.set_sensitive(need_job_code_for_renaming) #job code initialization - need_job_code = self.needJobCode() self.last_chosen_job_code = None self.prompting_for_job_code = False @@ -3300,8 +4798,12 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): #adjust viewport size for displaying media #this is important because the code in MediaTreeView.addCard() is inaccurate at program startup - height = self.media_collection_viewport.size_request()[1] - self.media_collection_scrolledwindow.set_size_request(-1, height) + if media_collection_treeview.mapThreadToRow: + height = self.media_collection_viewport.size_request()[1] + self.media_collection_scrolledwindow.set_size_request(-1, height) + else: + # don't allow the media collection to be absolutely empty + self.media_collection_scrolledwindow.set_size_request(-1, 47) self.download_button.grab_default() # for some reason, the grab focus command is not working... unsure why @@ -3342,7 +4844,17 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.prefs.video_download_folder = f + def _setupIcons(self): + icons = ['rapid-photo-downloader-downloaded', + 'rapid-photo-downloader-downloaded-with-error', + 'rapid-photo-downloader-downloaded-with-warning', + 'rapid-photo-downloader-download-pending', + 'rapid-photo-downloader-jobcode'] + icon_list = [(icon, paths.share_dir('glade3/%s.svg' % icon)) for icon in icons] + common.register_iconsets(icon_list) + + def checkImageDevicePathOnStartup(self): msg = None if not os.path.isdir(self.prefs.device_location): @@ -3403,7 +4915,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): sys.stderr.write(msg +'\n') return prefsOk - def needJobCode(self): + def needJobCodeForRenaming(self): return rn.usesJobCode(self.prefs.image_rename) or rn.usesJobCode(self.prefs.subfolder) or rn.usesJobCode(self.prefs.video_rename) or rn.usesJobCode(self.prefs.video_subfolder) def assignJobCode(self, code): @@ -3429,6 +4941,15 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.prefs.job_codes = [code] + jcs + def getShowWarningDownloadingFromCamera(self): + if self.prefs.show_warning_downloading_from_camera: + cmd_line(_("Displaying warning about downloading directly from camera")) + d = ShowWarningDialog(self.widget, self.gotShowWarningDownloadingFromCamera) + + def gotShowWarningDownloadingFromCamera(self, dialog, showWarningAgain): + dialog.destroy() + self.prefs.show_warning_downloading_from_camera = showWarningAgain + def getUseDevice(self, path, volume, autostart): """ Prompt user whether or not to download from this device """ @@ -3455,40 +4976,73 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): else: self.prefs.device_blacklist = [path] - def _getJobCode(self, postJobCodeEntryCB, autoStart): + def _getJobCode(self, postJobCodeEntryCB, autoStart, downloadSelected): """ prompt for a job code """ - if not self.prompting_for_job_code: cmd_line(_("Prompting for Job Code")) self.prompting_for_job_code = True - j = JobCodeDialog(self.widget, self.prefs.job_codes, self.last_chosen_job_code, postJobCodeEntryCB, autoStart, False) + j = JobCodeDialog(self.widget, self.prefs.job_codes, self.last_chosen_job_code, postJobCodeEntryCB, autoStart, downloadSelected, False) else: cmd_line(_("Already prompting for Job Code, do not prompt again")) - def getJobCode(self, autoStart=True): - """ called from the copyphotos thread""" + def getJobCode(self, autoStart=True, downloadSelected=False): + """ called from the copyphotos thread, or when the user clicks one of the two download buttons""" - self._getJobCode(self.gotJobCode, autoStart) + self._getJobCode(self.gotJobCode, autoStart, downloadSelected) - def gotJobCode(self, dialog, userChoseCode, code, autoStart): + def gotJobCode(self, dialog, userChoseCode, code, autoStart, downloadSelected): dialog.destroy() self.prompting_for_job_code = False if userChoseCode: self.assignJobCode(code) self.last_chosen_job_code = code - if autoStart: + self.selection_vbox.selection_treeview.apply_job_code(code, overwrite=False, to_all_rows = not downloadSelected) + threads = self.selection_vbox.selection_treeview.set_status_to_download_pending(selected_only = downloadSelected) + if downloadSelected or not autoStart: + cmd_line(_("Starting downloads")) + self.startDownload(threads) + else: + # autostart is true cmd_line(_("Starting downloads that have been waiting for a Job Code")) for w in workers.getWaitingForJobCodeWorkers(): w.startStop() - else: - cmd_line(_("Starting downloads")) - self.startDownload() - - # FIXME: what happens to these workers that are waiting? How will the user start their download? - # check if need to add code to start button + else: + # user cancelled + for w in workers.getWaitingForJobCodeWorkers(): + w.waitingForJobCode = False + + if autoStart: + for w in workers.getAutoStartWorkers(): + w.autoStart = False + + def addFile(self, mediaFile): + self.selection_vbox.add_file(mediaFile) + + def update_status_post_download(self, treerowref): + self.selection_vbox.selection_treeview.update_status_post_download(treerowref) + + def on_menu_size_column_toggled(self, widget): + self.prefs.display_size_column = widget.get_active() + self.selection_vbox.selection_treeview.display_size_column(self.prefs.display_size_column) + + def on_menu_type_column_toggled(self, widget): + self.prefs.display_type_column = widget.get_active() + self.selection_vbox.selection_treeview.display_type_column(self.prefs.display_type_column) + + def on_menu_filename_column_toggled(self, widget): + self.prefs.display_filename_column = widget.get_active() + self.selection_vbox.selection_treeview.display_filename_column(self.prefs.display_filename_column) + + def on_menu_path_column_toggled(self, widget): + self.prefs.display_path_column = widget.get_active() + self.selection_vbox.selection_treeview.display_path_column(self.prefs.display_path_column) + + def on_menu_device_column_toggled(self, widget): + self.prefs.display_device_column = widget.get_active() + self.selection_vbox.selection_treeview.display_device_column(self.prefs.display_device_column) def checkIfFirstTimeProgramEverRun(self): """ @@ -3593,23 +5147,27 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): for cap in caps: capabilities[cap] = True + do_not_size_icon = False + self.notification_icon_size = 48 try: info = pynotify.get_server_info() except: cmd_line(_("Warning: desktop environment notification server is incorrectly configured.")) - self.notification_icon_size = 48 else: try: - if info['name'] == 'Notification Daemon': - self.notification_icon_size = 128 - else: - self.notification_icon_size = 48 + if info["name"] == 'notify-osd': + do_not_size_icon = True except: - self.notification_icon_size = 48 - - self.application_icon = gtk.gdk.pixbuf_new_from_file_at_size( - paths.share_dir('glade3/rapid-photo-downloader-about.png'), - self.notification_icon_size, self.notification_icon_size) + pass + + if do_not_size_icon: + self.application_icon = gtk.gdk.pixbuf_new_from_file( + paths.share_dir('glade3/rapid-photo-downloader.svg')) + else: + self.application_icon = gtk.gdk.pixbuf_new_from_file_at_size( + paths.share_dir('glade3/rapid-photo-downloader.svg'), + self.notification_icon_size, self.notification_icon_size) + def usingVolumeMonitor(self): @@ -3662,12 +5220,23 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): return self.prefs.device_autodetection_psd and self.prefs.device_autodetection - def isGProxyShadowMount(self, gvfsVolume): + def isGProxyShadowMount(self, gMount): - """ gvfs GProxyShadowMount are used for camera specific things, not the data in the memory card """ + """ gvfs GProxyShadowMount is used for the camera itself, not the data in the memory card """ if using_gio: - #FIXME: this is a hack, but what is the correct function? - return str(type(gvfsVolume)).find('GProxyShadowMount') >= 0 + if hasattr(gMount, 'is_shadowed'): + return gMount.is_shadowed() + else: + return str(type(gMount)).find('GProxyShadowMount') >= 0 + else: + return False + + def isCamera(self, volume): + if using_gio: + try: + return volume.get_root().query_filesystem_info(gio.FILE_ATTRIBUTE_GVFS_BACKEND).get_attribute_as_string(gio.FILE_ATTRIBUTE_GVFS_BACKEND) == 'gphoto2' + except: + return False else: return False @@ -3703,17 +5272,19 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.backupVolumes[path] = volume self.rapid_statusbar.push(self.statusbar_context_id, self.displayBackupVolumes()) - elif media.is_DCIM_Media(path) or self.searchForPsd(): + elif self.prefs.device_autodetection and (media.is_DCIM_Media(path) or self.searchForPsd()): + if self.isCamera(volume.volume): + self.getShowWarningDownloadingFromCamera() if self.searchForPsd() and path not in self.prefs.device_whitelist: # prompt user if device should be used or not - self.getUseDevice(path, volume, self.prefs.auto_download_upon_device_insertion) + self.getUseDevice(path, volume, self.prefs.auto_download_upon_device_insertion) else: self._printAutoStart(self.prefs.auto_download_upon_device_insertion) self.initiateScan(path, volume, self.prefs.auto_download_upon_device_insertion) def initiateScan(self, path, volume, autostart): """ initiates scan of image device""" - cardMedia = CardMedia(path, volume, True) + cardMedia = CardMedia(path, volume) i = workers.getNextThread_id() workers.append(CopyPhotos(i, self, self.fileRenameLock, @@ -3748,12 +5319,14 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): if w.cardMedia.volume: if w.cardMedia.volume.volume == volume: media_collection_treeview.removeCard(w.thread_id) + self.selection_vbox.selection_treeview.clear_all(w.thread_id) workers.disableWorker(w.thread_id) # second scenario for w in workers.getReadyToDownloadWorkers(): if w.cardMedia.volume: if w.cardMedia.volume.volume == volume: media_collection_treeview.removeCard(w.thread_id) + self.selection_vbox.selection_treeview.clear_all(w.thread_id) workers.disableWorker(w.thread_id) # fourth scenario - nothing to do @@ -3774,6 +5347,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): for w in workers.getFinishedWorkers(): media_collection_treeview.removeCard(w.thread_id) + self.selection_vbox.selection_treeview.clear_all(w.thread_id) @@ -3822,7 +5396,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): program's initialization. onPreferenceChange should be True if this is being called as the result of a preference - bring changed + being changed Removes any image media that are currently not downloaded, or finished downloading @@ -3839,10 +5413,10 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): if self.usingVolumeMonitor(): # either using automatically detected backup devices - # or image devices + # or download devices for v in self.volumeMonitor.get_mounts(): - volume = Volume(v) + volume = Volume(v) #'volumes' are actually mounts (legacy variable name at work here) path = volume.get_path(avoid_gnomeVFS_bug = True) if path: @@ -3888,25 +5462,86 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): autoStart = (not onPreferenceChange) and ((self.prefs.auto_download_at_startup and onStartup) or (self.prefs.auto_download_upon_device_insertion and not onStartup)) self._printAutoStart(autoStart) + + shownWarning = False for i in range(len(volumeList)): path, volume = volumeList[i] + if volume: + if self.isCamera(volume.volume) and not shownWarning: + self.getShowWarningDownloadingFromCamera() + shownWarning = True if self.searchForPsd() and path not in self.prefs.device_whitelist: # prompt user to see if device should be used or not self.getUseDevice(path, volume, autoStart) else: self.initiateScan(path, volume, autoStart) + + def refreshBackupMedia(self): + """ + Setup the backup media - def _setupDownloadbutton(self): - + Assumptions: this is being called after the user has changed their preferences AND download media has already been setup + """ + self.backupVolumes = {} + if self.prefs.backup_images: + if not self.prefs.backup_device_autodetection: + # user manually specified backup location + # will backup to this path, but don't need any volume info associated with it + self.backupVolumes[self.prefs.backup_location] = None + self.rapid_statusbar.push(self.statusbar_context_id, _('Backing up to %(path)s') % {'path':self.prefs.backup_location}) + else: + for v in self.volumeMonitor.get_mounts(): + volume = Volume(v) + path = volume.get_path(avoid_gnomeVFS_bug = True) + if path: + if self.checkIfBackupVolume(path): + # is a backup volume + if path not in self.backupVolumes: + # ensure it is not in a list of workers which have not started downloading + # if it is, remove it + for w in workers.getNotDownloadingAndNotFinishedWorkers(): + if w.cardMedia.path == path: + media_collection_treeview.removeCard(w.thread_id) + self.selection_vbox.selection_treeview.clear_all(w.thread_id) + workers.disableWorker(w.thread_id) + + downloading_workers = [] + for w in workers.getDownloadingWorkers(): + downloading_workers.append(w) + + for w in downloading_workers: + if w.cardMedia.path == path: + # the user is trying to backup to a device that is currently being downloaded from..... we don't normally allow that, but what to do? + cmd_line(_("Warning: backup device %(device)s is currently being downloaded from") % {'device': volume.get_name(limit=0)}) + + self.backupVolumes[path] = volume + + self.rapid_statusbar.push(self.statusbar_context_id, self.displayBackupVolumes()) + + + def _setupDownloadbuttons(self): self.download_hbutton_box = gtk.HButtonBox() + self.download_hbutton_box.set_spacing(12) + self.download_hbutton_box.set_homogeneous(False) + + help_button = gtk.Button(stock=gtk.STOCK_HELP) + help_button.connect("clicked", self.on_help_button_clicked) + self.download_hbutton_box.pack_start(help_button) + self.download_hbutton_box.set_child_secondary(help_button, True) + + self.DOWNLOAD_SELECTED_LABEL = _("D_ownload Selected") self.download_button_is_download = True self.download_button = gtk.Button() self.download_button.set_use_underline(True) self.download_button.set_flags(gtk.CAN_DEFAULT) + self.download_selected_button = gtk.Button() + self.download_selected_button.set_use_underline(True) self._set_download_button() self.download_button.connect('clicked', self.on_download_button_clicked) - self.download_hbutton_box.set_layout(gtk.BUTTONBOX_START) + self.download_selected_button.connect('clicked', self.on_download_selected_button_clicked) + self.download_hbutton_box.set_layout(gtk.BUTTONBOX_END) + self.download_hbutton_box.pack_start(self.download_selected_button) self.download_hbutton_box.pack_start(self.download_button) self.download_hbutton_box.show_all() self.buttons_hbox.pack_start(self.download_hbutton_box, @@ -3914,14 +5549,16 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.setDownloadButtonSensitivity() - - def set_display_thumbnails(self, value): + def set_display_selection(self, value): if value: - self.image_scrolledwindow.show_all() + self.selection_vbox.preview_table.show_all() else: - self.image_scrolledwindow.hide() - - + self.selection_vbox.preview_table.hide() + self.selection_vbox.set_display_preview_folders(self.prefs.display_preview_folders) + + def set_display_preview_folders(self, value): + self.selection_vbox.set_display_preview_folders(value) + def _resetDownloadInfo(self): self.markSet = False self.startTime = None @@ -3947,28 +5584,29 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.timeMark = self.startTime self.sizeMark = 0 - def startOrResumeWorkers(self): + def startOrResumeWorkers(self, threads): # resume any paused workers for w in workers.getPausedDownloadingWorkers(): w.startStop() self.timeRemaining.setTimeMark(w) - #start any new workers - workers.startDownloadingWorkers() + #start any new workers that have downloads pending + for i in threads: + workers[i].startStop() - if is_beta and verbose: + if is_beta and verbose and False: workers.printWorkerStatus() - def updateOverallProgress(self, thread_id, imageSize, percentComplete): + def updateOverallProgress(self, thread_id, bytesDownloaded, percentComplete): """ Updates progress bar and status bar text with time remaining to download images """ - self.totalDownloadedSoFar += imageSize - self.totalDownloadedSoFarThisRun += imageSize + self.totalDownloadedSoFar += bytesDownloaded + self.totalDownloadedSoFarThisRun += bytesDownloaded fraction = self.totalDownloadedSoFar / float(self.totalDownloadSize) @@ -3985,12 +5623,13 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self._set_download_button() self.setDownloadButtonSensitivity() cmd_line(_("All downloads complete")) - if is_beta and verbose: + job_code = None + if is_beta and verbose and False: workers.printWorkerStatus() else: now = time.time() - self.timeRemaining.update(thread_id, imageSize) + self.timeRemaining.update(thread_id, bytesDownloaded) if now > (self.downloadTimeGap + self.timeMark): amtTime = now - self.timeMark @@ -4035,22 +5674,43 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): if self.displayDownloadSummaryNotification: message = _("All downloads complete") if self.downloadStats.noImagesDownloaded: - message += "\n%s " % self.downloadStats.noImagesDownloaded + _("photos downloaded") + filetype = file_types_by_number(self.downloadStats.noImagesDownloaded, 0) + message += "\n" + _("%(number)s %(numberdownloaded)s") % \ + {'number': self.downloadStats.noImagesDownloaded, + 'numberdownloaded': _("%(filetype)s downloaded") % \ + {'filetype': filetype}} if self.downloadStats.noImagesSkipped: - message = "%s\n%s " % (message, self.downloadStats.noImagesSkipped) + _("photos skipped") + filetype = file_types_by_number(self.downloadStats.noImagesSkipped, 0) + message += "\n" + _("%(number)s %(numberdownloaded)s") % \ + {'number': self.downloadStats.noImagesSkipped, + 'numberdownloaded': _("%(filetype)s failed to download") % \ + {'filetype': filetype}} if self.downloadStats.noVideosDownloaded: - message += "\n%s " % self.downloadStats.noVideosDownloaded + _("videos downloaded") + filetype = file_types_by_number(0, self.downloadStats.noVideosDownloaded) + message += "\n" + _("%(number)s %(numberdownloaded)s") % \ + {'number': self.downloadStats.noVideosDownloaded, + 'numberdownloaded': _("%(filetype)s downloaded") % \ + {'filetype': filetype}} if self.downloadStats.noVideosSkipped: - message = "%s\n%s " % (message, self.downloadStats.noVideosSkipped) + _("videos skipped") + filetype = file_types_by_number(0, self.downloadStats.noVideosSkipped) + message += "\n" + _("%(number)s %(numberdownloaded)s") % \ + {'number': self.downloadStats.noVideosSkipped, + 'numberdownloaded': _("%(filetype)s failed to download") % \ + {'filetype': filetype}} if self.downloadStats.noWarnings: - message = "%s\n%s " % (message, self.downloadStats.noWarnings) + _("warnings") + message += "\n" + _("%(number)s %(numberdownloaded)s") % \ + {'number': self.downloadStats.noWarnings, + 'numberdownloaded': _("warnings")} if self.downloadStats.noErrors: - message = "%s\n%s " % (message, self.downloadStats.noErrors) +_("errors") + message += "\n" + _("%(number)s %(numberdownloaded)s") % \ + {'number': self.downloadStats.noErrors, + 'numberdownloaded': _("errors")} + n = pynotify.Notification(PROGRAM_NAME, message) n.set_icon_from_pixbuf(self.application_icon) n.show() self.displayDownloadSummaryNotification = False # don't show it again unless needed - self.downloadStats.clear() + # download statistics are cleared in exitOnDownloadComplete() self._resetDownloadInfo() self.speed_label.set_text(' ') @@ -4060,6 +5720,9 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): if self.prefs.auto_exit: if not (self.downloadStats.noErrors or self.downloadStats.noWarnings): self.quit() + # since for whatever reason am not exiting, clear the download statistics + self.downloadStats.clear() + def downloadFailed(self, thread_id): if workers.noDownloadingWorkers() == 0: @@ -4072,13 +5735,19 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): def setDownloadButtonSensitivity(self): - isSensitive = workers.noReadyToDownloadWorkers() > 0 or workers.noDownloadingWorkers() > 0 + isSensitive = (workers.noReadyToDownloadWorkers() > 0 and + workers.noScanningWorkers() == 0 and + self.selection_vbox.selection_treeview.rows_available_for_download()) or \ + workers.noDownloadingWorkers() > 0 if isSensitive: self.download_button.props.sensitive = True + # download selected button sensitity is enabled only when the user selects something + self.selection_vbox.selection_treeview.update_download_selected_button() self.menu_download_pause.props.sensitive = True else: self.download_button.props.sensitive = False + self.download_selected_button.props.sensitive = False self.menu_download_pause.props.sensitive = False return isSensitive @@ -4086,6 +5755,15 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): def on_rapidapp_destroy(self, widget): """Called when the application is going to quit""" + + # save window and component sizes + self.prefs.hpaned_pos = self.selection_vbox.file_hpaned.get_position() + self.prefs.vpaned_pos = self.main_vpaned.get_position() + + x, y = self.rapidapp.get_size() + self.prefs.main_window_size_x = x + self.prefs.main_window_size_y = y + workers.quitAllWorkers() self.flushevents() @@ -4093,10 +5771,20 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): display_queue.close("w") + def on_rapidapp_window_state_event(self, widget, event): + """ Checkto see if the user maximized the main application window or not. """ + if event.changed_mask & gdk.WINDOW_STATE_MAXIMIZED: + self.prefs.main_window_maximized = event.new_window_state & gdk.WINDOW_STATE_MAXIMIZED + + def on_menu_clear_activate(self, widget): self.clearCompletedDownloads() widget.set_sensitive(False) + def on_menu_refresh_activate(self, widget): + self.selection_vbox.selection_treeview.clear_all() + self.setupAvailableImageAndBackupMedia(onStartup = False, onPreferenceChange = True, doNotAllowAutoStart = True) + def on_menu_report_problem_activate(self, widget): webbrowser.open("https://bugs.launchpad.net/rapid") @@ -4122,8 +5810,30 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): else: log_dialog.widget.hide() - def on_menu_display_thumbnails_toggled(self, check_button): - self.prefs.display_thumbnails = check_button.get_active() + def on_menu_display_selection_toggled(self, check_button): + self.prefs.display_selection = check_button.get_active() + + def on_menu_preview_folders_toggled(self, check_button): + self.prefs.display_preview_folders = check_button.get_active() + + def on_menu_select_all_activate(self, widget): + self.selection_vbox.selection_treeview.select_rows('all') + + def on_menu_select_all_photos_activate(self, widget): + self.selection_vbox.selection_treeview.select_rows('photos') + + def on_menu_select_all_videos_activate(self, widget): + self.selection_vbox.selection_treeview.select_rows('videos') + + def on_menu_select_none_activate(self, widget): + self.selection_vbox.selection_treeview.select_rows('none') + + def on_menu_select_all_with_job_code_activate(self, widget): + self.selection_vbox.selection_treeview.select_rows('withjobcode') + + def on_menu_select_all_without_job_code_activate(self, widget): + self.selection_vbox.selection_treeview.select_rows('withoutjobcode') + def on_menu_about_activate(self, widget): """ Display about dialog box """ @@ -4138,20 +5848,35 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): """ Sets download button to appropriate state """ + if self.download_button_is_download: # This text will be displayed to the user on the Download / Pause button. - # Please note the space at the end of the label - it is needed to meet the Gnome Human Interface Guidelines - self.download_button.set_label(_("_Download ")) + self.download_selected_button.set_label(self.DOWNLOAD_SELECTED_LABEL) + self.download_selected_button.set_image(gtk.image_new_from_stock( + gtk.STOCK_CONVERT, + gtk.ICON_SIZE_BUTTON)) + self.selection_vbox.selection_treeview.update_download_selected_button() + self.download_button.set_image(gtk.image_new_from_stock( gtk.STOCK_CONVERT, - gtk.ICON_SIZE_BUTTON)) + gtk.ICON_SIZE_BUTTON)) + + if workers.noPausedWorkers(): + self.download_button.set_label(_("_Resume")) + self.download_selected_button.hide() + else: + self.download_button.set_label(_("_Download All")) + self.download_selected_button.show_all() + else: # button should indicate paused state self.download_button.set_image(gtk.image_new_from_stock( gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_BUTTON)) # This text will be displayed to the user on the Download / Pause button. - self.download_button.set_label(_("_Pause") + " ") + self.download_button.set_label(_("_Pause")) + self.download_selected_button.set_sensitive(False) + self.download_selected_button.hide() def on_menu_download_pause_activate(self, widget): self.on_download_button_clicked(widget) @@ -4160,8 +5885,6 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): if workers.noReadyToStartWorkers() > 0: workers.startWorkers() - - def postStartDownloadTasks(self): if workers.noDownloadingWorkers() > 1: self.displayDownloadSummaryNotification = True @@ -4170,8 +5893,8 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): self.download_button_is_download = False self._set_download_button() - def startDownload(self): - self.startOrResumeWorkers() + def startDownload(self, threads): + self.startOrResumeWorkers(threads) self.postStartDownloadTasks() def pauseDownload(self): @@ -4186,55 +5909,141 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object): """ Handle download button click. - Button is in one of two states: download, or pause. + Button is in one of three states: download all, resume, or pause. If download, a click indicates to start or resume a download run. If pause, a click indicates to pause all running downloads. """ if self.download_button_is_download: - if need_job_code and job_code == None and not self.prompting_for_job_code: - self.getJobCode(autoStart=False) + if need_job_code_for_renaming and self.selection_vbox.selection_treeview.job_code_missing(False) and not self.prompting_for_job_code: + self.getJobCode(autoStart=False, downloadSelected=False) else: - self.startDownload() + threads = self.selection_vbox.selection_treeview.set_status_to_download_pending(selected_only = False) + self.startDownload(threads) + self._set_download_button() else: self.pauseDownload() + + def on_download_selected_button_clicked(self, widget): + # set the status of the selected workers to be downloading pending + if need_job_code_for_renaming and self.selection_vbox.selection_treeview.job_code_missing(True) and not self.prompting_for_job_code: + self.getJobCode(autoStart=False, downloadSelected=True) + else: + threads = self.selection_vbox.selection_treeview.set_status_to_download_pending(selected_only = True) + self.startDownload(threads) + + + + def on_help_button_clicked(self, widget): + webbrowser.open("http://www.damonlynch.net/rapid/help.html") def on_preference_changed(self, key, value): """ Called when user changes the program's preferences """ - if key == 'display_thumbnails': - self.set_display_thumbnails(value) + if key == 'display_selection': + self.set_display_selection(value) + elif key == 'display_preview_folders': + self.set_display_preview_folders(value) elif key == 'show_log_dialog': self.menu_log_window.set_active(value) - elif key in ['device_autodetection', 'device_autodetection_psd', 'backup_images', 'device_location', - 'backup_device_autodetection', 'backup_location' ]: - self.rerunSetupAvailableImageAndBackupMedia = True + elif key in ['device_autodetection', 'device_autodetection_psd', 'device_location']: + self.rerunSetupAvailableImageAndVideoMedia = True + if not self.preferencesDialogDisplayed: + self.postPreferenceChange() + + elif key in ['backup_images', 'backup_device_autodetection', 'backup_location', 'backup_identifier', 'video_backup_identifier']: + self.rerunSetupAvailableBackupMedia = True if not self.preferencesDialogDisplayed: self.postPreferenceChange() elif key in ['subfolder', 'image_rename', 'video_subfolder', 'video_rename']: - global need_job_code - need_job_code = self.needJobCode() + global need_job_code_for_renaming + need_job_code_for_renaming = self.needJobCodeForRenaming() + self.selection_vbox.set_job_code_display() + self.menu_select_all_without_job_code.set_sensitive(need_job_code_for_renaming) + self.menu_select_all_with_job_code.set_sensitive(need_job_code_for_renaming) + self.refreshGeneratedSampleSubfolderAndName = True + + if not self.preferencesDialogDisplayed: + self.postPreferenceChange() + + elif key in ['download_folder', 'video_download_folder']: + self.refreshSampleDownloadFolder = True + if not self.preferencesDialogDisplayed: + self.postPreferenceChange() + + elif key == 'job_codes': + # update job code list in left pane + self.selection_vbox.update_job_code_combo() + def postPreferenceChange(self): """ Handle changes in program preferences after the preferences dialog window has been closed """ - if self.rerunSetupAvailableImageAndBackupMedia: + if self.rerunSetupAvailableImageAndVideoMedia: if self.usingVolumeMonitor(): self.startVolumeMonitor() - cmd_line("\n" + _("Preferences were changed.")) - - self.setupAvailableImageAndBackupMedia(onStartup = False, onPreferenceChange = True, doNotAllowAutoStart = False) - if is_beta and verbose: - print "Current worker status:" + cmd_line("\n" + _("Download device settings preferences were changed.")) + + self.selection_vbox.selection_treeview.clear_all() + self.setupAvailableImageAndBackupMedia(onStartup = False, onPreferenceChange = True, doNotAllowAutoStart = True) + if is_beta and verbose and False: workers.printWorkerStatus() - self.rerunSetupAvailableImageAndBackupMedia = False + self.rerunSetupAvailableImageAndVideoMedia = False + + if self.rerunSetupAvailableBackupMedia: + if self.usingVolumeMonitor(): + self.startVolumeMonitor() + cmd_line("\n" + _("Backup preferences were changed.")) + + self.refreshBackupMedia() + self.rerunSetupAvailableBackupMedia = False + + if self.refreshGeneratedSampleSubfolderAndName: + cmd_line("\n" + _("Subfolder and filename preferences were changed.")) + for w in workers.getScanningWorkers(): + if not w.scanResultsStale: + w.scanResultsStale = True + self.noAfterScanRefreshGeneratedSampleSubfolderAndName += 1 + + self.selection_vbox.selection_treeview.refreshGeneratedSampleSubfolderAndName() + self.refreshGeneratedSampleSubfolderAndName = False + self.setDownloadButtonSensitivity() + + if self.refreshSampleDownloadFolder: + cmd_line("\n" + _("Download folder preferences were changed.")) + for w in workers.getScanningWorkers(): + if not w.scanResultsStaleDownloadFolder: + w.scanResultsStaleDownloadFolder = True + self.noAfterScanRefreshSampleDownloadFolders += 1 + + self.selection_vbox.selection_treeview.refreshSampleDownloadFolders() + self.refreshSampleDownloadFolder = False + def regenerateScannedDevices(self, thread_id): + """ + Regenerate the filenames / subfolders / download folders for this thread + + The user must have adjusted their preferences as the device was being scanned + """ + + if self.noAfterScanRefreshSampleDownloadFolders: + # no point updating it if we're going to update it in the + # refresh of sample names and subfolders anway! + if not self.noAfterScanRefreshGeneratedSampleSubfolderAndName: + self.selection_vbox.selection_treeview.refreshSampleDownloadFolders(thread_id) + self.noAfterScanRefreshSampleDownloadFolders -= 1 + + if self.noAfterScanRefreshGeneratedSampleSubfolderAndName: + self.selection_vbox.selection_treeview.refreshGeneratedSampleSubfolderAndName(thread_id) + self.noAfterScanRefreshGeneratedSampleSubfolderAndName -= 1 + + def on_error_eventbox_button_press_event(self, widget, event): self.prefs.show_log_dialog = True @@ -4264,7 +6073,6 @@ class Volume: """ Transistion to gvfs from gnomevfs""" def __init__(self, volume): self.volume = volume - self.using_gio = using_gio def get_name(self, limit=config.MAX_LENGTH_DEVICE_NAME): if using_gio: @@ -4296,25 +6104,7 @@ class Volume: def get_icon_pixbuf(self, size): """ returns icon for the volume, or None if not available""" - icontheme = gtk.icon_theme_get_default() - - if using_gio: - gicon = self.volume.get_icon() - f = None - if isinstance(gicon, gio.ThemedIcon): - try: - # on some user's systems, themes do not have icons associated with them - iconinfo = icontheme.choose_icon(gicon.get_names(), size, gtk.ICON_LOOKUP_USE_BUILTIN) - f = iconinfo.get_filename() - v = gtk.gdk.pixbuf_new_from_file_at_size(f, size, size) - except: - f = None - if not f: - v = icontheme.load_icon('gtk-harddisk', size, gtk.ICON_LOOKUP_USE_BUILTIN) - else: - gicon = self.volume.get_icon() - v = icontheme.load_icon(gicon, size, gtk.ICON_LOOKUP_USE_BUILTIN) - return v + return common.get_icon_pixbuf(using_gio, self.volume.get_icon(), size) def unmount(self, callback): self.volume.unmount(callback) @@ -4323,7 +6113,7 @@ class DownloadStats: def __init__(self): self.clear() - def adjust(self, size, noImagesDownloaded, noVideosDownloaded, noImagesSkipped, noVideosSkipped, noWarnings, noErrors): + def adjust(self, size, noImagesDownloaded, noVideosDownloaded, noImagesSkipped, noVideosSkipped, noWarnings, noErrors): self.downloadSize += size self.noImagesDownloaded += noImagesDownloaded self.noVideosDownloaded += noVideosDownloaded @@ -4381,15 +6171,14 @@ class TimeRemaining: def __init__(self): self.clear() - def add(self, w, size): - if w not in self.times: - t = TimeForDownload() - t.timeRemaining = None - t.size = size - t.downloaded = 0 - t.sizeMark = 0 - t.timeMark = time.time() - self.times[w] = t + def set(self, w, size): + t = TimeForDownload() + t.timeRemaining = None + t.size = size + t.downloaded = 0 + t.sizeMark = 0 + t.timeMark = time.time() + self.times[w] = t def update(self, w, size): if w in self.times: @@ -4401,9 +6190,10 @@ class TimeRemaining: self.times[w].timeMark = now amtDownloaded = self.times[w].downloaded - self.times[w].sizeMark self.times[w].sizeMark = self.times[w].downloaded - timefraction = amtDownloaded / amtTime + timefraction = amtDownloaded / float(amtTime) amtToDownload = float(self.times[w].size) - self.times[w].downloaded - self.times[w].timeRemaining = amtToDownload / timefraction + if timefraction: + self.times[w].timeRemaining = amtToDownload / timefraction def _timeEstimates(self): for t in self.times: diff --git a/rapid/renamesubfolderprefs.py b/rapid/renamesubfolderprefs.py index feb7366..727eef0 100644 --- a/rapid/renamesubfolderprefs.py +++ b/rapid/renamesubfolderprefs.py @@ -68,6 +68,8 @@ import ValidatedEntry import config from common import pythonifyVersion +import problemnotification as pn + # Special key in each dictionary which specifies the order of elements. # It is very important to have a consistent and rational order when displaying @@ -649,7 +651,7 @@ def upgradePreferencesToCurrent(imageRenamePrefs, subfolderPrefs, previousVersio def usesJobCode(prefs): """ Returns True if the preferences contain a job code, else returns False""" - for i in range(0, len(prefs), 3): + for i in range(0, len(prefs), 3): if prefs[i] == JOB_CODE: return True return False @@ -834,7 +836,7 @@ class Comboi18n(gtk.ComboBox): def append_text(self, text): model = self.get_model() - model.append((text, _(text))) + model.append((text, _(text))) def get_active_text(self): model = self.get_model() @@ -870,8 +872,23 @@ class ImageRenamePreferences: self.defaultRow = self.defaultPrefs self.stripForwardSlash = True self.L1DateCheck = IMAGE_DATE #used in _getDateComponent() + self.component = pn.FILENAME_COMPONENT + def initializeProblem(self, problem): + """ + Set the problem tracker used in name generation + """ + self.problem = problem + + def getProblems(self): + """ + Returns Problem class if there were problems, else returns None. + """ + if self.problem.has_problem(): + return self.problem + else: + return None def checkPrefsForValidity(self): """ @@ -905,40 +922,24 @@ class ImageRenamePreferences: self.job_code = job_code - def _fixMangledDateTime(self, d): - """ Some EXIF dates are badly formed. Try to fix them """ - - _datetime = d.strip() - # remove any weird characters at the end of the string - while _datetime and not _datetime[-1].isdigit(): - _datetime = _datetime[:-1] - _date, _time = _datetime.split(' ') - _datetime = "%s %s" % (_date.replace(":", "-") , _time.replace("-", ":")) - try: - d = datetime.datetime.strptime(_datetime, '%Y-%m-%d %H:%M:%S') - except: - d = None - return d - + def _getDateComponent(self): """ Returns portion of new image / subfolder name based on date time. If the date is missing, will attempt to use the fallback date. """ - problem = None - + # step 1: get the correct value from metadata if self.L1 == self.L1DateCheck: if self.L2 == SUBSECONDS: - d = self.photo.subSeconds() - problem = _("Subsecond metadata not present in photo") + d = self.metadata.subSeconds() if d == '00': - return ('', problem) + self.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L2)) + return '' else: - return (d, None) + return d else: - d = self.photo.dateTime(missing=None) - problem = _("%s metadata is not present") % self.L1.lower() + d = self.metadata.dateTime(missing=None) elif self.L1 == TODAY: d = datetime.datetime.now() @@ -948,34 +949,23 @@ class ImageRenamePreferences: else: raise("Date options invalid") - if d: - # if format is not the standard floating point representation - # of a date time, there is a problem - if type(d) == type('string'): - # will be a string only if the date time could not be converted in the datetime type - # try to massage badly formed date / times into a valid value - d = self._fixMangledDateTime(d) - if d is None: - v = '' - problem = _('Error in date time component. Value %s appears invalid') % '' - return (v, problem) - else: + # step 2: handle a missing value + if not d: if self.fallback_date: try: d = datetime.datetime.fromtimestamp(self.fallback_date) except: - v = '' - problem = _('Error in date time component. Value %s appears invalid') % '' - return (v, problem) + self.problem.add_problem(self.component, pn.INVALID_DATE_TIME, '') + return '' else: - return ('', problem) + self.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L1)) + return '' try: - return (d.strftime(convertDateForStrftime(self.L2)), None) + return d.strftime(convertDateForStrftime(self.L2)) except: - v = '' - problem = _('Error in date time component. Value %s appears invalid') % d - return (v, problem) + self.problem.add_problem(self.component, pn.INVALID_DATE_TIME, d) + return '' def _getFilenameComponent(self): """ @@ -983,7 +973,6 @@ class ImageRenamePreferences: """ name, extension = os.path.splitext(self.existingFilename) - problem = None if self.L1 == NAME_EXTENSION: filename = self.existingFilename @@ -1000,12 +989,13 @@ class ImageRenamePreferences: # is a bad idea! filename = extension[1:] else: - filename = "" - problem = _("extension was specified but filename does not have an extension") + self.problem.add_problem(self.component, pn.MISSING_FILE_EXTENSION) + return "" elif self.L1 == IMAGE_NUMBER or self.L1 == VIDEO_NUMBER: n = re.search("(?P<image_number>[0-9]+$)", name) if not n: - problem = _("image or video number was specified but filename has no number") + self.problem.add_problem(self.component, pn.MISSING_IMAGE_NUMBER) + return '' else: image_number = n.group("image_number") @@ -1027,7 +1017,7 @@ class ImageRenamePreferences: elif self.L2 == LOWERCASE: filename = filename.lower() - return (filename, problem) + return filename def _getMetadataComponent(self): """ @@ -1036,27 +1026,26 @@ class ImageRenamePreferences: Note: date time metadata found in _getDateComponent() """ - problem = None if self.L1 == APERTURE: - v = self.photo.aperture() + v = self.metadata.aperture() elif self.L1 == ISO: - v = self.photo.iso() + v = self.metadata.iso() elif self.L1 == EXPOSURE_TIME: - v = self.photo.exposureTime(alternativeFormat=True) + v = self.metadata.exposureTime(alternativeFormat=True) elif self.L1 == FOCAL_LENGTH: - v = self.photo.focalLength() + v = self.metadata.focalLength() elif self.L1 == CAMERA_MAKE: - v = self.photo.cameraMake() + v = self.metadata.cameraMake() elif self.L1 == CAMERA_MODEL: - v = self.photo.cameraModel() + v = self.metadata.cameraModel() elif self.L1 == SHORT_CAMERA_MODEL: - v = self.photo.shortCameraModel() + v = self.metadata.shortCameraModel() elif self.L1 == SHORT_CAMERA_MODEL_HYPHEN: - v = self.photo.shortCameraModel(includeCharacters = "\-") + v = self.metadata.shortCameraModel(includeCharacters = "\-") elif self.L1 == SERIAL_NUMBER: - v = self.photo.cameraSerial() + v = self.metadata.cameraSerial() elif self.L1 == SHUTTER_COUNT: - v = self.photo.shutterCount() + v = self.metadata.shutterCount() if v: v = int(v) padding = LIST_SHUTTER_COUNT_L2.index(self.L2) + 3 @@ -1064,7 +1053,7 @@ class ImageRenamePreferences: v = formatter % v elif self.L1 == OWNER_NAME: - v = self.photo.ownerName() + v = self.metadata.ownerName() else: raise TypeError("Invalid metadata option specified") if self.L1 in [CAMERA_MAKE, CAMERA_MODEL, SHORT_CAMERA_MODEL, @@ -1074,12 +1063,8 @@ class ImageRenamePreferences: elif self.L2 == LOWERCASE: v = v.lower() if not v: - if self.L1 <> ISO: - md = self.L1.lower() - else: - md = ISO - problem = _("%s metadata is not present in photo") % md - return (v, problem) + self.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L1)) + return v def _formatSequenceNo(self, value, amountToPad): @@ -1119,7 +1104,6 @@ class ImageRenamePreferences: than one subfolder sequence number in the same file name """ - problem = None self.subfolderSeqNoInstanceInFilename += 1 if self.downloadSubfolder: @@ -1135,33 +1119,23 @@ class ImageRenamePreferences: v = self.sequenceNos.calculate(subfolder) v = self.formatSequenceNo(v, self.L1) - return (v, problem) + return v def _getSessionSequenceNo(self): - problem = None - v = self._formatSequenceNo(self.sequences.getSessionSequenceNoUsingCounter(self.sequenceCounter), self.L2) - return (v, problem) + return self._formatSequenceNo(self.sequences.getSessionSequenceNoUsingCounter(self.sequenceCounter), self.L2) def _getDownloadsTodaySequenceNo(self): - problem = None - v = self._formatSequenceNo(self.sequences.getDownloadsTodayUsingCounter(self.sequenceCounter), self.L2) - - return (v, problem) + return self._formatSequenceNo(self.sequences.getDownloadsTodayUsingCounter(self.sequenceCounter), self.L2) + def _getStoredSequenceNo(self): - problem = None - v = self._formatSequenceNo(self.sequences.getStoredSequenceNoUsingCounter(self.sequenceCounter), self.L2) - - return (v, problem) + return self._formatSequenceNo(self.sequences.getStoredSequenceNoUsingCounter(self.sequenceCounter), self.L2) def _getSequenceLetter(self): + return self._calculateLetterSequence(self.sequences.getSequenceLetterUsingCounter(self.sequenceCounter)) - problem = None - v = self._calculateLetterSequence(self.sequences.getSequenceLetterUsingCounter(self.sequenceCounter)) - return (v, problem) def _getSequencesComponent(self): - problem = None if self.L1 == DOWNLOAD_SEQ_NUMBER: return self._getDownloadsTodaySequenceNo() elif self.L1 == SESSION_SEQ_NUMBER: @@ -1178,7 +1152,7 @@ class ImageRenamePreferences: if self.L0 == DATE_TIME: return self._getDateComponent() elif self.L0 == TEXT: - return (self.L1, None) + return self.L1 elif self.L0 == FILENAME: return self._getFilenameComponent() elif self.L0 == METADATA: @@ -1186,27 +1160,25 @@ class ImageRenamePreferences: elif self.L0 == SEQUENCES: return self._getSequencesComponent() elif self.L0 == JOB_CODE: - return (self.job_code, None) + return self.job_code elif self.L0 == SEPARATOR: - return (os.sep, None) + return os.sep except: - v = "" - problem = _("error generating name with component %s") % self.L0 - return (v, problem) - + self.problem.add_problem(self.component, pn.ERROR_IN_GENERATION, _(self.L0)) + return '' + def _getValuesFromList(self): for i in range(0, len(self.prefList), 3): yield (self.prefList[i], self.prefList[i+1], self.prefList[i+2]) - def _generateName(self, photo, existingFilename, stripCharacters, subfolder, stripInitialPeriodFromExtension, sequence, fallback_date): - self.photo = photo + def _generateName(self, metadata, existingFilename, stripCharacters, subfolder, stripInitialPeriodFromExtension, sequence, fallback_date): + self.metadata = metadata self.existingFilename = existingFilename self.stripInitialPeriodFromExtension = stripInitialPeriodFromExtension self.fallback_date = fallback_date name = '' - problem = '' #the subfolder in which the image will be downloaded to self.downloadSubfolder = subfolder @@ -1214,37 +1186,34 @@ class ImageRenamePreferences: self.sequenceCounter = sequence for self.L0, self.L1, self.L2 in self._getValuesFromList(): - v, p = self._getComponent() + v = self._getComponent() if v: name += v - if p: - problem += p + "; " - if problem: - # remove final semicolon and space - problem = problem[:-2] + '.' - if stripCharacters: for c in r'\:*?"<>|': name = name.replace(c, '') if self.stripForwardSlash: name = name.replace('/', '') + + name = name.strip() - return (name, problem) + return name - def generateNameUsingPreferences(self, photo, existingFilename=None, + def generateNameUsingPreferences(self, metadata, existingFilename=None, stripCharacters = False, subfolder=None, stripInitialPeriodFromExtension=False, sequencesPreliminary = True, sequence_to_use = None, fallback_date = None): """ - Generate a filename for the photo in string format based on user prefs. + Generate a filename for the photo or video in string format based on user preferences. - Returns a tuple of two strings: - - the name - - any problems generating the name. If blank, there were no problems + Returns the name in string format + + Any problems encountered during the generation of the name can be accessed + through the method getProblems() """ if self.sequences: @@ -1257,18 +1226,18 @@ class ImageRenamePreferences: else: sequence = 0 - return self._generateName(photo, existingFilename, stripCharacters, subfolder, - stripInitialPeriodFromExtension, sequence, fallback_date) + return self._generateName(metadata, existingFilename, stripCharacters, subfolder, + stripInitialPeriodFromExtension, sequence, fallback_date) - def generateNameSequencePossibilities(self, photo, existingFilename, + def generateNameSequencePossibilities(self, metadata, existingFilename, stripCharacters=False, subfolder=None, stripInitialPeriodFromExtension=False): """ Generates the possible image names using the sequence numbers / letter possibilities""" for sequence in self.sequences.getSequencePossibilities(): - yield self._generateName(photo, existingFilename, stripCharacters , subfolder, - stripInitialPeriodFromExtension, sequence) + yield self._generateName(metadata, existingFilename, stripCharacters, subfolder, + stripInitialPeriodFromExtension, sequence) def filterPreferences(self): """ @@ -1430,15 +1399,15 @@ def getVideoMetadataComponent(video): problem = None if video.L1 == CODEC: - v = video.photo.codec() + v = video.metadata.codec() elif video.L1 == WIDTH: - v = video.photo.width() + v = video.metadata.width() elif video.L1 == HEIGHT: - v = video.photo.height() + v = video.metadata.height() elif video.L1 == FPS: - v = video.photo.fps() + v = video.metadata.fps() elif video.L1 == LENGTH: - v = video.photo.length() + v = video.metadata.length() else: raise TypeError("Invalid metadata option specified") if video.L1 in [CODEC]: @@ -1447,8 +1416,8 @@ def getVideoMetadataComponent(video): elif video.L2 == LOWERCASE: v = v.lower() if not v: - problem = _("%s metadata is not present in video") % video.L1 - return (v, problem) + self.problem.add_problem(self.component, pn.MISSING_METADATA, _(video.L1)) + return v class VideoRenamePreferences(ImageRenamePreferences): def __init__(self, prefList, parent, fileSequenceLock=None, sequences=None): @@ -1457,6 +1426,7 @@ class VideoRenamePreferences(ImageRenamePreferences): self.defaultRow = self.defaultPrefs self.stripForwardSlash = True self.L1DateCheck = VIDEO_DATE + self.component = pn.FILENAME_COMPONENT ImageRenamePreferences.__init__(self, prefList, parent, fileSequenceLock, sequences) def _getMetadataComponent(self): @@ -1475,6 +1445,7 @@ class SubfolderPreferences(ImageRenamePreferences): self.defaultRow = [DATE_TIME, IMAGE_DATE, LIST_DATE_TIME_L2[0]] self.stripForwardSlash = False self.L1DateCheck = IMAGE_DATE + self.component = pn.SUBFOLDER_COMPONENT ImageRenamePreferences.__init__(self, prefList, parent) def generateNameUsingPreferences(self, photo, existingFilename=None, @@ -1487,7 +1458,7 @@ class SubfolderPreferences(ImageRenamePreferences): - any problems generating the name. If blank, there were no problems """ - subfolders, problem = ImageRenamePreferences.generateNameUsingPreferences( + subfolders = ImageRenamePreferences.generateNameUsingPreferences( self, photo, existingFilename, stripCharacters, stripInitialPeriodFromExtension=True, @@ -1499,7 +1470,7 @@ class SubfolderPreferences(ImageRenamePreferences): if subfolders[0] == os.sep: subfolders = subfolders[1:] - return (subfolders, problem) + return subfolders def filterPreferences(self): filtered, prefList = filterSubfolderPreferences(self.prefList) @@ -1561,6 +1532,7 @@ class VideoSubfolderPreferences(SubfolderPreferences): self.defaultPrefs = DEFAULT_VIDEO_SUBFOLDER_PREFS self.defaultRow = [DATE_TIME, VIDEO_DATE, LIST_DATE_TIME_L2[0]] self.L1DateCheck = VIDEO_DATE + self.component = pn.SUBFOLDER_COMPONENT def _getMetadataComponent(self): """ diff --git a/rapid/videometadata.py b/rapid/videometadata.py index 210da33..ab5d18c 100755 --- a/rapid/videometadata.py +++ b/rapid/videometadata.py @@ -27,6 +27,7 @@ import tempfile import gtk import media import paths +from filmstrip import add_filmstrip try: import kaa.metadata @@ -34,10 +35,13 @@ except ImportError: DOWNLOAD_VIDEO = False VIDEO_THUMBNAIL_FILE_EXTENSIONS = ['thm'] -VIDEO_FILE_EXTENSIONS = ['avi', 'mov', 'mp4'] +VIDEO_FILE_EXTENSIONS = ['avi', 'mov', 'mp4', 'mpg'] + + if DOWNLOAD_VIDEO: + try: subprocess.check_call(["ffmpegthumbnailer", "-h"], stdout=subprocess.PIPE) ffmpeg = True @@ -47,14 +51,31 @@ if DOWNLOAD_VIDEO: def version_info(): return str(kaa.metadata.VERSION) + + def get_video_THM_file(fullFileName): + """ + Checks to see if a thumbnail file (THM) is in the same directory as the + file. Expects a full path to be part of the file name. + + Returns the filename, including path, if found, else returns None. + """ + + f = None + name, ext = os.path.splitext(fullFileName) + for e in VIDEO_THUMBNAIL_FILE_EXTENSIONS: + if os.path.exists(name + '.' + e): + f = name + '.' + e + break + if os.path.exists(name + '.' + e.upper()): + f = name + '.' + e.upper() + break + + return f class VideoMetaData(): def __init__(self, filename): self.info = kaa.metadata.parse(filename) self.filename = filename - self.filmstrip = gtk.gdk.pixbuf_new_from_file(paths.share_dir('glade3/filmstrip-100x75.xpm')) - self.FILMSTRIP_WIDTH = 100 - self.FILMSTRIP_HEIGHT = 75 def rpd_keys(self): return self.info.keys() @@ -78,6 +99,17 @@ if DOWNLOAD_VIDEO: return missing else: return missing + + def timeStamp(self, missing=''): + """ + Returns a float value representing the time stamp, if it exists + """ + v = self._get('timestamp', missing=missing) + try: + v = float(v) + except: + v = missing + return v def codec(self, stream=0, missing=''): return self._get('codec', missing, stream) @@ -108,17 +140,24 @@ if DOWNLOAD_VIDEO: return self._get('fourcc', missing, stream) def getThumbnailData(self, size, tempWorkingDir): - thm = media.getVideoThumbnailFile(self.filename) + """ + Returns a pixbuf of the video's thumbnail + + If it cannot be created, returns None + """ + thm = get_video_THM_file(self.filename) if thm: - thumbnail = gtk.gdk.pixbuf_new_from_file_at_size(thm, size, size) - if thumbnail.get_width() <> self.FILMSTRIP_WIDTH or thumbnail.get_height() <> self.FILMSTRIP_HEIGHT: - thumbnail = thumbnail.scale_simple(self.FILMSTRIP_WIDTH, self.FILMSTRIP_HEIGHT, gtk.gdk.INTERP_BILINEAR) - - self.filmstrip.composite(thumbnail, 0, 0, self.filmstrip.props.width, self.filmstrip.props.height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 255) + thumbnail = gtk.gdk.pixbuf_new_from_file(thm) + aspect = float(thumbnail.get_height()) / thumbnail.get_width() + thumbnail = thumbnail.scale_simple(size, int(aspect*size), gtk.gdk.INTERP_BILINEAR) + thumbnail = add_filmstrip(thumbnail) else: if ffmpeg: - tmp = tempfile.NamedTemporaryFile(dir=tempWorkingDir, prefix="rpd-tmp") - tmp.close() + try: + tmp = tempfile.NamedTemporaryFile(dir=tempWorkingDir, prefix="rpd-tmp") + tmp.close() + except: + return None thm = os.path.join(tempWorkingDir, tmp.name) |