示例#1
0
 def toggle_spellcheck(self, widget, data=None):
     if self.spellcheck:
         if widget.get_active():
             self.SpellChecker.enable()
         else:
             self.SpellChecker.disable()
     elif widget.get_active():
         try:
             self.SpellChecker = SpellChecker(self.TextEditor,
                                              locale.getdefaultlocale()[0],
                                              collapse=False)
             self.spellcheck = True
         except:
             self.SpellChecker = None
             self.spellcheck = False
             dialog = Gtk.MessageDialog(
                 self, Gtk.DialogFlags.MODAL
                 | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                 Gtk.MessageType.INFO, None,
                 _("You can not enable the Spell Checker."))
             dialog.format_secondary_text(
                 _("Please install 'hunspell' or 'aspell' dictionarys for your language from the software center."
                   ))
             response = dialog.run()
             return
     return
示例#2
0
    def __init__(self, liststore, entry=None, source=None, account=None):
        self.entry = entry
        self.child = None  # for GtkGrid.get_child_at no available

        gui = Gtk.Builder()
        gui.add_from_file(SHARED_DATA_FILE('update.glade'))
        self.media = MediaFile(gui)
        self.config = AuthorizedTwitterAccount.CONFIG

        host_re = '//[A-Za-z0-9\'~+\-=_.,/%\?!;:@#\*&\(\)]+'
        self.http_re = re.compile("(http:%s)" % host_re)
        self.https_re = re.compile("(https:%s)" % host_re)
        self.screen_name_pattern = re.compile('\B@[0-9A-Za-z_]{1,15}')

        self.account_combobox = AccountCombobox(gui, liststore, source,
                                                account)

        is_above = SETTINGS.get_boolean('update-window-keep-above')
        self.update_window = gui.get_object('window1')
        self.update_window.set_keep_above(is_above)

        self.button_image = gui.get_object('button_image')

        self.label_num = gui.get_object('label_num')
        self.comboboxtext_privacy = FacebookPrivacyCombobox(gui)
        self.grid_button = gui.get_object('grid_button')
        self.on_combobox_account_changed()

        self.button_tweet = gui.get_object('button_tweet')
        self.text_buffer = gui.get_object('textbuffer')
        self.on_textbuffer_changed(self.text_buffer)

        textview = gui.get_object('textview')

        if SpellChecker:
            self.spellchecker = SpellChecker(textview)
            if not SETTINGS.get_boolean('spell-checker'):
                self.spellchecker.disable()

        gui.connect_signals(self)

        if entry:
            widget = 'buttonbox1' if entry.get('protected') else 'image_secret'
            gui.get_object(widget).hide()
            self._download_user_icon_with_callback(gui, entry)
        else:
            gui.get_object('grid_entry').destroy()
            self.update_window.present()
示例#3
0
    def create_textview(self):
        self.vbox_left1.add(self.text_grid)
        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_hexpand(True)
        scrolledwindow.set_vexpand(True)
        self.text_grid.attach(scrolledwindow, 0, 1, 3, 1)

        self.textview = Gtk.TextView()

        spellchecker = SpellChecker(self.textview,
                                    locale.getdefaultlocale()[0])

        self.textbuffer = self.textview.get_buffer()

        scrolledwindow.add(self.textview)

        self.tag_bold = self.textbuffer.create_tag("bold",
                                                   weight=Pango.Weight.BOLD)
        self.tag_italic = self.textbuffer.create_tag("italic",
                                                     style=Pango.Style.ITALIC)
        self.tag_underline = self.textbuffer.create_tag(
            "underline", underline=Pango.Underline.SINGLE)
        self.tag_found = self.textbuffer.create_tag("found",
                                                    background="yellow")
        self.textview.connect("key_release_event", self.on_key_release)
 def activate (self, recEditor):
     UIPlugin.activate(self,recEditor)
     for module in self.pluggable.modules:
         tvs = harvest_textviews(module.main)
         for tv in tvs:
             # gtkspell.Spell(tv)
             SpellChecker(tv)
 def toggle_spellchecker(self, value):
     if self._spellchecker_loaded:
         if value:
             if self._ssb_script_spellcheck:
                 self._ssb_script_spellcheck.enable()
             if self._explorerscript_spellcheck:
                 self._explorerscript_spellcheck.enable()
         else:
             if self._ssb_script_spellcheck:
                 self._ssb_script_spellcheck.disable()
             if self._explorerscript_spellcheck:
                 self._explorerscript_spellcheck.disable()
     elif value:
         self._spellchecker_loaded = True
         if self._ssb_script_view:
             self._ssb_script_spellcheck = SpellChecker(
                 self._ssb_script_view, 'en_US')
         if self._explorerscript_view:
             self._explorerscript_spellcheck = SpellChecker(
                 self._explorerscript_view, 'en_US')
示例#6
0
    def __init__(self, liststore, entry=None, source=None, account=None):
        self.entry = entry
        self.child = None # for GtkGrid.get_child_at no available

        gui = Gtk.Builder()
        gui.add_from_file(SHARED_DATA_FILE('update.glade'))
        self.media = MediaFile(gui)
        self.config = AuthorizedTwitterAccount.CONFIG

        host_re = '//[A-Za-z0-9\'~+\-=_.,/%\?!;:@#\*&\(\)]+'
        self.http_re = re.compile("(http:%s)" % host_re)
        self.https_re = re.compile("(https:%s)" % host_re)
        self.screen_name_pattern = re.compile('\B@[0-9A-Za-z_]{1,15}')

        self.account_combobox = AccountCombobox(
            gui, liststore, source, account)

        is_above = SETTINGS.get_boolean('update-window-keep-above')
        self.update_window = gui.get_object('window1')
        self.update_window.set_keep_above(is_above)

        self.button_image = gui.get_object('button_image')

        self.label_num = gui.get_object('label_num')
        self.comboboxtext_privacy = FacebookPrivacyCombobox(gui)
        self.grid_button = gui.get_object('grid_button')
        self.on_combobox_account_changed()

        self.button_tweet = gui.get_object('button_tweet')
        self.text_buffer = gui.get_object('textbuffer')
        self.on_textbuffer_changed(self.text_buffer)

        textview = gui.get_object('textview')

        if SpellChecker:
            self.spellchecker = SpellChecker(textview)
            if not SETTINGS.get_boolean('spell-checker'):
                self.spellchecker.disable()

        gui.connect_signals(self)

        if entry:
            widget = 'buttonbox1' if entry.get('protected') else 'image_secret'
            gui.get_object(widget).hide()
            self._download_user_icon_with_callback(gui, entry)
        else:
            gui.get_object('grid_entry').destroy()
            self.update_window.present()
 def toggle_spellcheck(self, widget, data=None):
     if self.spellcheck:
         if widget.get_active():
             self.SpellChecker.enable()
         else:
             self.SpellChecker.disable()
     elif widget.get_active(): 
         try:
             self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
             self.spellcheck = True
         except:
             self.SpellChecker = None
             self.spellcheck = False
             dialog = Gtk.MessageDialog(self,
                 Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                 Gtk.MessageType.INFO,
                 None, 
                 _("You can not enable the Spell Checker.")
             )
             dialog.format_secondary_text(_("Please install 'hunspell' or 'aspell' dictionarys for your language from the software center."))
             response = dialog.run()
             return
     return
    def finish_initializing(self, builder):  # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog
        self.builder = builder

        self.connect('save-file', self.save_document)
        self.connect('save-file-as', self.save_document_as)
        self.connect('new-file', self.new_document)
        self.connect('open-file', self.open_document)
        self.connect('toggle-fullscreen', self.menu_activate_fullscreen)
        self.connect('toggle-focusmode', self.menu_activate_focusmode)
        self.connect('toggle-preview', self.menu_activate_preview)
        self.connect('toggle-spellcheck', self.toggle_spellcheck)
        self.connect('close-window', self.on_mnu_close_activate)
        self.connect('toggle-search', self.open_search_and_replace)
        self.scroll_adjusted = False

        # Code for other initialization actions should be added here.

        # Texlive checker
        self.texlive_installed = False

        self.set_name('UberwriterWindow')

        self.use_headerbar = True
        if self.use_headerbar == True:
            self.hb_revealer = Gtk.Revealer()
            self.hb = Gtk.HeaderBar()
            self.hb_revealer.add(self.hb)
            self.hb_revealer.props.transition_duration = 1000
            self.hb_revealer.props.transition_type = Gtk.RevealerTransitionType.CROSSFADE
            self.hb.props.show_close_button = True
            self.hb.get_style_context().add_class("titlebar")
            self.set_titlebar(self.hb_revealer)
            self.hb_revealer.show()
            self.hb_revealer.set_reveal_child(True)
            self.hb.show()

            bbtn = Gtk.MenuButton()
            btn_settings = Gtk.MenuButton()
            btn_settings.props.image = Gtk.Image.new_from_icon_name('emblem-system-symbolic', Gtk.IconSize.BUTTON)
            btn_settings.set_popup(self.builder.get_object("menu4"))
            # icon = Gio.ThemedIcon(name="mail-sendm receive-symbolic")
            # image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
            # bbtn.add(image)
            bbtn.set_popup(self.builder.get_object("menu1"))
            self.hb.pack_start(bbtn)
            self.hb.pack_end(btn_settings)
            self.hb.show_all()
            self.testbits = Gdk.WindowState.TILED | Gdk.WindowState.MAXIMIZED
            self.connect('draw', self.override_headerbar_background)

        self.title_end = "  –  UberWriter"
        self.set_headerbar_title("New File" + self.title_end)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')
        self.menubar = builder.get_object('menubar1')
        self.menubar.hide()

        # Wire up buttons
        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.preview_button = builder.get_object('preview_toggle')

        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        self.preview_button.set_name('preview_toggle')

        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.statusbar_revealer = builder.get_object('status_bar_revealer')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)

        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # Setup light background
        self.TextEditor = TextEditor()
        self.TextEditor.set_name('UberwriterEditor')

        base_leftmargin = 40
        # self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)
        self.TextEditor.props.width_request = 600
        self.TextEditor.props.halign = Gtk.Align.CENTER
        self.TextEditor.set_vadjustment(builder.get_object('vadjustment1'))
        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)
        self.TextEditor.connect('focus-out-event', self.focus_out)
        self.TextEditor.get_style_context().connect('changed', self.style_changed)

        # self.TextEditor.install_style_property_parser

        self.TextEditor.show()
        self.TextEditor.grab_focus()

        self.ScrolledWindow = builder.get_object('editor_scrolledwindow')
        self.EditorAlignment = builder.get_object('editor_alignment')
        self.EditorAlignment.add(self.TextEditor)
        self.alignment_padding = 40
        self.EditorViewport = builder.get_object('editor_viewport')
        self.EditorViewport.connect_after("draw", self.draw_gradient)

        self.smooth_scroll_starttime = 0
        self.smooth_scroll_endtime = 0
        self.smooth_scroll_acttarget = 0
        self.smooth_scroll_data = {
            'target_pos': -1,
            'source_pos': -1, 
            'duration': 0
        }
        self.smooth_scroll_tickid = -1

        self.PreviewPane = builder.get_object('preview_scrolledwindow')

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(4)
        self.TextEditor.set_pixels_below_lines(4)
        self.TextEditor.set_pixels_inside_wrap(8)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)

        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding
        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()
        self.style_provider.load_from_path(helpers.get_media_path('style.css'))

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer, base_leftmargin)
        self.MarkupBuffer.markup_buffer()

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0
        self.timestamp_last_mouse_motion = 0
        self.TextBuffer.connect_after('mark-set', self.mark_set)

        # Drag and drop

        # self.TextEditor.drag_dest_unset()
        # self.TextEditor.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.TextEditor.drag_dest_set_target_list(self.target_list)
        self.TextEditor.connect_after('drag-data-received', self.on_drag_data_received)
        def on_drop(widget, *args):
            print("drop")
        self.TextEditor.connect('drag-drop', on_drop)


        self.TextBuffer.connect('paste-done', self.paste_done)
        # self.connect('key-press-event', self.alt_mod)

        # Events for Typewriter mode

        # Setting up inline preview
        self.InlinePreview = UberwriterInlinePreview(self.TextEditor, self.TextBuffer)

        # Vertical scrolling
        self.vadjustment = self.ScrolledWindow.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor,
                locale.getdefaultlocale()[0], collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)

        self.did_change = False

        ###
        #   Sidebar initialization test
        ###
        self.paned_window = builder.get_object("main_pained")
        self.sidebar_box = builder.get_object("sidebar_box")
        self.sidebar = UberwriterSidebar(self)
        self.sidebar_box.hide()

        ###
        #   Search and replace initialization
        #   Same interface as Sidebar ;)
        ###
        self.searchreplace = UberwriterSearchAndReplace(self)

        # Window resize
        self.window_resize(self)
        self.connect("configure-event", self.window_resize)
        self.connect("delete-event", self.on_delete_called)

        self.gtk_settings = Gtk.Settings.get_default()
        self.load_settings(builder)

        self.connect_after('realize', self.color_window)
