Beispiel #1
0
    def load_gpx_from_file(self, uri):
        """Parse GPX data, drawing each GPS track segment on the map."""
        start_time = clock()

        open_file = KMLFile if uri[-3:].lower() == 'kml' else GPXFile
        gpx = open_file(uri, self.progressbar)

        # Emitting this signal ensures the new tracks get the correct color.
        get_obj('colorselection').emit('color-changed')

        self.status_message(
            _('%d points loaded in %.2fs.') %
            (len(gpx.tracks), clock() - start_time), True)

        if len(gpx.tracks) < 2:
            return

        points.update(gpx.tracks)
        metadata.alpha = min(metadata.alpha, gpx.alpha)
        metadata.omega = max(metadata.omega, gpx.omega)

        map_view.emit('realize')
        map_view.set_zoom_level(map_view.get_max_zoom_level())
        bounds = Champlain.BoundingBox.new()
        for poly in polygons:
            bounds.compose(poly.get_bounding_box())
        gpx.latitude, gpx.longitude = bounds.get_center()
        map_view.ensure_visible(bounds, False)

        self.prefs.gpx_timezone = gpx.lookup_geoname()
        self.prefs.set_timezone()
        gpx_sensitivity()
    def __init__(self):
        """Start the map at the previous location, and connect signals."""
        perform_zoom = lambda button, zoom: zoom()
        back_button = get_obj('back_button')
        zoom_in_button = get_obj('zoom_in_button')
        zoom_out_button = get_obj('zoom_out_button')
        zoom_out_button.connect('clicked', perform_zoom, map_view.zoom_out)
        zoom_in_button.connect('clicked', perform_zoom, map_view.zoom_in)
        back_button.connect('clicked', go_back, map_view)

        for key in ['latitude', 'longitude', 'zoom-level']:
            gst.bind(key, map_view, key)

        accel = Gtk.AccelGroup()
        window = get_obj('main')
        window.add_accel_group(accel)
        for key in ['Left', 'Right', 'Up', 'Down']:
            accel.connect(Gdk.keyval_from_name(key),
                          Gdk.ModifierType.MOD1_MASK, 0, move_by_arrow_keys)

        map_view.connect('notify::zoom-level', zoom_button_sensitivity,
                         zoom_in_button.set_sensitive,
                         zoom_out_button.set_sensitive)
        map_view.connect('realize', remember_location)
        map_view.connect('animation-completed', set_window_title,
                         window.set_title, Coordinates())
        map_view.emit('animation-completed')
Beispiel #3
0
 def load_gpx_from_file(self, uri):
     """Parse GPX data, drawing each GPS track segment on the map."""
     start_time = clock()
     
     open_file = KMLFile if uri[-3:].lower() == 'kml' else GPXFile
     gpx = open_file(uri, self.progressbar)
     
     # Emitting this signal ensures the new tracks get the correct color.
     get_obj('colorselection').emit('color-changed')
     
     self.status_message(_('%d points loaded in %.2fs.') %
         (len(gpx.tracks), clock() - start_time), True)
     
     if len(gpx.tracks) < 2:
         return
     
     points.update(gpx.tracks)
     metadata.alpha = min(metadata.alpha, gpx.alpha)
     metadata.omega = max(metadata.omega, gpx.omega)
     
     map_view.emit('realize')
     map_view.set_zoom_level(map_view.get_max_zoom_level())
     bounds = Champlain.BoundingBox.new()
     for poly in polygons:
         bounds.compose(poly.get_bounding_box())
     gpx.latitude, gpx.longitude = bounds.get_center()
     map_view.ensure_visible(bounds, False)
     
     self.prefs.gpx_timezone = gpx.lookup_geoname()
     self.prefs.set_timezone()
     gpx_sensitivity()
