Basic linting (whitespace, docstrings, etc)

webkit2png
somas95 2018-07-29 13:44:07 +02:00
commit cf9d3d6fbc
13 changed files with 1126 additions and 573 deletions

View File

@ -1,221 +1,190 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# BEGIN LICENSE
# Copyright (C) 2012, Wolf Vollprecht <w.vollprecht@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
# END LICENSE
import gettext
import re
from gi.repository import Gtk, Gdk # pylint: disable=E0611
from gi.repository import Pango # pylint: disable=E0611
from gettext import gettext as _
from . MarkupBuffer import MarkupBuffer
class FormatShortcuts():
"""Manage the insertion of formatting for insert them using shortcuts
"""
def __init__(self, textbuffer, texteditor):
self.TextBuffer = textbuffer
self.TextEditor = texteditor
def rule(self):
self.TextBuffer.insert_at_cursor("\n\n-------\n")
self.TextEditor.scroll_mark_onscreen(self.TextBuffer.get_insert())
self.regex = MarkupBuffer.regex
def __init__(self, textbuffer, texteditor):
self.text_buffer = textbuffer
self.text_editor = texteditor
self.regex = MarkupBuffer.regex
def bold(self):
self.apply_format("**")
def italic(self):
self.apply_format("*")
def rule(self):
"""insert ruler at cursor
"""
def strikeout(self):
self.apply_format("~~")
self.text_buffer.insert_at_cursor("\n\n-------\n")
self.text_editor.scroll_mark_onscreen(self.text_buffer.get_insert())
def apply_format(self, wrap = "*"):
if self.TextBuffer.get_has_selection():
## Find current highlighting
def bold(self):
"""set selected text as bold
"""
(start, end) = self.TextBuffer.get_selection_bounds()
moved = False
if (
start.get_offset() >= len(wrap) and
end.get_offset() <= self.TextBuffer.get_char_count() - len(wrap)
):
moved = True
ext_start = start.copy()
ext_start.backward_chars(len(wrap))
ext_end = end.copy()
ext_end.forward_chars(len(wrap))
text = self.TextBuffer.get_text(ext_start, ext_end, True)
else:
text = self.TextBuffer.get_text(start, end, True)
if moved and text.startswith(wrap) and text.endswith(wrap):
text = text[len(wrap):-len(wrap)]
new_text = text
self.TextBuffer.delete(ext_start, ext_end)
move_back = 0
else:
if moved:
text = text[len(wrap):-len(wrap)]
new_text = text.lstrip().rstrip()
text = text.replace(new_text, wrap + new_text + wrap)
self.apply_format("**")
self.TextBuffer.delete(start, end)
move_back = len(wrap)
self.TextBuffer.insert_at_cursor(text)
text_length = len(new_text)
def italic(self):
"""set selected text as italic
"""
self.apply_format("*")
else:
helptext = ""
if wrap == "*":
helptext = _("emphasized text")
elif wrap == "**":
helptext = _("strong text")
elif wrap == "~~":
helptext = _("striked out text")
def strikeout(self):
"""set selected text as stricked out
"""
self.apply_format("~~")
self.TextBuffer.insert_at_cursor(wrap + helptext + wrap)
text_length = len(helptext)
move_back = len(wrap)
def apply_format(self, wrap="*"):
"""apply the given wrap to a selected text, or insert a helper text wraped
if nothing is selected
cursor_mark = self.TextBuffer.get_insert()
cursor_iter = self.TextBuffer.get_iter_at_mark(cursor_mark)
cursor_iter.backward_chars(move_back)
self.TextBuffer.move_mark_by_name('selection_bound', cursor_iter)
cursor_iter.backward_chars(text_length)
self.TextBuffer.move_mark_by_name('insert', cursor_iter)
Keyword Arguments:
wrap {str} -- [the format mark] (default: {"*"})
"""
def unordered_list_item(self):
helptext = _("List item")
text_length = len(helptext)
move_back = 0
if self.TextBuffer.get_has_selection():
(start, end) = self.TextBuffer.get_selection_bounds()
if start.starts_line():
text = self.TextBuffer.get_text(start, end, False)
if text.startswith(("- ", "* ", "+ ")):
delete_end = start.forward_chars(2)
self.TextBuffer.delete(start, delete_end)
else:
self.TextBuffer.insert(start, "- ")
else:
move_back = 0
cursor_mark = self.TextBuffer.get_insert()
cursor_iter = self.TextBuffer.get_iter_at_mark(cursor_mark)
if self.text_buffer.get_has_selection():
# Find current highlighting
(start, end) = self.text_buffer.get_selection_bounds()
moved = False
if (start.get_offset() >= len(wrap) and
end.get_offset() <= self.text_buffer.get_char_count() - len(wrap)):
moved = True
ext_start = start.copy()
ext_start.backward_chars(len(wrap))
ext_end = end.copy()
ext_end.forward_chars(len(wrap))
text = self.text_buffer.get_text(ext_start, ext_end, True)
else:
text = self.text_buffer.get_text(start, end, True)
start_ext = cursor_iter.copy()
start_ext.backward_lines(3)
text = self.TextBuffer.get_text(cursor_iter, start_ext, False)
lines = text.splitlines()
if moved and text.startswith(wrap) and text.endswith(wrap):
text = text[len(wrap):-len(wrap)]
new_text = text
self.text_buffer.delete(ext_start, ext_end)
move_back = 0
else:
if moved:
text = text[len(wrap):-len(wrap)]
new_text = text.lstrip().rstrip()
text = text.replace(new_text, wrap + new_text + wrap)
for line in reversed(lines):
if len(line) and line.startswith(("- ", "* ", "+ ")):
if cursor_iter.starts_line():
self.TextBuffer.insert_at_cursor(line[:2] + helptext)
else:
self.TextBuffer.insert_at_cursor("\n" + line[:2] + helptext)
break
else:
if len(lines[-1]) == 0 and len(lines[-2]) == 0:
self.TextBuffer.insert_at_cursor("- " + helptext)
elif len(lines[-1]) == 0:
if cursor_iter.starts_line():
self.TextBuffer.insert_at_cursor("- " + helptext)
else:
self.TextBuffer.insert_at_cursor("\n- " + helptext)
else:
self.TextBuffer.insert_at_cursor("\n\n- " + helptext)
break
self.text_buffer.delete(start, end)
move_back = len(wrap)
self.select_edit(move_back, text_length)
self.text_buffer.insert_at_cursor(text)
text_length = len(new_text)
def ordered_list_item(self):
pass
else:
helptext = ""
if wrap == "*":
helptext = _("emphasized text")
elif wrap == "**":
helptext = _("strong text")
elif wrap == "~~":
helptext = _("striked out text")
def select_edit(self, move_back, text_length):
cursor_mark = self.TextBuffer.get_insert()
cursor_iter = self.TextBuffer.get_iter_at_mark(cursor_mark)
cursor_iter.backward_chars(move_back)
self.TextBuffer.move_mark_by_name('selection_bound', cursor_iter)
cursor_iter.backward_chars(text_length)
self.TextBuffer.move_mark_by_name('insert', cursor_iter)
self.TextEditor.scroll_mark_onscreen(self.TextBuffer.get_insert())
self.text_buffer.insert_at_cursor(wrap + helptext + wrap)
text_length = len(helptext)
move_back = len(wrap)
def above(self, linestart = ""):
if not cursor_iter.starts_line():
return ""
else:
cursor_mark = self.TextBuffer.get_insert()
cursor_iter = self.TextBuffer.get_iter_at_mark(cursor_mark)
cursor_mark = self.text_buffer.get_insert()
cursor_iter = self.text_buffer.get_iter_at_mark(cursor_mark)
cursor_iter.backward_chars(move_back)
self.text_buffer.move_mark_by_name('selection_bound', cursor_iter)
cursor_iter.backward_chars(text_length)
self.text_buffer.move_mark_by_name('insert', cursor_iter)
start_ext = cursor_iter.copy()
start_ext.backward_lines(2)
text = self.TextBuffer.get_text(cursor_iter, start_ext, False)
lines = text.splitlines()
def unordered_list_item(self):
"""insert unordered list items or mark a selection as
an item in an unordered list
"""
#if line[-1].startswith
helptext = _("List item")
text_length = len(helptext)
move_back = 0
if self.text_buffer.get_has_selection():
(start, end) = self.text_buffer.get_selection_bounds()
if start.starts_line():
text = self.text_buffer.get_text(start, end, False)
if text.startswith(("- ", "* ", "+ ")):
delete_end = start.forward_chars(2)
self.text_buffer.delete(start, delete_end)
else:
self.text_buffer.insert(start, "- ")
else:
move_back = 0
cursor_mark = self.text_buffer.get_insert()
cursor_iter = self.text_buffer.get_iter_at_mark(cursor_mark)
def get_lines(self, cursor_iter):
start_ext = cursor_iter.copy()
start_ext.backward_lines(3)
text = self.text_buffer.get_text(cursor_iter, start_ext, False)
lines = text.splitlines()
start_ext = cursor_iter.copy()
start_ext.backward_lines(2)
text = self.TextBuffer.get_text(cursor_iter, start_ext, False)
lines = text.splitlines()
for line in reversed(lines):
if line and line.startswith(("- ", "* ", "+ ")):
if cursor_iter.starts_line():
self.text_buffer.insert_at_cursor(line[:2] + helptext)
else:
self.text_buffer.insert_at_cursor(
"\n" + line[:2] + helptext)
break
else:
if not lines[-1] and not lines[-2]:
self.text_buffer.insert_at_cursor("- " + helptext)
elif not lines[-1]:
if cursor_iter.starts_line():
self.text_buffer.insert_at_cursor("- " + helptext)
else:
self.text_buffer.insert_at_cursor("\n- " + helptext)
else:
self.text_buffer.insert_at_cursor("\n\n- " + helptext)
break
abs_line = cursor_iter.get_line()
self.select_edit(move_back, text_length)
return reversed(lines)
def ordered_list_item(self):
# TODO: implement ordered lists
pass
def heading(self, level = 0):
helptext = _("Heading")
before = ""
if self.TextBuffer.get_has_selection():
(start, end) = self.TextBuffer.get_selection_bounds()
text = self.TextBuffer.get_text(start, end, False)
self.TextBuffer.delete(start, end)
else:
text = helptext
def select_edit(self, move_back, text_length):
cursor_mark = self.text_buffer.get_insert()
cursor_iter = self.text_buffer.get_iter_at_mark(cursor_mark)
cursor_iter.backward_chars(move_back)
self.text_buffer.move_mark_by_name('selection_bound', cursor_iter)
cursor_iter.backward_chars(text_length)
self.text_buffer.move_mark_by_name('insert', cursor_iter)
self.text_editor.scroll_mark_onscreen(self.text_buffer.get_insert())
cursor_mark = self.TextBuffer.get_insert()
cursor_iter = self.TextBuffer.get_iter_at_mark(cursor_mark)
def heading(self):
"""insert heading at cursor position or set selected text as one
"""
helptext = _("Heading")
if self.text_buffer.get_has_selection():
(start, end) = self.text_buffer.get_selection_bounds()
text = self.text_buffer.get_text(start, end, False)
self.text_buffer.delete(start, end)
else:
text = helptext
#lines = self.get_lines(cursor_iter)
#if cursor_iter.starts_line():
# if lines[1] != '':
# before = before + "\n"
#else:
# match = re.match(r'([\#]+ )(.+)', lines[0])
# if match:
# if match.group(1):
#
# print match.group(0)
# if len(match.group(0)) < 6:
# before = before + "#" * (len(match.group(0)) + 1)
# else:
# before = before + "#"
# else:
# before = before + "\n\n"
#
#
# check_text = self.TextBuffer.get_text(start, cursor_iter, False).decode("utf-8")
# print check_text
self.TextBuffer.insert_at_cursor("#" + " " + text)
self.select_edit(0, len(text))
self.text_buffer.insert_at_cursor("#" + " " + text)
self.select_edit(0, len(text))