class UberwriterWindow(Window):

    __gtype_name__ = "UberwriterWindow"

    __gsignals__ = {
        'save-file': (GObject.SIGNAL_ACTION, None, ()),
        'open-file': (GObject.SIGNAL_ACTION, None, ()),
        'save-file-as': (GObject.SIGNAL_ACTION, None, ()),
        'new-file': (GObject.SIGNAL_ACTION, None, ()),
        'toggle-focusmode': (GObject.SIGNAL_ACTION, None, ()),
        'toggle-fullscreen': (GObject.SIGNAL_ACTION, None, ()),
        'toggle-spellcheck': (GObject.SIGNAL_ACTION, None, ()),
        'toggle-preview': (GObject.SIGNAL_ACTION, None, ()),
        'toggle-search': (GObject.SIGNAL_ACTION, None, ()),
        'toggle-search-replace': (GObject.SIGNAL_ACTION, None, ()),
        'close-window': (GObject.SIGNAL_ACTION, None, ())
    }

    def scrolled(self, widget):
        """if window scrolled + focusmode make font black again"""
        # if self.focusmode:
            # if self.textchange == False:
            #     if self.scroll_count >= 4:
            #         self.TextBuffer.apply_tag(
            #             self.MarkupBuffer.blackfont,
            #             self.TextBuffer.get_start_iter(),
            #             self.TextBuffer.get_end_iter())
            #     else:
            #         self.scroll_count += 1
            # else:
            #     self.scroll_count = 0
            #     self.textchange = False

    def paste_done(self, *args):
        self.MarkupBuffer.markup_buffer(0)

    def init_typewriter(self):
        self.EditorAlignment.props.top_padding = self.window_height / 2
        self.EditorAlignment.props.bottom_padding = self.window_height / 2
        self.typewriter_initiated = True

    def remove_typewriter(self):
        self.EditorAlignment.props.top_padding = self.alignment_padding
        self.EditorAlignment.props.bottom_padding = self.alignment_padding
        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)

    def get_text(self):
        start_iter = self.TextBuffer.get_start_iter()
        end_iter = self.TextBuffer.get_end_iter()
        return self.TextBuffer.get_text(start_iter, end_iter, False)

    WORDCOUNT = re.compile(r"(?!\-\w)[\s#*\+\-]+", re.UNICODE)
    def update_line_and_char_count(self):
        if self.status_bar_visible == False:
            return
        self.char_count.set_text(str(self.TextBuffer.get_char_count()))
        text = self.get_text()
        words = re.split(self.WORDCOUNT, text)
        length = len(words)
        # Last word a "space"
        if len(words[-1]) == 0:
            length = length - 1
        # First word a "space" (happens in focus mode...)
        if len(words[0]) == 0:
            length = length - 1
        if length == -1:
            length = 0
        self.word_count.set_text(str(length))

    def mark_set(self, buffer, location, mark, data=None):
        if mark.get_name() in ['insert', 'gtk_drag_target']:
            self.check_scroll(mark)
        return True

    def text_changed(self, widget, data=None):
        if self.did_change == False:
            self.did_change = True
            title = self.get_title()
            self.set_headerbar_title("* " + title)

        self.MarkupBuffer.markup_buffer(1)
        self.textchange = True

        self.buffer_modified_for_status_bar = True
        self.update_line_and_char_count()
        self.check_scroll(self.TextBuffer.get_insert())

    def toggle_fullscreen(self, widget, data=None):
        if widget.get_active():
            self.fullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.add_accelerator("activate",
                self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
            # Hide Menu
            self.menubar.hide()
        else:
            self.unfullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.remove_accelerator(
                self.accel_group, key, mod)
            self.menubar.show()

        self.TextEditor.grab_focus()

    def set_focusmode(self, widget, data=None):
        if widget.get_active():
            self.init_typewriter()
            self.MarkupBuffer.focusmode_highlight()
            self.focusmode = True
            self.TextEditor.grab_focus()
            self.check_scroll(self.TextBuffer.get_insert())
            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 0)
        else:
            self.remove_typewriter()
            self.focusmode = False
            self.TextBuffer.remove_tag(self.MarkupBuffer.grayfont,
                self.TextBuffer.get_start_iter(),
                self.TextBuffer.get_end_iter())
            self.TextBuffer.remove_tag(self.MarkupBuffer.blackfont,
                self.TextBuffer.get_start_iter(),
                self.TextBuffer.get_end_iter())

            self.MarkupBuffer.markup_buffer(1)
            self.TextEditor.grab_focus()
            self.update_line_and_char_count()
            self.check_scroll()
            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 4)

    def scroll_smoothly(self, widget, frame_clock, data = None):
        if self.smooth_scroll_data['target_pos'] == -1:
            return True
        def ease_out_cubic(t):
          p = t - 1;
          return p * p * p + 1;
        now = frame_clock.get_frame_time()
        if self.smooth_scroll_acttarget != self.smooth_scroll_data['target_pos']:
            self.smooth_scroll_starttime = now
            self.smooth_scroll_endtime = now + self.smooth_scroll_data['duration'] * 100
            self.smooth_scroll_acttarget = self.smooth_scroll_data['target_pos']

        if(now < self.smooth_scroll_endtime):
            t = float(now - self.smooth_scroll_starttime) / float(self.smooth_scroll_endtime - self.smooth_scroll_starttime)
        else:
            t = 1
        t = ease_out_cubic(t)
        pos = self.smooth_scroll_data['source_pos'] + (t * (self.smooth_scroll_data['target_pos'] - self.smooth_scroll_data['source_pos']))
        # print("n %i, t %f, p %i, st %i, et %i" % (now, t, pos, self.smooth_scroll_starttime, self.smooth_scroll_endtime))
        widget.get_vadjustment().props.value = pos
        return True # continue ticking

    def check_scroll(self, mark):
        gradient_offset = 80
        buf = self.TextEditor.get_buffer()
        ins_it = buf.get_iter_at_mark(mark)
        loc_rect = self.TextEditor.get_iter_location(ins_it)

        # alignment offset added from top
        pos_y = loc_rect.y + loc_rect.height + self.EditorAlignment.props.top_padding 
        
        ha = self.ScrolledWindow.get_vadjustment()
        if ha.props.page_size < gradient_offset:
            return
        pos = pos_y - ha.props.value
        # print("pos: %i, pos_y %i, page_sz: %i, val: %i" % (pos, pos_y, ha.props.page_size - gradient_offset, ha.props.value))
        # global t, amount, initvadjustment
        target_pos = -1
        if self.focusmode:
            # print("pos: %i > %i" % (pos, ha.props.page_size * 0.5))
            if pos != (ha.props.page_size * 0.5):
                target_pos = pos_y - (ha.props.page_size * 0.5)
        elif pos > ha.props.page_size - gradient_offset - 60:
            target_pos = pos_y - ha.props.page_size + gradient_offset + 60
        elif pos < gradient_offset:
            target_pos = pos_y - gradient_offset
        self.smooth_scroll_data = {
            'target_pos': target_pos,
            'source_pos': ha.props.value, 
            'duration': 2000
        }
        if self.smooth_scroll_tickid == -1:
            self.smooth_scroll_tickid = self.ScrolledWindow.add_tick_callback(self.scroll_smoothly)

    def window_resize(self, widget, data=None):
        # To calc padding top / bottom
        self.window_height = widget.get_size()[1]
        w_width = widget.get_size()[0]
        # Calculate left / right margin
        width_request = 600
        if(w_width < 900):
            # self.MarkupBuffer.set_multiplier(8)
            self.current_font_size = 12
            self.alignment_padding = 30
            lm = 7 * 8
            self.get_style_context().remove_class("medium")
            self.get_style_context().remove_class("large")
            self.get_style_context().add_class("small")

        elif(w_width < 1400):
            # self.MarkupBuffer.set_multiplier(10)
            width_request = 800
            self.current_font_size = 15
            self.alignment_padding = 40
            lm = 7 * 10
            self.get_style_context().remove_class("small")
            self.get_style_context().remove_class("large")
            self.get_style_context().add_class("medium")

        else:
            # self.MarkupBuffer.set_multiplier(13)
            self.current_font_size = 17
            width_request = 1000
            self.alignment_padding = 60
            lm = 7 * 13
            self.get_style_context().remove_class("medium")
            self.get_style_context().remove_class("small")
            self.get_style_context().add_class("large")


        self.EditorAlignment.props.top_padding = self.alignment_padding
        self.EditorAlignment.props.bottom_padding = self.alignment_padding
        self.TextEditor.set_left_margin(lm)
        self.TextEditor.set_right_margin(lm)

        self.MarkupBuffer.recalculate(lm)

        if self.focusmode:
            self.remove_typewriter()
            self.init_typewriter()

        if self.TextEditor.props.width_request != width_request:
            self.TextEditor.props.width_request = width_request
            alloc = self.TextEditor.get_allocation()
            alloc.width = width_request
            self.TextEditor.size_allocate(alloc)

    def style_changed(self, widget, data=None):
        pgc = self.TextEditor.get_pango_context()
        mets = pgc.get_metrics()
        self.MarkupBuffer.set_multiplier(Pango.units_to_double(mets.get_approximate_char_width()) + 1)
        print(Pango.units_to_double(mets.get_approximate_char_width()))


    def save_document(self, widget, data=None):
        if self.filename:
            logger.info("saving")
            filename = self.filename
            f = codecs.open(filename, encoding="utf-8", mode='w')
            f.write(self.get_text())
            f.close()
            if self.did_change:
                self.did_change = False
                title = self.get_title()
                self.set_headerbar_title(title[2:])
            return Gtk.ResponseType.OK

        else:
           
            filefilter = Gtk.FileFilter.new()
            filefilter.add_mime_type('text/x-markdown')
            filefilter.add_mime_type('text/plain')
            filefilter.set_name('MarkDown (.md)')
            filechooser = Gtk.FileChooserDialog(
                _("Save your File"),
                self,
                Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
                )

            filechooser.set_do_overwrite_confirmation(True)
            filechooser.add_filter(filefilter)
            response = filechooser.run()
            if response == Gtk.ResponseType.OK:
                filename = filechooser.get_filename()
               
                if filename[-3:] != ".md":
                    filename = filename + ".md"
                    try:
                        self.recent_manager.add_item("file:/ " + filename)
                    except:
                        pass

                f = codecs.open(filename, encoding="utf-8", mode='w')

                f.write(self.get_text())
                f.close()
               
                self.filename = filename
                self.set_headerbar_title(os.path.basename(filename) + self.title_end)
               
                self.did_change = False
                filechooser.destroy()
                return response

            else:
                filechooser.destroy()
                return Gtk.ResponseType.CANCEL

    def save_document_as(self, widget, data=None):
        filechooser = Gtk.FileChooserDialog(
            "Save your File",
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
            )
        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:

            filename = filechooser.get_filename()
            if filename[-3:] != ".md":
                filename = filename + ".md"
                try:
                    self.recent_manager.remove_item("file:/" + filename)       
                    self.recent_manager.add_item("file:/ " + filename)
                except:
                    pass

            f = codecs.open(filename, encoding="utf-8", mode='w')
            f.write(self.get_text())
            f.close()
           
            self.filename = filename
            self.set_headerbar_title(os.path.basename(filename) + self.title_end)

            try:
                self.recent_manager.add_item(filename)
            except:
                pass
               
            filechooser.destroy()
            self.did_change = False

        else:
            filechooser.destroy()
            return Gtk.ResponseType.CANCEL

    def export(self, export_type="html"):
        filechooser = Gtk.FileChooserDialog(
            "Export as %s" % export_type.upper(),
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
            )

        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename[:-2] + export_type.lower())
       
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            if filename.endswith("." + export_type):
                filename = filename[:-len(export_type)-1]
            filechooser.destroy()
        else:
            filechooser.destroy()
            return

        # Converting text to bytes for python 3
        text = bytes(self.get_text(), "utf-8")

        output_dir = os.path.abspath(os.path.join(filename, os.path.pardir))
       
        basename = os.path.basename(filename)

        args = ['pandoc', '--from=markdown', '--smart']
       
        if export_type == "pdf":
            args.append("-o%s.pdf" % basename)
       
        elif export_type == "odt":
            args.append("-o%s.odt" % basename)
       
        elif export_type == "html":
            css = helpers.get_media_file('uberwriter.css')
            args.append("-c%s" % css)
            args.append("-o%s.html" % basename)
            args.append("--mathjax")

        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=output_dir)
        output = p.communicate(text)[0]
       
        return filename
           
    def export_as_odt(self, widget, data=None):
        self.export("odt")

    def export_as_html(self, widget, data=None):
        self.export("html")

    def export_as_pdf(self, widget, data=None):
        if self.texlive_installed == False and APT_ENABLED:
            try:
                cache = apt.Cache()
                inst = cache["texlive"].is_installed
            except:
                inst = True

            if inst == False:
                dialog = Gtk.MessageDialog(self,
                    Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.NONE,
                    _("You can not export to PDF.")
                )
                dialog.format_secondary_markup(_("Please install <a href=\"apt:texlive\">texlive</a> from the software center."))
                response = dialog.run()
                return
            else:
                self.texlive_installed = True
        self.export("pdf")

    def copy_html_to_clipboard(self, widget, date=None):
        """Copies only html without headers etc. to Clipboard"""

        args = ['pandoc', '--from=markdown', '--smart', '-thtml']
        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

        text = bytes(self.get_text(), "utf-8")
        output = p.communicate(text)[0]
               
        cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        cb.set_text(output.decode("utf-8"), -1)
        cb.store()

    def open_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return

        if self.focusmode:
            self.focusmode_button.set_active(False)

        filefilter = Gtk.FileFilter.new()
        filefilter.add_mime_type('text/x-markdown')
        filefilter.add_mime_type('text/plain')
        filefilter.set_name(_('MarkDown or Plain Text'))

        filechooser = Gtk.FileChooserDialog(
            _("Open a .md-File"),
            self,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
            )
        filechooser.add_filter(filefilter)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            self.load_file(filename)
            filechooser.destroy()

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def check_change(self):
        if self.did_change and len(self.get_text()):
            dialog = Gtk.MessageDialog(self,
                Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                Gtk.MessageType.WARNING,
                Gtk.ButtonsType.NONE,
                _("You have not saved your changes.")
                )
            dialog.add_button(_("Close without Saving"), Gtk.ResponseType.NO)
            dialog.add_button(_("Cancel"), Gtk.ResponseType.CANCEL)
            dialog.add_button(_("Save now"), Gtk.ResponseType.YES)
            dialog.set_title(_('Unsaved changes'))
            dialog.set_default_size(200, 150)
            dialog.set_default_response(Gtk.ResponseType.YES)
            response = dialog.run()

            if response == Gtk.ResponseType.YES:
                title = self.get_title()
                if self.save_document(widget = None) == Gtk.ResponseType.CANCEL:
                    dialog.destroy()
                    return self.check_change()
                else:                   
                    dialog.destroy()
                    return response
            elif response == Gtk.ResponseType.NO:
                dialog.destroy()
                return response
            else:
                dialog.destroy()
                return Gtk.ResponseType.CANCEL

    def new_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return
        else:
            self.TextBuffer.set_text('')
            self.TextEditor.undos = []
            self.TextEditor.redos = []

            self.did_change = False
            self.filename = None
            self.set_headerbar_title("New File" + self.title_end)

    def menu_activate_focusmode(self, widget=None):
        self.focusmode_button.emit('activate')

    def menu_activate_fullscreen(self, widget=None):
        self.fullscreen_button.emit('activate')

    def menu_toggle_sidebar(self, widget=None):
        self.sidebar.toggle_sidebar()

    def menu_activate_preview(self, widget=None):
        self.preview_button.emit('activate')

    # # Not added as menu button as of now. Standard is typewriter active.
    # def toggle_typewriter(self, widget, data=None):
    #     self.typewriter_active = widget.get_active()

    def toggle_spellcheck(self, widget, data=None):
        if self.spellcheck:
            if widget.get_active():
                self.SpellChecker.enable()
            else:
                self.SpellChecker.disable()
        elif widget.get_active():
            try:
                self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
                self.spellcheck = True
            except:
                self.SpellChecker = None
                self.spellcheck = False
                dialog = Gtk.MessageDialog(self,
                    Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.NONE,
                    _("You can not enable the Spell Checker.")
                )
                dialog.format_secondary_text(_("Please install 'hunspell' or 'aspell' dictionarys for your language from the software center."))
                response = dialog.run()
                return
        return

    def on_drag_data_received(self, widget, drag_context, x, y,
                              data, info, time):
        """Handle drag and drop events"""
        if info == 1:
            # uri target
            uris = data.get_uris()
            print(uris)
            for uri in uris:
                uri = urllib.parse.unquote_plus(uri)
                mime = mimetypes.guess_type(uri)

                if mime[0] is not None and mime[0].startswith('image'):
                    if uri.startswith("file://"):
                        uri = uri[7:]
                    text = "![Insert image title here](%s)" % uri
                    ll = 2
                    lr = 23
                else:
                    text = "[Insert link title here](%s)" % uri
                    ll = 1
                    lr = 22
                self.TextBuffer.place_cursor(self.TextBuffer.get_iter_at_mark(
                    self.TextBuffer.get_mark('gtk_drag_target')))
                self.TextBuffer.insert_at_cursor(text)
                insert_mark = self.TextBuffer.get_insert()
                selection_bound = self.TextBuffer.get_selection_bound()
                cursor_iter = self.TextBuffer.get_iter_at_mark(insert_mark)
                cursor_iter.backward_chars(len(text) - ll)
                print('move_cursor')
                self.TextBuffer.move_mark(insert_mark, cursor_iter)
                cursor_iter.forward_chars(lr)
                self.TextBuffer.move_mark(selection_bound, cursor_iter)
                print('move selection')
       
        elif info == 2:
            # Text target
            self.TextBuffer.place_cursor(self.TextBuffer.get_iter_at_mark(
                self.TextBuffer.get_mark('gtk_drag_target')))
            self.TextBuffer.insert_at_cursor(data.get_text())
        Gtk.drag_finish(drag_context, True, True, time)
        self.present()
        print("returning true")
        return False

    def toggle_preview(self, widget, data=None):
        if widget.get_active():
            # Insert a tag with ID to scroll to
            # self.TextBuffer.insert_at_cursor('<span id="scroll_mark"></span>')
            # TODO
            # Find a way to find the next header, scroll to the next header.

            args = ['pandoc',
                    '--from=markdown',
                    '--smart',
                    '-thtml',
                    '--mathjax',
                    '-c', helpers.get_media_file('uberwriter.css')]

            p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

            text = bytes(self.get_text(), "utf-8")
            output = p.communicate(text)[0]

            # Load in Webview and scroll to #ID
            self.webview = WebKit.WebView()
            self.webview.load_html_string(output.decode("utf-8"), 'file://localhost/')

            # Delete the cursor-scroll mark again
            # cursor_iter = self.TextBuffer.get_iter_at_mark(self.TextBuffer.get_insert())
            # begin_del = cursor_iter.copy()
            # begin_del.backward_chars(30)
            # self.TextBuffer.delete(begin_del, cursor_iter)

            self.ScrolledWindow.remove(self.EditorViewport)
            self.ScrolledWindow.add(self.webview)
            self.webview.show()

            # This saying that all links will be opened in default browser, but local files are opened in appropriate apps:
            self.webview.connect("navigation-requested", self.on_click_link)
        else:
            self.ScrolledWindow.remove(self.webview)
            self.webview.destroy()
            self.ScrolledWindow.add(self.EditorViewport)
            self.TextEditor.show()

        self.queue_draw()
        return True

    def on_click_link(self, view, frame, req, data=None):
        # This provide ability for self.webview to open links in default browser
        if(req.get_uri().startswith("http://")):
            webbrowser.open(req.get_uri())
            return True # Don't let the event "bubble up"

    def dark_mode_toggled(self, widget, data=None):
        # Save state for saving settings later
        self.dark_mode = widget.get_active()
        if self.dark_mode:
            # Dark Mode is on
            self.gtk_settings.set_property('gtk-application-prefer-dark-theme', True)
            self.get_style_context().add_class("dark_mode")
            self.MarkupBuffer.dark_mode(True)
            # self.background_image = helpers.get_media_path('bg_dark.png')
        else:
            # Dark mode off
            self.gtk_settings.set_property('gtk-application-prefer-dark-theme', False)
            self.get_style_context().remove_class("dark_mode")
            self.MarkupBuffer.dark_mode(False)
            # self.background_image = helpers.get_media_path('bg_light.png')

        # surface = cairo.ImageSurface.create_from_png(self.background_image)
        # self.background_pattern = cairo.SurfacePattern(surface)
        # self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        # Gtk.StyleContext.add_provider_for_screen(
        #     Gdk.Screen.get_default(), self.style_provider,
        #     Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        # )
        # Redraw contents of window (self)
        self.queue_draw()

    def load_file(self, filename=None):
        """Open File from command line or open / open recent etc."""
        if filename:
            if filename.startswith('file://'):
                filename = filename[7:]
            filename = urllib.parse.unquote_plus(filename)
            try:
                self.preview_button.set_active(False)
                self.filename = filename
                f = codecs.open(filename, encoding="utf-8", mode='r')
                self.TextBuffer.set_text(f.read())
                f.close()
                self.MarkupBuffer.markup_buffer(0)
                self.set_headerbar_title(os.path.basename(filename) + self.title_end)
                self.TextEditor.undo_stack = []
                self.TextEditor.redo_stack = []
                # ei = self.TextBuffer.get_end_iter()
                # anchor = self.TextBuffer.create_child_anchor(ei)
                # al = Gtk.Label.new('asd')
                # al.set_text('...')
                # al.show()
                # self.TextEditor.add_child_at_anchor(al, anchor)

            except Exception as e:
                logger.warning("Error Reading File: %r" % e)
            self.did_change = False
        else:
            logger.warning("No File arg")

    # Help Menu
    def open_launchpad_translation(self, widget, data=None):
        webbrowser.open("https://translations.launchpad.net/uberwriter")

    def open_launchpad_help(self, widget, data=None):
        webbrowser.open("https://answers.launchpad.net/uberwriter")

    def open_pandoc_markdown(self, widget, data=None):
        webbrowser.open("http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown")

    def open_uberwriter_markdown(self, widget, data=None):
        self.load_file(helpers.get_media_file('uberwriter_markdown.md'))

    def open_search_and_replace(self, widget, data=None):
        self.searchreplace.toggle_search()

    def open_advanced_export(self, widget, data=None):
        if self.UberwriterAdvancedExportDialog is not None:
            advexp = self.UberwriterAdvancedExportDialog()  # pylint: disable=

            response = advexp.run()
            if response == 1:
                advexp.advanced_export(bytes(self.get_text(), "utf-8"))

            advexp.destroy()

    def open_recent(self, widget, data=None):
        if data:
            if self.check_change() == Gtk.ResponseType.CANCEL:
                return
            else:
                self.load_file(data)

    def generate_recent_files_menu(self, parent_menu):
        # Recent file filter
        self.recent_manager = Gtk.RecentManager.get_default()

        self.recent_files_menu = Gtk.RecentChooserMenu.new_for_manager(self.recent_manager)
        self.recent_files_menu.set_sort_type(Gtk.RecentSortType.MRU)

        recent_filter = Gtk.RecentFilter.new()
        recent_filter.add_mime_type('text/x-markdown')
        self.recent_files_menu.set_filter(recent_filter)
        menu = Gtk.Menu.new()

        for entry in self.recent_files_menu.get_items():
            if entry.exists():
                item = Gtk.MenuItem.new_with_label(entry.get_display_name())
                item.connect('activate', self.open_recent, entry.get_uri())
                menu.append(item)
                item.show()

        menu.show()
        parent_menu.set_submenu(menu)
        parent_menu.show()

    def poll_for_motion(self):
        if (self.was_motion == False
                and self.status_bar_visible
                and self.buffer_modified_for_status_bar
                and self.TextEditor.props.has_focus):
            # self.status_bar.set_state_flags(Gtk.StateFlags.INSENSITIVE, True)
            self.statusbar_revealer.set_reveal_child(False)
            self.hb_revealer.set_reveal_child(False)
            self.status_bar_visible = False
            self.buffer_modified_for_status_bar = False
            return False

        self.was_motion = False
        return True

    def on_motion_notify(self, widget, event, data=None):
        now = event.get_time()
        if now - self.timestamp_last_mouse_motion > 150:
            self.timestamp_last_mouse_motion = now
            return
        if now - self.timestamp_last_mouse_motion < 100:
            return
        if now - self.timestamp_last_mouse_motion > 100:
            if self.status_bar_visible == False:
                self.statusbar_revealer.set_reveal_child(True)
                self.hb_revealer.set_reveal_child(True)
                self.hb.props.opacity = 1
                self.status_bar_visible = True
                self.buffer_modified_for_status_bar = False
                self.update_line_and_char_count()
                # self.status_bar.set_state_flags(Gtk.StateFlags.NORMAL, True)
                GObject.timeout_add(3000, self.poll_for_motion)
            self.was_motion = True

    def focus_out(self, widget, data=None):
        if self.status_bar_visible == False:
            self.statusbar_revealer.set_reveal_child(True)
            self.hb_revealer.set_reveal_child(True)
            self.hb.props.opacity = 1
            self.status_bar_visible = True
            self.buffer_modified_for_status_bar = False
            self.update_line_and_char_count()

    def override_headerbar_background(self, widget, cr):
        if(widget.get_window().get_state() & self.testbits):
            bg_color = self.get_style_context().get_background_color(Gtk.StateFlags.ACTIVE)
            alloc = widget.get_allocation()
            width = alloc.width
            height = alloc.height

            cr.rectangle(0,0, width, height)
            cr.set_source_rgb(bg_color.red, bg_color.green, bg_color.blue)
            cr.fill()


    def draw_gradient(self, widget, cr):
        bg_color = self.get_style_context().get_background_color(Gtk.StateFlags.ACTIVE)

        lg_top = cairo.LinearGradient(0, 0, 0, 80)
        lg_top.add_color_stop_rgba(0, bg_color.red, bg_color.green, bg_color.blue, 1)
        lg_top.add_color_stop_rgba(1, bg_color.red, bg_color.green, bg_color.blue, 0)

        width = widget.get_allocation().width
        height = widget.get_allocation().height

        cr.rectangle(0, 0, width, 80)
        cr.set_source(lg_top)
        cr.fill()
        cr.rectangle(0, height - 80, width, height)
        
        lg_btm = cairo.LinearGradient(0, height - 80, 0, height)
        lg_btm.add_color_stop_rgba(1, bg_color.red, bg_color.green, bg_color.blue, 1)
        lg_btm.add_color_stop_rgba(0, bg_color.red, bg_color.green, bg_color.blue, 0)

        cr.set_source(lg_btm)
        cr.fill()

    def finish_initializing(self, builder):  # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog
        self.builder = builder

        self.connect('save-file', self.save_document)
        self.connect('save-file-as', self.save_document_as)
        self.connect('new-file', self.new_document)
        self.connect('open-file', self.open_document)
        self.connect('toggle-fullscreen', self.menu_activate_fullscreen)
        self.connect('toggle-focusmode', self.menu_activate_focusmode)
        self.connect('toggle-preview', self.menu_activate_preview)
        self.connect('toggle-spellcheck', self.toggle_spellcheck)
        self.connect('close-window', self.on_mnu_close_activate)
        self.connect('toggle-search', self.open_search_and_replace)
        self.scroll_adjusted = False

        # Code for other initialization actions should be added here.

        # Texlive checker
        self.texlive_installed = False

        self.set_name('UberwriterWindow')

        self.use_headerbar = True
        if self.use_headerbar == True:
            self.hb_revealer = Gtk.Revealer()
            self.hb = Gtk.HeaderBar()
            self.hb_revealer.add(self.hb)
            self.hb_revealer.props.transition_duration = 1000
            self.hb_revealer.props.transition_type = Gtk.RevealerTransitionType.CROSSFADE
            self.hb.props.show_close_button = True
            self.hb.get_style_context().add_class("titlebar")
            self.set_titlebar(self.hb_revealer)
            self.hb_revealer.show()
            self.hb_revealer.set_reveal_child(True)
            self.hb.show()

            bbtn = Gtk.MenuButton()
            btn_settings = Gtk.MenuButton()
            btn_settings.props.image = Gtk.Image.new_from_icon_name('emblem-system-symbolic', Gtk.IconSize.BUTTON)
            btn_settings.set_popup(self.builder.get_object("menu4"))
            # icon = Gio.ThemedIcon(name="mail-sendm receive-symbolic")
            # image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
            # bbtn.add(image)
            bbtn.set_popup(self.builder.get_object("menu1"))
            self.hb.pack_start(bbtn)
            self.hb.pack_end(btn_settings)
            self.hb.show_all()
            self.testbits = Gdk.WindowState.TILED | Gdk.WindowState.MAXIMIZED
            self.connect('draw', self.override_headerbar_background)

        self.title_end = "  –  UberWriter"
        self.set_headerbar_title("New File" + self.title_end)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')
        self.menubar = builder.get_object('menubar1')
        self.menubar.hide()

        # Wire up buttons
        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.preview_button = builder.get_object('preview_toggle')

        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        self.preview_button.set_name('preview_toggle')

        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.statusbar_revealer = builder.get_object('status_bar_revealer')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)

        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # Setup light background
        self.TextEditor = TextEditor()
        self.TextEditor.set_name('UberwriterEditor')

        base_leftmargin = 40
        # self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)
        self.TextEditor.props.width_request = 600
        self.TextEditor.props.halign = Gtk.Align.CENTER
        self.TextEditor.set_vadjustment(builder.get_object('vadjustment1'))
        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)
        self.TextEditor.connect('focus-out-event', self.focus_out)
        self.TextEditor.get_style_context().connect('changed', self.style_changed)

        # self.TextEditor.install_style_property_parser

        self.TextEditor.show()
        self.TextEditor.grab_focus()

        self.ScrolledWindow = builder.get_object('editor_scrolledwindow')
        self.EditorAlignment = builder.get_object('editor_alignment')
        self.EditorAlignment.add(self.TextEditor)
        self.alignment_padding = 40
        self.EditorViewport = builder.get_object('editor_viewport')
        self.EditorViewport.connect_after("draw", self.draw_gradient)

        self.smooth_scroll_starttime = 0
        self.smooth_scroll_endtime = 0
        self.smooth_scroll_acttarget = 0
        self.smooth_scroll_data = {
            'target_pos': -1,
            'source_pos': -1, 
            'duration': 0
        }
        self.smooth_scroll_tickid = -1

        self.PreviewPane = builder.get_object('preview_scrolledwindow')

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(4)
        self.TextEditor.set_pixels_below_lines(4)
        self.TextEditor.set_pixels_inside_wrap(8)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)

        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding
        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()
        self.style_provider.load_from_path(helpers.get_media_path('style.css'))

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer, base_leftmargin)
        self.MarkupBuffer.markup_buffer()

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0
        self.timestamp_last_mouse_motion = 0
        self.TextBuffer.connect_after('mark-set', self.mark_set)

        # Drag and drop

        # self.TextEditor.drag_dest_unset()
        # self.TextEditor.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.TextEditor.drag_dest_set_target_list(self.target_list)
        self.TextEditor.connect_after('drag-data-received', self.on_drag_data_received)
        def on_drop(widget, *args):
            print("drop")
        self.TextEditor.connect('drag-drop', on_drop)


        self.TextBuffer.connect('paste-done', self.paste_done)
        # self.connect('key-press-event', self.alt_mod)

        # Events for Typewriter mode

        # Setting up inline preview
        self.InlinePreview = UberwriterInlinePreview(self.TextEditor, self.TextBuffer)

        # Vertical scrolling
        self.vadjustment = self.ScrolledWindow.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor,
                locale.getdefaultlocale()[0], collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)

        self.did_change = False

        ###
        #   Sidebar initialization test
        ###
        self.paned_window = builder.get_object("main_pained")
        self.sidebar_box = builder.get_object("sidebar_box")
        self.sidebar = UberwriterSidebar(self)
        self.sidebar_box.hide()

        ###
        #   Search and replace initialization
        #   Same interface as Sidebar ;)
        ###
        self.searchreplace = UberwriterSearchAndReplace(self)

        # Window resize
        self.window_resize(self)
        self.connect("configure-event", self.window_resize)
        self.connect("delete-event", self.on_delete_called)

        self.gtk_settings = Gtk.Settings.get_default()
        self.load_settings(builder)

        self.connect_after('realize', self.color_window)

    def color_window(self, widget, data=None):
        window_gdk = self.get_window()
        window_gdk.set_background(Gdk.Color(0, 1, 0))

    def alt_mod(self, widget, event, data=None):
        # TODO: Click and open when alt is pressed
        if event.state & Gdk.ModifierType.MOD2_MASK:
            logger.info("Alt pressed")
        return

    def on_delete_called(self, widget, data=None):
        """Called when the TexteditorWindow is closed."""
        logger.info('delete called')
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return True
        return False

    def on_mnu_close_activate(self, widget, data=None):
        """
            Signal handler for closing the UberwriterWindow.
            Overriden from parent Window Class
        """
        if self.on_delete_called(self):  # Really destroy?
            return
        else:
            self.destroy()
        return

    def on_destroy(self, widget, data=None):
        """Called when the TexteditorWindow is closed."""
        # Clean up code for saving application state should be added here.
        self.save_settings()
        Gtk.main_quit()

    def set_headerbar_title(self, title):
        if self.use_headerbar:
            self.hb.props.title = title
        self.set_title(title)

    def save_settings(self):
        if not os.path.exists(CONFIG_PATH):
            try:
                os.makedirs(CONFIG_PATH)
            except Exception as e:
                logger.debug("Failed to make uberwriter config path in\
                     ~/.config/uberwriter. Error: %r" % e)
        try:
            settings = dict()
            settings["dark_mode"] = self.dark_mode
            settings["spellcheck"] = self.SpellChecker.enabled
            f = open(CONFIG_PATH + "settings.pickle", "wb+")
            pickle.dump(settings, f)
            f.close()
            logger.debug("Saved settings: %r" % settings)
        except Exception as e:
            logger.debug("Error writing settings file to disk. Error: %r" % e)

    def load_settings(self, builder):
        dark_mode_button = builder.get_object("dark_mode")
        spellcheck_button = builder.get_object("disable_spellcheck")
        try:
            f = open(CONFIG_PATH + "settings.pickle", "rb")
            settings = pickle.load(f)
            f.close()
            self.dark_mode = settings['dark_mode']
            dark_mode_button.set_active(settings['dark_mode'])
            spellcheck_button.set_active(settings['spellcheck'])
            logger.debug("loaded settings: %r" % settings)
        except Exception as e:
            logger.debug("(First Run?) Error loading settings from home dir. \
                Error: %r", e)
        return True