Beispiel #4
0
 def __init__(self):
     """Start the map at the previous location, and connect signals."""
     perform_zoom    = lambda button, zoom: zoom()
     back_button     = get_obj('back_button')
     zoom_in_button  = get_obj('zoom_in_button')
     zoom_out_button = get_obj('zoom_out_button')
     zoom_out_button.connect('clicked', perform_zoom, map_view.zoom_out)
     zoom_in_button.connect('clicked', perform_zoom, map_view.zoom_in)
     back_button.connect('clicked', go_back, map_view)
     
     for key in ['latitude', 'longitude', 'zoom-level']:
         gst.bind(key, map_view, key)
     
     accel = Gtk.AccelGroup()
     window = get_obj('main')
     window.add_accel_group(accel)
     for key in [ 'Left', 'Right', 'Up', 'Down' ]:
         accel.connect(Gdk.keyval_from_name(key),
             Gdk.ModifierType.MOD1_MASK, 0, move_by_arrow_keys)
     
     map_view.connect('notify::zoom-level', zoom_button_sensitivity,
         zoom_in_button.set_sensitive, zoom_out_button.set_sensitive)
     map_view.connect('realize', remember_location)
     map_view.connect('animation-completed', set_window_title,
         window.set_title, Coordinates())
     map_view.emit('animation-completed')
Beispiel #5
0
 def __init__(self):
     self.selection  = get_obj('photos_view').get_selection()
     self.selection.set_mode(Gtk.SelectionMode.MULTIPLE)
     self.layer = Champlain.MarkerLayer()
     map_view.add_layer(self.layer)
     
     self.selection.connect('changed', update_highlights)
     self.selection.connect('changed', selection_sensitivity,
         *[get_obj(name) for name in ('close_button',
             'save_button', 'revert_button', 'jump_button')])
Beispiel #6
0
 def __init__(self, camera_id, make, model):
     """Generate Gtk widgets and bind their properties to GSettings."""
     self.photos = set()
     
     empty_camera_label.hide()
     
     builder = Builder('camera')
     builder.get_object('camera_label').set_text(model)
     
     # GtkScale allows the user to correct the camera's clock.
     offset = builder.get_object('offset')
     offset.connect('value-changed', self.offset_handler)
     offset.connect('format-value', display_offset,
         _('Add %dm, %ds to clock.'),
         _('Subtract %dm, %ds from clock.'))
     
     # These two ComboBoxTexts are used for choosing the timezone manually.
     # They're hidden to reduce clutter when not needed.
     tz_region = builder.get_object('timezone_region')
     tz_cities = builder.get_object('timezone_cities')
     for name in tz_regions:
         tz_region.append(name, name)
     tz_region.connect('changed', self.region_handler, tz_cities)
     tz_cities.connect('changed', self.cities_handler)
     
     # TODO we're gonna need some on screen help to explain what it even
     # means to select the method of determining the timezone.
     # Back when this was radio button in a preferences window we had more
     # room for verbosity, but this combobox is *so terse* that I don't
     # really expect anybody to understand it at all.
     timezone = builder.get_object('timezone_method')
     timezone.connect('changed', self.method_handler, tz_region, tz_cities)
     
     # Push all the widgets into the UI
     get_obj('cameras_view').attach_next_to(
         builder.get_object('camera_settings'), None, BOTTOM, 1, 1)
     
     self.offset    = offset
     self.tz_method = timezone
     self.tz_region = tz_region
     self.tz_cities = tz_cities
     self.camera_id = camera_id
     self.make      = make
     self.model     = model
     
     self.gst = GSettings('camera', camera_id)
     
     self.gst.set_string('make', make)
     self.gst.set_string('model', model)
     
     self.gst.bind('offset', offset.get_adjustment(), 'value')
     self.gst.bind('timezone-method', timezone, 'active-id')
     self.gst.bind('timezone-region', tz_region, 'active')
     self.gst.bind('timezone-cities', tz_cities, 'active')
Beispiel #7
0
    def __init__(self):
        self.select_all = get_obj('select_all_button')
        self.selection = get_obj('photos_view').get_selection()
        self.selection.set_mode(Gtk.SelectionMode.MULTIPLE)
        self.layer = Champlain.MarkerLayer()
        map_view.add_layer(self.layer)

        self.selection.connect('changed', update_highlights)
        self.selection.connect(
            'changed', selection_sensitivity, *[
                get_obj(name) for name in ('apply_button', 'close_button',
                                           'save_button', 'revert_button')
            ])
Beispiel #8
0
 def __init__(self):
     """Make the search box and insert it into the window."""
     self.search = None
     self.results = get_obj('search_results')
     self.slide_to = map_view.go_to
     search = get_obj('search_completion')
     search.set_match_func(
         lambda c, s, itr, get: self.search(get(itr, LOCATION) or ''),
         self.results.get_value)
     search.connect('match-selected', self.search_completed, map_view)
     entry = get_obj('search_box')
     entry.connect('changed', self.load_results, self.results.append)
     entry.connect('icon-release', lambda entry, i, e: entry.set_text(''))
     entry.connect('activate', self.repeat_last_search,
                   self.results, map_view)
