Source

noor / noorgtk.py

Full commit
#!/usr/bin/env python
import sys

import gtk
import pango

from noor import uihelpers


class AyaCollector(object):

    def __init__(self, text_view, config):
        self.view = text_view
        self.buffer = text_view.get_buffer()
        self.result = []
        self._create_tags(config)
        self.view.set_editable(False)
        self.view.set_cursor_visible(False)
        self.view.set_wrap_mode(gtk.WRAP_WORD)

    def _create_tags(self, config):
        fgcolor = uihelpers.get_option(config, 'gtk.fgcolor')
        bgcolor = uihelpers.get_option(config, 'gtk.bgcolor')
        dirs = {'rtl': gtk.TEXT_DIR_RTL, 'ltr': gtk.TEXT_DIR_LTR}
        font = uihelpers.get_option(config, 'gtk.font', '')
        trans_font = uihelpers.get_option(config, 'gtk.translation_font', '')
        attrs = {'direction': dirs['rtl']}
        if fgcolor:
            attrs['foreground'] = fgcolor
        if bgcolor:
            attrs['background'] = bgcolor
        attrs1 = dict(attrs)
        attrs1.update(self._font_attrs(font))
        attrs2 = dict(attrs)
        attrs3 = dict(attrs1)
        attrs4 = dict(attrs1)
        attrs5 = dict(attrs1)
        attrs2.update(self._font_attrs(trans_font))
        attrs2['direction'] = direction=dirs[self._get_trans_dir(config)]
        attrs3['background'] = 'green'
        attrs4['foreground'] = 'blue'
        attrs5['foreground'] = 'red'
        self.tag1 = self.buffer.create_tag('quran', **attrs1)
        self.tag2 = self.buffer.create_tag('trans', **attrs2)
        self.tag3 = self.buffer.create_tag('juz', **attrs3)
        self.tag4 = self.buffer.create_tag('sign', **attrs4)
        self.tag5 = self.buffer.create_tag('sajda', **attrs5)

    def _font_attrs(self, rawfont):
        font = uihelpers.parse_font(rawfont)
        attrs = {}
        if font.face is not None:
            attrs['font'] = font.face
        if font.size is not None:
            attrs['size-points'] = int(font.size)
        if font.fgcolor is not None:
            attrs['foreground'] = font.fgcolor
        if font.bgcolor is not None:
            attrs['background'] = font.bgcolor
        return attrs

    def _get_trans_dir(self, config):
        trans_path = uihelpers.get_translation_path(config)
        if trans_path is not None:
            trans_info = uihelpers._zekr_translation_info(trans_path)
        else:
            trans_info = {}
        return trans_info.get('direction', 'rtl')

    def __call__(self, text, number=None, sajda=None,
                 translation=None, juz_start=None):
        if juz_start is not None:
            self._insert(juz_start.ljust(2), self.tag3)
            self._insert('\n')
        self._insert(text, self.tag1)
        # handling aya sign
        if number is not None:
            sign = str(number)
            sign_tag = self.tag5
            if sajda == 'minor':
                sign = '*%s*' % sign
            elif sajda == 'major':
                sign = '**%s**' % sign
            else:
                sign_tag = self.tag4
            self._insert('[', self.tag4)
            self._insert('%s' % sign, sign_tag)
            self._insert(']\n', self.tag4)
        else:
            self._insert('\n')
        if translation is not None:
            self._insert(translation + '\n', self.tag2)
        self._insert('\n')

    def _insert(self, text, *tags):
        self.buffer.insert_with_tags(self.buffer.get_end_iter(),
                                     text, *tags)

    @property
    def text(self):
        return ''.join(self.result)