示例#10
0
import sys
from os.path import join, dirname

sys.path.append(join(dirname(__file__), '../src/'))

import locale

import gtk

from gtkspellcheck import SpellChecker

if __name__ == '__main__':

    def quit(*args):
        gtk.main_quit()

    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.set_title('PyGtkSpellCheck Example')
    view = gtk.TextView()

    spellchecker = SpellChecker(view, locale.getdefaultlocale()[0])

    for code, name in spellchecker.languages:
        print('code: %5s, language: %s' % (code, name))

    window.set_default_size(600, 400)
    window.add(view)
    window.show_all()
    window.connect('delete-event', quit)
    gtk.main()
示例#11
0
    def finish_initializing(self, builder):  # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog

        # Code for other initialization actions should be added here.

        # Texlive checker

        self.texlive_installed = False

        # Draw background
        self.background_image = helpers.get_media_path('bg_light.png')
        self.connect('draw', self.draw_bg)

        self.set_name('UberwriterWindow')

        self.title_end = "  –  UberWriter"
        self.set_title("New File" + self.title_end)

        # Drag and drop
        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)

        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.drag_dest_set_target_list(self.target_list)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')
        self.menubar = builder.get_object('menubar1')

        # Wire up buttons
        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.preview_button = builder.get_object('preview_toggle')

        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        self.preview_button.set_name('preview_toggle')

        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)

        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # Setup light background

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        self.TextEditor = TextEditor()

        base_leftmargin = 100
        self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)

        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)

        self.TextEditor.show()

        self.ScrolledWindow = builder.get_object('editor_scrolledwindow')
        self.ScrolledWindow.add(self.TextEditor)

        self.PreviewPane = builder.get_object('preview_scrolledwindow')

        pangoFont = Pango.FontDescription("Ubuntu Mono 15px")

        self.TextEditor.modify_font(pangoFont)

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(4)
        self.TextEditor.set_pixels_below_lines(4)
        self.TextEditor.set_pixels_inside_wrap(8)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)

        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding

        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect(
            'changed', self.text_changed)

        self.TextEditor.connect('move-cursor', self.cursor_moved)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()

        css = open(helpers.get_media_path('style.css'), 'rb')
        css_data = css.read()
        css.close()

        self.style_provider.load_from_data(css_data)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

        # Still needed.
        self.fflines = 0

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer,
                                         base_leftmargin)
        self.MarkupBuffer.markup_buffer()
        self.FormatShortcuts = FormatShortcuts(self.TextBuffer,
                                               self.TextEditor)

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0

        self.TextBuffer.connect('mark-set', self.mark_set)

        self.TextEditor.drag_dest_unset()

        # Events to preserve margin. (To be deleted.)
        self.TextEditor.connect('delete-from-cursor', self.delete_from_cursor)
        self.TextEditor.connect('backspace', self.backspace)

        self.TextBuffer.connect('paste-done', self.paste_done)
        # self.connect('key-press-event', self.alt_mod)

        # Events for Typewriter mode
        self.TextBuffer.connect_after('mark-set', self.after_mark_set)
        self.TextBuffer.connect_after('changed', self.after_modify_text)
        self.TextEditor.connect_after('move-cursor', self.after_cursor_moved)
        self.TextEditor.connect_after('insert-at-cursor',
                                      self.after_insert_at_cursor)

        # Setting up inline preview
        self.InlinePreview = UberwriterInlinePreview(self.TextEditor,
                                                     self.TextBuffer)

        # Vertical scrolling
        self.vadjustment = self.TextEditor.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor,
                                             locale.getdefaultlocale()[0],
                                             collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)

        self.did_change = False

        # Window resize
        self.connect("configure-event", self.window_resize)
        self.connect("delete-event", self.on_delete_called)
        self.load_settings(builder)
示例#12
0
class UberwriterWindow(Window):

    __gtype_name__ = "UberwriterWindow"

    def scrolled(self, widget):
        """if window scrolled + focusmode make font black again"""
