Browse Source

code import

Ondřej Hruška 2 years ago
commit
50b9942ecf
Signed by: Ondřej Hruška <ondra@ondrovo.com> GPG key ID: 2C5FD5035250423D
2 changed files with 209 additions and 0 deletions
  1. 128 0
      gexync.py
  2. 81 0
      ini_syntax.py

+ 128 - 0
gexync.py View File

@@ -0,0 +1,128 @@
1
+#!/bin/env python3
2
+
3
+import gex
4
+
5
+import sys
6
+from PyQt4 import QtGui, QtCore
7
+import ini_syntax
8
+
9
+class GexIniEditor(QtGui.QMainWindow):
10
+    """
11
+    Gexync is a GEX ini file editor.
12
+    The editor loads the INI file through the communication interface
13
+    without having to mount the virtual filesystem, which is unreliable
14
+    on some systems.
15
+
16
+    This utility allows live editing of the UNITS.INI file.
17
+
18
+    On save, a new version is loaded with formatting and error messages
19
+    generated by GEX, as if the virtual config filesystem was re-mounted.
20
+
21
+    The editor does not keep GEX claimed, instead does so only when needed.
22
+    This allows testing of the current configuration without having to close
23
+    and reopen the editor.
24
+    """
25
+
26
+    def __init__(self, xferLambda):
27
+        self.xferLambda = xferLambda
28
+
29
+        self.filenum = int(sys.argv[1]) if len(sys.argv)>1 else 0
30
+
31
+        super().__init__()
32
+        self.initUI()
33
+        # TODO let user pick GEX device if multiple
34
+
35
+    def initToolbar(self):
36
+        icon = self.style().standardIcon(QtGui.QStyle.SP_BrowserReload)
37
+        loadAction = QtGui.QAction(icon, 'Reload', self)
38
+        loadAction.setShortcut('Ctrl+O')
39
+        loadAction.triggered.connect(self.gexLoad)
40
+
41
+        icon = self.style().standardIcon(QtGui.QStyle.SP_DialogSaveButton)
42
+        syncAction = QtGui.QAction(icon, 'Write Changes', self)
43
+        syncAction.setShortcut('Ctrl+S')
44
+        syncAction.triggered.connect(self.gexSync)
45
+
46
+        icon = self.style().standardIcon(QtGui.QStyle.SP_DialogOkButton)
47
+        persAction = QtGui.QAction(icon, 'Persist', self)
48
+        persAction.setShortcut('Ctrl+P')
49
+        persAction.triggered.connect(self.gexPersist)
50
+
51
+        self.toolbar = self.addToolBar('Toolbar')
52
+        self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
53
+        self.toolbar.addAction(loadAction)
54
+        self.toolbar.addAction(syncAction)
55
+        self.toolbar.addSeparator()
56
+        self.toolbar.addAction(persAction)
57
+
58
+    def initEditor(self):
59
+        self.editor = QtGui.QPlainTextEdit()
60
+
61
+        # Editor background and text color
62
+        pal = QtGui.QPalette()
63
+        bgc = QtGui.QColor(0xFFFFF6)
64
+        pal.setColor(QtGui.QPalette.Base, bgc)
65
+        textc = QtGui.QColor(0x000000)
66
+        pal.setColor(QtGui.QPalette.Text, textc)
67
+        self.editor.setPalette(pal)
68
+        # Font
69
+        font = QtGui.QFont('Liberation Mono', 12)
70
+        font.setStyleHint(QtGui.QFont.TypeWriter)
71
+        self.editor.setFont(font)
72
+        # Initial size
73
+        self.highlight = ini_syntax.IniHighlighter(self.editor.document())
74
+
75
+    def initUI(self):
76
+        self.setWindowTitle('GEX config file editor')
77
+        self.initToolbar()
78
+        self.initEditor()
79
+        self.setCentralWidget(self.editor)
80
+        self.show()
81
+
82
+        self.gexLoad()
83
+
84
+    def gexLoad(self):
85
+        self.editor.setPlainText("")
86
+        self.editor.repaint()
87
+
88
+        client = gex.Client(self.xferLambda(), load_units=False)
89
+        read_ini = client.ini_read(self.filenum)
90
+        client.close()
91
+
92
+        self.editor.setPlainText(read_ini)
93
+        self.highlight.rehighlight()
94
+        self.setWindowTitle('GEX config file editor')
95
+
96
+    def gexSync(self):
97
+        new_txt = self.editor.toPlainText()
98
+        self.editor.setPlainText("")
99
+        self.editor.repaint()
100
+
101
+        client = gex.Client(self.xferLambda(), load_units=False)
102
+        client.ini_write(new_txt)
103
+        read_ini = client.ini_read(self.filenum)
104
+        client.close()
105
+
106
+        self.editor.setPlainText(read_ini)
107
+        self.highlight.rehighlight()
108
+        self.setWindowTitle('*GEX config file editor')
109
+
110
+    def gexPersist(self):
111
+        client = gex.Client(self.xferLambda(), load_units=False)
112
+        client.ini_persist()
113
+        client.close()
114
+        self.setWindowTitle('GEX config file editor')
115
+
116
+if __name__ == '__main__':
117
+    app = QtGui.QApplication(sys.argv)
118
+    editor = GexIniEditor(lambda: gex.TrxRawUSB())
119
+    # editor = GexIniEditor(lambda: gex.TrxSerialThread(port='/dev/ttyUSB1',
120
+    #                                                   baud=57600))
121
+
122
+    # centered resize
123
+    w = 800
124
+    h = 900
125
+    ss = app.desktop().availableGeometry().size()
126
+    editor.setGeometry(int(ss.width() / 2 - w / 2), int(ss.height() / 2 - h / 2), w, h)
127
+
128
+    sys.exit(app.exec_())