View File

@ -102,7 +102,7 @@ class MarkupBuffer():
# self.ftag = self.TextBuffer.create_tag("pix_front", pixels_above_lines = 100)
regex = {
"ITALIC": re.compile(r"(\*|_)(.*?)\1", re.UNICODE), # *asdasd* // _asdasd asd asd_
"STRONG": re.compile(r"(\*\*|__)(.*?)\1", re.UNICODE), # **as das** // __asdasdasd asd ad a__
"STRONG": re.compile(r"(\*\*|__)(.*?)\1", re.UNICODE), # **as das** // __asdasd asd ad a__
"STRONGITALIC": re.compile(r"(\*\*\*|___)(.*?)\1"),
"BLOCKQUOTE": re.compile(r"^([\>]+ )", re.MULTILINE),
"STRIKETHROUGH": re.compile(r"~~[^ `~\n].+?~~"),

View File

@ -13,16 +13,14 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
from gi.repository import Gtk, Gdk, GLib, Gio
from gettext import gettext as _
from gi.repository import Gio
class Settings(Gio.Settings):
"""
UberWriter Settings
"""
def __init__(self):
"""
Init Settings
@ -35,4 +33,4 @@ class Settings(Gio.Settings):
"""
settings = Gio.Settings.new("de.wolfvollprecht.UberWriter")
settings.__class__ = Settings
return settings
return settings

View File

@ -43,8 +43,8 @@ class UberwriterAutoCorrect:
if self.bubble:
self.bubble_label.set_text(suggestion)
else:
pos = self.TextView.get_iter_location(iterator)
pos_adjusted = self.TextView.buffer_to_window_coords(
pos = self.text_view.get_iter_location(iterator)
pos_adjusted = self.text_view.buffer_to_window_coords(
Gtk.TextWindowType.TEXT, pos.x, pos.y + pos.height)
self.bubble_eventbox = Gtk.EventBox.new()
self.bubble = Gtk.Grid.new()
@ -52,7 +52,7 @@ class UberwriterAutoCorrect:
self.bubble_eventbox.add(self.bubble)
self.bubble_eventbox.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.bubble_eventbox.connect("button_press_event", self.clicked_bubble)
self.TextView.add_child_in_window(self.bubble_eventbox,
self.text_view.add_child_in_window(self.bubble_eventbox,
Gtk.TextWindowType.TEXT,
pos_adjusted[0], pos_adjusted[1])
@ -196,12 +196,12 @@ class UberwriterAutoCorrect:
self.enchant_dict = enchant.Dict(self.language)
def __init__(self, textview, textbuffer):
self.TextView = textview
self.text_view = textview
self.buffer = textbuffer
self.suggestion = ""
self.bubble = self.bubble_label = None
self.buffer.connect_after('insert-text', self.text_insert)
self.TextView.connect('key-press-event', self.key_pressed)
self.text_view.connect('key-press-event', self.key_pressed)
self.language = "en_US"
self.frequency_dict = {}

View File

@ -1,31 +1,30 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# BEGIN LICENSE
# Copyright (C) 2012, Wolf Vollprecht <w.vollprecht@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
# END LICENSE
import os
import re
import http.client
import urllib
from urllib.error import URLError, HTTPError
from urllib.error import URLError
import webbrowser
import gettext
import subprocess
import tempfile
import logging
import threading
from pprint import pprint
import telnetlib
from gettext import gettext as _
from gi.repository import Gtk, Gdk, GdkPixbuf, GObject
from uberwriter_lib import LatexToPNG
@ -35,12 +34,9 @@ from .FixTable import FixTable
from .MarkupBuffer import MarkupBuffer
from gettext import gettext as _
LOGGER = logging.getLogger('uberwriter')
import logging
logger = logging.getLogger('uberwriter')
GObject.threads_init() # Still needed?
GObject.threads_init() # Still needed?
# TODO:
# - Don't insert a span with id, it breaks the text to often
@ -48,78 +44,77 @@ GObject.threads_init() # Still needed?
# A jumping URL from that (for preview)
# Also, after going to preview, set cursor back to where it was
import telnetlib
import subprocess
class DictAccessor():
class DictAccessor(object):
def __init__( self, host='pan.alephnull.com', port=2628, timeout=60 ):
self.tn = telnetlib.Telnet( host, port )
def __init__(self, host='pan.alephnull.com', port=2628, timeout=60):
self.telnet = telnetlib.Telnet(host, port)
self.timeout = timeout
self.login_response = self.tn.expect( [ self.reEndResponse ], self.timeout )[ 2 ]
self.login_response = self.telnet.expect(
[self.reEndResponse], self.timeout)[2]
def get_online(self, word):
process = subprocess.Popen(['dict', '-d', 'wn', word],
stdout=subprocess.PIPE)
return process.communicate()[0]
def getOnline(self, word):
p = subprocess.Popen(['dict', '-d', 'wn', word], stdout=subprocess.PIPE)
return p.communicate()[0]
def run_command(self, cmd):
self.telnet.write(cmd.encode('utf-8') + b'\r\n')
return self.telnet.expect([self.reEndResponse], self.timeout)[2]
def runCommand( self, cmd ):
self.tn.write( cmd.encode('utf-8') + b'\r\n' )
return self.tn.expect( [ self.reEndResponse ], self.timeout )[ 2 ]
def getMatches( self, database, strategy, word ):
if database in [ '', 'all' ]:
def get_matches(self, database, strategy, word):
if database in ['', 'all']:
d = '*'
else:
d = database
if strategy in [ '', 'default' ]:
if strategy in ['', 'default']:
s = '.'
else:
s = strategy
w = word.replace( '"', r'\"' )
tsplit = self.runCommand( 'MATCH %s %s "%s"' % ( d, s, w ) ).splitlines( )
mlist = list( )
if tsplit[ -1 ].startswith( b'250 ok' ) and tsplit[ 0 ].startswith( b'1' ):
mlines = tsplit[ 1:-2 ]
w = word.replace('"', r'\"')
tsplit = self.run_command('MATCH %s %s "%s"' % (d, s, w)).splitlines()
mlist = list()
if tsplit[-1].startswith(b'250 ok') and tsplit[0].startswith(b'1'):
mlines = tsplit[1:-2]
for line in mlines:
lsplit = line.strip( ).split( )
db = lsplit[ 0 ]
word = unquote( ' '.join( lsplit[ 1: ] ) )
mlist.append( ( db, word ) )
lsplit = line.strip().split()
db = lsplit[0]
word = unquote(' '.join(lsplit[1:]))
mlist.append((db, word))
return mlist
reEndResponse = re.compile( br'^[2-5][0-58][0-9] .*\r\n$', re.DOTALL + re.MULTILINE )
reDefinition = re.compile( br'^151(.*?)^\.', re.DOTALL + re.MULTILINE )
reEndResponse = re.compile(
br'^[2-5][0-58][0-9] .*\r\n$', re.DOTALL + re.MULTILINE)
reDefinition = re.compile(br'^151(.*?)^\.', re.DOTALL + re.MULTILINE)
def getDefinition( self, database, word ):
if database in [ '', 'all' ]:
def get_definition(self, database, word):
if database in ['', 'all']:
d = '*'
else:
d = database
w = word.replace( '"', r'\"' )
dsplit = self.runCommand( 'DEFINE %s "%s"' % ( d, w ) ).splitlines( True )
w = word.replace('"', r'\"')
dsplit = self.run_command('DEFINE %s "%s"' % (d, w)).splitlines(True)
# dsplit = self.getOnline(word).splitlines()
dlist = list( )
if dsplit[ -1 ].startswith( b'250 ok' ) and dsplit[ 0 ].startswith( b'1' ):
dlines = dsplit[ 1:-1 ]
dtext = b''.join( dlines )
dlist = self.reDefinition.findall( dtext )
dlist = list()
if dsplit[-1].startswith(b'250 ok') and dsplit[0].startswith(b'1'):
dlines = dsplit[1:-1]
dtext = b''.join(dlines)
dlist = self.reDefinition.findall(dtext)
# print(dlist)
dlist = [ dtext ]
dlist = [dtext]
# dlist = dsplit # not using the localhost telnet connection
return dlist
def close( self ):
t = self.runCommand( 'QUIT' )
self.tn.close( )
def close(self):
t = self.run_command('QUIT')
self.telnet.close()
return t
def parse_wordnet(self, response):
# consisting of group (n,v,adj,adv)
# number, description, examples, synonyms, antonyms
capture = {}
lines = response.splitlines()
lines = lines[2:]
lines = ' '.join(lines)
@ -129,9 +124,9 @@ class DictAccessor(object):
act_res = {'defs': [], 'class': 'none', 'num': 'None'}
for l in lines:
l = l.strip()
if len(l) == 0:
if not l:
continue
if l in ['adv', 'adj', 'n', 'v']:
if l in ['adv', 'adj', 'n', 'v']:
if act_res:
res.append(act_res.copy())
act_res = {}
@ -160,7 +155,7 @@ class DictAccessor(object):
act_def['description'] = []
for llll in lll:
llll = llll.strip()
if(llll.strip().startswith('"')):
if llll.strip().startswith('"'):
act_def['examples'].append(llll)
else:
act_def['description'].append(llll)
@ -172,8 +167,9 @@ class DictAccessor(object):
res.append(act_res.copy())
return res
def check_url(url, item, spinner):
logger.debug("thread started, checking url")
LOGGER.debug("thread started, checking url")
error = False
try:
response = urllib.request.urlopen(url)
@ -183,25 +179,27 @@ def check_url(url, item, spinner):
if not error:
if (response.code / 100) >= 4:
logger.debug("Website not available")
LOGGER.debug("Website not available")
text = _("Website is not available")
else:
text = _("Website is available")
logger.debug("Response: %s" % text)
LOGGER.debug("Response: %s" % text)
spinner.destroy()
item.set_label(text)
def get_dictionary(term):
da = DictAccessor()
output = da.getDefinition('wn', term)
if(len(output)):
output = da.get_definition('wn', term)
if output:
output = output[0]
else:
return None
return da.parse_wordnet(output.decode(encoding='UTF-8'))
def get_web_thumbnail(url, item, spinner):
logger.debug("thread started, generating thumb")
LOGGER.debug("thread started, generating thumb")
# error = False
@ -211,9 +209,10 @@ def get_web_thumbnail(url, item, spinner):
filename = tempfile.mktemp(suffix='.png')
thumb_size = '256' # size can only be 32, 64, 96, 128 or 256!
args = ['gnome-web-photo', '--mode=thumbnail', '-s', thumb_size, url, filename]
p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output = p.communicate()[0]
args = ['gnome-web-photo', '--mode=thumbnail',
'-s', thumb_size, url, filename]
process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
_output = process.communicate()[0]
image = Gtk.Image.new_from_file(filename)
image.show()
@ -229,6 +228,7 @@ def get_web_thumbnail(url, item, spinner):
item.add(image)
item.show()
def fill_lexikon_bubble(vocab, lexikon_dict):
grid = Gtk.Grid.new()
i = 0
@ -259,31 +259,30 @@ def fill_lexikon_bubble(vocab, lexikon_dict):
i = i + 1
grid.show_all()
return grid
else:
return None
return None
class UberwriterInlinePreview():
def __init__(self, view, text_buffer):
self.TextView = view
self.TextBuffer = text_buffer
self.LatexConverter = LatexToPNG.LatexToPNG()
cursor_mark = self.TextBuffer.get_insert()
cursor_iter = self.TextBuffer.get_iter_at_mark(cursor_mark)
self.ClickMark = self.TextBuffer.create_mark('click', cursor_iter)
self.text_view = view
self.text_buffer = text_buffer
self.latex_converter = LatexToPNG.LatexToPNG()
cursor_mark = self.text_buffer.get_insert()
cursor_iter = self.text_buffer.get_iter_at_mark(cursor_mark)
self.click_mark = self.text_buffer.create_mark('click', cursor_iter)
# Events for popup menu
# self.TextView.connect_after('populate-popup', self.populate_popup)
# self.TextView.connect_after('popup-menu', self.move_popup)
self.TextView.connect('button-press-event', self.click_move_button)
self.text_view.connect('button-press-event', self.click_move_button)
self.popover = None
self.settings = Settings.new()
def open_popover_with_widget(self, widget):
a = self.TextBuffer.create_child_anchor(self.TextBuffer.get_iter_at_mark(self.ClickMark))
a = self.text_buffer.create_child_anchor(
self.text_buffer.get_iter_at_mark(self.click_mark))
lbl = Gtk.Label('')
self.TextView.add_child_at_anchor(lbl, a)
self.text_view.add_child_at_anchor(lbl, a)
lbl.show()
# a = Gtk.Window.new(Gtk.WindowType.POPUP)
# a.set_transient_for(self.TextView.get_toplevel())
@ -296,7 +295,6 @@ class UberwriterInlinePreview():
# if(event.keyval == Gdk.KEY_Escape):
# widget.destroy()
# a.connect('key-press-event', close)
b = Gtk.Grid.new()
alignment = Gtk.Alignment()
alignment.props.margin_bottom = 5
alignment.props.margin_top = 5
@ -310,7 +308,7 @@ class UberwriterInlinePreview():
self.popover.get_style_context().add_class("QuickPreviewPopup")
self.popover.add(alignment)
# a.add(alignment)
dismiss, rect = self.popover.get_pointing_to()
_dismiss, rect = self.popover.get_pointing_to()
rect.y = rect.y - 20
self.popover.set_pointing_to(rect)
# widget = Gtk.Label.new("testasds a;12j3 21 lk3j213")
@ -322,21 +320,21 @@ class UberwriterInlinePreview():
# print(self.popover)
self.popover.set_property('width-request', 50)
def click_move_button(self, widget, event):
def click_move_button(self, _widget, event):
if event.button == 1 and event.state & Gdk.ModifierType.CONTROL_MASK:
x, y = self.TextView.window_to_buffer_coords(2,
int(event.x),
int(event.y))
self.TextBuffer.move_mark(self.ClickMark,
self.TextView.get_iter_at_location(x, y).iter)
self.populate_popup(self.TextView)
x, y = self.text_view.window_to_buffer_coords(2,
int(event.x),
int(event.y))
self.text_buffer.move_mark(self.click_mark,
self.text_view.get_iter_at_location(x, y).iter)
self.populate_popup(self.text_view)
def fix_table(self, widget, data=None):
logger.debug('fixing that table')
f = FixTable(self.TextBuffer)
f.fix_table()
def fix_table(self, _widget, _data=None):
LOGGER.debug('fixing that table')
fix_table = FixTable(self.text_buffer)
fix_table.fix_table()
def populate_popup(self, editor, data=None):
def populate_popup(self, _editor, _data=None):
# popover = Gtk.Popover.new(editor)
# pop_cont = Gtk.Container.new()
# popover.add(pop_cont)
@ -354,14 +352,14 @@ class UberwriterInlinePreview():
# menu.prepend(table_item)
# menu.show()
start_iter = self.TextBuffer.get_iter_at_mark(self.ClickMark)
start_iter = self.text_buffer.get_iter_at_mark(self.click_mark)
# Line offset of click mark
line_offset = start_iter.get_line_offset()
end_iter = start_iter.copy()
start_iter.set_line_offset(0)
end_iter.forward_to_line_end()
text = self.TextBuffer.get_text(start_iter, end_iter, False)
text = self.text_buffer.get_text(start_iter, end_iter, False)
math = MarkupBuffer.regex["MATH"]
link = MarkupBuffer.regex["LINK"]
@ -369,22 +367,18 @@ class UberwriterInlinePreview():
footnote = re.compile(r'\[\^([^\s]+?)\]')
image = re.compile(r"!\[(.*?)\]\((.+?)\)")
buf = self.TextBuffer
context_offset = 0
matchlist = []
found_match = False
matches = re.finditer(math, text)
for match in matches:
logger.debug(match.group(1))
if match.start() < line_offset and match.end() > line_offset:
success, result = self.LatexConverter.generatepng(match.group(1))
LOGGER.debug(match.group(1))
if match.start() < line_offset < match.end():
success, result = self.latex_converter.generatepng(
match.group(1))
if success:
image = Gtk.Image.new_from_file(result)
image.show()
logger.debug("logging image")
LOGGER.debug("logging image")
# item.add(image)
self.open_popover_with_widget(image)
else:
@ -407,12 +401,12 @@ class UberwriterInlinePreview():
# Links
matches = re.finditer(link, text)
for match in matches:
if match.start() < line_offset and match.end() > line_offset:
if match.start() < line_offset < match.end():
text = text[text.find("http://"):-1]
item.connect("activate", lambda w: webbrowser.open(text))
logger.debug(text)
LOGGER.debug(text)
statusitem = Gtk.MenuItem.new()
statusitem.show()
@ -421,9 +415,9 @@ class UberwriterInlinePreview():
spinner.start()
statusitem.add(spinner)
spinner.show()
thread = threading.Thread(target=check_url,
args=(text, statusitem, spinner))
thread = threading.Thread(target=check_url,
args=(text, statusitem, spinner))
thread.start()
webphoto_item = Gtk.MenuItem.new()
@ -433,15 +427,15 @@ class UberwriterInlinePreview():
webphoto_item.add(spinner_2)
spinner_2.show()
thread_image = threading.Thread(target=get_web_thumbnail,
args=(text, webphoto_item, spinner_2))
thread_image = threading.Thread(target=get_web_thumbnail,
args=(text, webphoto_item, spinner_2))
thread_image.start()
item.set_label(_("Open Link in Webbrowser"))
item.show()
self.open_popover_with_widget(webphoto_item)
# menu.prepend(separator)
# separator.show()
@ -450,25 +444,25 @@ class UberwriterInlinePreview():
# menu.prepend(item)
# menu.show()
found_match = True
break
if not found_match:
matches = re.finditer(image, text)
for match in matches:
if match.start() < line_offset and match.end() > line_offset:
if match.start() < line_offset < match.end():
path = match.group(2)
if path.startswith("file://"):
path = path[7:]
elif not path.startswith("/"):
# then the path is relative
base_path = self.settings.get_value("open-file-path").get_string()
base_path = self.settings.get_value(
"open-file-path").get_string()
path = base_path + "/" + path
logger.info(path)
pb = GdkPixbuf.Pixbuf.new_from_file_at_size(path, 400, 300)
image = Gtk.Image.new_from_pixbuf(pb)
LOGGER.info(path)
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, 400, 300)
image = Gtk.Image.new_from_pixbuf(pixbuf)
image.show()
self.open_popover_with_widget(image)
item.set_property('width-request', 50)
@ -486,15 +480,18 @@ class UberwriterInlinePreview():
if not found_match:
matches = re.finditer(footnote, text)
for match in matches:
if match.start() < line_offset and match.end() > line_offset:
logger.debug(match.group(1))
footnote_match = re.compile(r"\[\^" + match.group(1) + r"\]: (.+(?:\n|\Z)(?:^[\t].+(?:\n|\Z))*)", re.MULTILINE)
if match.start() < line_offset < match.end():
LOGGER.debug(match.group(1))
footnote_match = re.compile(
r"\[\^" + match.group(1) + r"\]: (.+(?:\n|\Z)(?:^[\t].+(?:\n|\Z))*)",
re.MULTILINE)
replace = re.compile(r"^\t", re.MULTILINE)
start, end = self.TextBuffer.get_bounds()
fn_match = re.search(footnote_match, self.TextBuffer.get_text(start, end, False))
start, end = self.text_buffer.get_bounds()
fn_match = re.search(
footnote_match, self.text_buffer.get_text(start, end, False))
label = Gtk.Label()
label.set_alignment(0.0, 0.5)
logger.debug(fn_match)
LOGGER.debug(fn_match)
if fn_match:
result = re.sub(replace, "", fn_match.group(1))
if result.endswith("\n"):
@ -517,21 +514,19 @@ class UberwriterInlinePreview():
break
if not found_match:
start_iter = self.TextBuffer.get_iter_at_mark(self.ClickMark)
start_iter = self.text_buffer.get_iter_at_mark(self.click_mark)
start_iter.backward_word_start()
end_iter = start_iter.copy()
end_iter.forward_word_end()
word = self.TextBuffer.get_text(start_iter, end_iter, False)
word = self.text_buffer.get_text(start_iter, end_iter, False)
terms = get_dictionary(word)
if terms:
sc = Gtk.ScrolledWindow.new()
sc.add(fill_lexikon_bubble(word, terms))
sc.props.width_request = 500
sc.props.height_request = 400
sc.show_all()
self.open_popover_with_widget(sc)
return
scrolled_window = Gtk.ScrolledWindow.new()
scrolled_window.add(fill_lexikon_bubble(word, terms))
scrolled_window.props.width_request = 500
scrolled_window.props.height_request = 400
scrolled_window.show_all()
self.open_popover_with_widget(scrolled_window)
def move_popup(self):
pass

View File

@ -44,8 +44,6 @@ Extending
A TextEditor is Gtk.TextView
"""
try:
from gi.repository import Gtk
from gi.repository import Gdk
@ -55,8 +53,6 @@ try:
except:
print("couldn't load depencies")
import logging
LOGGER = logging.getLogger('uberwriter')
@ -104,7 +100,6 @@ class TextEditor(Gtk.TextView):
'redo': (GObject.SIGNAL_ACTION, None, ())
}
# TODO: delete this?
def scroll_to_iter(self, iterable, *args):
self.get_buffer().place_cursor(iterable)

View File

@ -20,7 +20,6 @@ import os
import codecs
import webbrowser
import urllib
import pickle
import logging
import mimetypes
@ -195,6 +194,8 @@ class UberwriterWindow(Window):
self.check_scroll(self.text_buffer.get_insert())
if self.spellcheck:
self.spell_checker._misspelled.set_property('underline', 0)
self.click_event = self.text_editor.connect("button-release-event",
self.on_focusmode_click)
else:
self.remove_typewriter()
self.focusmode = False
@ -210,7 +211,14 @@ class UberwriterWindow(Window):
self.update_line_and_char_count()
self.check_scroll()
if self.spellcheck:
self.spell_checker._misspelled.set_property('underline', 4)
self.SpellChecker._misspelled.set_property('underline', 4)
_click_event = self.text_editor.disconnect(self.click_event)
def on_focusmode_click(self, *_args):
"""call MarkupBuffer to mark as bold the line where the cursor is
"""
self.markup_buffer.markup_buffer(1)
def scroll_smoothly(self, widget, frame_clock, _data=None):
if self.smooth_scroll_data['target_pos'] == -1:

View File

@ -0,0 +1,568 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
jobs=1
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
# disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
locally-enabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
use-symbolic-message-instead,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details.
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio). You can also give a reporter class, e.g.
# mypackage.mymodule.MyReporterClass.
output-format=msvs
# Tells whether to display a full report or only the messages.
reports=yes
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module.
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: he (hspell), en_IE
# (hunspell), es_BO (hunspell), en_NZ (hunspell), es_DO (hunspell), es_MX
# (hunspell), en_ZA (hunspell), en_IN (hunspell), en_TT (hunspell), ca
# (aspell), ca_FR (hunspell), es_HN (hunspell), ca_AD (hunspell), es_SV
# (hunspell), es_PA (hunspell), en_DK (hunspell), es_NI (hunspell), es_PE
# (hunspell), en_SG (hunspell), es_UY (hunspell), en_BS (hunspell), en_BW
# (hunspell), es_CL (hunspell), es_AR (hunspell), en_BZ (hunspell), es_CO
# (hunspell), en_ZW (hunspell), en_HK (hunspell), es_CR (hunspell), en_NA
# (hunspell), es_PR (hunspell), en_JM (hunspell), es_VE (hunspell), en_AG
# (hunspell), es_CU (hunspell), en_NG (hunspell), ca_ES (hunspell), es_ES
# (hunspell), es_ANY (hunspell), es_EC (hunspell), es_GT (hunspell), en_PH
# (hunspell), en_GB (hunspell), en_US (hunspell), ca_IT (hunspell), es_PY
# (hunspell), en_GH (hunspell)..
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[BASIC]
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style.
#argument-rgx=
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
#class-attribute-rgx=
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style.
#class-rgx=
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style.
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names.
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style.
#function-rgx=
# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_
# Include a hint for the correct naming format with invalid-name.
include-naming-hint=yes
# Naming style matching correct inline iteration names.
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
#inlinevar-rgx=
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style.
#method-rgx=
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style.
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style.
#variable-rgx=
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=cls
[DESIGN]
# Maximum number of arguments for function / method.
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in an if statement.
max-bool-expr=5
# Maximum number of branch for function / method body.
max-branches=12
# Maximum number of locals for function / method body.
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body.
max-returns=6
# Maximum number of statements in function / method body.
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled).
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled).
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception".
overgeneral-exceptions=Exception

View File

@ -1,32 +1,29 @@
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.
import sys
import argparse
import gettext
import os
from gettext import gettext as _
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gtk', '3.0') # pylint: disable=wrong-import-position
from gi.repository import GLib, Gio, Gtk, GdkPixbuf
from . helpers import get_builder, show_uri, get_help_uri, get_media_path
from uberwriter import UberwriterWindow
from uberwriter.Settings import Settings
from uberwriter_lib import set_up_logging
from uberwriter_lib.PreferencesDialog import PreferencesDialog
from . helpers import get_builder, get_media_path
from gettext import gettext as _
class Window(Gtk.ApplicationWindow):
@ -35,26 +32,26 @@ class Window(Gtk.ApplicationWindow):
# This will be in the windows group and have the "win" prefix
max_action = Gio.SimpleAction.new_stateful("maximize", None,
GLib.Variant.new_boolean(False))
GLib.Variant.new_boolean(False))
max_action.connect("change-state", self.on_maximize_toggle)
self.add_action(max_action)
# Keep it in sync with the actual state
self.connect("notify::is-maximized",
lambda obj, pspec: max_action.set_state(
GLib.Variant.new_boolean(obj.props.is_maximized)))
self.set_default_size(850,500)
lambda obj, pspec: max_action.set_state(
GLib.Variant.new_boolean(obj.props.is_maximized)))
self.set_default_size(850, 500)
icon_file = get_media_path("uberwriter.svg")
self.set_icon_from_file(icon_file)
builder = get_builder('UberwriterWindow')
new_object = builder.get_object("FullscreenOverlay")
self.contents = new_object
self.add(self.contents)
self.finish_initializing(builder)
def on_maximize_toggle(self, action, value):
@ -63,7 +60,7 @@ class Window(Gtk.ApplicationWindow):
self.maximize()
else:
self.unmaximize()
def finish_initializing(self, builder):
"""Called while initializing this instance in __new__
@ -74,11 +71,10 @@ class Window(Gtk.ApplicationWindow):
# Get a reference to the builder and set up the signals.
self.builder = builder
self.ui = builder.get_ui(self, True)
self.PreferencesDialog = None # class
self.preferences_dialog = None # instance
self.AboutDialog = None # class
self.PreferencesDialog = None # class
self.preferences_dialog = None # instance
self.AboutDialog = None # class
# self.settings = Gio.Settings("net.launchpad.uberwriter")
# self.settings.connect('changed', self.on_preferences_changed)
@ -94,7 +90,7 @@ class Window(Gtk.ApplicationWindow):
self.indicator = indicator.new_application_indicator(self)
except ImportError:
pass
class Application(Gtk.Application):
@ -104,7 +100,7 @@ class Application(Gtk.Application):
**kwargs)
self.window = None
self.settings = Settings.new()
def do_startup(self):
Gtk.Application.do_startup(self)
@ -113,11 +109,11 @@ class Application(Gtk.Application):
action = Gio.SimpleAction.new("help", None)
action.connect("activate", self.on_help)
self.add_action(action)
action = Gio.SimpleAction.new("shortcuts", None)
action.connect("activate", self.on_shortcuts)
self.add_action(action)
action = Gio.SimpleAction.new("about", None)
action.connect("activate", self.on_about)
self.add_action(action)
@ -136,26 +132,26 @@ class Application(Gtk.Application):
set_dark_mode = self.settings.get_value("dark-mode")
action = Gio.SimpleAction.new_stateful("dark_mode",
None,
GLib.Variant.new_boolean(set_dark_mode))
None,
GLib.Variant.new_boolean(set_dark_mode))
action.connect("change-state", self.on_dark_mode)
self.add_action(action)
action = Gio.SimpleAction.new_stateful("focus_mode",
None,
GLib.Variant.new_boolean(False))
None,
GLib.Variant.new_boolean(False))
action.connect("change-state", self.on_focus_mode)
self.add_action(action)
action = Gio.SimpleAction.new_stateful("fullscreen",
None,
GLib.Variant.new_boolean(False))
None,
GLib.Variant.new_boolean(False))
action.connect("change-state", self.on_fullscreen)
self.add_action(action)
action = Gio.SimpleAction.new_stateful("preview",
None,
GLib.Variant.new_boolean(False))
None,
GLib.Variant.new_boolean(False))
action.connect("change-state", self.on_preview)
self.add_action(action)
@ -164,8 +160,8 @@ class Application(Gtk.Application):
self.add_action(action)
action = Gio.SimpleAction.new_stateful("spellcheck",
None,
GLib.Variant.new_boolean(True))
None,
GLib.Variant.new_boolean(True))
action.connect("change-state", self.on_spellcheck)
self.add_action(action)
@ -207,20 +203,18 @@ class Application(Gtk.Application):
action.connect("activate", self.on_preferences)
self.add_action(action)
'''Shortcuts'''
self.set_accels_for_action("app.focus_mode",["<Ctl>d"])
self.set_accels_for_action("app.fullscreen",["F11"])
self.set_accels_for_action("app.preview",["<Ctl>p"])
self.set_accels_for_action("app.search",["<Ctl>f"])
self.set_accels_for_action("app.spellcheck",["F7"])
self.set_accels_for_action("app.new",["<Ctl>n"])
self.set_accels_for_action("app.open",["<Ctl>o"])
self.set_accels_for_action("app.save",["<Ctl>s"])
self.set_accels_for_action("app.save_as",["<Ctl><shift>s"])
self.set_accels_for_action("app.focus_mode", ["<Ctl>d"])
self.set_accels_for_action("app.fullscreen", ["F11"])
self.set_accels_for_action("app.preview", ["<Ctl>p"])
self.set_accels_for_action("app.search", ["<Ctl>f"])
self.set_accels_for_action("app.spellcheck", ["F7"])
self.set_accels_for_action("app.new", ["<Ctl>n"])
self.set_accels_for_action("app.open", ["<Ctl>o"])
self.set_accels_for_action("app.save", ["<Ctl>s"])
self.set_accels_for_action("app.save_as", ["<Ctl><shift>s"])
def do_activate(self):
# We only allow a single window and raise any existing ones
@ -228,17 +222,16 @@ class Application(Gtk.Application):
# Windows are associated with the application
# when the last one is closed the application shuts down
# self.window = Window(application=self, title="UberWriter")
self.window = UberwriterWindow.UberwriterWindow(application=self, title="UberWriter")
if len(self.args) > 0:
self.window.load_file(self.args[0])
self.window = UberwriterWindow.UberwriterWindow(
application=self, title="UberWriter")
if self.args:
self.window.load_file(self.args[0])
if self.options.experimental_features:
self.window.use_experimental_features(True)
self.window.present()
def do_command_line(self, command_line):
def do_command_line(self, _command_line):
"""Support for command line options"""
parser = argparse.ArgumentParser()
parser.add_argument(
@ -247,37 +240,36 @@ class Application(Gtk.Application):
parser.add_argument(
"-e", "--experimental-features", help=_("Use experimental features"),
action='store_true'
)
)
(self.options, self.args) = parser.parse_known_args()
set_up_logging(self.options)
self.activate()
return 0
def on_about(self, action, param):
def on_about(self, _action, _param):
builder = get_builder('About')
about_dialog = builder.get_object("AboutDialog")
about_dialog.set_transient_for(self.window)
logo_file = get_media_path("uberwriter.svg")
logo = GdkPixbuf.Pixbuf.new_from_file(logo_file)
about_dialog.set_logo(logo)
about_dialog.present()
def on_help(self, action, param):
def on_help(self, _action, _param):
self.window.open_pandoc_markdown(self)
def on_translate(self, action, param):
def on_translate(self, _action, _param):
self.window.open_translation()
def on_donate(self, action, param):
def on_donate(self, _action, _param):
self.window.open_donation()
def on_shortcuts(self, action, param):
def on_shortcuts(self, _action, _param):
builder = get_builder('Shortcuts')
builder.get_object("shortcuts").set_transient_for(self.window)
builder.get_object("shortcuts").show()
@ -285,12 +277,13 @@ class Application(Gtk.Application):
def on_dark_mode(self, action, value):
action.set_state(value)
self.settings.set_value("dark-mode",
GLib.Variant("b", value))
GLib.Variant("b", value))
self.window.toggle_dark_mode(value)
#this changes the headerbar theme accordingly
# this changes the headerbar theme accordingly
self.dark_setting = Gtk.Settings.get_default()
self.dark_setting.set_property("gtk-application-prefer-dark-theme", value)
self.dark_setting.set_property(
"gtk-application-prefer-dark-theme", value)
def on_focus_mode(self, action, value):
action.set_state(value)
@ -304,44 +297,44 @@ class Application(Gtk.Application):
action.set_state(value)
self.window.toggle_preview(value)
def on_search(self, action, value):
def on_search(self, _action, _value):
self.window.open_search_and_replace()
def on_spellcheck(self, action, value):
action.set_state(value)
self.window.toggle_spellcheck(value)
def on_new(self, action, value):
def on_new(self, _action, _value):
self.window.new_document()
def on_open(self, action, value):
def on_open(self, _action, _value):
self.window.open_document()
def on_open_recent(self, action, value):
pass
def on_example(self, action, value):
def on_example(self, _action, _value):
self.window.open_uberwriter_markdown()
def on_save(self, action, value):
def on_save(self, _action, _value):
self.window.save_document()
def on_save_as(self, action, value):
def on_save_as(self, _action, _value):
self.window.save_document_as()
def on_export(self, action, value):
def on_export(self, _action, _value):
self.window.open_advanced_export()
def on_html_copy(self, action, value):
def on_html_copy(self, _action, _value):
self.window.copy_html_to_clipboard()
def on_preferences(self, action, value):
def on_preferences(self, _action, _value):
PreferencesWindow = PreferencesDialog()
PreferencesWindow.set_application(self)
PreferencesWindow.set_transient_for(self.window)
PreferencesWindow.show()
def on_quit(self, action, param):
def on_quit(self, _action, _param):
self.quit()
# ~ if __name__ == "__main__":

