Skip to content

Commit a53cc59

Browse files
committed
Feature: #47
Table cell data popup dialog: XML/Json Reformatting now works for binary/BLOB data.
1 parent 967930c commit a53cc59

File tree

7 files changed

+150
-53
lines changed

7 files changed

+150
-53
lines changed

sql12/core/doc/changes.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Not yet released, available in our GIT repository, snapshots and future releases
66

77
Enhancements:
88

9+
https://github.com/squirrel-sql-client/squirrel-sql-code/issues/47
10+
Table cell data popup dialog: XML/Json Reformatting now works for binary/BLOB data.
11+
912
https://github.com/squirrel-sql-client/squirrel-sql-code/issues/46
1013
SQL result and table export to MS-Excel files: New options to make exported sheets
1114
auto filtered and to choose if header rows are bold, centered and/or frozen.

sql12/core/src/net/sourceforge/squirrel_sql/fw/datasetviewer/cellcomponent/BinaryDisplayConverter.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,13 @@ private BinaryDisplayConverter() {}
9292
/**
9393
* Convert from an array of Bytes into a string.
9494
*/
95-
public static String convertToString(Byte[] data, int base, boolean showAscii) {
96-
95+
public static String convertToString(Byte[] data, int base, boolean showAscii)
96+
{
97+
return convertToString(data, base, showAscii ? DisplayAsciiMode.ASCII_DEFAULT : DisplayAsciiMode.ASCII_NO);
98+
}
99+
100+
public static String convertToString(Byte[] data, int base, DisplayAsciiMode displayAsciiMode) {
101+
97102
// handle null
98103
if (data == null)
99104
return null;
@@ -110,11 +115,20 @@ public static String convertToString(Byte[] data, int base, boolean showAscii) {
110115

111116
// if user wants to see ASCII chars as characters,
112117
// see if this is one that should be displayed that way
113-
if(showAscii)
118+
if(DisplayAsciiMode.isShowAscii(displayAsciiMode))
114119
{
115120
if(printable.indexOf((char) value) > -1)
116121
{
117-
s = Character.valueOf((char) value) + " ".substring(10 - (convConst.width - 1));
122+
s = Character.toString((char) value);
123+
124+
if(displayAsciiMode == DisplayAsciiMode.ASCII_DEFAULT)
125+
{
126+
s += " ".substring(10 - (convConst.width - 1));
127+
}
128+
}
129+
else if(displayAsciiMode == DisplayAsciiMode.ASCII_NO_ADDITIONAL_SPACES && Character.isWhitespace((char) value))
130+
{
131+
s = Character.toString((char) value);
118132
}
119133
}
120134

@@ -156,8 +170,12 @@ public static String convertToString(Byte[] data, int base, boolean showAscii) {
156170
}
157171
}
158172
buf.append(s);
159-
buf.append(" "); // always add spaces at end for consistancy
160-
}
173+
174+
if(displayAsciiMode != DisplayAsciiMode.ASCII_NO_ADDITIONAL_SPACES)
175+
{
176+
buf.append(" "); // always add spaces at end for consistancy
177+
}
178+
}
161179
return buf.toString();
162180
}
163181

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent;
2+
3+
public enum DisplayAsciiMode
4+
{
5+
ASCII_NO, ASCII_DEFAULT, ASCII_NO_ADDITIONAL_SPACES;
6+
7+
public static boolean isShowAscii(DisplayAsciiMode mode)
8+
{
9+
return mode == ASCII_DEFAULT || mode == ASCII_NO_ADDITIONAL_SPACES;
10+
}
11+
}

sql12/core/src/net/sourceforge/squirrel_sql/fw/datasetviewer/celldatapopup/I18NStrings.properties

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ popupeditableIoPanel.browse.tooltip=Select the file to export into
6363
popupeditableIoPanel.export.tooltip=Export to file
6464

6565

66-
CellDataPopupFormatter.failed.reformat=Failed to reformat cell data as JSON and as XML\nJSON-Format error: {0}\nXML-Format error: {1}
66+
CellDataPopupFormatter.failed.reformat=Failed to reformat cell data as JSON and as XML\nJSON-Format error: {0}\nXML-Format error: {1}
6767

6868
popupEditableIoPanel.compare.to.clip=Compare to clipboard
6969
popupEditableIoPanel.compare.to.clip.tooltip=Compare selection or complete content to clipboard
@@ -72,4 +72,7 @@ popupEditableIoPanel.clipboard.empty.warn=Cannot compare. Clipboard is empty or
7272
popupEditableIoPanel.cell.empty.warn=Cannot compare. Cell is empty or contains whitespaces only.
7373
popupEditableIoPanel.clipboard.vs.cell.data=Clipboard vs cell data
7474