Beispiel #9
0
 def __init__(self):
     """Make the search box and insert it into the window."""
     self.search = None
     self.results = get_obj('search_results')
     self.slide_to = map_view.go_to
     search = get_obj('search_completion')
     search.set_match_func(
         lambda c, s, itr, get: self.search(get(itr, LOCATION) or ''),
         self.results.get_value)
     search.connect('match-selected', self.search_completed, map_view)
     entry = get_obj('search_box')
     entry.connect('changed', self.load_results, self.results.append)
     entry.connect('icon-release', lambda entry, i, e: entry.set_text(''))
     entry.connect('activate', self.repeat_last_search, self.results,
                   map_view)
Beispiel #10
0
 def __init__(self):
     self.black = Clutter.Box.new(Clutter.BinLayout())
     self.black.set_color(Clutter.Color.new(0, 0, 0, 96))
     self.label = Clutter.Text()
     self.label.set_color(Clutter.Color.new(255, 255, 255, 255))
     self.xhair = Clutter.Rectangle.new_with_color(
         Clutter.Color.new(0, 0, 0, 64))
     for signal in [ 'latitude', 'longitude' ]:
         map_view.connect('notify::' + signal, display,
             get_obj('maps_link'), self.label)
     map_view.connect('notify::width',
         lambda view, param, black:
             black.set_size(view.get_width(), 30),
         self.black)
     
     scale = Champlain.Scale.new()
     scale.connect_view(map_view)
     gst.bind('show-map-scale', scale, 'visible')
     gst.bind('show-map-center', self.xhair, 'visible')
     gst.bind('show-map-coords', self.black, 'visible')
     map_view.bin_layout_add(scale,
         Clutter.BinAlignment.START, Clutter.BinAlignment.END)
     map_view.bin_layout_add(self.black,
         Clutter.BinAlignment.START, Clutter.BinAlignment.START)
     self.black.get_layout_manager().add(self.label,
         Clutter.BinAlignment.CENTER, Clutter.BinAlignment.CENTER)
     
     map_source_menu()
Beispiel #11
0
 def __init__(self, filename, root, watch):
     self.filename = filename
     self.progress = get_obj('progressbar')
     self.clock    = clock()
     self.append   = None
     self.tracks   = {}
     self.polygons = set()
     
     self.parser = XMLSimpleParser(root, watch)
     self.parser.parse(filename, self.element_start, self.element_end)
     
     empty_trackfile_label.hide()
     
     points.update(self.tracks)
     keys = self.tracks.keys()
     self.alpha = min(keys)
     self.omega = max(keys)
     self.latitude = self.tracks[self.alpha].lat
     self.longitude = self.tracks[self.alpha].lon
     
     # TODO find some kind of parent widget that can group these together
     # to make it easier to get them and insert them into places.
     builder = Builder('trackfile')
     self.colorpicker = builder.get_object('colorpicker')
     self.trash = builder.get_object('unload')
     self.label = builder.get_object('trackfile_label')
     
     self.label.set_text(basename(filename))
     self.colorpicker.set_title(basename(filename))
     self.colorpicker.connect('color-set', track_color_changed, self.polygons)
     self.trash.connect('clicked', self.destroy)
     
     get_obj('trackfiles_view').attach_next_to(
         builder.get_object('trackfile_settings'), None, BOTTOM, 1, 1)
     
     self.gst = GSettings('trackfile', basename(filename))
     
     if self.gst.get_string('start-timezone') is '':
         # Then this is the first time this file has been loaded
         # and we should honor the user-selected global default
         # track color instead of using the schema-defined default
         self.gst.set_value('track-color', gst.get_value('track-color'))
     
     self.gst.set_string('start-timezone', self.lookup_geoname())
     self.gst.bind_with_convert('track-color', self.colorpicker, 'color',
         lambda x: Gdk.Color(*x), lambda x: (x.red, x.green, x.blue))
     self.colorpicker.emit('color-set')
