mirror of
https://github.com/wassname/FanFicFare.git
synced 2026-09-09 11:14:08 +08:00
Merge default with branch.
This commit is contained in:
+67
-48
@@ -13,6 +13,8 @@ logger = logging.getLogger(__name__)
|
||||
import traceback, copy, threading
|
||||
from collections import OrderedDict
|
||||
|
||||
from ConfigParser import ParsingError
|
||||
|
||||
try:
|
||||
from PyQt5.Qt import (QDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
||||
QLineEdit, QFont, QWidget, QTextEdit, QComboBox,
|
||||
@@ -40,7 +42,7 @@ else:
|
||||
return x.toPyObject()
|
||||
|
||||
from calibre.gui2.ui import get_gui
|
||||
from calibre.gui2 import dynamic, info_dialog
|
||||
from calibre.gui2 import dynamic, info_dialog, question_dialog
|
||||
from calibre.constants import numeric_version as calibre_version
|
||||
|
||||
# pulls in translation files for _() strings
|
||||
@@ -73,7 +75,7 @@ no_trans = { 'pini':'personal.ini',
|
||||
from calibre_plugins.fanfictiondownloader_plugin.prefs import prefs, PREFS_NAMESPACE
|
||||
from calibre_plugins.fanfictiondownloader_plugin.dialogs \
|
||||
import (UPDATE, UPDATEALWAYS, collision_order, save_collisions, RejectListDialog,
|
||||
EditTextDialog, RejectUrlEntry)
|
||||
EditTextDialog, RejectUrlEntry, errors_dialog)
|
||||
|
||||
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.adapters \
|
||||
import getConfigSections
|
||||
@@ -81,6 +83,8 @@ from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.adapters \
|
||||
from calibre_plugins.fanfictiondownloader_plugin.common_utils \
|
||||
import ( KeyboardConfigDialog, PrefsViewerDialog )
|
||||
|
||||
from calibre_plugins.fanfictiondownloader_plugin.ffdl_util import (get_ffdl_config)
|
||||
|
||||
from calibre.gui2.complete2 import EditWithComplete #MultiCompleteLineEdit
|
||||
|
||||
class RejectURLList:
|
||||
@@ -255,7 +259,7 @@ class ConfigWidget(QWidget):
|
||||
prefs['addtolistsonread'] = self.readinglist_tab.addtolistsonread.isChecked()
|
||||
|
||||
# personal.ini
|
||||
ini = unicode(self.personalini_tab.ini.toPlainText())
|
||||
ini = self.personalini_tab.personalini
|
||||
if ini:
|
||||
prefs['personal.ini'] = ini
|
||||
else:
|
||||
@@ -541,10 +545,6 @@ class BasicTab(QWidget):
|
||||
if i > -1:
|
||||
self.collision.setCurrentIndex(i)
|
||||
|
||||
def show_defaults(self):
|
||||
text = get_resources('plugin-defaults.ini')
|
||||
ShowDefaultsIniDialog(self.windowIcon(),text,self).exec_()
|
||||
|
||||
def show_rejectlist(self):
|
||||
d = RejectListDialog(self,
|
||||
rejecturllist.get_list(),
|
||||
@@ -565,7 +565,9 @@ class BasicTab(QWidget):
|
||||
icon=self.windowIcon(),
|
||||
title=_("Reject Reasons"),
|
||||
label=_("Customize Reject List Reasons"),
|
||||
tooltip=_("Customize the Reasons presented when Rejecting URLs"))
|
||||
tooltip=_("Customize the Reasons presented when Rejecting URLs"),
|
||||
save_size_name='ffdl:Reject List Reasons',
|
||||
use_find=True)
|
||||
d.exec_()
|
||||
if d.result() == d.Accepted:
|
||||
prefs['rejectreasons'] = d.get_plain_text()
|
||||
@@ -578,7 +580,8 @@ class BasicTab(QWidget):
|
||||
label=_("Add Reject URLs. Use: <b>http://...,note</b> or <b>http://...,title by author - note</b><br>Invalid story URLs will be ignored."),
|
||||
tooltip=_("One URL per line:\n<b>http://...,note</b>\n<b>http://...,title by author - note</b>"),
|
||||
rejectreasons=rejecturllist.get_reject_reasons(),
|
||||
reasonslabel=_('Add this reason to all URLs added:'))
|
||||
reasonslabel=_('Add this reason to all URLs added:'),
|
||||
save_size_name='ffdl:Add Reject List')
|
||||
d.exec_()
|
||||
if d.result() == d.Accepted:
|
||||
rejecturllist.add_text(d.get_plain_text(),d.get_reason_text())
|
||||
@@ -601,16 +604,25 @@ class PersonalIniTab(QWidget):
|
||||
self.label = QLabel('personal.ini:')
|
||||
self.l.addWidget(self.label)
|
||||
|
||||
self.ini = QTextEdit(self)
|
||||
try:
|
||||
self.ini.setFont(QFont("Courier",
|
||||
self.plugin_action.gui.font().pointSize()+1))
|
||||
except Exception as e:
|
||||
logger.error("Couldn't get font: %s"%e)
|
||||
self.ini.setLineWrapMode(QTextEdit.NoWrap)
|
||||
self.ini.setText(prefs['personal.ini'])
|
||||
self.l.addWidget(self.ini)
|
||||
# self.ini = QTextEdit(self)
|
||||
# try:
|
||||
# self.ini.setFont(QFont("Courier",
|
||||
# self.plugin_action.gui.font().pointSize()+1))
|
||||
# except Exception as e:
|
||||
# logger.error("Couldn't get font: %s"%e)
|
||||
# self.ini.setLineWrapMode(QTextEdit.NoWrap)
|
||||
# self.ini.setText(prefs['personal.ini'])
|
||||
# self.l.addWidget(self.ini)
|
||||
|
||||
self.personalini = prefs['personal.ini']
|
||||
|
||||
self.ini_button = QPushButton(_('Edit personal.ini'), self)
|
||||
self.ini_button.setToolTip(_("Edit personal.ini file."))
|
||||
self.ini_button.clicked.connect(self.add_ini_button)
|
||||
self.l.addWidget(self.ini_button)
|
||||
|
||||
|
||||
|
||||
self.defaults = QPushButton(_('View Defaults')+' (plugin-defaults.ini)', self)
|
||||
self.defaults.setToolTip(_("View all of the plugin's configurable settings\nand their default settings."))
|
||||
self.defaults.clicked.connect(self.show_defaults)
|
||||
@@ -620,38 +632,45 @@ class PersonalIniTab(QWidget):
|
||||
# let edit box fill the space.
|
||||
|
||||
def show_defaults(self):
|
||||
text = get_resources('plugin-defaults.ini')
|
||||
ShowDefaultsIniDialog(self.windowIcon(),text,self).exec_()
|
||||
EditTextDialog(self,
|
||||
get_resources('plugin-defaults.ini'),
|
||||
icon=self.windowIcon(),
|
||||
title=_('Plugin Defaults'),
|
||||
label=_("Plugin Defaults (%s) (Read-Only)")%'plugin-defaults.ini',
|
||||
tooltip=_("These are all of the plugin's configurable options\nand their default settings."),
|
||||
use_find=True,
|
||||
read_only=True,
|
||||
save_size_name='ffdl:defaults.ini').exec_()
|
||||
|
||||
class ShowDefaultsIniDialog(QDialog):
|
||||
def add_ini_button(self):
|
||||
d = EditTextDialog(self,
|
||||
self.personalini,
|
||||
icon=self.windowIcon(),
|
||||
title=_("Edit personal.ini"),
|
||||
label=_("Edit personal.ini"),
|
||||
tooltip=_("Edit personal.ini"),
|
||||
use_find=True,
|
||||
save_size_name='ffdl:personal.ini')
|
||||
error=False
|
||||
while not error:
|
||||
error=True
|
||||
d.exec_()
|
||||
if d.result() == d.Accepted:
|
||||
self.personalini = unicode(d.get_plain_text())
|
||||
|
||||
def __init__(self, icon, text, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.resize(600, 500)
|
||||
self.l = QVBoxLayout()
|
||||
self.setLayout(self.l)
|
||||
self.label = QLabel(_("Plugin Defaults (%s) (Read-Only)")%'plugin-defaults.ini')
|
||||
self.label.setToolTip(_("These are all of the plugin's configurable options\nand their default settings."))
|
||||
self.setWindowTitle(_('Plugin Defaults'))
|
||||
self.setWindowIcon(icon)
|
||||
self.l.addWidget(self.label)
|
||||
|
||||
self.ini = QTextEdit(self)
|
||||
self.ini.setToolTip(_("These are all of the plugin's configurable options\nand their default settings."))
|
||||
try:
|
||||
self.ini.setFont(QFont("Courier",
|
||||
get_gui().font().pointSize()+1))
|
||||
except Exception as e:
|
||||
logger.error("Couldn't get font: %s"%e)
|
||||
self.ini.setLineWrapMode(QTextEdit.NoWrap)
|
||||
self.ini.setText(text)
|
||||
self.ini.setReadOnly(True)
|
||||
self.l.addWidget(self.ini)
|
||||
|
||||
self.ok_button = QPushButton(_('OK'), self)
|
||||
self.ok_button.clicked.connect(self.hide)
|
||||
self.l.addWidget(self.ok_button)
|
||||
|
||||
try:
|
||||
configini = get_ffdl_config("test1.com?sid=555",
|
||||
personalini=self.personalini)
|
||||
|
||||
errors = configini.test_config()
|
||||
except ParsingError as pe:
|
||||
errors = pe.errors
|
||||
|
||||
if errors:
|
||||
error = not errors_dialog(self.plugin_action.gui,
|
||||
_('Go back to fix errors?'),
|
||||
'<p>'+'</p><p>'.join([ '%s %s'%e for e in errors ])+'</p>')
|
||||
|
||||
class ReadingListTab(QWidget):
|
||||
|
||||
def __init__(self, parent_dialog, plugin_action):
|
||||
|
||||
+284
-9
@@ -4,7 +4,7 @@ from __future__ import (unicode_literals, division,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Jim Miller'
|
||||
__copyright__ = '2014, Jim Miller'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import logging
|
||||
@@ -23,18 +23,22 @@ from datetime import datetime
|
||||
|
||||
try:
|
||||
from PyQt5 import QtWidgets as QtGui
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.Qt import (QDialog, QTableWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QPushButton, QLabel, QCheckBox, QIcon, QLineEdit,
|
||||
QPushButton, QFont, QLabel, QCheckBox, QIcon, QLineEdit,
|
||||
QComboBox, QProgressDialog, QTimer, QDialogButtonBox,
|
||||
QPixmap, Qt, QAbstractItemView, QTextEdit, pyqtSignal,
|
||||
QGroupBox, QFrame)
|
||||
QGroupBox, QFrame, QTextBrowser, QSize, QAction,
|
||||
QSyntaxHighlighter, QTextCharFormat, QBrush )
|
||||
except ImportError as e:
|
||||
from PyQt4 import QtGui
|
||||
from PyQt4 import QtCore
|
||||
from PyQt4.Qt import (QDialog, QTableWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QPushButton, QLabel, QCheckBox, QIcon, QLineEdit,
|
||||
QPushButton, QFont, QLabel, QCheckBox, QIcon, QLineEdit,
|
||||
QComboBox, QProgressDialog, QTimer, QDialogButtonBox,
|
||||
QPixmap, Qt, QAbstractItemView, QTextEdit, pyqtSignal,
|
||||
QGroupBox, QFrame)
|
||||
QGroupBox, QFrame, QTextBrowser, QSize, QAction, QtCore,
|
||||
QSyntaxHighlighter, QTextCharFormat, QBrush )
|
||||
|
||||
try:
|
||||
from calibre.gui2 import QVariant
|
||||
@@ -1111,14 +1115,20 @@ class RejectListDialog(SizePersistedDialog):
|
||||
def get_deletebooks(self):
|
||||
return self.deletebooks.isChecked()
|
||||
|
||||
class EditTextDialog(QDialog):
|
||||
class EditTextDialog(SizePersistedDialog):
|
||||
|
||||
def __init__(self, parent, text,
|
||||
icon=None, title=None, label=None, tooltip=None,
|
||||
rejectreasons=[],reasonslabel=None
|
||||
rejectreasons=[],reasonslabel=None,
|
||||
use_find=False,
|
||||
read_only=False,
|
||||
save_size_name='ffdl:edit text dialog',
|
||||
):
|
||||
QDialog.__init__(self, parent)
|
||||
self.resize(600, 500)
|
||||
SizePersistedDialog.__init__(self, parent, save_size_name)
|
||||
|
||||
self.keys=dict()
|
||||
|
||||
#self.resize(600, 500)
|
||||
self.l = QVBoxLayout()
|
||||
self.setLayout(self.l)
|
||||
self.label = QLabel(label)
|
||||
@@ -1129,10 +1139,56 @@ class EditTextDialog(QDialog):
|
||||
self.l.addWidget(self.label)
|
||||
|
||||
self.textedit = QTextEdit(self)
|
||||
|
||||
highlighter = IniHighlighter(self.textedit, "Classic")
|
||||
|
||||
self.textedit.setLineWrapMode(QTextEdit.NoWrap)
|
||||
try:
|
||||
self.textedit.setFont(QFont("Courier",
|
||||
parent.font().pointSize()+1))
|
||||
except Exception as e:
|
||||
logger.error("Couldn't get font: %s"%e)
|
||||
|
||||
self.textedit.setReadOnly(read_only)
|
||||
|
||||
self.textedit.setText(text)
|
||||
self.l.addWidget(self.textedit)
|
||||
|
||||
self.lastStart = 0
|
||||
|
||||
if use_find:
|
||||
|
||||
findtooltip=_('Search for string in edit box.')
|
||||
|
||||
horz = QHBoxLayout()
|
||||
label = QLabel(_('Find:'))
|
||||
|
||||
label.setToolTip(findtooltip)
|
||||
|
||||
# Button to search the document for something
|
||||
self.findButton = QtGui.QPushButton(_('Find'),self)
|
||||
self.findButton.clicked.connect(self.find)
|
||||
self.findButton.setToolTip(findtooltip)
|
||||
|
||||
# The field into which to type the query
|
||||
self.findField = QLineEdit(self)
|
||||
self.findField.setToolTip(findtooltip)
|
||||
self.findField.returnPressed.connect(self.findButton.setFocus)
|
||||
|
||||
# Case Sensitivity option
|
||||
self.caseSens = QtGui.QCheckBox(_('Case sensitive'),self)
|
||||
self.caseSens.setToolTip(_("Search for case sensitive string; don't treat Harry, HARRY and harry all the same."))
|
||||
|
||||
horz.addWidget(label)
|
||||
horz.addWidget(self.findField)
|
||||
horz.addWidget(self.findButton)
|
||||
horz.addWidget(self.caseSens)
|
||||
|
||||
self.l.addLayout(horz)
|
||||
|
||||
self.addCtrlKeyPress(QtCore.Qt.Key_F,self.findFocus)
|
||||
self.addCtrlKeyPress(QtCore.Qt.Key_G,self.find)
|
||||
|
||||
if tooltip:
|
||||
self.label.setToolTip(tooltip)
|
||||
self.textedit.setToolTip(tooltip)
|
||||
@@ -1159,11 +1215,230 @@ class EditTextDialog(QDialog):
|
||||
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
button_box.accepted.connect(self.accept)
|
||||
button_box.rejected.connect(self.reject)
|
||||
# button_box.button(QDialogButtonBox.Ok).setDefault(False)
|
||||
# button_box.button(QDialogButtonBox.Cancel).setDefault(False)
|
||||
self.l.addWidget(button_box)
|
||||
|
||||
# Cause our dialog size to be restored from prefs or created on first usage
|
||||
self.resize_dialog()
|
||||
|
||||
def addCtrlKeyPress(self,key,func):
|
||||
# print("addKeyPress: key(0x%x)"%key)
|
||||
# print("control: 0x%x"%QtCore.Qt.ControlModifier)
|
||||
self.keys[key]=func
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
# print("event: key(0x%x) modifiers(0x%x)"%(event.key(),event.modifiers()))
|
||||
if (event.modifiers() & QtCore.Qt.ControlModifier) and event.key() in self.keys:
|
||||
func = self.keys[event.key()]
|
||||
return func()
|
||||
else:
|
||||
return SizePersistedDialog.keyPressEvent(self, event)
|
||||
|
||||
def get_plain_text(self):
|
||||
return unicode(self.textedit.toPlainText())
|
||||
|
||||
def get_reason_text(self):
|
||||
return unicode(self.reason_edit.currentText()).strip()
|
||||
|
||||
def findFocus(self):
|
||||
# print("findFocus called")
|
||||
self.findField.setFocus()
|
||||
self.findField.selectAll()
|
||||
|
||||
def find(self):
|
||||
|
||||
print("find self.lastStart:%s"%self.lastStart)
|
||||
|
||||
# Grab the parent's text
|
||||
text = self.textedit.toPlainText()
|
||||
|
||||
# And the text to find
|
||||
query = self.findField.text()
|
||||
|
||||
if not self.caseSens.isChecked():
|
||||
text = text.lower()
|
||||
query = query.lower()
|
||||
|
||||
# Use normal string search to find the query from the
|
||||
# last starting position
|
||||
self.lastStart = text.find(query,self.lastStart + 1)
|
||||
# If the find() method didn't return -1 (not found)
|
||||
|
||||
if self.lastStart >= 0:
|
||||
end = self.lastStart + len(query)
|
||||
self.moveCursor(self.lastStart,end)
|
||||
else:
|
||||
# Make the next search start from the begining again
|
||||
self.lastStart = 0
|
||||
self.textedit.moveCursor(self.textedit.textCursor().Start)
|
||||
|
||||
def moveCursor(self,start,end):
|
||||
|
||||
# We retrieve the QTextCursor object from the parent's QTextEdit
|
||||
cursor = self.textedit.textCursor()
|
||||
|
||||
# Then we set the position to the beginning of the last match
|
||||
cursor.setPosition(start)
|
||||
|
||||
# Next we move the Cursor by over the match and pass the KeepAnchor parameter
|
||||
# which will make the cursor select the the match's text
|
||||
cursor.movePosition(cursor.Right,cursor.KeepAnchor,end - start)
|
||||
|
||||
# And finally we set this new cursor as the parent's
|
||||
self.textedit.setTextCursor(cursor)
|
||||
|
||||
def errors_dialog(parent,
|
||||
title,
|
||||
html):
|
||||
|
||||
d = ViewLog(title,html,parent)
|
||||
|
||||
return d.exec_() == d.Accepted
|
||||
|
||||
|
||||
class ViewLog(QDialog):
|
||||
|
||||
def __init__(self, title, html, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
self.l = l = QVBoxLayout()
|
||||
self.setLayout(l)
|
||||
|
||||
self.tb = QTextBrowser(self)
|
||||
self.tb.setFont(QFont("Courier",
|
||||
parent.font().pointSize()+1))
|
||||
self.tb.setHtml(html)
|
||||
l.addWidget(self.tb)
|
||||
|
||||
self.bb = QDialogButtonBox(QDialogButtonBox.Yes | QDialogButtonBox.No)
|
||||
self.bb.accepted.connect(self.accept)
|
||||
self.bb.rejected.connect(self.reject)
|
||||
# self.copy_button = self.bb.addButton(_('Copy to clipboard'),
|
||||
# self.bb.ActionRole)
|
||||
# self.copy_button.setIcon(QIcon(I('edit-copy.png')))
|
||||
# self.copy_button.clicked.connect(self.copy_to_clipboard)
|
||||
l.addWidget(self.bb)
|
||||
self.setModal(False)
|
||||
self.resize(700, 500)
|
||||
self.setWindowTitle(title)
|
||||
self.setWindowIcon(QIcon(I('debug.png')))
|
||||
#self.show()
|
||||
|
||||
def copy_to_clipboard(self):
|
||||
txt = self.tb.toPlainText()
|
||||
QApplication.clipboard().setText(txt)
|
||||
|
||||
class IniHighlighter(QSyntaxHighlighter):
|
||||
|
||||
def __init__( self, parent, theme ):
|
||||
QSyntaxHighlighter.__init__( self, parent )
|
||||
self.parent = parent
|
||||
keyword = QTextCharFormat()
|
||||
reservedClasses = QTextCharFormat()
|
||||
assignmentOperator = QTextCharFormat()
|
||||
delimiter = QTextCharFormat()
|
||||
specialConstant = QTextCharFormat()
|
||||
boolean = QTextCharFormat()
|
||||
number = QTextCharFormat()
|
||||
comment = QTextCharFormat()
|
||||
string = QTextCharFormat()
|
||||
singleQuotedString = QTextCharFormat()
|
||||
|
||||
self.highlightingRules = []
|
||||
|
||||
# # keyword
|
||||
# brush = QBrush( Qt.darkBlue, Qt.SolidPattern )
|
||||
# keyword.setForeground( brush )
|
||||
# keyword.setFontWeight( QFont.Bold )
|
||||
# keywords = [ "break", "else", "for", "if", "in",
|
||||
# "next", "repeat", "return", "switch",
|
||||
# "try", "while" ]
|
||||
# for word in keywords:
|
||||
# pattern = "\\b" + word + "\\b"
|
||||
# rule = HighlightingRule( pattern, keyword )
|
||||
# self.highlightingRules.append( rule )
|
||||
|
||||
# # reservedClasses
|
||||
# reservedClasses.setForeground( brush )
|
||||
# reservedClasses.setFontWeight( QFont.Bold )
|
||||
# keywords = [ "array", "character", "complex",
|
||||
# "data.frame", "double", "factor",
|
||||
# "function", "integer", "list",
|
||||
# "logical", "matrix", "numeric",
|
||||
# "vector" ]
|
||||
# for word in keywords:
|
||||
# pattern = "\\b" + word + "\\b"
|
||||
# rule = HighlightingRule( pattern, reservedClasses )
|
||||
# self.highlightingRules.append( rule )
|
||||
|
||||
# # assignmentOperator
|
||||
# brush = QBrush( Qt.yellow, Qt.SolidPattern )
|
||||
# pattern = "(<){1,2}-"
|
||||
# assignmentOperator.setForeground( brush )
|
||||
# assignmentOperator.setFontWeight( QFont.Bold )
|
||||
# rule = HighlightingRule( pattern, assignmentOperator )
|
||||
# self.highlightingRules.append( rule )
|
||||
|
||||
# section
|
||||
pattern = r"^\[[^\]]+\]"
|
||||
brush = QBrush( Qt.darkBlue, Qt.SolidPattern )
|
||||
delimiter.setForeground( brush )
|
||||
delimiter.setFontWeight( QFont.Bold )
|
||||
rule = HighlightingRule( pattern, delimiter )
|
||||
self.highlightingRules.append( rule )
|
||||
|
||||
# # specialConstant
|
||||
# brush = QBrush( Qt.green, Qt.SolidPattern )
|
||||
# specialConstant.setForeground( brush )
|
||||
# keywords = [ "Inf", "NA", "NaN", "NULL" ]
|
||||
# for word in keywords:
|
||||
# pattern = "\\b" + word + "\\b"
|
||||
# rule = HighlightingRule( pattern, specialConstant )
|
||||
# self.highlightingRules.append( rule )
|
||||
|
||||
# boolean, case insensitive
|
||||
boolean.setForeground( brush )
|
||||
pattern = r"\b(true|false)\b"
|
||||
rule = HighlightingRule( pattern, boolean )
|
||||
self.highlightingRules.append( rule )
|
||||
|
||||
# # number
|
||||
# pattern = "[-+]?[0-9]*\.?[0-9]+?([eE][-+]?[0-9]+?)?"
|
||||
# number.setForeground( brush )
|
||||
# rule = HighlightingRule( pattern, number )
|
||||
# self.highlightingRules.append( rule )
|
||||
|
||||
# comment
|
||||
brush = QBrush( Qt.darkGray, Qt.SolidPattern )
|
||||
pattern = "#[^\n]*"
|
||||
comment.setForeground( brush )
|
||||
rule = HighlightingRule( pattern, comment )
|
||||
self.highlightingRules.append( rule )
|
||||
|
||||
# string
|
||||
brush = QBrush( Qt.red, Qt.SolidPattern )
|
||||
pattern = "\".*?\""
|
||||
string.setForeground( brush )
|
||||
rule = HighlightingRule( pattern, string )
|
||||
self.highlightingRules.append( rule )
|
||||
|
||||
# singleQuotedString
|
||||
pattern = "\'.*?\'"
|
||||
singleQuotedString.setForeground( brush )
|
||||
rule = HighlightingRule( pattern, singleQuotedString )
|
||||
self.highlightingRules.append( rule )
|
||||
|
||||
def highlightBlock( self, text ):
|
||||
for rule in self.highlightingRules:
|
||||
for match in rule.pattern.finditer(text):
|
||||
self.setFormat( match.start(), match.end()-match.start(), rule.format )
|
||||
self.setCurrentBlockState( 0 )
|
||||
|
||||
class HighlightingRule():
|
||||
def __init__( self, pattern, format ):
|
||||
if isinstance(pattern,basestring):
|
||||
self.pattern = re.compile(pattern)
|
||||
else:
|
||||
self.pattern=pattern
|
||||
self.format = format
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2011 Fanficdownloader team
|
||||
# Copyright 2014 Fanficdownloader team
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2011 Fanficdownloader team
|
||||
# Copyright 2014 Fanficdownloader team
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
#
|
||||
|
||||
import ConfigParser, re
|
||||
from ConfigParser import DEFAULTSECT, MissingSectionHeaderError, ParsingError
|
||||
|
||||
# All of the writers(epub,html,txt) and adapters(ffnet,twlt,etc)
|
||||
# inherit from Configurable. The config file(s) uses ini format:
|
||||
@@ -32,10 +33,15 @@ import ConfigParser, re
|
||||
# [overrides]
|
||||
# titlepage_entries: category
|
||||
|
||||
import adapters
|
||||
|
||||
class Configuration(ConfigParser.SafeConfigParser):
|
||||
|
||||
def __init__(self, site, fileform):
|
||||
ConfigParser.SafeConfigParser.__init__(self)
|
||||
|
||||
self.linenos=dict() # key by section or section,key -> lineno
|
||||
|
||||
self.sectionslist = ['defaults']
|
||||
|
||||
if site.startswith("www."):
|
||||
@@ -162,6 +168,132 @@ class Configuration(ConfigParser.SafeConfigParser):
|
||||
def getConfigList(self, key):
|
||||
return self.get_config_list(self.sectionslist, key)
|
||||
|
||||
|
||||
def test_config(self):
|
||||
errors=[]
|
||||
|
||||
sites = adapters.getConfigSections()
|
||||
sitesections = ['defaults','overrides']
|
||||
for section in sites:
|
||||
sitesections.append(section)
|
||||
if section.startswith('www.'):
|
||||
# add w/o www if has www
|
||||
sitesections.append(section[4:])
|
||||
else:
|
||||
# add w/ www if doesn't www
|
||||
sitesections.append('www.%s'%section)
|
||||
|
||||
allowedsections = []
|
||||
forms=['html','txt','epub','mobi']
|
||||
allowedsections.extend(forms)
|
||||
|
||||
for section in sitesections:
|
||||
allowedsections.append(section)
|
||||
for f in forms:
|
||||
allowedsections.append('%s:%s'%(section,f))
|
||||
|
||||
for section in self.sections():
|
||||
if section not in allowedsections and 'teststory:' not in section:
|
||||
errors.append((self.get_lineno(section),"Bad Section Name: %s"%section))
|
||||
|
||||
return errors
|
||||
|
||||
def get_lineno(self,section,key=None):
|
||||
if key:
|
||||
return self.linenos.get(section+','+key,None)
|
||||
else:
|
||||
return self.linenos.get(section,None)
|
||||
|
||||
## Copied from Python library so as to make it save linenos too.
|
||||
#
|
||||
# Regular expressions for parsing section headers and options.
|
||||
#
|
||||
def _read(self, fp, fpname):
|
||||
"""Parse a sectioned setup file.
|
||||
|
||||
The sections in setup file contains a title line at the top,
|
||||
indicated by a name in square brackets (`[]'), plus key/value
|
||||
options lines, indicated by `name: value' format lines.
|
||||
Continuations are represented by an embedded newline then
|
||||
leading whitespace. Blank lines, lines beginning with a '#',
|
||||
and just about everything else are ignored.
|
||||
"""
|
||||
cursect = None # None, or a dictionary
|
||||
optname = None
|
||||
lineno = 0
|
||||
e = None # None, or an exception
|
||||
while True:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
lineno = lineno + 1
|
||||
# comment or blank line?
|
||||
if line.strip() == '' or line[0] in '#;':
|
||||
continue
|
||||
if line.split(None, 1)[0].lower() == 'rem' and line[0] in "rR":
|
||||
# no leading whitespace
|
||||
continue
|
||||
# continuation line?
|
||||
if line[0].isspace() and cursect is not None and optname:
|
||||
value = line.strip()
|
||||
if value:
|
||||
cursect[optname] = "%s\n%s" % (cursect[optname], value)
|
||||
# a section header or option header?
|
||||
else:
|
||||
# is it a section header?
|
||||
mo = self.SECTCRE.match(line)
|
||||
if mo:
|
||||
sectname = mo.group('header')
|
||||
if sectname in self._sections:
|
||||
cursect = self._sections[sectname]
|
||||
elif sectname == DEFAULTSECT:
|
||||
cursect = self._defaults
|
||||
else:
|
||||
cursect = self._dict()
|
||||
cursect['__name__'] = sectname
|
||||
self._sections[sectname] = cursect
|
||||
self.linenos[sectname]=lineno
|
||||
# So sections can't start with a continuation line
|
||||
optname = None
|
||||
# no section header in the file?
|
||||
elif cursect is None:
|
||||
if not e:
|
||||
e = ParsingError(fpname)
|
||||
e.append(lineno, u'(Line outside section) '+line)
|
||||
#raise MissingSectionHeaderError(fpname, lineno, line)
|
||||
# an option line?
|
||||
else:
|
||||
mo = self._optcre.match(line)
|
||||
if mo:
|
||||
optname, vi, optval = mo.group('option', 'vi', 'value')
|
||||
# This check is fine because the OPTCRE cannot
|
||||
# match if it would set optval to None
|
||||
if optval is not None:
|
||||
if vi in ('=', ':') and ';' in optval:
|
||||
# ';' is a comment delimiter only if it follows
|
||||
# a spacing character
|
||||
pos = optval.find(';')
|
||||
if pos != -1 and optval[pos-1].isspace():
|
||||
optval = optval[:pos]
|
||||
optval = optval.strip()
|
||||
# allow empty values
|
||||
if optval == '""':
|
||||
optval = ''
|
||||
optname = self.optionxform(optname.rstrip())
|
||||
cursect[optname] = optval
|
||||
self.linenos[cursect['__name__']+','+optname]=lineno
|
||||
else:
|
||||
# a non-fatal parsing error occurred. set up the
|
||||
# exception but keep going. the exception will be
|
||||
# raised at the end of the file and will contain a
|
||||
# list of all bogus lines
|
||||
if not e:
|
||||
e = ParsingError(fpname)
|
||||
e.append(lineno, line)
|
||||
# if any parsing errors occurred, raise an exception
|
||||
if e:
|
||||
raise e
|
||||
|
||||
# extended by adapter, writer and story for ease of calling configuration.
|
||||
class Configurable(object):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user