75-
PopupEditableIOPanel.no.word.wrap.without.line.wrap=Word wrap is
75+
PopupEditableIOPanel.no.word.wrap.without.line.wrap=Word wrap is
76+
77+
78+
popupEditableIoPanel.cannot.update.binary.display.while.reformatted=Cannot update binary display while display is reformatted.

sql12/core/src/net/sourceforge/squirrel_sql/fw/datasetviewer/celldatapopup/PopupEditableIOPanel.java

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
import java.awt.GridBagLayout;
6161
import java.awt.Insets;
6262
import java.awt.event.ActionEvent;
63-
import java.awt.event.ActionListener;
6463
import java.awt.event.MouseAdapter;
6564
import java.awt.event.MouseEvent;
6665
import java.io.BufferedReader;
@@ -71,6 +70,7 @@
7170
import java.io.InputStreamReader;
7271
import java.nio.file.Path;
7372
import java.sql.Types;
73+
import java.util.Objects;
7474

7575
/**
7676
* @author gwg
@@ -90,6 +90,11 @@ public class PopupEditableIOPanel extends JPanel
9090
public static final String ACTION_APPLY = "apply";
9191
public static final String ACTION_IMPORT = "import";
9292

93+
public static final String RADIX_HEX = "Hex";
94+
public static final String RADIX_DECIMAL = "Decimal";
95+
public static final String RADIX_OCTAL = "Octal";
96+
public static final String RADIX_BINARY = "Binary";
97+
9398
// The text area displaying the object contents
9499
private final JTextArea _textArea;
95100

@@ -129,34 +134,7 @@ public class PopupEditableIOPanel extends JPanel
129134
private IOUtilities _iou = new IOUtilitiesImpl();
130135

131136
private final ReformatHandler _reformatHandler;
132-
133-
class BinaryOptionActionListener implements ActionListener {
134-
public void actionPerformed(ActionEvent e) {
135-
136-
// user asked to see binary data in a different format
137-
int base = 16; // default to hex
138-
if (previousRadixListItem.equals("Decimal")) base = 10;
139-
else if (previousRadixListItem.equals("Octal")) base = 8;
140-
else if (previousRadixListItem.equals("Binary")) base = 2;
141-
142-
Byte[] bytes = BinaryDisplayConverter.convertToBytes(_textArea.getText(),
143-
base, previousShowAscii);
144-
145-
// return the expected format for this data
146-
base = 16; // default to hex
147-
if (radixList.getSelectedItem().equals("Decimal")) base = 10;
148-
else if (radixList.getSelectedItem().equals("Octal")) base = 8;
149-
else if (radixList.getSelectedItem().equals("Binary")) base = 2;
150-
151-
((RestorableJTextArea) _textArea).updateText(
152-
BinaryDisplayConverter.convertToString(bytes,
153-
base, showAscii.isSelected()));
154-
155-
previousRadixListItem = (String)radixList.getSelectedItem();
156-
previousShowAscii = showAscii.isSelected();
157-
}
158-
}
159-
private BinaryOptionActionListener optionActionListener = new BinaryOptionActionListener();
137+
private boolean _dontReactToBinaryDisplayChanges;
160138

161139
// text put in file name field to indicate that we should
162140
// create a temp file for export
@@ -180,7 +158,7 @@ public PopupEditableIOPanel(ColumnDisplayDefinition colDef, Object value, boolea
180158
_colDef = colDef;
181159
_textArea = CellComponentFactory.getJTextArea(colDef, value);
182160

183-
_reformatHandler = new ReformatHandler(_textArea);
161+
_reformatHandler = new ReformatHandler(_textArea, CellComponentFactory.useBinaryEditingPanel(_colDef), () -> onOriginalTextWasRestored());
184162

185163
if (isEditable)
186164
{
@@ -222,14 +200,14 @@ public PopupEditableIOPanel(ColumnDisplayDefinition colDef, Object value, boolea
222200
{
223201
// this is a binary field, so allow for multiple viewing options
224202

225-
String[] radixListData = { "Hex", "Decimal", "Octal", "Binary" };
203+
String[] radixListData = {RADIX_HEX, RADIX_DECIMAL, RADIX_OCTAL, RADIX_BINARY};
226204
radixList = new JComboBox(radixListData);
227-
radixList.addActionListener(optionActionListener);
228-
previousRadixListItem = "Hex";
205+
radixList.addActionListener(e -> updateBinaryDisplay());
206+
previousRadixListItem = RADIX_HEX;
229207

230208
showAscii = new JCheckBox(s_stringMgr.getString("popupeditableIoPanel.showAscii"));
231209
previousShowAscii = false;
232-
showAscii.addActionListener(optionActionListener);
210+
showAscii.addActionListener(e -> updateBinaryDisplay());
233211

234212
JPanel displayControlsPanel = new JPanel();
235213
// use default sequential layout
@@ -266,6 +244,62 @@ public PopupEditableIOPanel(ColumnDisplayDefinition colDef, Object value, boolea
266244
new PasteFromHistoryAttach(_textArea);
267245
}
268246

247+
private void updateBinaryDisplay()
248+
{
249+
if(_dontReactToBinaryDisplayChanges)
250+
{
251+
return;
252+
}
253+
254+
if( _reformatHandler.isReformatted() )
255+
{
256+
Main.getApplication().getMessageHandler().showErrorMessage(s_stringMgr.getString("popupEditableIoPanel.cannot.update.binary.display.while.reformatted"));
257+
return;
258+
}
259+
260+
// user asked to see binary data in a different format
261+
int base = 16; // default to hex
262+
if (previousRadixListItem.equals(RADIX_DECIMAL)) base = 10;
263+
else if (previousRadixListItem.equals(RADIX_OCTAL)) base = 8;
264+
else if (previousRadixListItem.equals(RADIX_BINARY)) base = 2;
265+
266+
Byte[] bytes = BinaryDisplayConverter.convertToBytes(_textArea.getText(),
267+
base, previousShowAscii);
268+
269+
// return the expected format for this data
270+
base = 16; // default to hex
271+
if (Objects.equals(radixList.getSelectedItem(), RADIX_DECIMAL)) base = 10;
272+
else if (Objects.equals(radixList.getSelectedItem(), RADIX_OCTAL)) base = 8;
273+
else if (Objects.equals(radixList.getSelectedItem(), RADIX_BINARY)) base = 2;
274+
275+
((RestorableJTextArea) _textArea).updateText(
276+
BinaryDisplayConverter.convertToString(bytes, base, showAscii.isSelected()));
277+
278+
previousRadixListItem = (String)radixList.getSelectedItem();
279+
previousShowAscii = showAscii.isSelected();
280+
}
281+
282+
private void onOriginalTextWasRestored()
283+
{
284+
if(null == radixList || null == showAscii)
285+
{
286+
return;
287+
}
288+
289+
try
290+
{
291+
_dontReactToBinaryDisplayChanges = true;
292+
previousRadixListItem = RADIX_HEX;
293+
radixList.setSelectedItem(RADIX_HEX);
294+
showAscii.setSelected(false);
295+
}
296+
finally
297+
{
298+
_dontReactToBinaryDisplayChanges = false;
299+
}
300+
}
301+
302+
269303
/**
270304
* build the user interface for export/import operations
271305
*/
@@ -995,13 +1029,13 @@ private void importData(File file) {
9951029
// If the user has selected a non-cannonical Binary format, we need
9961030
// to convert the text appropriately
9971031
if (radixList != null &&
998-
! (radixList.getSelectedItem().equals("Hex") &&
1032+
! (radixList.getSelectedItem().equals(RADIX_HEX) &&
9991033
showAscii.isSelected() == false) ) {
10001034
// we need to convert to a different format
10011035
int base = 16; // default to hex
1002-
if (radixList.getSelectedItem().equals("Decimal")) base = 10;
1003-
else if (radixList.getSelectedItem().equals("Octal")) base = 8;
1004-
else if (radixList.getSelectedItem().equals("Binary")) base = 2;
1036+
if (radixList.getSelectedItem().equals(RADIX_DECIMAL)) base = 10;
1037+
else if (radixList.getSelectedItem().equals(RADIX_OCTAL)) base = 8;
1038+
else if (radixList.getSelectedItem().equals(RADIX_BINARY)) base = 2;
10051039

10061040
Byte[] bytes = BinaryDisplayConverter.convertToBytes(replacementText,
10071041
16, false);
@@ -1269,16 +1303,16 @@ private String getTextAreaCannonicalForm() {
12691303
// if the data is not binary, then there is no need for conversion.
12701304
// if the data is Hex with ASCII not shown as chars, then no conversion needed.
12711305
if (radixList == null ||
1272-
(radixList.getSelectedItem().equals("Hex") && ! showAscii.isSelected()) ) {
1306+
(radixList.getSelectedItem().equals(RADIX_HEX) && ! showAscii.isSelected()) ) {
12731307
// no need for conversion
12741308
return _textArea.getText();
12751309
}
12761310

12771311
// The field is binary and not in the format expected by the DataType
12781312
int base = 16; // default to hex
1279-
if (radixList.getSelectedItem().equals("Decimal")) base = 10;
1280-
else if (radixList.getSelectedItem().equals("Octal")) base = 8;
1281-
else if (radixList.getSelectedItem().equals("Binary")) base = 2;
1313+
if (radixList.getSelectedItem().equals(RADIX_DECIMAL)) base = 10;
1314+
else if (radixList.getSelectedItem().equals(RADIX_OCTAL)) base = 8;
1315+
else if (radixList.getSelectedItem().equals(RADIX_BINARY)) base = 2;
12821316

12831317
// the following can cause and exception if the text is not formatted correctly
12841318
Byte[] bytes = BinaryDisplayConverter.convertToBytes(_textArea.getText(),

sql12/core/src/net/sourceforge/squirrel_sql/fw/datasetviewer/celldatapopup/ReformatHandler.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package net.sourceforge.squirrel_sql.fw.datasetviewer.celldatapopup;
22

3+
import net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.BinaryDisplayConverter;
34
import net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeGeneral;
5+
import net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DisplayAsciiMode;
46
import net.sourceforge.squirrel_sql.fw.gui.GUIUtils;
57
import net.sourceforge.squirrel_sql.fw.util.StringManager;
68
import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
@@ -13,14 +15,20 @@ public class ReformatHandler
1315
private static final StringManager s_stringMgr = StringManagerFactory.getStringManager(ReformatHandler.class);
1416

1517
private final JTextArea _textArea;
18+
private final ReformatHandlerListener _reformatHandlerListener;
19+
private final boolean _originalUnformattedTextIsBinaryBase16BinaryData;
1620
private final JToggleButton _btnReformat;
1721
private String _originalUnformattedText;
1822
private boolean _reformatSilently = false;
1923

20-
public ReformatHandler(JTextArea textAreaWithOriginalUnformatedText)
24+
public ReformatHandler(JTextArea textAreaWithOriginalUnformattedText,
25+
boolean originalUnformattedTextIsBinaryBase16BinaryData,
26+
ReformatHandlerListener reformatHandlerListener)
2127
{
22-
_textArea = textAreaWithOriginalUnformatedText;
28+
_textArea = textAreaWithOriginalUnformattedText;
29+
_reformatHandlerListener = reformatHandlerListener;
2330
_originalUnformattedText = _textArea.getText();
31+
_originalUnformattedTextIsBinaryBase16BinaryData = originalUnformattedTextIsBinaryBase16BinaryData;
2432

2533
_btnReformat = new JToggleButton(s_stringMgr.getString("ReformatHandler.reformatXml"));
2634
//GUIUtils.setPreferredWidth(reformatButton, (int) (((double) reformatButton.getPreferredSize().width) * 1.2d));
@@ -76,7 +84,15 @@ private void reformat()
7684
{
7785
if(_btnReformat.isSelected())
7886
{
79-
FormattingResult formattingResult = CellDataPopupFormatter.format(_textArea.getText(), _reformatSilently);
87+
String text = _textArea.getText();
88+
89+
if(_originalUnformattedTextIsBinaryBase16BinaryData)
90+
{
91+
Byte[] bytes = BinaryDisplayConverter.convertToBytes(_originalUnformattedText, 16, false);
92+
text = BinaryDisplayConverter.convertToString(bytes, 16, DisplayAsciiMode.ASCII_NO_ADDITIONAL_SPACES);
93+
}
94+
95+
FormattingResult formattingResult = CellDataPopupFormatter.format(text, _reformatSilently);
8096
if(formattingResult.isSuccess())
8197
{
8298
_textArea.setText(formattingResult.getResult());
@@ -89,7 +105,12 @@ private void reformat()
89105
else
90106
{
91107
_textArea.setText(_originalUnformattedText);
108+
_reformatHandlerListener.originalTextWasRestored();
92109
}
93110
}
94111

112+
public boolean isReformatted()
113+
{
114+
return _btnReformat.isSelected();
115+
}
95116
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package net.sourceforge.squirrel_sql.fw.datasetviewer.celldatapopup;
2+
3+
@FunctionalInterface
4+
public interface ReformatHandlerListener
5+
{
6+
void originalTextWasRestored();
7+
}

0 commit comments

Comments
 (0)