WIP - ini edit, error check and syntax highlighting.

This commit is contained in:
Jim Miller
2014-12-29 14:01:29 -06:00
parent 4deeaa4cac
commit f1e9081c8c
6 changed files with 457 additions and 221 deletions
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2014, Jim Miller'
__docformat__ = 'restructuredtext en'
import re
try:
from PyQt5.Qt import (Qt, QSyntaxHighlighter, QTextCharFormat, QBrush)
except ImportError as e:
from PyQt4.Qt import (Qt, QSyntaxHighlighter, QTextCharFormat, QBrush)
class BasicIniHighlighter(QSyntaxHighlighter):
'''
QSyntaxHighlighter class for use with QTextEdit for highlighting
ini config files.
I looked high and low to find a high lighter for basic ini config
format, so I'm leaving this in the project even though I'm not
using.
'''
def __init__( self, parent, theme ):
QSyntaxHighlighter.__init__( self, parent )
self.parent = parent
self.highlightingRules = []
# keyword
self.highlightingRules.append( HighlightingRule( r"^[^:=\s][^:=]*[:=]",
Qt.blue,
Qt.SolidPattern ) )
# section
self.highlightingRules.append( HighlightingRule( r"^\[[^\]]+\]",
Qt.darkBlue,
Qt.SolidPattern ) )
# comment
self.highlightingRules.append( HighlightingRule( r"#[^\n]*" ,
Qt.darkYellow,
Qt.SolidPattern ) )
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.highlight )
self.setCurrentBlockState( 0 )
class HighlightingRule():
def __init__( self, pattern, color, style ):
if isinstance(pattern,basestring):
self.pattern = re.compile(pattern)
else:
self.pattern=pattern
charfmt = QTextCharFormat()
brush = QBrush(color, style)
charfmt.setForeground(brush)
self.highlight = charfmt
+7 -15
View File
@@ -13,8 +13,6 @@ 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,
@@ -75,7 +73,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, errors_dialog)
EditTextDialog, IniTextDialog, RejectUrlEntry, errors_dialog)
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.adapters \
import getConfigSections
@@ -83,7 +81,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_plugins.fanfictiondownloader_plugin.ffdl_util \
import (test_config)
from calibre.gui2.complete2 import EditWithComplete #MultiCompleteLineEdit
@@ -566,8 +565,7 @@ class BasicTab(QWidget):
title=_("Reject Reasons"),
label=_("Customize Reject List Reasons"),
tooltip=_("Customize the Reasons presented when Rejecting URLs"),
save_size_name='ffdl:Reject List Reasons',
use_find=True)
save_size_name='ffdl:Reject List Reasons')
d.exec_()
if d.result() == d.Accepted:
prefs['rejectreasons'] = d.get_plain_text()
@@ -632,7 +630,7 @@ class PersonalIniTab(QWidget):
# let edit box fill the space.
def show_defaults(self):
EditTextDialog(self,
IniTextDialog(self,
get_resources('plugin-defaults.ini'),
icon=self.windowIcon(),
title=_('Plugin Defaults'),
@@ -643,7 +641,7 @@ class PersonalIniTab(QWidget):
save_size_name='ffdl:defaults.ini').exec_()
def add_ini_button(self):
d = EditTextDialog(self,
d = IniTextDialog(self,
self.personalini,
icon=self.windowIcon(),
title=_("Edit personal.ini"),
@@ -658,13 +656,7 @@ class PersonalIniTab(QWidget):
if d.result() == d.Accepted:
self.personalini = unicode(d.get_plain_text())
try:
configini = get_ffdl_config("test1.com?sid=555",
personalini=self.personalini)
errors = configini.test_config()
except ParsingError as pe:
errors = pe.errors
errors = test_config(self.personalini)
if errors:
error = not errors_dialog(self.plugin_action.gui,
+75 -147
View File
@@ -7,9 +7,6 @@ __license__ = 'GPL v3'
__copyright__ = '2014, Jim Miller'
__docformat__ = 'restructuredtext en'
import logging
logger = logging.getLogger(__name__)
import traceback, re
from functools import partial
@@ -28,8 +25,7 @@ try:
QPushButton, QFont, QLabel, QCheckBox, QIcon, QLineEdit,
QComboBox, QProgressDialog, QTimer, QDialogButtonBox,
QPixmap, Qt, QAbstractItemView, QTextEdit, pyqtSignal,
QGroupBox, QFrame, QTextBrowser, QSize, QAction,
QSyntaxHighlighter, QTextCharFormat, QBrush )
QGroupBox, QFrame, QTextBrowser, QSize, QAction)
except ImportError as e:
from PyQt4 import QtGui
from PyQt4 import QtCore
@@ -37,8 +33,7 @@ except ImportError as e:
QPushButton, QFont, QLabel, QCheckBox, QIcon, QLineEdit,
QComboBox, QProgressDialog, QTimer, QDialogButtonBox,
QPixmap, Qt, QAbstractItemView, QTextEdit, pyqtSignal,
QGroupBox, QFrame, QTextBrowser, QSize, QAction, QtCore,
QSyntaxHighlighter, QTextCharFormat, QBrush )
QGroupBox, QFrame, QTextBrowser, QSize, QAction)
try:
from calibre.gui2 import QVariant
@@ -72,6 +67,12 @@ from calibre_plugins.fanfictiondownloader_plugin.common_utils \
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.geturls import get_urls_from_html, get_urls_from_text
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.adapters import getNormalStoryURL
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.configurable \
import (get_valid_sections, get_valid_entries,
get_valid_keywords, get_valid_entry_keywords)
from inihighlighter import IniHighlighter
SKIP=_('Skip')
ADDNEW=_('Add New Book')
UPDATE=_('Update EPUB if New Chapters')
@@ -1120,15 +1121,73 @@ class EditTextDialog(SizePersistedDialog):
def __init__(self, parent, text,
icon=None, title=None, label=None, tooltip=None,
rejectreasons=[],reasonslabel=None,
save_size_name='ffdl:edit text dialog',
):
SizePersistedDialog.__init__(self, parent, save_size_name)
self.l = QVBoxLayout()
self.setLayout(self.l)
self.label = QLabel(label)
if title:
self.setWindowTitle(title)
if icon:
self.setWindowIcon(icon)
self.l.addWidget(self.label)
self.textedit = QTextEdit(self)
self.textedit.setLineWrapMode(QTextEdit.NoWrap)
self.textedit.setText(text)
self.l.addWidget(self.textedit)
if tooltip:
self.label.setToolTip(tooltip)
self.textedit.setToolTip(tooltip)
if rejectreasons or reasonslabel:
self.reason_edit = EditWithComplete(self,sort_func=lambda x:1)
items = ['']+rejectreasons
self.reason_edit.update_items_cache(items)
self.reason_edit.show_initial_value('')
self.reason_edit.set_separator(None)
self.reason_edit.setToolTip(reasonslabel)
if reasonslabel:
horz = QHBoxLayout()
label = QLabel(reasonslabel)
label.setToolTip(reasonslabel)
horz.addWidget(label)
horz.addWidget(self.reason_edit)
self.l.addLayout(horz)
else:
self.l.addWidget(self.reason_edit)
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
self.l.addWidget(button_box)
# Cause our dialog size to be restored from prefs or created on first usage
self.resize_dialog()
def get_plain_text(self):
return unicode(self.textedit.toPlainText())
def get_reason_text(self):
return unicode(self.reason_edit.currentText()).strip()
class IniTextDialog(SizePersistedDialog):
def __init__(self, parent, text,
icon=None, title=None, label=None, tooltip=None,
use_find=False,
read_only=False,
save_size_name='ffdl:edit text dialog',
save_size_name='ffdl:ini text dialog',
):
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)
@@ -1140,7 +1199,12 @@ class EditTextDialog(SizePersistedDialog):
self.textedit = QTextEdit(self)
highlighter = IniHighlighter(self.textedit, "Classic")
highlighter = IniHighlighter(self.textedit,
sections=get_valid_sections(),
keywords=get_valid_keywords(),
entries=get_valid_entries(),
entry_keywords=get_valid_entry_keywords(),
)
self.textedit.setLineWrapMode(QTextEdit.NoWrap)
try:
@@ -1193,25 +1257,6 @@ class EditTextDialog(SizePersistedDialog):
self.label.setToolTip(tooltip)
self.textedit.setToolTip(tooltip)
if rejectreasons or reasonslabel:
self.reason_edit = EditWithComplete(self,sort_func=lambda x:1)
items = ['']+rejectreasons
self.reason_edit.update_items_cache(items)
self.reason_edit.show_initial_value('')
self.reason_edit.set_separator(None)
self.reason_edit.setToolTip(reasonslabel)
if reasonslabel:
horz = QHBoxLayout()
label = QLabel(reasonslabel)
label.setToolTip(reasonslabel)
horz.addWidget(label)
horz.addWidget(self.reason_edit)
self.l.addLayout(horz)
else:
self.l.addWidget(self.reason_edit)
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
@@ -1238,9 +1283,6 @@ class EditTextDialog(SizePersistedDialog):
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()
@@ -1248,7 +1290,7 @@ class EditTextDialog(SizePersistedDialog):
def find(self):
print("find self.lastStart:%s"%self.lastStart)
#print("find self.lastStart:%s"%self.lastStart)
# Grab the parent's text
text = self.textedit.toPlainText()
@@ -1328,117 +1370,3 @@ class ViewLog(QDialog):
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
+13 -1
View File
@@ -8,10 +8,11 @@ __copyright__ = '2013, Jim Miller'
__docformat__ = 'restructuredtext en'
from StringIO import StringIO
from ConfigParser import ParsingError
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader import adapters, exceptions
from calibre_plugins.fanfictiondownloader_plugin.fanficdownloader.configurable import Configuration
from calibre_plugins.fanfictiondownloader_plugin.prefs import (prefs)
from calibre_plugins.fanfictiondownloader_plugin.prefs import prefs
def get_ffdl_personalini():
if prefs['includeimages']:
@@ -40,4 +41,15 @@ def get_ffdl_config(url,fileform="epub",personalini=None):
def get_ffdl_adapter(url,fileform="epub",personalini=None):
return adapters.getAdapter(get_ffdl_config(url,fileform,personalini),url)
def test_config(initext):
configini = get_ffdl_config("test1.com?sid=555",
personalini=initext)
try:
errors = configini.test_config()
except ParsingError as pe:
errors = pe.errors
return errors
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2014, Jim Miller'
__docformat__ = 'restructuredtext en'
import re
try:
from PyQt5.Qt import (Qt, QSyntaxHighlighter, QTextCharFormat, QBrush, QFont)
except ImportError as e:
from PyQt4.Qt import (Qt, QSyntaxHighlighter, QTextCharFormat, QBrush, QFont)
# r'add_to_+key
class IniHighlighter(QSyntaxHighlighter):
'''
QSyntaxHighlighter class for use with QTextEdit for highlighting
ini config files.
'''
def __init__( self, parent, sections=[], keywords=[], entries=[], entry_keywords=[] ):
QSyntaxHighlighter.__init__( self, parent )
self.parent = parent
self.highlightingRules = []
# *all* keywords -- change known later.
self.errorRule = HighlightingRule( r"^[^:=\s][^:=]*[:=]", Qt.red )
self.highlightingRules.append( self.errorRule )
# *all* entry keywords -- change known later.
reentrykeywords = r'('+(r'|'.join([ e % r'[a-zA-Z0-9_]+' for e in entry_keywords ]))+r')'
self.highlightingRules.append( HighlightingRule( r"^(add_to_)?"+reentrykeywords+r"\s*[:=]", Qt.darkMagenta ) )
# true/false -- just to be nice.
self.highlightingRules.append( HighlightingRule( r"\b(true|false)\b", Qt.darkGreen ) )
if entries:
# *known* entries
reentries = r'('+(r'|'.join(entries))+r')'
self.highlightingRules.append( HighlightingRule( r"\b"+reentries+r"\b", Qt.darkGreen ) )
# *known* entry keywords
reentrykeywords = r'('+(r'|'.join([ e % reentries for e in entry_keywords ]))+r')'
self.highlightingRules.append( HighlightingRule( r"^(add_to_)?"+reentrykeywords+r"\s*[:=]", Qt.blue ) )
# *known* keywords
rekeywords = r'('+(r'|'.join(keywords))+r')'
self.highlightingRules.append( HighlightingRule( r"^(add_to_)?"+rekeywords+r"\s*[:=]", Qt.blue ) )
# *all* sections -- change known later.
self.highlightingRules.append( HighlightingRule( r"^\[[^\]]+\].*?$", Qt.red, QFont.Bold, blocknum=1 ) )
if sections:
# *known* sections
resections = r'('+(r'|'.join(sections))+r')'
resections = resections.replace('.','\.') #escape dots.
self.highlightingRules.append( HighlightingRule( r"^\["+resections+r"\]\s*$", Qt.darkBlue, QFont.Bold, blocknum=2 ) )
# test story sections
self.teststoryRule = HighlightingRule( r"^\[teststory:([0-9]+|defaults)\]", Qt.darkCyan, blocknum=3 )
self.highlightingRules.append( self.teststoryRule )
# NOT comments -- but can be custom columns, so don't flag.
#self.highlightingRules.append( HighlightingRule( r"(?<!^)#[^\n]*" , Qt.red ) )
# comments -- comments must start from column 0.
self.commentRule = HighlightingRule( r"^#[^\n]*" , Qt.darkYellow )
self.highlightingRules.append( self.commentRule )
def highlightBlock( self, text ):
is_comment = False
blocknum = self.previousBlockState()
for rule in self.highlightingRules:
for match in rule.pattern.finditer(text):
self.setFormat( match.start(), match.end()-match.start(), rule.highlight )
if rule == self.commentRule:
is_comment = True
if rule.blocknum > 0:
blocknum = rule.blocknum
if not is_comment:
# unknown section, error all:
if blocknum == 1 and blocknum == self.previousBlockState():
self.setFormat( 0, len(text), self.errorRule.highlight )
# teststory section rules:
if blocknum == 3:
self.setFormat( 0, len(text), self.teststoryRule.highlight )
self.setCurrentBlockState( blocknum )
class HighlightingRule():
def __init__( self, pattern, color,
weight=QFont.Normal,
style=Qt.SolidPattern,
blocknum=0):
if isinstance(pattern,basestring):
self.pattern = re.compile(pattern)
else:
self.pattern=pattern
charfmt = QTextCharFormat()
brush = QBrush(color, style)
charfmt.setForeground(brush)
charfmt.setFontWeight(weight)
self.highlight = charfmt
self.blocknum=blocknum