+ 81 - 0
ini_syntax.py View File

@@ -0,0 +1,81 @@
1
+# syntax.py
2
+
3
+# This is a companion file to gexync.py
4
+
5
+# based on https://wiki.python.org/moin/PyQt/Python%20syntax%20highlighting
6
+
7
+from PyQt4.QtCore import QRegExp
8
+from PyQt4.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter
9
+
10
+def format(color, style=''):
11
+    """Return a QTextCharFormat with the given attributes.
12
+    """
13
+    _color = QColor()
14
+    _color.setNamedColor(color)
15
+
16
+    _format = QTextCharFormat()
17
+    _format.setForeground(_color)
18
+    if 'bold' in style:
19
+        _format.setFontWeight(QFont.Bold)
20
+    if 'italic' in style:
21
+        _format.setFontItalic(True)
22
+
23
+    return _format
24
+
25
+
26
+# Syntax styles that can be shared by all languages
27
+STYLES = {
28
+    'operator': format('red'),
29
+    'string': format('magenta'),
30
+    'comment': format('#6C8A70', 'italic'),
31
+    'key': format('#008AFF'),
32
+    'numbers': format('brown'),
33
+    'section': format('black', 'bold'),
34
+}
35
+
36
+class IniHighlighter (QSyntaxHighlighter):
37
+    # Python braces
38
+    def __init__(self, document):
39
+        QSyntaxHighlighter.__init__(self, document)
40
+
41
+        rules = [
42
+            (r'=', 0, STYLES['operator']),
43
+            (r'\b[YN]\b', 0, STYLES['numbers']),
44
+
45
+            # Double-quoted string, possibly containing escape sequences
46
+            (r'"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
47
+            # Single-quoted string, possibly containing escape sequences
48
+            (r"'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string']),
49
+
50
+            # Numeric literals
51
+            (r'\b[+-]?[0-9]+\b', 0, STYLES['numbers']),
52
+            (r'\b[+-]?0[xX][0-9A-Fa-f]+\b', 0, STYLES['numbers']),
53
+            (r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0, STYLES['numbers']),
54
+
55
+            # From '#' until a newline
56
+            (r'#[^\n]*', 0, STYLES['comment']),
57
+
58
+            (r'^\[.+\]', 0, STYLES['section']),
59
+
60
+            (r'^[a-zA-Z0-9_-]+\s?=', 0, STYLES['key']),
61
+        ]
62
+
63
+        # Build a QRegExp for each pattern
64
+        self.rules = [(QRegExp(pat), index, fmt)
65
+            for (pat, index, fmt) in rules]
66
+
67
+    def highlightBlock(self, text):
68
+        """Apply syntax highlighting to the given block of text.
69
+        """
70
+        # Do other syntax formatting
71
+        for expression, nth, format in self.rules:
72
+            index = expression.indexIn(text, 0)
73
+
74
+            while index >= 0:
75
+                # We actually want the index of the nth match
76
+                index = expression.pos(nth)
77
+                length = len(expression.cap(nth))
78
+                self.setFormat(index, length, format)
79
+                index = expression.indexIn(text, index + length)
80
+
81
+        self.setCurrentBlockState(0)