Beispiel #12
0
 def __init__(self):
     self.region = region = get_obj('timezone_region')
     self.cities = cities = get_obj('timezone_cities')
     pref_button = get_obj('pref_button')
     
     for name in tz_regions:
         region.append(name, name)
     region.connect('changed', self.region_handler, cities)
     cities.connect('changed', self.cities_handler)
     gst.bind('timezone-region', region, 'active')
     gst.bind('timezone-cities', cities, 'active')
     
     self.colorpicker = get_obj('colorselection')
     gst.bind_with_convert('track-color', self.colorpicker, 'current-color',
         lambda x: Gdk.Color(*x), lambda x: (x.red, x.green, x.blue))
     self.colorpicker.connect('color-changed', self.track_color_changed)
     
     pref_button.connect('clicked', self.preferences_dialog,
         get_obj('preferences'), region, cities, self.colorpicker)
     
     self.radios = {}
     for option in ['system', 'lookup', 'custom']:
         option += '-timezone'
         radio = get_obj(option)
         radio.set_name(option)
         gst.bind(option, radio, 'active')
         self.radios[option] = radio
         radio.connect('clicked', self.radio_handler)
     gst.bind('custom-timezone', get_obj('custom_timezone_combos'),
              'sensitive')
     
     gst.bind('use-dark-theme', Gtk.Settings.get_default(),
              'gtk-application-prefer-dark-theme')
     
     map_source_menu()
Beispiel #13
0
 def __init__(self, open_files):
     # Drag source definitons
     photos_view = get_obj('photos_view')
     photos_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
         [], Gdk.DragAction.COPY)
     photos_view.drag_source_add_text_targets()
     photos_view.connect('drag-data-get', self.photo_drag_start)
     
     # Drag destination defintions
     photos_view.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
     photos_view.drag_dest_add_text_targets()
     photos_view.connect('drag-data-received', self.photo_drag_end, False)
     
     container = get_obj('map_container')
     container.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
     container.drag_dest_add_text_targets()
     container.connect('drag-data-received', self.photo_drag_end, True)
     
     self.external_drag = True
     self.selection = photos_view.get_selection()
     self.open_files = open_files
Beispiel #14
0
 def confirm_quit_dialog(self, *args):
     """Teardown method, inform user of unsaved files, if any."""
     if len(modified) == 0:
         Gtk.main_quit()
         return True
     dialog = get_obj('quit')
     dialog.format_secondary_markup(self.strings.quit % len(modified))
     response = dialog.run()
     dialog.hide()
     self.redraw_interface()
     if response == Gtk.ResponseType.ACCEPT: self.save_all_files()
     if response != Gtk.ResponseType.CANCEL: Gtk.main_quit()
     return True
Beispiel #15
0
    def __init__(self, open_files):
        # Drag source definitons
        photos_view = get_obj('photos_view')
        photos_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [],
                                             Gdk.DragAction.COPY)
        photos_view.drag_source_add_text_targets()
        photos_view.connect('drag-data-get', self.photo_drag_start)

        # Drag destination defintions
        photos_view.drag_dest_set(Gtk.DestDefaults.ALL, [],
                                  Gdk.DragAction.COPY)
        photos_view.drag_dest_add_text_targets()
        photos_view.connect('drag-data-received', self.photo_drag_end, False)

        container = get_obj('map_container')
        container.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        container.drag_dest_add_text_targets()
        container.connect('drag-data-received', self.photo_drag_end, True)

        self.external_drag = True
        self.selection = photos_view.get_selection()
        self.open_files = open_files
Beispiel #16
0
 def confirm_quit_dialog(self, *args):
     """Teardown method, inform user of unsaved files, if any."""
     if len(modified) == 0:
         Gtk.main_quit()
         return True
     dialog = get_obj('quit')
     dialog.format_secondary_markup(self.strings.quit % len(modified))
     response = dialog.run()
     dialog.hide()
     self.redraw_interface()
     if response == Gtk.ResponseType.ACCEPT: self.save_all_files()
     if response != Gtk.ResponseType.CANCEL: Gtk.main_quit()
     return True
Beispiel #17
0
def map_source_menu():
    """Load the predefined map sources into a menu the user can use."""
    radio_group = []
    map_menu = get_obj('map_source_menu')
    last_source = gst.get_string('map-source-id')
    gst.bind_with_convert('map-source-id', map_view, 'map-source',
        MAP_SOURCES.get, lambda x: x.get_id())
    menu_item_clicked = (lambda item, mapid: item.get_active() and
        map_view.set_map_source(MAP_SOURCES[mapid]))
    
    for i, source_id in enumerate(sorted(MAP_SOURCES.keys())):
        source = MAP_SOURCES[source_id]
        menu_item = Gtk.RadioMenuItem.new_with_label(radio_group,
                                                     source.get_name())
        radio_group.append(menu_item)
        if last_source == source_id:
            menu_item.set_active(True)
        menu_item.connect('activate', menu_item_clicked, source_id)
        map_menu.attach(menu_item, 0, 1, i, i+1)
    map_menu.show_all()
