diff --git a/ui/preferences.ui b/ui/preferences.ui
index 1162b2d..ea7209b 100644
--- a/ui/preferences.ui
+++ b/ui/preferences.ui
@@ -27,33 +27,33 @@
-
- Load recent file on startup
+ Load most recent file
-
- Strip readings from loaded files
+ Strip readings from files
-
- Check for updates on startup
+ Check for updates
-
- Maximum scan length
+ Text scan length
-
-
+
0
diff --git a/yomi_base/defaults.json b/yomi_base/defaults.json
index b02cfd6..1dd6b4d 100644
--- a/yomi_base/defaults.json
+++ b/yomi_base/defaults.json
@@ -1,13 +1,13 @@
{
+ "bgColor": 4294967295,
"checkForUpdates": true,
- "colorBg": 4294967295,
- "colorFg": 4278190080,
- "decks": [],
- "fantFamily": "Arial",
+ "fontFamily": "Arial",
+ "fgColor": 4278190080,
"fontSize": 12,
"loadRecentFile": true,
"recentFiles": [],
"scanLength": 16,
"stripReadings": false,
+ "tags": [],
"wordWrap": false
-}
\ No newline at end of file
+}
diff --git a/yomi_base/japanese/__init__.py b/yomi_base/japanese/__init__.py
index 25f19ee..77ab2a1 100644
--- a/yomi_base/japanese/__init__.py
+++ b/yomi_base/japanese/__init__.py
@@ -23,7 +23,7 @@ import translate
def initLanguage():
- directory = os.path.split(__file__)[0]
+ directory = os.path.dirname(__file__)
return translate.Translator(
deinflect.Deinflector(os.path.join(directory, 'deinflect.json')),
dictionary.Dictionary(os.path.join(directory, 'dictionary.db'))
diff --git a/yomi_base/preference_data.py b/yomi_base/preference_data.py
index 2626e7a..30872b6 100644
--- a/yomi_base/preference_data.py
+++ b/yomi_base/preference_data.py
@@ -16,245 +16,63 @@
# along with this program. If not, see .
-from PyQt4 import QtCore, QtGui
-from xml.dom import minidom
+import codecs
+import json
+import operator
import os
-class Preferences:
+class Preferences(object):
def __init__(self):
- self.clear()
+ self.filename = os.path.expanduser('~/.yomichan.json')
+ self.defaults = os.path.join(os.path.dirname(__file__), 'defaults.json')
+ self.settings = dict()
- def clear(self):
- self.generalFindUpdates = True
- self.generalReadingsStrip = False
- self.generalRecentLoad = True
- self.generalRecentFiles = list()
- self.generalRecentMax = 10
-
- self.uiContentFontFamily = 'Arial'
- self.uiContentFontSize = 12
- self.uiContentColorFg = QtGui.QColor(QtCore.Qt.black).rgba()
- self.uiContentColorBg = QtGui.QColor(QtCore.Qt.white).rgba()
- self.uiContentWordWrap = False
-
- self.uiReaderState = None
- self.uiReaderPosition = None
- self.uiReaderSize = None
-
- self.searchScanMax = 16
- self.searchResultMax = 32
- self.searchGroupByExp = True
-
- self.ankiFields = dict()
- self.ankiTags = list()
- self.ankiDeck = unicode()
- self.ankiModel = unicode()
+ def __getitem__(self, name):
+ return self.settings.get(name)
- def load(self, filename=None):
- if not filename:
- filename = self.defaultFilename()
+ def __setitem__(self, name, value):
+ self.settings[name] = value
+
+
+ def load(self):
+ with codecs.open(self.defaults, 'rb', 'utf-8') as fp:
+ self.settings = json.load(fp)
try:
- doc = minidom.parse(filename)
- except:
- return False
-
- root = doc.documentElement
- if root.nodeName != 'yomichan':
- return False
-
- self.clear()
-
- for general in root.getElementsByTagName('general'):
- self.generalRecentLoad = self.readAttrBool(general, 'recentLoad', self.generalRecentLoad)
- self.generalReadingsStrip = self.readAttrBool(general, 'readingsStrip', self.generalReadingsStrip)
- self.generalFindUpdates = self.readAttrBool(general, 'findUpdates', self.generalFindUpdates)
-
- for recent in general.getElementsByTagName('recent'):
- path = self.readAttrStr(recent, 'path')
- position = self.readAttrInt(recent, 'position')
- if path and os.path.isfile(path):
- self.generalRecentFiles.append((path, position))
-
- for ui in root.getElementsByTagName('ui'):
- for content in ui.getElementsByTagName('content'):
- self.uiContentFontFamily = self.readAttrStr(content, 'fontFamily', self.uiContentFontFamily)
- self.uiContentFontSize = self.readAttrInt(content, 'fontSize', self.uiContentFontSize)
- self.uiContentColorFg = self.readAttrInt(content, 'colorFg', self.uiContentColorFg)
- self.uiContentColorBg = self.readAttrInt(content, 'colorBg', self.uiContentColorBg)
- self.uiContentWordWrap = self.readAttrBool(content, 'wordWrap', self.uiContentWordWrap)
-
- for reader in ui.getElementsByTagName('reader'):
- self.uiReaderState = self.readAttrStr(reader, 'state', self.uiReaderState)
- self.uiReaderPosition = self.readAttrIntTuple(reader, 'position', self.uiReaderPosition)
- self.uiReaderSize = self.readAttrIntTuple(reader, 'size', self.uiReaderSize)
-
- for search in root.getElementsByTagName('search'):
- self.searchScanMax = self.readAttrInt(search, 'scanMax', self.searchScanMax)
- self.searchResultMax = self.readAttrInt(search, 'resultMax', self.searchResultMax)
- self.searchGroupByExp = self.readAttrBool(search, 'groupByExp', self.searchGroupByExp)
-
- for anki in root.getElementsByTagName('anki'):
- self.ankiDeck = self.readAttrStr(anki, 'deck', unicode())
- self.ankiModel = self.readAttrStr(anki, 'model', unicode())
-
- for tag in anki.getElementsByTagName('tag'):
- value = self.readAttrStr(tag, 'value', unicode())
- self.ankiTags.append(value)
-
- for model in anki.getElementsByTagName('model'):
- for field in model.getElementsByTagName('field'):
- name = self.readAttrStr(field, 'name')
- value = self.readAttrStr(field, 'value')
- if name and value:
- self.ankiFields[name] = value
-
- return True
+ if os.path.exists(self.filename):
+ with codecs.open(self.filename, 'rb', 'utf-8') as fp:
+ self.settings.update(json.load(fp))
+ except ValueError:
+ pass
- def save(self, filename=None):
- if not filename:
- filename = self.defaultFilename()
-
- directory = os.path.split(filename)[0]
- if not os.path.isdir(directory):
- try:
- os.makedirs(directory)
- except OSError:
- return False
-
- doc = minidom.Document()
- root = doc.createElement('yomichan')
- doc.appendChild(root)
-
- general = doc.createElement('general')
- root.appendChild(general)
- self.writeAttrBool(general, 'recentLoad', self.generalRecentLoad)
- self.writeAttrBool(general, 'readingsStrip', self.generalReadingsStrip)
- self.writeAttrBool(general, 'findUpdates', self.generalFindUpdates)
- for path, position in self.generalRecentFiles:
- recent = doc.createElement('recent')
- general.appendChild(recent)
- self.writeAttrStr(recent, 'path', path)
- self.writeAttrInt(recent, 'position', position)
-
- ui = doc.createElement('ui')
- root.appendChild(ui)
-
- content = doc.createElement('content')
- ui.appendChild(content)
- self.writeAttrStr(content, 'fontFamily', self.uiContentFontFamily)
- self.writeAttrInt(content, 'fontSize', self.uiContentFontSize)
- self.writeAttrInt(content, 'colorFg', self.uiContentColorFg)
- self.writeAttrInt(content, 'colorBg', self.uiContentColorBg)
- self.writeAttrBool(content, 'wordWrap', self.uiContentWordWrap)
-
- reader = doc.createElement('reader')
- ui.appendChild(reader)
- self.writeAttrStr(reader, 'state', self.uiReaderState)
- self.writeAttrIntTuple(reader, 'position', self.uiReaderPosition)
- self.writeAttrIntTuple(reader, 'size', self.uiReaderSize)
-
- search = doc.createElement('search')
- root.appendChild(search)
- self.writeAttrInt(search, 'scanMax', self.searchScanMax)
- self.writeAttrInt(search, 'resultMax', self.searchResultMax)
- self.writeAttrBool(search, 'groupByExp', self.searchGroupByExp)
-
- anki = doc.createElement('anki')
- root.appendChild(anki)
- self.writeAttrStr(anki, 'deck', self.ankiDeck)
- self.writeAttrStr(anki, 'model', self.ankiModel)
-
- for value in self.ankiTags:
- tag = doc.createElement('tag')
- anki.appendChild(tag)
- self.writeAttrStr(tag, 'value', value)
-
- if self.ankiFields:
- model = doc.createElement('model')
- anki.appendChild(model)
- for name, value in self.ankiFields.items():
- field = doc.createElement('field')
- model.appendChild(field)
- self.writeAttrStr(field, 'name', name)
- self.writeAttrStr(field, 'value', value)
-
- try:
- with open(filename, 'w') as fp:
- fp.write(doc.toprettyxml(encoding='utf-8'))
- except IOError:
- return False
-
- return True
-
-
- def defaultFilename(self):
- return os.path.expanduser('~/.yomichan/preferences.xml')
+ def save(self):
+ with codecs.open(self.filename, 'wb', 'utf-8') as fp:
+ json.dump(self.settings, fp, indent=4, sort_keys=True)
def filePosition(self, filename):
- results = filter(lambda x: x[0] == filename, self.generalRecentFiles)
- return results[0][1] if results else 0
+ matches = filter(lambda f: f['path'] != filename, self['recentFiles'])
+ return 0 if len(matches) == 0 else matches[0]['position']
def recentFiles(self):
- return map(lambda x: x[0], self.generalRecentFiles)
+ return map(operator.itemgetter('path'), self['recentFiles'])
def updateFactTags(self, tags):
- if tags in self.ankiTags:
- self.ankiTags.remove(tags)
- self.ankiTags.insert(0, tags)
+ if tags in self['tags']:
+ self['tags'].remove(tags)
+ self['tags'].insert(0, tags)
def updateRecentFile(self, filename, position):
- self.generalRecentFiles = filter(lambda x: x[0] != filename, self.generalRecentFiles)
- self.generalRecentFiles.insert(0, (filename, position))
- self.generalRecentFiles = self.generalRecentFiles[:self.generalRecentMax]
+ self['recentFiles'] = filter(lambda f: f['path'] != filename, self['recentFiles'])
+ self['recentFiles'].insert(0, {'path': filename, 'position': position})
def clearRecentFiles(self):
- self.generalRecentFiles = list()
-
-
- def readAttrStr(self, node, name, default=None):
- return node.getAttribute(name) or default
-
-
- def readAttrBool(self, node, name, default=False):
- value = self.readAttrStr(node, name)
- return value.lower() == 'true' if value else default
-
-
- def readAttrInt(self, node, name, default=0):
- value = self.readAttrStr(node, name)
- return int(value) if value else default
-
-
- def readAttrIntTuple(self, node, name, default=None):
- value = self.readAttrStr(node, name)
- return tuple([int(v) for v in value.split(',')]) if value else default
-
-
- def writeAttrStr(self, node, name, value):
- if value != None:
- node.setAttribute(name, value)
-
-
- def writeAttrBool(self, node, name, value):
- if value != None:
- node.setAttribute(name, ['false', 'true'][bool(value)])
-
-
- def writeAttrInt(self, node, name, value):
- if value != None:
- node.setAttribute(name, str(value))
-
-
- def writeAttrIntTuple(self, node, name, value):
- if value != None:
- node.setAttribute(name, ','.join([str(v) for v in value]))
+ self['recentFiles'] = list()
diff --git a/yomi_base/reader.py b/yomi_base/reader.py
index e0c82c2..59bf2ac 100644
--- a/yomi_base/reader.py
+++ b/yomi_base/reader.py
@@ -61,9 +61,9 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
if filename:
self.openFile(filename)
- elif self.preferences.generalRecentLoad:
+ elif self.preferences['loadRecentFile']:
filenames = self.preferences.recentFiles()
- if filenames:
+ if len(filenames) > 0:
self.openFile(filenames[0])
self.actionOpen.triggered.connect(self.onActionOpen)
@@ -88,40 +88,40 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
self.dockAnki.visibilityChanged.connect(self.onVisibilityChanged)
self.updateFinder.updateResult.connect(self.onUpdaterSearchResult)
- if self.preferences.generalFindUpdates:
+ if self.preferences['checkForUpdates']:
self.updateFinder.start()
def applyPreferences(self):
- if self.preferences.uiReaderState is not None:
- self.restoreState(QtCore.QByteArray.fromBase64(self.preferences.uiReaderState))
- if self.preferences.uiReaderPosition is not None:
- self.move(QtCore.QPoint(*self.preferences.uiReaderPosition))
- if self.preferences.uiReaderSize is not None:
- self.resize(QtCore.QSize(*self.preferences.uiReaderSize))
+ if self.preferences['windowState'] is not None:
+ self.restoreState(QtCore.QByteArray.fromBase64(self.preferences['windowState']))
+ if self.preferences['windowPosition'] is not None:
+ self.move(QtCore.QPoint(*self.preferences['windowPosition']))
+ if self.preferences['windowSize'] is not None:
+ self.resize(QtCore.QSize(*self.preferences['windowSize']))
- self.comboTags.addItems(self.preferences.ankiTags)
+ self.comboTags.addItems(self.preferences['tags'])
self.applyPreferencesContent()
def applyPreferencesContent(self):
palette = self.textContent.palette()
- palette.setColor(QtGui.QPalette.Base, QtGui.QColor(self.preferences.uiContentColorBg))
- palette.setColor(QtGui.QPalette.Text, QtGui.QColor(self.preferences.uiContentColorFg))
+ palette.setColor(QtGui.QPalette.Base, QtGui.QColor(self.preferences['bgColor']))
+ palette.setColor(QtGui.QPalette.Text, QtGui.QColor(self.preferences['fgColor']))
self.textContent.setPalette(palette)
font = self.textContent.font()
- font.setFamily(self.preferences.uiContentFontFamily)
- font.setPointSize(self.preferences.uiContentFontSize + self.zoom)
- self.textContent.setLineWrapMode(self.preferences.uiContentWordWrap)
+ font.setFamily(self.preferences['fontFamily'])
+ font.setPointSize(self.preferences['fontSize'] + self.zoom)
+ self.textContent.setLineWrapMode(self.preferences['wordWrap'])
self.textContent.setFont(font)
- self.actionToggleWrap.setChecked(self.preferences.uiContentWordWrap)
+ self.actionToggleWrap.setChecked(self.preferences['wordWrap'])
def closeEvent(self, event):
self.closeFile()
- self.preferences.uiReaderState = self.saveState().toBase64()
+ self.preferences['windowState'] = str(self.saveState().toBase64())
self.preferences.save()
if self.anki is not None:
@@ -148,11 +148,11 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
def moveEvent(self, event):
- self.preferences.uiReaderPosition = (event.pos().x(), event.pos().y())
+ self.preferences['windowPosition'] = event.pos().x(), event.pos().y()
def resizeEvent(self, event):
- self.preferences.uiReaderSize = (event.size().width(), event.size().height())
+ self.preferences['windowSize'] = event.size().width(), event.size().height()
def onActionOpen(self):
@@ -219,7 +219,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
def onActionToggleWrap(self, wrap):
mode = QtGui.QPlainTextEdit.WidgetWidth if wrap else QtGui.QPlainTextEdit.NoWrap
- self.preferences.uiContentWordWrap = wrap
+ self.preferences['wordWrap'] = wrap
self.textContent.setLineWrapMode(wrap)
@@ -328,7 +328,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
self.updateRecentFiles()
content, encoding = reader_util.decodeContent(content)
- if self.preferences.generalReadingsStrip:
+ if self.preferences['stripReadings']:
content = reader_util.stripContentReadings(content)
self.textContent.setPlainText(content)
@@ -339,7 +339,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
self.textContent.centerCursor()
self.setStatus(u'Loaded file {0}'.format(filename))
- self.setWindowTitle(u'Yomichan - {0} ({1})'.format(os.path.split(filename)[1], encoding))
+ self.setWindowTitle(u'Yomichan - {0} ({1})'.format(os.path.basename(filename), encoding))
def openFileByExtension(self, filename):
@@ -433,7 +433,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
if self.anki is None:
return False
- fields = reader_util.replaceMarkupInFields(self.preferences.ankiFields, markup)
+ fields = reader_util.replaceMarkupInFields(self.preferences['tags'], markup)
tagsSplit = reader_util.splitTags(unicode(self.comboTags.currentText()))
tagsJoined = ' '.join(tagsSplit)
@@ -444,6 +444,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
self.comboTags.insertItem(0, tagsJoined)
self.preferences.updateFactTags(tagsJoined)
+ #FIXME
factId = self.anki.addNote(self.preferences.ankiDeck, self.preferences.ankiModel, fields, tagsSplit)
if factId is None:
return False
@@ -463,6 +464,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
def ankiIsFactValid(self, markup):
+ #FIXME
if self.anki is not None:
fields = reader_util.replaceMarkupInFields(self.preferences.ankiFields, markup)
return self.anki.canAddNote(self.preferences.ankiDeck, self.preferences.ankiModel, fields)
@@ -479,7 +481,7 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
def updateSampleFromPosition(self):
samplePosStart = self.state.scanPosition
- samplePosEnd = self.state.scanPosition + self.preferences.searchScanMax
+ samplePosEnd = self.state.scanPosition + self.preferences['scanLength']
cursor = self.textContent.textCursor()
content = unicode(self.textContent.toPlainText())
@@ -544,11 +546,11 @@ class MainWindowReader(QtGui.QMainWindow, reader_ui.Ui_MainWindowReader):
self.menuOpenRecent.clear()
filenames = self.preferences.recentFiles()
- if not filenames:
+ if len(filenames) == 0:
return
for filename in filenames:
- self.menuOpenRecent.addAction(filename, lambda fn=filename: self.openFile(fn))
+ self.menuOpenRecent.addAction(filename, lambda f=filename: self.openFile(f))
self.menuOpenRecent.addSeparator()
self.menuOpenRecent.addAction('Clear file history', self.clearRecentFiles)