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