Beispiel #18
0
def map_source_menu():
    """Load the predefined map sources into a menu the user can use."""
    radio_group = []
    map_menu = get_obj('map_source_menu')
    last_source = gst.get_string('map-source-id')
    gst.bind_with_convert('map-source-id', map_view, 'map-source',
        MAP_SOURCES.get, lambda x: x.get_id())
    menu_item_clicked = (lambda item, mapid: item.get_active() and
        map_view.set_map_source(MAP_SOURCES[mapid]))
    
    for i, source_id in enumerate(sorted(MAP_SOURCES.keys())):
        source = MAP_SOURCES[source_id]
        menu_item = Gtk.RadioMenuItem.new_with_label(radio_group,
                                                     source.get_name())
        radio_group.append(menu_item)
        if last_source == source_id:
            menu_item.set_active(True)
        menu_item.connect('activate', menu_item_clicked, source_id)
        map_menu.attach(menu_item, 0, 1, i, i+1)
    map_menu.show_all()
Beispiel #19
0
    def __init__(self):
        self.black = Clutter.Box.new(Clutter.BinLayout())
        self.black.set_color(Clutter.Color.new(0, 0, 0, 96))
        self.label = Clutter.Text()
        self.label.set_color(Clutter.Color.new(255, 255, 255, 255))
        self.xhair = Clutter.Rectangle.new_with_color(
            Clutter.Color.new(0, 0, 0, 64))
        for signal in ['latitude', 'longitude']:
            map_view.connect('notify::' + signal, display,
                             get_obj('maps_link'), self.label)
        map_view.connect(
            'notify::width',
            lambda view, param, black: black.set_size(view.get_width(), 30),
            self.black)

        scale = Champlain.Scale.new()
        scale.connect_view(map_view)
        map_view.bin_layout_add(scale, Clutter.BinAlignment.START,
                                Clutter.BinAlignment.END)
        map_view.bin_layout_add(self.black, Clutter.BinAlignment.START,
                                Clutter.BinAlignment.START)
        self.black.get_layout_manager().add(self.label,
                                            Clutter.BinAlignment.CENTER,
                                            Clutter.BinAlignment.CENTER)
Beispiel #20
0
from gi.repository import Gtk, Gdk, GLib
from re import compile as re_compile
from os.path import basename
from calendar import timegm
from time import clock

from gpsmath import Coordinates
from common import GSettings, Builder, gst, get_obj
from common import map_view, points, metadata

BOTTOM = Gtk.PositionType.BOTTOM
RIGHT = Gtk.PositionType.RIGHT

known_trackfiles = {}

empty_trackfile_label = get_obj('empty_trackfile_list')

def get_trackfile(uri):
    """This method caches TrackFile instances."""
    if uri not in known_trackfiles:
        fmt = KMLFile if uri[-3:].lower() == 'kml' else GPXFile
        known_trackfiles[uri] = fmt(uri)
    
    return known_trackfiles[uri]

def make_clutter_color(color):
    """Generate a Clutter.Color from the currently chosen color."""
    return Clutter.Color.new(
        *[x / 256 for x in [color.red, color.green, color.blue, 49152]])

