Blob Blame History Raw
# vim:set et sts=4 sw=4:
# -*- coding: utf-8 -*-
#
# ibus - The Input Bus
#
# Copyright (c) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
# Copyright (c) 2017 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

# for python2
from __future__ import print_function

__all__ = (
    "EmojiLangButton",
);

from gi.repository import Gtk
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import IBus

import functools
import gettext
import i18n
import locale
import os

from icon import load_icon
from i18n import _, N_

ROW_TRAVEL_DIRECTION_NONE,      \
ROW_TRAVEL_DIRECTION_FORWARD,   \
ROW_TRAVEL_DIRECTION_BACKWARD = list(range(3))

class LanguageString:
    def __init__(self, id, trans = ""):
        self.id = id
        self.trans = trans

class EmojiLangChooser(Gtk.Dialog):
    __gtype_name__ = 'EmojiLangChooser'
    __initial_languages = [ IBus.get_language_name('en_US'),
                            IBus.get_language_name('en_GB'),
                            IBus.get_language_name('de_DE'),
                            IBus.get_language_name('fr_FR'),
                            IBus.get_language_name('es_ES'),
                            IBus.get_language_name('zh_CN'),
                            IBus.get_language_name('ja_JP'),
                            IBus.get_language_name('ru_RU'),
                            IBus.get_language_name('ar_EG') ]


    def __init__(self, id = None, transient_for = None):
        super(EmojiLangChooser, self).__init__(
                title = _("Select a language"),
                transient_for = transient_for,
                resizable = True)
        buttons = (_("_Cancel"), Gtk.ResponseType.CANCEL,
                   _("_OK"), Gtk.ResponseType.APPLY)
        self.add_buttons(*buttons)

        if id == None:
            id = 'en'
        self.__id = id
        self.__engines_for_lang = {}
        self.__untrans_for_lang = {}
        self.__langs = {}
        self.__lang_list = []

        self.__scrolled = Gtk.ScrolledWindow(
                hscrollbar_policy = Gtk.PolicyType.NEVER,
                vscrollbar_policy = Gtk.PolicyType.NEVER,
                shadow_type = Gtk.ShadowType.IN,
                margin_left = 6,
                margin_right = 6,
                margin_top = 6,
                margin_bottom = 6)
        self.vbox.add(self.__scrolled)
        viewport = Gtk.Viewport()
        self.__scrolled.add(viewport)
        self.__list = Gtk.ListBox(vexpand = True,
                                  halign = Gtk.Align.FILL,
                                  valign = Gtk.Align.FILL)
        viewport.add(self.__list)

        self.__adjustment = self.__scrolled.get_vadjustment()
        self.__list.set_adjustment(self.__adjustment)
        self.__list.set_filter_func(self.__list_filter, None)
        self.__list.connect('row-activated', self.__row_activated)

        self.__showing_extra = False
        self.__more_row = self.__more_row_new()
        self.__load_lang_list()
        self.__show_lang_rows()
        self.show_all()


    def __load_lang_list(self):
        dictdir = os.path.dirname(__file__) + '/../dicts'
        for filename in os.listdir(dictdir):
            suffix = '.dict'
            if not filename.endswith(suffix):
                continue
            lang_id = filename[0:len(filename) - len(suffix)]
            prefix = 'emoji-'
            if not lang_id.startswith(prefix):
                continue
            lang_id = lang_id[len(prefix):]
            lang = LanguageString(lang_id, IBus.get_language_name(lang_id))
            self.__lang_list.append(lang)
        if len(self.__lang_list) == 0:
            print("Not found dicts in %s" % dictdir, file=sys.stderr)
            lang = LanguageString('en', IBus.get_language_name('en'))
            self.__lang_list.append(lang)
            return

        def cmp_lang(a, b):
            label_a = a.trans + a.id
            label_b = b.trans + b.id
            return (label_a > label_b) - (label_a < label_b)

        self.__lang_list.sort(key = functools.cmp_to_key(cmp_lang))

        loc = locale.getlocale()[0]
        # None on C locale
        if loc == None or loc == 'C':
            loc = 'en_US'
        index = 0
        for lang in self.__lang_list:
            # move current language to the first place
            if lang.trans == IBus.get_language_name(loc):
                self.__lang_list.remove(lang)
                self.__lang_list.insert(index, lang)
                index += 1

        for lang in self.__lang_list:
            # move English to the second place
            if lang.trans == IBus.get_language_name('en'):
                self.__lang_list.remove(lang)
                self.__lang_list.insert(index, lang)
                index += 1


    def __list_filter(self, row, data):
        if row.id == self.__id:
            self.__list.select_row(row)
        if row == self.__more_row:
            return not self.__showing_extra
        if not self.__showing_extra and row.is_extra:
            return False
        return True


    def __row_activated(self, box, row):
        if row == self.__more_row:
            self.__show_more()
            return
        self.__id = row.id


    def __padded_label_new(self, text, icon, alignment, direction):
        hbox = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL)

        if direction == ROW_TRAVEL_DIRECTION_BACKWARD:
            rtl = (Gtk.Widget.get_default_direction() == \
                   Gtk.TextDirection.RTL)
            if rtl:
                arrow = Gtk.Image.new_from_icon_name(
                    'go-previous-rtl-symbolic', Gtk.IconSize.MENU)
            else:
                arrow = Gtk.Image.new_from_icon_name(
                    'go-previous-symbolic', Gtk.IconSize.MENU)
            hbox.pack_start(arrow, False, True, 0)

        if icon != None:
            pixbuf = load_icon(icon, Gtk.IconSize.LARGE_TOOLBAR)
            image = Gtk.Image(pixbuf = pixbuf)
            hbox.pack_start(image, False, True, 0)

        label = Gtk.Label(label = text)
        label.set_halign(alignment)
        label.set_valign(Gtk.Align.CENTER)
        label.set_margin_left(20)
        label.set_margin_right(20)
        label.set_margin_top(6)
        label.set_margin_bottom(6)
        hbox.pack_start(label, True, True, 0)
        return hbox


    def __list_box_row_new(self, lang):
        row = Gtk.ListBoxRow()
        row.trans = lang.trans
        row.id = lang.id
        row.is_extra = False
        return row


    def __lang_row_new(self, lang, prev_lang):
        row = self.__list_box_row_new(lang)
        label = lang.trans
        if lang.id == self.__id:
            row.is_extra = False
        elif prev_lang != None and label == prev_lang.trans:
            label = "%s (%s)" % (lang.trans, lang.id)
            row.is_extra = True
        elif not self.__showing_extra and \
           lang.trans not in self.__initial_languages:
            row.is_extra = True
        widget = self.__padded_label_new(label,
                                         None,
                                         Gtk.Align.CENTER,
                                         ROW_TRAVEL_DIRECTION_NONE)
        row.add(widget)
        return row


    def __more_row_new(self):
        row = Gtk.ListBoxRow()
        row.id = None
        hbox = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL)
        row.add(hbox)
        row.set_tooltip_text(_("Moreā€¦"))
        arrow = Gtk.Image.new_from_icon_name('view-more-symbolic',
                                             Gtk.IconSize.MENU)
        arrow.set_margin_left(20)
        arrow.set_margin_right(20)
        arrow.set_margin_top(6)
        arrow.set_margin_bottom(6)
        arrow.set_halign(Gtk.Align.CENTER)
        arrow.set_valign(Gtk.Align.CENTER)
        hbox.pack_start(arrow, True, True, 0)
        return row


    def __set_fixed_size(self):
        if self.__scrolled.get_policy()[0] == Gtk.PolicyType.AUTOMATIC:
            return
        (width, height) = self.get_size()
        self.set_size_request(width, height)
        self.__scrolled.set_policy(Gtk.PolicyType.AUTOMATIC,
                                   Gtk.PolicyType.AUTOMATIC)


    def __remove_all_children(self):
        for l in self.__list.get_children():
            self.__list.remove(l)


    def __show_lang_rows(self):
        self.__remove_all_children()
        prev_lang = None
        for lang in self.__lang_list:
            row = self.__lang_row_new(lang, prev_lang)
            self.__list.add(row)
            prev_lang = lang
        self.__list.add(self.__more_row)
        self.__list.show_all()
        self.__adjustment.set_value(self.__adjustment.get_lower())
        self.__list.invalidate_filter()
        self.__list.set_selection_mode(Gtk.SelectionMode.SINGLE)


    def __show_more(self):
        self.__set_fixed_size()
        self.__showing_extra = True
        self.__list.invalidate_filter()


    def get_selected_lang(self):
        return self.__id


