Index: gc_lang/fr/oxt/TextFormatter/TextFormatter.py ================================================================== --- gc_lang/fr/oxt/TextFormatter/TextFormatter.py +++ gc_lang/fr/oxt/TextFormatter/TextFormatter.py @@ -12,20 +12,22 @@ import tf_strings import tf_options import tf_tabrep import helpers +import TextFormatterEditor + import unohelper import uno from com.sun.star.task import XJobExecutor from com.sun.star.awt import XActionListener - from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK # BUTTONS_OK, BUTTONS_OK_CANCEL, BUTTONS_YES_NO, BUTTONS_YES_NO_CANCEL, BUTTONS_RETRY_CANCEL, BUTTONS_ABORT_IGNORE_RETRY # DEFAULT_BUTTON_OK, DEFAULT_BUTTON_CANCEL, DEFAULT_BUTTON_RETRY, DEFAULT_BUTTON_YES, DEFAULT_BUTTON_NO, DEFAULT_BUTTON_IGNORE from com.sun.star.awt.MessageBoxType import INFOBOX # MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX + def MessageBox (xParentWin, sMsg, sTitle, nBoxType=INFOBOX, nBoxButtons=BUTTONS_OK): ctx = uno.getComponentContext() xToolkit = ctx.ServiceManager.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx) xMsgBox = xToolkit.createMessageBox(xParentWin, nBoxType, nBoxButtons, sTitle, sMsg) @@ -36,10 +38,11 @@ def __init__ (self, ctx): self.ctx = ctx self.xSvMgr = self.ctx.ServiceManager self.xContainer = None self.xDialog = None + helpers.startConsole() # XJobExecutor def trigger (self, args): try: xTF = TextFormatter(self.ctx) @@ -58,10 +61,11 @@ setattr(xWidget, k, w) self.xDialog.insertByName(name, xWidget) return xWidget def run (self, sLang): + self.sLang = sLang self.dUI = tf_strings.getUI(sLang) ## dialog self.xDialog = self.xSvMgr.createInstanceWithContext('com.sun.star.awt.UnoControlDialogModel', self.ctx) self.xDialog.Width = 310 @@ -208,18 +212,22 @@ self.misc3 = self._addWidget('misc3', 'CheckBox', x2, y+35, nWidth, nHeight, Label = self.dUI.get('misc3', "#err"), State = True) #self.misc4 = self._addWidget('misc4', 'CheckBox', x2, y+45, nWidth, nHeight, Label = self.dUI.get('misc4', "#err"), State = True) self.misc5 = self._addWidget('misc5', 'CheckBox', x2, y+45, nWidth, nHeight, Label = self.dUI.get('misc5', "#err"), State = True) self.misc5b = self._addWidget('misc5b', 'CheckBox', x2+10, y+55, nWidth-40, nHeight, Label = self.dUI.get('misc5b', "#err"), State = False) self.misc5c = self._addWidget('misc5c', 'CheckBox', x2+nWidth-25, y+55, 30, nHeight, Label = self.dUI.get('misc5c', "#err"), State = False) + self.misccustom = self._addWidget('misccustom', "CheckBox", x2, y+65, nWidth-40, nHeight, Label = self.dUI.get('misccustom', "#err"), State = False) + self.beditor = self._addWidget('editor', 'Button', x2+95, y+64, 30, 9, Label = self.dUI.get('editor', "#err"), \ + HelpText = self.dUI.get('editor_help', "#err"), FontDescriptor = xFDsmall) self.misc1_res = self._addWidget('misc1_res', 'FixedText', nPosRes, y+15, 20, nHeight, Label = "", Align = 2) self.misc2_res = self._addWidget('misc2_res', 'FixedText', nPosRes, y+25, 20, nHeight, Label = "", Align = 2) self.misc3_res = self._addWidget('misc3_res', 'FixedText', nPosRes, y+35, 20, nHeight, Label = "", Align = 2) #self.misc4_res = self._addWidget('misc4_res', 'FixedText', nPosRes, y+45, 20, nHeight, Label = "", Align = 2) self.misc5_res = self._addWidget('misc5_res', 'FixedText', nPosRes, y+45, 20, nHeight, Label = "", Align = 2) + self.misccustom_res = self._addWidget('misccustom_res', 'FixedText', nPosRes, y+55, 20, nHeight, Label = "", Align = 2) # group box // restructuration - y = y + 65 + y = y + 75 self.struct = self._addWidget('struct', 'CheckBox', x2, y+2, nWidth, nHeight, Label = self.dUI.get('struct', "#err"), FontDescriptor = xFD1, \ FontRelief = 1, TextColor = nColor, HelpText = self.dUI.get('struct_help', "#err"), State = False) self._addWidget("section6", 'FixedLine', nRightLimit2-(nWidth//3), y, nWidth//3, nHeight) self.struct1 = self._addWidget('struct1', 'CheckBox', x2, y+15, nWidth, nHeight, Label = self.dUI.get('struct1', "#err"), State = True, Enabled = False) self.struct2 = self._addWidget('struct2', 'CheckBox', x2, y+25, nWidth, nHeight, Label = self.dUI.get('struct2', "#err"), State = True, Enabled = False) @@ -228,11 +236,11 @@ self.struct1_res = self._addWidget('struct1_res', 'FixedText', nPosRes, y+15, 20, nHeight, Label = "", Align = 2) self.struct2_res = self._addWidget('struct2_res', 'FixedText', nPosRes, y+25, 20, nHeight, Label = "", Align = 2) self.struct3_res = self._addWidget('struct3_res', 'FixedText', nPosRes, y+35, 20, nHeight, Label = "", Align = 2) # dialog height - self.xDialog.Height = 272 + self.xDialog.Height = 277 xWindowSize = helpers.getWindowSize() self.xDialog.PositionX = int((xWindowSize.Width / 2) - (self.xDialog.Width / 2)) self.xDialog.PositionY = int((xWindowSize.Height / 2) - (self.xDialog.Height / 2)) # lists of checkbox widgets @@ -242,11 +250,11 @@ "nbsp": [self.nbsp1, self.nbsp2, self.nbsp3, self.nbsp4, self.nbsp5, self.nbsp6, self.nnbsp1, self.nnbsp2, self.nnbsp4], "delete": [self.delete1, self.delete2, self.delete2a, self.delete2b, self.delete2c], "typo": [self.typo1, self.typo2, self.typo3, self.typo3a, self.typo3b, self.typo4, self.typo4a, self.typo4b, self.typo5, self.typo6, \ self.typo7, self.typo8, self.typo8a, self.typo8b, self.typo_ff, self.typo_fi, self.typo_ffi, self.typo_fl, self.typo_ffl, \ self.typo_ft, self.typo_st], - "misc": [self.misc1, self.misc2, self.misc3, self.misc5, self.misc1a, self.misc5b, self.misc5c], #self.misc4, + "misc": [self.misc1, self.misc2, self.misc3, self.misc5, self.misc1a, self.misc5b, self.misc5c, self.misccustom], #self.misc4, "struct": [self.struct1, self.struct2, self.struct3] } # progress bar self.pbar = self._addWidget('pbar', 'ProgressBar', 22, self.xDialog.Height-16, 210, 10) @@ -272,10 +280,12 @@ self.xContainer = self.xSvMgr.createInstanceWithContext('com.sun.star.awt.UnoControlDialog', self.ctx) self.xContainer.setModel(self.xDialog) self.xContainer.setVisible(False) self.xContainer.getControl('info').addActionListener(self) self.xContainer.getControl('info').setActionCommand('Info') + self.xContainer.getControl('editor').addActionListener(self) + self.xContainer.getControl('editor').setActionCommand('Editor') self.xContainer.getControl('default').addActionListener(self) self.xContainer.getControl('default').setActionCommand('Default') self.xContainer.getControl('apply').addActionListener(self) self.xContainer.getControl('apply').setActionCommand('Apply') self.xContainer.getControl('ssp').addActionListener(self) @@ -348,10 +358,13 @@ self._switchCheckBox(self.struct) self._setApplyButtonLabel() elif xActionEvent.ActionCommand == 'Default': self._setConfig(tf_options.dDefaultOpt) self._setApplyButtonLabel() + elif xActionEvent.ActionCommand == 'Editor': + xDialog = TextFormatterEditor.TextFormatterEditor(self.ctx) + xDialog.run(self.sLang) elif xActionEvent.ActionCommand == 'Info': xDesktop = self.xSvMgr.createInstanceWithContext('com.sun.star.frame.Desktop', self.ctx) xDoc = xDesktop.getCurrentComponent() xWindow = xDoc.CurrentController.Frame.ContainerWindow MessageBox (xWindow, self.dUI.get('infomsg', "#err"), self.dUI.get('infotitle', "#err")) @@ -660,10 +673,14 @@ n += self._replaceList(xElem, "misc5b") if self.misc5c.State: n += self._replaceList(xElem, "misc5c") self.misc5_res.Label = str(n) self.pbar.ProgressValue += 1 + if self.misccustom.State: + n = self._replaceList(xElem, "misccustom") + self.misccustom_res.Label = str(n) + self.pbar.ProgressValue += 1 self.misc.State = False self._switchCheckBox(self.misc) self.pbar.ProgressValue = self.pbar.ProgressValueMax # end of processing xPointer.setType(uno.getConstantByName("com.sun.star.awt.SystemPointer.ARROW")) ADDED gc_lang/fr/oxt/TextFormatter/TextFormatterEditor.py Index: gc_lang/fr/oxt/TextFormatter/TextFormatterEditor.py ================================================================== --- gc_lang/fr/oxt/TextFormatter/TextFormatterEditor.py +++ gc_lang/fr/oxt/TextFormatter/TextFormatterEditor.py @@ -0,0 +1,379 @@ +# Text Formatter Editor +# by Olivier R. +# License: MPL 2 + +import unohelper +import uno +import traceback +import platform +import json +import re + +import helpers +import tfe_strings as ui +import grammalecte.graphspell as sc + +from com.sun.star.awt import XActionListener +from com.sun.star.awt.grid import XGridSelectionListener + +from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK +# BUTTONS_OK, BUTTONS_OK_CANCEL, BUTTONS_YES_NO, BUTTONS_YES_NO_CANCEL, BUTTONS_RETRY_CANCEL, BUTTONS_ABORT_IGNORE_RETRY +# DEFAULT_BUTTON_OK, DEFAULT_BUTTON_CANCEL, DEFAULT_BUTTON_RETRY, DEFAULT_BUTTON_YES, DEFAULT_BUTTON_NO, DEFAULT_BUTTON_IGNORE +from com.sun.star.awt.MessageBoxType import INFOBOX, ERRORBOX # MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX + + +def MessageBox (xDocument, sMsg, sTitle, nBoxType=INFOBOX, nBoxButtons=BUTTONS_OK): + xParentWin = xDocument.CurrentController.Frame.ContainerWindow + ctx = uno.getComponentContext() + xToolkit = ctx.ServiceManager.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx) + xMsgBox = xToolkit.createMessageBox(xParentWin, nBoxType, nBoxButtons, sTitle, sMsg) + return xMsgBox.execute() + + +def _waitPointer (funcDecorated): + def wrapper (*args, **kwargs): + # self is the first parameter if the decorator is applied on a object + self = args[0] + # before + xPointer = self.xSvMgr.createInstanceWithContext("com.sun.star.awt.Pointer", self.ctx) + xPointer.setType(uno.getConstantByName("com.sun.star.awt.SystemPointer.WAIT")) + xWindowPeer = self.xContainer.getPeer() + xWindowPeer.setPointer(xPointer) + for x in xWindowPeer.Windows: + x.setPointer(xPointer) + # processing + result = funcDecorated(*args, **kwargs) + # after + xPointer.setType(uno.getConstantByName("com.sun.star.awt.SystemPointer.ARROW")) + xWindowPeer.setPointer(xPointer) + for x in xWindowPeer.Windows: + x.setPointer(xPointer) + self.xContainer.setVisible(True) # seems necessary to refresh the dialog box and text widgets (why?) + # return + return result + return wrapper + + +class TextFormatterEditor (unohelper.Base, XActionListener, XGridSelectionListener): + + def __init__ (self, ctx): + self.ctx = ctx + self.xSvMgr = self.ctx.ServiceManager + self.xDesktop = self.xSvMgr.createInstanceWithContext("com.sun.star.frame.Desktop", self.ctx) + self.xDocument = self.xDesktop.getCurrentComponent() + self.xContainer = None + self.xDialog = None + + def _addWidget (self, name, wtype, x, y, w, h, **kwargs): + xWidget = self.xDialog.createInstance('com.sun.star.awt.UnoControl%sModel' % wtype) + xWidget.Name = name + xWidget.PositionX = x + xWidget.PositionY = y + xWidget.Width = w + xWidget.Height = h + for k, w in kwargs.items(): + setattr(xWidget, k, w) + self.xDialog.insertByName(name, xWidget) + return xWidget + + def _addGrid (self, name, x, y, w, h, columns, **kwargs): + xGridModel = self.xDialog.createInstance('com.sun.star.awt.grid.UnoControlGridModel') + xGridModel.Name = name + xGridModel.PositionX = x + xGridModel.PositionY = y + xGridModel.Width = w + xGridModel.Height = h + xColumnModel = xGridModel.ColumnModel + for e in columns: + xCol = xColumnModel.createColumn() + for k, w in e.items(): + setattr(xCol, k, w) + xColumnModel.addColumn(xCol) + for k, w in kwargs.items(): + setattr(xGridModel, k, w) + self.xDialog.insertByName(name, xGridModel) + return xGridModel + + def run (self, sLang): + # lang + ui.selectLang(sLang) + + # dialog + self.xDialog = self.xSvMgr.createInstanceWithContext('com.sun.star.awt.UnoControlDialogModel', self.ctx) + self.xDialog.Width = 400 + self.xDialog.Height = 280 + self.xDialog.Title = ui.get('title') + xWindowSize = helpers.getWindowSize() + self.xDialog.PositionX = int((xWindowSize.Width / 2) - (self.xDialog.Width / 2)) + self.xDialog.PositionY = int((xWindowSize.Height / 2) - (self.xDialog.Height / 2)) + + # fonts + xFDTitle = uno.createUnoStruct("com.sun.star.awt.FontDescriptor") + xFDTitle.Height = 9 + xFDTitle.Weight = uno.getConstantByName("com.sun.star.awt.FontWeight.BOLD") + xFDTitle.Name = "Verdana" + + xFDMono = uno.createUnoStruct("com.sun.star.awt.FontDescriptor") + xFDMono.Height = 8 + xFDMono.Name = "Monospace" + + # widget + nX = 10 + nY1 = 5 + nY2 = nY1 + 200 + + nWidth = self.xDialog.Width - 20 + nHeight = 10 + + # Add + self._addWidget("new_entry", 'FixedLine', nX, nY1, nWidth, nHeight, Label = ui.get("new_entry"), FontDescriptor = xFDTitle) + + self._addWidget('newnamelbl', 'FixedText', nX, nY1+10, 60, nHeight, Label = ui.get("name")) + self._addWidget('newreplacelbl', 'FixedText', nX+65, nY1+10, 130, nHeight, Label = ui.get("replace")) + self._addWidget('newbylbl', 'FixedText', nX+200, nY1+10, 100, nHeight, Label = ui.get("by")) + + self.xNewname = self._addWidget('newname', 'Edit', nX, nY1+19, 60, 10, FontDescriptor = xFDMono) + self.xNewreplace = self._addWidget('newreplace', 'Edit', nX+65, nY1+19, 130, 10, FontDescriptor = xFDMono) + self.xNewby = self._addWidget('newby', 'Edit', nX+200, nY1+19, 100, 10, FontDescriptor = xFDMono) + self.xNewregex = self._addWidget('newregex', 'CheckBox', nX+305, nY1+21, 35, nHeight, Label = ui.get("regex"), HelpText=ui.get("regex_help")) + self.xNewcasesens = self._addWidget('newcasesens', 'CheckBox', nX+340, nY1+21, 40, nHeight, Label = ui.get("casesens"), HelpText=ui.get("casesens_help"), State=True) + + self._addWidget('add', 'Button', self.xDialog.Width-50, nY1+31, 40, 11, Label = ui.get('add')) + + lColumns = [ + {"Title": ui.get("name"), "ColumnWidth": 80}, + {"Title": ui.get("replace"), "ColumnWidth": 140}, + {"Title": ui.get("by"), "ColumnWidth": 140}, + {"Title": ui.get("regex"), "ColumnWidth": 60}, + {"Title": ui.get("casesens"), "ColumnWidth": 60}, + ] + self.xGridModel = self._addGrid("list_grid", nX, nY1+45, nWidth, 150, lColumns) + + # Modify + self._addWidget("edit_entry", 'FixedLine', nX, nY2, nWidth, nHeight, Label = ui.get("edit_entry"), FontDescriptor = xFDTitle) + + self._addWidget('editnamelbl', 'FixedText', nX, nY2+10, 60, nHeight, Label = ui.get("name")) + self._addWidget('editreplacelbl', 'FixedText', nX+65, nY2+10, 130, nHeight, Label = ui.get("replace")) + self._addWidget('editbylbl', 'FixedText', nX+200, nY2+10, 100, nHeight, Label = ui.get("by")) + + self.xEditname = self._addWidget('editname', 'Edit', nX, nY2+19, 60, 10, FontDescriptor = xFDMono, Enabled = False) + self.xEditreplace = self._addWidget('editreplace', 'Edit', nX+65, nY2+19, 130, 10, FontDescriptor = xFDMono, Enabled = False) + self.xEditby = self._addWidget('editby', 'Edit', nX+200, nY2+19, 100, 10, FontDescriptor = xFDMono, Enabled = False) + self.xEditregex = self._addWidget('editregex', 'CheckBox', nX+305, nY2+21, 35, nHeight, Label = ui.get("regex"), HelpText=ui.get("regex_help"), Enabled = False) + self.xEditcasesens = self._addWidget('editcasesens', 'CheckBox', nX+340, nY2+21, 40, nHeight, Label = ui.get("casesens"), HelpText=ui.get("casesens_help"), Enabled = False) + + self.xDeleteButton = self._addWidget('delete', 'Button', nX, nY2+31, 40, 11, Label = ui.get('delete'), TextColor = 0xAA0000, Enabled = False) + self.xApplyButton = self._addWidget('apply', 'Button', nX + (self.xDialog.Width/2)-20, nY2+31, 40, 11, Label = ui.get('apply'), HelpText="apply_help", TextColor = 0x0000AA, Enabled = False) + self.xModifyButton = self._addWidget('modify', 'Button', self.xDialog.Width-50, nY2+31, 40, 11, Label = ui.get('modify'), TextColor = 0x00AA00, Enabled = False) + + # import, export, save, close + self._addWidget("buttons_line", 'FixedLine', nX, self.xDialog.Height-35, nWidth, nHeight) + self._addWidget('import', 'Button', nX, self.xDialog.Height-25, 50, 14, Label = ui.get('import'), FontDescriptor = xFDTitle, TextColor = 0x0000AA) + self._addWidget('export', 'Button', nX+60, self.xDialog.Height-25, 50, 14, Label = ui.get('export'), FontDescriptor = xFDTitle, TextColor = 0x00AA00) + self._addWidget('save', 'Button', self.xDialog.Width-120, self.xDialog.Height-25, 50, 14, Label = ui.get('save'), FontDescriptor = xFDTitle, TextColor = 0x00AA00) + self._addWidget('close', 'Button', self.xDialog.Width-60, self.xDialog.Height-25, 50, 14, Label = ui.get('close'), FontDescriptor = xFDTitle, TextColor = 0xAA0000) + + # data + self.dRules = {} + self.iSelectedRow = -1 + self.loadRules() + + # container + self.xContainer = self.xSvMgr.createInstanceWithContext('com.sun.star.awt.UnoControlDialog', self.ctx) + self.xContainer.setModel(self.xDialog) + self.xGridControl = self.xContainer.getControl('list_grid') + self.xGridControl.addSelectionListener(self) + self.xContainer.getControl('add').addActionListener(self) + self.xContainer.getControl('add').setActionCommand('Add') + self.xContainer.getControl('delete').addActionListener(self) + self.xContainer.getControl('delete').setActionCommand('Delete') + self.xContainer.getControl('modify').addActionListener(self) + self.xContainer.getControl('modify').setActionCommand('Modify') + self.xContainer.getControl('import').addActionListener(self) + self.xContainer.getControl('import').setActionCommand('Import') + self.xContainer.getControl('export').addActionListener(self) + self.xContainer.getControl('export').setActionCommand('Export') + self.xContainer.getControl('save').addActionListener(self) + self.xContainer.getControl('save').setActionCommand('Save') + self.xContainer.getControl('close').addActionListener(self) + self.xContainer.getControl('close').setActionCommand('Close') + self.xContainer.setVisible(False) # True for non modal dialog + xToolkit = self.xSvMgr.createInstanceWithContext('com.sun.star.awt.ExtToolkit', self.ctx) + self.xContainer.createPeer(xToolkit, None) + self.xContainer.execute() + + # XActionListener + def actionPerformed (self, xActionEvent): + try: + if xActionEvent.ActionCommand == "Add": + self.addRule() + elif xActionEvent.ActionCommand == "Delete": + self.deleteRule() + elif xActionEvent.ActionCommand == "Modify": + self.modifyRule() + elif xActionEvent.ActionCommand == "Apply": + self.apply() + elif xActionEvent.ActionCommand == "Save": + self.saveRules() + elif xActionEvent.ActionCommand == "Import": + self.importRules() + elif xActionEvent.ActionCommand == "Export": + self.exportRules() + elif xActionEvent.ActionCommand == "Close": + self.xContainer.endExecute() # Modal dialog + except: + traceback.print_exc() + + # XGridSelectionListener + def selectionChanged (self, xGridSelectionEvent): + try: + aRows = self.xGridControl.getSelectedRows() + if aRows and len(aRows) == 1: + self.iSelectedRow = aRows[0] + self.sSelectedRuleName, sReplace, sBy, sRegex, sCaseSens = self.xGridModel.GridDataModel.getRowData(self.iSelectedRow) + # fill fields + self.xEditname.Text = self.sSelectedRuleName + self.xEditreplace.Text = sReplace + self.xEditby.Text = sBy + self.xEditregex.State = sRegex == "True" + self.xEditcasesens.State = sCaseSens == "True" + # enable widgets + self.xEditname.Enabled = True + self.xEditreplace.Enabled = True + self.xEditby.Enabled = True + self.xEditregex.Enabled = True + self.xEditcasesens.Enabled = True + self.xDeleteButton.Enabled = True + self.xApplyButton.Enabled = True + self.xModifyButton.Enabled = True + except: + self._clearEditFields() + traceback.print_exc() + + # Code + def _clearAddFields (self): + self.xNewname.Text = "" + self.xNewreplace.Text = "" + self.xNewby.Text = "" + self.xNewregex.State = False + self.xNewcasesens.State = True + + def _clearEditFields (self): + self.xEditname.Text = "" + self.xEditreplace.Text = "" + self.xEditby.Text = "" + self.xEditregex.State = False + self.xEditcasesens.State = True + # disable widgets + self.xEditname.Enabled = False + self.xEditreplace.Enabled = False + self.xEditby.Enabled = False + self.xEditregex.Enabled = False + self.xEditcasesens.Enabled = False + self.xDeleteButton.Enabled = False + self.xApplyButton.Enabled = False + self.xModifyButton.Enabled = False + + def addRule (self): + if not self._checkRuleName(self.xNewname.Text): + MessageBox(self.xDocument, ui.get("name_error"), ui.get("name_error_title"), ERRORBOX) + return + if not self.xNewname.Text or not self.xNewreplace.Text: + MessageBox(self.xDocument, ui.get("name_and_replace_error"), ui.get("name_and_replace_error_title"), ERRORBOX) + return + sRuleName = self.xNewname.Text + if sRuleName in self.dRules: + MessageBox(self.xDocument, ui.get('add_name_error'), ui.get("add_name_error_title"), ERRORBOX) + return + self.dRules[sRuleName] = { + "sReplace": self.xNewreplace.Text, + "sBy": self.xNewby.Text, + "bRegex": self.xNewregex.State == 1, + "bCaseSens": self.xNewcasesens.State == 1 + } + xGridDataModel = self.xGridModel.GridDataModel + xGridDataModel.addRow(xGridDataModel.RowCount + 1, self._getValuesForRow(sRuleName)) + self._clearAddFields() + + def _getValuesForRow (self, sRuleName): + return (sRuleName, self.dRules[sRuleName]["sReplace"], self.dRules[sRuleName]["sBy"], str(self.dRules[sRuleName]["bRegex"]), str(self.dRules[sRuleName]["bCaseSens"])) + + def _checkRuleName (self, sRuleName): + return re.match(r"\w[\w_#.,;!?-]*", sRuleName) + + def modifyRule (self): + if not self._checkRuleName(self.xEditname.Text): + MessageBox(self.xDocument, ui.get("name_error"), ui.get("name_error_title"), ERRORBOX) + return + sRuleName = self.xEditname.Text + if self.iSelectedRow < 0 or not sRuleName or not self.xEditreplace.Text: + MessageBox(self.xDocument, ui.get("name_and_replace_error"), ui.get("name_and_replace_error_title"), ERRORBOX) + return + if sRuleName != self.sSelectedRuleName and sRuleName in self.dRules: + MessageBox(self.xDocument, ui.get("modify_name_error"), ui.get("modify_name_error_title"), ERRORBOX) + return + try: + self.dRules[sRuleName] = { + "sReplace": self.xEditreplace.Text, + "sBy": self.xEditby.Text, + "bRegex": self.xEditregex.State == 1, + "bCaseSens": self.xEditcasesens.State == 1 + } + aColumns = (0, 1, 2, 3, 4) + self.xGridModel.GridDataModel.updateRowData(aColumns, self.iSelectedRow, self._getValuesForRow(sRuleName)) + except: + traceback.print_exc() + + def deleteRule (self): + if self.sSelectedRuleName != self.xEditname.Text: + MessageBox(self.xDocument, ui.get('delete_name_error'), ui.get("delete_name_error_title"), ERRORBOX) + return + sRuleName = self.sSelectedRuleName + if not sRuleName or sRuleName not in self.dRules: + return + try: + self._clearEditFields() + self.xGridModel.GridDataModel.removeRow(self.iSelectedRow) + self.iSelectedRow = -1 + del self.dRules[sRuleName] + except: + traceback.print_exc() + + @_waitPointer + def apply (self): + pass + + def loadRules (self): + pass + + @_waitPointer + def saveRules (self): + pass + + def importRules (self): + pass + + def exportRules (self): + if not self.dRules: + return + sText = json.dumps(self.dRules, ensure_ascii=False) + try: + xFilePicker = self.xSvMgr.createInstanceWithContext('com.sun.star.ui.dialogs.FilePicker', self.ctx) # other possibility: com.sun.star.ui.dialogs.SystemFilePicker + xFilePicker.initialize([uno.getConstantByName("com.sun.star.ui.dialogs.TemplateDescription.FILESAVE_SIMPLE")]) # seems useless + xFilePicker.appendFilter("Supported files", "*.json") + xFilePicker.setDefaultName("grammalecte_tf_trans_rules.json") # doesn’t work on Windows + xFilePicker.setDisplayDirectory("") + xFilePicker.setMultiSelectionMode(False) + nResult = xFilePicker.execute() + if nResult == 1: + # lFile = xFilePicker.getSelectedFiles() + lFile = xFilePicker.getFiles() + spfExported = lFile[0][5:].lstrip("/") # remove file:// + if platform.system() != "Windows": + spfExported = "/" + spfExported + #spfExported = os.path.join(os.path.expanduser("~"), "fr.personal.json") + with open(spfExported, "w", encoding="utf-8") as hDst: + hDst.write(sText) + except: + sMessage = traceback.format_exc() + MessageBox(self.xDocument, sMessage, self.ui.get('export_title'), ERRORBOX) Index: gc_lang/fr/oxt/TextFormatter/tf_options.py ================================================================== --- gc_lang/fr/oxt/TextFormatter/tf_options.py +++ gc_lang/fr/oxt/TextFormatter/tf_options.py @@ -4,8 +4,8 @@ 'ssp': 1, 'ssp1': 1, 'ssp2': 1, 'ssp3': 1, 'ssp4': 1, 'ssp5': 1, 'ssp6': 1, 'ssp7': 1, 'nbsp': 1, 'nbsp1': 1, 'nbsp2': 1, 'nbsp3': 1, 'nbsp4': 1, 'nbsp5': 1, 'nbsp6': 1, 'nnbsp1': 0, 'nnbsp2': 0, 'nnbsp4': 0, 'space': 1, 'space1': 1, 'space2': 1, 'delete': 0, 'delete1': 1, 'delete2': 1, 'delete2a': 0, 'delete2b': 1, 'delete2c': 0, 'typo': 1, 'typo1': 1, 'typo2': 1, 'typo3': 1, 'typo4': 1, 'typo5': 1, 'typo6': 1, 'typo7': 1, 'typo8': 0, 'typo3a': 0, 'typo3b': 1, 'typo4a': 1, 'typo4b': 0, 'typo8a': 0, 'typo8b': 1, 'typo_ff': 1, 'typo_fi':1, 'typo_ffi':1, 'typo_fl':1, 'typo_ffl':1, 'typo_ft':1, 'typo_st': 1, - 'misc': 1, 'misc1': 1, 'misc2': 1, 'misc3': 1, 'misc5': 1, 'misc1a': 0, 'misc5b': 0, 'misc5c': 0, + 'misc': 1, 'misc1': 1, 'misc2': 1, 'misc3': 1, 'misc5': 1, 'misc1a': 0, 'misc5b': 0, 'misc5c': 0, 'misccustom': 0, 'struct': 0, 'struct1': 1, 'struct2': 1, 'struct3': 0, } Index: gc_lang/fr/oxt/TextFormatter/tf_strings.py ================================================================== --- gc_lang/fr/oxt/TextFormatter/tf_strings.py +++ gc_lang/fr/oxt/TextFormatter/tf_strings.py @@ -67,10 +67,11 @@ "misc2": "Et cætera, etc.", "misc3": "Traits d’union manquants", "misc5": "Apostrophes manquantes", "misc5b": "lettres isolées (j’ n’ m’ t’ s’ c’ d’ l’)", "misc5c": "Maj.", + "misccustom": "Transformations personnelles", "struct": "~Restructuration [!]", "struct_help": "Attention : la restructuration coupe ou fusionne les paragraphes.", "struct1": "Retour à la ligne ⇒ fin de paragraphe", "struct2": "Enlever césures en fin de ligne/paragraphe", @@ -79,10 +80,12 @@ "default": "[·]", "default_help": "Options par défaut", "bsel": "Sur la sélection active", + "editor": "~Editeur…", + "editor_help": "Éditeur de transformations", "apply": "~Appliquer", "close": "~Fermer", "info": "(i)", "infotitle": "Informations", @@ -151,10 +154,11 @@ "misc2": "Et cætera, etc.", "misc3": "Missing hyphens", "misc5": "Missing apostrophes", "misc5b": "single letters (j’ n’ m’ t’ s’ c’ d’ l’)", "misc5c": "Cap.", + "misccustom": "Custom transformations", "struct": "~Restructuration [!]", "struct_help": "Caution: Restructuration cuts or merges paragraphs.", "struct1": "End of line ⇒ end of paragraph", "struct2": "Remove syllabification hyphens at EOL/EOP", @@ -163,10 +167,12 @@ "default": "[·]", "default_help": "Default options", "bsel": "On current selection", + "editor": "~Editor…", + "editor_help": "Transformations editor", "apply": "~Apply", "close": "~Close", "info": "(i)", "infotitle": "Informations", ADDED gc_lang/fr/oxt/TextFormatter/tfe_strings.py Index: gc_lang/fr/oxt/TextFormatter/tfe_strings.py ================================================================== --- gc_lang/fr/oxt/TextFormatter/tfe_strings.py +++ gc_lang/fr/oxt/TextFormatter/tfe_strings.py @@ -0,0 +1,102 @@ +# Strings for Text Formatter Editor + + +sUI = "fr" + + +def selectLang (sLang): + global sUI + sUI = sLang if sLang in dStrings else "fr" + + +def get (sMsgCode): + try: + return dStrings[sUI].get(sMsgCode, sMsgCode) + except: + return "#error" + + +dStrings = { + "fr": { + "title": "Grammalecte · Éditeur des transformations personnalisées", + + "name": "Nom de la règle", + "replace": "Remplacer", + "by": "par", + "regex": "Regex", + "regex_help": "Une expression régulière est une forme de syntaxe décrivant un motif de recherche de caractères", + "casesens": "Casse rigide", + "casesens_help": "La casse des caractères sera respectée telle quelle.", + + "new_entry": "Nouvelle entrée", + "edit_entry": "Édition de l’entrée sélectionnée", + + "add": "Ajouter", + "delete": "Supprimer", + "modify": "Modifier", + "apply": "Appliquer", + "apply_help": "Appliquer cette règle sur le texte", + + "save": "Enregistrer", + "import": "Importer", + "export": "Exporter", + "close": "Fermer", + + "name_error": "Pour le nom des règles, utilisez uniquement les lettres, les nombres et les caractères parmi ‹_-#.,;!?›.", + "name_error_title": "Le nom de la règle n’est pas conforme.", + + "name_and_replace_error": "Ni le nom de la règle, ni ce qui doit être remplacé ne peut être vide. Veuillez remplir les champs requis.", + "name_and_replace_error_title": "L’un des champs requis est vide", + + "add_name_error": "Une règle porte déjà ce nom. Veuillez modifier son nom.", + "add_name_error_title": "Nom déjà utilisé", + + "delete_name_error": "Vous avez modifié le nom de la règle. Veuillez resélectionner la règle que vous voulez supprimer, et cliquez sur ‹Supprimer›.", + "delete_name_error_title": "Nom de la règle à supprimer douteux", + + "modify_name_error": "Une autre règle porte déjà ce nom. Veuillez modifier le nom de la règle.", + "modify_name_error_title": "Nouveau nom déjà utilisé par une autre règle", + }, + "en": { + "title": "Grammalecte · Editor for custom transformations", + + "name": "Rule name", + "replace": "Replace", + "by": "by", + "regex": "Regex", + "regex_help": "A regular expression is a kind of syntax describing a search pattern of characters", + "casesens": "Case sensitivity", + "casesens_help": "Characters case will be treated as written.", + + "new_entry": "New entry", + "edit_entry": "Edition for selected entry", + + "add": "Add", + "delete": "Delete", + "modify": "Modify", + "apply": "Apply", + "apply_help": "Apply this rule on the text", + + "save": "Save", + "import": "Import", + "export": "Export", + "close": "Close", + + "name_error": "For rules names, only use letters, numbers et characters among ‹_-#.,;!?›", + "name_error_title": "Le nom de la règle n’est pas conforme.", + + "name_and_replace_error": "Neither the rule name, neither what has to be replaced can be empty. Please, fill the required fields.", + "name_and_replace_error_title": "One of the required fields is empty", + + "add_name_error": "There is already a rule with this name. Please, find another name.", + "add_name_error_title": "Rule name already used", + + "delete_name_error": "You have modified the name of the rule. Please, select again the rule you want to delete and click on ‹Delete›.", + "delete_name_error_title": "Dubious rule name to delete", + + "modify_name_error": "This rule name is already used by another rule. Please, modify the rule name.", + "modify_name_error_title": "New rule name already used by another rule", + } +} + +