def track_color_changed(selection, polys):
Beispiel #21
0
 def __init__(self):
     self.message_timeout_source = None
     self.progressbar = get_obj('progressbar')
     
     self.error = Struct({
         'message': get_obj('error_message'),
         'icon': get_obj('error_icon'),
         'bar': get_obj('error_bar')
     })
     
     self.error.bar.connect('response', lambda widget, signal: widget.hide())
     
     self.strings = Struct({
         'quit':    get_obj('quit').get_property('secondary-text'),
         'preview': get_obj('preview_label').get_text()
     })
     
     self.liststore = get_obj('loaded_photos')
     self.liststore.set_sort_column_id(TIMESTAMP, Gtk.SortType.ASCENDING)
     
     cell_string = Gtk.CellRendererText()
     cell_string.set_property('wrap-mode', Pango.WrapMode.WORD)
     cell_string.set_property('wrap-width', 200)
     cell_thumb  = Gtk.CellRendererPixbuf()
     cell_thumb.set_property('stock-id', Gtk.STOCK_MISSING_IMAGE)
     cell_thumb.set_property('ypad', 6)
     cell_thumb.set_property('xpad', 12)
     
     column = Gtk.TreeViewColumn('Photos')
     column.pack_start(cell_thumb, False)
     column.add_attribute(cell_thumb, 'pixbuf', THUMB)
     column.pack_start(cell_string, False)
     column.add_attribute(cell_string, 'markup', SUMMARY)
     column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
     
     # Deal with multiple selection drag and drop.
     self.defer_select = False
     photos_view = get_obj('photos_view')
     photos_view.connect('button-press-event', self.photoview_pressed)
     photos_view.connect('button-release-event', self.photoview_released)
     photos_view.append_column(column)
     
     self.drag      = DragController(self.open_files)
     self.navigator = NavigationController()
     self.search    = SearchController()
     self.labels    = LabelController()
     self.actors    = ActorController()
     
     about = get_obj('about')
     about.set_version(REVISION)
     about.set_program_name(APPNAME)
     about.set_logo(GdkPixbuf.Pixbuf.new_from_file_at_size(
         join(PKG_DATA_DIR, PACKAGE + '.svg'), 192, 192))
     
     click_handlers = {
         'open_button':
             [self.add_files_dialog, get_obj('open')],
         'save_button':
             [self.save_all_files],
         'close_button':
             [lambda btn: [p.destroy() for p in selected.copy()]],
         'revert_button':
             [lambda btn: self.open_files(
                 [p.filename for p in modified & selected])],
         'about_button':
             [lambda yes, you_can: you_can.run() and you_can.hide(), about],
         'help_button':
             [lambda *ignore: Gtk.show_uri(Gdk.Screen.get_default(),
                 'ghelp:gottengeography', Gdk.CURRENT_TIME)],
         'jump_button':
             [self.jump_to_photo],
         'apply_button':
             [self.apply_selected_photos],
     }
     for button, handler in click_handlers.items():
         get_obj(button).connect('clicked', *handler)
     
     # Hide the unused button that appears beside the map source menu.
     ugly = get_obj('map_source_menu_button').get_child().get_children()[0]
     ugly.set_no_show_all(True)
     ugly.hide()
     
     accel  = Gtk.AccelGroup()
     window = get_obj('main')
     window.resize(*gst.get('window-size'))
     window.connect('delete_event', self.confirm_quit_dialog)
     window.add_accel_group(accel)
     window.show_all()
     
     save_size = lambda v, s, size: gst.set_window_size(size())
     for prop in ['width', 'height']:
         map_view.connect('notify::' + prop, save_size, window.get_size)
     
     accel.connect(Gdk.keyval_from_name('q'),
         Gdk.ModifierType.CONTROL_MASK, 0, self.confirm_quit_dialog)
     
     self.labels.selection.emit('changed')
     clear_all_gpx()
     
     button = get_obj('apply_button')
     gst.bind('left-pane-page', get_obj('photo_camera_gps'), 'page')
     gst.bind('use-dark-theme', Gtk.Settings.get_default(),
              'gtk-application-prefer-dark-theme')
     
     # This bit of magic will only show the apply button when there is
     # at least one photo loaded that is not manually positioned.
     # In effect, it allows you to manually drag & drop some photos,
     # then batch-apply all the rest
     btn_sense = lambda *x: button.set_sensitive(
         [photo for photo in photos.values() if not photo.manual])
     self.liststore.connect('row-changed', btn_sense)
     self.liststore.connect('row-deleted', btn_sense)
     
     empty = get_obj('empty_photo_list')
     empty_visible = lambda l, *x: empty.set_visible(l.get_iter_first() is None)
     self.liststore.connect('row-changed', empty_visible)
     self.liststore.connect('row-deleted', empty_visible)
     
     toolbar = get_obj('photo_btn_bar')
     bar_visible = lambda l, *x: toolbar.set_visible(l.get_iter_first() is not None)
     self.liststore.connect('row-changed', bar_visible)
     self.liststore.connect('row-deleted', bar_visible)
     
     get_obj('open').connect('update-preview', self.update_preview,
         get_obj('preview_label'), get_obj('preview_image'))
