1334 lines
49 KiB
Python
1334 lines
49 KiB
Python
import os
|
|
import typing
|
|
|
|
from qtpy import QtCore as QC
|
|
from qtpy import QtWidgets as QW
|
|
|
|
from hydrus.core import HydrusConstants as HC
|
|
from hydrus.core import HydrusData
|
|
from hydrus.core import HydrusExceptions
|
|
from hydrus.core import HydrusTime
|
|
|
|
from hydrus.client import ClientConstants as CC
|
|
from hydrus.client import ClientParsing
|
|
from hydrus.client import ClientPaths
|
|
from hydrus.client import ClientStrings
|
|
from hydrus.client.gui import ClientGUIDialogsQuick
|
|
from hydrus.client.gui import ClientGUIFunctions
|
|
from hydrus.client.gui import ClientGUIScrolledPanels
|
|
from hydrus.client.gui import ClientGUIStringControls
|
|
from hydrus.client.gui import ClientGUIStringPanels
|
|
from hydrus.client.gui import ClientGUITopLevelWindowsPanels
|
|
from hydrus.client.gui import QtPorting as QP
|
|
from hydrus.client.gui.parsing import ClientGUIParsingTest
|
|
from hydrus.client.gui.widgets import ClientGUICommon
|
|
from hydrus.client.gui.widgets import ClientGUIMenuButton
|
|
|
|
class EditSpecificFormulaPanel( ClientGUIScrolledPanels.EditPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, collapse_newlines: bool ):
|
|
|
|
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
|
|
|
|
self._collapse_newlines = collapse_newlines
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
class EditCompoundFormulaPanel( EditSpecificFormulaPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, collapse_newlines: bool, formula: ClientParsing.ParseFormulaCompound, test_data: ClientParsing.ParsingTestData ):
|
|
|
|
EditSpecificFormulaPanel.__init__( self, parent, collapse_newlines )
|
|
|
|
#
|
|
|
|
menu_items = []
|
|
|
|
page_func = HydrusData.Call( ClientPaths.LaunchPathInWebBrowser, os.path.join( HC.HELP_DIR, 'downloader_parsers_formulae.html#compound_formula' ) )
|
|
|
|
menu_items.append( ( 'normal', 'open the compound formula help', 'Open the help page for compound formulae in your web browser.', page_func ) )
|
|
|
|
help_button = ClientGUIMenuButton.MenuBitmapButton( self, CC.global_pixmaps().help, menu_items )
|
|
|
|
help_hbox = ClientGUICommon.WrapInText( help_button, self, 'help for this panel -->', object_name = 'HydrusIndeterminate' )
|
|
|
|
#
|
|
|
|
test_panel = ClientGUICommon.StaticBox( self, 'test' )
|
|
|
|
self._test_panel = ClientGUIParsingTest.TestPanelFormula( test_panel, self.GetValue, test_data = test_data )
|
|
|
|
self._test_panel.SetCollapseNewlines( self._collapse_newlines )
|
|
|
|
#
|
|
|
|
edit_panel = ClientGUICommon.StaticBox( self, 'edit' )
|
|
|
|
self._formulae = QW.QListWidget( edit_panel )
|
|
self._formulae.setSelectionMode( QW.QAbstractItemView.SingleSelection )
|
|
self._formulae.itemDoubleClicked.connect( self.Edit )
|
|
|
|
self._add_formula = ClientGUICommon.BetterButton( edit_panel, 'add', self.Add )
|
|
|
|
self._edit_formula = ClientGUICommon.BetterButton( edit_panel, 'edit', self.Edit )
|
|
|
|
self._move_formula_up = ClientGUICommon.BetterButton( edit_panel, '\u2191', self.MoveUp )
|
|
|
|
self._delete_formula = ClientGUICommon.BetterButton( edit_panel, 'X', self.Delete )
|
|
|
|
self._move_formula_down = ClientGUICommon.BetterButton( edit_panel, '\u2193', self.MoveDown )
|
|
|
|
self._sub_phrase = QW.QLineEdit( edit_panel )
|
|
|
|
formulae = formula.GetFormulae()
|
|
sub_phrase = formula.GetSubstitutionPhrase()
|
|
string_processor = formula.GetStringProcessor()
|
|
|
|
self._string_processor_button = ClientGUIStringControls.StringProcessorButton( edit_panel, string_processor, self._test_panel.GetTestDataForStringProcessor )
|
|
|
|
#
|
|
|
|
for formula in formulae:
|
|
|
|
pretty_formula = formula.ToPrettyString()
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_formula )
|
|
item.setData( QC.Qt.UserRole, formula )
|
|
self._formulae.addItem( item )
|
|
|
|
|
|
self._sub_phrase.setText( sub_phrase )
|
|
|
|
#
|
|
|
|
udd_button_vbox = QP.VBoxLayout()
|
|
|
|
udd_button_vbox.addStretch( 1 )
|
|
QP.AddToLayout( udd_button_vbox, self._move_formula_up, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( udd_button_vbox, self._delete_formula, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( udd_button_vbox, self._move_formula_down, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
udd_button_vbox.addStretch( 1 )
|
|
|
|
formulae_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( formulae_hbox, self._formulae, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( formulae_hbox, udd_button_vbox, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
ae_button_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( ae_button_hbox, self._add_formula, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( ae_button_hbox, self._edit_formula, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'substitution phrase:', self._sub_phrase ) )
|
|
|
|
gridbox = ClientGUICommon.WrapInGrid( edit_panel, rows )
|
|
|
|
edit_panel.Add( formulae_hbox, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
edit_panel.Add( ae_button_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( ClientGUICommon.BetterStaticText( edit_panel, 'Newlines are removed from parsed strings right after parsing, before string processing.', ellipsize_end = True ), CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
edit_panel.Add( self._string_processor_button, CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
#
|
|
|
|
test_panel.Add( self._test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
#
|
|
|
|
hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( hbox, edit_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( vbox, help_hbox, CC.FLAGS_ON_RIGHT )
|
|
QP.AddToLayout( vbox, hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
|
|
def Add( self ):
|
|
|
|
existing_formula = ClientParsing.ParseFormulaHTML()
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit formula', frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
panel = EditFormulaPanel( dlg, existing_formula, self._test_panel.GetTestDataForChild )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
new_formula = panel.GetValue()
|
|
|
|
pretty_formula = new_formula.ToPrettyString()
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_formula )
|
|
item.setData( QC.Qt.UserRole, new_formula )
|
|
self._formulae.addItem( item )
|
|
|
|
|
|
|
|
|
|
def Delete( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._formulae )
|
|
|
|
if selection != -1:
|
|
|
|
if self._formulae.count() == 1:
|
|
|
|
QW.QMessageBox.critical( self, 'Error', 'A compound formula needs at least one sub-formula!' )
|
|
|
|
else:
|
|
|
|
QP.ListWidgetDelete( self._formulae, selection )
|
|
|
|
|
|
|
|
|
|
def Edit( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._formulae )
|
|
|
|
if selection != -1:
|
|
|
|
old_formula = QP.GetClientData( self._formulae, selection )
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit formula', frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
panel = EditFormulaPanel( dlg, old_formula, self._test_panel.GetTestDataForChild )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
new_formula = panel.GetValue()
|
|
|
|
pretty_formula = new_formula.ToPrettyString()
|
|
|
|
self._formulae.item( selection ).setText( pretty_formula )
|
|
self._formulae.item( selection ).setData( QC.Qt.UserRole, new_formula )
|
|
|
|
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
formulae = [ QP.GetClientData( self._formulae, i ) for i in range( self._formulae.count() ) ]
|
|
|
|
sub_phrase = self._sub_phrase.text()
|
|
|
|
string_processor = self._string_processor_button.GetValue()
|
|
|
|
formula = ClientParsing.ParseFormulaCompound( formulae, sub_phrase, string_processor )
|
|
|
|
return formula
|
|
|
|
|
|
def MoveDown( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._formulae )
|
|
|
|
if selection != -1 and selection + 1 < self._formulae.count():
|
|
|
|
pretty_rule = self._formulae.item( selection ).text()
|
|
rule = QP.GetClientData( self._formulae, selection )
|
|
|
|
QP.ListWidgetDelete( self._formulae, selection )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._formulae.insertItem( selection + 1, item )
|
|
|
|
|
|
|
|
def MoveUp( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._formulae )
|
|
|
|
if selection != -1 and selection > 0:
|
|
|
|
pretty_rule = self._formulae.item( selection ).text()
|
|
rule = QP.GetClientData( self._formulae, selection )
|
|
|
|
QP.ListWidgetDelete( self._formulae, selection )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._formulae.insertItem( selection - 1, item )
|
|
|
|
|
|
|
|
class EditContextVariableFormulaPanel( EditSpecificFormulaPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, collapse_newlines: bool, formula: ClientParsing.ParseFormulaContextVariable, test_data: ClientParsing.ParsingTestData ):
|
|
|
|
EditSpecificFormulaPanel.__init__( self, parent, collapse_newlines )
|
|
|
|
#
|
|
|
|
menu_items = []
|
|
|
|
page_func = HydrusData.Call( ClientPaths.LaunchPathInWebBrowser, os.path.join( HC.HELP_DIR, 'downloader_parsers_formulae.html#context_variable_formula' ) )
|
|
|
|
menu_items.append( ( 'normal', 'open the context variable formula help', 'Open the help page for context variable formulae in your web browser.', page_func ) )
|
|
|
|
help_button = ClientGUIMenuButton.MenuBitmapButton( self, CC.global_pixmaps().help, menu_items )
|
|
|
|
help_hbox = ClientGUICommon.WrapInText( help_button, self, 'help for this panel -->', object_name = 'HydrusIndeterminate' )
|
|
|
|
#
|
|
|
|
test_panel = ClientGUICommon.StaticBox( self, 'test' )
|
|
|
|
self._test_panel = ClientGUIParsingTest.TestPanelFormula( test_panel, self.GetValue, test_data = test_data )
|
|
|
|
self._test_panel.SetCollapseNewlines( collapse_newlines )
|
|
|
|
#
|
|
|
|
edit_panel = ClientGUICommon.StaticBox( self, 'edit' )
|
|
|
|
self._variable_name = QW.QLineEdit( edit_panel )
|
|
|
|
variable_name = formula.GetVariableName()
|
|
string_processor = formula.GetStringProcessor()
|
|
|
|
self._string_processor_button = ClientGUIStringControls.StringProcessorButton( edit_panel, string_processor, self._test_panel.GetTestDataForStringProcessor )
|
|
|
|
#
|
|
|
|
self._variable_name.setText( variable_name )
|
|
|
|
#
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'variable name:', self._variable_name ) )
|
|
|
|
gridbox = ClientGUICommon.WrapInGrid( edit_panel, rows )
|
|
|
|
edit_panel.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( ClientGUICommon.BetterStaticText( edit_panel, 'Newlines are removed from parsed strings right after parsing, before string processing.', ellipsize_end = True ), CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
edit_panel.Add( self._string_processor_button, CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
#
|
|
|
|
test_panel.Add( self._test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
#
|
|
|
|
hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( hbox, edit_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( vbox, help_hbox, CC.FLAGS_ON_RIGHT )
|
|
QP.AddToLayout( vbox, hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
variable_name = self._variable_name.text()
|
|
|
|
string_processor = self._string_processor_button.GetValue()
|
|
|
|
formula = ClientParsing.ParseFormulaContextVariable( variable_name, string_processor )
|
|
|
|
return formula
|
|
|
|
|
|
class EditFormulaPanel( ClientGUIScrolledPanels.EditPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, formula: ClientParsing.ParseFormula, test_data_callable: typing.Callable[ [], ClientParsing.ParsingTestData ] ):
|
|
|
|
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
|
|
|
|
self._current_formula = formula
|
|
self._test_data_callable = test_data_callable
|
|
|
|
self._collapse_newlines = True
|
|
|
|
#
|
|
|
|
my_panel = ClientGUICommon.StaticBox( self, 'formula' )
|
|
|
|
self._formula_description = QW.QPlainTextEdit( my_panel )
|
|
|
|
( width, height ) = ClientGUIFunctions.ConvertTextToPixels( self._formula_description, ( 90, 8 ) )
|
|
|
|
self._formula_description.setMinimumWidth( width )
|
|
self._formula_description.setMinimumHeight( height )
|
|
|
|
self._formula_description.setEnabled( False )
|
|
|
|
self._edit_formula = ClientGUICommon.BetterButton( my_panel, 'edit formula', self._EditFormula )
|
|
|
|
self._change_formula_type = ClientGUICommon.BetterButton( my_panel, 'change formula type', self._ChangeFormulaType )
|
|
|
|
#
|
|
|
|
self._UpdateControls()
|
|
|
|
#
|
|
|
|
button_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( button_hbox, self._edit_formula, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( button_hbox, self._change_formula_type, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
my_panel.Add( self._formula_description, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
my_panel.Add( button_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
|
|
#
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( vbox, my_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
|
|
def _ChangeFormulaType( self ):
|
|
|
|
if self._current_formula.ParsesSeparatedContent():
|
|
|
|
new_html = ClientParsing.ParseFormulaHTML( content_to_fetch = ClientParsing.HTML_CONTENT_HTML )
|
|
new_json = ClientParsing.ParseFormulaJSON( content_to_fetch = ClientParsing.JSON_CONTENT_JSON )
|
|
|
|
else:
|
|
|
|
new_html = ClientParsing.ParseFormulaHTML()
|
|
new_json = ClientParsing.ParseFormulaJSON()
|
|
|
|
|
|
new_compound = ClientParsing.ParseFormulaCompound()
|
|
new_context_variable = ClientParsing.ParseFormulaContextVariable()
|
|
|
|
if isinstance( self._current_formula, ClientParsing.ParseFormulaHTML ):
|
|
|
|
order = ( 'json', 'compound', 'context_variable' )
|
|
|
|
elif isinstance( self._current_formula, ClientParsing.ParseFormulaJSON ):
|
|
|
|
order = ( 'html', 'compound', 'context_variable' )
|
|
|
|
elif isinstance( self._current_formula, ClientParsing.ParseFormulaCompound ):
|
|
|
|
order = ( 'html', 'json', 'context_variable' )
|
|
|
|
elif isinstance( self._current_formula, ClientParsing.ParseFormulaContextVariable ):
|
|
|
|
order = ( 'html', 'json', 'compound', 'context_variable' )
|
|
|
|
|
|
choice_tuples = []
|
|
|
|
for formula_type in order:
|
|
|
|
if formula_type == 'html':
|
|
|
|
choice_tuples.append( ( 'change to a new HTML formula', new_html ) )
|
|
|
|
elif formula_type == 'json':
|
|
|
|
choice_tuples.append( ( 'change to a new JSON formula', new_json ) )
|
|
|
|
elif formula_type == 'compound':
|
|
|
|
choice_tuples.append( ( 'change to a new COMPOUND formula', new_compound ) )
|
|
|
|
elif formula_type == 'context_variable':
|
|
|
|
choice_tuples.append( ( 'change to a new CONTEXT VARIABLE formula', new_context_variable ) )
|
|
|
|
|
|
|
|
try:
|
|
|
|
self._current_formula = ClientGUIDialogsQuick.SelectFromList( self, 'select formula type', choice_tuples )
|
|
|
|
except HydrusExceptions.CancelledException:
|
|
|
|
return
|
|
|
|
|
|
self._UpdateControls()
|
|
|
|
|
|
def _EditFormula( self ):
|
|
|
|
if isinstance( self._current_formula, ClientParsing.ParseFormulaHTML ):
|
|
|
|
panel_class = EditHTMLFormulaPanel
|
|
|
|
elif isinstance( self._current_formula, ClientParsing.ParseFormulaJSON ):
|
|
|
|
panel_class = EditJSONFormulaPanel
|
|
|
|
elif isinstance( self._current_formula, ClientParsing.ParseFormulaCompound ):
|
|
|
|
panel_class = EditCompoundFormulaPanel
|
|
|
|
elif isinstance( self._current_formula, ClientParsing.ParseFormulaContextVariable ):
|
|
|
|
panel_class = EditContextVariableFormulaPanel
|
|
|
|
else:
|
|
|
|
raise Exception( 'Formula type not found!' )
|
|
|
|
|
|
test_data = self._test_data_callable()
|
|
|
|
dlg_title = 'edit formula'
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, dlg_title, frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
panel = panel_class( dlg, self._collapse_newlines, self._current_formula, test_data )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
self._current_formula = panel.GetValue()
|
|
|
|
self._UpdateControls()
|
|
|
|
|
|
|
|
|
|
def _UpdateControls( self ):
|
|
|
|
if self._current_formula is None:
|
|
|
|
self._formula_description.clear()
|
|
|
|
self._edit_formula.setEnabled( False )
|
|
self._change_formula_type.setEnabled( False )
|
|
|
|
else:
|
|
|
|
self._formula_description.setPlainText( self._current_formula.ToPrettyMultilineString() )
|
|
|
|
self._edit_formula.setEnabled( True )
|
|
self._change_formula_type.setEnabled( True )
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
return self._current_formula
|
|
|
|
|
|
def SetCollapseNewlines( self, value: bool ):
|
|
|
|
self._collapse_newlines = value
|
|
|
|
|
|
|
|
class EditHTMLTagRulePanel( ClientGUIScrolledPanels.EditPanel ):
|
|
|
|
def __init__( self, parent, tag_rule ):
|
|
|
|
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
|
|
|
|
( rule_type, tag_name, tag_attributes, tag_index, tag_depth, should_test_tag_string, tag_string_string_match ) = tag_rule.ToTuple()
|
|
|
|
if tag_name is None:
|
|
|
|
tag_name = ''
|
|
|
|
|
|
if tag_attributes is None:
|
|
|
|
tag_attributes = {}
|
|
|
|
|
|
if tag_depth is None:
|
|
|
|
tag_depth = 1
|
|
|
|
|
|
self._current_description = ClientGUICommon.BetterStaticText( self )
|
|
|
|
self._rule_type = ClientGUICommon.BetterChoice( self )
|
|
|
|
self._rule_type.addItem( 'search descendants', ClientParsing.HTML_RULE_TYPE_DESCENDING )
|
|
self._rule_type.addItem( 'walk back up ancestors', ClientParsing.HTML_RULE_TYPE_ASCENDING )
|
|
self._rule_type.addItem( 'search next siblings', ClientParsing.HTML_RULE_TYPE_NEXT_SIBLINGS )
|
|
self._rule_type.addItem( 'search previous siblings', ClientParsing.HTML_RULE_TYPE_PREV_SIBLINGS )
|
|
|
|
self._tag_name = QW.QLineEdit( self )
|
|
|
|
self._tag_attributes = ClientGUIStringControls.StringToStringDictControl( self, tag_attributes, min_height = 4 )
|
|
|
|
self._tag_index = ClientGUICommon.NoneableSpinCtrl( self, 'index to fetch', none_phrase = 'get all', min = -65536, max = 65535 )
|
|
self._tag_index.setToolTip( 'You can make this negative to do negative indexing, i.e. "Select the second from last item".' )
|
|
|
|
self._tag_depth = ClientGUICommon.BetterSpinBox( self, min=1, max=255 )
|
|
|
|
self._should_test_tag_string = QW.QCheckBox( self )
|
|
|
|
self._tag_string_string_match = ClientGUIStringControls.StringMatchButton( self, tag_string_string_match )
|
|
|
|
#
|
|
|
|
self._rule_type.SetValue( rule_type )
|
|
self._tag_name.setText( tag_name )
|
|
self._tag_index.SetValue( tag_index )
|
|
self._tag_depth.setValue( tag_depth )
|
|
self._should_test_tag_string.setChecked( should_test_tag_string )
|
|
|
|
self._UpdateTypeControls()
|
|
|
|
#
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'rule type: ', self._rule_type ) )
|
|
rows.append( ( 'tag name: ', self._tag_name ) )
|
|
|
|
gridbox_1 = ClientGUICommon.WrapInGrid( self, rows )
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'index to fetch: ', self._tag_index ) )
|
|
rows.append( ( 'depth to climb: ', self._tag_depth ) )
|
|
|
|
gridbox_2 = ClientGUICommon.WrapInGrid( self, rows )
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'should test tag string: ', self._should_test_tag_string ) )
|
|
rows.append( ( 'tag string match: ', self._tag_string_string_match ) )
|
|
|
|
gridbox_3 = ClientGUICommon.WrapInGrid( self, rows )
|
|
|
|
QP.AddToLayout( vbox, self._current_description, CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
QP.AddToLayout( vbox, gridbox_1, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
QP.AddToLayout( vbox, self._tag_attributes, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( vbox, gridbox_2, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
QP.AddToLayout( vbox, gridbox_3, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
self._UpdateShouldTest()
|
|
|
|
#
|
|
|
|
self._rule_type.currentIndexChanged.connect( self.EventTypeChanged )
|
|
self._tag_name.textChanged.connect( self.EventVariableChanged )
|
|
self._tag_attributes.columnListContentsChanged.connect( self.EventVariableChanged )
|
|
self._tag_index.valueChanged.connect( self.EventVariableChanged )
|
|
self._tag_depth.valueChanged.connect( self.EventVariableChanged )
|
|
|
|
self._should_test_tag_string.clicked.connect( self.EventShouldTestChanged )
|
|
|
|
ClientGUIFunctions.SetFocusLater( self._tag_name )
|
|
|
|
|
|
def _UpdateShouldTest( self ):
|
|
|
|
if self._should_test_tag_string.isChecked():
|
|
|
|
self._tag_string_string_match.setEnabled( True )
|
|
|
|
else:
|
|
|
|
self._tag_string_string_match.setEnabled( False )
|
|
|
|
|
|
|
|
def _UpdateTypeControls( self ):
|
|
|
|
rule_type = self._rule_type.GetValue()
|
|
|
|
if rule_type in [ ClientParsing.HTML_RULE_TYPE_DESCENDING, ClientParsing.HTML_RULE_TYPE_NEXT_SIBLINGS, ClientParsing.HTML_RULE_TYPE_PREV_SIBLINGS ]:
|
|
|
|
self._tag_attributes.setEnabled( True )
|
|
self._tag_index.setEnabled( True )
|
|
|
|
self._tag_depth.setEnabled( False )
|
|
|
|
else:
|
|
|
|
self._tag_attributes.setEnabled( False )
|
|
self._tag_index.setEnabled( False )
|
|
|
|
self._tag_depth.setEnabled( True )
|
|
|
|
|
|
self._UpdateDescription()
|
|
|
|
|
|
def _UpdateDescription( self ):
|
|
|
|
tag_rule = self.GetValue()
|
|
|
|
label = tag_rule.ToString()
|
|
|
|
self._current_description.setText( label )
|
|
|
|
|
|
def EventShouldTestChanged( self ):
|
|
|
|
self._UpdateShouldTest()
|
|
|
|
|
|
def EventTypeChanged( self, index ):
|
|
|
|
self._UpdateTypeControls()
|
|
|
|
|
|
def EventVariableChanged( self ):
|
|
|
|
self._UpdateDescription()
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
rule_type = self._rule_type.GetValue()
|
|
|
|
tag_name = self._tag_name.text()
|
|
|
|
if tag_name == '':
|
|
|
|
tag_name = None
|
|
|
|
|
|
should_test_tag_string = self._should_test_tag_string.isChecked()
|
|
tag_string_string_match = self._tag_string_string_match.GetValue()
|
|
|
|
if rule_type in [ ClientParsing.HTML_RULE_TYPE_DESCENDING, ClientParsing.HTML_RULE_TYPE_NEXT_SIBLINGS, ClientParsing.HTML_RULE_TYPE_PREV_SIBLINGS ]:
|
|
|
|
tag_attributes = self._tag_attributes.GetValue()
|
|
tag_index = self._tag_index.GetValue()
|
|
|
|
tag_rule = ClientParsing.ParseRuleHTML( rule_type = rule_type, tag_name = tag_name, tag_attributes = tag_attributes, tag_index = tag_index, should_test_tag_string = should_test_tag_string, tag_string_string_match = tag_string_string_match )
|
|
|
|
elif rule_type == ClientParsing.HTML_RULE_TYPE_ASCENDING:
|
|
|
|
tag_depth = self._tag_depth.value()
|
|
|
|
tag_rule = ClientParsing.ParseRuleHTML( rule_type = rule_type, tag_name = tag_name, tag_depth = tag_depth, should_test_tag_string = should_test_tag_string, tag_string_string_match = tag_string_string_match )
|
|
|
|
|
|
return tag_rule
|
|
|
|
|
|
class EditHTMLFormulaPanel( EditSpecificFormulaPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, collapse_newlines: bool, formula: ClientParsing.ParseFormulaHTML, test_data: ClientParsing.ParsingTestData ):
|
|
|
|
EditSpecificFormulaPanel.__init__( self, parent, collapse_newlines )
|
|
|
|
#
|
|
|
|
menu_items = []
|
|
|
|
page_func = HydrusData.Call( ClientPaths.LaunchPathInWebBrowser, os.path.join( HC.HELP_DIR, 'downloader_parsers_formulae.html#html_formula' ) )
|
|
|
|
menu_items.append( ( 'normal', 'open the html formula help', 'Open the help page for html formulae in your web browser.', page_func ) )
|
|
|
|
help_button = ClientGUIMenuButton.MenuBitmapButton( self, CC.global_pixmaps().help, menu_items )
|
|
|
|
help_hbox = ClientGUICommon.WrapInText( help_button, self, 'help for this panel -->', object_name = 'HydrusIndeterminate' )
|
|
|
|
#
|
|
|
|
test_panel = ClientGUICommon.StaticBox( self, 'test' )
|
|
|
|
self._test_panel = ClientGUIParsingTest.TestPanelFormula( test_panel, self.GetValue, test_data = test_data )
|
|
|
|
self._test_panel.SetCollapseNewlines( self._collapse_newlines )
|
|
|
|
#
|
|
|
|
edit_panel = ClientGUICommon.StaticBox( self, 'edit' )
|
|
|
|
self._tag_rules = QW.QListWidget( edit_panel )
|
|
self._tag_rules.setSelectionMode( QW.QAbstractItemView.SingleSelection )
|
|
|
|
self._tag_rules.itemDoubleClicked.connect( self.Edit )
|
|
|
|
self._add_rule = ClientGUICommon.BetterButton( edit_panel, 'add', self.Add )
|
|
|
|
self._edit_rule = ClientGUICommon.BetterButton( edit_panel, 'edit', self.Edit )
|
|
|
|
self._move_rule_up = ClientGUICommon.BetterButton( edit_panel, '\u2191', self.MoveUp )
|
|
|
|
self._delete_rule = ClientGUICommon.BetterButton( edit_panel, 'X', self.Delete )
|
|
|
|
self._move_rule_down = ClientGUICommon.BetterButton( edit_panel, '\u2193', self.MoveDown )
|
|
|
|
self._content_to_fetch = ClientGUICommon.BetterChoice( edit_panel )
|
|
|
|
self._content_to_fetch.addItem( 'attribute', ClientParsing.HTML_CONTENT_ATTRIBUTE )
|
|
self._content_to_fetch.addItem( 'string', ClientParsing.HTML_CONTENT_STRING )
|
|
self._content_to_fetch.addItem( 'html', ClientParsing.HTML_CONTENT_HTML )
|
|
|
|
self._content_to_fetch.currentIndexChanged.connect( self._UpdateControls )
|
|
|
|
self._attribute_to_fetch = QW.QLineEdit( edit_panel )
|
|
|
|
tag_rules = formula.GetTagRules()
|
|
content_to_fetch = formula.GetContentToFetch()
|
|
attribute_to_fetch = formula.GetAttributeToFetch()
|
|
string_processor = formula.GetStringProcessor()
|
|
|
|
self._string_processor_button = ClientGUIStringControls.StringProcessorButton( edit_panel, string_processor, self._test_panel.GetTestDataForStringProcessor )
|
|
|
|
#
|
|
|
|
for rule in tag_rules:
|
|
|
|
pretty_rule = rule.ToString()
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._tag_rules.addItem( item )
|
|
|
|
|
|
self._content_to_fetch.SetValue( content_to_fetch )
|
|
|
|
self._attribute_to_fetch.setText( attribute_to_fetch )
|
|
|
|
self._UpdateControls()
|
|
|
|
#
|
|
|
|
udd_button_vbox = QP.VBoxLayout()
|
|
|
|
udd_button_vbox.addStretch( 1 )
|
|
QP.AddToLayout( udd_button_vbox, self._move_rule_up, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( udd_button_vbox, self._delete_rule, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( udd_button_vbox, self._move_rule_down, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
udd_button_vbox.addStretch( 1 )
|
|
|
|
tag_rules_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( tag_rules_hbox, self._tag_rules, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( tag_rules_hbox, udd_button_vbox, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
ae_button_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( ae_button_hbox, self._add_rule, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( ae_button_hbox, self._edit_rule, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'content to fetch:', self._content_to_fetch ) )
|
|
rows.append( ( 'attribute to fetch: ', self._attribute_to_fetch ) )
|
|
|
|
gridbox = ClientGUICommon.WrapInGrid( edit_panel, rows )
|
|
|
|
edit_panel.Add( tag_rules_hbox, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
edit_panel.Add( ae_button_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( ClientGUICommon.BetterStaticText( edit_panel, 'Newlines are removed from parsed strings right after parsing, before string processing.', ellipsize_end = True ), CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
edit_panel.Add( self._string_processor_button, CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
#
|
|
|
|
test_panel.Add( self._test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
#
|
|
|
|
hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( hbox, edit_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( vbox, help_hbox, CC.FLAGS_ON_RIGHT )
|
|
QP.AddToLayout( vbox, hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
|
|
def _UpdateControls( self ):
|
|
|
|
if self._content_to_fetch.GetValue() == ClientParsing.HTML_CONTENT_ATTRIBUTE:
|
|
|
|
self._attribute_to_fetch.setEnabled( True )
|
|
|
|
else:
|
|
|
|
self._attribute_to_fetch.setEnabled( False )
|
|
|
|
|
|
|
|
def Add( self ):
|
|
|
|
dlg_title = 'edit tag rule'
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, dlg_title, frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
new_rule = ClientParsing.ParseRuleHTML()
|
|
|
|
panel = EditHTMLTagRulePanel( dlg, new_rule )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
rule = panel.GetValue()
|
|
|
|
pretty_rule = rule.ToString()
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._tag_rules.addItem( item )
|
|
|
|
|
|
|
|
|
|
def Delete( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._tag_rules )
|
|
|
|
if selection != -1:
|
|
|
|
QP.ListWidgetDelete( self._tag_rules, selection )
|
|
|
|
|
|
|
|
def Edit( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._tag_rules )
|
|
|
|
if selection != -1:
|
|
|
|
rule = QP.GetClientData( self._tag_rules, selection )
|
|
|
|
dlg_title = 'edit tag rule'
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, dlg_title, frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
panel = EditHTMLTagRulePanel( dlg, rule )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
rule = panel.GetValue()
|
|
|
|
pretty_rule = rule.ToString()
|
|
|
|
self._tag_rules.item( selection ).setText( pretty_rule )
|
|
self._tag_rules.item( selection ).setData( QC.Qt.UserRole, rule )
|
|
|
|
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
tags_rules = [ QP.GetClientData( self._tag_rules, i ) for i in range( self._tag_rules.count() ) ]
|
|
|
|
content_to_fetch = self._content_to_fetch.GetValue()
|
|
|
|
attribute_to_fetch = self._attribute_to_fetch.text()
|
|
|
|
if content_to_fetch == ClientParsing.HTML_CONTENT_ATTRIBUTE and attribute_to_fetch == '':
|
|
|
|
raise HydrusExceptions.VetoException( 'Please enter an attribute to fetch!' )
|
|
|
|
|
|
string_processor = self._string_processor_button.GetValue()
|
|
|
|
formula = ClientParsing.ParseFormulaHTML( tags_rules, content_to_fetch, attribute_to_fetch, string_processor )
|
|
|
|
return formula
|
|
|
|
|
|
def MoveDown( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._tag_rules )
|
|
|
|
if selection != -1 and selection + 1 < self._tag_rules.count():
|
|
|
|
pretty_rule = self._tag_rules.item( selection ).text()
|
|
rule = QP.GetClientData( self._tag_rules, selection )
|
|
|
|
QP.ListWidgetDelete( self._tag_rules, selection )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._tag_rules.insertItem( selection + 1, item )
|
|
|
|
|
|
|
|
def MoveUp( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._tag_rules )
|
|
|
|
if selection != -1 and selection > 0:
|
|
|
|
pretty_rule = self._tag_rules.item( selection ).text()
|
|
rule = QP.GetClientData( self._tag_rules, selection )
|
|
|
|
QP.ListWidgetDelete( self._tag_rules, selection )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._tag_rules.insertItem( selection - 1, item )
|
|
|
|
|
|
|
|
class EditJSONParsingRulePanel( ClientGUIScrolledPanels.EditPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, rule: ClientParsing.ParseRuleHTML ):
|
|
|
|
ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
|
|
|
|
self._parse_rule_type = ClientGUICommon.BetterChoice( self )
|
|
|
|
self._parse_rule_type.addItem( 'dictionary entry', ClientParsing.JSON_PARSE_RULE_TYPE_DICT_KEY )
|
|
self._parse_rule_type.addItem( 'all dictionary/list items', ClientParsing.JSON_PARSE_RULE_TYPE_ALL_ITEMS )
|
|
self._parse_rule_type.addItem( 'indexed item', ClientParsing.JSON_PARSE_RULE_TYPE_INDEXED_ITEM )
|
|
|
|
string_match = ClientStrings.StringMatch( match_type = ClientStrings.STRING_MATCH_FIXED, match_value = 'posts', example_string = 'posts' )
|
|
|
|
self._string_match = ClientGUIStringPanels.EditStringMatchPanel( self, string_match )
|
|
|
|
self._index = ClientGUICommon.BetterSpinBox( self, min=-65536, max=65535 )
|
|
self._index.setToolTip( 'You can make this negative to do negative indexing, i.e. "Select the second from last item".' )
|
|
|
|
#
|
|
|
|
( parse_rule_type, parse_rule ) = rule
|
|
|
|
self._parse_rule_type.SetValue( parse_rule_type )
|
|
|
|
if parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_INDEXED_ITEM:
|
|
|
|
self._index.setValue( parse_rule )
|
|
|
|
elif parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_DICT_KEY:
|
|
|
|
self._string_match.SetValue( parse_rule )
|
|
|
|
|
|
self._UpdateHideShow()
|
|
|
|
#
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'list index: ', self._index ) )
|
|
|
|
gridbox = ClientGUICommon.WrapInGrid( self, rows )
|
|
|
|
QP.AddToLayout( vbox, self._parse_rule_type, CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
QP.AddToLayout( vbox, self._string_match, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
#
|
|
|
|
self._parse_rule_type.currentIndexChanged.connect( self._UpdateHideShow )
|
|
|
|
|
|
def _UpdateHideShow( self ):
|
|
|
|
self._string_match.setEnabled( False )
|
|
self._index.setEnabled( False )
|
|
|
|
parse_rule_type = self._parse_rule_type.GetValue()
|
|
|
|
if parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_DICT_KEY:
|
|
|
|
self._string_match.setEnabled( True )
|
|
|
|
elif parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_INDEXED_ITEM:
|
|
|
|
self._index.setEnabled( True )
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
parse_rule_type = self._parse_rule_type.GetValue()
|
|
|
|
if parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_DICT_KEY:
|
|
|
|
parse_rule = self._string_match.GetValue()
|
|
|
|
elif parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_INDEXED_ITEM:
|
|
|
|
parse_rule = self._index.value()
|
|
|
|
elif parse_rule_type == ClientParsing.JSON_PARSE_RULE_TYPE_ALL_ITEMS:
|
|
|
|
parse_rule = None
|
|
|
|
|
|
return ( parse_rule_type, parse_rule )
|
|
|
|
|
|
class EditJSONFormulaPanel( EditSpecificFormulaPanel ):
|
|
|
|
def __init__( self, parent: QW.QWidget, collapse_newlines: bool, formula: ClientParsing.ParseFormulaJSON, test_data: ClientParsing.ParsingTestData ):
|
|
|
|
EditSpecificFormulaPanel.__init__( self, parent, collapse_newlines )
|
|
|
|
#
|
|
|
|
menu_items = []
|
|
|
|
page_func = HydrusData.Call( ClientPaths.LaunchPathInWebBrowser, os.path.join( HC.HELP_DIR, 'downloader_parsers_formulae.html#json_formula' ) )
|
|
|
|
menu_items.append( ( 'normal', 'open the json formula help', 'Open the help page for json formulae in your web browser.', page_func ) )
|
|
|
|
help_button = ClientGUIMenuButton.MenuBitmapButton( self, CC.global_pixmaps().help, menu_items )
|
|
|
|
help_hbox = ClientGUICommon.WrapInText( help_button, self, 'help for this panel -->', object_name = 'HydrusIndeterminate' )
|
|
|
|
#
|
|
|
|
test_panel = ClientGUICommon.StaticBox( self, 'test' )
|
|
|
|
self._test_panel = ClientGUIParsingTest.TestPanelFormula( test_panel, self.GetValue, test_data = test_data )
|
|
|
|
self._test_panel.SetCollapseNewlines( collapse_newlines )
|
|
|
|
#
|
|
|
|
edit_panel = ClientGUICommon.StaticBox( self, 'edit' )
|
|
|
|
self._parse_rules = QW.QListWidget( edit_panel )
|
|
self._parse_rules.setSelectionMode( QW.QAbstractItemView.SingleSelection )
|
|
self._parse_rules.itemDoubleClicked.connect( self.Edit )
|
|
|
|
self._add_rule = ClientGUICommon.BetterButton( edit_panel, 'add', self.Add )
|
|
|
|
self._edit_rule = ClientGUICommon.BetterButton( edit_panel, 'edit', self.Edit )
|
|
|
|
self._move_rule_up = ClientGUICommon.BetterButton( edit_panel, '\u2191', self.MoveUp )
|
|
|
|
self._delete_rule = ClientGUICommon.BetterButton( edit_panel, 'X', self.Delete )
|
|
|
|
self._move_rule_down = ClientGUICommon.BetterButton( edit_panel, '\u2193', self.MoveDown )
|
|
|
|
self._content_to_fetch = ClientGUICommon.BetterChoice( edit_panel )
|
|
|
|
self._content_to_fetch.addItem( 'string', ClientParsing.JSON_CONTENT_STRING )
|
|
self._content_to_fetch.addItem( 'dictionary keys', ClientParsing.JSON_CONTENT_DICT_KEYS )
|
|
self._content_to_fetch.addItem( 'json', ClientParsing.JSON_CONTENT_JSON )
|
|
|
|
parse_rules = formula.GetParseRules()
|
|
content_to_fetch = formula.GetContentToFetch()
|
|
string_processor = formula.GetStringProcessor()
|
|
|
|
self._string_processor_button = ClientGUIStringControls.StringProcessorButton( edit_panel, string_processor, self._test_panel.GetTestDataForStringProcessor )
|
|
|
|
#
|
|
|
|
for rule in parse_rules:
|
|
|
|
pretty_rule = ClientParsing.RenderJSONParseRule( rule )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._parse_rules.addItem( item )
|
|
|
|
|
|
self._content_to_fetch.SetValue( content_to_fetch )
|
|
|
|
#
|
|
|
|
udd_button_vbox = QP.VBoxLayout()
|
|
|
|
udd_button_vbox.addStretch( 1 )
|
|
QP.AddToLayout( udd_button_vbox, self._move_rule_up, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( udd_button_vbox, self._delete_rule, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( udd_button_vbox, self._move_rule_down, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
udd_button_vbox.addStretch( 1 )
|
|
|
|
parse_rules_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( parse_rules_hbox, self._parse_rules, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( parse_rules_hbox, udd_button_vbox, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
ae_button_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( ae_button_hbox, self._add_rule, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( ae_button_hbox, self._edit_rule, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
rows = []
|
|
|
|
rows.append( ( 'content to fetch:', self._content_to_fetch ) )
|
|
|
|
gridbox = ClientGUICommon.WrapInGrid( edit_panel, rows )
|
|
|
|
edit_panel.Add( parse_rules_hbox, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
edit_panel.Add( ae_button_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
edit_panel.Add( ClientGUICommon.BetterStaticText( edit_panel, 'Newlines are removed from parsed strings right after parsing, before string processing.', ellipsize_end = True ), CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
edit_panel.Add( self._string_processor_button, CC.FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
#
|
|
|
|
test_panel.Add( self._test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
#
|
|
|
|
hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( hbox, edit_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, test_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( vbox, help_hbox, CC.FLAGS_ON_RIGHT )
|
|
QP.AddToLayout( vbox, hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
|
|
|
self.widget().setLayout( vbox )
|
|
|
|
|
|
def Add( self ):
|
|
|
|
dlg_title = 'edit parse rule'
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, dlg_title, frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
new_rule = ( ClientParsing.JSON_PARSE_RULE_TYPE_DICT_KEY, ClientStrings.StringMatch( match_type = ClientStrings.STRING_MATCH_FIXED, match_value = 'posts', example_string = 'posts' ) )
|
|
|
|
panel = EditJSONParsingRulePanel( dlg, new_rule )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
rule = panel.GetValue()
|
|
|
|
pretty_rule = ClientParsing.RenderJSONParseRule( rule )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._parse_rules.addItem( item )
|
|
|
|
|
|
|
|
|
|
def Delete( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._parse_rules )
|
|
|
|
if selection != -1:
|
|
|
|
QP.ListWidgetDelete( self._parse_rules, selection )
|
|
|
|
|
|
|
|
def Edit( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._parse_rules )
|
|
|
|
if selection != -1:
|
|
|
|
rule = QP.GetClientData( self._parse_rules, selection )
|
|
|
|
dlg_title = 'edit parse rule'
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, dlg_title, frame_key = 'deeply_nested_dialog' ) as dlg:
|
|
|
|
panel = EditJSONParsingRulePanel( dlg, rule )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
rule = panel.GetValue()
|
|
|
|
pretty_rule = ClientParsing.RenderJSONParseRule( rule )
|
|
|
|
self._parse_rules.item( selection ).setText( pretty_rule )
|
|
self._parse_rules.item( selection ).setData( QC.Qt.UserRole, rule )
|
|
|
|
|
|
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
parse_rules = [ QP.GetClientData( self._parse_rules, i ) for i in range( self._parse_rules.count() ) ]
|
|
|
|
content_to_fetch = self._content_to_fetch.GetValue()
|
|
|
|
string_processor = self._string_processor_button.GetValue()
|
|
|
|
formula = ClientParsing.ParseFormulaJSON( parse_rules, content_to_fetch, string_processor )
|
|
|
|
return formula
|
|
|
|
|
|
def MoveDown( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._parse_rules )
|
|
|
|
if selection != -1 and selection + 1 < self._parse_rules.count():
|
|
|
|
pretty_rule = self._parse_rules.item( selection ).text()
|
|
rule = QP.GetClientData( self._parse_rules, selection )
|
|
|
|
QP.ListWidgetDelete( self._parse_rules, selection )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._parse_rules.insertItem( selection + 1, item )
|
|
|
|
|
|
|
|
def MoveUp( self ):
|
|
|
|
selection = QP.ListWidgetGetSelection( self._parse_rules )
|
|
|
|
if selection != -1 and selection > 0:
|
|
|
|
pretty_rule = self._parse_rules.item( selection ).text()
|
|
rule = QP.GetClientData( self._parse_rules, selection )
|
|
|
|
QP.ListWidgetDelete( self._parse_rules, selection )
|
|
|
|
item = QW.QListWidgetItem()
|
|
item.setText( pretty_rule )
|
|
item.setData( QC.Qt.UserRole, rule )
|
|
self._parse_rules.insertItem( selection - 1, item )
|
|
|
|
|