#         if self.focusmode:
#            if self.textchange == False:
#                if self.scroll_count >= 1:
#                    self.TextBuffer.apply_tag(
#                        self.MarkupBuffer.blackfont,
#                        self.TextBuffer.get_start_iter(),
#                        self.TextBuffer.get_end_iter())
#                else:
#                    self.scroll_count += 1
#            else:
#                self.scroll_count = 0
#                self.typewriter()
#                self.textchange = False

    def after_modify_text(self, *arg):
        if self.focusmode:
            self.typewriter()

    def after_insert_at_cursor(self, *arg):
        if self.focusmode:
            self.typewriter()

    def paste_done(self, *args):
        self.MarkupBuffer.markup_buffer(0)

    def init_typewriter(self):

        self.TextBuffer.disconnect(self.TextEditor.delete_event)
        self.TextBuffer.disconnect(self.TextEditor.insert_event)
        self.TextBuffer.disconnect(self.text_change_event)

        ci = self.TextBuffer.get_iter_at_mark(
            self.TextBuffer.get_mark('insert'))
        co = ci.get_offset()

        fflines = int(round((self.window_height - 55) / (2 * 30)))
        self.fflines = fflines
        self.TextEditor.fflines = fflines

        s = '\n' * fflines

        start_iter = self.TextBuffer.get_iter_at_offset(0)
        self.TextBuffer.insert(start_iter, s)

        end_iter = self.TextBuffer.get_iter_at_offset(-1)
        self.TextBuffer.insert(end_iter, s)

        ne_ci = self.TextBuffer.get_iter_at_offset(co + fflines)
        self.TextBuffer.place_cursor(ne_ci)

        # Scroll it to the center
        self.TextEditor.scroll_to_mark(self.TextBuffer.get_mark('insert'), 0.0,
                                       True, 0.0, 0.5)

        self.TextEditor.insert_event = self.TextBuffer.connect(
            "insert-text", self.TextEditor._on_insert)
        self.TextEditor.delete_event = self.TextBuffer.connect(
            "delete-range", self.TextEditor._on_delete)
        self.text_change_event = self.TextBuffer.connect(
            'changed', self.text_changed)

        self.typewriter_initiated = True

    def typewriter(self):
        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        self.TextEditor.scroll_to_iter(cursor_iter, 0.0, True, 0.0, 0.5)

    def remove_typewriter(self):
        self.TextBuffer.disconnect(self.TextEditor.delete_event)
        self.TextBuffer.disconnect(self.TextEditor.insert_event)
        self.TextBuffer.disconnect(self.text_change_event)

        startIter = self.TextBuffer.get_start_iter()
        endLineIter = startIter.copy()
        endLineIter.forward_lines(self.fflines)
        self.TextBuffer.delete(startIter, endLineIter)
        startIter = self.TextBuffer.get_end_iter()
        endLineIter = startIter.copy()

        # Move to line before last line
        endLineIter.backward_lines(self.fflines - 1)

        # Move to last char in last line
        endLineIter.backward_char()
        self.TextBuffer.delete(startIter, endLineIter)

        self.fflines = 0
        self.TextEditor.fflines = 0

        self.TextEditor.insert_event = self.TextBuffer.connect(
            "insert-text", self.TextEditor._on_insert)
        self.TextEditor.delete_event = self.TextBuffer.connect(
            "delete-range", self.TextEditor._on_delete)
        self.text_change_event = self.TextBuffer.connect(
            'changed', self.text_changed)

    WORDCOUNT = re.compile(r"[\s#*\+\-]+", re.UNICODE)

    def update_line_and_char_count(self):
        if self.status_bar_visible == False:
            return

        self.char_count.set_text(
            str(self.TextBuffer.get_char_count() - (2 * self.fflines)))

        text = self.get_text()
        words = re.split(self.WORDCOUNT, text)
        length = len(words)
        # Last word a "space"
        if len(words[-1]) == 0:
            length = length - 1
        # First word a "space" (happens in focus mode...)
        if len(words[0]) == 0:
            length = length - 1
        if length == -1:
            length = 0
        self.word_count.set_text(str(length))

        # TODO rename line_count to word_count

    def get_text(self):
        if self.focusmode == False:
            start_iter = self.TextBuffer.get_start_iter()
            end_iter = self.TextBuffer.get_end_iter()

        else:
            start_iter = self.TextBuffer.get_iter_at_line(self.fflines)
            rbline = self.TextBuffer.get_line_count() - self.fflines
            end_iter = self.TextBuffer.get_iter_at_line(rbline)

        return self.TextBuffer.get_text(start_iter, end_iter, False)

    def mark_set(self, buffer, location, mark, data=None):
        if self.focusmode and (mark.get_name() == 'insert'
                               or mark.get_name() == 'selection_bound'):
            akt_lines = self.TextBuffer.get_line_count()
            lb = self.fflines
            rb = akt_lines - self.fflines
            #print "a %d, lb %d, rb %d" % (akt_lines, lb, rb)
            #lb = self.TextBuffer.get_iter_at_line(self.fflines)
            #rbline =  self.TextBuffer.get_line_count() - self.fflines
            #rb = self.TextBuffer.get_iter_at_line(
            #   rbline)
            #rb.backward_line()

            linecount = location.get_line()
            #print "a %d, lb %d, rb %d, lc %d" % (akt_lines, lb, rb, linecount)

            if linecount < lb:
                move_to_line = self.TextBuffer.get_iter_at_line(lb)
                self.TextBuffer.move_mark(mark, move_to_line)
            elif linecount >= rb:
                move_to_line = self.TextBuffer.get_iter_at_line(rb)
                move_to_line.backward_char()
                self.TextBuffer.move_mark(mark, move_to_line)

    def after_mark_set(self, buffer, location, mark, data=None):
        if self.focusmode and mark.get_name() == 'insert':
            self.typewriter()

    def delete_from_cursor(self, editor, typ, count, Data=None):
        if not self.focusmode:
            return
        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        if count < 0 and cursor_iter.starts_line():
            lb = self.fflines
            linecount = cursor_iter.get_line()
            #print "lb %d, lc %d" % (lb, linecount)
            if linecount <= lb:
                self.TextEditor.emit_stop_by_name('delete-from-cursor')
        elif count > 0 and cursor_iter.ends_line():
            akt_lines = self.TextBuffer.get_line_count()
            rb = akt_lines - self.fflines
            linecount = cursor_iter.get_line() + 1
            #print "rb %d, lc %d" % (rb, linecount)
            if linecount >= rb:
                self.TextEditor.emit_stop_by_name('delete-from-cursor')

    def backspace(self, data=None):
        if not self.focusmode:
            return

        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        if cursor_iter.starts_line():
            lb = self.fflines
            linecount = cursor_iter.get_line()
            #print "lb %d, lc %d" % (lb, linecount)

            if linecount <= lb:
                self.TextEditor.emit_stop_by_name('backspace')

    def cursor_moved(self, widget, a, b, data=None):
        pass

    def after_cursor_moved(self,
                           widget,
                           step,
                           count,
                           extend_selection,
                           data=None):
        if self.focusmode:
            self.typewriter()

    def text_changed(self, widget, data=None):
        if self.did_change == False:
            self.did_change = True
            title = self.get_title()
            self.set_title("* " + title)

        self.MarkupBuffer.markup_buffer(1)
        self.textchange = True

        self.buffer_modified_for_status_bar = True
        self.update_line_and_char_count()

    def toggle_fullscreen(self, widget, data=None):
        if widget.get_active():
            self.fullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.add_accelerator("activate",
                                                   self.accel_group, key, mod,
                                                   Gtk.AccelFlags.VISIBLE)

            # Hide Menu
            self.menubar.hide()

        else:
            self.unfullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.remove_accelerator(self.accel_group, key,
                                                      mod)
            self.menubar.show()

        self.TextEditor.grab_focus()

    def delete_text(self, widget):
        pass

    def cut_text(self, widget, data=None):
        self.TextEditor.cut()

    def paste_text(self, widget, data=None):
        self.TextEditor.paste()

    def copy_text(self, widget, data=None):
        self.TextEditor.copy()

    def undo(self, widget, data=None):
        self.TextEditor.undo()

    def redo(self, widget, data=None):
        self.TextEditor.redo()

    def set_italic(self, widget, data=None):
        """Ctrl + I"""
        self.FormatShortcuts.italic()

    def set_bold(self, widget, data=None):
        """Ctrl + B"""
        self.FormatShortcuts.bold()

    def insert_horizontal_rule(self, widget, data=None):
        """Ctrl + R"""
        self.FormatShortcuts.rule()

    def insert_unordered_list_item(self, widget, data=None):
        """Ctrl + U"""
        self.FormatShortcuts.unordered_list_item()

    def insert_ordered_list(self, widget, data=None):
        """CTRL + O"""
        self.FormatShortcuts.ordered_list_item()

    def insert_heading(self, widget, data=None):
        """CTRL + H"""
        self.FormatShortcuts.heading()

    def set_focusmode(self, widget, data=None):
        if widget.get_active():
            self.init_typewriter()
            self.MarkupBuffer.focusmode_highlight()
            self.focusmode = True
            self.TextEditor.grab_focus()

            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 0)

        else:
            self.remove_typewriter()
            self.focusmode = False
            self.TextBuffer.remove_tag(self.MarkupBuffer.grayfont,
                                       self.TextBuffer.get_start_iter(),
                                       self.TextBuffer.get_end_iter())
            self.TextBuffer.remove_tag(self.MarkupBuffer.blackfont,
                                       self.TextBuffer.get_start_iter(),
                                       self.TextBuffer.get_end_iter())

            self.MarkupBuffer.markup_buffer(1)
            self.TextEditor.grab_focus()
            self.update_line_and_char_count()

            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 4)

    def window_resize(self, widget, data=None):
        # To calc padding top / bottom
        self.window_height = widget.get_size()[1]

        # Calculate left / right margin
        lm = (widget.get_size()[0] - 1050) / 2

        self.TextEditor.set_left_margin(lm)
        self.TextEditor.set_right_margin(lm)

        self.MarkupBuffer.recalculate(lm)

        if self.focusmode:
            self.remove_typewriter()
            self.init_typewriter()

    def window_close(self, widget, data=None):
        return True

    def save_document(self, widget, data=None):
        if self.filename:
            logger.info("saving")
            filename = self.filename
            f = codecs.open(filename, encoding="utf-8", mode='w')
            f.write(self.get_text())
            f.close()
            if self.did_change:
                self.did_change = False
                title = self.get_title()
                self.set_title(title[2:])
            return Gtk.ResponseType.OK

        else:

            filefilter = Gtk.FileFilter.new()
            filefilter.add_mime_type('text/x-markdown')
            filefilter.add_mime_type('text/plain')
            filefilter.set_name('MarkDown (.md)')
            filechooser = Gtk.FileChooserDialog(
                _("Save your File"), self, Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
                 Gtk.ResponseType.OK))

            filechooser.set_do_overwrite_confirmation(True)
            filechooser.add_filter(filefilter)
            response = filechooser.run()
            if response == Gtk.ResponseType.OK:
                filename = filechooser.get_filename()

                if filename[-3:] != ".md":
                    filename = filename + ".md"
                    try:
                        self.recent_manager.add_item("file:/ " + filename)
                    except:
                        pass

                f = codecs.open(filename, encoding="utf-8", mode='w')

                f.write(self.get_text())
                f.close()

                self.filename = filename
                self.set_title(os.path.basename(filename) + self.title_end)

                self.did_change = False
                filechooser.destroy()
                return response

            elif response == Gtk.ResponseType.CANCEL:
                filechooser.destroy()
                return response

    def save_document_as(self, widget, data=None):
        filechooser = Gtk.FileChooserDialog(
            "Save your File", self, Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.OK))
        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:

            filename = filechooser.get_filename()
            if filename[-3:] != ".md":
                filename = filename + ".md"
                try:
                    self.recent_manager.remove_item("file:/" + filename)
                    self.recent_manager.add_item("file:/ " + filename)
                except:
                    pass

            f = codecs.open(filename, encoding="utf-8", mode='w')
            f.write(self.get_text())
            f.close()

            self.filename = filename
            self.set_title(os.path.basename(filename) + self.title_end)

            try:
                self.recent_manager.add_item(filename)
            except:
                pass

            filechooser.destroy()
            self.did_change = False

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def export(self, export_type="html"):
        filechooser = Gtk.FileChooserDialog(
            "Export as %s" % export_type.upper(), self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE,
             Gtk.ResponseType.OK))

        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename[:-2] + export_type.lower())

        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            if filename.endswith("." + export_type):
                filename = filename[:-len(export_type) - 1]
            filechooser.destroy()
        else:
            filechooser.destroy()
            return

        # Converting text to bytes for python 3
        text = bytes(self.get_text(), "utf-8")

        output_dir = os.path.abspath(os.path.join(filename, os.path.pardir))

        basename = os.path.basename(filename)

        args = ['pandoc', '--from=markdown', '--smart']

        if export_type == "pdf":
            args.append("-o%s.pdf" % basename)

        elif export_type == "odt":
            args.append("-o%s.odt" % basename)

        elif export_type == "html":
            css = helpers.get_media_file('uberwriter.css')
            args.append("-c%s" % css)
            args.append("-o%s.html" % basename)
            args.append("--mathjax")

        p = subprocess.Popen(args,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             cwd=output_dir)
        output = p.communicate(text)[0]

        return filename

    def export_as_odt(self, widget, data=None):
        self.export("odt")

    def export_as_html(self, widget, data=None):
        self.export("html")

    def export_as_pdf(self, widget, data=None):
        if self.texlive_installed == False and APT_ENABLED:
            try:
                cache = apt.Cache()
                inst = cache["texlive"].is_installed
            except:
                inst = True

            if inst == False:
                dialog = Gtk.MessageDialog(
                    self, Gtk.DialogFlags.MODAL
                    | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO, None,
                    _("You can not export to PDF."))
                dialog.format_secondary_markup(
                    _("Please install <a href=\"apt:texlive\">texlive</a> from the software center."
                      ))
                response = dialog.run()
                return
            else:
                self.texlive_installed = True
        self.export("pdf")

    def copy_html_to_clipboard(self, widget, date=None):
        """Copies only html without headers etc. to Clipboard"""

        args = ['pandoc', '--from=markdown', '--smart', '-thtml']
        p = subprocess.Popen(args,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE)

        text = bytes(self.get_text(), "utf-8")
        output = p.communicate(text)[0]

        cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        cb.set_text(output.decode("utf-8"), -1)
        cb.store()

    def open_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return

        filefilter = Gtk.FileFilter.new()
        filefilter.add_mime_type('text/x-markdown')
        filefilter.add_mime_type('text/plain')
        filefilter.set_name(_('MarkDown or Plain Text'))

        filechooser = Gtk.FileChooserDialog(
            _("Open a .md-File"), self, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN,
             Gtk.ResponseType.OK))
        filechooser.add_filter(filefilter)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            self.load_file(filename)
            filechooser.destroy()

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def check_change(self):
        if self.did_change and len(self.get_text()):
            dialog = Gtk.MessageDialog(
                self,
                Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                Gtk.MessageType.WARNING, None,
                _("You have not saved your changes."))
            dialog.add_button(_("Close without Saving"), Gtk.ResponseType.NO)
            dialog.add_button(_("Cancel"), Gtk.ResponseType.CANCEL)
            dialog.add_button(_("Save now"), Gtk.ResponseType.YES).grab_focus()
            dialog.set_title(_('Unsaved changes'))
            dialog.set_default_size(200, 150)
            response = dialog.run()
            if response == Gtk.ResponseType.YES:
                title = self.get_title()
                if self.save_document(widget=None) == Gtk.ResponseType.CANCEL:
                    dialog.destroy()
                    return self.check_change()
                else:
                    dialog.destroy()
                    return response
            elif response == Gtk.ResponseType.CANCEL:
                dialog.destroy()
                return response
            elif response == Gtk.ResponseType.NO:
                dialog.destroy()
                return response

    def new_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return
        else:
            self.TextBuffer.set_text('')
            self.TextEditor.undos = []
            self.TextEditor.redos = []

            self.did_change = False
            self.filename = None
            self.set_title("New File" + self.title_end)

    def menu_activate_focusmode(self, widget):
        self.focusmode_button.emit('activate')

    def menu_activate_fullscreen(self, widget):
        self.fullscreen_button.emit('activate')

    def menu_activate_preview(self, widget):
        self.preview_button.emit('activate')

    # Not added as menu button as of now. Standard is typewriter active.
    def toggle_typewriter(self, widget, data=None):
        self.typewriter_active = widget.get_active()

    def toggle_spellcheck(self, widget, data=None):
        if self.spellcheck:
            if widget.get_active():
                self.SpellChecker.enable()
            else:
                self.SpellChecker.disable()
        elif widget.get_active():
            try:
                self.SpellChecker = SpellChecker(self.TextEditor,
                                                 locale.getdefaultlocale()[0],
                                                 collapse=False)
                self.spellcheck = True
            except:
                self.SpellChecker = None
                self.spellcheck = False
                dialog = Gtk.MessageDialog(
                    self, Gtk.DialogFlags.MODAL
                    | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO, None,
                    _("You can not enable the Spell Checker."))
                dialog.format_secondary_text(
                    _("Please install 'hunspell' or 'aspell' dictionarys for your language from the software center."
                      ))
                response = dialog.run()
                return
        return

    def on_drag_data_received(self, widget, drag_context, x, y, data, info,
                              time):
        """Handle drag and drop events"""

        if info == 1:
            # uri target
            uris = data.get_uris()
            for uri in uris:
                uri = urllib.parse.unquote_plus(uri)
                mime = mimetypes.guess_type(uri)

                if mime[0] is not None and mime[0].startswith('image'):
                    text = "![Insert image title here](%s)" % uri
                    ll = 2
                    lr = 23
                else:
                    text = "[Insert link title here](%s)" % uri
                    ll = 1
                    lr = 22

                self.TextBuffer.insert_at_cursor(text)
                insert_mark = self.TextBuffer.get_insert()
                selection_bound = self.TextBuffer.get_selection_bound()
                cursor_iter = self.TextBuffer.get_iter_at_mark(insert_mark)
                cursor_iter.backward_chars(len(text) - ll)
                self.TextBuffer.move_mark(insert_mark, cursor_iter)
                cursor_iter.forward_chars(lr)
                self.TextBuffer.move_mark(selection_bound, cursor_iter)

        elif info == 2:
            # Text target
            self.TextBuffer.insert_at_cursor(data.get_text())

        self.present()

    def toggle_preview(self, widget, data=None):
        if widget.get_active():
            # Insert a tag with ID to scroll to
            self.TextBuffer.insert_at_cursor('<span id="scroll_mark"></span>')

            args = [
                'pandoc', '--from=markdown', '--smart', '-thtml', '--mathjax',
                '-c',
                helpers.get_media_file('uberwriter.css')
            ]

            p = subprocess.Popen(args,
                                 stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE)

            text = bytes(self.get_text(), "utf-8")
            output = p.communicate(text)[0]

            # Load in Webview and scroll to #ID
            self.webview = WebKit.WebView()
            self.webview.load_html_string(output.decode("utf-8"),
                                          'file://localhost/' + '#scroll_mark')

            # Delete the cursor-scroll mark again
            cursor_iter = self.TextBuffer.get_iter_at_mark(
                self.TextBuffer.get_insert())
            begin_del = cursor_iter.copy()
            begin_del.backward_chars(30)
            self.TextBuffer.delete(begin_del, cursor_iter)

            self.ScrolledWindow.remove(self.TextEditor)
            self.ScrolledWindow.add(self.webview)
            self.webview.show()

            # Making the background white

            white_background = helpers.get_media_path('white.png')
            surface = cairo.ImageSurface.create_from_png(white_background)
            self.background_pattern = cairo.SurfacePattern(surface)
            self.background_pattern.set_extend(cairo.EXTEND_REPEAT)
            # This saying that all links will be opened in default browser, but local files are opened in appropriate apps:

            self.webview.connect("navigation-requested", self.on_click_link)
        else:
            self.ScrolledWindow.remove(self.webview)
            self.webview.destroy()
            self.ScrolledWindow.add(self.TextEditor)
            self.TextEditor.show()
            surface = cairo.ImageSurface.create_from_png(self.background_image)
            self.background_pattern = cairo.SurfacePattern(surface)
            self.background_pattern.set_extend(cairo.EXTEND_REPEAT)
        self.queue_draw()

    def on_click_link(self, view, frame, req, data=None):
        # This provide ability for self.webview to open links in default browser
        webbrowser.open(req.get_uri())
        return True  # that string is god-damn-important: without it link will be opened in default browser AND also in self.webview

    def dark_mode_toggled(self, widget, data=None):
        # Save state for saving settings later
        self.dark_mode = widget.get_active()
        if self.dark_mode:
            # Dark Mode is on
            css = open(helpers.get_media_path('style_dark.css'), 'rb')
            css_data = css.read()
            css.close()
            self.style_provider.load_from_data(css_data)
            self.background_image = helpers.get_media_path('bg_dark.png')
            self.MarkupBuffer.dark_mode(True)

        else:
            # Dark mode off
            css = open(helpers.get_media_path('style.css'), 'rb')
            css_data = css.read()
            css.close()
            self.style_provider.load_from_data(css_data)
            self.background_image = helpers.get_media_path('bg_light.png')
            self.MarkupBuffer.dark_mode(False)

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
        # Redraw contents of window (self)
        self.queue_draw()

    def load_file(self, filename=None):
        """Open File from command line or open / open recent etc."""
        if filename:
            if filename.startswith('file://'):
                filename = filename[7:]
            filename = urllib.parse.unquote_plus(filename)
            try:
                self.preview_button.set_active(False)
                self.filename = filename
                f = codecs.open(filename, encoding="utf-8", mode='r')
                self.TextBuffer.set_text(f.read())
                f.close()
                self.MarkupBuffer.markup_buffer(0)
                self.set_title(os.path.basename(filename) + self.title_end)
                self.TextEditor.undos = []
                self.TextEditor.redos = []

            except Exception as e:
                logger.warning("Error Reading File: %r" % e)
            self.did_change = False
        else:
            logger.warning("No File arg")

    def draw_bg(self, widget, context):
        context.set_source(self.background_pattern)
        context.paint()

    # Help Menu
    def open_launchpad_translation(self, widget, data=None):
        webbrowser.open("https://translations.launchpad.net/uberwriter")

    def open_launchpad_help(self, widget, data=None):
        webbrowser.open("https://answers.launchpad.net/uberwriter")

    def open_pandoc_markdown(self, widget, data=None):
        webbrowser.open(
            "http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown")

    def open_uberwriter_markdown(self, widget, data=None):
        self.load_file(helpers.get_media_file('uberwriter_markdown.md'))

    def open_advanced_export(self, widget, data=None):
        if self.UberwriterAdvancedExportDialog is not None:
            advexp = self.UberwriterAdvancedExportDialog()  # pylint: disable=

            response = advexp.run()
            if response == 1:
                advexp.advanced_export(bytes(self.get_text(), "utf-8"))

            advexp.destroy()

    def open_recent(self, widget, data=None):
        if data:
            if self.check_change() == Gtk.ResponseType.CANCEL:
                return
            else:
                self.load_file(data)

    def generate_recent_files_menu(self, parent_menu):
        # Recent file filter
        self.recent_manager = Gtk.RecentManager.get_default()

        self.recent_files_menu = Gtk.RecentChooserMenu.new_for_manager(
            self.recent_manager)
        self.recent_files_menu.set_sort_type(Gtk.RecentSortType.MRU)

        recent_filter = Gtk.RecentFilter.new()
        recent_filter.add_mime_type('text/x-markdown')
        self.recent_files_menu.set_filter(recent_filter)
        menu = Gtk.Menu.new()

        for entry in self.recent_files_menu.get_items():
            if entry.exists():
                item = Gtk.MenuItem.new_with_label(entry.get_display_name())
                item.connect('activate', self.open_recent, entry.get_uri())
                menu.append(item)
                item.show()

        menu.show()
        parent_menu.set_submenu(menu)
        parent_menu.show()

    def poll_for_motion(self):
        if (self.was_motion == False and self.status_bar_visible
                and self.buffer_modified_for_status_bar):
            self.status_bar.set_state_flags(Gtk.StateFlags.INSENSITIVE, True)
            self.status_bar_visible = False
            self.buffer_modified_for_status_bar = False
            return False

        self.was_motion = False
        return True

    def on_motion_notify(self, widget, data=None):
        self.was_motion = True
        if self.status_bar_visible == False:
            self.status_bar_visible = True
            self.buffer_modified_for_status_bar = False
            self.update_line_and_char_count()
            self.status_bar.set_state_flags(Gtk.StateFlags.NORMAL, True)
            GObject.timeout_add(3000, self.poll_for_motion)

    def move_popup(self, widget, data=None):
        pass

    def finish_initializing(self, builder):  # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog

        # Code for other initialization actions should be added here.

        # Texlive checker

        self.texlive_installed = False

        # Draw background
        self.background_image = helpers.get_media_path('bg_light.png')
        self.connect('draw', self.draw_bg)

        self.set_name('UberwriterWindow')

        self.title_end = "  –  UberWriter"
        self.set_title("New File" + self.title_end)

        # Drag and drop
        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)

        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.drag_dest_set_target_list(self.target_list)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')
        self.menubar = builder.get_object('menubar1')

        # Wire up buttons
        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.preview_button = builder.get_object('preview_toggle')

        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        self.preview_button.set_name('preview_toggle')

        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)

        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # Setup light background

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        self.TextEditor = TextEditor()

        base_leftmargin = 100
        self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)

        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)

        self.TextEditor.show()

        self.ScrolledWindow = builder.get_object('editor_scrolledwindow')
        self.ScrolledWindow.add(self.TextEditor)

        self.PreviewPane = builder.get_object('preview_scrolledwindow')

        pangoFont = Pango.FontDescription("Ubuntu Mono 15px")

        self.TextEditor.modify_font(pangoFont)

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(4)
        self.TextEditor.set_pixels_below_lines(4)
        self.TextEditor.set_pixels_inside_wrap(8)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)

        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding

        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect(
            'changed', self.text_changed)

        self.TextEditor.connect('move-cursor', self.cursor_moved)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()

        css = open(helpers.get_media_path('style.css'), 'rb')
        css_data = css.read()
        css.close()

        self.style_provider.load_from_data(css_data)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

        # Still needed.
        self.fflines = 0

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer,
                                         base_leftmargin)
        self.MarkupBuffer.markup_buffer()
        self.FormatShortcuts = FormatShortcuts(self.TextBuffer,
                                               self.TextEditor)

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0

        self.TextBuffer.connect('mark-set', self.mark_set)

        self.TextEditor.drag_dest_unset()

        # Events to preserve margin. (To be deleted.)
        self.TextEditor.connect('delete-from-cursor', self.delete_from_cursor)
        self.TextEditor.connect('backspace', self.backspace)

        self.TextBuffer.connect('paste-done', self.paste_done)
        # self.connect('key-press-event', self.alt_mod)

        # Events for Typewriter mode
        self.TextBuffer.connect_after('mark-set', self.after_mark_set)
        self.TextBuffer.connect_after('changed', self.after_modify_text)
        self.TextEditor.connect_after('move-cursor', self.after_cursor_moved)
        self.TextEditor.connect_after('insert-at-cursor',
                                      self.after_insert_at_cursor)

        # Setting up inline preview
        self.InlinePreview = UberwriterInlinePreview(self.TextEditor,
                                                     self.TextBuffer)

        # Vertical scrolling
        self.vadjustment = self.TextEditor.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor,
                                             locale.getdefaultlocale()[0],
                                             collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)

        self.did_change = False

        # Window resize
        self.connect("configure-event", self.window_resize)
        self.connect("delete-event", self.on_delete_called)
        self.load_settings(builder)

    def alt_mod(self, widget, event, data=None):
        # TODO: Click and open when alt is pressed
        if event.state & Gdk.ModifierType.MOD2_MASK:
            logger.info("Alt pressed")
        return

    def on_delete_called(self, widget, data=None):
        """Called when the TexteditorWindow is closed."""
        logger.info('delete called')
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return True
        return False

    def on_mnu_close_activate(self, widget, data=None):
        """
            Signal handler for closing the UberwriterWindow.
            Overriden from parent Window Class 
        """
        if self.on_delete_called(self):  #Really destroy?
            return
        else:
            self.destroy()
        return

    def on_destroy(self, widget, data=None):
        """Called when the TexteditorWindow is closed."""
        # Clean up code for saving application state should be added here.
        self.window_close(widget)
        self.save_settings()
        Gtk.main_quit()

    def save_settings(self):

        if not os.path.exists(CONFIG_PATH):
            try:
                os.makedirs(CONFIG_PATH)
            except Exception as e:
                log.debug(
                    "Failed to make uberwriter config path in ~/.config/uberwriter. Error: %r"
                    % e)
        try:
            settings = dict()
            settings["dark_mode"] = self.dark_mode
            settings["spellcheck"] = self.SpellChecker.enabled
            f = open(CONFIG_PATH + "settings.pickle", "wb+")
            pickle.dump(settings, f)
            f.close()
            logger.debug("Saved settings: %r" % settings)
        except Exception as e:
            logger.debug("Error writing settings file to disk. Error: %r" % e)

    def load_settings(self, builder):
        dark_mode_button = builder.get_object("dark_mode")
        spellcheck_button = builder.get_object("disable_spellcheck")
        try:
            f = open(CONFIG_PATH + "settings.pickle", "rb")
            settings = pickle.load(f)
            f.close()
            self.dark_mode = settings['dark_mode']
            dark_mode_button.set_active(settings['dark_mode'])
            spellcheck_button.set_active(settings['spellcheck'])
            logger.debug("loaded settings: %r" % settings)
        except Exception as e:
            logger.debug(
                "(First Run?) Error loading settings from home dir. Error: %r",
                e)
        return 1
