def combo_factory(combo_array, toolbar, callback, cb_arg=None, tooltip=None, default=None): '''Factory for making a toolbar combo box''' combo = ComboBox() if tooltip is not None and hasattr(combo, 'set_tooltip_text'): combo.set_tooltip_text(tooltip) if cb_arg is not None: combo.connect('changed', callback, cb_arg) else: combo.connect('changed', callback) for i, selection in enumerate(combo_array): combo.append_item(i, selection, None) combo.show() toolitem = Gtk.ToolItem() toolitem.add(combo) if hasattr(toolbar, 'insert'): # the main toolbar toolbar.insert(toolitem, -1) else: # or a secondary toolbar toolbar.props.page.insert(toolitem, -1) toolitem.show() if default is not None: combo.set_active(combo_array.index(default)) return combo
def __init__(self, activity): Gtk.Toolbar.__init__(self) self._activity = activity self._speech = SpeechManager() self._is_paused = False self.load_speech_parameters() self._voices = self._speech.get_all_voices() # a dictionary locale = os.environ.get('LANG', '') language_location = locale.split('.', 1)[0].lower() language = language_location.split('_')[0] # if the language is es but not es_es default to es_la (latin voice) if language == 'es' and language_location != 'es_es': language_location = 'es_la' self._voice = 'en_us' if language_location in self._voices: self._voice = language_location elif language in self._voices: self._voice = language voice_names = [] for language, name in self._voices.iteritems(): voice_names.append((language, name)) voice_names.sort(self._compare_voice) # Play button self._play_button = ToggleToolButton('media-playback-start') self._play_button.show() self._play_button.connect('toggled', self._play_toggled_cb) self.insert(self._play_button, -1) self._play_button.set_tooltip(_('Play / Pause')) # Stop button self._stop_button = ToolButton('media-playback-stop') self._stop_button.show() self._stop_button.connect('clicked', self._stop_clicked_cb) self._stop_button.set_sensitive(False) self.insert(self._stop_button, -1) self._stop_button.set_tooltip(_('Stop')) # Language list combo = ComboBox() which = 0 for pair in voice_names: language, name = pair combo.append_item(language, name) if language == self._voice: combo.set_active(which) which += 1 combo.connect('changed', self._voice_changed_cb) combotool = ToolComboBox(combo) self.insert(combotool, -1) combotool.show() self._speech.connect('stop', self._reset_buttons_cb)
class BooksToolbar(Gtk.Toolbar): __gtype_name__ = 'BooksToolbar' def __init__(self): Gtk.Toolbar.__init__(self) book_search_item = Gtk.ToolItem() self.search_entry = Gtk.Entry() self.search_entry.connect('activate', self.search_entry_activate_cb) width = int(Gdk.Screen.width() / 2) self.search_entry.set_size_request(width, -1) book_search_item.add(self.search_entry) self.search_entry.show() self.insert(book_search_item, -1) book_search_item.show() self._download = ToolButton('go-down') self._download.set_tooltip(_('Get Book')) self._download.props.sensitive = False self._download.connect('clicked', self._get_book_cb) self.insert(self._download, -1) self._download.show() self.format_combo = ComboBox() self.format_combo.connect('changed', self.format_changed_cb) self.format_combo.append_item('.djvu', 'Deja Vu') self.format_combo.append_item('_bw.pdf', 'B/W PDF') self.format_combo.append_item('.pdf', 'Color PDF') self.format_combo.append_item('.epub', 'EPUB') self.format_combo.set_active(0) self.format_combo.props.sensitive = False combotool = ToolComboBox(self.format_combo) self.insert(combotool, -1) combotool.show() self.search_entry.grab_focus() def set_activity(self, activity): self.activity = activity def format_changed_cb(self, combo): if self.activity != None: self.activity.show_book_data() def search_entry_activate_cb(self, entry): self.activity.find_books(entry.props.text) def _get_book_cb(self, button): self.activity.get_book() def enable_button(self, state): self._download.props.sensitive = state self.format_combo.props.sensitive = state
def _get_with_search_combo(self): with_search = ComboBox() with_search.append_item(_ACTION_EVERYBODY, _('Anyone')) with_search.append_separator() with_search.append_item(_ACTION_MY_FRIENDS, _('My friends')) with_search.append_item(_ACTION_MY_CLASS, _('My class')) with_search.append_separator() # TODO: Ask the model for buddies. with_search.append_item(3, 'Dan', 'theme:xo') with_search.set_active(0) with_search.connect('changed', self._combo_changed_cb) return with_search
def _combo_factory(combo_array, default, tooltip, toolbar): '''Factory for making a toolbar combo box''' my_combo = ComboBox() if hasattr(my_combo, 'set_tooltip_text'): my_combo.set_tooltip_text(tooltip) for i, s in enumerate(combo_array): my_combo.append_item(i, _(s), None) toolbar.insert(ToolComboBox(my_combo), -1) my_combo.set_active(default) return my_combo
def _get_when_search_combo(self): when_search = ComboBox() when_search.append_item(_ACTION_ANYTIME, _('Anytime')) when_search.append_separator() when_search.append_item(_ACTION_TODAY, _('Today')) when_search.append_item(_ACTION_SINCE_YESTERDAY, _('Since yesterday')) # TRANS: Filter entries modified during the last 7 days. when_search.append_item(_ACTION_PAST_WEEK, _('Past week')) # TRANS: Filter entries modified during the last 30 days. when_search.append_item(_ACTION_PAST_MONTH, _('Past month')) # TRANS: Filter entries modified during the last 356 days. when_search.append_item(_ACTION_PAST_YEAR, _('Past year')) when_search.set_active(0) when_search.connect('changed', self._combo_changed_cb) return when_search
def combo_factory(combo_array, toolbar, callback, cb_arg=None, tooltip=None, default=None): """Factory for making a toolbar combo box""" combo = ComboBox() if tooltip is not None and hasattr(combo, "set_tooltip_text"): combo.set_tooltip_text(tooltip) if cb_arg is not None: combo.connect("changed", callback, cb_arg) else: combo.connect("changed", callback) for i, selection in enumerate(combo_array): combo.append_item(i, selection, None) combo.show() toolitem = Gtk.ToolItem() toolitem.add(combo) if hasattr(toolbar, "insert"): # the main toolbar toolbar.insert(toolitem, -1) else: # or a secondary toolbar toolbar.props.page.insert(toolitem, -1) toolitem.show() if default is not None: combo.set_active(combo_array.index(default)) return combo
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): Gtk.Toolbar.__init__(self) voicebar = Gtk.Toolbar() self._activity = activity if not speech.supported: return self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_btn.connect('toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() self.pitchadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) pitchbar = Gtk.HScale(self.pitchadj) pitchbar.set_draw_value(False) pitchbar.set_update_policy(Gtk.UPDATE_DISCONTINUOUS) pitchbar.set_size_request(150, 15) self.pitchadj.set_value(speech.pitch) pitchtool = Gtk.ToolItem() pitchtool.add(pitchbar) pitchtool.show() self.insert(pitchtool, -1) pitchbar.show() self.rateadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) ratebar = Gtk.HScale(self.rateadj) ratebar.set_draw_value(False) ratebar.set_update_policy(Gtk.UPDATE_DISCONTINUOUS) ratebar.set_size_request(150, 15) self.rateadj.set_value(speech.rate) ratetool = Gtk.ToolItem() ratetool.add(ratebar) ratetool.show() self.insert(ratetool, -1) ratebar.show() self.pitchadj.connect("value_changed", self.pitch_adjusted_cb) self.rateadj.connect("value_changed", self.rate_adjusted_cb) def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0].lower() < b[0].lower(): return -1 if a[0].lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def pitch_adjusted_cb(self, get): speech.pitch = int(get.value) speech.say(_("pitch adjusted")) self.save_speech_parameters() def rate_adjusted_cb(self, get): speech.rate = int(get.value) speech.say(_("rate adjusted")) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = simplejson.load(f) speech.pitch = speech_parameters['pitch'] speech.rate = speech_parameters['rate'] speech.voice = speech_parameters['voice'] finally: f.close() def save_speech_parameters(self): speech_parameters = {} speech_parameters['pitch'] = speech.pitch speech_parameters['rate'] = speech.rate speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: simplejson.dump(speech_parameters, f) finally: f.close() def play_cb(self, widget): if widget.get_active(): self.play_btn.set_named_icon('media-playback-pause') if speech.is_stopped(): speech.play(self._activity._view.get_marked_words()) else: self.play_btn.set_named_icon('media-playback-start') speech.stop()
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): GObject.GObject.__init__(self) self._activity = activity if not speech.supported: return self.is_paused = False self._cnf_client = GConf.Client.get_default() self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton("media-playback-start") self.play_btn.show() self.play_toggled_handler = self.play_btn.connect("toggled", self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_("Play / Pause")) # Stop button self.stop_btn = ToolButton("media-playback-stop") self.stop_btn.show() self.stop_btn.connect("clicked", self.stop_cb) self.stop_btn.set_sensitive(False) self.insert(self.stop_btn, -1) self.stop_btn.set_tooltip(_("Stop")) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect("changed", self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() speech.reset_cb = self.reset_buttons_cb speech.end_text_cb = self.reset_buttons_cb def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0].lower() < b[0].lower(): return -1 if a[0].lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), "data") data_file_name = os.path.join(data_path, "speech_params.json") if os.path.exists(data_file_name): f = open(data_file_name, "r") try: speech_parameters = json.load(f) speech.voice = speech_parameters["voice"] finally: f.close() else: speech.voice = self.get_default_voice() logging.error("Default voice %s", speech.voice) self._cnf_client.add_dir("/desktop/sugar/speech", GConf.ClientPreloadType.PRELOAD_NONE) speech.pitch = self._cnf_client.get_int("/desktop/sugar/speech/pitch") speech.rate = self._cnf_client.get_int("/desktop/sugar/speech/rate") self._cnf_client.notify_add("/desktop/sugar/speech/pitch", self.__conf_changed_cb, None) self._cnf_client.notify_add("/desktop/sugar/speech/rate", self.__conf_changed_cb, None) def get_default_voice(self): """Try to figure out the default voice, from the current locale ($LANG) Fall back to espeak's voice called Default.""" voices = speech.get_all_voices() locale = os.environ.get("LANG", "") language_location = locale.split(".", 1)[0].lower() language = language_location.split("_")[0] variant = "" if language_location.find("_") > -1: variant = language_location.split("_")[1] # if the language is es but not es_es default to es_la (latin voice) if language == "es" and language_location != "es_es": language_location = "es_la" best = voices.get(language_location) or voices.get(language) or "default" logging.debug("Best voice for LANG %s seems to be %s", locale, best) return [best, language, variant] def __conf_changed_cb(self, client, connection_id, entry, args): key = entry.get_key() value = client.get_int(key) if key == "/desktop/sugar/speech/pitch": speech.pitch = value if key == "/desktop/sugar/speech/rate": speech.rate = value def save_speech_parameters(self): speech_parameters = {} speech_parameters["voice"] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), "data") data_file_name = os.path.join(data_path, "speech_params.json") f = open(data_file_name, "w") try: json.dump(speech_parameters, f) finally: f.close() def reset_buttons_cb(self): logging.error("reset buttons") self.play_btn.set_icon_name("media-playback-start") self.stop_btn.set_sensitive(False) self.play_btn.handler_block(self.play_toggled_handler) self.play_btn.set_active(False) self.play_btn.handler_unblock(self.play_toggled_handler) self.is_paused = False def play_cb(self, widget): self.stop_btn.set_sensitive(True) if widget.get_active(): self.play_btn.set_icon_name("media-playback-pause") logging.error("Paused %s", self.is_paused) if not self.is_paused: # get the text to speech, if there are a selection, # play selected text, if not, play all abi = self._activity.abiword_canvas selection = abi.get_selection("text/plain") if not selection or selection[0] is None or selection[1] == 0: # nothing selected abi.select_all() text = abi.get_selection("text/plain")[0] abi.moveto_bod() else: text = selection[0] speech.play(text) else: logging.error("Continue play") speech.continue_play() else: self.play_btn.set_icon_name("media-playback-start") self.is_paused = True speech.pause() def stop_cb(self, widget): self.stop_btn.set_sensitive(False) self.play_btn.set_icon_name("media-playback-start") self.play_btn.set_active(False) self.is_paused = False speech.stop()
def __init__(self, handle): activity.Activity.__init__(self, handle) # No sharing (Future Improvement) self.max_participants = 1 # Build the activity toolbar. toolbox = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbox.toolbar.insert(activity_button, 0) activity_button.show() comboLabel1 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(_('Level:') + ' ') comboLabel1.add(label1) toolbox.toolbar.insert(comboLabel1, -1) comboLabel1.show() label1.show() comboField = Gtk.ToolItem() combo = ComboBox() combo.set_wrap_width(3) combo.append_item(0, _('Easy')) combo.append_item(1, _('Moderate')) combo.append_item(2, _('Hard')) combo.set_active(0) comboField.add(combo) combo.connect('changed', self.change_combo) toolbox.toolbar.insert(comboField, -1) comboField.show() combo.show() separator = Gtk.SeparatorToolItem() separator.props.draw = True separator.set_expand(False) toolbox.toolbar.insert(separator, -1) separator.show() restart = ToolButton('new-game') toolbox.toolbar.insert(restart, -1) restart.set_tooltip(_('Restart')) restart.connect('clicked', self._restart_button_cb) restart.show() next_bt = ToolButton('next') toolbox.toolbar.insert(next_bt, -1) next_bt.set_tooltip(_('Next Number')) next_bt.connect('clicked', self._next_button_cb) next_bt.set_sensitive(False) next_bt.show() separator2 = Gtk.SeparatorToolItem() separator2.props.draw = True separator2.set_expand(False) toolbox.toolbar.insert(separator2, -1) separator2.show() comboLabel2 = Gtk.ToolItem() label1 = Gtk.Label() label1.set_text(_('Score:') + ' ') comboLabel2.add(label1) toolbox.toolbar.insert(comboLabel2, -1) comboLabel2.show() label1.show() self._score_image = Gtk.Image() item = Gtk.ToolItem() item.add(self._score_image) toolbox.toolbar.insert(item, -1) item.show() separator2 = Gtk.SeparatorToolItem() separator2.props.draw = False separator2.set_expand(True) toolbox.toolbar.insert(separator2, -1) separator2.show() stop_button = StopButton(self) toolbox.toolbar.insert(stop_button, -1) stop_button.show() stop_button.connect('clicked', self._stop_cb) toolbox.show() self.set_toolbar_box(toolbox) # Create the game instance. self.game = CowBulls.CowBulls(parent=self) # Build the Pygame canvas. self.game.canvas = self._pygamecanvas = sugargame.canvas.PygameCanvas( self, main=self.game.run, modules=[pygame.display, pygame.font]) # Note that set_canvas implicitly calls # read_file when resuming from the Journal. self.game.set_next_button(next_bt) self.set_canvas(self._pygamecanvas) Gdk.Screen.get_default().connect('size-changed', self.__configure_cb)
class SpeechToolbar(Gtk.Toolbar): def __init__(self): Gtk.Toolbar.__init__(self) voicebar = Gtk.Toolbar() self.activity = None self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == 'default': break default = default + 1 # Play button Image play_img = Gtk.Image() play_img.show() play_img.set_from_icon_name('media-playback-start', Gtk.IconSize.LARGE_TOOLBAR) # Pause button Image pause_img = Gtk.Image() pause_img.show() pause_img.set_from_icon_name('media-playback-pause', Gtk.IconSize.LARGE_TOOLBAR) # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_btn.connect('toggled', self.play_cb, [play_img, pause_img]) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) self.voice_combo = ComboBox() self.voice_combo.connect('changed', self.voice_changed_cb) for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() self.pitchadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) pitchbar = Gtk.HScale() pitchbar.set_adjustment(self.pitchadj) pitchbar.set_draw_value(False) # pitchbar.set_update_policy(Gtk.UpdatePolicy.ALWAYS) pitchbar.set_size_request(150,15) pitchtool = Gtk.ToolItem() pitchtool.add(pitchbar) pitchtool.show() self.insert(pitchtool, -1) pitchbar.show() self.rateadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) ratebar = Gtk.HScale() ratebar.set_adjustment(self.rateadj) ratebar.set_draw_value(False) #ratebar.set_update_policy(Gtk.UpdatePolicy.ALWAYS) ratebar.set_size_request(150,15) ratetool = Gtk.ToolItem() ratetool.add(ratebar) ratetool.show() self.insert(ratetool, -1) ratebar.show() def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0].lower() < b[0].lower(): return -1 if a[0].lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value if self.activity != None: speech.say(speech.voice[0]) def pitch_adjusted_cb(self, get): speech.pitch = int(get.get_value()) speech.say(_("pitch adjusted")) f = open(os.path.join(self.activity.get_activity_root(), 'instance', 'pitch.txt'), 'w') try: f.write(str(speech.pitch)) finally: f.close() def rate_adjusted_cb(self, get): speech.rate = int(get.get_value()) speech.say(_("rate adjusted")) f = open(os.path.join(self.activity.get_activity_root(), 'instance', 'rate.txt'), 'w') try: f.write(str(speech.rate)) finally: f.close() def set_activity(self, activity): self.activity = activity if os.path.exists(os.path.join(activity.get_activity_root(), 'instance', 'pitch.txt')): f = open(os.path.join(activity.get_activity_root(), 'instance', 'pitch.txt'), 'r') line = f.readline() pitch = int(line.strip()) self.pitchadj.set_value(pitch) speech.pitch = pitch f.close() if os.path.exists(os.path.join(activity.get_activity_root(), 'instance', 'rate.txt')): f = open(os.path.join(activity.get_activity_root(), 'instance', 'rate.txt'), 'r') line = f.readline() rate = int(line.strip()) self.rateadj.set_value(rate) speech.rate = rate f.close() self.pitchadj.connect("value_changed", self.pitch_adjusted_cb) self.rateadj.connect("value_changed", self.rate_adjusted_cb) def play_cb(self, widget, images): widget.set_icon_widget(images[int(widget.get_active())]) if widget.get_active(): if speech.is_stopped(): speech.play(self.activity.add_word_marks()) else: speech.stop()
def create_dialog(self): """Setup most of the dialog.""" # Toolbar self._toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self._parent) self._toolbar_box.toolbar.insert(activity_button, 0) def append(icon_name, label, page, position): toolbar_button = ToolbarButton() toolbar_button.props.page = page toolbar_button.props.icon_name = icon_name toolbar_button.props.label = label self._toolbar_box.toolbar.insert(toolbar_button, position) append('toolbar-edit', _('Edit'), EditToolbar(self._parent), -1) append('toolbar-algebra', _('Algebra'), AlgebraToolbar(self._parent), -1) append('toolbar-trigonometry', _('Trigonometry'), TrigonometryToolbar(self._parent), -1) append('toolbar-boolean', _('Boolean'), BooleanToolbar(self._parent), -1) self._misc_toolbar = MiscToolbar( self._parent, target_toolbar=self._toolbar_box.toolbar) append('toolbar-constants', _('Miscellaneous'), self._misc_toolbar, 5) self._stop_separator = Gtk.SeparatorToolItem() self._stop_separator.props.draw = False self._stop_separator.set_expand(True) self._stop_separator.show() self._toolbar_box.toolbar.insert(self._stop_separator, -1) self._stop = StopButton(self._parent) self._toolbar_box.toolbar.insert(self._stop, -1) self._toolbar_box.show_all() self._parent.set_toolbar_box(self._toolbar_box) # Some layout constants self.input_font = Pango.FontDescription('sans bold 12') self.button_font = Pango.FontDescription('sans bold 16') self.col_white = self.create_color(1.00, 1.00, 1.00) self.col_gray1 = self.create_color(0.76, 0.76, 0.76) self.col_gray2 = self.create_color(0.50, 0.50, 0.50) self.col_gray3 = self.create_color(0.25, 0.25, 0.25) self.col_black = self.create_color(0.00, 0.00, 0.00) self.col_red = self.create_color(1.00, 0.00, 0.00) # Big - Table, 16 rows, 10 columns, homogeneously divided self.grid = Gtk.Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_spacing(0) self.grid.set_column_spacing(4) # Left part: container and input vc1 = Gtk.VBox(False, 0) hc1 = Gtk.HBox(False, 10) eb = Gtk.EventBox() eb.add(hc1) eb.modify_bg(Gtk.StateType.NORMAL, self.col_black) eb.set_border_width(12) eb2 = Gtk.EventBox() eb2.add(eb) eb2.modify_bg(Gtk.StateType.NORMAL, self.col_black) label1 = Gtk.Label(label=_('Label:')) label1.modify_fg(Gtk.StateType.NORMAL, self.col_white) label1.set_alignment(1, 0.5) hc1.pack_start(label1, expand=False, fill=False, padding=10) self.label_entry = Gtk.Entry() self.label_entry.modify_bg(Gtk.StateType.INSENSITIVE, self.col_black) hc1.pack_start(self.label_entry, expand=True, fill=True, padding=0) vc1.pack_start(eb2, False, True, 0) self.text_entry = Gtk.Entry() try: self.text_entry.props.im_module = 'gtk-im-context-simple' except AttributeError: pass self.text_entry.set_size_request(-1, 75) self.text_entry.connect('key_press_event', self._parent.ignore_key_cb) self.text_entry.modify_font(self.input_font) self.text_entry.modify_bg(Gtk.StateType.INSENSITIVE, self.col_black) eb = Gtk.EventBox() eb.add(self.text_entry) eb.modify_bg(Gtk.StateType.NORMAL, self.col_black) eb.set_border_width(12) eb2 = Gtk.EventBox() eb2.add(eb) eb2.modify_bg(Gtk.StateType.NORMAL, self.col_black) vc1.pack_start(eb2, expand=True, fill=True, padding=0) self.grid.attach(vc1, 0, 0, 7, 6) # Left part: buttons self.pad = Gtk.Grid() self.pad.set_column_homogeneous(True) self.pad.set_row_spacing(6) self.pad.set_column_spacing(6) self.create_button_data() self.buttons = {} for x, y, w, h, cap, bgcol, cb in self.button_data: button = self.create_button(_(cap), cb, self.col_white, bgcol, w, h) self.buttons[cap] = button self.pad.attach(button, x, y, w, h) eb = Gtk.EventBox() eb.add(self.pad) eb.modify_bg(Gtk.StateType.NORMAL, self.col_black) self.grid.attach(eb, 0, 6, 7, 20) # Right part: container and equation button hc2 = Gtk.HBox() combo = ComboBox() combo.append_item(0, _('All equations')) combo.append_item(1, _('My equations')) combo.append_item(2, _('Show variables')) combo.set_active(0) combo.connect('changed', self._history_filter_cb) hc2.pack_start(combo, True, True, 0) hc2.set_border_width(6) self.grid.attach(hc2, 7, 0, 4, 2) # Right part: last equation self.last_eq = Gtk.TextView() self.last_eq.set_editable(False) self.last_eq.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.last_eq.connect('realize', self._textview_realize_cb) self.last_eq.modify_base( Gtk.StateType.NORMAL, Gdk.color_parse(sugar3.profile.get_color().get_fill_color())) self.last_eq.modify_bg( Gtk.StateType.NORMAL, Gdk.color_parse(sugar3.profile.get_color().get_stroke_color())) self.last_eq.set_border_window_size(Gtk.TextWindowType.LEFT, 4) self.last_eq.set_border_window_size(Gtk.TextWindowType.RIGHT, 4) self.last_eq.set_border_window_size(Gtk.TextWindowType.TOP, 4) self.last_eq.set_border_window_size(Gtk.TextWindowType.BOTTOM, 4) # TODO Fix for old Sugar 0.82 builds, red_float not available xo_color = sugar3.profile.get_color() bright = (Gdk.color_parse(xo_color.get_fill_color()).red_float + Gdk.color_parse(xo_color.get_fill_color()).green_float + Gdk.color_parse(xo_color.get_fill_color()).blue_float) / 3.0 if bright < 0.5: self.last_eq.modify_text(Gtk.StateType.NORMAL, self.col_white) else: self.last_eq.modify_text(Gtk.StateType.NORMAL, self.col_black) self.grid.attach(self.last_eq, 7, 2, 4, 5) # Right part: history scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.history_vbox = Gtk.VBox() self.history_vbox.set_homogeneous(False) self.history_vbox.set_border_width(0) self.history_vbox.set_spacing(4) self.variable_vbox = Gtk.VBox() self.variable_vbox.set_homogeneous(False) self.variable_vbox.set_border_width(0) self.variable_vbox.set_spacing(4) vbox = Gtk.VBox() vbox.pack_start(self.history_vbox, True, True, 0) vbox.pack_start(self.variable_vbox, True, True, 0) scrolled_window.add_with_viewport(vbox) self.grid.attach(scrolled_window, 7, 7, 4, 19) Gdk.Screen.get_default().connect('size-changed', self._configure_cb)
def __init__(self): Gtk.Toolbar.__init__(self) self.activity = None self._speech = SpeechManager() self._voices = self._speech.get_all_voices() # a dictionary locale = os.environ.get('LANG', '') language_location = locale.split('.', 1)[0].lower() language = language_location.split('_')[0] # if the language is es but not es_es default to es_la (latin voice) if language == 'es' and language_location != 'es_es': language_location = 'es_la' self._voice = 'en_us' if language_location in self._voices: self._voice = language_location elif language in self._voices: self._voice = language voice_names = [] for language, name in self._voices.iteritems(): voice_names.append((language, name)) voice_names.sort(self._compare_voices) # Play button Image play_img = Gtk.Image() play_img.show() play_img.set_from_icon_name('media-playback-start', Gtk.IconSize.LARGE_TOOLBAR) # Pause button Image pause_img = Gtk.Image() pause_img.show() pause_img.set_from_icon_name('media-playback-pause', Gtk.IconSize.LARGE_TOOLBAR) # Play button self.play_button = ToggleToolButton('media-playback-start') self.play_button.show() self.play_button.connect('toggled', self._play_toggled_cb, [play_img, pause_img]) self.insert(self.play_button, -1) self.play_button.set_tooltip(_('Play / Pause')) combo = ComboBox() which = 0 for pair in voice_names: language, name = pair combo.append_item(language, name) if language == self._voice: combo.set_active(which) which += 1 combo.connect('changed', self._voice_changed_cb) combotool = ToolComboBox(combo) self.insert(combotool, -1) combotool.show() self.pitchadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) pitchbar = Gtk.HScale() pitchbar.set_adjustment(self.pitchadj) pitchbar.set_draw_value(False) # pitchbar.set_update_policy(Gtk.UpdatePolicy.ALWAYS) pitchbar.set_size_request(150,15) pitchtool = Gtk.ToolItem() pitchtool.add(pitchbar) pitchtool.show() self.insert(pitchtool, -1) pitchbar.show() self.rateadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) ratebar = Gtk.HScale() ratebar.set_adjustment(self.rateadj) ratebar.set_draw_value(False) #ratebar.set_update_policy(Gtk.UpdatePolicy.ALWAYS) ratebar.set_size_request(150,15) ratetool = Gtk.ToolItem() ratetool.add(ratebar) ratetool.show() self.insert(ratetool, -1) ratebar.show()
class MainToolbox(ToolbarBox): __gsignals__ = { 'query-changed': (GObject.SignalFlags.RUN_FIRST, None, ([object])), } def __init__(self): ToolbarBox.__init__(self) self._mount_point = None self.search_entry = iconentry.IconEntry() self.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'entry-search') text = _('Search in %s') % _('Journal') self.search_entry.set_placeholder_text(text) self.search_entry.connect('activate', self._search_entry_activated_cb) self.search_entry.connect('changed', self._search_entry_changed_cb) self.search_entry.add_clear_button() self._autosearch_timer = None self._add_widget(self.search_entry, expand=True) self._favorite_button = ToggleToolButton('emblem-favorite') self._favorite_button.set_tooltip(_('Favorite entries')) self._favorite_button.connect('toggled', self.__favorite_button_toggled_cb) self.toolbar.insert(self._favorite_button, -1) self._favorite_button.show() self._what_search_combo = ComboBox() self._what_combo_changed_sid = self._what_search_combo.connect( 'changed', self._combo_changed_cb) tool_item = ToolComboBox(self._what_search_combo) self.toolbar.insert(tool_item, -1) tool_item.show() self._when_search_combo = self._get_when_search_combo() tool_item = ToolComboBox(self._when_search_combo) self.toolbar.insert(tool_item, -1) tool_item.show() self._sorting_button = SortingButton() self.toolbar.insert(self._sorting_button, -1) self._sorting_button.connect('sort-property-changed', self.__sort_changed_cb) self._sorting_button.show() # TODO: enable it when the DS supports saving the buddies. #self._with_search_combo = self._get_with_search_combo() #tool_item = ToolComboBox(self._with_search_combo) #self.insert(tool_item, -1) #tool_item.show() self._query = self._build_query() self.refresh_filters() def _get_when_search_combo(self): when_search = ComboBox() when_search.append_item(_ACTION_ANYTIME, _('Anytime')) when_search.append_separator() when_search.append_item(_ACTION_TODAY, _('Today')) when_search.append_item(_ACTION_SINCE_YESTERDAY, _('Since yesterday')) # TRANS: Filter entries modified during the last 7 days. when_search.append_item(_ACTION_PAST_WEEK, _('Past week')) # TRANS: Filter entries modified during the last 30 days. when_search.append_item(_ACTION_PAST_MONTH, _('Past month')) # TRANS: Filter entries modified during the last 356 days. when_search.append_item(_ACTION_PAST_YEAR, _('Past year')) when_search.set_active(0) when_search.connect('changed', self._combo_changed_cb) return when_search def _get_with_search_combo(self): with_search = ComboBox() with_search.append_item(_ACTION_EVERYBODY, _('Anyone')) with_search.append_separator() with_search.append_item(_ACTION_MY_FRIENDS, _('My friends')) with_search.append_item(_ACTION_MY_CLASS, _('My class')) with_search.append_separator() # TODO: Ask the model for buddies. with_search.append_item(3, 'Dan', 'theme:xo') with_search.set_active(0) with_search.connect('changed', self._combo_changed_cb) return with_search def _add_widget(self, widget, expand=False): tool_item = Gtk.ToolItem() tool_item.set_expand(expand) tool_item.add(widget) widget.show() self.toolbar.insert(tool_item, -1) tool_item.show() def _build_query(self): query = {} if self._mount_point: query['mountpoints'] = [self._mount_point] if self._favorite_button.props.active: query['keep'] = 1 if self._what_search_combo.props.value: value = self._what_search_combo.props.value generic_type = mime.get_generic_type(value) if generic_type: mime_types = generic_type.mime_types query['mime_type'] = mime_types else: query['activity'] = self._what_search_combo.props.value if self._when_search_combo.props.value: date_from, date_to = self._get_date_range() query['timestamp'] = {'start': date_from, 'end': date_to} if self.search_entry.props.text: text = self.search_entry.props.text.strip() if text: query['query'] = text property_, order = self._sorting_button.get_current_sort() if order == Gtk.SortType.ASCENDING: sign = '+' else: sign = '-' query['order_by'] = [sign + property_] return query def _get_date_range(self): today_start = datetime.today().replace(hour=0, minute=0, second=0) right_now = datetime.today() if self._when_search_combo.props.value == _ACTION_TODAY: date_range = (today_start, right_now) elif self._when_search_combo.props.value == _ACTION_SINCE_YESTERDAY: date_range = (today_start - timedelta(1), right_now) elif self._when_search_combo.props.value == _ACTION_PAST_WEEK: date_range = (today_start - timedelta(7), right_now) elif self._when_search_combo.props.value == _ACTION_PAST_MONTH: date_range = (today_start - timedelta(30), right_now) elif self._when_search_combo.props.value == _ACTION_PAST_YEAR: date_range = (today_start - timedelta(356), right_now) return (time.mktime(date_range[0].timetuple()), time.mktime(date_range[1].timetuple())) def _combo_changed_cb(self, combo): self._update_if_needed() def __sort_changed_cb(self, button): self._update_if_needed() def _update_if_needed(self): new_query = self._build_query() if self._query != new_query: self._query = new_query self.emit('query-changed', self._query) def _search_entry_activated_cb(self, search_entry): if self._autosearch_timer: GObject.source_remove(self._autosearch_timer) new_query = self._build_query() if self._query != new_query: self._query = new_query self.emit('query-changed', self._query) def _search_entry_changed_cb(self, search_entry): if not search_entry.props.text: search_entry.activate() return if self._autosearch_timer: GObject.source_remove(self._autosearch_timer) self._autosearch_timer = GObject.timeout_add(_AUTOSEARCH_TIMEOUT, self._autosearch_timer_cb) def _autosearch_timer_cb(self): logging.debug('_autosearch_timer_cb') self._autosearch_timer = None self.search_entry.activate() return False def set_mount_point(self, mount_point): self._mount_point = mount_point new_query = self._build_query() if self._query != new_query: self._query = new_query self.emit('query-changed', self._query) def set_what_filter(self, what_filter): combo_model = self._what_search_combo.get_model() what_filter_index = -1 for i in range(0, len(combo_model) - 1): if combo_model[i][0] == what_filter: what_filter_index = i break if what_filter_index == -1: logging.warning('what_filter %r not known', what_filter) else: self._what_search_combo.set_active(what_filter_index) def refresh_filters(self): current_value = self._what_search_combo.props.value current_value_index = 0 self._what_search_combo.handler_block(self._what_combo_changed_sid) try: self._what_search_combo.remove_all() # TRANS: Item in a combo box that filters by entry type. self._what_search_combo.append_item(_ACTION_ANYTHING, _('Anything')) registry = bundleregistry.get_registry() appended_separator = False types = mime.get_all_generic_types() for generic_type in types: if not appended_separator: self._what_search_combo.append_separator() appended_separator = True self._what_search_combo.append_item(generic_type.type_id, generic_type.name, generic_type.icon) if generic_type.type_id == current_value: current_value_index = \ len(self._what_search_combo.get_model()) - 1 self._what_search_combo.set_active(current_value_index) self._what_search_combo.append_separator() for service_name in model.get_unique_values('activity'): activity_info = registry.get_bundle(service_name) if activity_info is None: continue if service_name == current_value: combo_model = self._what_search_combo.get_model() current_value_index = len(combo_model) # try activity-provided icon if os.path.exists(activity_info.get_icon()): try: self._what_search_combo.append_item( service_name, activity_info.get_name(), file_name=activity_info.get_icon()) except GObject.GError, exception: logging.warning( 'Falling back to default icon for' ' "what" filter because %r (%r) has an' ' invalid icon: %s', activity_info.get_name(), str(service_name), exception) else: continue # fall back to generic icon self._what_search_combo.append_item( service_name, activity_info.get_name(), icon_name='application-octet-stream') finally: self._what_search_combo.handler_unblock( self._what_combo_changed_sid) def __favorite_button_toggled_cb(self, favorite_button): self._update_if_needed() def clear_query(self): self.search_entry.props.text = '' self._what_search_combo.set_active(0) self._when_search_combo.set_active(0) self._favorite_button.props.active = False
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): GObject.GObject.__init__(self) self._activity = activity if not speech.supported: return self.is_paused = False self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_toggled_handler = self.play_btn.connect( 'toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) # Stop button self.stop_btn = ToolButton('media-playback-stop') self.stop_btn.show() self.stop_btn.connect('clicked', self.stop_cb) self.stop_btn.set_sensitive(False) self.insert(self.stop_btn, -1) self.stop_btn.set_tooltip(_('Stop')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() speech.reset_cb = self.reset_buttons_cb speech.end_text_cb = self.reset_buttons_cb def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0].lower() < b[0].lower(): return -1 if a[0].lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = json.load(f) speech.voice = speech_parameters['voice'] finally: f.close() def save_speech_parameters(self): speech_parameters = {} speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: json.dump(speech_parameters, f) finally: f.close() def reset_buttons_cb(self): logging.error('reset buttons') self.play_btn.set_icon_name('media-playback-start') self.stop_btn.set_sensitive(False) self.play_btn.handler_block(self.play_toggled_handler) self.play_btn.set_active(False) self.play_btn.handler_unblock(self.play_toggled_handler) self.is_paused = False def play_cb(self, widget): self.stop_btn.set_sensitive(True) if widget.get_active(): self.play_btn.set_icon_name('media-playback-pause') logging.error('Paused %s', self.is_paused) if not self.is_paused: # get the text to speech, if there are a selection, # play selected text, if not, play all abi = self._activity.abiword_canvas selection = abi.get_selection('text/plain') if not selection or selection[0] is None or selection[1] == 0: # nothing selected abi.select_all() text = abi.get_selection('text/plain')[0] abi.moveto_bod() else: text = selection[0] speech.play(text) else: logging.error('Continue play') speech.continue_play() else: self.play_btn.set_icon_name('media-playback-start') self.is_paused = True speech.pause() def stop_cb(self, widget): self.stop_btn.set_sensitive(False) self.play_btn.set_icon_name('media-playback-start') self.play_btn.set_active(False) self.is_paused = False speech.stop()
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): GObject.GObject.__init__(self) self._activity = activity if not speech.supported: return self.is_paused = False self._cnf_client = GConf.Client.get_default() self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_toggled_handler = self.play_btn.connect( 'toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) # Stop button self.stop_btn = ToolButton('media-playback-stop') self.stop_btn.show() self.stop_btn.connect('clicked', self.stop_cb) self.stop_btn.set_sensitive(False) self.insert(self.stop_btn, -1) self.stop_btn.set_tooltip(_('Stop')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() speech.reset_cb = self.reset_buttons_cb speech.end_text_cb = self.reset_buttons_cb def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0].lower() < b[0].lower(): return -1 if a[0].lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = json.load(f) speech.voice = speech_parameters['voice'] finally: f.close() else: speech.voice = self.get_default_voice() logging.error('Default voice %s', speech.voice) self._cnf_client.add_dir('/desktop/sugar/speech', GConf.ClientPreloadType.PRELOAD_NONE) speech.pitch = self._cnf_client.get_int('/desktop/sugar/speech/pitch') speech.rate = self._cnf_client.get_int('/desktop/sugar/speech/rate') self._cnf_client.notify_add('/desktop/sugar/speech/pitch', self.__conf_changed_cb, None) self._cnf_client.notify_add('/desktop/sugar/speech/rate', self.__conf_changed_cb, None) def get_default_voice(self): """Try to figure out the default voice, from the current locale ($LANG) Fall back to espeak's voice called Default.""" voices = speech.get_all_voices() locale = os.environ.get('LANG', '') language_location = locale.split('.', 1)[0].lower() language = language_location.split('_')[0] variant = '' if language_location.find('_') > -1: variant = language_location.split('_')[1] # if the language is es but not es_es default to es_la (latin voice) if language == 'es' and language_location != 'es_es': language_location = 'es_la' best = voices.get(language_location) or voices.get(language) \ or 'default' logging.debug('Best voice for LANG %s seems to be %s', locale, best) return [best, language, variant] def __conf_changed_cb(self, client, connection_id, entry, args): key = entry.get_key() value = client.get_int(key) if key == '/desktop/sugar/speech/pitch': speech.pitch = value if key == '/desktop/sugar/speech/rate': speech.rate = value def save_speech_parameters(self): speech_parameters = {} speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: json.dump(speech_parameters, f) finally: f.close() def reset_buttons_cb(self): logging.error('reset buttons') self.play_btn.set_icon_name('media-playback-start') self.stop_btn.set_sensitive(False) self.play_btn.handler_block(self.play_toggled_handler) self.play_btn.set_active(False) self.play_btn.handler_unblock(self.play_toggled_handler) self.is_paused = False def play_cb(self, widget): self.stop_btn.set_sensitive(True) if widget.get_active(): self.play_btn.set_icon_name('media-playback-pause') logging.error('Paused %s', self.is_paused) if not self.is_paused: # get the text to speech, if there are a selection, # play selected text, if not, play all abi = self._activity.abiword_canvas selection = abi.get_selection('text/plain') if not selection or selection[0] is None or selection[1] == 0: # nothing selected abi.select_all() text = abi.get_selection('text/plain')[0] abi.moveto_bod() else: text = selection[0] speech.play(text) else: logging.error('Continue play') speech.continue_play() else: self.play_btn.set_icon_name('media-playback-start') self.is_paused = True speech.pause() def stop_cb(self, widget): self.stop_btn.set_sensitive(False) self.play_btn.set_icon_name('media-playback-start') self.play_btn.set_active(False) self.is_paused = False speech.stop()
def create_dialog(self): """Setup most of the dialog.""" # Toolbar self._toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self._parent) self._toolbar_box.toolbar.insert(activity_button, 0) def append(icon_name, label, page, position): toolbar_button = ToolbarButton() toolbar_button.props.page = page toolbar_button.props.icon_name = icon_name toolbar_button.props.label = label self._toolbar_box.toolbar.insert(toolbar_button, position) append('toolbar-edit', _('Edit'), EditToolbar(self._parent), -1) append('toolbar-algebra', _('Algebra'), AlgebraToolbar(self._parent), -1) append('toolbar-trigonometry', _('Trigonometry'), TrigonometryToolbar(self._parent), -1) append('toolbar-boolean', _('Boolean'), BooleanToolbar(self._parent), -1) self._misc_toolbar = MiscToolbar( self._parent, target_toolbar=self._toolbar_box.toolbar) append('toolbar-constants', _('Miscellaneous'), self._misc_toolbar, 5) self._stop_separator = Gtk.SeparatorToolItem() self._stop_separator.props.draw = False self._stop_separator.set_expand(True) self._stop_separator.show() self._toolbar_box.toolbar.insert(self._stop_separator, -1) self._stop = StopButton(self._parent) self._toolbar_box.toolbar.insert(self._stop, -1) self._toolbar_box.show_all() self._parent.set_toolbar_box(self._toolbar_box) # Some layout constants self.input_font = Pango.FontDescription('sans bold 12') self.button_font = Pango.FontDescription('sans bold 16') self.col_white = self.create_color(1.00, 1.00, 1.00) self.col_gray1 = self.create_color(0.76, 0.76, 0.76) self.col_gray2 = self.create_color(0.50, 0.50, 0.50) self.col_gray3 = self.create_color(0.25, 0.25, 0.25) self.col_black = self.create_color(0.00, 0.00, 0.00) self.col_red = self.create_color(1.00, 0.00, 0.00) # Big - Table, 16 rows, 10 columns, homogeneously divided self.grid = Gtk.Grid() self.grid.set_column_homogeneous(True) self.grid.set_row_spacing(0) self.grid.set_column_spacing(4) # Left part: container and input vc1 = Gtk.VBox(False, 0) hc1 = Gtk.HBox(False, 10) eb = Gtk.EventBox() eb.add(hc1) eb.modify_bg(Gtk.StateType.NORMAL, self.col_black) eb.set_border_width(12) eb2 = Gtk.EventBox() eb2.add(eb) eb2.modify_bg(Gtk.StateType.NORMAL, self.col_black) label1 = Gtk.Label(label=_('Label:')) label1.modify_fg(Gtk.StateType.NORMAL, self.col_white) label1.set_alignment(1, 0.5) hc1.pack_start(label1, expand=False, fill=False, padding=10) self.label_entry = Gtk.Entry() self.label_entry.modify_bg(Gtk.StateType.INSENSITIVE, self.col_black) hc1.pack_start(self.label_entry, expand=True, fill=True, padding=0) vc1.pack_start(eb2, False, True, 0) self.text_entry = Gtk.Entry() try: self.text_entry.props.im_module = 'gtk-im-context-simple' except AttributeError: pass self.text_entry.set_size_request(-1, 75) self.text_entry.connect('key_press_event', self._parent.ignore_key_cb) self.text_entry.modify_font(self.input_font) self.text_entry.modify_bg(Gtk.StateType.INSENSITIVE, self.col_black) eb = Gtk.EventBox() eb.add(self.text_entry) eb.modify_bg(Gtk.StateType.NORMAL, self.col_black) eb.set_border_width(12) eb2 = Gtk.EventBox() eb2.add(eb) eb2.modify_bg(Gtk.StateType.NORMAL, self.col_black) vc1.pack_start(eb2, expand=True, fill=True, padding=0) self.grid.attach(vc1, 0, 0, 7, 6) # Left part: buttons self.pad = Gtk.Grid() self.pad.set_column_homogeneous(True) self.pad.set_row_spacing(6) self.pad.set_column_spacing(6) self.create_button_data() self.buttons = {} for x, y, w, h, cap, bgcol, cb in self.button_data: button = self.create_button( _(cap), cb, self.col_white, bgcol, w, h) self.buttons[cap] = button self.pad.attach(button, x, y, w, h) eb = Gtk.EventBox() eb.add(self.pad) eb.modify_bg(Gtk.StateType.NORMAL, self.col_black) self.grid.attach(eb, 0, 6, 7, 20) # Right part: container and equation button hc2 = Gtk.HBox() combo = ComboBox() combo.append_item(0, _('All equations')) combo.append_item(1, _('My equations')) combo.append_item(2, _('Show variables')) combo.set_active(0) combo.connect('changed', self._history_filter_cb) hc2.pack_start(combo, True, True, 0) hc2.set_border_width(6) self.grid.attach(hc2, 7, 0, 4, 2) # Right part: last equation self.last_eq = Gtk.TextView() self.last_eq.set_editable(False) self.last_eq.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) self.last_eq.connect('realize', self._textview_realize_cb) self.last_eq.modify_base(Gtk.StateType.NORMAL, Gdk.color_parse( sugar3.profile.get_color().get_fill_color())) self.last_eq.modify_bg(Gtk.StateType.NORMAL, Gdk.color_parse( sugar3.profile.get_color().get_stroke_color())) self.last_eq.set_border_window_size(Gtk.TextWindowType.LEFT, 4) self.last_eq.set_border_window_size(Gtk.TextWindowType.RIGHT, 4) self.last_eq.set_border_window_size(Gtk.TextWindowType.TOP, 4) self.last_eq.set_border_window_size(Gtk.TextWindowType.BOTTOM, 4) # TODO Fix for old Sugar 0.82 builds, red_float not available xo_color = sugar3.profile.get_color() bright = ( Gdk.color_parse(xo_color.get_fill_color()).red_float + Gdk.color_parse(xo_color.get_fill_color()).green_float + Gdk.color_parse(xo_color.get_fill_color()).blue_float) / 3.0 if bright < 0.5: self.last_eq.modify_text(Gtk.StateType.NORMAL, self.col_white) else: self.last_eq.modify_text(Gtk.StateType.NORMAL, self.col_black) self.grid.attach(self.last_eq, 7, 2, 4, 5) # Right part: history scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.history_vbox = Gtk.VBox() self.history_vbox.set_homogeneous(False) self.history_vbox.set_border_width(0) self.history_vbox.set_spacing(4) self.variable_vbox = Gtk.VBox() self.variable_vbox.set_homogeneous(False) self.variable_vbox.set_border_width(0) self.variable_vbox.set_spacing(4) vbox = Gtk.VBox() vbox.pack_start(self.history_vbox, True, True, 0) vbox.pack_start(self.variable_vbox, True, True, 0) scrolled_window.add_with_viewport(vbox) self.grid.attach(scrolled_window, 7, 7, 4, 19) Gdk.Screen.get_default().connect('size-changed', self._configure_cb)
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): Gtk.Toolbar.__init__(self) self._activity = activity if not speech.supported: return self.is_paused = False self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_btn.connect('toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) # Stop button self.stop_btn = ToolButton('media-playback-stop') self.stop_btn.show() self.stop_btn.connect('clicked', self.stop_cb) self.stop_btn.set_sensitive(False) self.insert(self.stop_btn, -1) self.stop_btn.set_tooltip(_('Stop')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() speech.reset_buttons_cb = self.reset_buttons_cb def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0].lower() < b[0].lower(): return -1 if a[0].lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = json.load(f) speech.voice = speech_parameters['voice'] finally: f.close() def save_speech_parameters(self): speech_parameters = {} speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: json.dump(speech_parameters, f) finally: f.close() def reset_buttons_cb(self): self.play_btn.set_icon_name('media-playback-start') self.stop_btn.set_sensitive(False) self.is_paused = False def play_cb(self, widget): self.stop_btn.set_sensitive(True) if widget.get_active(): self.play_btn.set_icon_name('media-playback-pause') if not self.is_paused: speech.play(self._activity._view.get_marked_words()) else: speech.continue_play() else: self.play_btn.set_icon_name('media-playback-start') self.is_paused = True speech.pause() def stop_cb(self, widget): self.stop_btn.set_sensitive(False) self.play_btn.set_icon_name('media-playback-start') self.play_btn.set_active(False) self.is_paused = False speech.stop()
class GetIABooksActivity(activity.Activity): def __init__(self, handle): "The entry point to the Activity" activity.Activity.__init__(self, handle, False) self.max_participants = 1 self._sequence = 0 self.selected_book = None self.queryresults = None self._getter = None self.show_images = True self.languages = {} self._lang_code_handler = languagenames.LanguageNames() self.catalogs_configuration = {} self.catalog_history = [] if os.path.exists('/etc/get-books.cfg'): self._read_configuration('/etc/get-books.cfg') else: self._read_configuration() toolbar_box = ToolbarBox() activity_button = ToolButton() color = profile.get_color() bundle = ActivityBundle(activity.get_bundle_path()) icon = Icon(file=bundle.get_icon(), xo_color=color) activity_button.set_icon_widget(icon) activity_button.show() toolbar_box.toolbar.insert(activity_button, 0) self._add_search_controls(toolbar_box.toolbar) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) toolbar_box.toolbar.insert(StopButton(self), -1) self.set_toolbar_box(toolbar_box) toolbar_box.show_all() self._books_toolbar = toolbar_box.toolbar self._create_controls() self.using_powerd = os.access(POWERD_INHIBIT_DIR, os.W_OK) self.__book_downloader = self.__image_downloader = None def get_path(self): self._sequence += 1 return os.path.join(self.get_activity_root(), 'instance', '%03d.tmp' % self._sequence) def _inhibit_suspend(self): if self.using_powerd: fd = open(POWERD_INHIBIT_DIR + "/%u" % os.getpid(), 'w') logging.error("inhibit_suspend file is %s", (POWERD_INHIBIT_DIR \ + "/%u" % os.getpid())) fd.close() return True return False def _allow_suspend(self): if self.using_powerd: if os.path.exists(POWERD_INHIBIT_DIR + "/%u" % os.getpid()): os.unlink(POWERD_INHIBIT_DIR + "/%u" % os.getpid()) logging.error("allow_suspend unlinking %s", (POWERD_INHIBIT_DIR \ + "/%u" % os.getpid())) return True return False def _read_configuration(self, file_name='get-books.cfg'): logging.error('Reading configuration from file %s', file_name) config = ConfigParser.ConfigParser() config.readfp(open(file_name)) if config.has_option('GetBooks', 'show_images'): self.show_images = config.getboolean('GetBooks', 'show_images') self.languages = {} if config.has_option('GetBooks', 'languages'): languages_param = config.get('GetBooks', 'languages') for language in languages_param.split(','): lang_code = language.strip() if len(lang_code) > 0: self.languages[lang_code] = \ self._lang_code_handler.get_full_language_name(lang_code) for section in config.sections(): if section != 'GetBooks' and not section.startswith('Catalogs'): name = config.get(section, 'name') _SOURCES[section] = name repo_config = {} repo_config['query_uri'] = config.get(section, 'query_uri') repo_config['opds_cover'] = config.get(section, 'opds_cover') if config.has_option(section, 'summary_field'): repo_config['summary_field'] = \ config.get(section, 'summary_field') else: repo_config['summary_field'] = None if config.has_option(section, 'blacklist'): blacklist = config.get(section, 'blacklist') repo_config['blacklist'] = blacklist.split(',') # TODO strip? else: repo_config['blacklist'] = [] _SOURCES_CONFIG[section] = repo_config logging.error('_SOURCES %s', pformat(_SOURCES)) logging.error('_SOURCES_CONFIG %s', pformat(_SOURCES_CONFIG)) for section in config.sections(): if section.startswith('Catalogs'): catalog_source = section.split('_')[1] if not catalog_source in _SOURCES_CONFIG: logging.error( 'There are not a source for the catalog ' + 'section %s', section) break source_config = _SOURCES_CONFIG[catalog_source] opds_cover = source_config['opds_cover'] for catalog in config.options(section): catalog_config = {} catalog_config['query_uri'] = config.get(section, catalog) catalog_config['opds_cover'] = opds_cover catalog_config['source'] = catalog_source catalog_config['name'] = catalog catalog_config['summary_field'] = \ source_config['summary_field'] self.catalogs_configuration[catalog] = catalog_config self.source = _SOURCES_CONFIG.keys()[0] self.filter_catalogs_by_source() logging.error('languages %s', pformat(self.languages)) logging.error('catalogs %s', pformat(self.catalogs)) def _add_search_controls(self, toolbar): book_search_item = Gtk.ToolItem() toolbar.search_entry = iconentry.IconEntry() toolbar.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'system-search') toolbar.search_entry.add_clear_button() toolbar.search_entry.connect('activate', self.__search_entry_activate_cb) width = int(Gdk.Screen.width() / 4) toolbar.search_entry.set_size_request(width, -1) book_search_item.add(toolbar.search_entry) toolbar.search_entry.show() toolbar.insert(book_search_item, -1) book_search_item.show() toolbar.source_combo = ComboBox() toolbar.source_combo.props.sensitive = True toolbar.source_changed_cb_id = \ toolbar.source_combo.connect('changed', self.__source_changed_cb) combotool = ToolComboBox(toolbar.source_combo) toolbar.insert(combotool, -1) combotool.show() self.bt_catalogs = ToggleToolButton('books') self.bt_catalogs.set_tooltip(_('Catalogs')) toolbar.insert(self.bt_catalogs, -1) self.bt_catalogs.connect('toggled', self.__toggle_cats_cb) if len(self.catalogs) > 0: self.bt_catalogs.show() if len(self.languages) > 0: toolbar.config_toolbarbutton = ToolbarButton() toolbar.config_toolbarbutton.props.icon_name = 'preferences-system' toolbar.config_toolbarbox = Gtk.Toolbar() toolbar.config_toolbarbutton.props.page = toolbar.config_toolbarbox toolbar.language_combo = ComboBox() toolbar.language_combo.props.sensitive = True combotool = ToolComboBox(toolbar.language_combo) toolbar.language_combo.append_item('all', _('Any language')) for key in self.languages.keys(): toolbar.language_combo.append_item(key, self.languages[key]) toolbar.language_combo.set_active(0) toolbar.config_toolbarbutton.props.page.insert(combotool, -1) toolbar.insert(toolbar.config_toolbarbutton, -1) toolbar.config_toolbarbutton.show() combotool.show() toolbar.language_changed_cb_id = \ toolbar.language_combo.connect('changed', self.__language_changed_cb) self._device_manager = devicemanager.DeviceManager() self._refresh_sources(toolbar) self._device_manager.connect('device-changed', self.__device_changed_cb) toolbar.search_entry.grab_focus() return toolbar def __bt_catalogs_clicked_cb(self, button): palette = button.get_palette() palette.popup(immediate=True, state=palette.SECONDARY) def __switch_catalog_cb(self, catalog_name): catalog_config = self.catalogs[catalog_name.decode('utf-8')] self.__activate_catalog_cb(None, catalog_config) def __activate_catalog_cb(self, menu, catalog_config): query_language = self.get_query_language() self.enable_button(False) self.clear_downloaded_bytes() self.book_selected = False self.listview.handler_block(self.selection_cb_id) self.listview.clear() self.listview.handler_unblock(self.selection_cb_id) logging.error('SOURCE %s', catalog_config['source']) self._books_toolbar.search_entry.props.text = '' self.source = catalog_config['source'] position = _SOURCES_CONFIG[self.source]['position'] self._books_toolbar.source_combo.set_active(position) if self.queryresults is not None: self.queryresults.cancel() self.queryresults = None self.queryresults = opds.RemoteQueryResult(catalog_config, '', query_language) self.show_message(_('Performing lookup, please wait...')) # README: I think we should create some global variables for # each cursor that we are using to avoid the creation of them # every time that we want to change it self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH)) self.queryresults.connect('updated', self.__query_updated_cb) def update_format_combo(self, links): self.format_combo.handler_block(self.__format_changed_cb_id) self.format_combo.remove_all() for key in _MIMETYPES.keys(): if _MIMETYPES[key] in links.keys(): self.format_combo.append_item(_MIMETYPES[key], key) self.format_combo.set_active(0) self.format_combo.handler_unblock(self.__format_changed_cb_id) def get_search_terms(self): return self._books_toolbar.search_entry.props.text def __device_changed_cb(self, mgr): logging.debug('Device was added/removed') self._refresh_sources(self._books_toolbar) def _refresh_sources(self, toolbar): toolbar.source_combo.handler_block(toolbar.source_changed_cb_id) #TODO: Do not blindly clear this toolbar.source_combo.remove_all() position = 0 for key in _SOURCES.keys(): toolbar.source_combo.append_item(_SOURCES[key], key, icon_name='internet-icon') _SOURCES_CONFIG[key]['position'] = position position = position + 1 # Add menu for local books if len(_SOURCES) > 0: toolbar.source_combo.append_separator() toolbar.source_combo.append_item('local_books', _('My books'), icon_name='activity-journal') devices = self._device_manager.get_devices() first_device = True for device_name in devices: device = devices[device_name] logging.debug('device %s', device) if device['removable']: mount_point = device['mount_path'] label = device['label'] if label == '' or label is None: capacity = device['size'] label = (_('%.2f GB Volume') % (capacity / (1024.0**3))) logging.debug('Adding device %s', (label)) if first_device: toolbar.source_combo.append_separator() first_device = False toolbar.source_combo.append_item(mount_point, label) toolbar.source_combo.set_active(0) toolbar.source_combo.handler_unblock(toolbar.source_changed_cb_id) def __format_changed_cb(self, combo): self.show_book_data(False) def __language_changed_cb(self, combo): self.find_books(self.get_search_terms()) def __search_entry_activate_cb(self, entry): self.find_books(self.get_search_terms()) def __get_book_cb(self, button): self.get_book() def enable_button(self, state): self._download.props.sensitive = state self.format_combo.props.sensitive = state def move_up_catalog(self, treeview): len_cat = len(self.catalog_history) if len_cat == 1: return else: # move a level up the tree self.catalog_listview.handler_block(self._catalog_changed_id) self.catalog_history.pop() len_cat -= 1 if (len_cat == 1): title = self.catalog_history[0]['title'] self.bt_move_up_catalog.set_label(title) self.bt_move_up_catalog.hide_image() else: title = self.catalog_history[len_cat - 1]['title'] self.bt_move_up_catalog.set_label(title) self.bt_move_up_catalog.show_image() self.catalogs = self.catalog_history[len_cat - 1]['catalogs'] if len(self.catalogs) > 0: self.path_iter = {} self.categories = [] for key in self.catalogs.keys(): self.categories.append({'text': key, 'dentro': []}) self.treemodel.clear() for p in self.categories: self.path_iter[p['text']] = \ self.treemodel.append([p['text']]) self.catalog_listview.handler_unblock(self._catalog_changed_id) def move_down_catalog(self, treeview, path, column): treestore, coldex = \ self.catalog_listview.get_selection().get_selected() len_cat = len(self.catalog_history) if len_cat > 0 and self.catalog_history[len_cat - 1]['catalogs'] == []: self.catalog_history.pop() len_cat = len(self.catalog_history) # README: when the Activity starts by default there is nothing # selected and this signal is called, so we have to avoid this # 'append' because it fails if coldex is not None: self.catalog_history.append({ 'title': treestore.get_value(coldex, 0), 'catalogs': [] }) self.__switch_catalog_cb(treestore.get_value(coldex, 0)) def _sort_logfile(self, treemodel, itera, iterb): a = treemodel.get_value(itera, 0) b = treemodel.get_value(iterb, 0) if a == None or b == None: return 0 a = a.lower() b = b.lower() if a > b: return 1 if a < b: return -1 return 0 def __toggle_cats_cb(self, button): if button.get_active(): self.tree_scroller.show_all() self.separa.show() else: self.tree_scroller.hide() self.separa.hide() def _create_controls(self): self._download_content_length = 0 self._download_content_type = None self.msg_label = Gtk.Label() self.list_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) # Catalogs treeview self.catalog_listview = Gtk.TreeView() self.catalog_listview.headers_clickble = True self.catalog_listview.hover_expand = True self.catalog_listview.rules_hint = True self._catalog_changed_id = self.catalog_listview.connect( 'row-activated', self.move_down_catalog) self.catalog_listview.set_activate_on_single_click(True) self.catalog_listview.set_enable_search(False) self.treemodel = Gtk.ListStore(str) self.treemodel.set_sort_column_id(0, Gtk.SortType.ASCENDING) self.catalog_listview.set_model(self.treemodel) renderer = Gtk.CellRendererText() renderer.set_property('wrap-mode', Pango.WrapMode.WORD) self.treecol = Gtk.TreeViewColumn(_('Catalogs'), renderer, text=0) self.treecol.set_property('clickable', True) self.treecol.connect('clicked', self.move_up_catalog) self.catalog_listview.append_column(self.treecol) self.bt_move_up_catalog = ButtonWithImage(_('Catalogs')) self.bt_move_up_catalog.hide_image() self.treecol.set_widget(self.bt_move_up_catalog) self.load_source_catalogs() self.tree_scroller = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.tree_scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.tree_scroller.add(self.catalog_listview) self.list_box.pack_start(self.tree_scroller, expand=False, fill=False, padding=0) self.separa = Gtk.VSeparator() self.list_box.pack_start(self.separa, expand=False, fill=False, padding=0) # books listview self.listview = ListView(self._lang_code_handler) self.selection_cb_id = self.listview.connect('selection-changed', self.selection_cb) self.listview.set_enable_search(False) self.list_scroller = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.list_scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) vadjustment = self.list_scroller.get_vadjustment() vadjustment.connect('value-changed', self.__vadjustment_value_changed_cb) self.list_scroller.add(self.listview) self.list_box.pack_start(self.list_scroller, expand=True, fill=True, padding=0) self.scrolled = Gtk.ScrolledWindow() self.scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scrolled.props.shadow_type = Gtk.ShadowType.NONE self.textview = Gtk.TextView() self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_wrap_mode(Gtk.WrapMode.WORD) self.textview.set_justification(Gtk.Justification.LEFT) self.textview.set_left_margin(20) self.textview.set_right_margin(20) self.scrolled.add(self.textview) self.list_box.show_all() self.separa.hide() self.tree_scroller.hide() vbox_download = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox_format = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) format_label = Gtk.Label(label=_('Format:')) self.format_combo = ComboBox() for key in _MIMETYPES.keys(): self.format_combo.append_item(_MIMETYPES[key], key) self.format_combo.set_active(0) self.format_combo.props.sensitive = False self.__format_changed_cb_id = \ self.format_combo.connect('changed', self.__format_changed_cb) hbox_format.pack_start(format_label, False, False, 10) hbox_format.pack_start(self.format_combo, False, False, 10) vbox_download.pack_start(hbox_format, False, False, 10) self._download = Gtk.Button(_('Get Book')) self._download.set_image(Icon(icon_name='data-download')) self._download.props.sensitive = False self._download.connect('clicked', self.__get_book_cb) vbox_download.pack_start(self._download, False, False, 10) self.progressbox = Gtk.Box(spacing=20, orientation=Gtk.Orientation.HORIZONTAL) self.progressbar = Gtk.ProgressBar() self.progressbar.set_fraction(0.0) self.progressbox.pack_start(self.progressbar, expand=True, fill=True, padding=0) self.cancel_btn = Gtk.Button(stock=Gtk.STOCK_CANCEL) self.cancel_btn.set_image(Icon(icon_name='dialog-cancel')) self.cancel_btn.connect('clicked', self.__cancel_btn_clicked_cb) self.progressbox.pack_start(self.cancel_btn, expand=False, fill=False, padding=0) vbox_download.pack_start(self.progressbox, False, False, 10) bottom_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) if self.show_images: self.__image_downloader = None self.image = Gtk.Image() self.add_default_image() bottom_hbox.pack_start(self.image, False, False, 10) bottom_hbox.pack_start(self.scrolled, True, True, 10) bottom_hbox.pack_start(vbox_download, False, False, 10) bottom_hbox.show_all() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.pack_start(self.msg_label, False, False, 10) vbox.pack_start(self.list_box, True, True, 0) vbox.pack_start(bottom_hbox, False, False, 10) self.set_canvas(vbox) self.listview.show() vbox.show() self.list_scroller.show() self.progress_hide() self.show_message( _('Enter words from the Author or Title to begin search.')) self._books_toolbar.search_entry.grab_focus() if len(self.catalogs) > 0: self.bt_catalogs.set_active(True) def progress_hide(self): self.clear_downloaded_bytes() self.progressbar.set_sensitive(False) self.cancel_btn.set_sensitive(False) def progress_show(self): self.progressbar.set_sensitive(True) self.cancel_btn.set_sensitive(True) def filter_catalogs_by_source(self): self.catalogs = {} for catalog_key in self.catalogs_configuration: catalog = self.catalogs_configuration[catalog_key] if catalog['source'] == self.source: self.catalogs[catalog_key] = catalog def load_source_catalogs(self): self.filter_catalogs_by_source() if len(self.catalogs) > 0: self.categories = [] self.path_iter = {} self.catalog_history = [] self.catalog_history.append({ 'title': _('Catalogs'), 'catalogs': self.catalogs }) for key in self.catalogs.keys(): self.categories.append({'text': key, 'dentro': []}) self.treemodel.clear() for p in self.categories: self.path_iter[p['text']] = self.treemodel.append([p['text']]) def can_close(self): if self.queryresults is not None: self.queryresults.cancel() self.queryresults = None return True def selection_cb(self, widget): selected_book = self.listview.get_selected_book() if self.source == 'local_books': if selected_book: self.selected_book = selected_book self._download.hide() self.show_book_data() self._object_id = selected_book.get_object_id() self._show_journal_alert(_('Selected book'), self.selected_title) else: self.clear_downloaded_bytes() if selected_book: self.update_format_combo(selected_book.get_types()) self.selected_book = selected_book self._download.show() self.show_book_data() def show_message(self, text): self.msg_label.set_text(text) self.msg_label.show() def hide_message(self): self.msg_label.hide() def show_book_data(self, load_image=True): self.selected_title = self.selected_book.get_title() book_data = _('Title:\t\t') + self.selected_title + '\n' self.selected_author = self.selected_book.get_author() book_data += _('Author:\t\t') + self.selected_author + '\n' self.selected_publisher = self.selected_book.get_publisher() self.selected_summary = self.selected_book.get_summary() if (self.selected_summary is not 'Unknown'): book_data += _('Summary:\t') + self.selected_summary + '\n' self.selected_language_code = self.selected_book.get_language() if self.selected_language_code != '': try: self.selected_language = \ self._lang_code_handler.get_full_language_name( self.selected_book.get_language()) except: self.selected_language = self.selected_book.get_language() book_data += _('Language:\t') + self.selected_language + '\n' book_data += _('Publisher:\t') + self.selected_publisher + '\n' textbuffer = self.textview.get_buffer() textbuffer.set_text('\n' + book_data) self.enable_button(True) # Cover Image self.exist_cover_image = False if self.show_images and load_image: if self.source == 'local_books': cover_image_buffer = self.get_journal_entry_cover_image( self.selected_book.get_object_id()) if (cover_image_buffer): self.add_image_buffer( self.get_pixbuf_from_buffer(cover_image_buffer)) else: self.add_default_image() else: url_image = self.selected_book.get_image_url() self.add_default_image() if url_image: self.download_image(url_image.values()[0]) def get_pixbuf_from_buffer(self, image_buffer): """Buffer To Pixbuf""" pixbuf_loader = GdkPixbuf.PixbufLoader() pixbuf_loader.write(image_buffer) pixbuf_loader.close() pixbuf = pixbuf_loader.get_pixbuf() return pixbuf def get_journal_entry_cover_image(self, object_id): ds_object = datastore.get(object_id) if 'cover_image' in ds_object.metadata: cover_data = ds_object.metadata['cover_image'] return base64.b64decode(cover_data) elif 'preview' in ds_object.metadata: return ds_object.metadata['preview'] else: return "" def download_image(self, url): self._inhibit_suspend() self.progress_show() if self.__image_downloader is not None: self.__image_downloader.stop() self.__image_downloader = opds.FileDownloader(url, self.get_path()) self.__image_downloader.connect('updated', self.__image_updated_cb) self.__image_downloader.connect('progress', self.__image_progress_cb) def __image_updated_cb(self, downloader, path, content_type): if path is not None: self.add_image(path) self.exist_cover_image = True os.remove(path) else: self.add_default_image() self.__image_downloader = None GObject.timeout_add(500, self.progress_hide) self._allow_suspend() def __image_progress_cb(self, downloader, progress): self.progressbar.set_fraction(progress) while Gtk.events_pending(): Gtk.main_iteration() def add_default_image(self): file_path = os.path.join(activity.get_bundle_path(), 'generic_cover.png') self.add_image(file_path) def add_image(self, file_path): pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_path) self.add_image_buffer(pixbuf) def add_image_buffer(self, pixbuf): image_height = int(Gdk.Screen.height() / 4) image_width = image_height / 3 * 2 width, height = pixbuf.get_width(), pixbuf.get_height() scale = 1 if (width > image_width) or (height > image_height): scale_x = image_width / float(width) scale_y = image_height / float(height) scale = min(scale_x, scale_y) pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), image_width, image_height) pixbuf2.fill(style.COLOR_PANEL_GREY.get_int()) margin_x = int((image_width - (width * scale)) / 2) margin_y = int((image_height - (height * scale)) / 2) pixbuf.scale(pixbuf2, margin_x, margin_y, image_width - (margin_x * 2), image_height - (margin_y * 2), margin_x, margin_y, scale, scale, GdkPixbuf.InterpType.BILINEAR) self.image.set_from_pixbuf(pixbuf2) def get_query_language(self): query_language = None if len(self.languages) > 0: query_language = self._books_toolbar.language_combo.props.value return query_language def find_books(self, search_text=''): self._inhibit_suspend() self.source = self._books_toolbar.source_combo.props.value query_language = self.get_query_language() self.enable_button(False) self.clear_downloaded_bytes() self.book_selected = False self.listview.handler_block(self.selection_cb_id) self.listview.clear() self.listview.handler_unblock(self.selection_cb_id) if self.queryresults is not None: self.queryresults.cancel() self.queryresults = None if self.source == 'local_books': self.listview.populate_with_books( self.get_entrys_info(search_text)) else: if search_text is None: return elif len(search_text) < 3: self.show_message(_('You must enter at least 3 letters.')) self._books_toolbar.search_entry.grab_focus() return if self.source == 'Internet Archive': self.queryresults = \ opds.InternetArchiveQueryResult(search_text, self.get_path()) elif self.source in _SOURCES_CONFIG: repo_configuration = _SOURCES_CONFIG[self.source] self.queryresults = opds.RemoteQueryResult( repo_configuration, search_text, query_language) else: self.queryresults = opds.LocalVolumeQueryResult( self.source, search_text, query_language) self.show_message(_('Performing lookup, please wait...')) self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH)) self.queryresults.connect('updated', self.__query_updated_cb) def __query_updated_cb(self, query, midway): self.listview.populate(self.queryresults) if hasattr(self.queryresults, '_feedobj') and \ 'bozo_exception' in self.queryresults._feedobj: # something went wrong and we have to inform about this bozo_exception = self.queryresults._feedobj.bozo_exception if isinstance(bozo_exception, urllib2.URLError): if isinstance(bozo_exception.reason, socket.gaierror): if bozo_exception.reason.errno == -2: self.show_message( _('Could not reach the server. ' 'Maybe you are not connected to the network')) self.window.set_cursor(None) return self.show_message(_('There was an error downloading the list.')) elif (len(self.queryresults.get_catalog_list()) > 0): self.show_message(_('New catalog list %s was found') \ % self.queryresults._configuration["name"]) self.catalogs_updated(query, midway) elif len(self.queryresults) == 0: self.show_message(_('Sorry, no books could be found.')) if not midway and len(self.queryresults) > 0: self.hide_message() query_language = self.get_query_language() if query_language != 'all' and query_language != 'en': # the bookserver send english books if there are not books in # the requested language only_english = True for book in self.queryresults.get_book_list(): if book.get_language() == query_language: only_english = False break if only_english: self.show_message(_('Sorry, we only found english books.')) self.get_window().set_cursor(None) self._allow_suspend() def catalogs_updated(self, query, midway): self.catalogs = {} for catalog_item in self.queryresults.get_catalog_list(): logging.debug('Add catalog %s', catalog_item.get_title()) catalog_config = {} download_link = '' download_links = catalog_item.get_types() for link in download_links.keys(): download_link = download_links[link] break catalog_config['query_uri'] = download_link catalog_config['opds_cover'] = \ catalog_item._configuration['opds_cover'] catalog_config['source'] = catalog_item._configuration['source'] source_config = _SOURCES_CONFIG[catalog_config['source']] catalog_config['name'] = catalog_item.get_title() catalog_config['summary_field'] = \ catalog_item._configuration['summary_field'] if catalog_item.get_title() in source_config['blacklist']: logging.debug('Catalog "%s" is in blacklist', catalog_item.get_title()) else: self.catalogs[catalog_item.get_title().strip()] = \ catalog_config if len(self.catalogs) > 0: len_cat = len(self.catalog_history) self.catalog_history[len_cat - 1]['catalogs'] = self.catalogs self.path_iter = {} self.categories = [] for key in self.catalogs.keys(): self.categories.append({'text': key, 'dentro': []}) self.treemodel.clear() for p in self.categories: self.path_iter[p['text']] = \ self.treemodel.append([p['text']]) title = self.catalog_history[len_cat - 1]['title'] self.bt_move_up_catalog.set_label(title) self.bt_move_up_catalog.show_image() else: self.catalog_history.pop() def __source_changed_cb(self, widget): search_terms = self.get_search_terms() if search_terms == '': self.find_books(None) else: self.find_books(search_terms) # enable/disable catalogs button if configuration is available self.source = self._books_toolbar.source_combo.props.value # Get catalogs for this source self.load_source_catalogs() if len(self.catalogs) > 0: self.bt_catalogs.show() self.bt_catalogs.set_active(True) else: self.bt_catalogs.set_active(False) self.bt_catalogs.hide() def __vadjustment_value_changed_cb(self, vadjustment): if not self.queryresults.is_ready(): return try: # Use various tricks to update resultset as user scrolls down if ((vadjustment.props.upper - vadjustment.props.lower) > 1000 \ and (vadjustment.props.upper - vadjustment.props.value - \ vadjustment.props.page_size) / (vadjustment.props.upper - \ vadjustment.props.lower) < 0.3) or ((vadjustment.props.upper \ - vadjustment.props.value - vadjustment.props.page_size) < 200): if self.queryresults.has_next(): self.queryresults.update_with_next() finally: return def __cancel_btn_clicked_cb(self, btn): if self.__image_downloader is not None: self.__image_downloader.stop() if self.__book_downloader is not None: self.__book_downloader.stop() self.progress_hide() self.enable_button(True) self.listview.props.sensitive = True self._books_toolbar.search_entry.set_sensitive(True) self._allow_suspend() def get_book(self): self.enable_button(False) self.clear_downloaded_bytes() self.progress_show() if self.source != 'local_books': self.selected_book.get_download_links( self.format_combo.props.value, self.download_book, self.get_path()) def download_book(self, url): logging.error('DOWNLOAD BOOK %s', url) self._inhibit_suspend() self.listview.props.sensitive = False self._books_toolbar.search_entry.set_sensitive(False) self.__book_downloader = opds.FileDownloader(url, self.get_path()) self.__book_downloader.connect('updated', self.__book_updated_cb) self.__book_downloader.connect('progress', self.__book_progress_cb) def __book_updated_cb(self, downloader, path, content_type): self._books_toolbar.search_entry.set_sensitive(True) self.listview.props.sensitive = True self._allow_suspend() GObject.timeout_add(500, self.progress_hide) self.enable_button(True) self.__book_downloader = None if path is None: self._show_error_alert( _('Error: Could not download %s. ' + 'The path in the catalog seems to be incorrect.') % self.selected_title) return if os.stat(path).st_size == 0: self._show_error_alert( _('Error: Could not download %s. ' + 'The other end sent an empty file.') % self.selected_title) return if content_type.startswith('text/html'): self._show_error_alert( _('Error: Could not download %s. ' + 'The other end sent text/html instead of a book.') % self.selected_title) return self.process_downloaded_book(path) def __book_progress_cb(self, downloader, progress): self.progressbar.set_fraction(progress) while Gtk.events_pending(): Gtk.main_iteration() def clear_downloaded_bytes(self): self.progressbar.set_fraction(0.0) def process_downloaded_book(self, path): logging.debug("Got document %s", path) self.create_journal_entry(path) self._getter = None self._allow_suspend() def create_journal_entry(self, path): journal_entry = datastore.create() journal_title = self.selected_title if self.selected_author != '': journal_title = journal_title + ', by ' + self.selected_author journal_entry.metadata['title'] = journal_title journal_entry.metadata['title_set_by_user'] = '******' journal_entry.metadata['keep'] = '0' journal_entry.metadata['mime_type'] = \ self.format_combo.props.value # Fix fake mime type for black&white pdfs if journal_entry.metadata['mime_type'] == _MIMETYPES['PDF BW']: journal_entry.metadata['mime_type'] = _MIMETYPES['PDF'] journal_entry.metadata['buddies'] = '' journal_entry.metadata['icon-color'] = profile.get_color().to_string() textbuffer = self.textview.get_buffer() journal_entry.metadata['description'] = \ textbuffer.get_text(textbuffer.get_start_iter(), textbuffer.get_end_iter(), True) if self.exist_cover_image: image_buffer = self._get_preview_image_buffer() journal_entry.metadata['preview'] = dbus.ByteArray(image_buffer) image_buffer = self._get_cover_image_buffer() journal_entry.metadata['cover_image'] = \ dbus.ByteArray(base64.b64encode(image_buffer)) else: journal_entry.metadata['cover_image'] = "" journal_entry.metadata['tags'] = self.source journal_entry.metadata['source'] = self.source journal_entry.metadata['author'] = self.selected_author journal_entry.metadata['publisher'] = self.selected_publisher journal_entry.metadata['summary'] = self.selected_summary journal_entry.metadata['language'] = self.selected_language_code journal_entry.file_path = path datastore.write(journal_entry) os.remove(path) self.progress_hide() self._object_id = journal_entry.object_id self._show_journal_alert(_('Download completed'), self.selected_title) def _show_journal_alert(self, title, msg): _stop_alert = Alert() _stop_alert.props.title = title _stop_alert.props.msg = msg if _HAS_BUNDLE_LAUNCHER: bundle = get_bundle(object_id=self._object_id) if bundle is not None: icon = Icon(file=bundle.get_icon()) label = _('Open with %s') % bundle.get_name() _stop_alert.add_button(Gtk.ResponseType.ACCEPT, label, icon) else: icon = Icon(icon_name='zoom-activity') label = _('Show in Journal') _stop_alert.add_button(Gtk.ResponseType.APPLY, label, icon) icon.show() ok_icon = Icon(icon_name='dialog-ok') _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon) ok_icon.show() # Remove other alerts for alert in self._alerts: self.remove_alert(alert) self.add_alert(_stop_alert) _stop_alert.connect('response', self.__stop_response_cb) _stop_alert.show() def __stop_response_cb(self, alert, response_id): if response_id is Gtk.ResponseType.APPLY: activity.show_object_in_journal(self._object_id) elif response_id is Gtk.ResponseType.ACCEPT: launch_bundle(object_id=self._object_id) self.remove_alert(alert) def _get_preview_image_buffer(self): preview_width, preview_height = style.zoom(300), style.zoom(225) pixbuf = self.image.get_pixbuf() width, height = pixbuf.get_width(), pixbuf.get_height() scale = 1 if (width > preview_width) or (height > preview_height): scale_x = preview_width / float(width) scale_y = preview_height / float(height) scale = min(scale_x, scale_y) pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), preview_width, preview_height) pixbuf2.fill(style.COLOR_WHITE.get_int()) margin_x = int((preview_width - (width * scale)) / 2) margin_y = int((preview_height - (height * scale)) / 2) pixbuf.scale(pixbuf2, margin_x, margin_y, preview_width - (margin_x * 2), preview_height - (margin_y * 2), margin_x, margin_y, scale, scale, GdkPixbuf.InterpType.BILINEAR) succes, data = pixbuf2.save_to_bufferv('png', [], []) return data def _get_cover_image_buffer(self): pixbuf = self.image.get_pixbuf() succes, data = pixbuf.save_to_bufferv('png', [], []) return data def _show_error_alert(self, title, text=None): alert = NotifyAlert(timeout=20) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) self.textview.grab_focus() def get_entrys_info(self, query): books = [] for key in _MIMETYPES.keys(): books.extend(self.get_entry_info_format(query, _MIMETYPES[key])) return books def get_entry_info_format(self, query, mime): books = [] if query is not None and len(query) > 0: ds_objects, num_objects = datastore.find({ 'mime_type': '%s' % mime, 'query': '*%s*' % query }) else: ds_objects, num_objects = datastore.find( {'mime_type': '%s' % mime}) logging.error('Local search %d books found %s format', num_objects, mime) for i in range(0, num_objects): entry = {} entry['title'] = ds_objects[i].metadata['title'] entry['mime'] = ds_objects[i].metadata['mime_type'] entry['object_id'] = ds_objects[i].object_id if 'author' in ds_objects[i].metadata: entry['author'] = ds_objects[i].metadata['author'] else: entry['author'] = '' if 'publisher' in ds_objects[i].metadata: entry['dcterms_publisher'] = \ ds_objects[i].metadata['publisher'] else: entry['dcterms_publisher'] = '' if 'language' in ds_objects[i].metadata: entry['dcterms_language'] = \ ds_objects[i].metadata['language'] else: entry['dcterms_language'] = '' if 'source' in ds_objects[i].metadata: entry['source'] = \ ds_objects[i].metadata['source'] else: entry['source'] = '' if entry['source'] in _SOURCES_CONFIG: repo_configuration = _SOURCES_CONFIG[entry['source']] summary_field = repo_configuration['summary_field'] if 'summary' in ds_objects[i].metadata: entry[summary_field] = ds_objects[i].metadata['summary'] else: entry[summary_field] = '' else: repo_configuration = None books.append(opds.Book(repo_configuration, entry, '')) return books def close(self, skip_save=False): "Override the close method so we don't try to create a Journal entry." activity.Activity.close(self, True) def save(self): pass
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): Gtk.Toolbar.__init__(self) self._activity = activity if not speech.supported: return self.is_paused = False self._cnf_client = GConf.Client.get_default() self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_btn.connect('toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) # Stop button self.stop_btn = ToolButton('media-playback-stop') self.stop_btn.show() self.stop_btn.connect('clicked', self.stop_cb) self.stop_btn.set_sensitive(False) self.insert(self.stop_btn, -1) self.stop_btn.set_tooltip(_('Stop')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() speech.reset_buttons_cb = self.reset_buttons_cb def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0] .lower() < b[0].lower(): return -1 if a[0] .lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = json.load(f) speech.voice = speech_parameters['voice'] finally: f.close() self._cnf_client.add_dir('/desktop/sugar/speech', GConf.ClientPreloadType.PRELOAD_NONE) speech.pitch = self._cnf_client.get_int('/desktop/sugar/speech/pitch') speech.rate = self._cnf_client.get_int('/desktop/sugar/speech/rate') self._cnf_client.notify_add('/desktop/sugar/speech/pitch', self.__conf_changed_cb, None) self._cnf_client.notify_add('/desktop/sugar/speech/rate', self.__conf_changed_cb, None) def __conf_changed_cb(self, client, connection_id, entry, args): key = entry.get_key() value = client.get_int(key) if key == '/desktop/sugar/speech/pitch': speech.pitch = value if key == '/desktop/sugar/speech/rate': speech.rate = value def save_speech_parameters(self): speech_parameters = {} speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: json.dump(speech_parameters, f) finally: f.close() def reset_buttons_cb(self): self.play_btn.set_icon_name('media-playback-start') self.stop_btn.set_sensitive(False) self.is_paused = False def play_cb(self, widget): self.stop_btn.set_sensitive(True) if widget.get_active(): self.play_btn.set_icon_name('media-playback-pause') if not self.is_paused: speech.play(self._activity._view.get_marked_words()) else: speech.continue_play() else: self.play_btn.set_icon_name('media-playback-start') self.is_paused = True speech.pause() def stop_cb(self, widget): self.stop_btn.set_sensitive(False) self.play_btn.set_icon_name('media-playback-start') self.play_btn.set_active(False) self.is_paused = False speech.stop()
from gi.repository import Gtk from sugar3.graphics.combobox import ComboBox def _destroy_cb(widget, data=None): Gtk.main_quit() def __combo_changed_cb(widget, data=None): print 'combo-changed' w = Gtk.Window() w.connect("destroy", _destroy_cb) box = Gtk.VBox() w.add(box) combo = ComboBox() combo.append_item(0, 'one') combo.append_item(1, 'two', 'go-next') combo.append_item(2, 'three') combo.set_active(1) combo.connect('changed', __combo_changed_cb) box.pack_start(combo, False, False, 0) w.show_all() Gtk.main()
class MainToolbox(ToolbarBox): __gsignals__ = { 'query-changed': (GObject.SignalFlags.RUN_FIRST, None, ([object])), } def __init__(self): ToolbarBox.__init__(self) self._mount_point = None self._filter_type = None self._what_filter = None self.search_entry = iconentry.IconEntry() self.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'entry-search') text = _('Search in %s') % _('Journal') self.search_entry.set_placeholder_text(text) self.search_entry.connect('activate', self._search_entry_activated_cb) self.search_entry.connect('changed', self._search_entry_changed_cb) self.search_entry.add_clear_button() self._autosearch_timer = None self._add_widget(self.search_entry, expand=True) self._favorite_button = ToggleToolButton('emblem-favorite') self._favorite_button.set_tooltip(_('Favorite entries')) self._favorite_button.connect('toggled', self.__favorite_button_toggled_cb) self.toolbar.insert(self._favorite_button, -1) self._favorite_button.show() self._what_search_combo = ComboBox() self._what_combo_changed_sid = self._what_search_combo.connect( 'changed', self._combo_changed_cb) tool_item = ToolComboBox(self._what_search_combo) self.toolbar.insert(tool_item, -1) tool_item.show() self._when_search_combo = self._get_when_search_combo() tool_item = ToolComboBox(self._when_search_combo) self.toolbar.insert(tool_item, -1) tool_item.show() self._sorting_button = SortingButton() self.toolbar.insert(self._sorting_button, -1) self._sorting_button.connect('sort-property-changed', self.__sort_changed_cb) self._sorting_button.show() # TODO: enable it when the DS supports saving the buddies. # self._with_search_combo = self._get_with_search_combo() # tool_item = ToolComboBox(self._with_search_combo) # self.insert(tool_item, -1) # tool_item.show() self._query = self._build_query() self.refresh_filters() def _get_when_search_combo(self): when_search = ComboBox() when_search.append_item(_ACTION_ANYTIME, _('Anytime')) when_search.append_separator() when_search.append_item(_ACTION_TODAY, _('Today')) when_search.append_item(_ACTION_SINCE_YESTERDAY, _('Since yesterday')) # TRANS: Filter entries modified during the last 7 days. when_search.append_item(_ACTION_PAST_WEEK, _('Past week')) # TRANS: Filter entries modified during the last 30 days. when_search.append_item(_ACTION_PAST_MONTH, _('Past month')) # TRANS: Filter entries modified during the last 356 days. when_search.append_item(_ACTION_PAST_YEAR, _('Past year')) when_search.set_active(0) when_search.connect('changed', self._combo_changed_cb) return when_search def _get_with_search_combo(self): with_search = ComboBox() with_search.append_item(_ACTION_EVERYBODY, _('Anyone')) with_search.append_separator() with_search.append_item(_ACTION_MY_FRIENDS, _('My friends')) with_search.append_item(_ACTION_MY_CLASS, _('My class')) with_search.append_separator() # TODO: Ask the model for buddies. with_search.append_item(3, 'Dan', 'theme:xo') with_search.set_active(0) with_search.connect('changed', self._combo_changed_cb) return with_search def _add_widget(self, widget, expand=False): tool_item = Gtk.ToolItem() tool_item.set_expand(expand) tool_item.add(widget) widget.show() self.toolbar.insert(tool_item, -1) tool_item.show() def _build_query(self): query = {} if self._mount_point: query['mountpoints'] = [self._mount_point] if self._favorite_button.props.active: query['keep'] = 1 if self._what_search_combo.props.value: value = self._what_search_combo.props.value filter_type = self._filter_type if self._filter_type is None: # for backward compatibility, try to guess the filter generic_type = mime.get_generic_type(value) if generic_type: filter_type = FILTER_TYPE_GENERIC_MIME else: filter_type = FILTER_TYPE_ACTIVITY logging.error('DEPRECATED: sety the filter_type parameter') if filter_type == FILTER_TYPE_GENERIC_MIME: generic_type = mime.get_generic_type(value) if generic_type: mime_types = generic_type.mime_types query['mime_type'] = mime_types else: logging.error('filter_type="generic_mime", ' 'but "%s" is not a generic mime' % value) elif filter_type == FILTER_TYPE_ACTIVITY: query['activity'] = value elif self._filter_type == FILTER_TYPE_MIME_BY_ACTIVITY: registry = bundleregistry.get_registry() bundle = \ registry.get_bundle(value) if bundle is not None: query['mime_type'] = bundle.get_mime_types() else: logging.error('Trying to filter using activity mimetype ' 'but bundle id is wrong %s' % value) if self._when_search_combo.props.value: date_from, date_to = self._get_date_range() query['timestamp'] = {'start': date_from, 'end': date_to} if self.search_entry.props.text: text = self.search_entry.props.text.strip() if text: query['query'] = text property_, order = self._sorting_button.get_current_sort() if order == Gtk.SortType.ASCENDING: sign = '+' else: sign = '-' query['order_by'] = [sign + property_] return query def _get_date_range(self): today_start = datetime.today().replace(hour=0, minute=0, second=0) right_now = datetime.today() if self._when_search_combo.props.value == _ACTION_TODAY: date_range = (today_start, right_now) elif self._when_search_combo.props.value == _ACTION_SINCE_YESTERDAY: date_range = (today_start - timedelta(1), right_now) elif self._when_search_combo.props.value == _ACTION_PAST_WEEK: date_range = (today_start - timedelta(7), right_now) elif self._when_search_combo.props.value == _ACTION_PAST_MONTH: date_range = (today_start - timedelta(30), right_now) elif self._when_search_combo.props.value == _ACTION_PAST_YEAR: date_range = (today_start - timedelta(356), right_now) return (time.mktime(date_range[0].timetuple()), time.mktime(date_range[1].timetuple())) def _combo_changed_cb(self, combo): self._update_if_needed() def __sort_changed_cb(self, button): self._update_if_needed() def _update_if_needed(self): # check if the what_search combo should be visible self._what_search_combo.set_visible( self._filter_type != FILTER_TYPE_MIME_BY_ACTIVITY) new_query = self._build_query() if self._query != new_query: self._query = new_query self.emit('query-changed', self._query) def _search_entry_activated_cb(self, search_entry): if self._autosearch_timer: GObject.source_remove(self._autosearch_timer) self._update_if_needed() def _search_entry_changed_cb(self, search_entry): if not search_entry.props.text: search_entry.activate() return if self._autosearch_timer: GObject.source_remove(self._autosearch_timer) self._autosearch_timer = GObject.timeout_add(_AUTOSEARCH_TIMEOUT, self._autosearch_timer_cb) def _autosearch_timer_cb(self): logging.debug('_autosearch_timer_cb') self._autosearch_timer = None self.search_entry.activate() return False def set_mount_point(self, mount_point): self._mount_point = mount_point self._update_if_needed() def set_what_filter(self, what_filter): combo_model = self._what_search_combo.get_model() what_filter_index = -1 for i in range(0, len(combo_model) - 1): if combo_model[i][0] == what_filter: what_filter_index = i break if what_filter_index == -1: logging.warning('what_filter %r not known', what_filter) else: self._what_search_combo.set_active(what_filter_index) def update_filters(self, mount_point, what_filter, filter_type=None): self._mount_point = mount_point self._filter_type = filter_type self._what_filter = what_filter self.set_what_filter(what_filter) self._update_if_needed() def set_filter_type(self, filter_type): self._filter_type = filter_type self._update_if_needed() def refresh_filters(self): current_value = self._what_search_combo.props.value current_value_index = 0 self._what_search_combo.handler_block(self._what_combo_changed_sid) try: self._what_search_combo.remove_all() # TRANS: Item in a combo box that filters by entry type. self._what_search_combo.append_item(_ACTION_ANYTHING, _('Anything')) registry = bundleregistry.get_registry() appended_separator = False types = mime.get_all_generic_types() for generic_type in types: if not appended_separator: self._what_search_combo.append_separator() appended_separator = True self._what_search_combo.append_item( generic_type.type_id, generic_type.name, generic_type.icon) if generic_type.type_id == current_value: current_value_index = \ len(self._what_search_combo.get_model()) - 1 self._what_search_combo.set_active(current_value_index) self._what_search_combo.append_separator() for service_name in model.get_unique_values('activity'): activity_info = registry.get_bundle(service_name) if activity_info is None: continue if service_name == current_value: combo_model = self._what_search_combo.get_model() current_value_index = len(combo_model) # try activity-provided icon if os.path.exists(activity_info.get_icon()): try: self._what_search_combo.append_item( service_name, activity_info.get_name(), file_name=activity_info.get_icon()) except GObject.GError, exception: logging.warning('Falling back to default icon for' ' "what" filter because %r (%r) has an' ' invalid icon: %s', activity_info.get_name(), str(service_name), exception) else: continue # fall back to generic icon self._what_search_combo.append_item( service_name, activity_info.get_name(), icon_name='application-octet-stream') finally: self._what_search_combo.handler_unblock( self._what_combo_changed_sid) def __favorite_button_toggled_cb(self, favorite_button): self._update_if_needed() def clear_query(self): self.search_entry.props.text = '' if self._what_filter is None: self._what_search_combo.set_active(0) else: self.set_what_filter(self._what_filter) self._when_search_combo.set_active(0) self._favorite_button.props.active = False
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): Gtk.Toolbar.__init__(self) self._activity = activity if not speech.supported: return self._cnf_client = GConf.Client.get_default() self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_btn.connect('toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) # Stop button self.stop_btn = ToolButton('media-playback-stop') self.stop_btn.show() self.stop_btn.connect('clicked', self.stop_cb) self.stop_btn.set_sensitive(False) self.insert(self.stop_btn, -1) self.stop_btn.set_tooltip(_('Stop')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() speech.reset_buttons_cb = self.reset_buttons_cb def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0] .lower() < b[0].lower(): return -1 if a[0] .lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = simplejson.load(f) speech.voice = speech_parameters['voice'] finally: f.close() self._cnf_client.add_dir('/desktop/sugar/speech', GConf.ClientPreloadType.PRELOAD_NONE) speech.pitch = self._cnf_client.get_int('/desktop/sugar/speech/pitch') speech.rate = self._cnf_client.get_int('/desktop/sugar/speech/rate') self._cnf_client.notify_add('/desktop/sugar/speech/pitch', \ self.__conf_changed_cb, None) self._cnf_client.notify_add('/desktop/sugar/speech/rate', \ self.__conf_changed_cb, None) def __conf_changed_cb(self, client, connection_id, entry, args): key = entry.get_key() value = client.get_int(key) if key == '/desktop/sugar/speech/pitch': speech.pitch = value if key == '/desktop/sugar/speech/rate': speech.rate = value def save_speech_parameters(self): speech_parameters = {} speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: simplejson.dump(speech_parameters, f) finally: f.close() def reset_buttons_cb(self): logging.error('reset buttons') self.play_btn.set_named_icon('media-playback-start') self.stop_btn.set_sensitive(False) def play_cb(self, widget): self.stop_btn.set_sensitive(True) if widget.get_active(): self.play_btn.set_named_icon('media-playback-pause') if speech.is_stopped(): speech.play(self._activity._view.get_marked_words()) else: self.play_btn.set_named_icon('media-playback-start') speech.pause() def stop_cb(self, widget): self.stop_btn.set_sensitive(False) self.play_btn.set_named_icon('media-playback-start') self.play_btn.set_active(False) speech.stop()
def __init__(self): Gtk.Toolbar.__init__(self) self.activity = None self._speech = SpeechManager() self._voices = self._speech.get_all_voices() # a dictionary locale = os.environ.get('LANG', '') language_location = locale.split('.', 1)[0].lower() language = language_location.split('_')[0] # if the language is es but not es_es default to es_la (latin voice) if language == 'es' and language_location != 'es_es': language_location = 'es_la' self._voice = 'en_us' if language_location in self._voices: self._voice = language_location elif language in self._voices: self._voice = language voice_names = [] for language, name in self._voices.items(): voice_names.append((language, name)) voice_names.sort() # Play button Image play_img = Gtk.Image() play_img.show() play_img.set_from_icon_name('media-playback-start', Gtk.IconSize.LARGE_TOOLBAR) # Pause button Image pause_img = Gtk.Image() pause_img.show() pause_img.set_from_icon_name('media-playback-pause', Gtk.IconSize.LARGE_TOOLBAR) # Play button self.play_button = ToggleToolButton('media-playback-start') self.play_button.show() self.play_button.connect('toggled', self._play_toggled_cb, [play_img, pause_img]) self.insert(self.play_button, -1) self.play_button.set_tooltip(_('Play / Pause')) combo = ComboBox() which = 0 for pair in voice_names: language, name = pair combo.append_item(language, name) if language == self._voice: combo.set_active(which) which += 1 combo.connect('changed', self._voice_changed_cb) combotool = ToolComboBox(combo) self.insert(combotool, -1) combotool.show() self.pitchadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) pitchbar = Gtk.HScale() pitchbar.set_adjustment(self.pitchadj) pitchbar.set_draw_value(False) # pitchbar.set_update_policy(Gtk.UpdatePolicy.ALWAYS) pitchbar.set_size_request(150, 15) pitchtool = Gtk.ToolItem() pitchtool.add(pitchbar) pitchtool.show() self.insert(pitchtool, -1) pitchbar.show() self.rateadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) ratebar = Gtk.HScale() ratebar.set_adjustment(self.rateadj) ratebar.set_draw_value(False) # ratebar.set_update_policy(Gtk.UpdatePolicy.ALWAYS) ratebar.set_size_request(150, 15) ratetool = Gtk.ToolItem() ratetool.add(ratebar) ratetool.show() self.insert(ratetool, -1) ratebar.show()
class GetIABooksActivity(activity.Activity): def __init__(self, handle, create_jobject=True): "The entry point to the Activity" activity.Activity.__init__(self, handle, False) if _NEW_TOOLBAR_SUPPORT: self.create_new_toolbar() else: self.create_old_toolbar() self.scrolled = Gtk.ScrolledWindow() self.scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.textview = Gtk.TextView() self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_justification(Gtk.Justification.LEFT) self.textview.set_wrap_mode(Gtk.WrapMode.WORD) self.textview.set_left_margin(50) self.textview.set_right_margin(50) textbuffer = self.textview.get_buffer() textbuffer.set_text(_('Enter words from the Author or Title to begin search') + '.') self.scrolled.add(self.textview) self.textview.show() self.scrolled.show() self._download_content_length = 0 self._download_content_type = None self.ls = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) self.treeview = Gtk.TreeView(self.ls) self.treeview.set_rules_hint(True) self.treeview.set_search_column(COLUMN_TITLE) selection = self.treeview.get_selection() selection.set_mode(Gtk.SelectionMode.SINGLE) selection.connect("changed", self.selection_cb) renderer = Gtk.CellRendererText() renderer.set_property('wrap-mode', Gtk.WrapMode.WORD) renderer.set_property('wrap-width', 500) renderer.set_property('width', 500) col = Gtk.TreeViewColumn(_('Title'), renderer, text=COLUMN_TITLE) col.set_sort_column_id(COLUMN_TITLE) self.treeview.append_column(col) renderer = Gtk.CellRendererText() col = Gtk.TreeViewColumn(_('Volume'), renderer, text=COLUMN_VOLUME) col.set_sort_column_id(COLUMN_VOLUME) self.treeview.append_column(col) renderer = Gtk.CellRendererText() renderer.set_property('wrap-mode', Gtk.WrapMode.WORD) renderer.set_property('wrap-width', 200) renderer.set_property('width', 200) col = Gtk.TreeViewColumn(_('Author'), renderer, text=COLUMN_CREATOR) col.set_sort_column_id(COLUMN_CREATOR) self.treeview.append_column(col) renderer = Gtk.CellRendererText() col = Gtk.TreeViewColumn(_('Language'), renderer, text=COLUMN_LANGUAGE) col.set_sort_column_id(COLUMN_LANGUAGE) self.treeview.append_column(col) self.list_scroller = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.list_scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.list_scroller.add(self.treeview) self.progressbar = Gtk.ProgressBar() self.progressbar.set_orientation(Gtk.Orientation.HORIZONTAL) self.progressbar.set_fraction(0.0) vbox = Gtk.VBox() vbox.pack_start(self.progressbar, False, False, 10) vbox.add(self.scrolled) vbox.pack_end(self.list_scroller, True, True, 0) self.set_canvas(vbox) self.treeview.show() vbox.show() self.list_scroller.show() self.progressbar.hide() def close(self, skip_save=False): "Override the close method so we don't try to create a Journal entry." activity.Activity.close(self, True) def create_old_toolbar(self): toolbox = activity.ActivityToolbox(self) activity_toolbar = toolbox.get_activity_toolbar() activity_toolbar.keep.props.visible = False activity_toolbar.share.props.visible = False self.set_toolbox(toolbox) self._books_toolbar = BooksToolbar() toolbox.add_toolbar(_('Books'), self._books_toolbar) self._books_toolbar.set_activity(self) self._books_toolbar.show() toolbox.show() self.toolbox.set_current_toolbar(_TOOLBAR_BOOKS) self._books_toolbar.search_entry.grab_focus() def create_new_toolbar(self): toolbar_box = ToolbarBox() book_search_item = Gtk.ToolItem() self.search_entry = Gtk.Entry() self.search_entry.connect('activate', self.search_entry_activate_cb) width = int(Gdk.Screen.width() / 2.1) self.search_entry.set_size_request(width, -1) book_search_item.add(self.search_entry) self.search_entry.show() toolbar_box.toolbar.insert(book_search_item, -1) book_search_item.show() self._download = ToolButton('go-down') self._download.set_tooltip(_('Get Book')) self._download.props.sensitive = False self._download.connect('clicked', self._get_book_cb) toolbar_box.toolbar.insert(self._download, -1) self._download.show() self.format_combo = ComboBox() self.format_combo.connect('changed', self.format_changed_cb) self.format_combo.append_item('.djvu', 'Deja Vu') self.format_combo.append_item('_bw.pdf', 'B/W PDF') self.format_combo.append_item('.pdf', 'Color PDF') self.format_combo.append_item('.epub', 'EPUB') self.format_combo.set_active(0) self.format_combo.props.sensitive = False combotool = ToolComboBox(self.format_combo) toolbar_box.toolbar.insert(combotool, -1) combotool.show() self.search_entry.grab_focus() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl><Shift>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() def format_changed_cb(self, combo): self.show_book_data() def search_entry_activate_cb(self, entry): self.find_books(entry.props.text) def _get_book_cb(self, button): self.get_book() def enable_button(self, state): self._download.props.sensitive = state self.format_combo.props.sensitive = state def selection_cb(self, selection): self.clear_downloaded_bytes() tv = selection.get_tree_view() model = tv.get_model() sel = selection.get_selected() if sel: model, iter = sel self.book_data = model.get_value(iter,COLUMN_TITLE) + '\n\n' self.selected_title = self.truncate(model.get_value(iter,COLUMN_TITLE), 75) self.selected_volume = model.get_value(iter,COLUMN_VOLUME) if self.selected_volume != '': self.book_data += _('Volume') + ': ' + self.selected_volume + '\n\n' self.book_data += model.get_value(iter,COLUMN_CREATOR) + '\n\n' self.selected_author = self.truncate(model.get_value(iter,COLUMN_CREATOR), 40) description = model.get_value(iter,COLUMN_DESCRIPTION) if description != '': self.book_data += description + '\n\n' subject = model.get_value(iter,COLUMN_SUBJECT) if subject != '': self.book_data += _('Subject') + ': ' + subject + '\n\n' self.book_data += _('Publisher') + ': ' + model.get_value(iter,COLUMN_PUBLISHER) + '\n\n' self.book_data += _('Language') +': '+ model.get_value(iter,COLUMN_LANGUAGE) + '\n\n' self.download_url = 'http://www.archive.org/download/' identifier = model.get_value(iter,COLUMN_IDENTIFIER) self.download_url += identifier + '/' + identifier self.show_book_data() def show_book_data(self): if _NEW_TOOLBAR_SUPPORT: format = self.format_combo.props.value else: format = self._books_toolbar.format_combo.props.value if not hasattr(self, 'textview'): return textbuffer = self.textview.get_buffer() textbuffer.set_text(self.book_data + _('Download URL') + ': ' + self.download_url + format) if _NEW_TOOLBAR_SUPPORT: self.enable_button(True) else: self._books_toolbar.enable_button(True) def find_books(self, search_text): if _NEW_TOOLBAR_SUPPORT: self.enable_button(False) else: self._books_toolbar.enable_button(False) self.clear_downloaded_bytes() textbuffer = self.textview.get_buffer() textbuffer.set_text(_('Performing lookup, please wait') + '...') self.book_selected = False self.ls.clear() search_tuple = search_text.lower().split() if len(search_tuple) == 0: self._alert(_('Error'), _('You must enter at least one search word.')) if _NEW_TOOLBAR_SUPPORT: self.search_entry.grab_focus() else: self._books_toolbar.search_entry.grab_focus() return FL = urllib.quote('fl[]') SORT = urllib.quote('sort[]') self.search_url = 'http://www.archive.org/advancedsearch.php?q=' + \ urllib.quote('(title:(' + search_text.lower() + ') OR creator:(' + search_text.lower() +')) AND format:(DJVU)') self.search_url += '&' + FL + '=creator&' + FL + '=description&' + FL + '=format&' + FL + '=identifier&' \ + FL + '=language' self.search_url += '&' + FL + '=publisher&' + FL + '=subject&' + FL + '=title&' + FL + '=volume' self.search_url += '&' + SORT + '=title&' + SORT + '&' + SORT + '=&rows=500&save=yes&fmt=csv&xmlsearch=Search' GObject.idle_add(self.download_csv, self.search_url) def get_book(self): if _NEW_TOOLBAR_SUPPORT: self.enable_button(False) format = self.format_combo.props.value else: self._books_toolbar.enable_button(False) format = self._books_toolbar.format_combo.props.value self.progressbar.show() GObject.idle_add(self.download_book, self.download_url + format) def download_csv(self, url): print "get csv from", url path = os.path.join(self.get_activity_root(), 'instance', 'tmp%i.csv' % time.time()) print 'path=', path getter = ReadURLDownloader(url) getter.connect("finished", self._get_csv_result_cb) getter.connect("progress", self._get_csv_progress_cb) getter.connect("error", self._get_csv_error_cb) _logger.debug("Starting download to %s...", path) try: getter.start(path) except: self._alert(_('Error'), _('Connection timed out for CSV: ') + url) self._download_content_type = getter.get_content_type() def _get_csv_progress_cb(self, getter, bytes_downloaded): if self._download_content_length > 0: _logger.debug("Downloaded %u of %u bytes...", bytes_downloaded, self._download_content_length) else: _logger.debug("Downloaded %u bytes...", bytes_downloaded) def _get_csv_error_cb(self, getter, err): _logger.debug("Error getting CSV: %s", err) self._alert(_('Error'), _('Error getting CSV') ) self._download_content_length = 0 self._download_content_type = None def _get_csv_result_cb(self, getter, tempfile, suggested_name): print 'Content type:', self._download_content_type if self._download_content_type.startswith('text/html'): # got an error page instead self._get_csv_error_cb(getter, 'HTTP Error') return self.process_downloaded_csv(tempfile, suggested_name) def process_downloaded_csv(self, tempfile, suggested_name): textbuffer = self.textview.get_buffer() textbuffer.set_text(_('Finished')) reader = csv.reader(open(tempfile, 'rb')) reader.next() # skip the first header row. for row in reader: if len(row) < 9: self._alert("Server Error", self.search_url) return iter = self.ls.append() self.ls.set(iter, 0, row[0], 1, row[1], 2, row[2], 3, row[3], 4, row[4], 5, row[5], \ 6, row[6], 7, row[7], 8, row[8]) os.remove(tempfile) def download_book(self, url): self.treeview.props.sensitive = False path = os.path.join(self.get_activity_root(), 'instance', 'tmp%i' % time.time()) getter = ReadURLDownloader(url) getter.connect("finished", self._get_book_result_cb) getter.connect("progress", self._get_book_progress_cb) getter.connect("error", self._get_book_error_cb) _logger.debug("Starting download to %s...", path) try: getter.start(path) except: self._alert(_('Error'), _('Connection timed out for ') + self.selected_title) self._download_content_length = getter.get_content_length() self._download_content_type = getter.get_content_type() def _get_book_result_cb(self, getter, tempfile, suggested_name): self.treeview.props.sensitive = True if self._download_content_type.startswith('text/html'): # got an error page instead self._get_book_error_cb(getter, 'HTTP Error') return self.process_downloaded_book(tempfile, suggested_name) def _get_book_progress_cb(self, getter, bytes_downloaded): if self._download_content_length > 0: _logger.debug("Downloaded %u of %u bytes...", bytes_downloaded, self._download_content_length) else: _logger.debug("Downloaded %u bytes...", bytes_downloaded) total = self._download_content_length self.set_downloaded_bytes(bytes_downloaded, total) while Gtk.events_pending(): Gtk.main_iteration() def set_downloaded_bytes(self, bytes, total): fraction = float(bytes) / float(total) self.progressbar.set_fraction(fraction) def clear_downloaded_bytes(self): self.progressbar.set_fraction(0.0) def _get_book_error_cb(self, getter, err): self.treeview.props.sensitive = True if _NEW_TOOLBAR_SUPPORT: self.enable_button(True) else: self._books_toolbar.enable_button(True) self.progressbar.hide() _logger.debug("Error getting document: %s", err) self._alert(_('Error'), _('Could not download ') + self.selected_title + _(' path in catalog is incorrect. ' \ + ' If you tried to download B/W PDF try another format.')) self._download_content_length = 0 self._download_content_type = None def process_downloaded_book(self, tempfile, suggested_name): _logger.debug("Got document %s (%s)", tempfile, suggested_name) self.create_journal_entry(tempfile) def create_journal_entry(self, tempfile): journal_entry = datastore.create() journal_title = self.selected_title if self.selected_volume != '': journal_title += ' ' + _('Volume') + ' ' + self.selected_volume if self.selected_author != '': journal_title = journal_title + ', by ' + self.selected_author journal_entry.metadata['title'] = journal_title journal_entry.metadata['title_set_by_user'] = '******' journal_entry.metadata['keep'] = '0' if _NEW_TOOLBAR_SUPPORT: format = self.format_combo.props.value else: format = self._books_toolbar.format_combo.props.value if format == '.epub': journal_entry.metadata['mime_type'] = 'application/epub+zip' if format == '.djvu': journal_entry.metadata['mime_type'] = 'image/vnd.djvu' if format == '.pdf' or format == '_bw.pdf': journal_entry.metadata['mime_type'] = 'application/pdf' journal_entry.metadata['buddies'] = '' journal_entry.metadata['preview'] = '' journal_entry.metadata['icon-color'] = profile.get_color().to_string() textbuffer = self.textview.get_buffer() journal_entry.metadata['description'] = textbuffer.get_text(textbuffer.get_start_iter(), textbuffer.get_end_iter(), True) journal_entry.file_path = tempfile datastore.write(journal_entry) os.remove(tempfile) self.progressbar.hide() self._alert(_('Success'), self.selected_title + _(' added to Journal.')) def truncate(self, str, length): if len(str) > length: return str[0:length-1] + '...' else: return str def _alert(self, title, text=None): alert = NotifyAlert(timeout=20) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) self.textview.grab_focus()
class SpeechToolbar(Gtk.Toolbar): def __init__(self, activity): Gtk.Toolbar.__init__(self) voicebar = Gtk.Toolbar() self._activity = activity if not speech.supported: return self.load_speech_parameters() self.sorted_voices = [i for i in speech.voices()] self.sorted_voices.sort(self.compare_voices) default = 0 for voice in self.sorted_voices: if voice[0] == speech.voice[0]: break default = default + 1 # Play button self.play_btn = ToggleToolButton('media-playback-start') self.play_btn.show() self.play_btn.connect('toggled', self.play_cb) self.insert(self.play_btn, -1) self.play_btn.set_tooltip(_('Play / Pause')) self.voice_combo = ComboBox() for voice in self.sorted_voices: self.voice_combo.append_item(voice, voice[0]) self.voice_combo.set_active(default) self.voice_combo.connect('changed', self.voice_changed_cb) combotool = ToolComboBox(self.voice_combo) self.insert(combotool, -1) combotool.show() self.pitchadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) pitchbar = Gtk.HScale(self.pitchadj) pitchbar.set_draw_value(False) pitchbar.set_update_policy(Gtk.UPDATE_DISCONTINUOUS) pitchbar.set_size_request(150, 15) self.pitchadj.set_value(speech.pitch) pitchtool = Gtk.ToolItem() pitchtool.add(pitchbar) pitchtool.show() self.insert(pitchtool, -1) pitchbar.show() self.rateadj = Gtk.Adjustment(0, -100, 100, 1, 10, 0) ratebar = Gtk.HScale(self.rateadj) ratebar.set_draw_value(False) ratebar.set_update_policy(Gtk.UPDATE_DISCONTINUOUS) ratebar.set_size_request(150, 15) self.rateadj.set_value(speech.rate) ratetool = Gtk.ToolItem() ratetool.add(ratebar) ratetool.show() self.insert(ratetool, -1) ratebar.show() self.pitchadj.connect("value_changed", self.pitch_adjusted_cb) self.rateadj.connect("value_changed", self.rate_adjusted_cb) def compare_voices(self, a, b): if a[0].lower() == b[0].lower(): return 0 if a[0] .lower() < b[0].lower(): return -1 if a[0] .lower() > b[0].lower(): return 1 def voice_changed_cb(self, combo): speech.voice = combo.props.value speech.say(speech.voice[0]) self.save_speech_parameters() def pitch_adjusted_cb(self, get): speech.pitch = int(get.value) speech.say(_("pitch adjusted")) self.save_speech_parameters() def rate_adjusted_cb(self, get): speech.rate = int(get.value) speech.say(_("rate adjusted")) self.save_speech_parameters() def load_speech_parameters(self): speech_parameters = {} data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') if os.path.exists(data_file_name): f = open(data_file_name, 'r') try: speech_parameters = simplejson.load(f) speech.pitch = speech_parameters['pitch'] speech.rate = speech_parameters['rate'] speech.voice = speech_parameters['voice'] finally: f.close() def save_speech_parameters(self): speech_parameters = {} speech_parameters['pitch'] = speech.pitch speech_parameters['rate'] = speech.rate speech_parameters['voice'] = speech.voice data_path = os.path.join(self._activity.get_activity_root(), 'data') data_file_name = os.path.join(data_path, 'speech_params.json') f = open(data_file_name, 'w') try: simplejson.dump(speech_parameters, f) finally: f.close() def play_cb(self, widget): if widget.get_active(): self.play_btn.set_named_icon('media-playback-pause') if speech.is_stopped(): speech.play(self._activity._view.get_marked_words()) else: self.play_btn.set_named_icon('media-playback-start') speech.stop()
class BeatToolbar(Gtk.Toolbar): def __init__(self, owner): GObject.GObject.__init__(self) self.owner = owner self.toolItem = {} self.blockBeat = False self.beatWheel = [] btn = RadioToolButton(group=None) btn.set_icon_name('beats') btn.connect('toggled', self.setBeat, 0) btn.set_tooltip(_('Jump To Beat')) self.insert(btn, -1) self.beatWheel.append(btn) for i in range(1, 12): btn = RadioToolButton(group=self.beatWheel[0]) btn.set_icon_name('beats') btn.connect('toggled', self.setBeat, i) btn.set_tooltip(_('Jump To Beat')) self.insert(btn, -1) self.beatWheel.append(btn) label = Gtk.Label(label=_("Synch to:")) self.syncLabel = Gtk.ToolItem() self.syncLabel.add(label) self.insert(self.syncLabel, 0) self.comboBox = ComboBox() self.comboBox.append_item(1, _("1 Beat")) self.comboBox.append_item(2, _("2 Beats")) self.comboBox.append_item(3, _("3 Beats")) self.comboBox.append_item(4, _("4 Beats")) self.comboBox.append_item(5, _("5 Beats")) self.comboBox.append_item(6, _("6 Beats")) self.comboBox.append_item(7, _("7 Beats")) self.comboBox.append_item(8, _("8 Beats")) self.comboBox.append_item(9, _("9 Beats")) self.comboBox.append_item(10, _("10 Beats")) self.comboBox.append_item(11, _("11 Beats")) self.comboBox.append_item(12, _("12 Beats")) self.comboBox.set_active(4 - 1) # default 4 beats self.comboBox.connect("changed", self.changeSync) self.syncBox = ToolComboBox(self.comboBox) self.insert(self.syncBox, 1) self.show_all() #def _add_palette(self, widget, palette, position = Palette.DEFAULT): def _add_palette(self, widget, palette): widget._palette = palette widget._palette.props.invoker = WidgetInvoker(widget) #widget._palette.set_property("position", position) def _add_tooltip(self, widget, tooltip): #self._add_palette(widget, Palette(tooltip), Palette.DEFAULT) self._add_palette(widget, Palette(tooltip)) def _insert_widget(self, widget, pos): self.toolItem[widget] = Gtk.ToolItem() self.toolItem[widget].add(widget) self.insert(self.toolItem[widget], pos) def _insert_separator(self, expand=False): separator = Gtk.SeparatorToolItem() separator.set_draw(False) separator.set_expand(expand) self.insert(separator, -1) def setBeat(self, widget, beat): if not self.blockBeat and widget.get_active(): self.owner._setBeat(beat) def updateBeatWheel(self, beat): self.blockBeat = True self.beatWheel[beat].set_active(True) self.blockBeat = False def setSyncBeats(self, beats): self.comboBox.set_active(beats - 1) def changeSync(self, widget): beats = widget.get_active() + 1 for i in range(beats): self.beatWheel[i].show() for i in range(beats, 12): self.beatWheel[i].hide() self.owner._setSyncBeats(beats)
class GetIABooksActivity(activity.Activity): def __init__(self, handle): "The entry point to the Activity" activity.Activity.__init__(self, handle, False) self.max_participants = 1 self._sequence = 0 self.selected_book = None self.queryresults = None self._getter = None self.show_images = True self.languages = {} self._lang_code_handler = languagenames.LanguageNames() self.catalogs_configuration = {} self.catalog_history = [] if os.path.exists('/etc/get-books.cfg'): self._read_configuration('/etc/get-books.cfg') else: self._read_configuration() toolbar_box = ToolbarBox() activity_button = ToolButton() color = profile.get_color() bundle = ActivityBundle(activity.get_bundle_path()) icon = Icon(file=bundle.get_icon(), xo_color=color) activity_button.set_icon_widget(icon) activity_button.show() toolbar_box.toolbar.insert(activity_button, 0) self._add_search_controls(toolbar_box.toolbar) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) toolbar_box.toolbar.insert(StopButton(self), -1) self.set_toolbar_box(toolbar_box) toolbar_box.show_all() self._books_toolbar = toolbar_box.toolbar self._create_controls() self.using_powerd = os.access(POWERD_INHIBIT_DIR, os.W_OK) self.__book_downloader = self.__image_downloader = None def get_path(self): self._sequence += 1 return os.path.join(self.get_activity_root(), 'instance', '%03d.tmp' % self._sequence) def _inhibit_suspend(self): if self.using_powerd: fd = open(POWERD_INHIBIT_DIR + "/%u" % os.getpid(), 'w') logging.error("inhibit_suspend file is %s", (POWERD_INHIBIT_DIR \ + "/%u" % os.getpid())) fd.close() return True return False def _allow_suspend(self): if self.using_powerd: if os.path.exists(POWERD_INHIBIT_DIR + "/%u" % os.getpid()): os.unlink(POWERD_INHIBIT_DIR + "/%u" % os.getpid()) logging.error("allow_suspend unlinking %s", (POWERD_INHIBIT_DIR \ + "/%u" % os.getpid())) return True return False def _read_configuration(self, file_name='get-books.cfg'): logging.error('Reading configuration from file %s', file_name) config = ConfigParser.ConfigParser() config.readfp(open(file_name)) if config.has_option('GetBooks', 'show_images'): self.show_images = config.getboolean('GetBooks', 'show_images') self.languages = {} if config.has_option('GetBooks', 'languages'): languages_param = config.get('GetBooks', 'languages') for language in languages_param.split(','): lang_code = language.strip() if len(lang_code) > 0: self.languages[lang_code] = \ self._lang_code_handler.get_full_language_name(lang_code) for section in config.sections(): if section != 'GetBooks' and not section.startswith('Catalogs'): name = config.get(section, 'name') _SOURCES[section] = name repo_config = {} repo_config['query_uri'] = config.get(section, 'query_uri') repo_config['opds_cover'] = config.get(section, 'opds_cover') if config.has_option(section, 'summary_field'): repo_config['summary_field'] = \ config.get(section, 'summary_field') else: repo_config['summary_field'] = None if config.has_option(section, 'blacklist'): blacklist = config.get(section, 'blacklist') repo_config['blacklist'] = blacklist.split(',') # TODO strip? else: repo_config['blacklist'] = [] _SOURCES_CONFIG[section] = repo_config logging.error('_SOURCES %s', pformat(_SOURCES)) logging.error('_SOURCES_CONFIG %s', pformat(_SOURCES_CONFIG)) for section in config.sections(): if section.startswith('Catalogs'): catalog_source = section.split('_')[1] if not catalog_source in _SOURCES_CONFIG: logging.error('There are not a source for the catalog ' + 'section %s', section) break source_config = _SOURCES_CONFIG[catalog_source] opds_cover = source_config['opds_cover'] for catalog in config.options(section): catalog_config = {} catalog_config['query_uri'] = config.get(section, catalog) catalog_config['opds_cover'] = opds_cover catalog_config['source'] = catalog_source catalog_config['name'] = catalog catalog_config['summary_field'] = \ source_config['summary_field'] self.catalogs_configuration[catalog] = catalog_config self.source = _SOURCES_CONFIG.keys()[0] self.filter_catalogs_by_source() logging.error('languages %s', pformat(self.languages)) logging.error('catalogs %s', pformat(self.catalogs)) def _add_search_controls(self, toolbar): book_search_item = Gtk.ToolItem() toolbar.search_entry = iconentry.IconEntry() toolbar.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, 'system-search') toolbar.search_entry.add_clear_button() toolbar.search_entry.connect('activate', self.__search_entry_activate_cb) width = int(Gdk.Screen.width() / 4) toolbar.search_entry.set_size_request(width, -1) book_search_item.add(toolbar.search_entry) toolbar.search_entry.show() toolbar.insert(book_search_item, -1) book_search_item.show() toolbar.source_combo = ComboBox() toolbar.source_combo.props.sensitive = True toolbar.source_changed_cb_id = \ toolbar.source_combo.connect('changed', self.__source_changed_cb) combotool = ToolComboBox(toolbar.source_combo) toolbar.insert(combotool, -1) combotool.show() self.bt_catalogs = ToggleToolButton('books') self.bt_catalogs.set_tooltip(_('Catalogs')) toolbar.insert(self.bt_catalogs, -1) self.bt_catalogs.connect('toggled', self.__toggle_cats_cb) if len(self.catalogs) > 0: self.bt_catalogs.show() if len(self.languages) > 0: toolbar.config_toolbarbutton = ToolbarButton() toolbar.config_toolbarbutton.props.icon_name = 'preferences-system' toolbar.config_toolbarbox = Gtk.Toolbar() toolbar.config_toolbarbutton.props.page = toolbar.config_toolbarbox toolbar.language_combo = ComboBox() toolbar.language_combo.props.sensitive = True combotool = ToolComboBox(toolbar.language_combo) toolbar.language_combo.append_item('all', _('Any language')) for key in self.languages.keys(): toolbar.language_combo.append_item(key, self.languages[key]) toolbar.language_combo.set_active(0) toolbar.config_toolbarbutton.props.page.insert(combotool, -1) toolbar.insert(toolbar.config_toolbarbutton, -1) toolbar.config_toolbarbutton.show() combotool.show() toolbar.language_changed_cb_id = \ toolbar.language_combo.connect('changed', self.__language_changed_cb) self._device_manager = devicemanager.DeviceManager() self._refresh_sources(toolbar) self._device_manager.connect('device-changed', self.__device_changed_cb) toolbar.search_entry.grab_focus() return toolbar def __bt_catalogs_clicked_cb(self, button): palette = button.get_palette() palette.popup(immediate=True, state=palette.SECONDARY) def __switch_catalog_cb(self, catalog_name): catalog_config = self.catalogs[catalog_name.decode('utf-8')] self.__activate_catalog_cb(None, catalog_config) def __activate_catalog_cb(self, menu, catalog_config): query_language = self.get_query_language() self.enable_button(False) self.clear_downloaded_bytes() self.book_selected = False self.listview.handler_block(self.selection_cb_id) self.listview.clear() self.listview.handler_unblock(self.selection_cb_id) logging.error('SOURCE %s', catalog_config['source']) self._books_toolbar.search_entry.props.text = '' self.source = catalog_config['source'] position = _SOURCES_CONFIG[self.source]['position'] self._books_toolbar.source_combo.set_active(position) if self.queryresults is not None: self.queryresults.cancel() self.queryresults = None self.queryresults = opds.RemoteQueryResult(catalog_config, '', query_language) self.show_message(_('Performing lookup, please wait...')) # README: I think we should create some global variables for # each cursor that we are using to avoid the creation of them # every time that we want to change it self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH)) self.queryresults.connect('updated', self.__query_updated_cb) def update_format_combo(self, links): self.format_combo.handler_block(self.__format_changed_cb_id) self.format_combo.remove_all() for key in _MIMETYPES.keys(): if _MIMETYPES[key] in links.keys(): self.format_combo.append_item(_MIMETYPES[key], key) self.format_combo.set_active(0) self.format_combo.handler_unblock(self.__format_changed_cb_id) def get_search_terms(self): return self._books_toolbar.search_entry.props.text def __device_changed_cb(self, mgr): logging.debug('Device was added/removed') self._refresh_sources(self._books_toolbar) def _refresh_sources(self, toolbar): toolbar.source_combo.handler_block(toolbar.source_changed_cb_id) #TODO: Do not blindly clear this toolbar.source_combo.remove_all() position = 0 for key in _SOURCES.keys(): toolbar.source_combo.append_item(_SOURCES[key], key, icon_name='internet-icon') _SOURCES_CONFIG[key]['position'] = position position = position + 1 # Add menu for local books if len(_SOURCES) > 0: toolbar.source_combo.append_separator() toolbar.source_combo.append_item('local_books', _('My books'), icon_name='activity-journal') devices = self._device_manager.get_devices() first_device = True for device_name in devices: device = devices[device_name] logging.debug('device %s', device) if device['removable']: mount_point = device['mount_path'] label = device['label'] if label == '' or label is None: capacity = device['size'] label = (_('%.2f GB Volume') % (capacity / (1024.0 ** 3))) logging.debug('Adding device %s', (label)) if first_device: toolbar.source_combo.append_separator() first_device = False toolbar.source_combo.append_item(mount_point, label) toolbar.source_combo.set_active(0) toolbar.source_combo.handler_unblock(toolbar.source_changed_cb_id) def __format_changed_cb(self, combo): self.show_book_data(False) def __language_changed_cb(self, combo): self.find_books(self.get_search_terms()) def __search_entry_activate_cb(self, entry): self.find_books(self.get_search_terms()) def __get_book_cb(self, button): self.get_book() def enable_button(self, state): self._download.props.sensitive = state self.format_combo.props.sensitive = state def move_up_catalog(self, treeview): len_cat = len(self.catalog_history) if len_cat == 1: return else: # move a level up the tree self.catalog_listview.handler_block(self._catalog_changed_id) self.catalog_history.pop() len_cat -= 1 if(len_cat == 1): title = self.catalog_history[0]['title'] self.bt_move_up_catalog.set_label(title) self.bt_move_up_catalog.hide_image() else: title = self.catalog_history[len_cat - 1]['title'] self.bt_move_up_catalog.set_label(title) self.bt_move_up_catalog.show_image() self.catalogs = self.catalog_history[len_cat - 1]['catalogs'] if len(self.catalogs) > 0: self.path_iter = {} self.categories = [] for key in self.catalogs.keys(): self.categories.append({'text': key, 'dentro': []}) self.treemodel.clear() for p in self.categories: self.path_iter[p['text']] = \ self.treemodel.append([p['text']]) self.catalog_listview.handler_unblock(self._catalog_changed_id) def move_down_catalog(self, treeview): treestore, coldex = \ self.catalog_listview.get_selection().get_selected() len_cat = len(self.catalog_history) if len_cat > 0 and self.catalog_history[len_cat - 1]['catalogs'] == []: self.catalog_history.pop() len_cat = len(self.catalog_history) # README: when the Activity starts by default there is nothing # selected and this signal is called, so we have to avoid this # 'append' because it fails if coldex is not None: self.catalog_history.append( {'title': treestore.get_value(coldex, 0), 'catalogs': []}) self.__switch_catalog_cb(treestore.get_value(coldex, 0)) def _sort_logfile(self, treemodel, itera, iterb): a = treemodel.get_value(itera, 0) b = treemodel.get_value(iterb, 0) if a == None or b == None: return 0 a = a.lower() b = b.lower() if a > b: return 1 if a < b: return -1 return 0 def __toggle_cats_cb(self, button): if button.get_active(): self.tree_scroller.show_all() self.separa.show() else: self.tree_scroller.hide() self.separa.hide() def _create_controls(self): self._download_content_length = 0 self._download_content_type = None self.msg_label = Gtk.Label() self.list_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) # Catalogs treeview self.catalog_listview = Gtk.TreeView() self.catalog_listview.headers_clickble = True self.catalog_listview.hover_expand = True self.catalog_listview.rules_hint = True self._catalog_changed_id = self.catalog_listview.connect( 'cursor-changed', self.move_down_catalog) self.catalog_listview.set_enable_search(False) self.treemodel = Gtk.ListStore(str) self.treemodel.set_sort_column_id(0, Gtk.SortType.ASCENDING) self.catalog_listview.set_model(self.treemodel) renderer = Gtk.CellRendererText() renderer.set_property('wrap-mode', Pango.WrapMode.WORD) self.treecol = Gtk.TreeViewColumn(_('Catalogs'), renderer, text=0) self.treecol.set_property('clickable', True) self.treecol.connect('clicked', self.move_up_catalog) self.catalog_listview.append_column(self.treecol) self.bt_move_up_catalog = ButtonWithImage(_('Catalogs')) self.bt_move_up_catalog.hide_image() self.treecol.set_widget(self.bt_move_up_catalog) self.load_source_catalogs() self.tree_scroller = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.tree_scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.tree_scroller.add(self.catalog_listview) self.list_box.pack_start(self.tree_scroller, expand=False, fill=False, padding=0) self.separa = Gtk.VSeparator() self.list_box.pack_start(self.separa, expand=False, fill=False, padding=0) # books listview self.listview = ListView(self._lang_code_handler) self.selection_cb_id = self.listview.connect('selection-changed', self.selection_cb) self.listview.set_enable_search(False) self.list_scroller = Gtk.ScrolledWindow(hadjustment=None, vadjustment=None) self.list_scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) vadjustment = self.list_scroller.get_vadjustment() vadjustment.connect('value-changed', self.__vadjustment_value_changed_cb) self.list_scroller.add(self.listview) self.list_box.pack_start(self.list_scroller, expand=True, fill=True, padding=0) self.scrolled = Gtk.ScrolledWindow() self.scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.scrolled.props.shadow_type = Gtk.ShadowType.NONE self.textview = Gtk.TextView() self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_wrap_mode(Gtk.WrapMode.WORD) self.textview.set_justification(Gtk.Justification.LEFT) self.textview.set_left_margin(20) self.textview.set_right_margin(20) self.scrolled.add(self.textview) self.list_box.show_all() self.separa.hide() self.tree_scroller.hide() vbox_download = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox_format = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) format_label = Gtk.Label(label=_('Format:')) self.format_combo = ComboBox() for key in _MIMETYPES.keys(): self.format_combo.append_item(_MIMETYPES[key], key) self.format_combo.set_active(0) self.format_combo.props.sensitive = False self.__format_changed_cb_id = \ self.format_combo.connect('changed', self.__format_changed_cb) hbox_format.pack_start(format_label, False, False, 10) hbox_format.pack_start(self.format_combo, False, False, 10) vbox_download.pack_start(hbox_format, False, False, 10) self._download = Gtk.Button(_('Get Book')) self._download.set_image(Icon(icon_name='data-download')) self._download.props.sensitive = False self._download.connect('clicked', self.__get_book_cb) vbox_download.pack_start(self._download, False, False, 10) self.progressbox = Gtk.Box(spacing=20, orientation=Gtk.Orientation.HORIZONTAL) self.progressbar = Gtk.ProgressBar() self.progressbar.set_fraction(0.0) self.progressbox.pack_start(self.progressbar, expand=True, fill=True, padding=0) self.cancel_btn = Gtk.Button(stock=Gtk.STOCK_CANCEL) self.cancel_btn.set_image(Icon(icon_name='dialog-cancel')) self.cancel_btn.connect('clicked', self.__cancel_btn_clicked_cb) self.progressbox.pack_start(self.cancel_btn, expand=False, fill=False, padding=0) vbox_download.pack_start(self.progressbox, False, False, 10) bottom_hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) if self.show_images: self.__image_downloader = None self.image = Gtk.Image() self.add_default_image() bottom_hbox.pack_start(self.image, False, False, 10) bottom_hbox.pack_start(self.scrolled, True, True, 10) bottom_hbox.pack_start(vbox_download, False, False, 10) bottom_hbox.show_all() vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox.pack_start(self.msg_label, False, False, 10) vbox.pack_start(self.list_box, True, True, 0) vbox.pack_start(bottom_hbox, False, False, 10) self.set_canvas(vbox) self.listview.show() vbox.show() self.list_scroller.show() self.progress_hide() self.show_message( _('Enter words from the Author or Title to begin search.')) self._books_toolbar.search_entry.grab_focus() if len(self.catalogs) > 0: self.bt_catalogs.set_active(True) def progress_hide(self): self.clear_downloaded_bytes() self.progressbar.set_sensitive(False) self.cancel_btn.set_sensitive(False) def progress_show(self): self.progressbar.set_sensitive(True) self.cancel_btn.set_sensitive(True) def filter_catalogs_by_source(self): self.catalogs = {} for catalog_key in self.catalogs_configuration: catalog = self.catalogs_configuration[catalog_key] if catalog['source'] == self.source: self.catalogs[catalog_key] = catalog def load_source_catalogs(self): self.filter_catalogs_by_source() if len(self.catalogs) > 0: self.categories = [] self.path_iter = {} self.catalog_history = [] self.catalog_history.append({'title': _('Catalogs'), 'catalogs': self.catalogs}) for key in self.catalogs.keys(): self.categories.append({'text': key, 'dentro': []}) self.treemodel.clear() for p in self.categories: self.path_iter[p['text']] = self.treemodel.append([p['text']]) def can_close(self): if self.queryresults is not None: self.queryresults.cancel() self.queryresults = None return True def selection_cb(self, widget): selected_book = self.listview.get_selected_book() if self.source == 'local_books': if selected_book: self.selected_book = selected_book self._download.hide() self.show_book_data() self._object_id = selected_book.get_object_id() self._show_journal_alert(_('Selected book'), self.selected_title) else: self.clear_downloaded_bytes() if selected_book: self.update_format_combo(selected_book.get_types()) self.selected_book = selected_book self._download.show() self.show_book_data() def show_message(self, text): self.msg_label.set_text(text) self.msg_label.show() def hide_message(self): self.msg_label.hide() def show_book_data(self, load_image=True): self.selected_title = self.selected_book.get_title() book_data = _('Title:\t\t') + self.selected_title + '\n' self.selected_author = self.selected_book.get_author() book_data += _('Author:\t\t') + self.selected_author + '\n' self.selected_publisher = self.selected_book.get_publisher() self.selected_summary = self.selected_book.get_summary() if (self.selected_summary is not 'Unknown'): book_data += _('Summary:\t') + self.selected_summary + '\n' self.selected_language_code = self.selected_book.get_language() if self.selected_language_code != '': try: self.selected_language = \ self._lang_code_handler.get_full_language_name( self.selected_book.get_language()) except: self.selected_language = self.selected_book.get_language() book_data += _('Language:\t') + self.selected_language + '\n' book_data += _('Publisher:\t') + self.selected_publisher + '\n' textbuffer = self.textview.get_buffer() textbuffer.set_text('\n' + book_data) self.enable_button(True) # Cover Image self.exist_cover_image = False if self.show_images and load_image: if self.source == 'local_books': cover_image_buffer = self.get_journal_entry_cover_image( self.selected_book.get_object_id()) if (cover_image_buffer): self.add_image_buffer( self.get_pixbuf_from_buffer(cover_image_buffer)) else: self.add_default_image() else: url_image = self.selected_book.get_image_url() self.add_default_image() if url_image: self.download_image(url_image.values()[0]) def get_pixbuf_from_buffer(self, image_buffer): """Buffer To Pixbuf""" pixbuf_loader = GdkPixbuf.PixbufLoader() pixbuf_loader.write(image_buffer) pixbuf_loader.close() pixbuf = pixbuf_loader.get_pixbuf() return pixbuf def get_journal_entry_cover_image(self, object_id): ds_object = datastore.get(object_id) if 'cover_image' in ds_object.metadata: cover_data = ds_object.metadata['cover_image'] return base64.b64decode(cover_data) elif 'preview' in ds_object.metadata: return ds_object.metadata['preview'] else: return "" def download_image(self, url): self._inhibit_suspend() self.progress_show() if self.__image_downloader is not None: self.__image_downloader.stop() self.__image_downloader = opds.FileDownloader(url, self.get_path()) self.__image_downloader.connect('updated', self.__image_updated_cb) self.__image_downloader.connect('progress', self.__image_progress_cb) def __image_updated_cb(self, downloader, path, content_type): if path is not None: self.add_image(path) self.exist_cover_image = True os.remove(path) else: self.add_default_image() self.__image_downloader = None GObject.timeout_add(500, self.progress_hide) self._allow_suspend() def __image_progress_cb(self, downloader, progress): self.progressbar.set_fraction(progress) while Gtk.events_pending(): Gtk.main_iteration() def add_default_image(self): file_path = os.path.join(activity.get_bundle_path(), 'generic_cover.png') self.add_image(file_path) def add_image(self, file_path): pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_path) self.add_image_buffer(pixbuf) def add_image_buffer(self, pixbuf): image_height = int(Gdk.Screen.height() / 4) image_width = image_height / 3 * 2 width, height = pixbuf.get_width(), pixbuf.get_height() scale = 1 if (width > image_width) or (height > image_height): scale_x = image_width / float(width) scale_y = image_height / float(height) scale = min(scale_x, scale_y) pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), image_width, image_height) pixbuf2.fill(style.COLOR_PANEL_GREY.get_int()) margin_x = int((image_width - (width * scale)) / 2) margin_y = int((image_height - (height * scale)) / 2) pixbuf.scale(pixbuf2, margin_x, margin_y, image_width - (margin_x * 2), image_height - (margin_y * 2), margin_x, margin_y, scale, scale, GdkPixbuf.InterpType.BILINEAR) self.image.set_from_pixbuf(pixbuf2) def get_query_language(self): query_language = None if len(self.languages) > 0: query_language = self._books_toolbar.language_combo.props.value return query_language def find_books(self, search_text=''): self._inhibit_suspend() self.source = self._books_toolbar.source_combo.props.value query_language = self.get_query_language() self.enable_button(False) self.clear_downloaded_bytes() self.book_selected = False self.listview.handler_block(self.selection_cb_id) self.listview.clear() self.listview.handler_unblock(self.selection_cb_id) if self.queryresults is not None: self.queryresults.cancel() self.queryresults = None if self.source == 'local_books': self.listview.populate_with_books( self.get_entrys_info(search_text)) else: if search_text is None: return elif len(search_text) < 3: self.show_message(_('You must enter at least 3 letters.')) self._books_toolbar.search_entry.grab_focus() return if self.source == 'Internet Archive': self.queryresults = \ opds.InternetArchiveQueryResult(search_text, self.get_path()) elif self.source in _SOURCES_CONFIG: repo_configuration = _SOURCES_CONFIG[self.source] self.queryresults = opds.RemoteQueryResult(repo_configuration, search_text, query_language) else: self.queryresults = opds.LocalVolumeQueryResult(self.source, search_text, query_language) self.show_message(_('Performing lookup, please wait...')) self.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.WATCH)) self.queryresults.connect('updated', self.__query_updated_cb) def __query_updated_cb(self, query, midway): self.listview.populate(self.queryresults) if hasattr(self.queryresults, '_feedobj') and \ 'bozo_exception' in self.queryresults._feedobj: # something went wrong and we have to inform about this bozo_exception = self.queryresults._feedobj.bozo_exception if isinstance(bozo_exception, urllib2.URLError): if isinstance(bozo_exception.reason, socket.gaierror): if bozo_exception.reason.errno == -2: self.show_message(_('Could not reach the server. ' 'Maybe you are not connected to the network')) self.window.set_cursor(None) return self.show_message(_('There was an error downloading the list.')) elif (len(self.queryresults.get_catalog_list()) > 0): self.show_message(_('New catalog list %s was found') \ % self.queryresults._configuration["name"]) self.catalogs_updated(query, midway) elif len(self.queryresults) == 0: self.show_message(_('Sorry, no books could be found.')) if not midway and len(self.queryresults) > 0: self.hide_message() query_language = self.get_query_language() if query_language != 'all' and query_language != 'en': # the bookserver send english books if there are not books in # the requested language only_english = True for book in self.queryresults.get_book_list(): if book.get_language() == query_language: only_english = False break if only_english: self.show_message( _('Sorry, we only found english books.')) self.get_window().set_cursor(None) self._allow_suspend() def catalogs_updated(self, query, midway): self.catalogs = {} for catalog_item in self.queryresults.get_catalog_list(): logging.debug('Add catalog %s', catalog_item.get_title()) catalog_config = {} download_link = '' download_links = catalog_item.get_download_links() for link in download_links.keys(): download_link = download_links[link] break catalog_config['query_uri'] = download_link catalog_config['opds_cover'] = \ catalog_item._configuration['opds_cover'] catalog_config['source'] = catalog_item._configuration['source'] source_config = _SOURCES_CONFIG[catalog_config['source']] catalog_config['name'] = catalog_item.get_title() catalog_config['summary_field'] = \ catalog_item._configuration['summary_field'] if catalog_item.get_title() in source_config['blacklist']: logging.debug('Catalog "%s" is in blacklist', catalog_item.get_title()) else: self.catalogs[catalog_item.get_title().strip()] = \ catalog_config if len(self.catalogs) > 0: len_cat = len(self.catalog_history) self.catalog_history[len_cat - 1]['catalogs'] = self.catalogs self.path_iter = {} self.categories = [] for key in self.catalogs.keys(): self.categories.append({'text': key, 'dentro': []}) self.treemodel.clear() for p in self.categories: self.path_iter[p['text']] = \ self.treemodel.append([p['text']]) title = self.catalog_history[len_cat - 1]['title'] self.bt_move_up_catalog.set_label(title) self.bt_move_up_catalog.show_image() else: self.catalog_history.pop() def __source_changed_cb(self, widget): search_terms = self.get_search_terms() if search_terms == '': self.find_books(None) else: self.find_books(search_terms) # enable/disable catalogs button if configuration is available self.source = self._books_toolbar.source_combo.props.value # Get catalogs for this source self.load_source_catalogs() if len(self.catalogs) > 0: self.bt_catalogs.show() self.bt_catalogs.set_active(True) else: self.bt_catalogs.set_active(False) self.bt_catalogs.hide() def __vadjustment_value_changed_cb(self, vadjustment): if not self.queryresults.is_ready(): return try: # Use various tricks to update resultset as user scrolls down if ((vadjustment.props.upper - vadjustment.props.lower) > 1000 \ and (vadjustment.props.upper - vadjustment.props.value - \ vadjustment.props.page_size) / (vadjustment.props.upper - \ vadjustment.props.lower) < 0.3) or ((vadjustment.props.upper \ - vadjustment.props.value - vadjustment.props.page_size) < 200): if self.queryresults.has_next(): self.queryresults.update_with_next() finally: return def __cancel_btn_clicked_cb(self, btn): if self.__image_downloader is not None: self.__image_downloader.stop() if self.__book_downloader is not None: self.__book_downloader.stop() self.progress_hide() self.enable_button(True) self.listview.props.sensitive = True self._books_toolbar.search_entry.set_sensitive(True) self._allow_suspend() def get_book(self): self.enable_button(False) self.clear_downloaded_bytes() self.progress_show() if self.source != 'local_books': self.selected_book.get_download_links(self.format_combo.props.value, self.download_book, self.get_path()) def download_book(self, url): logging.error('DOWNLOAD BOOK %s', url) self._inhibit_suspend() self.listview.props.sensitive = False self._books_toolbar.search_entry.set_sensitive(False) self.__book_downloader = opds.FileDownloader(url, self.get_path()) self.__book_downloader.connect('updated', self.__book_updated_cb) self.__book_downloader.connect('progress', self.__book_progress_cb) def __book_updated_cb(self, downloader, path, content_type): self._books_toolbar.search_entry.set_sensitive(True) self.listview.props.sensitive = True self._allow_suspend() GObject.timeout_add(500, self.progress_hide) self.enable_button(True) self.__book_downloader = None if path is None: self._show_error_alert(_('Error: Could not download %s. ' + 'The path in the catalog seems to be incorrect.') % self.selected_title) return if os.stat(path).st_size == 0: self._show_error_alert(_('Error: Could not download %s. ' + 'The other end sent an empty file.') % self.selected_title) return if content_type.startswith('text/html'): self._show_error_alert(_('Error: Could not download %s. ' + 'The other end sent text/html instead of a book.') % self.selected_title) return self.process_downloaded_book(path) def __book_progress_cb(self, downloader, progress): self.progressbar.set_fraction(progress) while Gtk.events_pending(): Gtk.main_iteration() def clear_downloaded_bytes(self): self.progressbar.set_fraction(0.0) def process_downloaded_book(self, path): logging.debug("Got document %s", path) self.create_journal_entry(path) self._getter = None self._allow_suspend() def create_journal_entry(self, path): journal_entry = datastore.create() journal_title = self.selected_title if self.selected_author != '': journal_title = journal_title + ', by ' + self.selected_author journal_entry.metadata['title'] = journal_title journal_entry.metadata['title_set_by_user'] = '******' journal_entry.metadata['keep'] = '0' journal_entry.metadata['mime_type'] = \ self.format_combo.props.value # Fix fake mime type for black&white pdfs if journal_entry.metadata['mime_type'] == _MIMETYPES['PDF BW']: journal_entry.metadata['mime_type'] = _MIMETYPES['PDF'] journal_entry.metadata['buddies'] = '' journal_entry.metadata['icon-color'] = profile.get_color().to_string() textbuffer = self.textview.get_buffer() journal_entry.metadata['description'] = \ textbuffer.get_text(textbuffer.get_start_iter(), textbuffer.get_end_iter(), True) if self.exist_cover_image: image_buffer = self._get_preview_image_buffer() journal_entry.metadata['preview'] = dbus.ByteArray(image_buffer) image_buffer = self._get_cover_image_buffer() journal_entry.metadata['cover_image'] = \ dbus.ByteArray(base64.b64encode(image_buffer)) else: journal_entry.metadata['cover_image'] = "" journal_entry.metadata['tags'] = self.source journal_entry.metadata['source'] = self.source journal_entry.metadata['author'] = self.selected_author journal_entry.metadata['publisher'] = self.selected_publisher journal_entry.metadata['summary'] = self.selected_summary journal_entry.metadata['language'] = self.selected_language_code journal_entry.file_path = path datastore.write(journal_entry) os.remove(path) self.progress_hide() self._object_id = journal_entry.object_id self._show_journal_alert(_('Download completed'), self.selected_title) def _show_journal_alert(self, title, msg): _stop_alert = Alert() _stop_alert.props.title = title _stop_alert.props.msg = msg if _HAS_BUNDLE_LAUNCHER: bundle = get_bundle(object_id=self._object_id) if bundle is not None: icon = Icon(file=bundle.get_icon()) label = _('Open with %s') % bundle.get_name() _stop_alert.add_button(Gtk.ResponseType.ACCEPT, label, icon) else: icon = Icon(icon_name='zoom-activity') label = _('Show in Journal') _stop_alert.add_button(Gtk.ResponseType.APPLY, label, icon) icon.show() ok_icon = Icon(icon_name='dialog-ok') _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon) ok_icon.show() # Remove other alerts for alert in self._alerts: self.remove_alert(alert) self.add_alert(_stop_alert) _stop_alert.connect('response', self.__stop_response_cb) _stop_alert.show() def __stop_response_cb(self, alert, response_id): if response_id is Gtk.ResponseType.APPLY: activity.show_object_in_journal(self._object_id) elif response_id is Gtk.ResponseType.ACCEPT: launch_bundle(object_id=self._object_id) self.remove_alert(alert) def _get_preview_image_buffer(self): preview_width, preview_height = style.zoom(300), style.zoom(225) pixbuf = self.image.get_pixbuf() width, height = pixbuf.get_width(), pixbuf.get_height() scale = 1 if (width > preview_width) or (height > preview_height): scale_x = preview_width / float(width) scale_y = preview_height / float(height) scale = min(scale_x, scale_y) pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), preview_width, preview_height) pixbuf2.fill(style.COLOR_WHITE.get_int()) margin_x = int((preview_width - (width * scale)) / 2) margin_y = int((preview_height - (height * scale)) / 2) pixbuf.scale(pixbuf2, margin_x, margin_y, preview_width - (margin_x * 2), preview_height - (margin_y * 2), margin_x, margin_y, scale, scale, GdkPixbuf.InterpType.BILINEAR) succes, data = pixbuf2.save_to_bufferv('png', [], []) return data def _get_cover_image_buffer(self): pixbuf = self.image.get_pixbuf() succes, data = pixbuf.save_to_bufferv('png', [], []) return data def _show_error_alert(self, title, text=None): alert = NotifyAlert(timeout=20) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) self.textview.grab_focus() def get_entrys_info(self, query): books = [] for key in _MIMETYPES.keys(): books.extend(self.get_entry_info_format(query, _MIMETYPES[key])) return books def get_entry_info_format(self, query, mime): books = [] if query is not None and len(query) > 0: ds_objects, num_objects = datastore.find( {'mime_type': '%s' % mime, 'query': '*%s*' % query}) else: ds_objects, num_objects = datastore.find( {'mime_type': '%s' % mime}) logging.error('Local search %d books found %s format', num_objects, mime) for i in range(0, num_objects): entry = {} entry['title'] = ds_objects[i].metadata['title'] entry['mime'] = ds_objects[i].metadata['mime_type'] entry['object_id'] = ds_objects[i].object_id if 'author' in ds_objects[i].metadata: entry['author'] = ds_objects[i].metadata['author'] else: entry['author'] = '' if 'publisher' in ds_objects[i].metadata: entry['dcterms_publisher'] = \ ds_objects[i].metadata['publisher'] else: entry['dcterms_publisher'] = '' if 'language' in ds_objects[i].metadata: entry['dcterms_language'] = \ ds_objects[i].metadata['language'] else: entry['dcterms_language'] = '' if 'source' in ds_objects[i].metadata: entry['source'] = \ ds_objects[i].metadata['source'] else: entry['source'] = '' if entry['source'] in _SOURCES_CONFIG: repo_configuration = _SOURCES_CONFIG[entry['source']] summary_field = repo_configuration['summary_field'] if 'summary' in ds_objects[i].metadata: entry[summary_field] = ds_objects[i].metadata['summary'] else: entry[summary_field] = '' else: repo_configuration = None books.append(opds.Book(repo_configuration, entry, '')) return books def close(self, skip_save=False): "Override the close method so we don't try to create a Journal entry." activity.Activity.close(self, True) def save(self): pass