Beispiel #22
0
from gi.repository import Gio, GObject, Gtk
from math import modf as split_float
from gettext import gettext as _
from time import tzset
from os import environ

from territories import tz_regions, get_timezone
from common import get_obj, GSettings, Builder
from version import PACKAGE

BOTTOM = Gtk.PositionType.BOTTOM
RIGHT = Gtk.PositionType.RIGHT

known_cameras = {}

empty_camera_label = get_obj('empty_camera_list')

def get_camera(photo):
    """This method caches Camera instances."""
    names = {'Make': 'Unknown Make', 'Model': 'Unknown Camera'}
    keys = ['Exif.Image.' + key for key in names.keys()
        + ['CameraSerialNumber']] + ['Exif.Photo.BodySerialNumber']
    
    for key in keys:
        try:
            names.update({key.split('.')[-1]: photo.exif[key].value})
        except KeyError:
            pass
    
    # Turn a Nikon Wonder Cam with serial# 12345 into '12345_nikon_wonder_cam'
    camera_id = '_'.join(sorted(names.values())).lower().replace(' ', '_')
Beispiel #23
0
 def __init__(self):
     self.progressbar = get_obj('progressbar')
     
     self.error = Struct({
         'message': get_obj('error_message'),
         'icon': get_obj('error_icon'),
         'bar': get_obj('error_bar')
     })
     
     self.error.bar.connect('response', lambda widget, signal: widget.hide())
     
     self.strings = Struct({
         'quit':    get_obj('quit').get_property('secondary-text'),
         'preview': get_obj('preview_label').get_text()
     })
     
     self.liststore = get_obj('loaded_photos')
     self.liststore.set_sort_column_id(TIMESTAMP, Gtk.SortType.ASCENDING)
     
     cell_string = Gtk.CellRendererText()
     cell_thumb  = Gtk.CellRendererPixbuf()
     cell_thumb.set_property('stock-id', Gtk.STOCK_MISSING_IMAGE)
     cell_thumb.set_property('ypad', 6)
     cell_thumb.set_property('xpad', 12)
     
     column = Gtk.TreeViewColumn('Photos')
     column.pack_start(cell_thumb, False)
     column.add_attribute(cell_thumb, 'pixbuf', THUMB)
     column.pack_start(cell_string, False)
     column.add_attribute(cell_string, 'markup', SUMMARY)
     column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
     
     get_obj('photos_view').append_column(column)
     
     self.drag      = DragController(self.open_files)
     self.navigator = NavigationController()
     self.search    = SearchController()
     self.prefs     = PreferencesController()
     self.labels    = LabelController()
     self.actors    = ActorController()
     
     about = get_obj('about')
     about.set_version(REVISION)
     about.set_program_name(APPNAME)
     about.set_logo(GdkPixbuf.Pixbuf.new_from_file_at_size(
         join(PKG_DATA_DIR, PACKAGE + '.svg'), 192, 192))
     
     click_handlers = {
         'open_button':       [self.add_files_dialog, get_obj('open')],
         'save_button':       [self.save_all_files],
         'clear_button':      [clear_all_gpx],
         'close_button':      [self.close_selected_photos],
         'revert_button':     [self.revert_selected_photos],
         'about_button':      [lambda b, d: d.run() and d.hide(), about],
         'apply_button':      [self.apply_selected_photos, map_view],
         'select_all_button': [toggle_selected_photos, self.labels.selection]
     }
     for button, handler in click_handlers.items():
         get_obj(button).connect('clicked', *handler)
     
     accel  = Gtk.AccelGroup()
     window = get_obj('main')
     window.resize(*gst.get('window-size'))
     window.connect('delete_event', self.confirm_quit_dialog)
     window.add_accel_group(accel)
     window.show_all()
     
     # Hide the unused button that appears beside the map source menu.
     get_obj('map_source_menu_button').get_child().get_children()[0].set_visible(False)
     
     save_size = lambda v, s, size: gst.set_window_size(size())
     for prop in ['width', 'height']:
         map_view.connect('notify::' + prop, save_size, window.get_size)
     
     accel.connect(Gdk.keyval_from_name('q'),
         Gdk.ModifierType.CONTROL_MASK, 0, self.confirm_quit_dialog)
     
     self.labels.selection.emit('changed')
     clear_all_gpx()
     
     metadata.delta = 0
     self.secbutton, self.minbutton = get_obj('seconds'), get_obj('minutes')
     for spinbutton in [ self.secbutton, self.minbutton ]:
         spinbutton.connect('value-changed', self.time_offset_changed)
     gst.bind('offset-minutes', self.minbutton, 'value')
     gst.bind('offset-seconds', self.secbutton, 'value')
     
     gst.bind('left-pane-page', get_obj('photo_camera_gps'), 'page')
     
     get_obj('open').connect('update-preview', self.update_preview,
         get_obj('preview_label'), get_obj('preview_image'))