示例#13
0
class UpdateWindow(UpdateWidgetBase):

    def __init__(self, liststore, entry=None, source=None, account=None):
        self.entry = entry
        self.child = None # for GtkGrid.get_child_at no available

        gui = Gtk.Builder()
        gui.add_from_file(SHARED_DATA_FILE('update.glade'))
        self.media = MediaFile(gui)
        self.config = AuthorizedTwitterAccount.CONFIG

        host_re = '//[A-Za-z0-9\'~+\-=_.,/%\?!;:@#\*&\(\)]+'
        self.http_re = re.compile("(http:%s)" % host_re)
        self.https_re = re.compile("(https:%s)" % host_re)
        self.screen_name_pattern = re.compile('\B@[0-9A-Za-z_]{1,15}')

        self.account_combobox = AccountCombobox(
            gui, liststore, source, account)

        is_above = SETTINGS.get_boolean('update-window-keep-above')
        self.update_window = gui.get_object('window1')
        self.update_window.set_keep_above(is_above)

        self.button_image = gui.get_object('button_image')

        self.label_num = gui.get_object('label_num')
        self.comboboxtext_privacy = FacebookPrivacyCombobox(gui)
        self.grid_button = gui.get_object('grid_button')
        self.on_combobox_account_changed()

        self.button_tweet = gui.get_object('button_tweet')
        self.text_buffer = gui.get_object('textbuffer')
        self.on_textbuffer_changed(self.text_buffer)

        textview = gui.get_object('textview')

        if SpellChecker:
            self.spellchecker = SpellChecker(textview)
            if not SETTINGS.get_boolean('spell-checker'):
                self.spellchecker.disable()

        gui.connect_signals(self)

        if entry:
            widget = 'buttonbox1' if entry.get('protected') else 'image_secret'
            gui.get_object(widget).hide()
            self._download_user_icon_with_callback(gui, entry)
        else:
            gui.get_object('grid_entry').destroy()
            self.update_window.present()

    def _run(self, unknown, gui, entry, icon, *args):
        self._set_ui(gui, entry, icon)

        user = entry['user_name']
        self.update_window.set_title(_('Reply to %s') % user.decode('utf-8'))
        self.text_buffer.set_text(self._get_all_mentions_from(entry))

        self.update_window.present()

    def _get_all_mentions_from(self, entry):
        account_user = '******' + self.account_combobox.get_account_obj().user_name
        users = '@%s ' % entry['user_name']

        matches = self.screen_name_pattern.finditer(entry['status_body'])
        other_users = ' '.join([x.group() for x in matches 
                                if x.group() != account_user])
        if other_users:
            users += other_users + ' '

        return users

    def set_upload_media(self, file):
        self.media.set(file)
        self.on_textbuffer_changed(self.text_buffer)

    def on_textview_populate_popup(self, textview, default_menu):
        if not SpellChecker:
            return

        menuitem = Gtk.CheckMenuItem.new_with_mnemonic(_('Check _Spelling'))
        menuitem.connect("toggled", self._toggle)

        is_enbled = SETTINGS.get_boolean('spell-checker')
        menuitem.set_active(is_enbled)

        if not menuitem.get_active():
            separator = Gtk.SeparatorMenuItem.new()
            default_menu.prepend(separator)

        default_menu.prepend(menuitem)
        default_menu.show_all()

    def _toggle(self, menuitem):
        state = menuitem.get_active()
        SETTINGS.set_boolean('spell-checker', state)
        if state:
            self.spellchecker.enable()
        else:
            self.spellchecker.disable()

    def on_button_tweet_clicked(self, button):
        start, end = self.text_buffer.get_bounds()
        status = self.text_buffer.get_text(start, end, False).decode('utf-8')

        account_obj = self.account_combobox.get_account_obj()
        account_source = self.account_combobox.get_account_source()

        params = {'in_reply_to_status_id': self.entry.get('id')} \
            if self.entry else {}

        if account_source == 'Facebook':
            params = self.comboboxtext_privacy.get_params()

        if self.media.file: # update with media
            is_shrink = True
            size = 1024

            upload_file = self.media.get_upload_file_obj(is_shrink, size)
            account_obj.api.update_with_media(
                status.encode('utf-8'), upload_file.name, params=params)

        else: # normal update
            account_obj.api.update(status, params=params)

        if not self.entry:
            num = self.account_combobox.combobox_account.get_active()
            SETTINGS.set_int('recent-account', num)

        self.update_window.destroy()

    def on_button_image_clicked(self, button):
        dialog = FileChooserDialog()
        file = dialog.run(self.update_window)
        self.set_upload_media(file)

    def on_eventbox_attached_press_event(self, image_menu, event):
        if event.button == 3:
            image_menu.popup(None, None, None, None, event.button, event.time)

    def on_menuitem_remove_activate(self, menuitem):
        self.media.clear()
        self.on_textbuffer_changed(self.text_buffer)

    def on_file_activated(self, *args):
        print args

    def on_combobox_account_changed(self, *args):
        source = self.account_combobox.get_account_source()

        self.button_image.set_sensitive(source == 'Twitter')

        widget = self.label_num if source == 'Twitter' \
            else self.comboboxtext_privacy.widget if source == 'Facebook' \
            else None

        if self.child: # for GtkGrid.get_child_at no available
            self.grid_button.remove(self.child)
        if widget:
            self.grid_button.attach(widget, 0, 0, 1, 1)
        self.child = widget

    def on_textbuffer_changed(self, text_buffer):
        start, end = self.text_buffer.get_bounds()

        status = self.text_buffer.get_text(start, end, False).decode('utf-8')
        status = self.http_re.sub("*"*self.config.short_url_length, status)
        status = self.https_re.sub("*"*self.config.short_url_length_https, status)

        num = 140 - len(status) - self.media.get_link_letters()

        color = 'red' if num <= 10 else 'black'
        text = '<span fgcolor="%s">%s</span>' % (color, str(num))
        self.label_num.set_markup(text)

        status = bool(0 <= num < 140)
        self.button_tweet.set_sensitive(status)

    def on_textview_key_press_event(self, textview, event):
        key = event.keyval
        masks = event.state.value_names

        if key == Gdk.KEY_Return and 'GDK_CONTROL_MASK' in masks:
            if self.button_tweet.get_sensitive():
                self.on_button_tweet_clicked(None)
        else:
            return False

        return True

    def on_button_link_clicked(self, textbuffer):
        text = ' https://twitter.com/%s/status/%s' % (
            self.entry['user_name'], self.entry['id'])
        textbuffer.place_cursor(textbuffer.get_end_iter())
        textbuffer.insert_at_cursor(text)

    def on_button_quote_clicked(self, textbuffer):
        quote_format = SETTINGS_TWITTER.get_string('quote-format')
        text = quote_format.format(user=self.entry.get('user_name'), 
                                   status=self.entry.get('status_body'))

        textbuffer.delete(textbuffer.get_start_iter(), textbuffer.get_end_iter(),)
        textbuffer.insert_at_cursor(text)
        textbuffer.place_cursor(textbuffer.get_start_iter())
