Ejemplo n.º 1
0
class Camera():
    """Store per-camera configuration in GSettings."""
    
    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')
    
    def method_handler(self, method, region, cities):
        """Only show manual tz selectors when necessary."""
        visible = method.get_active_id() == 'custom'
        region.set_visible(visible)
        cities.set_visible(visible)
        self.set_timezone()
    
    def region_handler(self, region, cities):
        """Populate the list of cities when a continent is selected."""
        cities.remove_all()
        for city in get_timezone(region.get_active_id(), []):
            cities.append(city, city)
    
    def cities_handler(self, cities):
        """When a city is selected, update the chosen timezone."""
        if cities.get_active_id() is not None:
            self.set_timezone()
    
    def set_found_timezone(self, found):
        """Store discovered timezone in GSettings."""
        self.gst.set_string('found-timezone', found)
    
    def set_timezone(self):
        """Set the timezone to the chosen zone and update all photos."""
        environ['TZ'] = ''
        case = lambda x, y=self.tz_method.get_active_id(): x == y
        if case('lookup'):
            # Note that this will gracefully fallback on system timezone
            # if no timezone has actually been found yet.
            environ['TZ'] = self.gst.get_string('found-timezone')
        elif case('custom'):
            region = self.tz_region.get_active_id()
            city   = self.tz_cities.get_active_id()
            if region is not None and city is not None:
                environ['TZ'] = '/'.join([region, city])
        tzset()
        self.offset_handler()
    
    def offset_handler(self, offset=None):
        """When the offset is changed, update the loaded photos."""
        for photo in self.photos:
            photo.calculate_timestamp()
    
    def get_offset(self):
        """Return the currently selected clock offset value."""
        return int(self.offset.get_value())
Ejemplo n.º 2
0
class Camera(GObject.GObject):
    """Store per-camera configuration in GSettings.
    
    >>> from common import Dummy as Photo
    >>> cam = Camera('unknown_camera')
    >>> cam.add_photo(Photo())
    >>> cam.num_photos
    1
    >>> photo = Photo()
    >>> cam.add_photo(photo)
    >>> cam.num_photos
    2
    >>> cam.remove_photo(photo)
    >>> cam.num_photos
    1
    
    >>> Camera.generate_id({'Make': 'Nikon',
    ...                     'Model': 'Wonder Cam',
    ...                     'Serial': '12345'})
    ('12345_nikon_wonder_cam', 'Nikon Wonder Cam')
    >>> Camera.generate_id({})
    ('unknown_camera', 'Unknown Camera')
    
    >>> cam = Camera('canon_canon_powershot_a590_is')
    >>> cam.timezone_method = 'lookup'
    >>> environ['TZ']
    'America/Edmonton'
    >>> cam.timezone_method = 'offset'
    >>> environ['TZ'].startswith('UTC')
    True
    """
    offset = GObject.property(type=int, minimum=-3600, maximum=3600)
    utc_offset = GObject.property(type=int, minimum=-24, maximum=24)
    found_timezone = GObject.property(type=str)
    timezone_method = GObject.property(type=str)
    timezone_region = GObject.property(type=str)
    timezone_city = GObject.property(type=str)
    
    @GObject.property(type=int)
    def num_photos(self):
        """Read-only count of the loaded photos taken by this camera."""
        return len(self.photos)
    
    @staticmethod
    def generate_id(info):
        """Identifies a camera by serial number, make, and model."""
        maker = info.get('Make', '').capitalize()
        model = info.get('Model', '')
        
        # Some makers put their name twice
        model = model if model.startswith(maker) else maker + ' ' + model
        
        camera_id = '_'.join(sorted(info.values())).lower().replace(' ', '_')
        
        return (camera_id.strip(' _') or 'unknown_camera',
                model.strip() or _('Unknown Camera'))
    
    @staticmethod
    def set_all_found_timezone(timezone):
        """"Set all cameras to the given timezone."""
        for camera in Camera.instances:
            camera.found_timezone = timezone
    
    @staticmethod
    def timezone_handler_all():
        """Update all of the photos from all of the cameras."""
        for camera in Camera.instances:
            camera.timezone_handler()
    
    def __init__(self, camera_id):
        GObject.GObject.__init__(self)
        self.id = camera_id
        self.photos = set()
        
        # Bind properties to settings
        self.gst = GSettings('camera', camera_id)
        for prop in self.gst.list_keys():
            self.gst.bind(prop, self)
        
        # Get notifications when properties are changed
        self.connect('notify::offset', self.offset_handler)
        self.connect('notify::timezone-method', self.timezone_handler)
        self.connect('notify::timezone-city', self.timezone_handler)
        self.connect('notify::utc-offset', self.timezone_handler)
    
    def timezone_handler(self, *ignore):
        """Set the timezone to the chosen zone and update all photos."""
        environ['TZ'] = ''
        if self.timezone_method == 'lookup':
            # Note that this will gracefully fallback on system timezone
            # if no timezone has actually been found yet.
            environ['TZ'] = self.found_timezone
        elif self.timezone_method == 'offset':
            environ['TZ'] = 'UTC%+d' % -self.utc_offset
        elif self.timezone_method == 'custom' and \
             self.timezone_region and self.timezone_city:
            environ['TZ'] = '/'.join(
                [self.timezone_region, self.timezone_city])
        
        tzset()
        self.offset_handler()
    
    def offset_handler(self, *ignore):
        """When the offset is changed, update the loaded photos."""
        for i, photo in enumerate(self.photos):
            if not i % 10:
                Widgets.redraw_interface()
            photo.calculate_timestamp(self.offset)
    
    def add_photo(self, photo):
        """Adds photo to the list of photos taken by this camera."""
        photo.camera = self
        self.photos.add(photo)
        self.notify('num_photos')
    
    def remove_photo(self, photo):
        """Removes photo from the list of photos taken by this camera."""
        photo.camera = None
        self.photos.discard(photo)
        self.notify('num_photos')