# Copyright (C) 2008 Jimmy Do # Copyright (C) 2010 Kenny Meyer # # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from gettext import gettext as _ from gettext import ngettext from datetime import datetime, timedelta import mateapplet import gst import gtk import gtk.glade as glade import gtk.gdk as gdk import subprocess import shlex import threading from timerapplet import config from timerapplet import core from timerapplet import ui from timerapplet import utils def on_widget_button_press_event(sender, event, data=None): if event.button != 1: sender.emit_stop_by_name('button-press-event') return False def force_no_focus_padding(widget): gtk.rc_parse_string('\n' ' style "timer-applet-button-style"\n' ' {\n' ' GtkWidget::focus-line-width=0\n' ' GtkWidget::focus-padding=0\n' ' }\n' '\n' ' widget "*.timer-applet-button" style "timer-applet-button-style"\n' '\n') widget.set_name('timer-applet-button') class TimerApplet(object): # MateConf key identifiers ## You can find Timer Applet's schemas file in data/timer-applet.schemas.in _SHOW_REMAINING_TIME_KEY = 'show_remaining_time' _PLAY_SOUND_KEY = 'play_notification_sound' _USE_CUSTOM_SOUND_KEY = 'use_custom_notification_sound' _SHOW_POPUP_NOTIFICATION_KEY = 'show_popup_notification' _SHOW_PULSING_ICON_KEY = 'show_pulsing_icon' _CUSTOM_SOUND_PATH_KEY = 'custom_notification_sound_path' _PRESETS_PLACEHOLDER_NAME = 'Placeholder' _PRESETS_PLACEHOLDER_PATH = '/popups/popup/Presets/' + _PRESETS_PLACEHOLDER_NAME _PRESETS_PATH = '/popups/popup/Presets' def __init__(self, presets_store, manage_presets_dialog, applet, timer, mateconf_wrapper): self._presets_store = presets_store self._manage_presets_dialog = manage_presets_dialog self._applet = applet self._timer = timer self._gst_playbin = gst.element_factory_make('playbin', 'player') def bus_event(bus, message): t = message.type if t == gst.MESSAGE_EOS: self._gst_playbin.set_state(gst.STATE_NULL) elif t == gst.MESSAGE_ERROR: self._gst_playbin.set_state(gst.STATE_NULL) err, debug = message.parse_error() print 'Error playing sound: %s' % err, debug return True self._gst_playbin.get_bus().add_watch(bus_event) self._status_button = ui.StatusButton() self._notifier = ui.Notifier('TimerApplet', gtk.STOCK_DIALOG_INFO, self._status_button) self._start_next_timer_dialog = ui.StartNextTimerDialog( config.GLADE_PATH, "Start next timer", "Would you like to start the next timer?") self._start_timer_dialog = ui.StartTimerDialog(config.GLADE_PATH, lambda name: utils.is_valid_preset_name(name, self._presets_store), self._presets_store.get_model(), lambda row_iter: utils.get_preset_display_text(self._presets_store, row_iter)) self._continue_dialog = ui.ContinueTimerDialog(config.GLADE_PATH, _('Continue timer countdown?'), _('The timer is currently paused. Would you like to continue countdown?')) self._preferences_dialog = ui.PreferencesDialog(config.GLADE_PATH) self._mateconf = mateconf_wrapper self._about_dialog = glade.XML(config.GLADE_PATH, 'about_dialog').get_widget('about_dialog') self._about_dialog.set_version(config.VERSION) self._applet.set_applet_flags(mateapplet.EXPAND_MINOR) self._applet.setup_menu_from_file( None, config.POPUP_MENU_FILE_PATH, None, [('PauseTimer', lambda component, verb: self._timer.stop()), ('ContinueTimer', lambda component, verb: self._timer.start()), ('StopTimer', lambda component, verb: self._timer.reset()), ('RestartTimer', lambda component, verb: self._restart_timer()), ('StartNextTimer', lambda component, verb: self._start_next_timer()), ('ManagePresets', lambda component, verb: self._manage_presets_dialog.show()), ('Preferences', lambda component, verb: self._preferences_dialog.show()), ('About', lambda component, verb: self._about_dialog.show())] ) self._applet.add(self._status_button) # Remove padding around button contents. force_no_focus_padding(self._status_button) # TODO: # Fix bug in which button would not propogate middle-clicks # and right-clicks to the applet. self._status_button.connect('button-press-event', on_widget_button_press_event) self._status_button.set_relief(gtk.RELIEF_NONE) self._status_button.set_icon(config.ICON_PATH); self._connect_signals() self._update_status_button() self._update_popup_menu() self._update_preferences_dialog() self._status_button.show() self._applet.show() def _connect_signals(self): self._applet.connect('change-orient', lambda applet, orientation: self._update_status_button()) self._applet.connect('change-size', lambda applet, size: self._update_status_button()) self._applet.connect('change-background', self._on_applet_change_background) self._applet.connect('destroy', self._on_applet_destroy) self._presets_store.get_model().connect('row-deleted', lambda model, row_path: self._update_popup_menu()) self._presets_store.get_model().connect('row-changed', lambda model, row_path, row_iter: self._update_popup_menu()) self._timer.connect('time-changed', self._on_timer_time_changed) self._timer.connect('state-changed', self._on_timer_state_changed) self._status_button.connect('clicked', self._on_status_button_clicked) self._start_timer_dialog.connect('clicked-start', self._on_start_dialog_clicked_start) self._start_timer_dialog.connect('clicked-manage-presets', self._on_start_dialog_clicked_manage_presets) self._start_timer_dialog.connect('clicked-save', self._on_start_dialog_clicked_save) self._start_timer_dialog.connect('clicked-preset', self._on_start_dialog_clicked_preset) self._start_timer_dialog.connect('double-clicked-preset', self._on_start_dialog_double_clicked_preset) self._preferences_dialog.connect('show-remaining-time-changed', self._on_prefs_show_time_changed) self._preferences_dialog.connect('play-sound-changed', self._on_prefs_play_sound_changed) self._preferences_dialog.connect('use-custom-sound-changed', self._on_prefs_use_custom_sound_changed) self._preferences_dialog.connect('show-popup-notification-changed', self._on_prefs_show_popup_notification_changed) self._preferences_dialog.connect('show-pulsing-icon-changed', self._on_prefs_show_pulsing_icon_changed) self._preferences_dialog.connect('custom-sound-path-changed', self._on_prefs_custom_sound_path_changed) self._about_dialog.connect('delete-event', gtk.Widget.hide_on_delete) self._about_dialog.connect('response', lambda dialog, response_id: self._about_dialog.hide()) self._mateconf.add_notification(TimerApplet._SHOW_REMAINING_TIME_KEY, self._on_mateconf_changed) self._mateconf.add_notification(TimerApplet._PLAY_SOUND_KEY, self._on_mateconf_changed) self._mateconf.add_notification(TimerApplet._USE_CUSTOM_SOUND_KEY, self._on_mateconf_changed) self._mateconf.add_notification(TimerApplet._SHOW_PULSING_ICON_KEY, self._on_mateconf_changed) self._mateconf.add_notification(TimerApplet._SHOW_POPUP_NOTIFICATION_KEY, self._on_mateconf_changed) self._mateconf.add_notification(TimerApplet._CUSTOM_SOUND_PATH_KEY, self._on_mateconf_changed) ## Private methods for updating UI ## def _update_status_button(self): current_state = self._timer.get_state() if current_state == core.Timer.STATE_IDLE: print 'Idle' # This label text should not be visible because the label # is hidden when the timer is idle. self._status_button.set_label('--:--:--') self._status_button.set_tooltip(_('Click to start a new timer countdown.')) elif current_state == core.Timer.STATE_RUNNING: print 'Running' elif current_state == core.Timer.STATE_PAUSED: print 'Paused' self._status_button.set_tooltip(_('Paused. Click to continue timer countdown.')) elif current_state == core.Timer.STATE_FINISHED: print 'Finished' self._status_button.set_label(_('Finished')) name_str = self._timer.get_name() time_str = utils.get_display_text_from_datetime(self._timer.get_end_time()) if len(name_str) > 0: # "" finished at