示例#14
0
class UberwriterWindow(Window):

    __gtype_name__ = "UberwriterWindow"

    def scrolled(self, widget):
        """if window scrolled + focusmode make font black again"""
        if self.focusmode:
            if self.textchange == False:
                if self.scroll_count >= 1:
                    self.TextBuffer.apply_tag(
                        self.MarkupBuffer.blackfont, 
                        self.TextBuffer.get_start_iter(), 
                        self.TextBuffer.get_end_iter())
                else:
                    self.scroll_count += 1
            else: 
                self.scroll_count = 0
                self.typewriter()
                self.textchange = False

    def after_modify_text(self, *arg):
        if self.focusmode:
            self.typewriter()

    def after_insert_at_cursor(self, *arg):
        if self.focusmode:
            self.typewriter()

    def paste_done(self, *args):
        self.MarkupBuffer.markup_buffer(0)

    def init_typewriter(self):

        self.TextBuffer.disconnect(self.TextEditor.delete_event)
        self.TextBuffer.disconnect(self.TextEditor.insert_event)
        self.TextBuffer.disconnect(self.text_change_event)

        ci = self.TextBuffer.get_iter_at_mark(self.TextBuffer.get_mark('insert'))
        co = ci.get_offset()

        fflines = int(round((self.window_height-55)/(2*30)))
        self.fflines = fflines
        self.TextEditor.fflines = fflines

        s = '\n'*fflines

        start_iter =  self.TextBuffer.get_iter_at_offset(0)
        self.TextBuffer.insert(start_iter, s)
        
        end_iter =  self.TextBuffer.get_iter_at_offset(-1)
        self.TextBuffer.insert(end_iter, s)

        ne_ci = self.TextBuffer.get_iter_at_offset(co + fflines)
        self.TextBuffer.place_cursor(ne_ci)

        # Scroll it to the center
        self.TextEditor.scroll_to_mark(self.TextBuffer.get_mark('insert'), 0.0, True, 0.0, 0.5)

        self.TextEditor.insert_event = self.TextBuffer.connect("insert-text",self.TextEditor._on_insert)
        self.TextEditor.delete_event = self.TextBuffer.connect("delete-range",self.TextEditor._on_delete)
        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)

        self.typewriter_initiated = True

    def typewriter(self):
        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        self.TextEditor.scroll_to_iter(cursor_iter, 0.0, True, 0.0, 0.5)

    def remove_typewriter(self):
        self.TextBuffer.disconnect(self.TextEditor.delete_event)
        self.TextBuffer.disconnect(self.TextEditor.insert_event)
        self.TextBuffer.disconnect(self.text_change_event)

        startIter = self.TextBuffer.get_start_iter()
        endLineIter = startIter.copy()
        endLineIter.forward_lines(self.fflines)
        self.TextBuffer.delete(startIter, endLineIter)
        startIter = self.TextBuffer.get_end_iter()
        endLineIter = startIter.copy()
        
        # Move to line before last line
        endLineIter.backward_lines(self.fflines - 1)
        
        # Move to last char in last line
        endLineIter.backward_char()
        self.TextBuffer.delete(startIter, endLineIter)

        self.fflines = 0
        self.TextEditor.fflines = 0

        self.TextEditor.insert_event = self.TextBuffer.connect("insert-text",self.TextEditor._on_insert)
        self.TextEditor.delete_event = self.TextBuffer.connect("delete-range",self.TextEditor._on_delete)
        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)


    WORDCOUNT = re.compile(r"[\s#*\+\-]+", re.UNICODE)
    def update_line_and_char_count(self):
        if self.status_bar_visible == False:
            return

        self.char_count.set_text(str(self.TextBuffer.get_char_count() - 
                (2 * self.fflines)))

        text = self.get_text()

        words = re.split(self.WORDCOUNT, text)
        length = len(words)
        # Last word a "space"
        if len(words[-1]) == 0:
            length = length - 1
        # First word a "space" (happens in focus mode...)
        if len(words[0]) == 0:
            length = length - 1
        if length == -1: 
            length = 0
        self.word_count.set_text(str(length))

        # TODO rename line_count to word_count

    def get_text(self):
        if self.focusmode == False:
            start_iter = self.TextBuffer.get_start_iter()
            end_iter = self.TextBuffer.get_end_iter()

        else:
            start_iter = self.TextBuffer.get_iter_at_line(self.fflines)
            rbline =  self.TextBuffer.get_line_count() - self.fflines
            end_iter = self.TextBuffer.get_iter_at_line(rbline)

        return self.TextBuffer.get_text(start_iter, end_iter, False)

    def mark_set(self, buffer, location, mark, data=None):
        if self.focusmode and (mark.get_name() == 'insert' or
            mark.get_name() == 'selection_bound'):
            akt_lines = self.TextBuffer.get_line_count()
            lb = self.fflines
            rb = akt_lines - self.fflines
            #print "a %d, lb %d, rb %d" % (akt_lines, lb, rb)
            #lb = self.TextBuffer.get_iter_at_line(self.fflines)
            #rbline =  self.TextBuffer.get_line_count() - self.fflines
            #rb = self.TextBuffer.get_iter_at_line(
            #   rbline)
            #rb.backward_line()
            

            linecount = location.get_line()
            #print "a %d, lb %d, rb %d, lc %d" % (akt_lines, lb, rb, linecount)

            if linecount < lb:
                move_to_line = self.TextBuffer.get_iter_at_line(lb)
                self.TextBuffer.move_mark(mark, move_to_line)
            elif linecount >= rb:
                move_to_line = self.TextBuffer.get_iter_at_line(rb)
                move_to_line.backward_char()
                self.TextBuffer.move_mark(mark, move_to_line)

    def after_mark_set(self, buffer, location, mark, data=None):
        if self.focusmode and mark.get_name() == 'insert':
            self.typewriter()


    def delete_from_cursor(self, editor, typ, count, Data=None):
        if not self.focusmode:
            return
        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        if count < 0 and cursor_iter.starts_line():
            lb = self.fflines
            linecount = cursor_iter.get_line()
            #print "lb %d, lc %d" % (lb, linecount)
            if linecount <= lb:
                self.TextEditor.emit_stop_by_name('delete-from-cursor')
        elif count > 0 and cursor_iter.ends_line():
            akt_lines = self.TextBuffer.get_line_count()
            rb = akt_lines - self.fflines
            linecount = cursor_iter.get_line() + 1
            #print "rb %d, lc %d" % (rb, linecount)
            if linecount >= rb:
                self.TextEditor.emit_stop_by_name('delete-from-cursor')

    def backspace(self, data=None):
        if not self.focusmode:
            return

        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        if cursor_iter.starts_line():
            lb = self.fflines
            linecount = cursor_iter.get_line()
            #print "lb %d, lc %d" % (lb, linecount)

            if linecount <= lb:
                self.TextEditor.emit_stop_by_name('backspace')


    def cursor_moved(self, widget, a, b, data=None):
        pass

    def after_cursor_moved(self, widget, step, count, extend_selection, data=None):
        if self.focusmode:
            self.typewriter()

    def text_changed(self, widget, data=None):
        if self.did_change == False:
            self.did_change = True
            title = self.get_title()
            self.set_title("* " + title)

        self.MarkupBuffer.markup_buffer(1)
        self.textchange = True

        self.buffer_modified_for_status_bar = True
        self.update_line_and_char_count()

    def toggle_fullscreen(self, widget, data=None):
        if widget.get_active():
            self.fullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.add_accelerator("activate", 
            self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
        else:
            self.unfullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.remove_accelerator(
                self.accel_group, key, mod)
        self.TextEditor.grab_focus()

    def delete_text(self, widget):
        pass

    def cut_text(self, widget, data=None):
        self.TextEditor.cut()

    def paste_text(self, widget, data=None):
        self.TextEditor.paste()

    def copy_text(self, widget, data=None):
        self.TextEditor.copy()

    def undo(self, widget, data=None):
        self.TextEditor.undo()

    def redo(self, widget, data=None):
        self.TextEditor.redo()

    def set_italic(self, widget, data=None):
        """Ctrl + I"""
        self.FormatShortcuts.italic()

    def set_bold(self, widget, data=None):
        """Ctrl + B"""
        self.FormatShortcuts.bold()

    def insert_horizontal_rule(self, widget, data=None):
        """Ctrl + R"""
        self.FormatShortcuts.rule()

    def insert_unordered_list_item(self, widget, data=None):
        """Ctrl + U"""
        self.FormatShortcuts.unordered_list_item()

    def insert_ordered_list(self, widget, data=None):
        """CTRL + O"""
        self.FormatShortcuts.ordered_list_item()

    def insert_heading(self, widget, data=None):
        """CTRL + H"""
        self.FormatShortcuts.heading()

    def set_focusmode(self, widget, data=None):
        if widget.get_active():
            self.init_typewriter()
            self.MarkupBuffer.focusmode_highlight()
            self.focusmode = True
            self.TextEditor.grab_focus()
            
            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 0)
            
        else:
            self.remove_typewriter()
            self.focusmode = False
            self.TextBuffer.remove_tag(self.MarkupBuffer.grayfont, 
                self.TextBuffer.get_start_iter(),
                self.TextBuffer.get_end_iter())
            self.TextBuffer.remove_tag(self.MarkupBuffer.blackfont, 
                self.TextBuffer.get_start_iter(),
                self.TextBuffer.get_end_iter())

            self.MarkupBuffer.markup_buffer(1)
            self.TextEditor.grab_focus()
            self.update_line_and_char_count()
            
            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 4)

    def window_resize(self, widget, data=None):
        # To calc padding top / bottom
        self.window_height = widget.get_size()[1]

        # Calculate left / right margin
        lm = (widget.get_size()[0] - 600) / 2
            
        self.TextEditor.set_left_margin(lm)
        self.TextEditor.set_right_margin(lm)

        self.MarkupBuffer.recalculate(lm)

        if self.focusmode:
            self.remove_typewriter()
            self.init_typewriter()

    def window_close(self, widget, data=None):
        return True


    def save_document(self, widget, data=None):
        if self.filename:
            logger.info("saving")
            filename = self.filename

            with open(filename, "wb") as f:
                f.write(self.get_text().encode("utf-8"))

            if self.did_change:
                self.did_change = False
                title = self.get_title()
                self.set_title(title[2:])
            return Gtk.ResponseType.OK

        else:
            
            filefilter = Gtk.FileFilter.new()
            filefilter.add_mime_type('text/x-markdown')
            filefilter.add_mime_type('text/plain')
            filefilter.set_name('MarkDown (.md)')
            filechooser = Gtk.FileChooserDialog(
                _("Save your File"),
                self,
                Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
                )

            filechooser.set_do_overwrite_confirmation(True)
            filechooser.add_filter(filefilter)
            response = filechooser.run()
            if response == Gtk.ResponseType.OK:
                filename = filechooser.get_filename()
                
                if filename[-3:] != ".md":
                    filename = filename + ".md"
                    try:
                        self.recent_manager.add_item("file:/ " + filename)
                    except:
                        pass

                text = self.get_text()

                with open(filename, "wb") as f:
                    f.write(text.encode("utf-8"))
                
                self.filename = filename
                self.set_title(os.path.basename(filename) + self.title_end)
                
                self.did_change = False
                filechooser.destroy()
                return response

            elif response == Gtk.ResponseType.CANCEL:
                filechooser.destroy()
                return response
    def save_document_as(self, widget, data=None):
        filechooser = Gtk.FileChooserDialog(
            "Save your File",
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
            )
        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:

            filename = filechooser.get_filename()
            if filename[-3:] != ".md":
                filename = filename + ".md"
                try:
                    self.recent_manager.remove_item("file:/" + filename)        
                    self.recent_manager.add_item("file:/ " + filename)
                except: 
                    pass

            # Codecs have been deprecated http://bugs.python.org/issue8796
            # f = codecs.open(filename, encoding="utf-8", mode='w')
            text = self.get_text()

            # use python3 with-statement
            with open(filename, "wb") as f:
                f.write(text.encode("utf-8"))
            
            self.filename = filename
            self.set_title(os.path.basename(filename) + self.title_end)

            try:
                self.recent_manager.add_item(filename)
            except:
                pass
                
            filechooser.destroy()
            self.did_change = False

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def export(self, export_type="html"):
        filechooser = Gtk.FileChooserDialog(
            "Export as %s" % export_type.upper(),
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
            )

        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename[:-2] + export_type.lower())
        
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            if filename.endswith("." + export_type):
                filename = filename[:-len(export_type)-1]
            filechooser.destroy()
        else: 
            filechooser.destroy()
            return 

        text = self.get_text().encode("utf-8")
                
        output_dir = os.path.abspath(os.path.join(filename, os.path.pardir))
        
        basename = os.path.basename(filename)

        args = ['pandoc', '--from=markdown', '--smart']
        
        if export_type == "pdf":
            args.append("-o%s.pdf" % basename) 
        
        elif export_type == "odt":
            args.append("-o%s.odt" % basename)
        
        elif export_type == "html":
            css = helpers.get_media_file('uberwriter.css')
            args.append("-c%s" % css)
            args.append("-o%s.html" % basename)
            args.append("--mathjax")

        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=output_dir)
        output = p.communicate(text)[0]
        
        return filename
            
    def export_as_odt(self, widget, data=None):
        self.export("odt")

    def export_as_html(self, widget, data=None):
        self.export("html")

    def export_as_pdf(self, widget, data=None):
        if self.texlive_installed == False:

            debian_like = True

            try:
                import apt
            except:
                debian_like = False
                
            if debian_like :
                try:
                    cache = apt.Cache()
                    inst = cache["texlive"].is_installed
                except:
                    inst = True
            else:
                inst = False

                # replaces the apt check for non-apt distros
                fpath, fname = os.path.split('latex')
                if fpath:
                    if is_exe('latex'):
                        inst = True
                else:
                    for path in os.environ["PATH"].split(os.pathsep):
                        path = path.strip('"').strip()
                        exe_file = os.path.join(path, 'latex')
                        if os.path.isfile(exe_file) and os.access(exe_file, os.X_OK):
                            inst = True


            if inst == False:
                dialog = Gtk.MessageDialog(self,
                    Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.NONE,
                    _("You can not export to PDF.")
                )
                dialog.format_secondary_markup(_("Please install texlive from the software center."))
                response = dialog.run()
                return
            else:
                self.texlive_installed = True
        self.export("pdf")

    def copy_html_to_clipboard(self, widget, date=None):
        # TODO connect to item in Menubar, and make new pandoc template for 
        # only HTML, no headers etc.
        
        args = ['pandoc', '--from=markdown', '--smart', '-thtml']
        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        
        text = self.get_text().encode("utf-8")
        output = p.communicate(text)[0]
                
        cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        cb.set_text(output.decode("utf-8"), -1)
        cb.store()

    def open_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return

        filefilter = Gtk.FileFilter.new()
        filefilter.add_mime_type('text/x-markdown')
        filefilter.add_mime_type('text/plain')
        filefilter.set_name(_('MarkDown or Plain Text'))

        filechooser = Gtk.FileChooserDialog(
            _("Open a .md-File"),
            self,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
            )
        filechooser.add_filter(filefilter)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            self.load_file(filename)
            filechooser.destroy()

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def check_change(self):
        if self.did_change and len(self.get_text()):
            dialog = Gtk.MessageDialog(self,
                Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                Gtk.MessageType.WARNING,
                Gtk.ButtonsType.NONE, 
                _("You have not saved your changes.")
                )
            dialog.add_button(_("Close without Saving"), Gtk.ResponseType.NO)
            dialog.add_button(_("Cancel"), Gtk.ResponseType.CANCEL)
            dialog.add_button(_("Save now"), Gtk.ResponseType.YES).grab_focus()
            dialog.set_title(_('Unsaved changes'))
            dialog.set_default_size(200, 150)
            response = dialog.run()
            if response == Gtk.ResponseType.YES:
                title = self.get_title()
                if self.save_document(widget = None) == Gtk.ResponseType.CANCEL:
                    dialog.destroy()
                    return self.check_change()
                else:                    
                    dialog.destroy()
                    return response
            elif response == Gtk.ResponseType.CANCEL:
                dialog.destroy()
                return response
            elif response == Gtk.ResponseType.NO:
                dialog.destroy()
                return response

    def new_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return
        else:
            self.TextBuffer.set_text('')
            self.TextEditor.undos = []
            self.TextEditor.redos = []

            self.did_change = False
            self.filename = None
            self.set_title("New File" + self.title_end)

    def menu_activate_focusmode(self, widget):
        self.focusmode_button.emit('activate')

    def menu_activate_fullscreen(self, widget):
        self.fullscreen_button.emit('activate')

    # Not added as menu button as of now. Standard is typewriter active.
    def toggle_typewriter(self, widget, data=None):
        self.typewriter_active = widget.get_active()

    def toggle_spellcheck(self, widget, data=None):
        if self.spellcheck:
            if widget.get_active():
                self.SpellChecker.enable()
            else:
                self.SpellChecker.disable()
        elif widget.get_active(): 
            try:
                self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
                self.spellcheck = True
            except:
                self.SpellChecker = None
                self.spellcheck = False
                dialog = Gtk.MessageDialog(self,
                    Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.NONE,
                    _("You can not enable the Spell Checker.")
                )
                dialog.format_secondary_text(_("Please install 'hunspell' or 'aspell' dictionarys for your language from the software center."))
                response = dialog.run()
                return
        return

    def on_drag_data_received(self, widget, drag_context, x, y, 
                              data, info, time):
        """Handle drag and drop events"""

        if info == 1:
            # uri target
            uris = data.get_uris()
            for uri in uris:
                uri = urllib.parse.unquote_plus(uri)

                mime = mimetypes.guess_type(uri)

                if mime[0] is not None and mime[0].startswith('image'):
                    text = "![Insert image title here](%s)" % uri
                    ll = 2
                    lr = 23
                else:
                    text = "[Insert link title here](%s)" % uri
                    ll = 1
                    lr = 22

                self.TextBuffer.insert_at_cursor(text)
                insert_mark = self.TextBuffer.get_insert()
                selection_bound = self.TextBuffer.get_selection_bound()
                cursor_iter = self.TextBuffer.get_iter_at_mark(insert_mark)
                cursor_iter.backward_chars(len(text) - ll)
                self.TextBuffer.move_mark(insert_mark, cursor_iter)
                cursor_iter.forward_chars(lr)
                self.TextBuffer.move_mark(selection_bound, cursor_iter)
        
        elif info == 2:
            # Text target
            self.TextBuffer.insert_at_cursor(data.get_text())

        self.present()

    def dark_mode_toggled(self, widget, data=None):
        if widget.get_active():
            # Dark Mode is on
            # Hack for f*****g unico-shit
            if Gtk.get_minor_version() == 4:
                css = open(helpers.get_media_path('style_dark_old.css'), 'rb')
            else:
                css = open(helpers.get_media_path('style_dark.css'), 'rb')
            css_data = css.read()
            css.close()
            self.style_provider.load_from_data(css_data)
            self.background_image = helpers.get_media_path('bg_dark.png')
            self.MarkupBuffer.dark_mode(True)

        else: 
            # Dark mode off
            css = open(helpers.get_media_path('style.css'), 'rb')
            css_data = css.read()
            css.close()

            self.style_provider.load_from_data(css_data)
            self.background_image = helpers.get_media_path('bg_light.png')
            self.MarkupBuffer.dark_mode(False)

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,     
            Gtk.STYLE_PROVIDER_PRIORITY_USER
        )
        (w, h) = self.get_size()
        self.resize(w+1, h+1)

    def load_file(self, filename = None):
        """Open File from command line"""
        if filename:
            if filename.startswith('file://'):
                filename = filename[7:]

            filename = urllib.parse.unquote_plus(filename)

            self.filename = filename
            try:                

                with open(filename, mode='r', encoding='utf-8') as f:
                    self.TextBuffer.set_text(f.read())

                self.MarkupBuffer.markup_buffer(0)
                self.set_title(os.path.basename(filename) + self.title_end)
                self.TextEditor.undos = []
                self.TextEditor.redos = []
            
            except Exception as e:
                logger.warning("Error Reading File")
                logger.warning(e)

            self.did_change = False
        else:
            logger.warning("No File arg")


    def draw_bg(self, widget, context):
        context.set_source(self.background_pattern)
        context.paint()

    def open_launchpad_translation(self, widget, data = None):
        webbrowser.open("https://translations.launchpad.net/uberwriter")

    def open_launchpad_help(self, widget, data = None):
        webbrowser.open("https://answers.launchpad.net/uberwriter")

    def open_advanced_export(self, widget, data=None):
        if self.UberwriterAdvancedExportDialog is not None:
            advexp = self.UberwriterAdvancedExportDialog() # pylint: disable=

            response = advexp.run()
            if response == 1:
                advexp.advanced_export(self.get_text())

            advexp.destroy()

    def open_recent(self, widget, data=None):
        if data:
            logger.info("Filename: %s" % data)
            if self.check_change() == Gtk.ResponseType.CANCEL:
                return
            else:
                self.load_file(data)

    def generate_recent_files_menu(self, parent_menu):
        # Recent file filter
        self.recent_manager = Gtk.RecentManager.get_default()

        self.recent_files_menu = Gtk.RecentChooserMenu.new_for_manager(self.recent_manager)
        self.recent_files_menu.set_sort_type(Gtk.RecentSortType.MRU)
        
        recent_filter = Gtk.RecentFilter.new()
        recent_filter.add_mime_type('text/x-markdown')
        self.recent_files_menu.set_filter(recent_filter)
        menu = Gtk.Menu.new()

        for entry in self.recent_files_menu.get_items():
            if entry.exists():
                item = Gtk.MenuItem.new_with_label(entry.get_display_name())
                item.connect('activate', self.open_recent, entry.get_uri())
                menu.append(item)
                item.show()

        menu.show()
        parent_menu.set_submenu(menu)
        parent_menu.show()        

    def poll_for_motion(self):
        if (self.was_motion == False
                and self.status_bar_visible 
                and self.buffer_modified_for_status_bar):
            self.status_bar.set_state_flags(Gtk.StateFlags.INSENSITIVE, True)
            self.status_bar_visible = False
            self.buffer_modified_for_status_bar = False
            return False

        self.was_motion = False
        return True

    def on_motion_notify(self, widget, data=None):
        self.was_motion = True
        if self.status_bar_visible == False:
            self.status_bar_visible = True
            self.buffer_modified_for_status_bar = False
            self.update_line_and_char_count()
            self.status_bar.set_state_flags(Gtk.StateFlags.NORMAL, True)
            GObject.timeout_add(3000, self.poll_for_motion)

    def populate_popup(self, editor, menu,  data=None):
        return
        item = Gtk.MenuItem.new()
        image = Gtk.Image.new_from_file('/home/wolf/test.jpg')
        image.show()
        item.add(image)
        item.show()
        logger.info("%s %s" % (menu, item)) 
        menu.prepend(item)
        menu.show()

    def move_popup(self, widget, data=None):
        pass
        
    def finish_initializing(self, builder): # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog

        # Code for other initialization actions should be added here.
        
        # Texlive checker

        self.texlive_installed = False

        # Draw background
        self.background_image = helpers.get_media_path('bg_light.png')
        self.connect('draw', self.draw_bg)

        self.set_name('UberwriterWindow')

        self.title_end = "  –  UberWriter"
        self.set_title("New File" + self.title_end)

        # Drag and drop
        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        
        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.drag_dest_set_target_list(self.target_list)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')

        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        

        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)


        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # p = "~/.uberwriter/"
        #p = os.path.expanduser(p)
        #self.temp_dir = p     
        #if not os.path.exists(p):
        #    os.makedirs(p)

        # Setting up light background

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)


        self.TextEditor = TextEditor()

        base_leftmargin = 100
        self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)

        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)

        self.TextEditor.show()

        self.ScrolledWindow = builder.get_object('scrolledwindow1')

        self.ScrolledWindow.add(self.TextEditor)

        pangoFont = Pango.FontDescription("Ubuntu Mono 15px")

        self.TextEditor.modify_font(pangoFont)

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(5)
        self.TextEditor.set_pixels_below_lines(5)
        self.TextEditor.set_pixels_inside_wrap(10)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)


        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding

        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)
        
        self.TextEditor.connect('move-cursor', self.cursor_moved)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()

        css = open(helpers.get_media_path('style.css'), 'r')
        css_data = css.read()
        css.close()

        self.style_provider.load_from_data(css_data.encode("utf-8"))

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,     
            Gtk.STYLE_PROVIDER_PRIORITY_USER
        )


        # Still needed.
        self.fflines = 0

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer, base_leftmargin)
        self.MarkupBuffer.markup_buffer()
        self.FormatShortcuts = FormatShortcuts(self.TextBuffer, self.TextEditor)

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0

        self.TextBuffer.connect('mark-set', self.mark_set)
        
        self.TextEditor.drag_dest_unset()

        # Events to preserve margin. (To be deleted.)
        self.TextEditor.connect('delete-from-cursor', self.delete_from_cursor)
        self.TextEditor.connect('backspace', self.backspace)

        self.TextBuffer.connect('paste-done', self.paste_done)


        # Events for Typewriter mode
        self.TextBuffer.connect_after('mark-set', self.after_mark_set)
        self.TextBuffer.connect_after('changed', self.after_modify_text)
        self.TextEditor.connect_after('move-cursor', self.after_cursor_moved)
        self.TextEditor.connect_after('insert-at-cursor', self.after_insert_at_cursor)
        
        # Events for popup menu
        self.TextEditor.connect_after('populate-popup', self.populate_popup)
        self.TextEditor.connect_after('popup-menu', self.move_popup)


        # Vertical scrolling
        self.vadjustment = self.TextEditor.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)


        # Open file from commandline

        self.did_change = False


        # Window resize
        self.connect("configure-event", self.window_resize)

        # Window destroyed??
        self.connect("delete-event", self.on_delete_called)
    
    def on_delete_called(self, widget, data=None):
        """Called when the TexteditorWindow is closed.""" 
        logger.info('delete called')       
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return True
        return False
 
    def on_destroy(self, widget, data=None):
        """Called when the TexteditorWindow is closed."""
        # Clean up code for saving application state should be added here.
        self.window_close(widget)        
        Gtk.main_quit()
示例#15
0
class UpdateWindow(UpdateWidgetBase):
    def __init__(self, liststore, entry=None, source=None, account=None):
        self.entry = entry
        self.child = None  # for GtkGrid.get_child_at no available

        gui = Gtk.Builder()
        gui.add_from_file(SHARED_DATA_FILE('update.glade'))
        self.media = MediaFile(gui)
        self.config = AuthorizedTwitterAccount.CONFIG

        host_re = '//[A-Za-z0-9\'~+\-=_.,/%\?!;:@#\*&\(\)]+'
        self.http_re = re.compile("(http:%s)" % host_re)
        self.https_re = re.compile("(https:%s)" % host_re)
        self.screen_name_pattern = re.compile('\B@[0-9A-Za-z_]{1,15}')

        self.account_combobox = AccountCombobox(gui, liststore, source,
                                                account)

        is_above = SETTINGS.get_boolean('update-window-keep-above')
        self.update_window = gui.get_object('window1')
        self.update_window.set_keep_above(is_above)

        self.button_image = gui.get_object('button_image')

        self.label_num = gui.get_object('label_num')
        self.comboboxtext_privacy = FacebookPrivacyCombobox(gui)
        self.grid_button = gui.get_object('grid_button')
        self.on_combobox_account_changed()

        self.button_tweet = gui.get_object('button_tweet')
        self.text_buffer = gui.get_object('textbuffer')
        self.on_textbuffer_changed(self.text_buffer)

        textview = gui.get_object('textview')

        if SpellChecker:
            self.spellchecker = SpellChecker(textview)
            if not SETTINGS.get_boolean('spell-checker'):
                self.spellchecker.disable()

        gui.connect_signals(self)

        if entry:
            widget = 'buttonbox1' if entry.get('protected') else 'image_secret'
            gui.get_object(widget).hide()
            self._download_user_icon_with_callback(gui, entry)
        else:
            gui.get_object('grid_entry').destroy()
            self.update_window.present()

    def _run(self, unknown, gui, entry, icon, *args):
        self._set_ui(gui, entry, icon)

        user = entry['user_name']
        self.update_window.set_title(_('Reply to %s') % user.decode('utf-8'))
        self.text_buffer.set_text(self._get_all_mentions_from(entry))

        self.update_window.present()

    def _get_all_mentions_from(self, entry):
        account_user = '******' + self.account_combobox.get_account_obj().user_name
        users = '@%s ' % entry['user_name']

        matches = self.screen_name_pattern.finditer(entry['status_body'])
        other_users = ' '.join(
            [x.group() for x in matches if x.group() != account_user])
        if other_users:
            users += other_users + ' '

        return users

    def set_upload_media(self, file):
        self.media.set(file)
        self.on_textbuffer_changed(self.text_buffer)

    def on_textview_populate_popup(self, textview, default_menu):
        if not SpellChecker:
            return

        menuitem = Gtk.CheckMenuItem.new_with_mnemonic(_('Check _Spelling'))
        menuitem.connect("toggled", self._toggle)

        is_enbled = SETTINGS.get_boolean('spell-checker')
        menuitem.set_active(is_enbled)

        if not menuitem.get_active():
            separator = Gtk.SeparatorMenuItem.new()
            default_menu.prepend(separator)

        default_menu.prepend(menuitem)
        default_menu.show_all()

    def _toggle(self, menuitem):
        state = menuitem.get_active()
        SETTINGS.set_boolean('spell-checker', state)
        if state:
            self.spellchecker.enable()
        else:
            self.spellchecker.disable()

    def on_button_tweet_clicked(self, button):
        start, end = self.text_buffer.get_bounds()
        status = self.text_buffer.get_text(start, end, False).decode('utf-8')

        account_obj = self.account_combobox.get_account_obj()
        account_source = self.account_combobox.get_account_source()

        params = {'in_reply_to_status_id': self.entry.get('id')} \
            if self.entry else {}

        if account_source == 'Facebook':
            params = self.comboboxtext_privacy.get_params()

        if self.media.file:  # update with media
            is_shrink = True
            size = 1024

            upload_file = self.media.get_upload_file_obj(is_shrink, size)
            account_obj.api.update_with_media(status.encode('utf-8'),
                                              upload_file.name,
                                              params=params)

        else:  # normal update
            account_obj.api.update(status, params=params)

        if not self.entry:
            num = self.account_combobox.combobox_account.get_active()
            SETTINGS.set_int('recent-account', num)

        self.update_window.destroy()

    def on_button_image_clicked(self, button):
        dialog = FileChooserDialog()
        file = dialog.run(self.update_window)
        self.set_upload_media(file)

    def on_eventbox_attached_press_event(self, image_menu, event):
        if event.button == 3:
            image_menu.popup(None, None, None, None, event.button, event.time)

    def on_menuitem_remove_activate(self, menuitem):
        self.media.clear()
        self.on_textbuffer_changed(self.text_buffer)

    def on_file_activated(self, *args):
        print args

    def on_combobox_account_changed(self, *args):
        source = self.account_combobox.get_account_source()

        self.button_image.set_sensitive(source == 'Twitter')

        widget = self.label_num if source == 'Twitter' \
            else self.comboboxtext_privacy.widget if source == 'Facebook' \
            else None

        if self.child:  # for GtkGrid.get_child_at no available
            self.grid_button.remove(self.child)
        if widget:
            self.grid_button.attach(widget, 0, 0, 1, 1)
        self.child = widget

    def on_textbuffer_changed(self, text_buffer):
        start, end = self.text_buffer.get_bounds()

        status = self.text_buffer.get_text(start, end, False).decode('utf-8')
        status = self.http_re.sub("*" * self.config.short_url_length, status)
        status = self.https_re.sub("*" * self.config.short_url_length_https,
                                   status)

        num = 140 - len(status) - self.media.get_link_letters()

        color = 'red' if num <= 10 else 'black'
        text = '<span fgcolor="%s">%s</span>' % (color, str(num))
        self.label_num.set_markup(text)

        status = bool(0 <= num < 140)
        self.button_tweet.set_sensitive(status)

    def on_textview_key_press_event(self, textview, event):
        key = event.keyval
        masks = event.state.value_names

        if key == Gdk.KEY_Return and 'GDK_CONTROL_MASK' in masks:
            if self.button_tweet.get_sensitive():
                self.on_button_tweet_clicked(None)
        else:
            return False

        return True

    def on_button_link_clicked(self, textbuffer):
        text = ' https://twitter.com/%s/status/%s' % (self.entry['user_name'],
                                                      self.entry['id'])
        textbuffer.place_cursor(textbuffer.get_end_iter())
        textbuffer.insert_at_cursor(text)

    def on_button_quote_clicked(self, textbuffer):
        quote_format = SETTINGS_TWITTER.get_string('quote-format')
        text = quote_format.format(user=self.entry.get('user_name'),
                                   status=self.entry.get('status_body'))

        textbuffer.delete(
            textbuffer.get_start_iter(),
            textbuffer.get_end_iter(),
        )
        textbuffer.insert_at_cursor(text)
        textbuffer.place_cursor(textbuffer.get_start_iter())