View File

@ -1,34 +1,35 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# BEGIN LICENSE
# Copyright (C) 2012, Wolf Vollprecht <w.vollprecht@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
# END LICENSE
### DO NOT EDIT THIS FILE ###
'''Enhances builder connections, provides object to access glade objects'''
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gtk # pylint: disable=E0611
import inspect
import functools
import logging
logger = logging.getLogger('uberwriter_lib')
from xml.etree.cElementTree import ElementTree
import gi
gi.require_version('Gtk', '3.0') # pylint: disable=wrong-import-position
from gi.repository import GObject, Gtk # pylint: disable=E0611
LOGGER = logging.getLogger('uberwriter_lib')
# this module is big so uses some conventional prefixes and postfixes
# *s list, except self.widgets is a dictionary
# *_dict dictionary
@ -57,7 +58,7 @@ class Builder(Gtk.Builder):
# pylint: disable=R0201
# this is a method so that a subclass of Builder can redefine it
def default_handler(self,
handler_name, filename, *args, **kwargs):
handler_name, filename, *args, **kwargs):
'''helps the apprentice guru
glade defined handlers that do not exist come here instead.
@ -65,7 +66,7 @@ class Builder(Gtk.Builder):
now he can define any likely candidates in glade and notice which
ones get triggered when he plays with the project.
this method does not appear in Gtk.Builder'''
logger.debug('''tried to call non-existent function:%s()
LOGGER.debug('''tried to call non-existent function:%s()
expected in %s
args:%s
kwargs:%s''', handler_name, filename, args, kwargs)
@ -101,8 +102,8 @@ class Builder(Gtk.Builder):
connections = [
(name,
ele_signal.attrib['name'],
ele_signal.attrib['handler']) for ele_signal in ele_signals]
ele_signal.attrib['name'],
ele_signal.attrib['handler']) for ele_signal in ele_signals]
if connections:
self.connections.extend(connections)
@ -110,7 +111,7 @@ class Builder(Gtk.Builder):
ele_signals = tree.getiterator("signal")
for ele_signal in ele_signals:
self.glade_handler_dict.update(
{ele_signal.attrib["handler"]: None})
{ele_signal.attrib["handler"]: None})
def connect_signals(self, callback_obj):
'''connect the handlers defined in glade
@ -131,8 +132,8 @@ class Builder(Gtk.Builder):
connection_dict[item[0]] = handler
# replace the run time warning
logger.warn("expected handler '%s' in %s",
item[0], filename)
LOGGER.warning("expected handler '%s' in %s",
item[0], filename)
# connect glade define handlers
Gtk.Builder.connect_signals(self, connection_dict)
@ -140,8 +141,8 @@ class Builder(Gtk.Builder):
# let's tell the user how we applied the glade design
for connection in self.connections:
widget_name, signal_name, handler_name = connection
logger.debug("connect builder by design '%s', '%s', '%s'",
widget_name, signal_name, handler_name)
LOGGER.debug("connect builder by design '%s', '%s', '%s'",
widget_name, signal_name, handler_name)
def get_ui(self, callback_obj=None, by_name=True):
'''Creates the ui object with widgets as attributes
@ -167,6 +168,7 @@ class Builder(Gtk.Builder):
# apart from the glade widgets
class UiFactory():
''' provides an object with attributes as glade widgets'''
def __init__(self, widget_dict):
self._widget_dict = widget_dict
for (widget_name, widget) in widget_dict.items():
@ -177,14 +179,14 @@ class UiFactory():
cannot_message = """cannot bind ui.%s, name already exists
consider using a pythonic name instead of design name '%s'"""
consider_message = """consider using a pythonic name instead of design name '%s'"""
for (widget_name, widget) in widget_dict.items():
pyname = make_pyname(widget_name)
if pyname != widget_name:
if hasattr(self, pyname):
logger.debug(cannot_message, pyname, widget_name)
LOGGER.debug(cannot_message, pyname, widget_name)
else:
logger.debug(consider_message, widget_name)
LOGGER.debug(consider_message, widget_name)
setattr(self, pyname, widget)
def iterator():
@ -203,14 +205,14 @@ def make_pyname(name):
pyname = ''
for character in name:
if (character.isalpha() or character == '_' or
(pyname and character.isdigit())):
(pyname and character.isdigit())):
pyname += character
else:
pyname += '_'
return pyname
# Until bug https://bugzilla.gnome.org/show_bug.cgi?id=652127 is fixed, we
# Until bug https://bugzilla.gnome.org/show_bug.cgi?id=652127 is fixed, we
# need to reimplement inspect.getmembers. GObject introspection doesn't
# play nice with it.
def getmembers(obj, check):
@ -233,10 +235,10 @@ def dict_from_callback_obj(callback_obj):
aliased_methods = [x[1] for x in methods if hasattr(x[1], 'aliases')]
# a method may have several aliases
#~ @alias('on_btn_foo_clicked')
#~ @alias('on_tool_foo_activate')
#~ on_menu_foo_activate():
#~ pass
# ~ @alias('on_btn_foo_clicked')
# ~ @alias('on_tool_foo_activate')
# ~ on_menu_foo_activate():
# ~ pass
alias_groups = [(x.aliases, x) for x in aliased_methods]
aliases = []
@ -287,13 +289,13 @@ def auto_connect_by_name(callback_obj, builder):
handler_names.append("on_%s" % sig)
do_connect(item, sig, handler_names,
callback_handler_dict, builder.connections)
callback_handler_dict, builder.connections)
log_unconnected_functions(callback_handler_dict, builder.connections)
def do_connect(item, signal_name, handler_names,
callback_handler_dict, connections):
callback_handler_dict, connections):
'''connect this signal to an unused handler'''
widget_name, widget = item
@ -305,8 +307,8 @@ def do_connect(item, signal_name, handler_names,
widget.connect(signal_name, callback_handler_dict[handler_name])
connections.append(connection)
logger.debug("connect builder by name '%s','%s', '%s'",
widget_name, signal_name, handler_name)
LOGGER.debug("connect builder by name '%s','%s', '%s'",
widget_name, signal_name, handler_name)
def log_unconnected_functions(callback_handler_dict, connections):
@ -324,4 +326,4 @@ def log_unconnected_functions(callback_handler_dict, connections):
pass
for handler_name in unconnected:
logger.debug("Not connected to builder '%s'", handler_name)
LOGGER.debug("Not connected to builder '%s'", handler_name)

View File

@ -16,11 +16,15 @@ COPYING
granted under the terms of the MIT License.
"""
import os, sys, tempfile, subprocess
import os
import sys
import tempfile
import subprocess
class LatexToPNG():
TEX_HEADER = r'''\documentclass{article}
TEX_HEADER = r'''\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{amssymb}
@ -30,79 +34,79 @@ class LatexToPNG():
\newcommand{\T}{\text{T}} % Transpose
\pagestyle{empty}
\begin{document}'''
TEX_FOOTER = r'''\end{document}'''
def __init__(self):
self.temp_result = tempfile.NamedTemporaryFile(suffix='.png')
TEX_FOOTER = r'''\end{document}'''
def latex2png(self, tex, outfile, dpi, modified):
'''Convert LaTeX input file infile to PNG file named outfile.'''
outfile = os.path.abspath(outfile)
outdir = os.path.dirname(outfile)
texfile = tempfile.mktemp(suffix='.tex', dir=os.path.dirname(outfile))
basefile = os.path.splitext(texfile)[0]
dvifile = basefile + '.dvi'
temps = [basefile + ext for ext in ('.tex','.dvi', '.aux', '.log')]
skip = False
tex = '%s\n%s\n%s\n' % (self.TEX_HEADER, tex.strip(), self.TEX_FOOTER)
def __init__(self):
self.temp_result = tempfile.NamedTemporaryFile(suffix='.png')
open(texfile, 'w').write(tex)
saved_pwd = os.getcwd()
def latex2png(self, tex, outfile, dpi, modified):
'''Convert LaTeX input file infile to PNG file named outfile.'''
outfile = os.path.abspath(outfile)
outdir = os.path.dirname(outfile)
texfile = tempfile.mktemp(suffix='.tex', dir=os.path.dirname(outfile))
basefile = os.path.splitext(texfile)[0]
dvifile = basefile + '.dvi'
temps = [basefile + ext for ext in ('.tex', '.dvi', '.aux', '.log')]
skip = False
os.chdir(outdir)
args = ['latex', '-halt-on-error', texfile]
p = subprocess.Popen(args,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE)
tex = '%s\n%s\n%s\n' % (self.TEX_HEADER, tex.strip(), self.TEX_FOOTER)
output = p.stdout
output_lines = output.readlines()
if os.path.isfile(dvifile): # DVI File exists
# Convert DVI file to PNG.
args = ['dvipng',
'-D', str(dpi),
'-T', 'tight',
'-x', '1000',
'-z', '9',
'-bg', 'Transparent',
'-o', outfile,
dvifile]
open(texfile, 'w').write(tex)
saved_pwd = os.getcwd()
p = subprocess.Popen(args)
p.communicate()
else:
self.clean_up(temps)
'''
os.chdir(outdir)
args = ['latex', '-halt-on-error', texfile]
p = subprocess.Popen(args,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE)
output = p.stdout
output_lines = output.readlines()
if os.path.isfile(dvifile): # DVI File exists
# Convert DVI file to PNG.
args = ['dvipng',
'-D', str(dpi),
'-T', 'tight',
'-x', '1000',
'-z', '9',
'-bg', 'Transparent',
'-o', outfile,
dvifile]
p = subprocess.Popen(args)
p.communicate()
else:
self.clean_up(temps)
'''
Errors in Latex output start with "! "
Stripping exclamation marks and superflous newlines
and telling the user what he's done wrong.
'''
i = []
error = ""
for line in output_lines:
line = line.decode('utf-8')
if line.startswith("!"):
error += line[2:] # removing "! "
if error.endswith("\n"):
error = error[:-1]
raise Exception(error)
i = []
error = ""
for line in output_lines:
line = line.decode('utf-8')
if line.startswith("!"):
error += line[2:] # removing "! "
if error.endswith("\n"):
error = error[:-1]
raise Exception(error)
def generatepng(self, formula):
try:
self.temp_result = tempfile.NamedTemporaryFile(suffix='.png')
formula = "$" + formula + "$"
self.latex2png(formula, self.temp_result.name, 300, False)
return (True, self.temp_result.name)
def generatepng(self, formula):
try:
self.temp_result = tempfile.NamedTemporaryFile(suffix='.png')
formula = "$" + formula + "$"
self.latex2png(formula, self.temp_result.name, 300, False)
return (True, self.temp_result.name)
except Exception as e:
self.temp_result.close()
return (False, e.args[0])
except Exception as e:
self.temp_result.close()
return (False, e.args[0])
def clean_up(self, files):
for f in files:
if os.path.isfile(f):
os.remove(f)
def clean_up(self, files):
for f in files:
if os.path.isfile(f):
os.remove(f)

View File

@ -1,39 +1,34 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# BEGIN LICENSE
# Copyright (C) 2012, Wolf Vollprecht <w.vollprecht@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
# END LICENSE
### DO NOT EDIT THIS FILE ###
"""Helpers for an Ubuntu application."""
"""Helpers for the application."""
import logging
import os
import sys
import shutil
from . uberwriterconfig import get_data_file
from . Builder import Builder
import locale
import gettext
from gettext import gettext as _
def get_builder(builder_file_name):
"""Return a fully-instantiated Gtk.Builder instance from specified ui
"""Return a fully-instantiated Gtk.Builder instance from specified ui
file
:param builder_file_name: The name of the builder file, without extension.
Assumed to be in the 'ui' directory under the data path.
"""
@ -50,35 +45,50 @@ def get_builder(builder_file_name):
# Owais Lone : To get quick access to icons and stuff.
def get_media_file(media_file_name):
"""Return the full path of a given filename under the media dir
(starts with file:///)
"""
media_filename = get_data_file('media', '%s' % (media_file_name,))
if not os.path.exists(media_filename):
media_filename = None
return "file:///"+media_filename
return "file:///" + media_filename
def get_media_path(media_file_name):
"""Return the full path of a given filename under the media dir
(doesn't start with file:///)
"""
media_filename = get_data_file('media', '%s' % (media_file_name,))
if not os.path.exists(media_filename):
media_filename = None
return media_filename
def get_script_path(script_file_name):
"""Return the full path of a given filename under the script dir
"""
script_filename = get_data_file('lua', '%s' % (script_file_name,))
if not os.path.exists(script_filename):
script_filename = None
return script_filename
class NullHandler(logging.Handler):
def emit(self, record):
pass
def set_up_logging(opts):
# add a handler to prevent basicConfig
root = logging.getLogger()
null_handler = NullHandler()
root.addHandler(null_handler)
formatter = logging.Formatter("%(levelname)s:%(name)s: %(funcName)s() '%(message)s'")
formatter = logging.Formatter(
"%(levelname)s:%(name)s: %(funcName)s() '%(message)s'")
logger = logging.getLogger('uberwriter')
logger_sh = logging.StreamHandler()
@ -97,6 +107,7 @@ def set_up_logging(opts):
if opts.verbose and opts.verbose > 1:
lib_logger.setLevel(logging.DEBUG)
def get_help_uri(page=None):
# help_uri from source tree - default language
here = os.path.dirname(__file__)
@ -112,11 +123,13 @@ def get_help_uri(page=None):
return help_uri
def show_uri(parent, link):
from gi.repository import Gtk # pylint: disable=E0611
from gi.repository import Gtk # pylint: disable=E0611
screen = parent.get_screen()
Gtk.show_uri(screen, link, Gtk.get_current_event_time())
def alias(alternative_function_name):
'''see http://www.drdobbs.com/web-development/184406073#l9'''
def decorator(function):
@ -127,5 +140,15 @@ def alias(alternative_function_name):
return function
return decorator
def exist_executable(command):
return shutil.which(command) is not None
"""return if a command can be executed in the SO
Arguments:
command {str} -- a command
Returns:
{bool} -- if the given command exists in the system
"""
return shutil.which(command) is not None

View File

@ -1,16 +1,16 @@
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# Copyright (C) 2012, Wolf Vollprecht <w.vollprecht@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
@ -30,9 +30,7 @@ __version__ = 'VERSION'
import os
from locale import gettext as _
class project_path_not_found(Exception):
class ProjectPathNotFound(Exception):
"""Raised when we can't find the project directory."""
@ -68,7 +66,7 @@ def get_data_path():
if not os.path.exists(abs_data_path):
abs_data_path = '/opt/uberwriter/data/'
elif not os.path.exists(abs_data_path):
raise project_path_not_found
raise ProjectPathNotFound
return abs_data_path