Beispiel #24
0
    def __init__(self):
        self.progressbar = get_obj('progressbar')

        self.error = Struct({
            'message': get_obj('error_message'),
            'icon': get_obj('error_icon'),
            'bar': get_obj('error_bar')
        })

        self.error.bar.connect('response',
                               lambda widget, signal: widget.hide())

        self.strings = Struct({
            'quit':
            get_obj('quit').get_property('secondary-text'),
            'preview':
            get_obj('preview_label').get_text()
        })

        self.liststore = get_obj('loaded_photos')
        self.liststore.set_sort_column_id(TIMESTAMP, Gtk.SortType.ASCENDING)

        cell_string = Gtk.CellRendererText()
        cell_thumb = Gtk.CellRendererPixbuf()
        cell_thumb.set_property('stock-id', Gtk.STOCK_MISSING_IMAGE)
        cell_thumb.set_property('ypad', 6)
        cell_thumb.set_property('xpad', 12)

        column = Gtk.TreeViewColumn('Photos')
        column.pack_start(cell_thumb, False)
        column.add_attribute(cell_thumb, 'pixbuf', THUMB)
        column.pack_start(cell_string, False)
        column.add_attribute(cell_string, 'markup', SUMMARY)
        column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)

        get_obj('photos_view').append_column(column)

        self.drag = DragController(self.open_files)
        self.navigator = NavigationController()
        self.search = SearchController()
        self.prefs = PreferencesController()
        self.labels = LabelController()
        self.actors = ActorController()

        about = get_obj('about')
        about.set_version(REVISION)
        about.set_program_name(APPNAME)
        about.set_logo(
            GdkPixbuf.Pixbuf.new_from_file_at_size(
                join(PKG_DATA_DIR, PACKAGE + '.svg'), 192, 192))

        click_handlers = {
            'open_button': [self.add_files_dialog,
                            get_obj('open')],
            'save_button': [self.save_all_files],
            'clear_button': [clear_all_gpx],
            'close_button': [self.close_selected_photos],
            'revert_button': [self.revert_selected_photos],
            'about_button': [lambda b, d: d.run() and d.hide(), about],
            'apply_button': [self.apply_selected_photos, map_view],
            'select_all_button':
            [toggle_selected_photos, self.labels.selection]
        }
        for button, handler in click_handlers.items():
            get_obj(button).connect('clicked', *handler)

        accel = Gtk.AccelGroup()
        window = get_obj('main')
        window.resize(*gst.get('window-size'))
        window.connect('delete_event', self.confirm_quit_dialog)
        window.add_accel_group(accel)
        window.show_all()

        # Hide the unused button that appears beside the map source menu.
        get_obj('map_source_menu_button').get_child().get_children(
        )[0].set_visible(False)

        save_size = lambda v, s, size: gst.set_window_size(size())
        for prop in ['width', 'height']:
            map_view.connect('notify::' + prop, save_size, window.get_size)

        accel.connect(Gdk.keyval_from_name('q'), Gdk.ModifierType.CONTROL_MASK,
                      0, self.confirm_quit_dialog)

        self.labels.selection.emit('changed')
        clear_all_gpx()

        metadata.delta = 0
        self.secbutton, self.minbutton = get_obj('seconds'), get_obj('minutes')
        for spinbutton in [self.secbutton, self.minbutton]:
            spinbutton.connect('value-changed', self.time_offset_changed)
        gst.bind('offset-minutes', self.minbutton, 'value')
        gst.bind('offset-seconds', self.secbutton, 'value')

        gst.bind('left-pane-page', get_obj('photo_camera_gps'), 'page')

        get_obj('open').connect('update-preview', self.update_preview,
                                get_obj('preview_label'),
                                get_obj('preview_image'))