class UberwriterWindow(Window):

    __gtype_name__ = "UberwriterWindow"

    def scrolled(self, widget):
        """if window scrolled + focusmode make font black again"""
#         if self.focusmode:
#            if self.textchange == False:
#                if self.scroll_count >= 1:
#                    self.TextBuffer.apply_tag(
#                        self.MarkupBuffer.blackfont, 
#                        self.TextBuffer.get_start_iter(), 
#                        self.TextBuffer.get_end_iter())
#                else:
#                    self.scroll_count += 1
#            else: 
#                self.scroll_count = 0
#                self.typewriter()
#                self.textchange = False

    def after_modify_text(self, *arg):
        if self.focusmode:
            self.typewriter()

    def after_insert_at_cursor(self, *arg):
        if self.focusmode:
            self.typewriter()

    def paste_done(self, *args):
        self.MarkupBuffer.markup_buffer(0)

    def init_typewriter(self):

        self.TextBuffer.disconnect(self.TextEditor.delete_event)
        self.TextBuffer.disconnect(self.TextEditor.insert_event)
        self.TextBuffer.disconnect(self.text_change_event)

        ci = self.TextBuffer.get_iter_at_mark(self.TextBuffer.get_mark('insert'))
        co = ci.get_offset()

        fflines = int(round((self.window_height-55)/(2*30)))
        self.fflines = fflines
        self.TextEditor.fflines = fflines

        s = '\n'*fflines

        start_iter =  self.TextBuffer.get_iter_at_offset(0)
        self.TextBuffer.insert(start_iter, s)
        
        end_iter =  self.TextBuffer.get_iter_at_offset(-1)
        self.TextBuffer.insert(end_iter, s)

        ne_ci = self.TextBuffer.get_iter_at_offset(co + fflines)
        self.TextBuffer.place_cursor(ne_ci)

        # Scroll it to the center
        self.TextEditor.scroll_to_mark(self.TextBuffer.get_mark('insert'), 0.0, True, 0.0, 0.5)

        self.TextEditor.insert_event = self.TextBuffer.connect("insert-text",self.TextEditor._on_insert)
        self.TextEditor.delete_event = self.TextBuffer.connect("delete-range",self.TextEditor._on_delete)
        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)

        self.typewriter_initiated = True

    def typewriter(self):
        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        self.TextEditor.scroll_to_iter(cursor_iter, 0.0, True, 0.0, 0.5)

    def remove_typewriter(self):
        self.TextBuffer.disconnect(self.TextEditor.delete_event)
        self.TextBuffer.disconnect(self.TextEditor.insert_event)
        self.TextBuffer.disconnect(self.text_change_event)

        startIter = self.TextBuffer.get_start_iter()
        endLineIter = startIter.copy()
        endLineIter.forward_lines(self.fflines)
        self.TextBuffer.delete(startIter, endLineIter)
        startIter = self.TextBuffer.get_end_iter()
        endLineIter = startIter.copy()
        
        # Move to line before last line
        endLineIter.backward_lines(self.fflines - 1)
        
        # Move to last char in last line
        endLineIter.backward_char()
        self.TextBuffer.delete(startIter, endLineIter)

        self.fflines = 0
        self.TextEditor.fflines = 0

        self.TextEditor.insert_event = self.TextBuffer.connect("insert-text",self.TextEditor._on_insert)
        self.TextEditor.delete_event = self.TextBuffer.connect("delete-range",self.TextEditor._on_delete)
        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)


    WORDCOUNT = re.compile(r"[\s#*\+\-]+", re.UNICODE)
    def update_line_and_char_count(self):
        if self.status_bar_visible == False:
            return

        self.char_count.set_text(str(self.TextBuffer.get_char_count() - 
                (2 * self.fflines)))

        text = self.get_text()
        words = re.split(self.WORDCOUNT, text)
        length = len(words)
        # Last word a "space"
        if len(words[-1]) == 0:
            length = length - 1
        # First word a "space" (happens in focus mode...)
        if len(words[0]) == 0:
            length = length - 1
        if length == -1: 
            length = 0
        self.word_count.set_text(str(length))

        # TODO rename line_count to word_count

    def get_text(self):
        if self.focusmode == False:
            start_iter = self.TextBuffer.get_start_iter()
            end_iter = self.TextBuffer.get_end_iter()

        else:
            start_iter = self.TextBuffer.get_iter_at_line(self.fflines)
            rbline =  self.TextBuffer.get_line_count() - self.fflines
            end_iter = self.TextBuffer.get_iter_at_line(rbline)

        return self.TextBuffer.get_text(start_iter, end_iter, False)

    def mark_set(self, buffer, location, mark, data=None):
        if self.focusmode and (mark.get_name() == 'insert' or
            mark.get_name() == 'selection_bound'):
            akt_lines = self.TextBuffer.get_line_count()
            lb = self.fflines
            rb = akt_lines - self.fflines
            #print "a %d, lb %d, rb %d" % (akt_lines, lb, rb)
            #lb = self.TextBuffer.get_iter_at_line(self.fflines)
            #rbline =  self.TextBuffer.get_line_count() - self.fflines
            #rb = self.TextBuffer.get_iter_at_line(
            #   rbline)
            #rb.backward_line()
            

            linecount = location.get_line()
            #print "a %d, lb %d, rb %d, lc %d" % (akt_lines, lb, rb, linecount)

            if linecount < lb:
                move_to_line = self.TextBuffer.get_iter_at_line(lb)
                self.TextBuffer.move_mark(mark, move_to_line)
            elif linecount >= rb:
                move_to_line = self.TextBuffer.get_iter_at_line(rb)
                move_to_line.backward_char()
                self.TextBuffer.move_mark(mark, move_to_line)

    def after_mark_set(self, buffer, location, mark, data=None):
        if self.focusmode and mark.get_name() == 'insert':
            self.typewriter()


    def delete_from_cursor(self, editor, typ, count, Data=None):
        if not self.focusmode:
            return
        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        if count < 0 and cursor_iter.starts_line():
            lb = self.fflines
            linecount = cursor_iter.get_line()
            #print "lb %d, lc %d" % (lb, linecount)
            if linecount <= lb:
                self.TextEditor.emit_stop_by_name('delete-from-cursor')
        elif count > 0 and cursor_iter.ends_line():
            akt_lines = self.TextBuffer.get_line_count()
            rb = akt_lines - self.fflines
            linecount = cursor_iter.get_line() + 1
            #print "rb %d, lc %d" % (rb, linecount)
            if linecount >= rb:
                self.TextEditor.emit_stop_by_name('delete-from-cursor')

    def backspace(self, data=None):
        if not self.focusmode:
            return

        cursor = self.TextBuffer.get_mark("insert")
        cursor_iter = self.TextBuffer.get_iter_at_mark(cursor)
        if cursor_iter.starts_line():
            lb = self.fflines
            linecount = cursor_iter.get_line()
            #print "lb %d, lc %d" % (lb, linecount)

            if linecount <= lb:
                self.TextEditor.emit_stop_by_name('backspace')


    def cursor_moved(self, widget, a, b, data=None):
        pass

    def after_cursor_moved(self, widget, step, count, extend_selection, data=None):
        if self.focusmode:
            self.typewriter()

    def text_changed(self, widget, data=None):
        if self.did_change == False:
            self.did_change = True
            title = self.get_title()
            self.set_title("* " + title)

        self.MarkupBuffer.markup_buffer(1)
        self.textchange = True

        self.buffer_modified_for_status_bar = True
        self.update_line_and_char_count()

    def toggle_fullscreen(self, widget, data=None):
        if widget.get_active():
            self.fullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.add_accelerator("activate", 
            self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
            
            # Hide Menu
            self.menubar.hide()

        else:
            self.unfullscreen()
            key, mod = Gtk.accelerator_parse("Escape")
            self.fullscreen_button.remove_accelerator(
                self.accel_group, key, mod)
            self.menubar.show()

        self.TextEditor.grab_focus()

    def delete_text(self, widget):
        pass

    def cut_text(self, widget, data=None):
        self.TextEditor.cut()

    def paste_text(self, widget, data=None):
        self.TextEditor.paste()

    def copy_text(self, widget, data=None):
        self.TextEditor.copy()

    def undo(self, widget, data=None):
        self.TextEditor.undo()

    def redo(self, widget, data=None):
        self.TextEditor.redo()

    def set_italic(self, widget, data=None):
        """Ctrl + I"""
        self.FormatShortcuts.italic()

    def set_bold(self, widget, data=None):
        """Ctrl + B"""
        self.FormatShortcuts.bold()

    def insert_horizontal_rule(self, widget, data=None):
        """Ctrl + R"""
        self.FormatShortcuts.rule()

    def insert_unordered_list_item(self, widget, data=None):
        """Ctrl + U"""
        self.FormatShortcuts.unordered_list_item()

    def insert_ordered_list(self, widget, data=None):
        """CTRL + O"""
        self.FormatShortcuts.ordered_list_item()

    def insert_heading(self, widget, data=None):
        """CTRL + H"""
        self.FormatShortcuts.heading()

    def set_focusmode(self, widget, data=None):
        if widget.get_active():
            self.init_typewriter()
            self.MarkupBuffer.focusmode_highlight()
            self.focusmode = True
            self.TextEditor.grab_focus()
            
            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 0)
            
        else:
            self.remove_typewriter()
            self.focusmode = False
            self.TextBuffer.remove_tag(self.MarkupBuffer.grayfont, 
                self.TextBuffer.get_start_iter(),
                self.TextBuffer.get_end_iter())
            self.TextBuffer.remove_tag(self.MarkupBuffer.blackfont, 
                self.TextBuffer.get_start_iter(),
                self.TextBuffer.get_end_iter())

            self.MarkupBuffer.markup_buffer(1)
            self.TextEditor.grab_focus()
            self.update_line_and_char_count()
            
            if self.spellcheck != False:
                self.SpellChecker._misspelled.set_property('underline', 4)

    def window_resize(self, widget, data=None):
        # To calc padding top / bottom
        self.window_height = widget.get_size()[1]

        # Calculate left / right margin
        lm = (widget.get_size()[0] - 1050) / 2
            
        self.TextEditor.set_left_margin(lm)
        self.TextEditor.set_right_margin(lm)

        self.MarkupBuffer.recalculate(lm)

        if self.focusmode:
            self.remove_typewriter()
            self.init_typewriter()

    def window_close(self, widget, data=None):
        return True


    def save_document(self, widget, data=None):
        if self.filename:
            logger.info("saving")
            filename = self.filename
            f = codecs.open(filename, encoding="utf-8", mode='w')
            f.write(self.get_text())
            f.close()
            if self.did_change:
                self.did_change = False
                title = self.get_title()
                self.set_title(title[2:])
            return Gtk.ResponseType.OK

        else:
            
            filefilter = Gtk.FileFilter.new()
            filefilter.add_mime_type('text/x-markdown')
            filefilter.add_mime_type('text/plain')
            filefilter.set_name('MarkDown (.md)')
            filechooser = Gtk.FileChooserDialog(
                _("Save your File"),
                self,
                Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
                )

            filechooser.set_do_overwrite_confirmation(True)
            filechooser.add_filter(filefilter)
            response = filechooser.run()
            if response == Gtk.ResponseType.OK:
                filename = filechooser.get_filename()
                
                if filename[-3:] != ".md":
                    filename = filename + ".md"
                    try:
                        self.recent_manager.add_item("file:/ " + filename)
                    except:
                        pass

                f = codecs.open(filename, encoding="utf-8", mode='w')

                f.write(self.get_text())
                f.close()
                
                self.filename = filename
                self.set_title(os.path.basename(filename) + self.title_end)
                
                self.did_change = False
                filechooser.destroy()
                return response

            elif response == Gtk.ResponseType.CANCEL:
                filechooser.destroy()
                return response

    def save_document_as(self, widget, data=None):
        filechooser = Gtk.FileChooserDialog(
            "Save your File",
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
            )
        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:

            filename = filechooser.get_filename()
            if filename[-3:] != ".md":
                filename = filename + ".md"
                try:
                    self.recent_manager.remove_item("file:/" + filename)        
                    self.recent_manager.add_item("file:/ " + filename)
                except: 
                    pass

            f = codecs.open(filename, encoding="utf-8", mode='w')
            f.write(self.get_text())
            f.close()
            
            self.filename = filename
            self.set_title(os.path.basename(filename) + self.title_end)

            try:
                self.recent_manager.add_item(filename)
            except:
                pass
                
            filechooser.destroy()
            self.did_change = False

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def export(self, export_type="html"):
        filechooser = Gtk.FileChooserDialog(
            "Export as %s" % export_type.upper(),
            self,
            Gtk.FileChooserAction.SAVE,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK)
            )

        filechooser.set_do_overwrite_confirmation(True)
        if self.filename:
            filechooser.set_filename(self.filename[:-2] + export_type.lower())
        
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            if filename.endswith("." + export_type):
                filename = filename[:-len(export_type)-1]
            filechooser.destroy()
        else: 
            filechooser.destroy()
            return 

        # Converting text to bytes for python 3
        text = bytes(self.get_text(), "utf-8")

        output_dir = os.path.abspath(os.path.join(filename, os.path.pardir))
        
        basename = os.path.basename(filename)

        args = ['pandoc', '--from=markdown', '--smart']
        
        if export_type == "pdf":
            args.append("-o%s.pdf" % basename) 
        
        elif export_type == "odt":
            args.append("-o%s.odt" % basename)
        
        elif export_type == "html":
            css = helpers.get_media_file('uberwriter.css')
            args.append("-c%s" % css)
            args.append("-o%s.html" % basename)
            args.append("--mathjax")

        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, cwd=output_dir)
        output = p.communicate(text)[0]
        
        return filename
            
    def export_as_odt(self, widget, data=None):
        self.export("odt")

    def export_as_html(self, widget, data=None):
        self.export("html")

    def export_as_pdf(self, widget, data=None):
        if self.texlive_installed == False and APT_ENABLED:
            try:
                cache = apt.Cache()
                inst = cache["texlive"].is_installed
            except:
                inst = True

            if inst == False:
                dialog = Gtk.MessageDialog(self,
                    Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    None, 
                    _("You can not export to PDF.")
                )
                dialog.format_secondary_markup(_("Please install <a href=\"apt:texlive\">texlive</a> from the software center."))
                response = dialog.run()
                return
            else:
                self.texlive_installed = True
        self.export("pdf")

    def copy_html_to_clipboard(self, widget, date=None):
        """Copies only html without headers etc. to Clipboard"""

        args = ['pandoc', '--from=markdown', '--smart', '-thtml']
        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

        text = bytes(self.get_text(), "utf-8")
        output = p.communicate(text)[0]
                
        cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
        cb.set_text(output.decode("utf-8"), -1)
        cb.store()

    def open_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return

        filefilter = Gtk.FileFilter.new()
        filefilter.add_mime_type('text/x-markdown')
        filefilter.add_mime_type('text/plain')
        filefilter.set_name(_('MarkDown or Plain Text'))

        filechooser = Gtk.FileChooserDialog(
            _("Open a .md-File"),
            self,
            Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OPEN, Gtk.ResponseType.OK)
            )
        filechooser.add_filter(filefilter)
        response = filechooser.run()
        if response == Gtk.ResponseType.OK:
            filename = filechooser.get_filename()
            self.load_file(filename)
            filechooser.destroy()

        elif response == Gtk.ResponseType.CANCEL:
            filechooser.destroy()

    def check_change(self):
        if self.did_change and len(self.get_text()):
            dialog = Gtk.MessageDialog(self,
                Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                Gtk.MessageType.WARNING,
                None, 
                _("You have not saved your changes.")
                )
            dialog.add_button(_("Close without Saving"), Gtk.ResponseType.NO)
            dialog.add_button(_("Cancel"), Gtk.ResponseType.CANCEL)
            dialog.add_button(_("Save now"), Gtk.ResponseType.YES).grab_focus()
            dialog.set_title(_('Unsaved changes'))
            dialog.set_default_size(200, 150)
            response = dialog.run()
            if response == Gtk.ResponseType.YES:
                title = self.get_title()
                if self.save_document(widget = None) == Gtk.ResponseType.CANCEL:
                    dialog.destroy()
                    return self.check_change()
                else:                    
                    dialog.destroy()
                    return response
            elif response == Gtk.ResponseType.CANCEL:
                dialog.destroy()
                return response
            elif response == Gtk.ResponseType.NO:
                dialog.destroy()
                return response

    def new_document(self, widget):
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return
        else:
            self.TextBuffer.set_text('')
            self.TextEditor.undos = []
            self.TextEditor.redos = []

            self.did_change = False
            self.filename = None
            self.set_title("New File" + self.title_end)

    def menu_activate_focusmode(self, widget):
        self.focusmode_button.emit('activate')

    def menu_activate_fullscreen(self, widget):
        self.fullscreen_button.emit('activate')

    def menu_activate_preview(self, widget):
        self.preview_button.emit('activate')

    # Not added as menu button as of now. Standard is typewriter active.
    def toggle_typewriter(self, widget, data=None):
        self.typewriter_active = widget.get_active()

    def toggle_spellcheck(self, widget, data=None):
        if self.spellcheck:
            if widget.get_active():
                self.SpellChecker.enable()
            else:
                self.SpellChecker.disable()
        elif widget.get_active(): 
            try:
                self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
                self.spellcheck = True
            except:
                self.SpellChecker = None
                self.spellcheck = False
                dialog = Gtk.MessageDialog(self,
                    Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
                    Gtk.MessageType.INFO,
                    None, 
                    _("You can not enable the Spell Checker.")
                )
                dialog.format_secondary_text(_("Please install 'hunspell' or 'aspell' dictionarys for your language from the software center."))
                response = dialog.run()
                return
        return

    def on_drag_data_received(self, widget, drag_context, x, y, 
                              data, info, time):
        """Handle drag and drop events"""

        if info == 1:
            # uri target
            uris = data.get_uris()
            for uri in uris:
                uri = urllib.parse.unquote_plus(uri)
                mime = mimetypes.guess_type(uri)

                if mime[0] is not None and mime[0].startswith('image'):
                    text = "![Insert image title here](%s)" % uri
                    ll = 2
                    lr = 23
                else:
                    text = "[Insert link title here](%s)" % uri
                    ll = 1
                    lr = 22

                self.TextBuffer.insert_at_cursor(text)
                insert_mark = self.TextBuffer.get_insert()
                selection_bound = self.TextBuffer.get_selection_bound()
                cursor_iter = self.TextBuffer.get_iter_at_mark(insert_mark)
                cursor_iter.backward_chars(len(text) - ll)
                self.TextBuffer.move_mark(insert_mark, cursor_iter)
                cursor_iter.forward_chars(lr)
                self.TextBuffer.move_mark(selection_bound, cursor_iter)
        
        elif info == 2:
            # Text target
            self.TextBuffer.insert_at_cursor(data.get_text())

        self.present()

    def toggle_preview(self, widget, data=None):
        if widget.get_active():
            # Insert a tag with ID to scroll to
            self.TextBuffer.insert_at_cursor('<span id="scroll_mark"></span>')

            args = ['pandoc', 
                    '--from=markdown', 
                    '--smart', 
                    '-thtml', 
                    '--mathjax', 
                    '-c', helpers.get_media_file('uberwriter.css')]
            
            p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
            
            text = bytes(self.get_text(), "utf-8")
            output = p.communicate(text)[0]

            # Load in Webview and scroll to #ID
            self.webview = WebKit.WebView()
            self.webview.load_html_string(output.decode("utf-8"), 'file://localhost/' + '#scroll_mark')

            # Delete the cursor-scroll mark again
            cursor_iter = self.TextBuffer.get_iter_at_mark(self.TextBuffer.get_insert())
            begin_del = cursor_iter.copy()
            begin_del.backward_chars(30)
            self.TextBuffer.delete(begin_del, cursor_iter)

            self.ScrolledWindow.remove(self.TextEditor)
            self.ScrolledWindow.add(self.webview)
            self.webview.show()

            # Making the background white

            white_background = helpers.get_media_path('white.png')
            surface = cairo.ImageSurface.create_from_png(white_background)
            self.background_pattern = cairo.SurfacePattern(surface)
            self.background_pattern.set_extend(cairo.EXTEND_REPEAT)
            # This saying that all links will be opened in default browser, but local files are opened in appropriate apps:
            
            self.webview.connect("navigation-requested", self.on_click_link)
        else:
            self.ScrolledWindow.remove(self.webview)
            self.webview.destroy()
            self.ScrolledWindow.add(self.TextEditor)
            self.TextEditor.show()
            surface = cairo.ImageSurface.create_from_png(self.background_image)            
            self.background_pattern = cairo.SurfacePattern(surface)
            self.background_pattern.set_extend(cairo.EXTEND_REPEAT)
        self.queue_draw()

    def on_click_link(self, view, frame, req, data=None):
        # This provide ability for self.webview to open links in default browser
        webbrowser.open(req.get_uri())
        return True # that string is god-damn-important: without it link will be opened in default browser AND also in self.webview

    def dark_mode_toggled(self, widget, data=None):
        # Save state for saving settings later
        self.dark_mode = widget.get_active()
        if self.dark_mode:
            # Dark Mode is on
            css = open(helpers.get_media_path('style_dark.css'), 'rb')
            css_data = css.read()
            css.close()
            self.style_provider.load_from_data(css_data)
            self.background_image = helpers.get_media_path('bg_dark.png')
            self.MarkupBuffer.dark_mode(True)

        else: 
            # Dark mode off
            css = open(helpers.get_media_path('style.css'), 'rb')
            css_data = css.read()
            css.close()
            self.style_provider.load_from_data(css_data)
            self.background_image = helpers.get_media_path('bg_light.png')
            self.MarkupBuffer.dark_mode(False)

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,     
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )
        # Redraw contents of window (self)
        self.queue_draw()

    def load_file(self, filename = None):
        """Open File from command line or open / open recent etc."""
        if filename:
            if filename.startswith('file://'):
                filename = filename[7:]
            filename = urllib.parse.unquote_plus(filename)
            try:
                self.preview_button.set_active(False)
                self.filename = filename
                f = codecs.open(filename, encoding="utf-8", mode='r')
                self.TextBuffer.set_text(f.read())
                f.close()
                self.MarkupBuffer.markup_buffer(0)
                self.set_title(os.path.basename(filename) + self.title_end)
                self.TextEditor.undos = []
                self.TextEditor.redos = []
            
            except Exception as e:
                logger.warning("Error Reading File: %r" % e)
            self.did_change = False
        else:
            logger.warning("No File arg")

    def draw_bg(self, widget, context):
        context.set_source(self.background_pattern)
        context.paint()

    # Help Menu
    def open_launchpad_translation(self, widget, data = None):
        webbrowser.open("https://translations.launchpad.net/uberwriter")

    def open_launchpad_help(self, widget, data = None):
        webbrowser.open("https://answers.launchpad.net/uberwriter")

    def open_pandoc_markdown(self, widget, data=None):
        webbrowser.open("http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown")

    def open_uberwriter_markdown(self, widget, data=None):
        self.load_file(helpers.get_media_file('uberwriter_markdown.md'))

    def open_advanced_export(self, widget, data=None):
        if self.UberwriterAdvancedExportDialog is not None:
            advexp = self.UberwriterAdvancedExportDialog() # pylint: disable=

            response = advexp.run()
            if response == 1:
                advexp.advanced_export(bytes(self.get_text(), "utf-8"))

            advexp.destroy()

    def open_recent(self, widget, data=None):
        if data:
            if self.check_change() == Gtk.ResponseType.CANCEL:
                return
            else:
                self.load_file(data)

    def generate_recent_files_menu(self, parent_menu):
        # Recent file filter
        self.recent_manager = Gtk.RecentManager.get_default()

        self.recent_files_menu = Gtk.RecentChooserMenu.new_for_manager(self.recent_manager)
        self.recent_files_menu.set_sort_type(Gtk.RecentSortType.MRU)
        
        recent_filter = Gtk.RecentFilter.new()
        recent_filter.add_mime_type('text/x-markdown')
        self.recent_files_menu.set_filter(recent_filter)
        menu = Gtk.Menu.new()

        for entry in self.recent_files_menu.get_items():
            if entry.exists():
                item = Gtk.MenuItem.new_with_label(entry.get_display_name())
                item.connect('activate', self.open_recent, entry.get_uri())
                menu.append(item)
                item.show()

        menu.show()
        parent_menu.set_submenu(menu)
        parent_menu.show()        

    def poll_for_motion(self):
        if (self.was_motion == False
                and self.status_bar_visible 
                and self.buffer_modified_for_status_bar):
            self.status_bar.set_state_flags(Gtk.StateFlags.INSENSITIVE, True)
            self.status_bar_visible = False
            self.buffer_modified_for_status_bar = False
            return False

        self.was_motion = False
        return True

    def on_motion_notify(self, widget, data=None):
        self.was_motion = True
        if self.status_bar_visible == False:
            self.status_bar_visible = True
            self.buffer_modified_for_status_bar = False
            self.update_line_and_char_count()
            self.status_bar.set_state_flags(Gtk.StateFlags.NORMAL, True)
            GObject.timeout_add(3000, self.poll_for_motion)

    def move_popup(self, widget, data=None):
        pass
        
    def finish_initializing(self, builder): # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog

        # Code for other initialization actions should be added here.
        
        # Texlive checker

        self.texlive_installed = False

        # Draw background
        self.background_image = helpers.get_media_path('bg_light.png')
        self.connect('draw', self.draw_bg)

        self.set_name('UberwriterWindow')

        self.title_end = "  –  UberWriter"
        self.set_title("New File" + self.title_end)

        # Drag and drop
        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        
        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.drag_dest_set_target_list(self.target_list)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')
        self.menubar = builder.get_object('menubar1')
        
        # Wire up buttons
        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.preview_button = builder.get_object('preview_toggle')

        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        self.preview_button.set_name('preview_toggle')
        
        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)

        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # Setup light background

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        self.TextEditor = TextEditor()

        base_leftmargin = 100
        self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)

        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)

        self.TextEditor.show()

        self.ScrolledWindow = builder.get_object('editor_scrolledwindow')
        self.ScrolledWindow.add(self.TextEditor)
        
        self.PreviewPane = builder.get_object('preview_scrolledwindow')

        pangoFont = Pango.FontDescription("Ubuntu Mono 15px")

        self.TextEditor.modify_font(pangoFont)

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(4)
        self.TextEditor.set_pixels_below_lines(4)
        self.TextEditor.set_pixels_inside_wrap(8)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)


        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding

        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)
        
        self.TextEditor.connect('move-cursor', self.cursor_moved)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()

        css = open(helpers.get_media_path('style.css'), 'rb')
        css_data = css.read()
        css.close()

        self.style_provider.load_from_data(css_data)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,     
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )
 
        # Still needed.
        self.fflines = 0

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer, base_leftmargin)
        self.MarkupBuffer.markup_buffer()
        self.FormatShortcuts = FormatShortcuts(self.TextBuffer, self.TextEditor)

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0

        self.TextBuffer.connect('mark-set', self.mark_set)
        
        self.TextEditor.drag_dest_unset()

        # Events to preserve margin. (To be deleted.)
        self.TextEditor.connect('delete-from-cursor', self.delete_from_cursor)
        self.TextEditor.connect('backspace', self.backspace)

        self.TextBuffer.connect('paste-done', self.paste_done)
        # self.connect('key-press-event', self.alt_mod)

        # Events for Typewriter mode
        self.TextBuffer.connect_after('mark-set', self.after_mark_set)
        self.TextBuffer.connect_after('changed', self.after_modify_text)
        self.TextEditor.connect_after('move-cursor', self.after_cursor_moved)
        self.TextEditor.connect_after('insert-at-cursor', self.after_insert_at_cursor)

        # Setting up inline preview
        self.InlinePreview = UberwriterInlinePreview(self.TextEditor, self.TextBuffer)

        # Vertical scrolling
        self.vadjustment = self.TextEditor.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)

        self.did_change = False

        # Window resize
        self.connect("configure-event", self.window_resize)
        self.connect("delete-event", self.on_delete_called)
        self.load_settings(builder)

    def alt_mod(self, widget, event, data=None):
        # TODO: Click and open when alt is pressed
        if event.state & Gdk.ModifierType.MOD2_MASK:
            logger.info("Alt pressed")
        return

    def on_delete_called(self, widget, data=None):
        """Called when the TexteditorWindow is closed.""" 
        logger.info('delete called')
        if self.check_change() == Gtk.ResponseType.CANCEL:
            return True
        return False

    def on_mnu_close_activate(self, widget, data=None):
        """
            Signal handler for closing the UberwriterWindow.
            Overriden from parent Window Class 
        """
        if self.on_delete_called(self): #Really destroy?
            return 
        else: 
            self.destroy()        
        return 

    def on_destroy(self, widget, data=None):
        """Called when the TexteditorWindow is closed."""
        # Clean up code for saving application state should be added here.
        self.window_close(widget)        
        self.save_settings()
        Gtk.main_quit()

    def save_settings(self):
        
        if not os.path.exists(CONFIG_PATH):
            try:
                os.makedirs(CONFIG_PATH)
            except Exception as e:
                log.debug("Failed to make uberwriter config path in ~/.config/uberwriter. Error: %r" % e)
        try:
            settings = dict()
            settings["dark_mode"] = self.dark_mode
            settings["spellcheck"] = self.SpellChecker.enabled
            f = open(CONFIG_PATH + "settings.pickle", "wb+")
            pickle.dump(settings, f)
            f.close()
            logger.debug("Saved settings: %r" % settings)
        except Exception as e:
            logger.debug("Error writing settings file to disk. Error: %r" % e)

    def load_settings(self, builder):
        dark_mode_button = builder.get_object("dark_mode")
        spellcheck_button = builder.get_object("disable_spellcheck")        
        try:
            f = open(CONFIG_PATH + "settings.pickle", "rb")
            settings = pickle.load(f)
            f.close()
            self.dark_mode = settings['dark_mode']
            dark_mode_button.set_active(settings['dark_mode'])
            spellcheck_button.set_active(settings['spellcheck'])
            logger.debug("loaded settings: %r" % settings)
        except Exception as e:
            logger.debug("(First Run?) Error loading settings from home dir. Error: %r", e)
        return 1
    def finish_initializing(self, builder): # pylint: disable=E1002
        """Set up the main window"""
        super(UberwriterWindow, self).finish_initializing(builder)

        self.AboutDialog = AboutUberwriterDialog
        self.UberwriterAdvancedExportDialog = UberwriterAdvancedExportDialog

        # Code for other initialization actions should be added here.
        
        # Texlive checker

        self.texlive_installed = False

        # Draw background
        self.background_image = helpers.get_media_path('bg_light.png')
        self.connect('draw', self.draw_bg)

        self.set_name('UberwriterWindow')

        self.title_end = "  –  UberWriter"
        self.set_title("New File" + self.title_end)

        # Drag and drop
        self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY)
        
        self.target_list = Gtk.TargetList.new([])
        self.target_list.add_uri_targets(1)
        self.target_list.add_text_targets(2)

        self.drag_dest_set_target_list(self.target_list)

        self.focusmode = False

        self.word_count = builder.get_object('word_count')
        self.char_count = builder.get_object('char_count')
        self.menubar = builder.get_object('menubar1')
        
        # Wire up buttons
        self.fullscreen_button = builder.get_object('fullscreen_toggle')
        self.focusmode_button = builder.get_object('focus_toggle')
        self.preview_button = builder.get_object('preview_toggle')

        self.fullscreen_button.set_name('fullscreen_toggle')
        self.focusmode_button.set_name('focus_toggle')
        self.preview_button.set_name('preview_toggle')
        
        # Setup status bar hide after 3 seconds

        self.status_bar = builder.get_object('status_bar_box')
        self.status_bar.set_name('status_bar_box')
        self.status_bar_visible = True
        self.was_motion = True
        self.buffer_modified_for_status_bar = False
        self.connect("motion-notify-event", self.on_motion_notify)
        GObject.timeout_add(3000, self.poll_for_motion)

        self.accel_group = Gtk.AccelGroup()
        self.add_accel_group(self.accel_group)

        # Setup light background

        surface = cairo.ImageSurface.create_from_png(self.background_image)
        self.background_pattern = cairo.SurfacePattern(surface)
        self.background_pattern.set_extend(cairo.EXTEND_REPEAT)

        self.TextEditor = TextEditor()

        base_leftmargin = 100
        self.TextEditor.set_left_margin(base_leftmargin)
        self.TextEditor.set_left_margin(40)

        self.TextEditor.set_wrap_mode(Gtk.WrapMode.WORD)

        self.TextEditor.show()

        self.ScrolledWindow = builder.get_object('editor_scrolledwindow')
        self.ScrolledWindow.add(self.TextEditor)
        
        self.PreviewPane = builder.get_object('preview_scrolledwindow')

        pangoFont = Pango.FontDescription("Ubuntu Mono 15px")

        self.TextEditor.modify_font(pangoFont)

        self.TextEditor.set_margin_top(38)
        self.TextEditor.set_margin_bottom(16)

        self.TextEditor.set_pixels_above_lines(4)
        self.TextEditor.set_pixels_below_lines(4)
        self.TextEditor.set_pixels_inside_wrap(8)

        tab_array = Pango.TabArray.new(1, True)
        tab_array.set_tab(0, Pango.TabAlign.LEFT, 20)
        self.TextEditor.set_tabs(tab_array)


        self.TextBuffer = self.TextEditor.get_buffer()
        self.TextBuffer.set_text('')

        # Init Window height for top/bottom padding

        self.window_height = self.get_size()[1]

        self.text_change_event = self.TextBuffer.connect('changed', self.text_changed)
        
        self.TextEditor.connect('move-cursor', self.cursor_moved)

        # Init file name with None
        self.filename = None

        self.generate_recent_files_menu(self.builder.get_object('recent'))

        self.style_provider = Gtk.CssProvider()

        css = open(helpers.get_media_path('style.css'), 'rb')
        css_data = css.read()
        css.close()

        self.style_provider.load_from_data(css_data)

        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(), self.style_provider,     
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )
 
        # Still needed.
        self.fflines = 0

        # Markup and Shortcuts for the TextBuffer
        self.MarkupBuffer = MarkupBuffer(self, self.TextBuffer, base_leftmargin)
        self.MarkupBuffer.markup_buffer()
        self.FormatShortcuts = FormatShortcuts(self.TextBuffer, self.TextEditor)

        # Scrolling -> Dark or not?
        self.textchange = False
        self.scroll_count = 0

        self.TextBuffer.connect('mark-set', self.mark_set)
        
        self.TextEditor.drag_dest_unset()

        # Events to preserve margin. (To be deleted.)
        self.TextEditor.connect('delete-from-cursor', self.delete_from_cursor)
        self.TextEditor.connect('backspace', self.backspace)

        self.TextBuffer.connect('paste-done', self.paste_done)
        # self.connect('key-press-event', self.alt_mod)

        # Events for Typewriter mode
        self.TextBuffer.connect_after('mark-set', self.after_mark_set)
        self.TextBuffer.connect_after('changed', self.after_modify_text)
        self.TextEditor.connect_after('move-cursor', self.after_cursor_moved)
        self.TextEditor.connect_after('insert-at-cursor', self.after_insert_at_cursor)

        # Setting up inline preview
        self.InlinePreview = UberwriterInlinePreview(self.TextEditor, self.TextBuffer)

        # Vertical scrolling
        self.vadjustment = self.TextEditor.get_vadjustment()
        self.vadjustment.connect('value-changed', self.scrolled)

        # Setting up spellcheck
        try:
            self.SpellChecker = SpellChecker(self.TextEditor, locale.getdefaultlocale()[0], collapse=False)
            self.spellcheck = True
        except:
            self.SpellChecker = None
            self.spellcheck = False
            builder.get_object("disable_spellcheck").set_active(False)

        if self.spellcheck:
            self.SpellChecker.append_filter('[#*]+', SpellChecker.FILTER_WORD)

        self.did_change = False

        # Window resize
        self.connect("configure-event", self.window_resize)
        self.connect("delete-event", self.on_delete_called)
        self.load_settings(builder)
示例#18
0
import sys
from os.path import join, dirname
sys.path.append(join(dirname(__file__), '../src/'))

import locale

import gtk

from gtkspellcheck import SpellChecker

if __name__ == '__main__':

    def quit(*args):
        gtk.main_quit()

    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.set_title('PyGtkSpellCheck Example')
    view = gtk.TextView()

    spellchecker = SpellChecker(view,
                                locale.getdefaultlocale()[0],
                                collapse=False)

    for code, name in spellchecker.languages:
        print('code: %5s, language: %s' % (code, name))

    window.set_default_size(600, 400)
    window.add(view)
    window.show_all()
    window.connect('delete-event', quit)
    gtk.main()