class EmojiLangButton(Gtk.Button):
    __gtype_name__ = 'EmojiLangButton'
    __gproperties__ = {
        'lang' : (
            str,
            'lang',
            'lang for emojo-*.dict',
            'en',
            GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE)
    }


    def __init__(self):
        super(EmojiLangButton, self).__init__()
        self.__lang = ''


    def do_get_property(self, prop):
        if prop.name == 'lang':
            return self.__lang
        else:
            raise AttributeError('unknown property %s' % prop.name)


    def do_set_property(self, prop, value):
        if prop.name == 'lang':
            self.set_lang(value)
        else:
            raise AttributeError('unknown property %s' % prop.name)


    def do_clicked(self):
        dialog = EmojiLangChooser(id = self.__lang,
                                  transient_for = self.get_toplevel())
        id = dialog.run()
        if id != Gtk.ResponseType.APPLY:
            dialog.destroy()
            return
        self.set_lang(dialog.get_selected_lang())
        dialog.destroy()


    def set_lang(self, lang):
        self.__lang = lang
        self.notify("lang")
        self.set_label(IBus.get_language_name(lang))


    def get_lang(self, lang):
        return self.__lang


GObject.type_register(EmojiLangButton)


if __name__ == "__main__":
        dialog = EmojiLangChooser()
        id = dialog.run()
        if id != Gtk.ResponseType.APPLY:
            dialog.destroy()
            import sys
            sys.exit(0)
        print("Selected language:", dialog.get_selected_lang())