View Javadoc
1   package com.jsql.view.swing.sql;
2   
3   import com.jsql.model.injection.engine.model.Engine;
4   import com.jsql.model.injection.engine.model.yaml.Method;
5   import com.jsql.model.injection.engine.model.yaml.ModelYaml;
6   import com.jsql.util.I18nUtil;
7   import com.jsql.view.swing.tab.TabbedPaneWheeled;
8   import com.jsql.view.swing.text.listener.DocumentListenerEditing;
9   import com.jsql.view.swing.util.I18nViewUtil;
10  import com.jsql.view.swing.util.MediatorHelper;
11  import com.jsql.view.swing.util.UiUtil;
12  import org.apache.commons.lang3.StringUtils;
13  import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
14  import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
15  import org.fife.ui.rtextarea.RTextScrollPane;
16  
17  import javax.swing.*;
18  import java.awt.*;
19  import java.awt.event.MouseAdapter;
20  import java.awt.event.MouseEvent;
21  import java.util.AbstractMap.SimpleEntry;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.LinkedList;
25  import java.util.List;
26  import java.util.stream.Stream;
27  
28  public class SqlEngine extends JPanel {
29  
30      private static ModelYaml modelYaml = MediatorHelper.model().getMediatorEngine().getEngine().instance().getModelYaml();
31      private static final JTabbedPane TABS_ERROR = new TabbedPaneWheeled(SwingConstants.RIGHT);
32      private static final List<JSyntaxTextArea> LIST_TEXTAREAS_ERROR = new ArrayList<>();
33      
34      enum TextareaWithColor {
35          
36          // Default
37          DATABASE_DEFAULT(new JSyntaxTextArea(
38              v -> SqlEngine.modelYaml.getResource().getSchema().setDatabase(v),
39              () -> SqlEngine.modelYaml.getResource().getSchema().getDatabase()
40          )),
41          TABLE_DEFAULT(new JSyntaxTextArea(
42              v -> SqlEngine.modelYaml.getResource().getSchema().setTable(v),
43              () -> SqlEngine.modelYaml.getResource().getSchema().getTable()
44          )),
45          COLUMN_DEFAULT(new JSyntaxTextArea(
46              v -> SqlEngine.modelYaml.getResource().getSchema().setColumn(v),
47              () -> SqlEngine.modelYaml.getResource().getSchema().getColumn()
48          )),
49          QUERY_DEFAULT(new JSyntaxTextArea(
50              v -> SqlEngine.modelYaml.getResource().getSchema().getRow().setQuery(v),
51              () -> SqlEngine.modelYaml.getResource().getSchema().getRow().getQuery()
52          )),
53          FIELD_DEFAULT(new JSyntaxTextArea(
54              v -> SqlEngine.modelYaml.getResource().getSchema().getRow().getFields().setField(v),
55              () -> SqlEngine.modelYaml.getResource().getSchema().getRow().getFields().getField()
56          )),
57          CONCAT_DEFAULT(new JSyntaxTextArea(
58              v -> SqlEngine.modelYaml.getResource().getSchema().getRow().getFields().setConcat(v),
59              () -> SqlEngine.modelYaml.getResource().getSchema().getRow().getFields().getConcat()
60          )),
61          
62          // Zip
63          DATABASE_ZIP(new JSyntaxTextArea(
64              v -> SqlEngine.modelYaml.getResource().getZip().setDatabase(v),
65              () -> SqlEngine.modelYaml.getResource().getZip().getDatabase()
66          )),
67          TABLE_ZIP(new JSyntaxTextArea(
68              v -> SqlEngine.modelYaml.getResource().getZip().setTable(v),
69              () -> SqlEngine.modelYaml.getResource().getZip().getTable()
70          )),
71          COLUMN_ZIP(new JSyntaxTextArea(
72              v -> SqlEngine.modelYaml.getResource().getZip().setColumn(v),
73              () -> SqlEngine.modelYaml.getResource().getZip().getColumn()
74          )),
75          QUERY_ZIP(new JSyntaxTextArea(
76              v -> SqlEngine.modelYaml.getResource().getZip().getRow().setQuery(v),
77              () -> SqlEngine.modelYaml.getResource().getZip().getRow().getQuery()
78          )),
79          FIELD_ZIP(new JSyntaxTextArea(
80              v -> SqlEngine.modelYaml.getResource().getZip().getRow().getFields().setField(v),
81              () -> SqlEngine.modelYaml.getResource().getZip().getRow().getFields().getField()
82          )),
83          CONCAT_ZIP(new JSyntaxTextArea(
84              v -> SqlEngine.modelYaml.getResource().getZip().getRow().getFields().setConcat(v),
85              () -> SqlEngine.modelYaml.getResource().getZip().getRow().getFields().getConcat()
86          )),
87          
88          // Dios
89          DATABASE_DIOS(new JSyntaxTextArea(
90              v -> SqlEngine.modelYaml.getResource().getDios().setDatabase(v),
91              () -> SqlEngine.modelYaml.getResource().getDios().getDatabase()
92          )),
93          TABLE_DIOS(new JSyntaxTextArea(
94              v -> SqlEngine.modelYaml.getResource().getDios().setTable(v),
95              () -> SqlEngine.modelYaml.getResource().getDios().getTable()
96          )),
97          COLUMN_DIOS(new JSyntaxTextArea(
98              v -> SqlEngine.modelYaml.getResource().getDios().setColumn(v),
99              () -> SqlEngine.modelYaml.getResource().getDios().getColumn()
100         )),
101         QUERY_DIOS(new JSyntaxTextArea(
102             v -> SqlEngine.modelYaml.getResource().getDios().getRow().setQuery(v),
103             () -> SqlEngine.modelYaml.getResource().getDios().getRow().getQuery()
104         )),
105         FIELD_DIOS(new JSyntaxTextArea(
106             v -> SqlEngine.modelYaml.getResource().getDios().getRow().getFields().setField(v),
107             () -> SqlEngine.modelYaml.getResource().getDios().getRow().getFields().getField()
108         )),
109         CONCAT_DIOS(new JSyntaxTextArea(
110             v -> SqlEngine.modelYaml.getResource().getDios().getRow().getFields().setConcat(v),
111             () -> SqlEngine.modelYaml.getResource().getDios().getRow().getFields().getConcat()
112         )),
113         
114         INFO(new JSyntaxTextArea(
115             v -> SqlEngine.modelYaml.getResource().setInfo(v),
116             () -> SqlEngine.modelYaml.getResource().getInfo()
117         )),
118 
119         // Configuration
120         SLIDING_WINDOW(new JSyntaxTextArea(
121             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().setSlidingWindow(v),
122             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getSlidingWindow()
123         )),
124         LIMIT(new JSyntaxTextArea(
125             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().setLimit(v),
126             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getLimit()
127         )),
128         FAILSAFE(new JSyntaxTextArea(
129             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().setFailsafe(v),
130             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFailsafe()
131         )),
132         CALIBRATOR(new JSyntaxTextArea(
133             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().setCalibrator(v),
134             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getCalibrator()
135         )),
136         ENDING_COMMENT(new JSyntaxTextArea(
137             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().setEndingComment(v),
138             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getEndingComment()
139         )),
140         LIMIT_BOUNDARY(new JSyntaxTextArea(
141             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().setLimitBoundary(v),
142             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getLimitBoundary()
143         )),
144         
145         // Union
146         INDICES(new JSyntaxTextArea(
147             v -> SqlEngine.modelYaml.getStrategy().getUnion().setIndices(v),
148             () -> SqlEngine.modelYaml.getStrategy().getUnion().getIndices()
149         )),
150         CAPACITY(new JSyntaxTextArea(
151             v -> SqlEngine.modelYaml.getStrategy().getUnion().setCapacity(v),
152             () -> SqlEngine.modelYaml.getStrategy().getUnion().getCapacity()
153         )),
154 
155         STACK(new JSyntaxTextArea(
156             v -> SqlEngine.modelYaml.getStrategy().setStack(v),
157             () -> SqlEngine.modelYaml.getStrategy().getStack()
158         )),
159         DNS(new JSyntaxTextArea(
160             v -> SqlEngine.modelYaml.getStrategy().setDns(v),
161             () -> SqlEngine.modelYaml.getStrategy().getDns()
162         )),
163 
164         // Boolean
165         MODE_AND(new JSyntaxTextArea(
166             v -> SqlEngine.modelYaml.getStrategy().getBinary().setModeAnd(v),
167             () -> SqlEngine.modelYaml.getStrategy().getBinary().getModeAnd()
168         )),
169         MODE_OR(new JSyntaxTextArea(
170             v -> SqlEngine.modelYaml.getStrategy().getBinary().setModeOr(v),
171             () -> SqlEngine.modelYaml.getStrategy().getBinary().getModeOr()
172         )),
173         MODE_STACK(new JSyntaxTextArea(
174             v -> SqlEngine.modelYaml.getStrategy().getBinary().setModeStack(v),
175             () -> SqlEngine.modelYaml.getStrategy().getBinary().getModeStack()
176         )),
177         BLIND(new JSyntaxTextArea(
178             v -> SqlEngine.modelYaml.getStrategy().getBinary().setBlind(v),
179             () -> SqlEngine.modelYaml.getStrategy().getBinary().getBlind()
180         )),
181         TIME(new JSyntaxTextArea(
182             v -> SqlEngine.modelYaml.getStrategy().getBinary().setTime(v),
183             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTime()
184         )),
185         MULTIBIT(new JSyntaxTextArea(
186             v -> SqlEngine.modelYaml.getStrategy().getBinary().setMultibit(v),
187             () -> SqlEngine.modelYaml.getStrategy().getBinary().getMultibit()
188         )),
189         TEST_BIT(new JSyntaxTextArea(
190             v -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().setBit(v),
191             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().getBit()
192         )),
193         TEST_BIN(new JSyntaxTextArea(
194             v -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().setBin(v),
195             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().getBin()
196         )),
197         TRUTHY_BIN(new JSyntaxTextArea(
198             v -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().setTruthyBin(v),
199             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().getTruthyBinAsString()
200         )),
201         FALSY_BIN(new JSyntaxTextArea(
202             v -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().setFalsyBin(v),
203             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().getFalsyBinAsString()
204         )),
205 
206 
207         // Exploit
208         EXPLOIT(new JSyntaxTextArea(
209             v -> SqlEngine.modelYaml.getResource().setExploit(v),
210             () -> SqlEngine.modelYaml.getResource().getExploit()
211         )),
212 
213         // Fingerprint
214         TRUTHY(new JSyntaxTextArea(
215             v -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().setTruthyBit(v),
216             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().getTruthyBitAsString()
217         )),
218         FALSY(new JSyntaxTextArea(
219             v -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().setFalsyBit(v),
220             () -> SqlEngine.modelYaml.getStrategy().getBinary().getTest().getFalsyBitAsString()
221         )),
222         INCORRECT_STRING_ERROR_MESSAGE(new JSyntaxTextArea(
223             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFingerprint().setErrorMessageAsString(v),
224             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFingerprint().getErrorMessageAsString()
225         )),
226         ORDER_BY_ERROR_MESSAGE(new JSyntaxTextArea(
227             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFingerprint().setOrderByErrorMessage(v),
228             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFingerprint().getOrderByErrorMessage()
229         )),
230         ORDER_BY(new JSyntaxTextArea(
231             v -> SqlEngine.modelYaml.getStrategy().getUnion().setOrderBy(v),
232             () -> SqlEngine.modelYaml.getStrategy().getUnion().getOrderBy()
233         )),
234         ENGINE_SPECIFIC(new JSyntaxTextArea(
235             v -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFingerprint().setEngineSpecific(v),
236             () -> SqlEngine.modelYaml.getStrategy().getConfiguration().getFingerprint().getEngineSpecific()
237         )),
238         ;
239         
240         final JSyntaxTextArea textarea;
241 
242         public JSyntaxTextArea getTextArea() {
243             return this.textarea;
244         }
245 
246         TextareaWithColor(JSyntaxTextArea textarea) {
247             this.textarea = textarea;
248         }
249     }
250     
251     public SqlEngine() {
252         // user can switch to another engine then close, so restore current engine
253         SqlEngine.modelYaml = MediatorHelper.model().getMediatorEngine().getEngine().instance().getModelYaml();
254 
255         SqlEngine.initTextComponents();
256 
257         JTabbedPane panelStructure = this.getPanelStructure();
258         RTextScrollPane panelFile = new RTextScrollPane(TextareaWithColor.EXPLOIT.getTextArea(), false);
259         JTabbedPane panelStrategy = this.getPanelStrategy();
260         JTabbedPane panelConfiguration = this.getPanelConfiguration();
261         JTabbedPane panelFingerprinting = this.getPanelFingerprinting();
262 
263         JTabbedPane tabsBottom = new TabbedPaneWheeled(SwingConstants.BOTTOM);
264         
265         Stream.of(
266             new SimpleEntry<>("SQLENGINE_STRUCTURE", panelStructure),
267             new SimpleEntry<>("SQLENGINE_STRATEGY", panelStrategy),
268             new SimpleEntry<>("SQLENGINE_CONFIGURATION", panelConfiguration),
269             new SimpleEntry<>("SQLENGINE_FINGERPRINTING", panelFingerprinting),
270             new SimpleEntry<>("SQLENGINE_EXPLOIT", panelFile)
271         )
272         .forEach(entry -> {
273             tabsBottom.addTab(I18nUtil.valueByKey(entry.getKey()), entry.getValue());
274             var label = new JLabel(I18nUtil.valueByKey(entry.getKey()));
275             tabsBottom.setTabComponentAt(
276                 tabsBottom.indexOfTab(I18nUtil.valueByKey(entry.getKey())),
277                 label
278             );
279             I18nViewUtil.addComponentForKey(entry.getKey(), label);
280         });
281 
282         this.setLayout(new BorderLayout());
283 
284         JPanel panelCombo = SqlEngine.initMenuEngine();
285         tabsBottom.putClientProperty("JTabbedPane.trailingComponent", panelCombo);
286         this.add(tabsBottom);
287 
288         SwingUtilities.invokeLater(() -> {
289             MediatorHelper.menubar().switchLocale(I18nUtil.getCurrentLocale());  // required for arabic
290             SqlEngine.TABS_ERROR.updateUI();  // required for theme switch when tabs closed
291         });
292     }
293 
294     private JTabbedPane getPanelStructure() {
295         final var keyDatabases = "SQLENGINE_DATABASES";
296         final var keyTables = "SQLENGINE_TABLES";
297         final var keyColumns = "SQLENGINE_COLUMNS";
298         final var keyRows = "SQLENGINE_ROWS";
299         final var keyField = "SQLENGINE_FIELD";
300         final var keyFieldSeparator = "SQLENGINE_FIELDS_SEPARATOR";
301 
302         JTabbedPane tabsDefault = new TabbedPaneWheeled();
303         Stream.of(
304             new SimpleEntry<>(keyDatabases, TextareaWithColor.DATABASE_DEFAULT.getTextArea()),
305             new SimpleEntry<>(keyTables, TextareaWithColor.TABLE_DEFAULT.getTextArea()),
306             new SimpleEntry<>(keyColumns, TextareaWithColor.COLUMN_DEFAULT.getTextArea()),
307             new SimpleEntry<>(keyRows, TextareaWithColor.QUERY_DEFAULT.getTextArea()),
308             new SimpleEntry<>(keyField, TextareaWithColor.FIELD_DEFAULT.getTextArea()),
309             new SimpleEntry<>(keyFieldSeparator, TextareaWithColor.CONCAT_DEFAULT.getTextArea()),
310             new SimpleEntry<>("SQLENGINE_METADATA", TextareaWithColor.INFO.getTextArea())
311         )
312         .forEach(entry -> {
313             tabsDefault.addTab(I18nUtil.valueByKey(entry.getKey()), new RTextScrollPane(entry.getValue(), false));
314             var label = new JLabel(I18nUtil.valueByKey(entry.getKey()));
315             tabsDefault.setTabComponentAt(tabsDefault.indexOfTab(I18nUtil.valueByKey(entry.getKey())), label);
316             I18nViewUtil.addComponentForKey(entry.getKey(), label);
317         });
318         
319         JTabbedPane tabsZip = new TabbedPaneWheeled();
320         Stream.of(
321             new SimpleEntry<>(keyDatabases, TextareaWithColor.DATABASE_ZIP.getTextArea()),
322             new SimpleEntry<>(keyTables, TextareaWithColor.TABLE_ZIP.getTextArea()),
323             new SimpleEntry<>(keyColumns, TextareaWithColor.COLUMN_ZIP.getTextArea()),
324             new SimpleEntry<>(keyRows, TextareaWithColor.QUERY_ZIP.getTextArea()),
325             new SimpleEntry<>(keyField, TextareaWithColor.FIELD_ZIP.getTextArea()),
326             new SimpleEntry<>(keyFieldSeparator, TextareaWithColor.CONCAT_ZIP.getTextArea())
327         )
328         .forEach(entry -> {
329             tabsZip.addTab(I18nUtil.valueByKey(entry.getKey()), new RTextScrollPane(entry.getValue(), false));
330             var label = new JLabel(I18nUtil.valueByKey(entry.getKey()));
331             tabsZip.setTabComponentAt(tabsZip.indexOfTab(I18nUtil.valueByKey(entry.getKey())), label);
332             I18nViewUtil.addComponentForKey(entry.getKey(), label);
333         });
334         
335         JTabbedPane tabsDios = new TabbedPaneWheeled();
336         Stream.of(
337             new SimpleEntry<>(keyDatabases, TextareaWithColor.DATABASE_DIOS.getTextArea()),
338             new SimpleEntry<>(keyTables, TextareaWithColor.TABLE_DIOS.getTextArea()),
339             new SimpleEntry<>(keyColumns, TextareaWithColor.COLUMN_DIOS.getTextArea()),
340             new SimpleEntry<>(keyRows, TextareaWithColor.QUERY_DIOS.getTextArea()),
341             new SimpleEntry<>(keyField, TextareaWithColor.FIELD_DIOS.getTextArea()),
342             new SimpleEntry<>(keyFieldSeparator, TextareaWithColor.CONCAT_DIOS.getTextArea())
343         )
344         .forEach(entry -> {
345             tabsDios.addTab(I18nUtil.valueByKey(entry.getKey()), new RTextScrollPane(entry.getValue(), false));
346             var label = new JLabel(I18nUtil.valueByKey(entry.getKey()));
347             tabsDios.setTabComponentAt(tabsDios.indexOfTab(I18nUtil.valueByKey(entry.getKey())), label);
348             I18nViewUtil.addComponentForKey(entry.getKey(), label);
349         });
350 
351         JTabbedPane tabs = new TabbedPaneWheeled(SwingConstants.RIGHT);
352         Stream.of(
353             new SimpleEntry<>("SQLENGINE_STANDARD", tabsDefault),
354             new SimpleEntry<>("SQLENGINE_ZIP", tabsZip),
355             new SimpleEntry<>("SQLENGINE_DIOS", tabsDios)
356         )
357         .forEach(entry -> {
358             tabs.addTab(I18nUtil.valueByKey(entry.getKey()), entry.getValue());
359             var label = new JLabel(I18nUtil.valueByKey(entry.getKey()));
360             tabs.setTabComponentAt(tabs.indexOfTab(I18nUtil.valueByKey(entry.getKey())), label);
361             I18nViewUtil.addComponentForKey(entry.getKey(), label);
362         });
363         return tabs;
364     }
365 
366     private JTabbedPane getPanelStrategy() {
367         JTabbedPane tabs = new TabbedPaneWheeled();
368         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_UNION"), new RTextScrollPane(TextareaWithColor.INDICES.getTextArea(), false));
369         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_STACK"), new RTextScrollPane(TextareaWithColor.STACK.getTextArea(), false));
370         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_ERROR"), SqlEngine.TABS_ERROR);
371         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_DNS"), new RTextScrollPane(TextareaWithColor.DNS.getTextArea(), false));
372 
373         JTabbedPane tabsBoolean = new TabbedPaneWheeled(SwingConstants.RIGHT);
374         Stream.of(
375             new SimpleEntry<>("AND mode", TextareaWithColor.MODE_AND.getTextArea()),
376             new SimpleEntry<>("OR mode", TextareaWithColor.MODE_OR.getTextArea()),
377             new SimpleEntry<>("Stack mode", TextareaWithColor.MODE_STACK.getTextArea()),
378             new SimpleEntry<>("Time", TextareaWithColor.TIME.getTextArea()),
379             new SimpleEntry<>("Blind", TextareaWithColor.BLIND.getTextArea()),
380             new SimpleEntry<>("Bin test", TextareaWithColor.TEST_BIN.getTextArea()),
381             new SimpleEntry<>("Bin truthy", TextareaWithColor.TRUTHY_BIN.getTextArea()),
382             new SimpleEntry<>("Bin falsy", TextareaWithColor.FALSY_BIN.getTextArea()),
383             new SimpleEntry<>("Bit test", TextareaWithColor.TEST_BIT.getTextArea()),
384             new SimpleEntry<>("Multibit", TextareaWithColor.MULTIBIT.getTextArea())
385         )
386         .forEach(entry -> {
387             tabsBoolean.addTab(entry.getKey(), new RTextScrollPane(entry.getValue(), false));
388             tabsBoolean.setTitleAt(
389                 tabsBoolean.getTabCount() - 1,
390                 String.format(
391                     "<html><div style=\"text-align:left;width:60px;\">%s</div></html>",
392                     entry.getKey()
393                 )
394             );
395         });
396         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_BOOLEAN"), tabsBoolean);
397 
398         Stream.of(
399             "SQLENGINE_UNION",
400             "SQLENGINE_STACK",
401             "SQLENGINE_ERROR",
402             "SQLENGINE_BOOLEAN"
403         )
404         .forEach(keyI18n -> {
405             var label = new JLabel(I18nUtil.valueByKey(keyI18n));
406             tabs.setTabComponentAt(tabs.indexOfTab(I18nUtil.valueByKey(keyI18n)), label);
407             I18nViewUtil.addComponentForKey(keyI18n, label);
408         });
409         return tabs;
410     }
411 
412     private JTabbedPane getPanelConfiguration() {
413         JTabbedPane tabs = new TabbedPaneWheeled();
414         Stream.of(
415             new SimpleEntry<>("SQLENGINE_CHARACTERS_SLIDINGWINDOW", new RTextScrollPane(TextareaWithColor.SLIDING_WINDOW.getTextArea(), false)),
416             new SimpleEntry<>("SQLENGINE_ROWS_SLIDINGWINDOW", new RTextScrollPane(TextareaWithColor.LIMIT.getTextArea(), false)),
417             new SimpleEntry<>("SQLENGINE_LIMIT_START_INDEX", new RTextScrollPane(TextareaWithColor.LIMIT_BOUNDARY.getTextArea(), false)),
418             new SimpleEntry<>("SQLENGINE_CAPACITY", new RTextScrollPane(TextareaWithColor.CAPACITY.getTextArea(), false)),
419             new SimpleEntry<>("SQLENGINE_CALIBRATOR", new RTextScrollPane(TextareaWithColor.CALIBRATOR.getTextArea(), false)),
420             new SimpleEntry<>("SQLENGINE_FAILSAFE", new RTextScrollPane(TextareaWithColor.FAILSAFE.getTextArea(), false)),
421             new SimpleEntry<>("SQLENGINE_END_COMMENT", new RTextScrollPane(TextareaWithColor.ENDING_COMMENT.getTextArea(), false))
422         )
423         .forEach(keyI18n -> {
424             tabs.addTab(I18nUtil.valueByKey(keyI18n.getKey()), keyI18n.getValue());
425             var label = new JLabel(I18nUtil.valueByKey(keyI18n.getKey()));
426             tabs.setTabComponentAt(tabs.indexOfTab(I18nUtil.valueByKey(keyI18n.getKey())), label);
427             I18nViewUtil.addComponentForKey(keyI18n.getKey(), label);
428         });
429         return tabs;
430     }
431     
432     private JTabbedPane getPanelFingerprinting() {
433         JTabbedPane tabs = new TabbedPaneWheeled();
434         tabs.addTab(I18nUtil.valueByKey("SQLENGINE_ORDER_BY"), new RTextScrollPane(TextareaWithColor.ORDER_BY.getTextArea(), false));
435         tabs.addTab("Order by error", new RTextScrollPane(TextareaWithColor.ORDER_BY_ERROR_MESSAGE.getTextArea(), false));
436         tabs.addTab("String error", new RTextScrollPane(TextareaWithColor.INCORRECT_STRING_ERROR_MESSAGE.getTextArea(), false));
437         tabs.addTab("Engine specific", new RTextScrollPane(TextareaWithColor.ENGINE_SPECIFIC.getTextArea(), false));
438         tabs.addTab("Truthy", new RTextScrollPane(TextareaWithColor.TRUTHY.getTextArea(), false));
439         tabs.addTab("Falsy", new RTextScrollPane(TextareaWithColor.FALSY.getTextArea(), false));
440         
441         Stream.of("SQLENGINE_ORDER_BY").forEach(keyI18n -> {
442             var label = new JLabel(I18nUtil.valueByKey(keyI18n));
443             tabs.setTabComponentAt(tabs.indexOfTab(I18nUtil.valueByKey(keyI18n)), label);
444             I18nViewUtil.addComponentForKey(keyI18n, label);
445         });
446         return tabs;
447     }
448 
449     private static JPanel initMenuEngine() {
450         var panelMenuEngine = new JPanel();  // required for label on right
451         panelMenuEngine.setLayout(new BorderLayout());
452 
453         JPopupMenu popupMenuEngines = new JPopupMenu();
454         popupMenuEngines.setLayout(UiUtil.getColumnLayout(MediatorHelper.model().getMediatorEngine().getEngines().size()));
455 
456         JLabel labelEngine = new JLabel(MediatorHelper.model().getMediatorEngine().getEngine().toString(), UiUtil.ARROW_DOWN.getIcon(), SwingConstants.LEFT);
457         labelEngine.setBorder(UiUtil.BORDER_5PX);  // required for padding
458         labelEngine.addMouseListener(new MouseAdapter() {
459             @Override
460             public void mousePressed(MouseEvent e) {
461                 Arrays.stream(popupMenuEngines.getComponents()).map(a -> (JComponent) a).forEach(JComponent::updateUI);  // required: incorrect when dark/light mode switch
462                 popupMenuEngines.updateUI();  // required: incorrect when dark/light mode switch
463                 popupMenuEngines.show(e.getComponent(), e.getComponent().getX(),e.getComponent().getY() + e.getComponent().getHeight());
464                 popupMenuEngines.setLocation(e.getComponent().getLocationOnScreen().x,e.getComponent().getLocationOnScreen().y + e.getComponent().getHeight());
465             }
466         });
467 
468         List<Engine> listEngines = new LinkedList<>(MediatorHelper.model().getMediatorEngine().getEngines());
469         listEngines.removeIf(engine -> engine == MediatorHelper.model().getMediatorEngine().getAuto());
470 
471         var groupEngine = new ButtonGroup();
472         for (final Engine engine : listEngines) {
473             JMenuItem itemRadioEngine = new JRadioButtonMenuItem(
474                 engine.toString(),
475                 engine == MediatorHelper.model().getMediatorEngine().getEngine()
476             );
477             
478             itemRadioEngine.addActionListener(actionEvent -> {
479                 SqlEngine.modelYaml = engine.instance().getModelYaml();
480                 SqlEngine.initTextComponents();
481                 labelEngine.setText(engine.toString());
482             });
483             
484             groupEngine.add(itemRadioEngine);
485             popupMenuEngines.add(itemRadioEngine);
486         }
487         
488         panelMenuEngine.add(labelEngine, BorderLayout.LINE_END);  // required to set on right
489         return panelMenuEngine;
490     }
491     
492     /**
493      * Configure all text components with new coloring and new modelYaml setter.
494      */
495     private static void initTextComponents() {
496         SqlEngine.getTextareas().forEach(SqlEngine::reset);
497         SqlEngine.getTextareas().forEach(textPaneLexer -> textPaneLexer.setText(StringUtils.EMPTY));
498 
499         Stream.of(TextareaWithColor.values())
500         .map(textareaWithColor -> textareaWithColor.textarea)
501         .forEach(textArea -> {
502             textArea.setText(textArea.getSupplierGetter().get().trim());
503             textArea.setCaretPosition(0);
504         });
505 
506         SqlEngine.populateTabError();
507         SqlEngine.applyTheme();
508     }
509 
510     public static void applyTheme() {
511         SqlEngine.getTextareas().forEach(UiUtil::applySyntaxTheme);
512     }
513 
514     /**
515      * Dynamically add textPanes to Error tab for current engine.
516      */
517     private static void populateTabError() {
518         SqlEngine.TABS_ERROR.removeAll();
519 
520         if (SqlEngine.modelYaml.getStrategy().getError() == null) {
521             return;
522         }
523             
524         for (Method methodError: SqlEngine.modelYaml.getStrategy().getError().getMethod()) {
525             var panelError = new JPanel(new BorderLayout());
526 
527             var textareaError = new JSyntaxTextArea(methodError::setQuery, methodError::getQuery);
528             SqlEngine.reset(textareaError);
529             textareaError.setText(methodError.getQuery().trim());
530             textareaError.setCaretPosition(0);
531             panelError.add(new RTextScrollPane(textareaError, false), BorderLayout.CENTER);
532             
533             var panelLimit = new JPanel();  // TODO add Error capacity
534             panelLimit.setLayout(new BoxLayout(panelLimit, BoxLayout.LINE_AXIS));
535             panelLimit.add(new JLabel(" Overflow limit: "));
536             panelLimit.add(new JTextField(Integer.toString(methodError.getCapacity())));
537             panelError.add(panelLimit, BorderLayout.SOUTH);
538 
539             SqlEngine.TABS_ERROR.addTab(methodError.getName(), panelError);
540             SqlEngine.TABS_ERROR.setTitleAt(
541                 SqlEngine.TABS_ERROR.getTabCount() - 1,
542                 String.format(
543                     "<html><div style=\"text-align:left;width:100px;\">%s</div></html>",
544                     methodError.getName()
545                 )
546             );
547             SqlEngine.LIST_TEXTAREAS_ERROR.add(textareaError);
548         }
549     }
550     
551     /**
552      * Reset the textarea colorer.
553      * @param textarea which colorer will be reset.
554      */
555     private static void reset(JSyntaxTextArea textarea) {
556         textarea.setDocument(new RSyntaxDocument(SyntaxConstants.SYNTAX_STYLE_SQL));  // required else empty on reopen
557         textarea.getDocument().addDocumentListener(new DocumentListenerEditing() {
558             @Override
559             public void process() {
560                 textarea.setAttribute();
561             }
562         });
563     }
564     
565     /**
566      * Merge list of Error textPanes and list of other textAreas.
567      * @return the merged list
568      */
569     private static List<JSyntaxTextArea> getTextareas() {
570         return Stream.concat(
571             SqlEngine.LIST_TEXTAREAS_ERROR.stream(),
572             Stream.of(TextareaWithColor.values()).map(TextareaWithColor::getTextArea)
573         )
574         .toList();
575     }
576 }