class NoorDialog(object):

    def __init__(self, config, quran, sura):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title(self._get_title(quran, sura))
        self.window.set_border_width(1)
        self.window.set_size_request(800, 600)
        self.window.connect('destroy', self._quit)

        self.text_view = gtk.TextView()
        self._set_text(config, quran, sura)

        self.sura_window = gtk.ScrolledWindow()
        self.sura_window.add_with_viewport(self.text_view)
        self.sura_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        self.text_view.connect('key_press_event', self._key_pressed)
        self.window.add(self.sura_window)
        self.adjustment = self.sura_window.get_vscrollbar().get_adjustment()

    def _set_text(self, config, quran, sura):
        trans = uihelpers.get_translation(config)
        arabic_numbers = uihelpers.get_option(
            config, 'common.arabic_numbers', False)
        collector = AyaCollector(self.text_view, config)
        uihelpers.write_sura(quran, sura, collector, trans,
                             arabic_numbers=arabic_numbers)
        return collector.text

    def _get_title(self, quran, sura):
        return 'Noor - ' + str(sura) + '. ' + quran.suras[sura - 1].name

    def _key_pressed(self, widget, event, data=None):
        if event.type == gtk.gdk.KEY_PRESS:
            keyval = event.keyval
            keys = self.keys
            if event.state & gtk.gdk.CONTROL_MASK:
                keys = self.c_keys
            if event.state & gtk.gdk.MOD1_MASK:
                keys = self.m_keys
            if event.state & gtk.gdk.SHIFT_MASK:
                keys = self.s_keys
            if keyval in keys:
                keys[keyval](self)
                return True

    def _adjust_page(self, increment):
        new_value = self.adjustment.value + increment
        newvalue = max(self.adjustment.lower,
                       min(new_value, self.adjustment.upper
                           - self.adjustment.page_size))
        self.adjustment.set_value(newvalue)

    def _prev_line(self):
        self._adjust_page(-self.adjustment.step_increment)

    def _next_line(self):
        self._adjust_page(self.adjustment.step_increment)

    def _prev_page(self):
        self._adjust_page(-self.adjustment.page_increment)

    def _next_page(self):
        self._adjust_page(self.adjustment.page_increment)

    def _start(self):
        self._adjust_page(self.adjustment.lower - self.adjustment.value)

    def _end(self):
        self._adjust_page(self.adjustment.upper - self.adjustment.value
                          - self.adjustment.page_size)

    def _quit(self, *args):
        gtk.main_quit()

    def run(self):
        self.window.show_all()
        gtk.main()

    keys = {gtk.keysyms.Prior: _prev_page, gtk.keysyms.Next: _next_page,
            gtk.keysyms.Down: _next_line, gtk.keysyms.Up: _prev_line,
            gtk.keysyms.Home: _start, gtk.keysyms.End: _end,
            ord('j'): _next_line, ord('k'): _prev_line,
            ord(' '): _next_page, ord('q'): _quit}
    c_keys = {ord('v'): _next_page, ord('n'): _next_line,
              ord('p'): _prev_line, ord('a'): _start, ord('e'): _end}
    m_keys = {ord('v'): _prev_page}
    s_keys = {ord(' '): _prev_page}


class SurasDialog(object):

    def __init__(self, config, quran):
        self.dialog = gtk.Dialog()
        self.dialog.set_title('Noor - Choose Sura')
        self.dialog.set_border_width(1)
        self.dialog.set_size_request(400, 200)
        self.dialog.connect('destroy', self._quit)

        l = gtk.Label()
        l.set_markup('Choose a sura to display:')
        self.combobox = gtk.combo_box_new_text()
        self._modify_font(config, self.combobox)
        for index, sura in enumerate(quran.suras):
            self.combobox.append_text('%d - %s' % (index + 1, sura.name))
        self.combobox.set_active(0)

        button = gtk.Button()
        button.connect('clicked', self._selected)
        button_label = gtk.Label()
        button_label.set_markup('Choose')
        button.add(button_label)

        self.dialog.vbox.pack_start(l, True, True, 0)
        self.dialog.vbox.pack_start(self.combobox, True, True, 0)
        self.dialog.vbox.pack_start(button, True, True, 0)
        self.selected = False

    def _quit(self, *args):
        gtk.main_quit()

    def _selected(self, *args):
        self.selected = True
        self.dialog.hide()
        self._quit()

    def run(self):
        self.dialog.show_all()
        gtk.main()

    def get_sura(self):
        if self.selected:
            return self.combobox.get_active() + 1

    def _modify_font(self, config, widget):
        raw_font = uihelpers.get_option(config, 'gtk.font', None)
        if raw_font is not None:
            font = uihelpers.parse_font(raw_font)
            widget.modify_font(pango.FontDescription(font.face + ' '
                                                     + font.size))


def ask_sura(config, quran):
    dialog = SurasDialog(config, quran)
    dialog.run()
    return dialog.get_sura()

def show(sura=None):
    quran = uihelpers.get_quran()
    config = uihelpers.get_config()
    if sura is None:
        sura = ask_sura(config, quran)
        if sura is None:
            return
    NoorDialog(config, quran, sura).run()

if __name__ == '__main__':
    if len(sys.argv) == 1:
        show()
    else:
        if not sys.argv[1].isdigit():
            print 'Usage: %s [sura_number]' % sys.argv[0]
        else:
            show(int(sys.argv[1]))