propane 3.10.0-java → 3.11.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/wrapper/maven-wrapper.properties +1 -1
  3. data/CHANGELOG.md +2 -0
  4. data/README.md +7 -7
  5. data/lib/propane/app.rb +2 -5
  6. data/lib/propane/helper_methods.rb +6 -6
  7. data/lib/propane/version.rb +1 -1
  8. data/lib/{propane-3.10.0.jar → propane-3.11.0.jar} +0 -0
  9. data/pom.rb +6 -6
  10. data/pom.xml +6 -6
  11. data/propane.gemspec +3 -3
  12. data/src/main/java/monkstone/noise/OpenSimplex2F.java +838 -737
  13. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +8 -13
  14. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +14 -28
  15. data/src/main/java/processing/awt/PImageAWT.java +6 -4
  16. data/src/main/java/processing/core/PApplet.java +71 -59
  17. data/src/main/java/processing/core/PImage.java +14 -14
  18. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +13 -13
  19. data/src/main/java/processing/opengl/PShader.java +1 -6
  20. data/src/main/java/processing/opengl/PSurfaceJOGL.java +6 -6
  21. data/{lib/java/processing/opengl → src/main/resources}/cursors/arrow.png +0 -0
  22. data/{lib/java/processing/opengl → src/main/resources}/cursors/cross.png +0 -0
  23. data/{lib/java/processing/opengl → src/main/resources}/cursors/hand.png +0 -0
  24. data/{lib/java/processing/opengl → src/main/resources}/cursors/license.txt +0 -0
  25. data/{lib/java/processing/opengl → src/main/resources}/cursors/move.png +0 -0
  26. data/{lib/java/processing/opengl → src/main/resources}/cursors/text.png +0 -0
  27. data/{lib/java/processing/opengl → src/main/resources}/cursors/wait.png +0 -0
  28. data/{lib/java/processing/opengl → src/main/resources}/shaders/ColorFrag.glsl +0 -0
  29. data/{lib/java/processing/opengl → src/main/resources}/shaders/ColorVert.glsl +0 -0
  30. data/{lib/java/processing/opengl → src/main/resources}/shaders/LightFrag.glsl +0 -0
  31. data/{lib/java/processing/opengl → src/main/resources}/shaders/LightVert.glsl +0 -0
  32. data/{lib/java/processing/opengl → src/main/resources}/shaders/LineFrag.glsl +0 -0
  33. data/{lib/java/processing/opengl → src/main/resources}/shaders/LineVert.glsl +0 -0
  34. data/{lib/java/processing/opengl → src/main/resources}/shaders/MaskFrag.glsl +0 -0
  35. data/{lib/java/processing/opengl → src/main/resources}/shaders/PointFrag.glsl +0 -0
  36. data/{lib/java/processing/opengl → src/main/resources}/shaders/PointVert.glsl +0 -0
  37. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexFrag.glsl +0 -0
  38. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexLightFrag.glsl +0 -0
  39. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexLightVert.glsl +0 -0
  40. data/{lib/java/processing/opengl → src/main/resources}/shaders/TexVert.glsl +0 -0
  41. data/test/test_helper.rb +1 -0
  42. data/vendors/Rakefile +1 -1
  43. metadata +29 -155
  44. data/lib/java/japplemenubar/JAppleMenuBar.java +0 -88
  45. data/lib/java/japplemenubar/libjAppleMenuBar.jnilib +0 -0
  46. data/lib/java/monkstone/ColorUtil.java +0 -127
  47. data/lib/java/monkstone/MathToolModule.java +0 -287
  48. data/lib/java/monkstone/PropaneLibrary.java +0 -46
  49. data/lib/java/monkstone/core/LibraryProxy.java +0 -136
  50. data/lib/java/monkstone/fastmath/DegLutTables.java +0 -111
  51. data/lib/java/monkstone/fastmath/Deglut.java +0 -71
  52. data/lib/java/monkstone/fastmath/package-info.java +0 -6
  53. data/lib/java/monkstone/filechooser/Chooser.java +0 -39
  54. data/lib/java/monkstone/noise/FastTerrain.java +0 -874
  55. data/lib/java/monkstone/noise/Noise.java +0 -90
  56. data/lib/java/monkstone/noise/NoiseGenerator.java +0 -75
  57. data/lib/java/monkstone/noise/NoiseMode.java +0 -28
  58. data/lib/java/monkstone/noise/OpenSimplex2F.java +0 -881
  59. data/lib/java/monkstone/noise/OpenSimplex2S.java +0 -1106
  60. data/lib/java/monkstone/noise/SmoothTerrain.java +0 -1099
  61. data/lib/java/monkstone/slider/CustomHorizontalSlider.java +0 -164
  62. data/lib/java/monkstone/slider/CustomVerticalSlider.java +0 -178
  63. data/lib/java/monkstone/slider/SimpleHorizontalSlider.java +0 -145
  64. data/lib/java/monkstone/slider/SimpleSlider.java +0 -166
  65. data/lib/java/monkstone/slider/SimpleVerticalSlider.java +0 -157
  66. data/lib/java/monkstone/slider/Slider.java +0 -61
  67. data/lib/java/monkstone/slider/SliderBar.java +0 -245
  68. data/lib/java/monkstone/slider/SliderGroup.java +0 -56
  69. data/lib/java/monkstone/slider/WheelHandler.java +0 -35
  70. data/lib/java/monkstone/vecmath/GfxRender.java +0 -86
  71. data/lib/java/monkstone/vecmath/JRender.java +0 -56
  72. data/lib/java/monkstone/vecmath/ShapeRender.java +0 -87
  73. data/lib/java/monkstone/vecmath/package-info.java +0 -20
  74. data/lib/java/monkstone/vecmath/vec2/Vec2.java +0 -802
  75. data/lib/java/monkstone/vecmath/vec2/package-info.java +0 -6
  76. data/lib/java/monkstone/vecmath/vec3/Vec3.java +0 -727
  77. data/lib/java/monkstone/vecmath/vec3/package-info.java +0 -6
  78. data/lib/java/monkstone/videoevent/CaptureEvent.java +0 -27
  79. data/lib/java/monkstone/videoevent/MovieEvent.java +0 -32
  80. data/lib/java/monkstone/videoevent/package-info.java +0 -20
  81. data/lib/java/processing/awt/PGraphicsJava2D.java +0 -3040
  82. data/lib/java/processing/awt/PImageAWT.java +0 -377
  83. data/lib/java/processing/awt/PShapeJava2D.java +0 -387
  84. data/lib/java/processing/awt/PSurfaceAWT.java +0 -1581
  85. data/lib/java/processing/awt/ShimAWT.java +0 -581
  86. data/lib/java/processing/core/PApplet.java +0 -15156
  87. data/lib/java/processing/core/PConstants.java +0 -523
  88. data/lib/java/processing/core/PFont.java +0 -1126
  89. data/lib/java/processing/core/PGraphics.java +0 -8600
  90. data/lib/java/processing/core/PImage.java +0 -3377
  91. data/lib/java/processing/core/PMatrix.java +0 -208
  92. data/lib/java/processing/core/PMatrix2D.java +0 -562
  93. data/lib/java/processing/core/PMatrix3D.java +0 -890
  94. data/lib/java/processing/core/PShape.java +0 -3561
  95. data/lib/java/processing/core/PShapeOBJ.java +0 -483
  96. data/lib/java/processing/core/PShapeSVG.java +0 -2016
  97. data/lib/java/processing/core/PStyle.java +0 -63
  98. data/lib/java/processing/core/PSurface.java +0 -198
  99. data/lib/java/processing/core/PSurfaceNone.java +0 -431
  100. data/lib/java/processing/core/PVector.java +0 -1066
  101. data/lib/java/processing/core/ThinkDifferent.java +0 -115
  102. data/lib/java/processing/data/DoubleDict.java +0 -850
  103. data/lib/java/processing/data/DoubleList.java +0 -928
  104. data/lib/java/processing/data/FloatDict.java +0 -847
  105. data/lib/java/processing/data/FloatList.java +0 -936
  106. data/lib/java/processing/data/IntDict.java +0 -807
  107. data/lib/java/processing/data/IntList.java +0 -936
  108. data/lib/java/processing/data/JSONArray.java +0 -1260
  109. data/lib/java/processing/data/JSONObject.java +0 -2282
  110. data/lib/java/processing/data/JSONTokener.java +0 -435
  111. data/lib/java/processing/data/LongDict.java +0 -802
  112. data/lib/java/processing/data/LongList.java +0 -937
  113. data/lib/java/processing/data/Sort.java +0 -46
  114. data/lib/java/processing/data/StringDict.java +0 -613
  115. data/lib/java/processing/data/StringList.java +0 -800
  116. data/lib/java/processing/data/Table.java +0 -4936
  117. data/lib/java/processing/data/TableRow.java +0 -198
  118. data/lib/java/processing/data/XML.java +0 -1156
  119. data/lib/java/processing/dxf/RawDXF.java +0 -404
  120. data/lib/java/processing/event/Event.java +0 -125
  121. data/lib/java/processing/event/KeyEvent.java +0 -70
  122. data/lib/java/processing/event/MouseEvent.java +0 -114
  123. data/lib/java/processing/event/TouchEvent.java +0 -57
  124. data/lib/java/processing/javafx/PGraphicsFX2D.java +0 -32
  125. data/lib/java/processing/javafx/PSurfaceFX.java +0 -173
  126. data/lib/java/processing/net/Client.java +0 -744
  127. data/lib/java/processing/net/Server.java +0 -388
  128. data/lib/java/processing/opengl/FontTexture.java +0 -378
  129. data/lib/java/processing/opengl/FrameBuffer.java +0 -513
  130. data/lib/java/processing/opengl/LinePath.java +0 -627
  131. data/lib/java/processing/opengl/LineStroker.java +0 -681
  132. data/lib/java/processing/opengl/PGL.java +0 -3483
  133. data/lib/java/processing/opengl/PGraphics2D.java +0 -615
  134. data/lib/java/processing/opengl/PGraphics3D.java +0 -281
  135. data/lib/java/processing/opengl/PGraphicsOpenGL.java +0 -13753
  136. data/lib/java/processing/opengl/PJOGL.java +0 -2008
  137. data/lib/java/processing/opengl/PShader.java +0 -1484
  138. data/lib/java/processing/opengl/PShapeOpenGL.java +0 -5269
  139. data/lib/java/processing/opengl/PSurfaceJOGL.java +0 -1385
  140. data/lib/java/processing/opengl/Texture.java +0 -1696
  141. data/lib/java/processing/opengl/VertexBuffer.java +0 -88
  142. data/lib/java/processing/pdf/PGraphicsPDF.java +0 -581
  143. data/lib/java/processing/svg/PGraphicsSVG.java +0 -378
  144. data/src/main/java/processing/opengl/cursors/arrow.png +0 -0
  145. data/src/main/java/processing/opengl/cursors/cross.png +0 -0
  146. data/src/main/java/processing/opengl/cursors/hand.png +0 -0
  147. data/src/main/java/processing/opengl/cursors/license.txt +0 -27
  148. data/src/main/java/processing/opengl/cursors/move.png +0 -0
  149. data/src/main/java/processing/opengl/cursors/text.png +0 -0
  150. data/src/main/java/processing/opengl/cursors/wait.png +0 -0
  151. data/src/main/java/processing/opengl/shaders/ColorFrag.glsl +0 -32
  152. data/src/main/java/processing/opengl/shaders/ColorVert.glsl +0 -34
  153. data/src/main/java/processing/opengl/shaders/LightFrag.glsl +0 -33
  154. data/src/main/java/processing/opengl/shaders/LightVert.glsl +0 -151
  155. data/src/main/java/processing/opengl/shaders/LineFrag.glsl +0 -32
  156. data/src/main/java/processing/opengl/shaders/LineVert.glsl +0 -100
  157. data/src/main/java/processing/opengl/shaders/MaskFrag.glsl +0 -40
  158. data/src/main/java/processing/opengl/shaders/PointFrag.glsl +0 -32
  159. data/src/main/java/processing/opengl/shaders/PointVert.glsl +0 -56
  160. data/src/main/java/processing/opengl/shaders/TexFrag.glsl +0 -37
  161. data/src/main/java/processing/opengl/shaders/TexLightFrag.glsl +0 -37
  162. data/src/main/java/processing/opengl/shaders/TexLightVert.glsl +0 -157
  163. data/src/main/java/processing/opengl/shaders/TexVert.glsl +0 -38
@@ -1,4936 +0,0 @@
1
- /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2
-
3
- /*
4
- Part of the Processing project - http://processing.org
5
-
6
- Copyright (c) 2011-13 Ben Fry and Casey Reas
7
- Copyright (c) 2006-11 Ben Fry
8
-
9
- This library is free software; you can redistribute it and/or
10
- modify it under the terms of the GNU Lesser General Public
11
- License version 2.1 as published by the Free Software Foundation.
12
-
13
- This library is distributed in the hope that it will be useful,
14
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
- Lesser General Public License for more details.
17
-
18
- You should have received a copy of the GNU Lesser General
19
- Public License along with this library; if not, write to the
20
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21
- Boston, MA 02111-1307 USA
22
- */
23
-
24
- package processing.data;
25
-
26
- import java.io.*;
27
- import java.lang.reflect.*;
28
- import java.nio.charset.Charset;
29
- import java.sql.ResultSet;
30
- import java.sql.ResultSetMetaData;
31
- import java.sql.SQLException;
32
- import java.sql.Types;
33
- import java.util.*;
34
- import java.util.concurrent.ExecutorService;
35
- import java.util.concurrent.Executors;
36
- import java.util.zip.ZipEntry;
37
- import java.util.zip.ZipInputStream;
38
- import java.util.zip.ZipOutputStream;
39
-
40
- import javax.xml.parsers.ParserConfigurationException;
41
-
42
- import org.xml.sax.SAXException;
43
-
44
- import processing.core.PApplet;
45
- import processing.core.PConstants;
46
-
47
-
48
- /**
49
- * <p>Generic class for handling tabular data, typically from a CSV, TSV, or
50
- * other sort of spreadsheet file.</p>
51
- * <p>CSV files are
52
- * <a href="http://en.wikipedia.org/wiki/Comma-separated_values">comma separated values</a>,
53
- * often with the data in quotes. TSV files use tabs as separators, and usually
54
- * don't bother with the quotes.</p>
55
- * <p>File names should end with .csv if they're comma separated.</p>
56
- * <p>A rough "spec" for CSV can be found <a href="http://tools.ietf.org/html/rfc4180">here</a>.</p>
57
- *
58
- * @webref data:composite
59
- * @see PApplet#loadTable(String)
60
- * @see PApplet#saveTable(Table, String)
61
- * @see TableRow
62
- */
63
- public class Table {
64
- protected int rowCount;
65
- protected int allocCount;
66
-
67
- // protected boolean skipEmptyRows = true;
68
- // protected boolean skipCommentLines = true;
69
- // protected String extension = null;
70
- // protected boolean commaSeparatedValues = false;
71
- // protected boolean awfulCSV = false;
72
-
73
- protected String missingString = null;
74
- protected int missingInt = 0;
75
- protected long missingLong = 0;
76
- protected float missingFloat = Float.NaN;
77
- protected double missingDouble = Double.NaN;
78
- protected int missingCategory = -1;
79
-
80
- String[] columnTitles;
81
- HashMapBlows[] columnCategories;
82
- HashMap<String, Integer> columnIndices;
83
-
84
- protected Object[] columns; // [column]
85
-
86
- // accessible for advanced users
87
- static public final int STRING = 0;
88
- static public final int INT = 1;
89
- static public final int LONG = 2;
90
- static public final int FLOAT = 3;
91
- static public final int DOUBLE = 4;
92
- static public final int CATEGORY = 5;
93
- int[] columnTypes;
94
-
95
- protected RowIterator rowIterator;
96
-
97
- // 0 for doubling each time, otherwise the number of rows to increment on
98
- // each expansion.
99
- protected int expandIncrement;
100
-
101
-
102
- /**
103
- * Creates a new, empty table. Use addRow() to add additional rows.
104
- */
105
- public Table() {
106
- init();
107
- }
108
-
109
- /**
110
- * @nowebref
111
- */
112
- public Table(File file) throws IOException {
113
- this(file, null);
114
- }
115
-
116
-
117
- /**
118
- * version that uses a File object; future releases (or data types)
119
- * may include additional optimizations here
120
- *
121
- * @nowebref
122
- */
123
- public Table(File file, String options) throws IOException {
124
- // uses createInput() to handle .gz (and eventually .bz2) files
125
- init();
126
- parse(PApplet.createInput(file),
127
- extensionOptions(true, file.getName(), options));
128
- }
129
-
130
- /**
131
- * @nowebref
132
- */
133
- public Table(InputStream input) throws IOException {
134
- this(input, null);
135
- }
136
-
137
-
138
- /**
139
- * Read the table from a stream. Possible options include:
140
- * <ul>
141
- * <li>csv - parse the table as comma-separated values
142
- * <li>tsv - parse the table as tab-separated values
143
- * <li>newlines - this CSV file contains newlines inside individual cells
144
- * <li>header - this table has a header (title) row
145
- * </ul>
146
- *
147
- * @nowebref
148
- * @param input
149
- * @param options
150
- * @throws IOException
151
- */
152
- public Table(InputStream input, String options) throws IOException {
153
- init();
154
- parse(input, options);
155
- }
156
-
157
-
158
- public Table(Iterable<TableRow> rows) {
159
- init();
160
-
161
- int row = 0;
162
- int alloc = 10;
163
-
164
- for (TableRow incoming : rows) {
165
- if (row == 0) {
166
- setColumnTypes(incoming.getColumnTypes());
167
- setColumnTitles(incoming.getColumnTitles());
168
- // Do this after setting types, otherwise it'll attempt to parse the
169
- // allocated but empty rows, and drive CATEGORY columns nutso.
170
- setRowCount(alloc);
171
- // sometimes more columns than titles (and types?)
172
- setColumnCount(incoming.getColumnCount());
173
-
174
- } else if (row == alloc) {
175
- // Far more efficient than re-allocating all columns and doing a copy
176
- alloc *= 2;
177
- setRowCount(alloc);
178
- }
179
-
180
- //addRow(row);
181
- // try {
182
- setRow(row++, incoming);
183
- // } catch (ArrayIndexOutOfBoundsException aioobe) {
184
- // for (int i = 0; i < incoming.getColumnCount(); i++) {
185
- // System.out.format("[%d] %s%n", i, incoming.getString(i));
186
- // }
187
- // throw aioobe;
188
- // }
189
- }
190
- // Shrink the table to only the rows that were used
191
- if (row != alloc) {
192
- setRowCount(row);
193
- }
194
- }
195
-
196
-
197
- /**
198
- * @nowebref
199
- */
200
- public Table(ResultSet rs) {
201
- init();
202
- try {
203
- ResultSetMetaData rsmd = rs.getMetaData();
204
-
205
- int columnCount = rsmd.getColumnCount();
206
- setColumnCount(columnCount);
207
-
208
- for (int col = 0; col < columnCount; col++) {
209
- setColumnTitle(col, rsmd.getColumnName(col + 1));
210
-
211
- int type = rsmd.getColumnType(col + 1);
212
- switch (type) { // TODO these aren't tested. nor are they complete.
213
- case Types.INTEGER:
214
- case Types.TINYINT:
215
- case Types.SMALLINT:
216
- setColumnType(col, INT);
217
- break;
218
- case Types.BIGINT:
219
- setColumnType(col, LONG);
220
- break;
221
- case Types.FLOAT:
222
- setColumnType(col, FLOAT);
223
- break;
224
- case Types.DECIMAL:
225
- case Types.DOUBLE:
226
- case Types.REAL:
227
- setColumnType(col, DOUBLE);
228
- break;
229
- }
230
- }
231
-
232
- int row = 0;
233
- while (rs.next()) {
234
- for (int col = 0; col < columnCount; col++) {
235
- switch (columnTypes[col]) {
236
- case STRING: setString(row, col, rs.getString(col+1)); break;
237
- case INT: setInt(row, col, rs.getInt(col+1)); break;
238
- case LONG: setLong(row, col, rs.getLong(col+1)); break;
239
- case FLOAT: setFloat(row, col, rs.getFloat(col+1)); break;
240
- case DOUBLE: setDouble(row, col, rs.getDouble(col+1)); break;
241
- default: throw new IllegalArgumentException("column type " + columnTypes[col] + " not supported.");
242
- }
243
- }
244
- row++;
245
- // String[] row = new String[columnCount];
246
- // for (int col = 0; col < columnCount; col++) {
247
- // row[col] = rs.get(col + 1);
248
- // }
249
- // addRow(row);
250
- }
251
-
252
- } catch (SQLException s) {
253
- throw new RuntimeException(s);
254
- }
255
- }
256
-
257
-
258
- public Table typedParse(InputStream input, String options) throws IOException {
259
- Table table = new Table();
260
- table.setColumnTypes(this);
261
- table.parse(input, options);
262
- return table;
263
- }
264
-
265
-
266
- protected void init() {
267
- columns = new Object[0];
268
- columnTypes = new int[0];
269
- columnCategories = new HashMapBlows[0];
270
- }
271
-
272
-
273
- /*
274
- protected String checkOptions(File file, String options) throws IOException {
275
- String extension = null;
276
- String filename = file.getName();
277
- int dotIndex = filename.lastIndexOf('.');
278
- if (dotIndex != -1) {
279
- extension = filename.substring(dotIndex + 1).toLowerCase();
280
- if (!extension.equals("csv") &&
281
- !extension.equals("tsv") &&
282
- !extension.equals("html") &&
283
- !extension.equals("bin")) {
284
- // ignore extension
285
- extension = null;
286
- }
287
- }
288
- if (extension == null) {
289
- if (options == null) {
290
- throw new IOException("This table filename has no extension, and no options are set.");
291
- }
292
- } else { // extension is not null
293
- if (options == null) {
294
- options = extension;
295
- } else {
296
- // prepend the extension, it will be overridden if there's an option for it.
297
- options = extension + "," + options;
298
- }
299
- }
300
- return options;
301
- }
302
- */
303
-
304
-
305
- static final String[] loadExtensions = { "csv", "tsv", "ods", "bin" };
306
- static final String[] saveExtensions = { "csv", "tsv", "ods", "bin", "html" };
307
-
308
- static public String extensionOptions(boolean loading, String filename, String options) {
309
- String extension = PApplet.checkExtension(filename);
310
- if (extension != null) {
311
- for (String possible : loading ? loadExtensions : saveExtensions) {
312
- if (extension.equals(possible)) {
313
- if (options == null) {
314
- return extension;
315
- } else {
316
- // prepend the extension to the options (will be replaced by other
317
- // options that override it later in the load loop)
318
- return extension + "," + options;
319
- }
320
- }
321
- }
322
- }
323
- return options;
324
- }
325
-
326
-
327
- protected void parse(InputStream input, String options) throws IOException {
328
- // boolean awfulCSV = false;
329
- boolean header = false;
330
- String extension = null;
331
- boolean binary = false;
332
- String encoding = "UTF-8";
333
-
334
- String worksheet = null;
335
- final String sheetParam = "worksheet=";
336
-
337
- String[] opts = null;
338
- if (options != null) {
339
- opts = PApplet.trim(PApplet.split(options, ','));
340
- for (String opt : opts) {
341
- if (opt.equals("tsv")) {
342
- extension = "tsv";
343
- } else if (opt.equals("csv")) {
344
- extension = "csv";
345
- } else if (opt.equals("ods")) {
346
- extension = "ods";
347
- } else if (opt.equals("newlines")) {
348
- //awfulCSV = true;
349
- //extension = "csv";
350
- throw new IllegalArgumentException("The 'newlines' option is no longer necessary.");
351
- } else if (opt.equals("bin")) {
352
- binary = true;
353
- extension = "bin";
354
- } else if (opt.equals("header")) {
355
- header = true;
356
- } else if (opt.startsWith(sheetParam)) {
357
- worksheet = opt.substring(sheetParam.length());
358
- } else if (opt.startsWith("dictionary=")) {
359
- // ignore option, this is only handled by PApplet
360
- } else if (opt.startsWith("encoding=")) {
361
- encoding = opt.substring(9);
362
- } else {
363
- throw new IllegalArgumentException("'" + opt + "' is not a valid option for loading a Table");
364
- }
365
- }
366
- }
367
-
368
- if (extension == null) {
369
- throw new IllegalArgumentException("No extension specified for this Table");
370
- }
371
-
372
- if (binary) {
373
- loadBinary(input);
374
-
375
- } else if (extension.equals("ods")) {
376
- odsParse(input, worksheet, header);
377
-
378
- } else {
379
- InputStreamReader isr = new InputStreamReader(input, encoding);
380
- BufferedReader reader = new BufferedReader(isr);
381
-
382
- // strip out the Unicode BOM, if present
383
- reader.mark(1);
384
- int c = reader.read();
385
- // if not the BOM, back up to the beginning again
386
- if (c != '\uFEFF') {
387
- reader.reset();
388
- }
389
-
390
- /*
391
- if (awfulCSV) {
392
- parseAwfulCSV(reader, header);
393
- } else if ("tsv".equals(extension)) {
394
- parseBasic(reader, header, true);
395
- } else if ("csv".equals(extension)) {
396
- parseBasic(reader, header, false);
397
- }
398
- */
399
- parseBasic(reader, header, "tsv".equals(extension));
400
- }
401
- }
402
-
403
-
404
- protected void parseBasic(BufferedReader reader,
405
- boolean header, boolean tsv) throws IOException {
406
- String line = null;
407
- int row = 0;
408
- if (rowCount == 0) {
409
- setRowCount(10);
410
- }
411
- //int prev = 0; //-1;
412
- try {
413
- while ((line = reader.readLine()) != null) {
414
- if (row == getRowCount()) {
415
- setRowCount(row << 1);
416
- }
417
- if (row == 0 && header) {
418
- setColumnTitles(tsv ? PApplet.split(line, '\t') : splitLineCSV(line, reader));
419
- header = false;
420
- } else {
421
- setRow(row, tsv ? PApplet.split(line, '\t') : splitLineCSV(line, reader));
422
- row++;
423
- }
424
-
425
- if (row % 10000 == 0) {
426
- /*
427
- // this is problematic unless we're going to calculate rowCount first
428
- if (row < rowCount) {
429
- int pct = (100 * row) / rowCount;
430
- if (pct != prev) { // also prevents "0%" from showing up
431
- System.out.println(pct + "%");
432
- prev = pct;
433
- }
434
- }
435
- */
436
- try {
437
- // Sleep this thread so that the GC can catch up
438
- Thread.sleep(10);
439
- } catch (InterruptedException e) {
440
- e.printStackTrace();
441
- }
442
- }
443
- }
444
- } catch (Exception e) {
445
- throw new RuntimeException("Error reading table on line " + row, e);
446
- }
447
- // shorten or lengthen based on what's left
448
- if (row != getRowCount()) {
449
- setRowCount(row);
450
- }
451
- }
452
-
453
-
454
- // public void convertTSV(BufferedReader reader, File outputFile) throws IOException {
455
- // convertBasic(reader, true, outputFile);
456
- // }
457
-
458
-
459
- /*
460
- protected void parseAwfulCSV(BufferedReader reader,
461
- boolean header) throws IOException {
462
- char[] c = new char[100];
463
- int count = 0;
464
- boolean insideQuote = false;
465
-
466
- int alloc = 100;
467
- setRowCount(100);
468
-
469
- int row = 0;
470
- int col = 0;
471
- int ch;
472
- while ((ch = reader.read()) != -1) {
473
- if (insideQuote) {
474
- if (ch == '\"') {
475
- // this is either the end of a quoted entry, or a quote character
476
- reader.mark(1);
477
- if (reader.read() == '\"') {
478
- // it's "", which means a quote character
479
- if (count == c.length) {
480
- c = PApplet.expand(c);
481
- }
482
- c[count++] = '\"';
483
- } else {
484
- // nope, just the end of a quoted csv entry
485
- reader.reset();
486
- insideQuote = false;
487
- // TODO nothing here that prevents bad csv data from showing up
488
- // after the quote and before the comma...
489
- // set(row, col, new String(c, 0, count));
490
- // count = 0;
491
- // col++;
492
- // insideQuote = false;
493
- }
494
- } else { // inside a quote, but the character isn't a quote
495
- if (count == c.length) {
496
- c = PApplet.expand(c);
497
- }
498
- c[count++] = (char) ch;
499
- }
500
- } else { // not inside a quote
501
- if (ch == '\"') {
502
- insideQuote = true;
503
-
504
- } else if (ch == '\r' || ch == '\n') {
505
- if (ch == '\r') {
506
- // check to see if next is a '\n'
507
- reader.mark(1);
508
- if (reader.read() != '\n') {
509
- reader.reset();
510
- }
511
- }
512
- setString(row, col, new String(c, 0, count));
513
- count = 0;
514
- row++;
515
- if (row == 1 && header) {
516
- // Use internal row removal (efficient because only one row).
517
- removeTitleRow();
518
- // Un-set the header variable so that next time around, we don't
519
- // just get stuck into a loop, removing the 0th row repeatedly.
520
- header = false;
521
- // Reset the number of rows (removeTitleRow() won't reset our local 'row' counter)
522
- row = 0;
523
- }
524
- // if (row % 1000 == 0) {
525
- // PApplet.println(PApplet.nfc(row));
526
- // }
527
- if (row == alloc) {
528
- alloc *= 2;
529
- setRowCount(alloc);
530
- }
531
- col = 0;
532
-
533
- } else if (ch == ',') {
534
- setString(row, col, new String(c, 0, count));
535
- count = 0;
536
- // starting a new column, make sure we have room
537
- col++;
538
- ensureColumn(col);
539
-
540
- } else { // just a regular character, add it
541
- if (count == c.length) {
542
- c = PApplet.expand(c);
543
- }
544
- c[count++] = (char) ch;
545
- }
546
- }
547
- }
548
- // catch any leftovers
549
- if (count > 0) {
550
- setString(row, col, new String(c, 0, count));
551
- }
552
- row++; // set row to row count (the current row index + 1)
553
- if (alloc != row) {
554
- setRowCount(row); // shrink to the actual size
555
- }
556
- }
557
- */
558
-
559
-
560
- static class CommaSeparatedLine {
561
- char[] c;
562
- String[] pieces;
563
- int pieceCount;
564
-
565
- // int offset;
566
- int start; //, stop;
567
-
568
- String[] handle(String line, BufferedReader reader) throws IOException {
569
- // PApplet.println("handle() called for: " + line);
570
- start = 0;
571
- pieceCount = 0;
572
- c = line.toCharArray();
573
-
574
- // get tally of number of columns and allocate the array
575
- int cols = 1; // the first comma indicates the second column
576
- boolean quote = false;
577
- for (int i = 0; i < c.length; i++) {
578
- if (!quote && (c[i] == ',')) {
579
- cols++;
580
- } else if (c[i] == '\"') {
581
- // double double quotes (escaped quotes like "") will simply toggle
582
- // this back and forth, so it should remain accurate
583
- quote = !quote;
584
- }
585
- }
586
- pieces = new String[cols];
587
-
588
- // while (offset < c.length) {
589
- // start = offset;
590
- while (start < c.length) {
591
- boolean enough = ingest();
592
- while (!enough) {
593
- // found a newline inside the quote, grab another line
594
- String nextLine = reader.readLine();
595
- // System.out.println("extending to " + nextLine);
596
- if (nextLine == null) {
597
- // System.err.println(line);
598
- throw new IOException("Found a quoted line that wasn't terminated properly.");
599
- }
600
- // for simplicity, not bothering to skip what's already been read
601
- // from c (and reset the offset to 0), opting to make a bigger array
602
- // with both lines.
603
- char[] temp = new char[c.length + 1 + nextLine.length()];
604
- PApplet.arrayCopy(c, temp, c.length);
605
- // NOTE: we're converting to \n here, which isn't perfect
606
- temp[c.length] = '\n';
607
- nextLine.getChars(0, nextLine.length(), temp, c.length + 1);
608
- // c = temp;
609
- return handle(new String(temp), reader);
610
- //System.out.println(" full line is now " + new String(c));
611
- //stop = nextComma(c, offset);
612
- //System.out.println("stop is now " + stop);
613
- //enough = ingest();
614
- }
615
- }
616
-
617
- // Make any remaining entries blanks instead of nulls. Empty columns from
618
- // CSV are always "" not null, so this handles successive commas in a line
619
- for (int i = pieceCount; i < pieces.length; i++) {
620
- pieces[i] = "";
621
- }
622
- // PApplet.printArray(pieces);
623
- return pieces;
624
- }
625
-
626
- protected void addPiece(int start, int stop, boolean quotes) {
627
- if (quotes) {
628
- int dest = start;
629
- for (int i = start; i < stop; i++) {
630
- if (c[i] == '\"') {
631
- ++i; // step over the quote
632
- }
633
- if (i != dest) {
634
- c[dest] = c[i];
635
- }
636
- dest++;
637
- }
638
- pieces[pieceCount++] = new String(c, start, dest - start);
639
-
640
- } else {
641
- pieces[pieceCount++] = new String(c, start, stop - start);
642
- }
643
- }
644
-
645
- /**
646
- * Returns the next comma (not inside a quote) in the specified array.
647
- * @param c array to search
648
- * @param index offset at which to start looking
649
- * @return index of the comma, or -1 if line ended inside an unclosed quote
650
- */
651
- protected boolean ingest() {
652
- boolean hasEscapedQuotes = false;
653
- // not possible
654
- // if (index == c.length) { // we're already at the end
655
- // return c.length;
656
- // }
657
- boolean quoted = c[start] == '\"';
658
- if (quoted) {
659
- start++; // step over the quote
660
- }
661
- int i = start;
662
- while (i < c.length) {
663
- // PApplet.println(c[i] + " i=" + i);
664
- if (c[i] == '\"') {
665
- // if this fella started with a quote
666
- if (quoted) {
667
- if (i == c.length-1) {
668
- // closing quote for field; last field on the line
669
- addPiece(start, i, hasEscapedQuotes);
670
- start = c.length;
671
- return true;
672
-
673
- } else if (c[i+1] == '\"') {
674
- // an escaped quote inside a quoted field, step over it
675
- hasEscapedQuotes = true;
676
- i += 2;
677
-
678
- } else if (c[i+1] == ',') {
679
- // that was our closing quote, get outta here
680
- addPiece(start, i, hasEscapedQuotes);
681
- start = i+2;
682
- return true;
683
-
684
- } else {
685
- // This is a lone-wolf quote, occasionally seen in exports.
686
- // It's a single quote in the middle of some other text,
687
- // and not escaped properly. Pray for the best!
688
- i++;
689
- }
690
-
691
- } else { // not a quoted line
692
- if (i == c.length-1) {
693
- // we're at the end of the line, can't have an unescaped quote
694
- throw new RuntimeException("Unterminated quote at end of line");
695
-
696
- } else if (c[i+1] == '\"') {
697
- // step over this crummy quote escape
698
- hasEscapedQuotes = true;
699
- i += 2;
700
-
701
- } else {
702
- throw new RuntimeException("Unterminated quoted field mid-line");
703
- }
704
- }
705
- } else if (!quoted && c[i] == ',') {
706
- addPiece(start, i, hasEscapedQuotes);
707
- start = i+1;
708
- return true;
709
-
710
- } else if (!quoted && i == c.length-1) {
711
- addPiece(start, c.length, hasEscapedQuotes);
712
- start = c.length;
713
- return true;
714
-
715
- } else { // nothing all that interesting
716
- i++;
717
- }
718
- }
719
- // if (!quote && (c[i] == ',')) {
720
- // // found a comma, return this location
721
- // return i;
722
- // } else if (c[i] == '\"') {
723
- // // if it's a quote, then either the next char is another quote,
724
- // // or if this is a quoted entry, it better be a comma
725
- // quote = !quote;
726
- // }
727
- // }
728
-
729
- // if still inside a quote, indicate that another line should be read
730
- if (quoted) {
731
- return false;
732
- }
733
-
734
- // // made it to the end of the array with no new comma
735
- // return c.length;
736
-
737
- throw new RuntimeException("not sure how...");
738
- }
739
- }
740
-
741
-
742
- CommaSeparatedLine csl;
743
-
744
- /**
745
- * Parse a line of text as comma-separated values, returning each value as
746
- * one entry in an array of String objects. Remove quotes from entries that
747
- * begin and end with them, and convert 'escaped' quotes to actual quotes.
748
- * @param line line of text to be parsed
749
- * @return an array of the individual values formerly separated by commas
750
- */
751
- protected String[] splitLineCSV(String line, BufferedReader reader) throws IOException {
752
- if (csl == null) {
753
- csl = new CommaSeparatedLine();
754
- }
755
- return csl.handle(line, reader);
756
- }
757
-
758
-
759
- /**
760
- * Returns the next comma (not inside a quote) in the specified array.
761
- * @param c array to search
762
- * @param index offset at which to start looking
763
- * @return index of the comma, or -1 if line ended inside an unclosed quote
764
- */
765
- /*
766
- static protected int nextComma(char[] c, int index) {
767
- if (index == c.length) { // we're already at the end
768
- return c.length;
769
- }
770
- boolean quoted = c[index] == '\"';
771
- if (quoted) {
772
- index++; // step over the quote
773
- }
774
- for (int i = index; i < c.length; i++) {
775
- if (c[i] == '\"') {
776
- // if this fella started with a quote
777
- if (quoted) {
778
- if (i == c.length-1) {
779
- //return -1; // ran out of chars
780
- // closing quote for field; last field on the line
781
- return c.length;
782
- } else if (c[i+1] == '\"') {
783
- // an escaped quote inside a quoted field, step over it
784
- i++;
785
- } else if (c[i+1] == ',') {
786
- // that's our closing quote, get outta here
787
- return i+1;
788
- }
789
-
790
- } else { // not a quoted line
791
- if (i == c.length-1) {
792
- // we're at the end of the line, can't have an unescaped quote
793
- //return -1; // ran out of chars
794
- throw new RuntimeException("Unterminated quoted field at end of line");
795
- } else if (c[i+1] == '\"') {
796
- // step over this crummy quote escape
797
- ++i;
798
- } else {
799
- throw new RuntimeException("Unterminated quoted field mid-line");
800
- }
801
- }
802
- } else if (!quoted && c[i] == ',') {
803
- return i;
804
- }
805
- if (!quote && (c[i] == ',')) {
806
- // found a comma, return this location
807
- return i;
808
- } else if (c[i] == '\"') {
809
- // if it's a quote, then either the next char is another quote,
810
- // or if this is a quoted entry, it better be a comma
811
- quote = !quote;
812
- }
813
- }
814
- // if still inside a quote, indicate that another line should be read
815
- if (quote) {
816
- return -1;
817
- }
818
- // made it to the end of the array with no new comma
819
- return c.length;
820
- }
821
- */
822
-
823
-
824
- /**
825
- * Read a .ods (OpenDoc spreadsheet) zip file from an InputStream, and
826
- * return the InputStream for content.xml contained inside.
827
- */
828
- private InputStream odsFindContentXML(InputStream input) {
829
- ZipInputStream zis = new ZipInputStream(input);
830
- ZipEntry entry = null;
831
- try {
832
- while ((entry = zis.getNextEntry()) != null) {
833
- if (entry.getName().equals("content.xml")) {
834
- return zis;
835
- }
836
- }
837
- } catch (IOException e) {
838
- e.printStackTrace();
839
- }
840
- return null;
841
- }
842
-
843
-
844
- protected void odsParse(InputStream input, String worksheet, boolean header) {
845
- try {
846
- InputStream contentStream = odsFindContentXML(input);
847
- XML xml = new XML(contentStream);
848
-
849
- // table files will have multiple sheets..
850
- // <table:table table:name="Sheet1" table:style-name="ta1" table:print="false">
851
- // <table:table table:name="Sheet2" table:style-name="ta1" table:print="false">
852
- // <table:table table:name="Sheet3" table:style-name="ta1" table:print="false">
853
- XML[] sheets =
854
- xml.getChildren("office:body/office:spreadsheet/table:table");
855
-
856
- boolean found = false;
857
- for (XML sheet : sheets) {
858
- // System.out.println(sheet.getAttribute("table:name"));
859
- if (worksheet == null || worksheet.equals(sheet.getString("table:name"))) {
860
- odsParseSheet(sheet, header);
861
- found = true;
862
- if (worksheet == null) {
863
- break; // only read the first sheet
864
- }
865
- }
866
- }
867
- if (!found) {
868
- if (worksheet == null) {
869
- throw new RuntimeException("No worksheets found in the ODS file.");
870
- } else {
871
- throw new RuntimeException("No worksheet named " + worksheet +
872
- " found in the ODS file.");
873
- }
874
- }
875
- } catch (UnsupportedEncodingException e) {
876
- e.printStackTrace();
877
- } catch (IOException e) {
878
- e.printStackTrace();
879
- } catch (ParserConfigurationException e) {
880
- e.printStackTrace();
881
- } catch (SAXException e) {
882
- e.printStackTrace();
883
- }
884
- }
885
-
886
-
887
- /**
888
- * Parses a single sheet of XML from this file.
889
- * @param The XML object for a single worksheet from the ODS file
890
- */
891
- private void odsParseSheet(XML sheet, boolean header) {
892
- // Extra <p> or <a> tags inside the text tag for the cell will be stripped.
893
- // Different from showing formulas, and not quite the same as 'save as
894
- // displayed' option when saving from inside OpenOffice. Only time we
895
- // wouldn't want this would be so that we could parse hyperlinks and
896
- // styling information intact, but that's out of scope for the p5 version.
897
- final boolean ignoreTags = true;
898
-
899
- XML[] rows = sheet.getChildren("table:table-row");
900
- //xml.getChildren("office:body/office:spreadsheet/table:table/table:table-row");
901
-
902
- int rowIndex = 0;
903
- for (XML row : rows) {
904
- int rowRepeat = row.getInt("table:number-rows-repeated", 1);
905
- // if (rowRepeat != 1) {
906
- // System.out.println(rowRepeat + " " + rowCount + " " + (rowCount + rowRepeat));
907
- // }
908
- boolean rowNotNull = false;
909
- XML[] cells = row.getChildren();
910
- int columnIndex = 0;
911
-
912
- for (XML cell : cells) {
913
- int cellRepeat = cell.getInt("table:number-columns-repeated", 1);
914
-
915
- // <table:table-cell table:formula="of:=SUM([.E7:.E8])" office:value-type="float" office:value="4150">
916
- // <text:p>4150.00</text:p>
917
- // </table:table-cell>
918
-
919
- String cellData = ignoreTags ? cell.getString("office:value") : null;
920
-
921
- // if there's an office:value in the cell, just roll with that
922
- if (cellData == null) {
923
- int cellKids = cell.getChildCount();
924
- if (cellKids != 0) {
925
- XML[] paragraphElements = cell.getChildren("text:p");
926
- if (paragraphElements.length != 1) {
927
- for (XML el : paragraphElements) {
928
- System.err.println(el.toString());
929
- }
930
- throw new RuntimeException("found more than one text:p element");
931
- }
932
- XML textp = paragraphElements[0];
933
- String textpContent = textp.getContent();
934
- // if there are sub-elements, the content shows up as a child element
935
- // (for which getName() returns null.. which seems wrong)
936
- if (textpContent != null) {
937
- cellData = textpContent; // nothing fancy, the text is in the text:p element
938
- } else {
939
- XML[] textpKids = textp.getChildren();
940
- StringBuilder cellBuffer = new StringBuilder();
941
- for (XML kid : textpKids) {
942
- String kidName = kid.getName();
943
- if (kidName == null) {
944
- odsAppendNotNull(kid, cellBuffer);
945
-
946
- } else if (kidName.equals("text:s")) {
947
- int spaceCount = kid.getInt("text:c", 1);
948
- for (int space = 0; space < spaceCount; space++) {
949
- cellBuffer.append(' ');
950
- }
951
- } else if (kidName.equals("text:span")) {
952
- odsAppendNotNull(kid, cellBuffer);
953
-
954
- } else if (kidName.equals("text:a")) {
955
- // <text:a xlink:href="http://blah.com/">blah.com</text:a>
956
- if (ignoreTags) {
957
- cellBuffer.append(kid.getString("xlink:href"));
958
- } else {
959
- odsAppendNotNull(kid, cellBuffer);
960
- }
961
-
962
- } else {
963
- odsAppendNotNull(kid, cellBuffer);
964
- System.err.println(getClass().getName() + ": don't understand: " + kid);
965
- //throw new RuntimeException("I'm not used to this.");
966
- }
967
- }
968
- cellData = cellBuffer.toString();
969
- }
970
- //setString(rowIndex, columnIndex, c); //text[0].getContent());
971
- //columnIndex++;
972
- }
973
- }
974
- for (int r = 0; r < cellRepeat; r++) {
975
- if (cellData != null) {
976
- //System.out.println("setting " + rowIndex + "," + columnIndex + " to " + cellData);
977
- setString(rowIndex, columnIndex, cellData);
978
- }
979
- columnIndex++;
980
- if (cellData != null) {
981
- // if (columnIndex > columnMax) {
982
- // columnMax = columnIndex;
983
- // }
984
- rowNotNull = true;
985
- }
986
- }
987
- }
988
- if (header) {
989
- removeTitleRow(); // efficient enough on the first row
990
- header = false; // avoid infinite loop
991
-
992
- } else {
993
- if (rowNotNull && rowRepeat > 1) {
994
- String[] rowStrings = getStringRow(rowIndex);
995
- for (int r = 1; r < rowRepeat; r++) {
996
- addRow(rowStrings);
997
- }
998
- }
999
- rowIndex += rowRepeat;
1000
- }
1001
- }
1002
- }
1003
-
1004
-
1005
- private void odsAppendNotNull(XML kid, StringBuilder buffer) {
1006
- String content = kid.getContent();
1007
- if (content != null) {
1008
- buffer.append(content);
1009
- }
1010
- }
1011
-
1012
-
1013
- // A 'Class' object is used here, so the syntax for this function is:
1014
- // Table t = loadTable("cars3.tsv", "header");
1015
- // Record[] records = (Record[]) t.parse(Record.class);
1016
- // While t.parse("Record") might be nicer, the class is likely to be an
1017
- // inner class (another tab in a PDE sketch) or even inside a package,
1018
- // so additional information would be needed to locate it. The name of the
1019
- // inner class would be "SketchName$Record" which isn't acceptable syntax
1020
- // to make people use. Better to just introduce the '.class' syntax.
1021
-
1022
- // Unlike the Table class itself, this accepts char and boolean fields in
1023
- // the target class, since they're much more prevalent, and don't require
1024
- // a zillion extra methods and special cases in the rest of the class here.
1025
-
1026
- // since this is likely an inner class, needs a reference to its parent,
1027
- // because that's passed to the constructor parameter (inserted by the
1028
- // compiler) of an inner class by the runtime.
1029
-
1030
- /** incomplete, do not use */
1031
- public void parseInto(Object enclosingObject, String fieldName) {
1032
- Class<?> target = null;
1033
- Object outgoing = null;
1034
- Field targetField = null;
1035
- try {
1036
- // Object targetObject,
1037
- // Class target -> get this from the type of fieldName
1038
- // Class sketchClass = sketch.getClass();
1039
- Class<?> sketchClass = enclosingObject.getClass();
1040
- targetField = sketchClass.getDeclaredField(fieldName);
1041
- // PApplet.println("found " + targetField);
1042
- Class<?> targetArray = targetField.getType();
1043
- if (!targetArray.isArray()) {
1044
- // fieldName is not an array
1045
- } else {
1046
- target = targetArray.getComponentType();
1047
- outgoing = Array.newInstance(target, getRowCount());
1048
- }
1049
- } catch (NoSuchFieldException e) {
1050
- e.printStackTrace();
1051
- } catch (SecurityException e) {
1052
- e.printStackTrace();
1053
- }
1054
-
1055
- // Object enclosingObject = sketch;
1056
- // PApplet.println("enclosing obj is " + enclosingObject);
1057
- Class<?> enclosingClass = target.getEnclosingClass();
1058
- Constructor<?> con = null;
1059
-
1060
- try {
1061
- if (enclosingClass == null) {
1062
- con = target.getDeclaredConstructor(); //new Class[] { });
1063
- // PApplet.println("no enclosing class");
1064
- } else {
1065
- con = target.getDeclaredConstructor(enclosingClass);
1066
- // PApplet.println("enclosed by " + enclosingClass.getName());
1067
- }
1068
- if (!con.canAccess(null)) {
1069
- // System.out.println("setting constructor to public");
1070
- con.setAccessible(true);
1071
- }
1072
- } catch (SecurityException e) {
1073
- e.printStackTrace();
1074
- } catch (NoSuchMethodException e) {
1075
- e.printStackTrace();
1076
- }
1077
-
1078
- Field[] fields = target.getDeclaredFields();
1079
- ArrayList<Field> inuse = new ArrayList<>();
1080
- for (Field field : fields) {
1081
- String name = field.getName();
1082
- if (getColumnIndex(name, false) != -1) {
1083
- inuse.add(field);
1084
- } else {
1085
- // System.out.println("skipping field " + name);
1086
- }
1087
- }
1088
-
1089
- int index = 0;
1090
- try {
1091
- for (TableRow row : rows()) {
1092
- Object item = null;
1093
- if (enclosingClass == null) {
1094
- //item = target.newInstance();
1095
- item = con.newInstance();
1096
- } else {
1097
- item = con.newInstance(enclosingObject);
1098
- }
1099
-
1100
- // Only needed once
1101
- if (index == 0) {
1102
- for (Field field : inuse) {
1103
- if (!field.canAccess(item)) {
1104
- // PApplet.println(" changing field access");
1105
- field.setAccessible(true);
1106
- }
1107
- }
1108
- }
1109
-
1110
- //Object item = defaultCons.newInstance(new Object[] { });
1111
- for (Field field : inuse) {
1112
- String name = field.getName();
1113
- // PApplet.println("gonna set field " + name);
1114
-
1115
- if (field.getType() == String.class) {
1116
- field.set(item, row.getString(name));
1117
-
1118
- } else if (field.getType() == Integer.TYPE) {
1119
- field.setInt(item, row.getInt(name));
1120
-
1121
- } else if (field.getType() == Long.TYPE) {
1122
- field.setLong(item, row.getLong(name));
1123
-
1124
- } else if (field.getType() == Float.TYPE) {
1125
- field.setFloat(item, row.getFloat(name));
1126
-
1127
- } else if (field.getType() == Double.TYPE) {
1128
- field.setDouble(item, row.getDouble(name));
1129
-
1130
- } else if (field.getType() == Boolean.TYPE) {
1131
- String content = row.getString(name);
1132
- if (content != null) {
1133
- // Only bother setting if it's true,
1134
- // otherwise false by default anyway.
1135
- if (content.toLowerCase().equals("true") ||
1136
- content.equals("1")) {
1137
- field.setBoolean(item, true);
1138
- }
1139
- }
1140
- // if (content == null) {
1141
- // field.setBoolean(item, false); // necessary?
1142
- // } else if (content.toLowerCase().equals("true")) {
1143
- // field.setBoolean(item, true);
1144
- // } else if (content.equals("1")) {
1145
- // field.setBoolean(item, true);
1146
- // } else {
1147
- // field.setBoolean(item, false); // necessary?
1148
- // }
1149
- } else if (field.getType() == Character.TYPE) {
1150
- String content = row.getString(name);
1151
- if (content != null && content.length() > 0) {
1152
- // Otherwise set to \0 anyway
1153
- field.setChar(item, content.charAt(0));
1154
- }
1155
- }
1156
- }
1157
- // list.add(item);
1158
- Array.set(outgoing, index++, item);
1159
- }
1160
- if (!targetField.canAccess(enclosingObject)) {
1161
- // PApplet.println("setting target field to public");
1162
- targetField.setAccessible(true);
1163
- }
1164
- // Set the array in the sketch
1165
- // targetField.set(sketch, outgoing);
1166
- targetField.set(enclosingObject, outgoing);
1167
-
1168
- } catch (InstantiationException e) {
1169
- e.printStackTrace();
1170
- } catch (IllegalAccessException e) {
1171
- e.printStackTrace();
1172
- } catch (IllegalArgumentException e) {
1173
- e.printStackTrace();
1174
- } catch (InvocationTargetException e) {
1175
- e.printStackTrace();
1176
- }
1177
- }
1178
-
1179
-
1180
- public boolean save(File file, String options) throws IOException {
1181
- return save(PApplet.createOutput(file),
1182
- Table.extensionOptions(false, file.getName(), options));
1183
- }
1184
-
1185
-
1186
- public boolean save(OutputStream output, String options) {
1187
- PrintWriter writer = PApplet.createWriter(output);
1188
- String extension = null;
1189
- if (options == null) {
1190
- throw new IllegalArgumentException("No extension specified for saving this Table");
1191
- }
1192
-
1193
- String[] opts = PApplet.trim(PApplet.split(options, ','));
1194
- // Only option for save is the extension, so we can safely grab the last
1195
- extension = opts[opts.length - 1];
1196
- boolean found = false;
1197
- for (String ext : saveExtensions) {
1198
- if (extension.equals(ext)) {
1199
- found = true;
1200
- break;
1201
- }
1202
- }
1203
- // Not providing a fallback; let's make users specify an extension
1204
- if (!found) {
1205
- throw new IllegalArgumentException("'" + extension + "' not available for Table");
1206
- }
1207
-
1208
- if (extension.equals("csv")) {
1209
- writeCSV(writer);
1210
- } else if (extension.equals("tsv")) {
1211
- writeTSV(writer);
1212
- } else if (extension.equals("ods")) {
1213
- try {
1214
- saveODS(output);
1215
- } catch (IOException e) {
1216
- e.printStackTrace();
1217
- return false;
1218
- }
1219
- } else if (extension.equals("html")) {
1220
- writeHTML(writer);
1221
- } else if (extension.equals("bin")) {
1222
- try {
1223
- saveBinary(output);
1224
- } catch (IOException e) {
1225
- e.printStackTrace();
1226
- return false;
1227
- }
1228
- }
1229
- writer.flush();
1230
- writer.close();
1231
- return true;
1232
- }
1233
-
1234
-
1235
- protected void writeTSV(PrintWriter writer) {
1236
- if (columnTitles != null) {
1237
- for (int col = 0; col < columns.length; col++) {
1238
- if (col != 0) {
1239
- writer.print('\t');
1240
- }
1241
- if (columnTitles[col] != null) {
1242
- writer.print(columnTitles[col]);
1243
- }
1244
- }
1245
- writer.println();
1246
- }
1247
- for (int row = 0; row < rowCount; row++) {
1248
- for (int col = 0; col < getColumnCount(); col++) {
1249
- if (col != 0) {
1250
- writer.print('\t');
1251
- }
1252
- String entry = getString(row, col);
1253
- // just write null entries as blanks, rather than spewing 'null'
1254
- // all over the spreadsheet file.
1255
- if (entry != null) {
1256
- writer.print(entry);
1257
- }
1258
- }
1259
- writer.println();
1260
- }
1261
- writer.flush();
1262
- }
1263
-
1264
-
1265
- protected void writeCSV(PrintWriter writer) {
1266
- if (columnTitles != null) {
1267
- for (int col = 0; col < getColumnCount(); col++) {
1268
- if (col != 0) {
1269
- writer.print(',');
1270
- }
1271
- try {
1272
- if (columnTitles[col] != null) { // col < columnTitles.length &&
1273
- writeEntryCSV(writer, columnTitles[col]);
1274
- }
1275
- } catch (ArrayIndexOutOfBoundsException e) {
1276
- PApplet.printArray(columnTitles);
1277
- PApplet.printArray(columns);
1278
- throw e;
1279
- }
1280
- }
1281
- writer.println();
1282
- }
1283
- for (int row = 0; row < rowCount; row++) {
1284
- for (int col = 0; col < getColumnCount(); col++) {
1285
- if (col != 0) {
1286
- writer.print(',');
1287
- }
1288
- String entry = getString(row, col);
1289
- // just write null entries as blanks, rather than spewing 'null'
1290
- // all over the spreadsheet file.
1291
- if (entry != null) {
1292
- writeEntryCSV(writer, entry);
1293
- }
1294
- }
1295
- // Prints the newline for the row, even if it's missing
1296
- writer.println();
1297
- }
1298
- writer.flush();
1299
- }
1300
-
1301
-
1302
- protected void writeEntryCSV(PrintWriter writer, String entry) {
1303
- if (entry != null) {
1304
- if (entry.indexOf('\"') != -1) { // convert quotes to double quotes
1305
- char[] c = entry.toCharArray();
1306
- writer.print('\"');
1307
- for (int i = 0; i < c.length; i++) {
1308
- if (c[i] == '\"') {
1309
- writer.print("\"\"");
1310
- } else {
1311
- writer.print(c[i]);
1312
- }
1313
- }
1314
- writer.print('\"');
1315
-
1316
- // add quotes if commas or CR/LF are in the entry
1317
- } else if (entry.indexOf(',') != -1 ||
1318
- entry.indexOf('\n') != -1 ||
1319
- entry.indexOf('\r') != -1) {
1320
- writer.print('\"');
1321
- writer.print(entry);
1322
- writer.print('\"');
1323
-
1324
-
1325
- // add quotes if leading or trailing space
1326
- } else if ((entry.length() > 0) &&
1327
- (entry.charAt(0) == ' ' ||
1328
- entry.charAt(entry.length() - 1) == ' ')) {
1329
- writer.print('\"');
1330
- writer.print(entry);
1331
- writer.print('\"');
1332
-
1333
- } else {
1334
- writer.print(entry);
1335
- }
1336
- }
1337
- }
1338
-
1339
-
1340
- protected void writeHTML(PrintWriter writer) {
1341
- writer.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2//EN\">");
1342
- // writer.println("<!DOCTYPE html>");
1343
- // writer.println("<meta charset=\"utf-8\">");
1344
-
1345
- writer.println("<html>");
1346
- writer.println("<head>");
1347
- writer.println(" <meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />");
1348
- writer.println("</head>");
1349
-
1350
- writer.println("<body>");
1351
- writer.println(" <table>");
1352
-
1353
- if (hasColumnTitles()) {
1354
- writer.println(" <tr>");
1355
- for (String entry : getColumnTitles()) {
1356
- writer.print(" <th>");
1357
- if (entry != null) {
1358
- writeEntryHTML(writer, entry);
1359
- }
1360
- writer.println("</th>");
1361
- }
1362
- writer.println(" </tr>");
1363
- }
1364
-
1365
- for (int row = 0; row < getRowCount(); row++) {
1366
- writer.println(" <tr>");
1367
- for (int col = 0; col < getColumnCount(); col++) {
1368
- String entry = getString(row, col);
1369
- writer.print(" <td>");
1370
- if (entry != null) {
1371
- // probably not a great idea to mess w/ the export
1372
- // if (entry.startsWith("<") && entry.endsWith(">")) {
1373
- // writer.print(entry);
1374
- // } else {
1375
- writeEntryHTML(writer, entry);
1376
- // }
1377
- }
1378
- writer.println("</td>");
1379
- }
1380
- writer.println(" </tr>");
1381
- }
1382
- writer.println(" </table>");
1383
- writer.println("</body>");
1384
-
1385
- writer.println("</html>");
1386
- writer.flush();
1387
- }
1388
-
1389
-
1390
- protected void writeEntryHTML(PrintWriter writer, String entry) {
1391
- //char[] chars = entry.toCharArray();
1392
- for (char c : entry.toCharArray()) { //chars) {
1393
- if (c == '<') {
1394
- writer.print("&lt;");
1395
- } else if (c == '>') {
1396
- writer.print("&gt;");
1397
- } else if (c == '&') {
1398
- writer.print("&amp;");
1399
- // } else if (c == '\'') { // only in XML
1400
- // writer.print("&apos;");
1401
- } else if (c == '"') {
1402
- writer.print("&quot;");
1403
-
1404
- } else if (c < 32 || c > 127) { // keep in ASCII or Tidy complains
1405
- writer.print("&#");
1406
- writer.print((int) c);
1407
- writer.print(';');
1408
-
1409
- } else {
1410
- writer.print(c);
1411
- }
1412
- }
1413
- }
1414
-
1415
-
1416
- protected void saveODS(OutputStream os) throws IOException {
1417
- ZipOutputStream zos = new ZipOutputStream(os);
1418
-
1419
- final String xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1420
-
1421
- ZipEntry entry = new ZipEntry("META-INF/manifest.xml");
1422
- String[] lines = new String[] {
1423
- xmlHeader,
1424
- "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">",
1425
- " <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.spreadsheet\" manifest:version=\"1.2\" manifest:full-path=\"/\"/>",
1426
- " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>",
1427
- " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>",
1428
- " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>",
1429
- " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"settings.xml\"/>",
1430
- "</manifest:manifest>"
1431
- };
1432
- zos.putNextEntry(entry);
1433
- zos.write(PApplet.join(lines, "\n").getBytes());
1434
- zos.closeEntry();
1435
-
1436
- /*
1437
- entry = new ZipEntry("meta.xml");
1438
- lines = new String[] {
1439
- xmlHeader,
1440
- "<office:document-meta office:version=\"1.0\"" +
1441
- " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" />"
1442
- };
1443
- zos.putNextEntry(entry);
1444
- zos.write(PApplet.join(lines, "\n").getBytes());
1445
- zos.closeEntry();
1446
-
1447
- entry = new ZipEntry("meta.xml");
1448
- lines = new String[] {
1449
- xmlHeader,
1450
- "<office:document-settings office:version=\"1.0\"" +
1451
- " xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"" +
1452
- " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
1453
- " xmlns:ooo=\"http://openoffice.org/2004/office\"" +
1454
- " xmlns:xlink=\"http://www.w3.org/1999/xlink\" />"
1455
- };
1456
- zos.putNextEntry(entry);
1457
- zos.write(PApplet.join(lines, "\n").getBytes());
1458
- zos.closeEntry();
1459
-
1460
- entry = new ZipEntry("settings.xml");
1461
- lines = new String[] {
1462
- xmlHeader,
1463
- "<office:document-settings office:version=\"1.0\"" +
1464
- " xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\"" +
1465
- " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
1466
- " xmlns:ooo=\"http://openoffice.org/2004/office\"" +
1467
- " xmlns:xlink=\"http://www.w3.org/1999/xlink\" />"
1468
- };
1469
- zos.putNextEntry(entry);
1470
- zos.write(PApplet.join(lines, "\n").getBytes());
1471
- zos.closeEntry();
1472
-
1473
- entry = new ZipEntry("styles.xml");
1474
- lines = new String[] {
1475
- xmlHeader,
1476
- "<office:document-styles office:version=\"1.0\"" +
1477
- " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" />"
1478
- };
1479
- zos.putNextEntry(entry);
1480
- zos.write(PApplet.join(lines, "\n").getBytes());
1481
- zos.closeEntry();
1482
- */
1483
-
1484
- final String[] dummyFiles = new String[] {
1485
- "meta.xml", "settings.xml", "styles.xml"
1486
- };
1487
- lines = new String[] {
1488
- xmlHeader,
1489
- "<office:document-meta office:version=\"1.0\"" +
1490
- " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" />"
1491
- };
1492
- byte[] dummyBytes = PApplet.join(lines, "\n").getBytes();
1493
- for (String filename : dummyFiles) {
1494
- entry = new ZipEntry(filename);
1495
- zos.putNextEntry(entry);
1496
- zos.write(dummyBytes);
1497
- zos.closeEntry();
1498
- }
1499
-
1500
- //
1501
-
1502
- entry = new ZipEntry("mimetype");
1503
- zos.putNextEntry(entry);
1504
- zos.write("application/vnd.oasis.opendocument.spreadsheet".getBytes());
1505
- zos.closeEntry();
1506
-
1507
- //
1508
-
1509
- entry = new ZipEntry("content.xml");
1510
- zos.putNextEntry(entry);
1511
- //lines = new String[] {
1512
- writeUTF(zos, xmlHeader,
1513
- "<office:document-content" +
1514
- " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
1515
- " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" +
1516
- " xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" +
1517
- " office:version=\"1.2\">",
1518
- " <office:body>",
1519
- " <office:spreadsheet>",
1520
- " <table:table table:name=\"Sheet1\" table:print=\"false\">");
1521
- //zos.write(PApplet.join(lines, "\n").getBytes());
1522
-
1523
- byte[] rowStart = " <table:table-row>\n".getBytes();
1524
- byte[] rowStop = " </table:table-row>\n".getBytes();
1525
-
1526
- if (hasColumnTitles()) {
1527
- zos.write(rowStart);
1528
- for (int i = 0; i < getColumnCount(); i++) {
1529
- saveStringODS(zos, columnTitles[i]);
1530
- }
1531
- zos.write(rowStop);
1532
- }
1533
-
1534
- for (TableRow row : rows()) {
1535
- zos.write(rowStart);
1536
- for (int i = 0; i < getColumnCount(); i++) {
1537
- if (columnTypes[i] == STRING || columnTypes[i] == CATEGORY) {
1538
- saveStringODS(zos, row.getString(i));
1539
- } else {
1540
- saveNumberODS(zos, row.getString(i));
1541
- }
1542
- }
1543
- zos.write(rowStop);
1544
- }
1545
-
1546
- //lines = new String[] {
1547
- writeUTF(zos, " </table:table>",
1548
- " </office:spreadsheet>",
1549
- " </office:body>",
1550
- "</office:document-content>");
1551
- //zos.write(PApplet.join(lines, "\n").getBytes());
1552
- zos.closeEntry();
1553
-
1554
- zos.flush();
1555
- zos.close();
1556
- }
1557
-
1558
-
1559
- void saveStringODS(OutputStream output, String text) throws IOException {
1560
- // At this point, I should have just used the XML library. But this does
1561
- // save us from having to create the entire document in memory again before
1562
- // writing to the file. So while it's dorky, the outcome is still useful.
1563
- StringBuilder sanitized = new StringBuilder();
1564
- if (text != null) {
1565
- char[] array = text.toCharArray();
1566
- for (char c : array) {
1567
- if (c == '&') {
1568
- sanitized.append("&amp;");
1569
- } else if (c == '\'') {
1570
- sanitized.append("&apos;");
1571
- } else if (c == '"') {
1572
- sanitized.append("&quot;");
1573
- } else if (c == '<') {
1574
- sanitized.append("&lt;");
1575
- } else if (c == '>') {
1576
- sanitized.append("&rt;");
1577
- } else if (c < 32 || c > 127) {
1578
- sanitized.append("&#" + ((int) c) + ";");
1579
- } else {
1580
- sanitized.append(c);
1581
- }
1582
- }
1583
- }
1584
-
1585
- writeUTF(output,
1586
- " <table:table-cell office:value-type=\"string\">",
1587
- " <text:p>" + sanitized + "</text:p>",
1588
- " </table:table-cell>");
1589
- }
1590
-
1591
-
1592
- void saveNumberODS(OutputStream output, String text) throws IOException {
1593
- writeUTF(output,
1594
- " <table:table-cell office:value-type=\"float\" office:value=\"" + text + "\">",
1595
- " <text:p>" + text + "</text:p>",
1596
- " </table:table-cell>");
1597
- }
1598
-
1599
-
1600
- static Charset utf8;
1601
-
1602
- static void writeUTF(OutputStream output, String... lines) throws IOException {
1603
- if (utf8 == null) {
1604
- utf8 = Charset.forName("UTF-8");
1605
- }
1606
- for (String str : lines) {
1607
- output.write(str.getBytes(utf8));
1608
- output.write('\n');
1609
- }
1610
- }
1611
-
1612
-
1613
- protected void saveBinary(OutputStream os) throws IOException {
1614
- DataOutputStream output = new DataOutputStream(new BufferedOutputStream(os));
1615
- output.writeInt(0x9007AB1E); // version
1616
- output.writeInt(getRowCount());
1617
- output.writeInt(getColumnCount());
1618
- if (columnTitles != null) {
1619
- output.writeBoolean(true);
1620
- for (String title : columnTitles) {
1621
- output.writeUTF(title);
1622
- }
1623
- } else {
1624
- output.writeBoolean(false);
1625
- }
1626
- for (int i = 0; i < getColumnCount(); i++) {
1627
- //System.out.println(i + " is " + columnTypes[i]);
1628
- output.writeInt(columnTypes[i]);
1629
- }
1630
-
1631
- for (int i = 0; i < getColumnCount(); i++) {
1632
- if (columnTypes[i] == CATEGORY) {
1633
- columnCategories[i].write(output);
1634
- }
1635
- }
1636
- if (missingString == null) {
1637
- output.writeBoolean(false);
1638
- } else {
1639
- output.writeBoolean(true);
1640
- output.writeUTF(missingString);
1641
- }
1642
- output.writeInt(missingInt);
1643
- output.writeLong(missingLong);
1644
- output.writeFloat(missingFloat);
1645
- output.writeDouble(missingDouble);
1646
- output.writeInt(missingCategory);
1647
-
1648
- for (TableRow row : rows()) {
1649
- for (int col = 0; col < getColumnCount(); col++) {
1650
- switch (columnTypes[col]) {
1651
- case STRING:
1652
- String str = row.getString(col);
1653
- if (str == null) {
1654
- output.writeBoolean(false);
1655
- } else {
1656
- output.writeBoolean(true);
1657
- output.writeUTF(str);
1658
- }
1659
- break;
1660
- case INT:
1661
- output.writeInt(row.getInt(col));
1662
- break;
1663
- case LONG:
1664
- output.writeLong(row.getLong(col));
1665
- break;
1666
- case FLOAT:
1667
- output.writeFloat(row.getFloat(col));
1668
- break;
1669
- case DOUBLE:
1670
- output.writeDouble(row.getDouble(col));
1671
- break;
1672
- case CATEGORY:
1673
- String peace = row.getString(col);
1674
- if (peace.equals(missingString)) {
1675
- output.writeInt(missingCategory);
1676
- } else {
1677
- output.writeInt(columnCategories[col].index(peace));
1678
- }
1679
- break;
1680
- }
1681
- }
1682
- }
1683
-
1684
- output.flush();
1685
- output.close();
1686
- }
1687
-
1688
-
1689
- protected void loadBinary(InputStream is) throws IOException {
1690
- DataInputStream input = new DataInputStream(new BufferedInputStream(is));
1691
-
1692
- int magic = input.readInt();
1693
- if (magic != 0x9007AB1E) {
1694
- throw new IOException("Not a compatible binary table (magic was " + PApplet.hex(magic) + ")");
1695
- }
1696
- int rowCount = input.readInt();
1697
- setRowCount(rowCount);
1698
- int columnCount = input.readInt();
1699
- setColumnCount(columnCount);
1700
-
1701
- boolean hasTitles = input.readBoolean();
1702
- if (hasTitles) {
1703
- columnTitles = new String[getColumnCount()];
1704
- for (int i = 0; i < columnCount; i++) {
1705
- //columnTitles[i] = input.readUTF();
1706
- setColumnTitle(i, input.readUTF());
1707
- }
1708
- }
1709
- for (int column = 0; column < columnCount; column++) {
1710
- int newType = input.readInt();
1711
- columnTypes[column] = newType;
1712
- switch (newType) {
1713
- case INT:
1714
- columns[column] = new int[rowCount];
1715
- break;
1716
- case LONG:
1717
- columns[column] = new long[rowCount];
1718
- break;
1719
- case FLOAT:
1720
- columns[column] = new float[rowCount];
1721
- break;
1722
- case DOUBLE:
1723
- columns[column] = new double[rowCount];
1724
- break;
1725
- case STRING:
1726
- columns[column] = new String[rowCount];
1727
- break;
1728
- case CATEGORY:
1729
- columns[column] = new int[rowCount];
1730
- break;
1731
- default:
1732
- throw new IllegalArgumentException(newType + " is not a valid column type.");
1733
- }
1734
- }
1735
-
1736
- for (int i = 0; i < columnCount; i++) {
1737
- if (columnTypes[i] == CATEGORY) {
1738
- columnCategories[i] = new HashMapBlows(input);
1739
- }
1740
- }
1741
-
1742
- if (input.readBoolean()) {
1743
- missingString = input.readUTF();
1744
- } else {
1745
- missingString = null;
1746
- }
1747
- missingInt = input.readInt();
1748
- missingLong = input.readLong();
1749
- missingFloat = input.readFloat();
1750
- missingDouble = input.readDouble();
1751
- missingCategory = input.readInt();
1752
-
1753
- for (int row = 0; row < rowCount; row++) {
1754
- for (int col = 0; col < columnCount; col++) {
1755
- switch (columnTypes[col]) {
1756
- case STRING:
1757
- String str = null;
1758
- if (input.readBoolean()) {
1759
- str = input.readUTF();
1760
- }
1761
- setString(row, col, str);
1762
- break;
1763
- case INT:
1764
- setInt(row, col, input.readInt());
1765
- break;
1766
- case LONG:
1767
- setLong(row, col, input.readLong());
1768
- break;
1769
- case FLOAT:
1770
- setFloat(row, col, input.readFloat());
1771
- break;
1772
- case DOUBLE:
1773
- setDouble(row, col, input.readDouble());
1774
- break;
1775
- case CATEGORY:
1776
- int index = input.readInt();
1777
- //String name = columnCategories[col].key(index);
1778
- setInt(row, col, index);
1779
- break;
1780
- }
1781
- }
1782
- }
1783
-
1784
- input.close();
1785
- }
1786
-
1787
-
1788
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1789
-
1790
-
1791
- /**
1792
- * @webref table:method
1793
- * @brief Adds a new column to a table
1794
- * @see Table#removeColumn(String)
1795
- */
1796
- public void addColumn() {
1797
- addColumn(null, STRING);
1798
- }
1799
-
1800
-
1801
- /**
1802
- * @param title the title to be used for the new column
1803
- */
1804
- public void addColumn(String title) {
1805
- addColumn(title, STRING);
1806
- }
1807
-
1808
-
1809
- /**
1810
- * @param type the type to be used for the new column: INT, LONG, FLOAT, DOUBLE, or STRING
1811
- */
1812
- public void addColumn(String title, int type) {
1813
- insertColumn(columns.length, title, type);
1814
- }
1815
-
1816
-
1817
- public void insertColumn(int index) {
1818
- insertColumn(index, null, STRING);
1819
- }
1820
-
1821
-
1822
- public void insertColumn(int index, String title) {
1823
- insertColumn(index, title, STRING);
1824
- }
1825
-
1826
-
1827
- public void insertColumn(int index, String title, int type) {
1828
- if (title != null && columnTitles == null) {
1829
- columnTitles = new String[columns.length];
1830
- }
1831
- if (columnTitles != null) {
1832
- columnTitles = PApplet.splice(columnTitles, title, index);
1833
- columnIndices = null;
1834
- }
1835
- columnTypes = PApplet.splice(columnTypes, type, index);
1836
-
1837
- // columnCategories = (HashMapBlows[])
1838
- // PApplet.splice(columnCategories, new HashMapBlows(), index);
1839
- HashMapBlows[] catTemp = new HashMapBlows[columns.length + 1];
1840
- // Faster than arrayCopy for a dozen or so entries
1841
- for (int i = 0; i < index; i++) {
1842
- catTemp[i] = columnCategories[i];
1843
- }
1844
- catTemp[index] = new HashMapBlows();
1845
- for (int i = index; i < columns.length; i++) {
1846
- catTemp[i+1] = columnCategories[i];
1847
- }
1848
- columnCategories = catTemp;
1849
-
1850
- Object[] temp = new Object[columns.length + 1];
1851
- System.arraycopy(columns, 0, temp, 0, index);
1852
- System.arraycopy(columns, index, temp, index+1, columns.length - index);
1853
- columns = temp;
1854
-
1855
- switch (type) {
1856
- case INT: columns[index] = new int[rowCount]; break;
1857
- case LONG: columns[index] = new long[rowCount]; break;
1858
- case FLOAT: columns[index] = new float[rowCount]; break;
1859
- case DOUBLE: columns[index] = new double[rowCount]; break;
1860
- case STRING: columns[index] = new String[rowCount]; break;
1861
- case CATEGORY: columns[index] = new int[rowCount]; break;
1862
- }
1863
- }
1864
-
1865
- /**
1866
- * @webref table:method
1867
- * @brief Removes a column from a table
1868
- * @param columnName the title of the column to be removed
1869
- * @see Table#addColumn()
1870
- */
1871
- public void removeColumn(String columnName) {
1872
- removeColumn(getColumnIndex(columnName));
1873
- }
1874
-
1875
- /**
1876
- * @param column the index number of the column to be removed
1877
- */
1878
- public void removeColumn(int column) {
1879
- int newCount = columns.length - 1;
1880
-
1881
- Object[] columnsTemp = new Object[newCount];
1882
- HashMapBlows[] catTemp = new HashMapBlows[newCount];
1883
-
1884
- for (int i = 0; i < column; i++) {
1885
- columnsTemp[i] = columns[i];
1886
- catTemp[i] = columnCategories[i];
1887
- }
1888
- for (int i = column; i < newCount; i++) {
1889
- columnsTemp[i] = columns[i+1];
1890
- catTemp[i] = columnCategories[i+1];
1891
- }
1892
-
1893
- columns = columnsTemp;
1894
- columnCategories = catTemp;
1895
-
1896
- if (columnTitles != null) {
1897
- String[] titlesTemp = new String[newCount];
1898
- for (int i = 0; i < column; i++) {
1899
- titlesTemp[i] = columnTitles[i];
1900
- }
1901
- for (int i = column; i < newCount; i++) {
1902
- titlesTemp[i] = columnTitles[i+1];
1903
- }
1904
- columnTitles = titlesTemp;
1905
- columnIndices = null;
1906
- }
1907
- }
1908
-
1909
-
1910
- /**
1911
- * @webref table:method
1912
- * @brief Gets the number of columns in a table
1913
- * @see Table#getRowCount()
1914
- */
1915
- public int getColumnCount() {
1916
- return columns.length;
1917
- }
1918
-
1919
-
1920
- /**
1921
- * Change the number of columns in this table. Resizes all rows to ensure
1922
- * the same number of columns in each row. Entries in the additional (empty)
1923
- * columns will be set to null.
1924
- * @param newCount
1925
- */
1926
- public void setColumnCount(int newCount) {
1927
- int oldCount = columns.length;
1928
- if (oldCount != newCount) {
1929
- columns = (Object[]) PApplet.expand(columns, newCount);
1930
- // create new columns, default to String as the data type
1931
- for (int c = oldCount; c < newCount; c++) {
1932
- columns[c] = new String[rowCount];
1933
- }
1934
-
1935
- if (columnTitles != null) {
1936
- columnTitles = PApplet.expand(columnTitles, newCount);
1937
- }
1938
- columnTypes = PApplet.expand(columnTypes, newCount);
1939
- columnCategories = (HashMapBlows[])
1940
- PApplet.expand(columnCategories, newCount);
1941
- }
1942
- }
1943
-
1944
-
1945
- public void setColumnType(String columnName, String columnType) {
1946
- setColumnType(checkColumnIndex(columnName), columnType);
1947
- }
1948
-
1949
-
1950
- static int parseColumnType(String columnType) {
1951
- columnType = columnType.toLowerCase();
1952
- int type = -1;
1953
- if (columnType.equals("string")) {
1954
- type = STRING;
1955
- } else if (columnType.equals("int")) {
1956
- type = INT;
1957
- } else if (columnType.equals("long")) {
1958
- type = LONG;
1959
- } else if (columnType.equals("float")) {
1960
- type = FLOAT;
1961
- } else if (columnType.equals("double")) {
1962
- type = DOUBLE;
1963
- } else if (columnType.equals("category")) {
1964
- type = CATEGORY;
1965
- } else {
1966
- throw new IllegalArgumentException("'" + columnType + "' is not a valid column type.");
1967
- }
1968
- return type;
1969
- }
1970
-
1971
-
1972
- /**
1973
- * Set the data type for a column so that using it is more efficient.
1974
- * @param column the column to change
1975
- * @param columnType One of int, long, float, double, string, or category.
1976
- */
1977
- public void setColumnType(int column, String columnType) {
1978
- setColumnType(column, parseColumnType(columnType));
1979
- }
1980
-
1981
-
1982
- public void setColumnType(String columnName, int newType) {
1983
- setColumnType(checkColumnIndex(columnName), newType);
1984
- }
1985
-
1986
-
1987
- /**
1988
- * Sets the column type. If data already exists, then it'll be converted to
1989
- * the new type.
1990
- * @param column the column whose type should be changed
1991
- * @param newType something fresh, maybe try an int or a float for size?
1992
- */
1993
- public void setColumnType(int column, int newType) {
1994
- switch (newType) {
1995
- case INT: {
1996
- int[] intData = new int[rowCount];
1997
- for (int row = 0; row < rowCount; row++) {
1998
- String s = getString(row, column);
1999
- intData[row] = (s == null) ? missingInt : PApplet.parseInt(s, missingInt);
2000
- }
2001
- columns[column] = intData;
2002
- break;
2003
- }
2004
- case LONG: {
2005
- long[] longData = new long[rowCount];
2006
- for (int row = 0; row < rowCount; row++) {
2007
- String s = getString(row, column);
2008
- try {
2009
- longData[row] = (s == null) ? missingLong : Long.parseLong(s);
2010
- } catch (NumberFormatException nfe) {
2011
- longData[row] = missingLong;
2012
- }
2013
- }
2014
- columns[column] = longData;
2015
- break;
2016
- }
2017
- case FLOAT: {
2018
- float[] floatData = new float[rowCount];
2019
- for (int row = 0; row < rowCount; row++) {
2020
- String s = getString(row, column);
2021
- floatData[row] = (s == null) ? missingFloat : PApplet.parseFloat(s, missingFloat);
2022
- }
2023
- columns[column] = floatData;
2024
- break;
2025
- }
2026
- case DOUBLE: {
2027
- double[] doubleData = new double[rowCount];
2028
- for (int row = 0; row < rowCount; row++) {
2029
- String s = getString(row, column);
2030
- try {
2031
- doubleData[row] = (s == null) ? missingDouble : Double.parseDouble(s);
2032
- } catch (NumberFormatException nfe) {
2033
- doubleData[row] = missingDouble;
2034
- }
2035
- }
2036
- columns[column] = doubleData;
2037
- break;
2038
- }
2039
- case STRING: {
2040
- if (columnTypes[column] != STRING) {
2041
- String[] stringData = new String[rowCount];
2042
- for (int row = 0; row < rowCount; row++) {
2043
- stringData[row] = getString(row, column);
2044
- }
2045
- columns[column] = stringData;
2046
- }
2047
- break;
2048
- }
2049
- case CATEGORY: {
2050
- int[] indexData = new int[rowCount];
2051
- HashMapBlows categories = new HashMapBlows();
2052
- for (int row = 0; row < rowCount; row++) {
2053
- String s = getString(row, column);
2054
- indexData[row] = categories.index(s);
2055
- }
2056
- columnCategories[column] = categories;
2057
- columns[column] = indexData;
2058
- break;
2059
- }
2060
- default: {
2061
- throw new IllegalArgumentException("That's not a valid column type.");
2062
- }
2063
- }
2064
- // System.out.println("new type is " + newType);
2065
- columnTypes[column] = newType;
2066
- }
2067
-
2068
-
2069
- /**
2070
- * Set the entire table to a specific data type.
2071
- */
2072
- public void setTableType(String type) {
2073
- for (int col = 0; col < getColumnCount(); col++) {
2074
- setColumnType(col, type);
2075
- }
2076
- }
2077
-
2078
-
2079
- public void setColumnTypes(int[] types) {
2080
- ensureColumn(types.length - 1);
2081
- for (int col = 0; col < types.length; col++) {
2082
- setColumnType(col, types[col]);
2083
- }
2084
- }
2085
-
2086
-
2087
- /**
2088
- * Set the titles (and if a second column is present) the data types for
2089
- * this table based on a file loaded separately. This will look for the
2090
- * title in column 0, and the type in column 1. Better yet, specify a
2091
- * column named "title" and another named "type" in the dictionary table
2092
- * to future-proof the code.
2093
- * @param dictionary
2094
- */
2095
- public void setColumnTypes(final Table dictionary) {
2096
- ensureColumn(dictionary.getRowCount() - 1);
2097
- int titleCol = 0;
2098
- int typeCol = 1;
2099
- if (dictionary.hasColumnTitles()) {
2100
- titleCol = dictionary.getColumnIndex("title", true);
2101
- typeCol = dictionary.getColumnIndex("type", true);
2102
- }
2103
- setColumnTitles(dictionary.getStringColumn(titleCol));
2104
- final String[] typeNames = dictionary.getStringColumn(typeCol);
2105
-
2106
- if (dictionary.getColumnCount() > 1) {
2107
- if (getRowCount() > 1000) {
2108
- int proc = Runtime.getRuntime().availableProcessors();
2109
- ExecutorService pool = Executors.newFixedThreadPool(proc/2);
2110
- for (int i = 0; i < dictionary.getRowCount(); i++) {
2111
- final int col = i;
2112
- pool.execute(new Runnable() {
2113
- public void run() {
2114
- setColumnType(col, typeNames[col]);
2115
- }
2116
- });
2117
- }
2118
- pool.shutdown();
2119
- while (!pool.isTerminated()) {
2120
- Thread.yield();
2121
- }
2122
-
2123
- } else {
2124
- for (int col = 0; col < dictionary.getRowCount(); col++) {
2125
- // setColumnType(i, dictionary.getString(i, typeCol));
2126
- setColumnType(col, typeNames[col]);
2127
- }
2128
- }
2129
- }
2130
- }
2131
-
2132
-
2133
- public int getColumnType(String columnName) {
2134
- return getColumnType(getColumnIndex(columnName));
2135
- }
2136
-
2137
-
2138
- /** Returns one of Table.STRING, Table.INT, etc... */
2139
- public int getColumnType(int column) {
2140
- return columnTypes[column];
2141
- }
2142
-
2143
-
2144
- public int[] getColumnTypes() {
2145
- return columnTypes;
2146
- }
2147
-
2148
-
2149
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2150
-
2151
-
2152
- /**
2153
- * Remove the first row from the data set, and use it as the column titles.
2154
- * Use loadTable("table.csv", "header") instead.
2155
- */
2156
- @Deprecated
2157
- public String[] removeTitleRow() {
2158
- String[] titles = getStringRow(0);
2159
- removeRow(0);
2160
- setColumnTitles(titles);
2161
- return titles;
2162
- }
2163
-
2164
-
2165
- public void setColumnTitles(String[] titles) {
2166
- if (titles != null) {
2167
- ensureColumn(titles.length - 1);
2168
- }
2169
- columnTitles = titles;
2170
- columnIndices = null; // remove the cache
2171
- }
2172
-
2173
-
2174
- public void setColumnTitle(int column, String title) {
2175
- ensureColumn(column);
2176
- if (columnTitles == null) {
2177
- columnTitles = new String[getColumnCount()];
2178
- }
2179
- columnTitles[column] = title;
2180
- columnIndices = null; // reset these fellas
2181
- }
2182
-
2183
-
2184
- public boolean hasColumnTitles() {
2185
- return columnTitles != null;
2186
- }
2187
-
2188
-
2189
- public String[] getColumnTitles() {
2190
- return columnTitles;
2191
- }
2192
-
2193
-
2194
- public String getColumnTitle(int col) {
2195
- return (columnTitles == null) ? null : columnTitles[col];
2196
- }
2197
-
2198
-
2199
- public int getColumnIndex(String columnName) {
2200
- return getColumnIndex(columnName, true);
2201
- }
2202
-
2203
-
2204
- /**
2205
- * Get the index of a column.
2206
- * @param name Name of the column.
2207
- * @param report Whether to throw an exception if the column wasn't found.
2208
- * @return index of the found column, or -1 if not found.
2209
- */
2210
- protected int getColumnIndex(String name, boolean report) {
2211
- if (columnTitles == null) {
2212
- if (report) {
2213
- throw new IllegalArgumentException("This table has no header, so no column titles are set.");
2214
- }
2215
- return -1;
2216
- }
2217
- // only create this on first get(). subsequent calls to set the title will
2218
- // also update this array, but only if it exists.
2219
- if (columnIndices == null) {
2220
- columnIndices = new HashMap<>();
2221
- for (int col = 0; col < columns.length; col++) {
2222
- columnIndices.put(columnTitles[col], col);
2223
- }
2224
- }
2225
- Integer index = columnIndices.get(name);
2226
- if (index == null) {
2227
- if (report) {
2228
- // Throws an exception here because the name is known and therefore most useful.
2229
- // (Rather than waiting for it to fail inside, say, getInt())
2230
- throw new IllegalArgumentException("This table has no column named '" + name + "'");
2231
- }
2232
- return -1;
2233
- }
2234
- return index.intValue();
2235
- }
2236
-
2237
-
2238
- /**
2239
- * Same as getColumnIndex(), but creates the column if it doesn't exist.
2240
- * Named this way to not conflict with checkColumn(), an internal function
2241
- * used to ensure that a columns exists, and also to denote that it returns
2242
- * an int for the column index.
2243
- * @param title column title
2244
- * @return index of a new or previously existing column
2245
- */
2246
- public int checkColumnIndex(String title) {
2247
- int index = getColumnIndex(title, false);
2248
- if (index != -1) {
2249
- return index;
2250
- }
2251
- addColumn(title);
2252
- return getColumnCount() - 1;
2253
- }
2254
-
2255
-
2256
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2257
-
2258
- /**
2259
- * @webref table:method
2260
- * @brief Gets the number of rows in a table
2261
- * @see Table#getColumnCount()
2262
- */
2263
- public int getRowCount() {
2264
- return rowCount;
2265
- }
2266
-
2267
-
2268
- public int lastRowIndex() {
2269
- return getRowCount() - 1;
2270
- }
2271
-
2272
-
2273
- /**
2274
- * @webref table:method
2275
- * @brief Removes all rows from a table
2276
- * @see Table#addRow()
2277
- * @see Table#removeRow(int)
2278
- */
2279
- public void clearRows() {
2280
- setRowCount(0);
2281
- }
2282
-
2283
-
2284
- public void setRowCount(int newCount) {
2285
- if (newCount != rowCount) {
2286
- if (newCount > 1000000) {
2287
- System.out.print("Note: setting maximum row count to " + PApplet.nfc(newCount));
2288
- }
2289
- long t = System.currentTimeMillis();
2290
- for (int col = 0; col < columns.length; col++) {
2291
- switch (columnTypes[col]) {
2292
- case INT: columns[col] = PApplet.expand((int[]) columns[col], newCount); break;
2293
- case LONG: columns[col] = PApplet.expand((long[]) columns[col], newCount); break;
2294
- case FLOAT: columns[col] = PApplet.expand((float[]) columns[col], newCount); break;
2295
- case DOUBLE: columns[col] = PApplet.expand((double[]) columns[col], newCount); break;
2296
- case STRING: columns[col] = PApplet.expand((String[]) columns[col], newCount); break;
2297
- case CATEGORY: columns[col] = PApplet.expand((int[]) columns[col], newCount); break;
2298
- }
2299
- if (newCount > 1000000) {
2300
- try {
2301
- Thread.sleep(10); // gc time!
2302
- } catch (InterruptedException e) {
2303
- e.printStackTrace();
2304
- }
2305
- }
2306
- }
2307
- if (newCount > 1000000) {
2308
- int ms = (int) (System.currentTimeMillis() - t);
2309
- System.out.println(" (resize took " + PApplet.nfc(ms) + " ms)");
2310
- }
2311
- }
2312
- rowCount = newCount;
2313
- }
2314
-
2315
-
2316
- /**
2317
- * @webref table:method
2318
- * @brief Adds a row to a table
2319
- * @see Table#removeRow(int)
2320
- * @see Table#clearRows()
2321
- */
2322
- public TableRow addRow() {
2323
- //if (rowIncrement == 0) {
2324
- setRowCount(rowCount + 1);
2325
- return new RowPointer(this, rowCount - 1);
2326
- }
2327
-
2328
-
2329
- /**
2330
- * @param source a reference to the original row to be duplicated
2331
- */
2332
- public TableRow addRow(TableRow source) {
2333
- return setRow(rowCount, source);
2334
- }
2335
-
2336
-
2337
- public TableRow setRow(int row, TableRow source) {
2338
- // Make sure there are enough columns to add this data
2339
- ensureBounds(row, source.getColumnCount() - 1);
2340
-
2341
- for (int col = 0; col < Math.min(source.getColumnCount(), columns.length); col++) {
2342
- switch (columnTypes[col]) {
2343
- case INT:
2344
- setInt(row, col, source.getInt(col));
2345
- break;
2346
- case LONG:
2347
- setLong(row, col, source.getLong(col));
2348
- break;
2349
- case FLOAT:
2350
- setFloat(row, col, source.getFloat(col));
2351
- break;
2352
- case DOUBLE:
2353
- setDouble(row, col, source.getDouble(col));
2354
- break;
2355
- case STRING:
2356
- setString(row, col, source.getString(col));
2357
- break;
2358
- case CATEGORY:
2359
- int index = source.getInt(col);
2360
- setInt(row, col, index);
2361
- if (!columnCategories[col].hasCategory(index)) {
2362
- columnCategories[col].setCategory(index, source.getString(col));
2363
- }
2364
- break;
2365
-
2366
- default:
2367
- throw new RuntimeException("no types");
2368
- }
2369
- }
2370
- return new RowPointer(this, row);
2371
- }
2372
-
2373
-
2374
- /**
2375
- * @nowebref
2376
- */
2377
- public TableRow addRow(Object[] columnData) {
2378
- setRow(getRowCount(), columnData);
2379
- return new RowPointer(this, rowCount - 1);
2380
- }
2381
-
2382
-
2383
- public void addRows(Table source) {
2384
- int index = getRowCount();
2385
- setRowCount(index + source.getRowCount());
2386
- for (TableRow row : source.rows()) {
2387
- setRow(index++, row);
2388
- }
2389
- }
2390
-
2391
-
2392
- public void insertRow(int insert, Object[] columnData) {
2393
- for (int col = 0; col < columns.length; col++) {
2394
- switch (columnTypes[col]) {
2395
- case CATEGORY:
2396
- case INT: {
2397
- int[] intTemp = new int[rowCount+1];
2398
- System.arraycopy(columns[col], 0, intTemp, 0, insert);
2399
- System.arraycopy(columns[col], insert, intTemp, insert+1, rowCount - insert);
2400
- columns[col] = intTemp;
2401
- break;
2402
- }
2403
- case LONG: {
2404
- long[] longTemp = new long[rowCount+1];
2405
- System.arraycopy(columns[col], 0, longTemp, 0, insert);
2406
- System.arraycopy(columns[col], insert, longTemp, insert+1, rowCount - insert);
2407
- columns[col] = longTemp;
2408
- break;
2409
- }
2410
- case FLOAT: {
2411
- float[] floatTemp = new float[rowCount+1];
2412
- System.arraycopy(columns[col], 0, floatTemp, 0, insert);
2413
- System.arraycopy(columns[col], insert, floatTemp, insert+1, rowCount - insert);
2414
- columns[col] = floatTemp;
2415
- break;
2416
- }
2417
- case DOUBLE: {
2418
- double[] doubleTemp = new double[rowCount+1];
2419
- System.arraycopy(columns[col], 0, doubleTemp, 0, insert);
2420
- System.arraycopy(columns[col], insert, doubleTemp, insert+1, rowCount - insert);
2421
- columns[col] = doubleTemp;
2422
- break;
2423
- }
2424
- case STRING: {
2425
- String[] stringTemp = new String[rowCount+1];
2426
- System.arraycopy(columns[col], 0, stringTemp, 0, insert);
2427
- System.arraycopy(columns[col], insert, stringTemp, insert+1, rowCount - insert);
2428
- columns[col] = stringTemp;
2429
- break;
2430
- }
2431
- }
2432
- }
2433
- // Need to increment before setRow(), because it calls ensureBounds()
2434
- // https://github.com/processing/processing/issues/5406
2435
- ++rowCount;
2436
- setRow(insert, columnData);
2437
- }
2438
-
2439
-
2440
- /**
2441
- * @webref table:method
2442
- * @brief Removes a row from a table
2443
- * @param row ID number of the row to remove
2444
- * @see Table#addRow()
2445
- * @see Table#clearRows()
2446
- */
2447
- public void removeRow(int row) {
2448
- for (int col = 0; col < columns.length; col++) {
2449
- switch (columnTypes[col]) {
2450
- case CATEGORY:
2451
- case INT: {
2452
- int[] intTemp = new int[rowCount-1];
2453
- // int[] intData = (int[]) columns[col];
2454
- // System.arraycopy(intData, 0, intTemp, 0, dead);
2455
- // System.arraycopy(intData, dead+1, intTemp, dead, (rowCount - dead) + 1);
2456
- System.arraycopy(columns[col], 0, intTemp, 0, row);
2457
- System.arraycopy(columns[col], row+1, intTemp, row, (rowCount - row) - 1);
2458
- columns[col] = intTemp;
2459
- break;
2460
- }
2461
- case LONG: {
2462
- long[] longTemp = new long[rowCount-1];
2463
- // long[] longData = (long[]) columns[col];
2464
- // System.arraycopy(longData, 0, longTemp, 0, dead);
2465
- // System.arraycopy(longData, dead+1, longTemp, dead, (rowCount - dead) + 1);
2466
- System.arraycopy(columns[col], 0, longTemp, 0, row);
2467
- System.arraycopy(columns[col], row+1, longTemp, row, (rowCount - row) - 1);
2468
- columns[col] = longTemp;
2469
- break;
2470
- }
2471
- case FLOAT: {
2472
- float[] floatTemp = new float[rowCount-1];
2473
- // float[] floatData = (float[]) columns[col];
2474
- // System.arraycopy(floatData, 0, floatTemp, 0, dead);
2475
- // System.arraycopy(floatData, dead+1, floatTemp, dead, (rowCount - dead) + 1);
2476
- System.arraycopy(columns[col], 0, floatTemp, 0, row);
2477
- System.arraycopy(columns[col], row+1, floatTemp, row, (rowCount - row) - 1);
2478
- columns[col] = floatTemp;
2479
- break;
2480
- }
2481
- case DOUBLE: {
2482
- double[] doubleTemp = new double[rowCount-1];
2483
- // double[] doubleData = (double[]) columns[col];
2484
- // System.arraycopy(doubleData, 0, doubleTemp, 0, dead);
2485
- // System.arraycopy(doubleData, dead+1, doubleTemp, dead, (rowCount - dead) + 1);
2486
- System.arraycopy(columns[col], 0, doubleTemp, 0, row);
2487
- System.arraycopy(columns[col], row+1, doubleTemp, row, (rowCount - row) - 1);
2488
- columns[col] = doubleTemp;
2489
- break;
2490
- }
2491
- case STRING: {
2492
- String[] stringTemp = new String[rowCount-1];
2493
- System.arraycopy(columns[col], 0, stringTemp, 0, row);
2494
- System.arraycopy(columns[col], row+1, stringTemp, row, (rowCount - row) - 1);
2495
- columns[col] = stringTemp;
2496
- }
2497
- }
2498
- }
2499
- rowCount--;
2500
- }
2501
-
2502
-
2503
- /*
2504
- public void setRow(int row, String[] pieces) {
2505
- checkSize(row, pieces.length - 1);
2506
- // pieces.length may be less than columns.length, so loop over pieces
2507
- for (int col = 0; col < pieces.length; col++) {
2508
- setRowCol(row, col, pieces[col]);
2509
- }
2510
- }
2511
-
2512
-
2513
- protected void setRowCol(int row, int col, String piece) {
2514
- switch (columnTypes[col]) {
2515
- case STRING:
2516
- String[] stringData = (String[]) columns[col];
2517
- stringData[row] = piece;
2518
- break;
2519
- case INT:
2520
- int[] intData = (int[]) columns[col];
2521
- intData[row] = PApplet.parseInt(piece, missingInt);
2522
- break;
2523
- case LONG:
2524
- long[] longData = (long[]) columns[col];
2525
- try {
2526
- longData[row] = Long.parseLong(piece);
2527
- } catch (NumberFormatException nfe) {
2528
- longData[row] = missingLong;
2529
- }
2530
- break;
2531
- case FLOAT:
2532
- float[] floatData = (float[]) columns[col];
2533
- floatData[row] = PApplet.parseFloat(piece, missingFloat);
2534
- break;
2535
- case DOUBLE:
2536
- double[] doubleData = (double[]) columns[col];
2537
- try {
2538
- doubleData[row] = Double.parseDouble(piece);
2539
- } catch (NumberFormatException nfe) {
2540
- doubleData[row] = missingDouble;
2541
- }
2542
- break;
2543
- case CATEGORY:
2544
- int[] indexData = (int[]) columns[col];
2545
- indexData[row] = columnCategories[col].index(piece);
2546
- break;
2547
- default:
2548
- throw new IllegalArgumentException("That's not a valid column type.");
2549
- }
2550
- }
2551
- */
2552
-
2553
-
2554
- public void setRow(int row, Object[] pieces) {
2555
- ensureBounds(row, pieces.length - 1);
2556
- // pieces.length may be less than columns.length, so loop over pieces
2557
- for (int col = 0; col < pieces.length; col++) {
2558
- setRowCol(row, col, pieces[col]);
2559
- }
2560
- }
2561
-
2562
-
2563
- protected void setRowCol(int row, int col, Object piece) {
2564
- switch (columnTypes[col]) {
2565
- case STRING:
2566
- String[] stringData = (String[]) columns[col];
2567
- if (piece == null) {
2568
- stringData[row] = null;
2569
- // } else if (piece instanceof String) {
2570
- // stringData[row] = (String) piece;
2571
- } else {
2572
- // Calls toString() on the object, which is 'return this' for String
2573
- stringData[row] = String.valueOf(piece);
2574
- }
2575
- break;
2576
- case INT:
2577
- int[] intData = (int[]) columns[col];
2578
- //intData[row] = PApplet.parseInt(piece, missingInt);
2579
- if (piece == null) {
2580
- intData[row] = missingInt;
2581
- } else if (piece instanceof Integer) {
2582
- intData[row] = (Integer) piece;
2583
- } else {
2584
- intData[row] = PApplet.parseInt(String.valueOf(piece), missingInt);
2585
- }
2586
- break;
2587
- case LONG:
2588
- long[] longData = (long[]) columns[col];
2589
- if (piece == null) {
2590
- longData[row] = missingLong;
2591
- } else if (piece instanceof Long) {
2592
- longData[row] = (Long) piece;
2593
- } else {
2594
- try {
2595
- longData[row] = Long.parseLong(String.valueOf(piece));
2596
- } catch (NumberFormatException nfe) {
2597
- longData[row] = missingLong;
2598
- }
2599
- }
2600
- break;
2601
- case FLOAT:
2602
- float[] floatData = (float[]) columns[col];
2603
- if (piece == null) {
2604
- floatData[row] = missingFloat;
2605
- } else if (piece instanceof Float) {
2606
- floatData[row] = (Float) piece;
2607
- } else {
2608
- floatData[row] = PApplet.parseFloat(String.valueOf(piece), missingFloat);
2609
- }
2610
- break;
2611
- case DOUBLE:
2612
- double[] doubleData = (double[]) columns[col];
2613
- if (piece == null) {
2614
- doubleData[row] = missingDouble;
2615
- } else if (piece instanceof Double) {
2616
- doubleData[row] = (Double) piece;
2617
- } else {
2618
- try {
2619
- doubleData[row] = Double.parseDouble(String.valueOf(piece));
2620
- } catch (NumberFormatException nfe) {
2621
- doubleData[row] = missingDouble;
2622
- }
2623
- }
2624
- break;
2625
- case CATEGORY:
2626
- int[] indexData = (int[]) columns[col];
2627
- if (piece == null) {
2628
- indexData[row] = missingCategory;
2629
- } else {
2630
- String peace = String.valueOf(piece);
2631
- if (peace.equals(missingString)) { // missingString might be null
2632
- indexData[row] = missingCategory;
2633
- } else {
2634
- indexData[row] = columnCategories[col].index(peace);
2635
- }
2636
- }
2637
- break;
2638
- default:
2639
- throw new IllegalArgumentException("That's not a valid column type.");
2640
- }
2641
- }
2642
-
2643
-
2644
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2645
-
2646
- /**
2647
- * @webref table:method
2648
- * @brief Gets a row from a table
2649
- * @param row ID number of the row to get
2650
- * @see Table#rows()
2651
- * @see Table#findRow(String, int)
2652
- * @see Table#findRows(String, int)
2653
- * @see Table#matchRow(String, int)
2654
- * @see Table#matchRows(String, int)
2655
- */
2656
- public TableRow getRow(int row) {
2657
- return new RowPointer(this, row);
2658
- }
2659
-
2660
-
2661
- /**
2662
- * Note that this one iterator instance is shared by any calls to iterate
2663
- * the rows of this table. This is very efficient, but not thread-safe.
2664
- * If you want to iterate in a multi-threaded manner, don't use the iterator.
2665
- *
2666
- * @webref table:method
2667
- * @brief Gets multiple rows from a table
2668
- * @see Table#getRow(int)
2669
- * @see Table#findRow(String, int)
2670
- * @see Table#findRows(String, int)
2671
- * @see Table#matchRow(String, int)
2672
- * @see Table#matchRows(String, int)
2673
- */
2674
- public Iterable<TableRow> rows() {
2675
- return new Iterable<TableRow>() {
2676
- public Iterator<TableRow> iterator() {
2677
- if (rowIterator == null) {
2678
- rowIterator = new RowIterator(Table.this);
2679
- } else {
2680
- rowIterator.reset();
2681
- }
2682
- return rowIterator;
2683
- }
2684
- };
2685
- }
2686
-
2687
- /**
2688
- * @nowebref
2689
- */
2690
- public Iterable<TableRow> rows(final int[] indices) {
2691
- return new Iterable<TableRow>() {
2692
- public Iterator<TableRow> iterator() {
2693
- return new RowIndexIterator(Table.this, indices);
2694
- }
2695
- };
2696
- }
2697
-
2698
-
2699
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2700
-
2701
-
2702
- static class RowPointer implements TableRow {
2703
- Table table;
2704
- int row;
2705
-
2706
- public RowPointer(Table table, int row) {
2707
- this.table = table;
2708
- this.row = row;
2709
- }
2710
-
2711
- public void setRow(int row) {
2712
- this.row = row;
2713
- }
2714
-
2715
- public String getString(int column) {
2716
- return table.getString(row, column);
2717
- }
2718
-
2719
- public String getString(String columnName) {
2720
- return table.getString(row, columnName);
2721
- }
2722
-
2723
- public int getInt(int column) {
2724
- return table.getInt(row, column);
2725
- }
2726
-
2727
- public int getInt(String columnName) {
2728
- return table.getInt(row, columnName);
2729
- }
2730
-
2731
- public long getLong(int column) {
2732
- return table.getLong(row, column);
2733
- }
2734
-
2735
- public long getLong(String columnName) {
2736
- return table.getLong(row, columnName);
2737
- }
2738
-
2739
- public float getFloat(int column) {
2740
- return table.getFloat(row, column);
2741
- }
2742
-
2743
- public float getFloat(String columnName) {
2744
- return table.getFloat(row, columnName);
2745
- }
2746
-
2747
- public double getDouble(int column) {
2748
- return table.getDouble(row, column);
2749
- }
2750
-
2751
- public double getDouble(String columnName) {
2752
- return table.getDouble(row, columnName);
2753
- }
2754
-
2755
- public void setString(int column, String value) {
2756
- table.setString(row, column, value);
2757
- }
2758
-
2759
- public void setString(String columnName, String value) {
2760
- table.setString(row, columnName, value);
2761
- }
2762
-
2763
- public void setInt(int column, int value) {
2764
- table.setInt(row, column, value);
2765
- }
2766
-
2767
- public void setInt(String columnName, int value) {
2768
- table.setInt(row, columnName, value);
2769
- }
2770
-
2771
- public void setLong(int column, long value) {
2772
- table.setLong(row, column, value);
2773
- }
2774
-
2775
- public void setLong(String columnName, long value) {
2776
- table.setLong(row, columnName, value);
2777
- }
2778
-
2779
- public void setFloat(int column, float value) {
2780
- table.setFloat(row, column, value);
2781
- }
2782
-
2783
- public void setFloat(String columnName, float value) {
2784
- table.setFloat(row, columnName, value);
2785
- }
2786
-
2787
- public void setDouble(int column, double value) {
2788
- table.setDouble(row, column, value);
2789
- }
2790
-
2791
- public void setDouble(String columnName, double value) {
2792
- table.setDouble(row, columnName, value);
2793
- }
2794
-
2795
- public int getColumnCount() {
2796
- return table.getColumnCount();
2797
- }
2798
-
2799
- public int getColumnType(String columnName) {
2800
- return table.getColumnType(columnName);
2801
- }
2802
-
2803
- public int getColumnType(int column) {
2804
- return table.getColumnType(column);
2805
- }
2806
-
2807
- public int[] getColumnTypes() {
2808
- return table.getColumnTypes();
2809
- }
2810
-
2811
- public String getColumnTitle(int column) {
2812
- return table.getColumnTitle(column);
2813
- }
2814
-
2815
- public String[] getColumnTitles() {
2816
- return table.getColumnTitles();
2817
- }
2818
-
2819
- public void print() {
2820
- write(new PrintWriter(System.out));
2821
- }
2822
-
2823
- public void write(PrintWriter writer) {
2824
- for (int i = 0 ; i < getColumnCount(); i++) {
2825
- if (i != 0) {
2826
- writer.print('\t');
2827
- }
2828
- writer.print(getString(i));
2829
- }
2830
- }
2831
- }
2832
-
2833
-
2834
- static class RowIterator implements Iterator<TableRow> {
2835
- Table table;
2836
- RowPointer rp;
2837
- int row;
2838
-
2839
- public RowIterator(Table table) {
2840
- this.table = table;
2841
- row = -1;
2842
- rp = new RowPointer(table, row);
2843
- }
2844
-
2845
- public void remove() {
2846
- table.removeRow(row);
2847
- }
2848
-
2849
- public TableRow next() {
2850
- rp.setRow(++row);
2851
- return rp;
2852
- }
2853
-
2854
- public boolean hasNext() {
2855
- return row+1 < table.getRowCount();
2856
- }
2857
-
2858
- public void reset() {
2859
- row = -1;
2860
- }
2861
- }
2862
-
2863
-
2864
- static class RowIndexIterator implements Iterator<TableRow> {
2865
- Table table;
2866
- RowPointer rp;
2867
- int[] indices;
2868
- int index;
2869
-
2870
- public RowIndexIterator(Table table, int[] indices) {
2871
- this.table = table;
2872
- this.indices = indices;
2873
- index = -1;
2874
- // just set to something arbitrary
2875
- rp = new RowPointer(table, -1);
2876
- }
2877
-
2878
- public void remove() {
2879
- table.removeRow(indices[index]);
2880
- }
2881
-
2882
- public TableRow next() {
2883
- rp.setRow(indices[++index]);
2884
- return rp;
2885
- }
2886
-
2887
- public boolean hasNext() {
2888
- //return row+1 < table.getRowCount();
2889
- return index + 1 < indices.length;
2890
- }
2891
-
2892
- public void reset() {
2893
- index = -1;
2894
- }
2895
- }
2896
-
2897
-
2898
- /*
2899
- static public Iterator<TableRow> createIterator(final ResultSet rs) {
2900
- return new Iterator<TableRow>() {
2901
- boolean already;
2902
-
2903
- public boolean hasNext() {
2904
- already = true;
2905
- try {
2906
- return rs.next();
2907
- } catch (SQLException e) {
2908
- throw new RuntimeException(e);
2909
- }
2910
- }
2911
-
2912
-
2913
- public TableRow next() {
2914
- if (!already) {
2915
- try {
2916
- rs.next();
2917
- } catch (SQLException e) {
2918
- throw new RuntimeException(e);
2919
- }
2920
- } else {
2921
- already = false;
2922
- }
2923
-
2924
- return new TableRow() {
2925
- public double getDouble(int column) {
2926
- try {
2927
- return rs.getDouble(column);
2928
- } catch (SQLException e) {
2929
- throw new RuntimeException(e);
2930
- }
2931
- }
2932
-
2933
- public double getDouble(String columnName) {
2934
- try {
2935
- return rs.getDouble(columnName);
2936
- } catch (SQLException e) {
2937
- throw new RuntimeException(e);
2938
- }
2939
- }
2940
-
2941
- public float getFloat(int column) {
2942
- try {
2943
- return rs.getFloat(column);
2944
- } catch (SQLException e) {
2945
- throw new RuntimeException(e);
2946
- }
2947
- }
2948
-
2949
- public float getFloat(String columnName) {
2950
- try {
2951
- return rs.getFloat(columnName);
2952
- } catch (SQLException e) {
2953
- throw new RuntimeException(e);
2954
- }
2955
- }
2956
-
2957
- public int getInt(int column) {
2958
- try {
2959
- return rs.getInt(column);
2960
- } catch (SQLException e) {
2961
- throw new RuntimeException(e);
2962
- }
2963
- }
2964
-
2965
- public int getInt(String columnName) {
2966
- try {
2967
- return rs.getInt(columnName);
2968
- } catch (SQLException e) {
2969
- throw new RuntimeException(e);
2970
- }
2971
- }
2972
-
2973
- public long getLong(int column) {
2974
- try {
2975
- return rs.getLong(column);
2976
- } catch (SQLException e) {
2977
- throw new RuntimeException(e);
2978
- }
2979
- }
2980
-
2981
- public long getLong(String columnName) {
2982
- try {
2983
- return rs.getLong(columnName);
2984
- } catch (SQLException e) {
2985
- throw new RuntimeException(e);
2986
- }
2987
- }
2988
-
2989
- public String getString(int column) {
2990
- try {
2991
- return rs.getString(column);
2992
- } catch (SQLException e) {
2993
- throw new RuntimeException(e);
2994
- }
2995
- }
2996
-
2997
- public String getString(String columnName) {
2998
- try {
2999
- return rs.getString(columnName);
3000
- } catch (SQLException e) {
3001
- throw new RuntimeException(e);
3002
- }
3003
- }
3004
-
3005
- public void setString(int column, String value) { immutable(); }
3006
- public void setString(String columnName, String value) { immutable(); }
3007
- public void setInt(int column, int value) { immutable(); }
3008
- public void setInt(String columnName, int value) { immutable(); }
3009
- public void setLong(int column, long value) { immutable(); }
3010
- public void setLong(String columnName, long value) { immutable(); }
3011
- public void setFloat(int column, float value) { immutable(); }
3012
- public void setFloat(String columnName, float value) { immutable(); }
3013
- public void setDouble(int column, double value) { immutable(); }
3014
- public void setDouble(String columnName, double value) { immutable(); }
3015
-
3016
- private void immutable() {
3017
- throw new IllegalArgumentException("This TableRow cannot be modified.");
3018
- }
3019
-
3020
- public int getColumnCount() {
3021
- try {
3022
- return rs.getMetaData().getColumnCount();
3023
- } catch (SQLException e) {
3024
- e.printStackTrace();
3025
- return -1;
3026
- }
3027
- }
3028
-
3029
-
3030
- public int getColumnType(String columnName) {
3031
- // unimplemented
3032
- }
3033
-
3034
-
3035
- public int getColumnType(int column) {
3036
- // unimplemented
3037
- }
3038
-
3039
- };
3040
- }
3041
-
3042
- public void remove() {
3043
- throw new IllegalArgumentException("remove() not supported");
3044
- }
3045
- };
3046
- }
3047
- */
3048
-
3049
-
3050
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3051
-
3052
-
3053
- /**
3054
- * @webref table:method
3055
- * @brief Get an integer value from the specified row and column
3056
- * @param row ID number of the row to reference
3057
- * @param column ID number of the column to reference
3058
- * @see Table#getFloat(int, int)
3059
- * @see Table#getString(int, int)
3060
- * @see Table#getStringColumn(String)
3061
- * @see Table#setInt(int, int, int)
3062
- * @see Table#setFloat(int, int, float)
3063
- * @see Table#setString(int, int, String)
3064
- */
3065
- public int getInt(int row, int column) {
3066
- checkBounds(row, column);
3067
- if (columnTypes[column] == INT ||
3068
- columnTypes[column] == CATEGORY) {
3069
- int[] intData = (int[]) columns[column];
3070
- return intData[row];
3071
- }
3072
- String str = getString(row, column);
3073
- return (str == null || str.equals(missingString)) ?
3074
- missingInt : PApplet.parseInt(str, missingInt);
3075
- }
3076
-
3077
- /**
3078
- * @param columnName title of the column to reference
3079
- */
3080
- public int getInt(int row, String columnName) {
3081
- return getInt(row, getColumnIndex(columnName));
3082
- }
3083
-
3084
-
3085
- public void setMissingInt(int value) {
3086
- missingInt = value;
3087
- }
3088
-
3089
-
3090
- /**
3091
- * @webref table:method
3092
- * @brief Store an integer value in the specified row and column
3093
- * @param row ID number of the target row
3094
- * @param column ID number of the target column
3095
- * @param value value to assign
3096
- * @see Table#setFloat(int, int, float)
3097
- * @see Table#setString(int, int, String)
3098
- * @see Table#getInt(int, int)
3099
- * @see Table#getFloat(int, int)
3100
- * @see Table#getString(int, int)
3101
- * @see Table#getStringColumn(String)
3102
- */
3103
- public void setInt(int row, int column, int value) {
3104
- if (columnTypes[column] == STRING) {
3105
- setString(row, column, String.valueOf(value));
3106
-
3107
- } else {
3108
- ensureBounds(row, column);
3109
- if (columnTypes[column] != INT &&
3110
- columnTypes[column] != CATEGORY) {
3111
- throw new IllegalArgumentException("Column " + column + " is not an int column.");
3112
- }
3113
- int[] intData = (int[]) columns[column];
3114
- intData[row] = value;
3115
- }
3116
- }
3117
-
3118
- /**
3119
- * @param columnName title of the target column
3120
- */
3121
- public void setInt(int row, String columnName, int value) {
3122
- setInt(row, getColumnIndex(columnName), value);
3123
- }
3124
-
3125
-
3126
-
3127
- public int[] getIntColumn(String name) {
3128
- int col = getColumnIndex(name);
3129
- return (col == -1) ? null : getIntColumn(col);
3130
- }
3131
-
3132
-
3133
- public int[] getIntColumn(int col) {
3134
- int[] outgoing = new int[rowCount];
3135
- for (int row = 0; row < rowCount; row++) {
3136
- outgoing[row] = getInt(row, col);
3137
- }
3138
- return outgoing;
3139
- }
3140
-
3141
-
3142
- public int[] getIntRow(int row) {
3143
- int[] outgoing = new int[columns.length];
3144
- for (int col = 0; col < columns.length; col++) {
3145
- outgoing[col] = getInt(row, col);
3146
- }
3147
- return outgoing;
3148
- }
3149
-
3150
-
3151
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3152
-
3153
-
3154
- public long getLong(int row, int column) {
3155
- checkBounds(row, column);
3156
- if (columnTypes[column] == LONG) {
3157
- long[] longData = (long[]) columns[column];
3158
- return longData[row];
3159
- }
3160
- String str = getString(row, column);
3161
- if (str == null || str.equals(missingString)) {
3162
- return missingLong;
3163
- }
3164
- try {
3165
- return Long.parseLong(str);
3166
- } catch (NumberFormatException nfe) {
3167
- return missingLong;
3168
- }
3169
- }
3170
-
3171
-
3172
- public long getLong(int row, String columnName) {
3173
- return getLong(row, getColumnIndex(columnName));
3174
- }
3175
-
3176
-
3177
- public void setMissingLong(long value) {
3178
- missingLong = value;
3179
- }
3180
-
3181
-
3182
- public void setLong(int row, int column, long value) {
3183
- if (columnTypes[column] == STRING) {
3184
- setString(row, column, String.valueOf(value));
3185
-
3186
- } else {
3187
- ensureBounds(row, column);
3188
- if (columnTypes[column] != LONG) {
3189
- throw new IllegalArgumentException("Column " + column + " is not a 'long' column.");
3190
- }
3191
- long[] longData = (long[]) columns[column];
3192
- longData[row] = value;
3193
- }
3194
- }
3195
-
3196
-
3197
- public void setLong(int row, String columnName, long value) {
3198
- setLong(row, getColumnIndex(columnName), value);
3199
- }
3200
-
3201
-
3202
- public long[] getLongColumn(String name) {
3203
- int col = getColumnIndex(name);
3204
- return (col == -1) ? null : getLongColumn(col);
3205
- }
3206
-
3207
-
3208
- public long[] getLongColumn(int col) {
3209
- long[] outgoing = new long[rowCount];
3210
- for (int row = 0; row < rowCount; row++) {
3211
- outgoing[row] = getLong(row, col);
3212
- }
3213
- return outgoing;
3214
- }
3215
-
3216
-
3217
- public long[] getLongRow(int row) {
3218
- long[] outgoing = new long[columns.length];
3219
- for (int col = 0; col < columns.length; col++) {
3220
- outgoing[col] = getLong(row, col);
3221
- }
3222
- return outgoing;
3223
- }
3224
-
3225
-
3226
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3227
-
3228
-
3229
- /**
3230
- * Get a float value from the specified row and column. If the value is null
3231
- * or not parseable as a float, the "missing" value is returned. By default,
3232
- * this is Float.NaN, but can be controlled with setMissingFloat().
3233
- *
3234
- * @webref table:method
3235
- * @brief Get a float value from the specified row and column
3236
- * @param row ID number of the row to reference
3237
- * @param column ID number of the column to reference
3238
- * @see Table#getInt(int, int)
3239
- * @see Table#getString(int, int)
3240
- * @see Table#getStringColumn(String)
3241
- * @see Table#setInt(int, int, int)
3242
- * @see Table#setFloat(int, int, float)
3243
- * @see Table#setString(int, int, String)
3244
- */
3245
- public float getFloat(int row, int column) {
3246
- checkBounds(row, column);
3247
- if (columnTypes[column] == FLOAT) {
3248
- float[] floatData = (float[]) columns[column];
3249
- return floatData[row];
3250
- }
3251
- String str = getString(row, column);
3252
- if (str == null || str.equals(missingString)) {
3253
- return missingFloat;
3254
- }
3255
- return PApplet.parseFloat(str, missingFloat);
3256
- }
3257
-
3258
- /**
3259
- * @param columnName title of the column to reference
3260
- */
3261
- public float getFloat(int row, String columnName) {
3262
- return getFloat(row, getColumnIndex(columnName));
3263
- }
3264
-
3265
-
3266
- public void setMissingFloat(float value) {
3267
- missingFloat = value;
3268
- }
3269
-
3270
-
3271
- /**
3272
- * @webref table:method
3273
- * @brief Store a float value in the specified row and column
3274
- * @param row ID number of the target row
3275
- * @param column ID number of the target column
3276
- * @param value value to assign
3277
- * @see Table#setInt(int, int, int)
3278
- * @see Table#setString(int, int, String)
3279
- * @see Table#getInt(int, int)
3280
- * @see Table#getFloat(int, int)
3281
- * @see Table#getString(int, int)
3282
- * @see Table#getStringColumn(String)
3283
- */
3284
- public void setFloat(int row, int column, float value) {
3285
- if (columnTypes[column] == STRING) {
3286
- setString(row, column, String.valueOf(value));
3287
-
3288
- } else {
3289
- ensureBounds(row, column);
3290
- if (columnTypes[column] != FLOAT) {
3291
- throw new IllegalArgumentException("Column " + column + " is not a float column.");
3292
- }
3293
- float[] longData = (float[]) columns[column];
3294
- longData[row] = value;
3295
- }
3296
- }
3297
-
3298
- /**
3299
- * @param columnName title of the target column
3300
- */
3301
- public void setFloat(int row, String columnName, float value) {
3302
- setFloat(row, getColumnIndex(columnName), value);
3303
- }
3304
-
3305
-
3306
- public float[] getFloatColumn(String name) {
3307
- int col = getColumnIndex(name);
3308
- return (col == -1) ? null : getFloatColumn(col);
3309
- }
3310
-
3311
-
3312
- public float[] getFloatColumn(int col) {
3313
- float[] outgoing = new float[rowCount];
3314
- for (int row = 0; row < rowCount; row++) {
3315
- outgoing[row] = getFloat(row, col);
3316
- }
3317
- return outgoing;
3318
- }
3319
-
3320
-
3321
- public float[] getFloatRow(int row) {
3322
- float[] outgoing = new float[columns.length];
3323
- for (int col = 0; col < columns.length; col++) {
3324
- outgoing[col] = getFloat(row, col);
3325
- }
3326
- return outgoing;
3327
- }
3328
-
3329
-
3330
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3331
-
3332
-
3333
- public double getDouble(int row, int column) {
3334
- checkBounds(row, column);
3335
- if (columnTypes[column] == DOUBLE) {
3336
- double[] doubleData = (double[]) columns[column];
3337
- return doubleData[row];
3338
- }
3339
- String str = getString(row, column);
3340
- if (str == null || str.equals(missingString)) {
3341
- return missingDouble;
3342
- }
3343
- try {
3344
- return Double.parseDouble(str);
3345
- } catch (NumberFormatException nfe) {
3346
- return missingDouble;
3347
- }
3348
- }
3349
-
3350
-
3351
- public double getDouble(int row, String columnName) {
3352
- return getDouble(row, getColumnIndex(columnName));
3353
- }
3354
-
3355
-
3356
- public void setMissingDouble(double value) {
3357
- missingDouble = value;
3358
- }
3359
-
3360
-
3361
- public void setDouble(int row, int column, double value) {
3362
- if (columnTypes[column] == STRING) {
3363
- setString(row, column, String.valueOf(value));
3364
-
3365
- } else {
3366
- ensureBounds(row, column);
3367
- if (columnTypes[column] != DOUBLE) {
3368
- throw new IllegalArgumentException("Column " + column + " is not a 'double' column.");
3369
- }
3370
- double[] doubleData = (double[]) columns[column];
3371
- doubleData[row] = value;
3372
- }
3373
- }
3374
-
3375
-
3376
- public void setDouble(int row, String columnName, double value) {
3377
- setDouble(row, getColumnIndex(columnName), value);
3378
- }
3379
-
3380
-
3381
- public double[] getDoubleColumn(String name) {
3382
- int col = getColumnIndex(name);
3383
- return (col == -1) ? null : getDoubleColumn(col);
3384
- }
3385
-
3386
-
3387
- public double[] getDoubleColumn(int col) {
3388
- double[] outgoing = new double[rowCount];
3389
- for (int row = 0; row < rowCount; row++) {
3390
- outgoing[row] = getDouble(row, col);
3391
- }
3392
- return outgoing;
3393
- }
3394
-
3395
-
3396
- public double[] getDoubleRow(int row) {
3397
- double[] outgoing = new double[columns.length];
3398
- for (int col = 0; col < columns.length; col++) {
3399
- outgoing[col] = getDouble(row, col);
3400
- }
3401
- return outgoing;
3402
- }
3403
-
3404
-
3405
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3406
-
3407
-
3408
- //public long getTimestamp(String rowName, int column) {
3409
- //return getTimestamp(getRowIndex(rowName), column);
3410
- //}
3411
-
3412
-
3413
- /**
3414
- * Returns the time in milliseconds by parsing a SQL Timestamp at this cell.
3415
- */
3416
- // public long getTimestamp(int row, int column) {
3417
- // String str = get(row, column);
3418
- // java.sql.Timestamp timestamp = java.sql.Timestamp.valueOf(str);
3419
- // return timestamp.getTime();
3420
- // }
3421
-
3422
-
3423
- // public long getExcelTimestamp(int row, int column) {
3424
- // return parseExcelTimestamp(get(row, column));
3425
- // }
3426
-
3427
-
3428
- // static protected DateFormat excelDateFormat;
3429
-
3430
- // static public long parseExcelTimestamp(String timestamp) {
3431
- // if (excelDateFormat == null) {
3432
- // excelDateFormat = new SimpleDateFormat("MM/dd/yy HH:mm");
3433
- // }
3434
- // try {
3435
- // return excelDateFormat.parse(timestamp).getTime();
3436
- // } catch (ParseException e) {
3437
- // e.printStackTrace();
3438
- // return -1;
3439
- // }
3440
- // }
3441
-
3442
-
3443
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3444
-
3445
-
3446
- // public void setObject(int row, int column, Object value) {
3447
- // if (value == null) {
3448
- // data[row][column] = null;
3449
- // } else if (value instanceof String) {
3450
- // set(row, column, (String) value);
3451
- // } else if (value instanceof Float) {
3452
- // setFloat(row, column, ((Float) value).floatValue());
3453
- // } else if (value instanceof Integer) {
3454
- // setInt(row, column, ((Integer) value).intValue());
3455
- // } else {
3456
- // set(row, column, value.toString());
3457
- // }
3458
- // }
3459
-
3460
-
3461
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3462
-
3463
-
3464
- /**
3465
- * Get a String value from the table. If the row is longer than the table
3466
- *
3467
- * @webref table:method
3468
- * @brief Get an String value from the specified row and column
3469
- * @param row ID number of the row to reference
3470
- * @param column ID number of the column to reference
3471
- * @see Table#getInt(int, int)
3472
- * @see Table#getFloat(int, int)
3473
- * @see Table#getStringColumn(String)
3474
- * @see Table#setInt(int, int, int)
3475
- * @see Table#setFloat(int, int, float)
3476
- * @see Table#setString(int, int, String)
3477
- */
3478
- public String getString(int row, int column) {
3479
- checkBounds(row, column);
3480
- if (columnTypes[column] == STRING) {
3481
- String[] stringData = (String[]) columns[column];
3482
- return stringData[row];
3483
- } else if (columnTypes[column] == CATEGORY) {
3484
- int cat = getInt(row, column);
3485
- if (cat == missingCategory) {
3486
- return missingString;
3487
- }
3488
- return columnCategories[column].key(cat);
3489
- } else if (columnTypes[column] == FLOAT) {
3490
- if (Float.isNaN(getFloat(row, column))) {
3491
- return null;
3492
- }
3493
- } else if (columnTypes[column] == DOUBLE) {
3494
- if (Double.isNaN(getFloat(row, column))) {
3495
- return null;
3496
- }
3497
- }
3498
- return String.valueOf(Array.get(columns[column], row));
3499
- }
3500
-
3501
-
3502
- /**
3503
- * @param columnName title of the column to reference
3504
- */
3505
- public String getString(int row, String columnName) {
3506
- return getString(row, getColumnIndex(columnName));
3507
- }
3508
-
3509
-
3510
- /**
3511
- * Treat entries with this string as "missing". Also used for categorial.
3512
- */
3513
- public void setMissingString(String value) {
3514
- missingString = value;
3515
- }
3516
-
3517
-
3518
- /**
3519
- * @webref table:method
3520
- * @brief Store a String value in the specified row and column
3521
- * @param row ID number of the target row
3522
- * @param column ID number of the target column
3523
- * @param value value to assign
3524
- * @see Table#setInt(int, int, int)
3525
- * @see Table#setFloat(int, int, float)
3526
- * @see Table#getInt(int, int)
3527
- * @see Table#getFloat(int, int)
3528
- * @see Table#getString(int, int)
3529
- * @see Table#getStringColumn(String)
3530
- */
3531
- public void setString(int row, int column, String value) {
3532
- ensureBounds(row, column);
3533
- if (columnTypes[column] != STRING) {
3534
- throw new IllegalArgumentException("Column " + column + " is not a String column.");
3535
- }
3536
- String[] stringData = (String[]) columns[column];
3537
- stringData[row] = value;
3538
- }
3539
-
3540
- /**
3541
- * @param columnName title of the target column
3542
- */
3543
- public void setString(int row, String columnName, String value) {
3544
- int column = checkColumnIndex(columnName);
3545
- setString(row, column, value);
3546
- }
3547
-
3548
- /**
3549
- * @webref table:method
3550
- * @brief Gets all values in the specified column
3551
- * @param columnName title of the column to search
3552
- * @see Table#getInt(int, int)
3553
- * @see Table#getFloat(int, int)
3554
- * @see Table#getString(int, int)
3555
- * @see Table#setInt(int, int, int)
3556
- * @see Table#setFloat(int, int, float)
3557
- * @see Table#setString(int, int, String)
3558
- */
3559
- public String[] getStringColumn(String columnName) {
3560
- int col = getColumnIndex(columnName);
3561
- return (col == -1) ? null : getStringColumn(col);
3562
- }
3563
-
3564
-
3565
- /**
3566
- * @param column ID number of the column to search
3567
- */
3568
- public String[] getStringColumn(int column) {
3569
- String[] outgoing = new String[rowCount];
3570
- for (int i = 0; i < rowCount; i++) {
3571
- outgoing[i] = getString(i, column);
3572
- }
3573
- return outgoing;
3574
- }
3575
-
3576
-
3577
- public String[] getStringRow(int row) {
3578
- String[] outgoing = new String[columns.length];
3579
- for (int col = 0; col < columns.length; col++) {
3580
- outgoing[col] = getString(row, col);
3581
- }
3582
- return outgoing;
3583
- }
3584
-
3585
-
3586
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3587
-
3588
-
3589
- /**
3590
- * Return the row that contains the first String that matches.
3591
- * @param value the String to match
3592
- * @param column ID number of the column to search
3593
- */
3594
- public int findRowIndex(String value, int column) {
3595
- checkColumn(column);
3596
- if (columnTypes[column] == STRING) {
3597
- String[] stringData = (String[]) columns[column];
3598
- if (value == null) {
3599
- for (int row = 0; row < rowCount; row++) {
3600
- if (stringData[row] == null) return row;
3601
- }
3602
- } else {
3603
- for (int row = 0; row < rowCount; row++) {
3604
- if (stringData[row] != null && stringData[row].equals(value)) {
3605
- return row;
3606
- }
3607
- }
3608
- }
3609
- } else { // less efficient, includes conversion as necessary
3610
- for (int row = 0; row < rowCount; row++) {
3611
- String str = getString(row, column);
3612
- if (str == null) {
3613
- if (value == null) {
3614
- return row;
3615
- }
3616
- } else if (str.equals(value)) {
3617
- return row;
3618
- }
3619
- }
3620
- }
3621
- return -1;
3622
- }
3623
-
3624
-
3625
- /**
3626
- * Return the row that contains the first String that matches.
3627
- * @param value the String to match
3628
- * @param columnName title of the column to search
3629
- */
3630
- public int findRowIndex(String value, String columnName) {
3631
- return findRowIndex(value, getColumnIndex(columnName));
3632
- }
3633
-
3634
-
3635
- /**
3636
- * Return a list of rows that contain the String passed in. If there are no
3637
- * matches, a zero length array will be returned (not a null array).
3638
- * @param value the String to match
3639
- * @param column ID number of the column to search
3640
- */
3641
- public int[] findRowIndices(String value, int column) {
3642
- int[] outgoing = new int[rowCount];
3643
- int count = 0;
3644
-
3645
- checkColumn(column);
3646
- if (columnTypes[column] == STRING) {
3647
- String[] stringData = (String[]) columns[column];
3648
- if (value == null) {
3649
- for (int row = 0; row < rowCount; row++) {
3650
- if (stringData[row] == null) {
3651
- outgoing[count++] = row;
3652
- }
3653
- }
3654
- } else {
3655
- for (int row = 0; row < rowCount; row++) {
3656
- if (stringData[row] != null && stringData[row].equals(value)) {
3657
- outgoing[count++] = row;
3658
- }
3659
- }
3660
- }
3661
- } else { // less efficient, includes conversion as necessary
3662
- for (int row = 0; row < rowCount; row++) {
3663
- String str = getString(row, column);
3664
- if (str == null) {
3665
- if (value == null) {
3666
- outgoing[count++] = row;
3667
- }
3668
- } else if (str.equals(value)) {
3669
- outgoing[count++] = row;
3670
- }
3671
- }
3672
- }
3673
- return PApplet.subset(outgoing, 0, count);
3674
- }
3675
-
3676
-
3677
- /**
3678
- * Return a list of rows that contain the String passed in. If there are no
3679
- * matches, a zero length array will be returned (not a null array).
3680
- * @param value the String to match
3681
- * @param columnName title of the column to search
3682
- */
3683
- public int[] findRowIndices(String value, String columnName) {
3684
- return findRowIndices(value, getColumnIndex(columnName));
3685
- }
3686
-
3687
-
3688
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3689
-
3690
- /**
3691
- * @webref table:method
3692
- * @brief Finds a row that contains the given value
3693
- * @param value the value to match
3694
- * @param column ID number of the column to search
3695
- * @see Table#getRow(int)
3696
- * @see Table#rows()
3697
- * @see Table#findRows(String, int)
3698
- * @see Table#matchRow(String, int)
3699
- * @see Table#matchRows(String, int)
3700
- */
3701
- public TableRow findRow(String value, int column) {
3702
- int row = findRowIndex(value, column);
3703
- return (row == -1) ? null : new RowPointer(this, row);
3704
- }
3705
-
3706
-
3707
- /**
3708
- * @param columnName title of the column to search
3709
- */
3710
- public TableRow findRow(String value, String columnName) {
3711
- return findRow(value, getColumnIndex(columnName));
3712
- }
3713
-
3714
-
3715
- /**
3716
- * @webref table:method
3717
- * @brief Finds multiple rows that contain the given value
3718
- * @param value the value to match
3719
- * @param column ID number of the column to search
3720
- * @see Table#getRow(int)
3721
- * @see Table#rows()
3722
- * @see Table#findRow(String, int)
3723
- * @see Table#matchRow(String, int)
3724
- * @see Table#matchRows(String, int)
3725
- */
3726
- public Iterable<TableRow> findRows(final String value, final int column) {
3727
- return new Iterable<TableRow>() {
3728
- public Iterator<TableRow> iterator() {
3729
- return findRowIterator(value, column);
3730
- }
3731
- };
3732
- }
3733
-
3734
-
3735
- /**
3736
- * @param columnName title of the column to search
3737
- */
3738
- public Iterable<TableRow> findRows(final String value, final String columnName) {
3739
- return findRows(value, getColumnIndex(columnName));
3740
- }
3741
-
3742
-
3743
- /**
3744
- * @brief Finds multiple rows that contain the given value
3745
- * @param value the value to match
3746
- * @param column ID number of the column to search
3747
- */
3748
- public Iterator<TableRow> findRowIterator(String value, int column) {
3749
- return new RowIndexIterator(this, findRowIndices(value, column));
3750
- }
3751
-
3752
-
3753
- /**
3754
- * @param columnName title of the column to search
3755
- */
3756
- public Iterator<TableRow> findRowIterator(String value, String columnName) {
3757
- return findRowIterator(value, getColumnIndex(columnName));
3758
- }
3759
-
3760
-
3761
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3762
-
3763
-
3764
- /**
3765
- * Return the row that contains the first String that matches.
3766
- * @param regexp the String to match
3767
- * @param column ID number of the column to search
3768
- */
3769
- public int matchRowIndex(String regexp, int column) {
3770
- checkColumn(column);
3771
- if (columnTypes[column] == STRING) {
3772
- String[] stringData = (String[]) columns[column];
3773
- for (int row = 0; row < rowCount; row++) {
3774
- if (stringData[row] != null &&
3775
- PApplet.match(stringData[row], regexp) != null) {
3776
- return row;
3777
- }
3778
- }
3779
- } else { // less efficient, includes conversion as necessary
3780
- for (int row = 0; row < rowCount; row++) {
3781
- String str = getString(row, column);
3782
- if (str != null &&
3783
- PApplet.match(str, regexp) != null) {
3784
- return row;
3785
- }
3786
- }
3787
- }
3788
- return -1;
3789
- }
3790
-
3791
-
3792
- /**
3793
- * Return the row that contains the first String that matches.
3794
- * @param what the String to match
3795
- * @param columnName title of the column to search
3796
- */
3797
- public int matchRowIndex(String what, String columnName) {
3798
- return matchRowIndex(what, getColumnIndex(columnName));
3799
- }
3800
-
3801
-
3802
- /**
3803
- * Return a list of rows that contain the String passed in. If there are no
3804
- * matches, a zero length array will be returned (not a null array).
3805
- * @param regexp the String to match
3806
- * @param column ID number of the column to search
3807
- */
3808
- public int[] matchRowIndices(String regexp, int column) {
3809
- int[] outgoing = new int[rowCount];
3810
- int count = 0;
3811
-
3812
- checkColumn(column);
3813
- if (columnTypes[column] == STRING) {
3814
- String[] stringData = (String[]) columns[column];
3815
- for (int row = 0; row < rowCount; row++) {
3816
- if (stringData[row] != null &&
3817
- PApplet.match(stringData[row], regexp) != null) {
3818
- outgoing[count++] = row;
3819
- }
3820
- }
3821
- } else { // less efficient, includes conversion as necessary
3822
- for (int row = 0; row < rowCount; row++) {
3823
- String str = getString(row, column);
3824
- if (str != null &&
3825
- PApplet.match(str, regexp) != null) {
3826
- outgoing[count++] = row;
3827
- }
3828
- }
3829
- }
3830
- return PApplet.subset(outgoing, 0, count);
3831
- }
3832
-
3833
-
3834
- /**
3835
- * Return a list of rows that match the regex passed in. If there are no
3836
- * matches, a zero length array will be returned (not a null array).
3837
- * @param what the String to match
3838
- * @param columnName title of the column to search
3839
- */
3840
- public int[] matchRowIndices(String what, String columnName) {
3841
- return matchRowIndices(what, getColumnIndex(columnName));
3842
- }
3843
-
3844
-
3845
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3846
-
3847
- /**
3848
- * @webref table:method
3849
- * @brief Finds a row that matches the given expression
3850
- * @param regexp the regular expression to match
3851
- * @param column ID number of the column to search
3852
- * @see Table#getRow(int)
3853
- * @see Table#rows()
3854
- * @see Table#findRow(String, int)
3855
- * @see Table#findRows(String, int)
3856
- * @see Table#matchRows(String, int)
3857
- */
3858
- public TableRow matchRow(String regexp, int column) {
3859
- int row = matchRowIndex(regexp, column);
3860
- return (row == -1) ? null : new RowPointer(this, row);
3861
- }
3862
-
3863
-
3864
- /**
3865
- * @param columnName title of the column to search
3866
- */
3867
- public TableRow matchRow(String regexp, String columnName) {
3868
- return matchRow(regexp, getColumnIndex(columnName));
3869
- }
3870
-
3871
-
3872
- /**
3873
- * @webref table:method
3874
- * @brief Finds multiple rows that match the given expression
3875
- * @param regexp the regular expression to match
3876
- * @param column ID number of the column to search
3877
- * @see Table#getRow(int)
3878
- * @see Table#rows()
3879
- * @see Table#findRow(String, int)
3880
- * @see Table#findRows(String, int)
3881
- * @see Table#matchRow(String, int)
3882
- */
3883
- public Iterable<TableRow> matchRows(final String regexp, final int column) {
3884
- return new Iterable<TableRow>() {
3885
- public Iterator<TableRow> iterator() {
3886
- return matchRowIterator(regexp, column);
3887
- }
3888
- };
3889
- }
3890
-
3891
-
3892
- /**
3893
- * @param columnName title of the column to search
3894
- */
3895
- public Iterable<TableRow> matchRows(String regexp, String columnName) {
3896
- return matchRows(regexp, getColumnIndex(columnName));
3897
- }
3898
-
3899
-
3900
- /**
3901
- * @webref table:method
3902
- * @brief Finds multiple rows that match the given expression
3903
- * @param value the regular expression to match
3904
- * @param column ID number of the column to search
3905
- */
3906
- public Iterator<TableRow> matchRowIterator(String value, int column) {
3907
- return new RowIndexIterator(this, matchRowIndices(value, column));
3908
- }
3909
-
3910
-
3911
- /**
3912
- * @param columnName title of the column to search
3913
- */
3914
- public Iterator<TableRow> matchRowIterator(String value, String columnName) {
3915
- return matchRowIterator(value, getColumnIndex(columnName));
3916
- }
3917
-
3918
-
3919
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3920
-
3921
-
3922
- /**
3923
- * Replace a String with another. Set empty entries null by using
3924
- * replace("", null) or use replace(null, "") to go the other direction.
3925
- * If this is a typed table, only String columns will be modified.
3926
- * @param orig
3927
- * @param replacement
3928
- */
3929
- public void replace(String orig, String replacement) {
3930
- for (int col = 0; col < columns.length; col++) {
3931
- replace(orig, replacement, col);
3932
- }
3933
- }
3934
-
3935
-
3936
- public void replace(String orig, String replacement, int col) {
3937
- if (columnTypes[col] == STRING) {
3938
- String[] stringData = (String[]) columns[col];
3939
-
3940
- if (orig != null) {
3941
- for (int row = 0; row < rowCount; row++) {
3942
- if (orig.equals(stringData[row])) {
3943
- stringData[row] = replacement;
3944
- }
3945
- }
3946
- } else { // null is a special case (and faster anyway)
3947
- for (int row = 0; row < rowCount; row++) {
3948
- if (stringData[row] == null) {
3949
- stringData[row] = replacement;
3950
- }
3951
- }
3952
- }
3953
- }
3954
- }
3955
-
3956
-
3957
- public void replace(String orig, String replacement, String colName) {
3958
- replace(orig, replacement, getColumnIndex(colName));
3959
- }
3960
-
3961
-
3962
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3963
-
3964
-
3965
- public void replaceAll(String regex, String replacement) {
3966
- for (int col = 0; col < columns.length; col++) {
3967
- replaceAll(regex, replacement, col);
3968
- }
3969
- }
3970
-
3971
-
3972
- public void replaceAll(String regex, String replacement, int column) {
3973
- checkColumn(column);
3974
- if (columnTypes[column] == STRING) {
3975
- String[] stringData = (String[]) columns[column];
3976
- for (int row = 0; row < rowCount; row++) {
3977
- if (stringData[row] != null) {
3978
- stringData[row] = stringData[row].replaceAll(regex, replacement);
3979
- }
3980
- }
3981
- } else {
3982
- throw new IllegalArgumentException("replaceAll() can only be used on String columns");
3983
- }
3984
- }
3985
-
3986
-
3987
- /**
3988
- * Run String.replaceAll() on all entries in a column.
3989
- * Only works with columns that are already String values.
3990
- * @param regex the String to match
3991
- * @param columnName title of the column to search
3992
- */
3993
- public void replaceAll(String regex, String replacement, String columnName) {
3994
- replaceAll(regex, replacement, getColumnIndex(columnName));
3995
- }
3996
-
3997
-
3998
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3999
-
4000
-
4001
- /**
4002
- * Remove any of the specified characters from the entire table.
4003
- *
4004
- * @webref table:method
4005
- * @brief Removes characters from the table
4006
- * @param tokens a list of individual characters to be removed
4007
- * @see Table#trim()
4008
- */
4009
- public void removeTokens(String tokens) {
4010
- for (int col = 0; col < getColumnCount(); col++) {
4011
- removeTokens(tokens, col);
4012
- }
4013
- }
4014
-
4015
-
4016
- /**
4017
- * Removed any of the specified characters from a column. For instance,
4018
- * the following code removes dollar signs and commas from column 2:
4019
- * <pre>
4020
- * table.removeTokens(",$", 2);
4021
- * </pre>
4022
- *
4023
- * @param column ID number of the column to process
4024
- */
4025
- public void removeTokens(String tokens, int column) {
4026
- for (int row = 0; row < rowCount; row++) {
4027
- String s = getString(row, column);
4028
- if (s != null) {
4029
- char[] c = s.toCharArray();
4030
- int index = 0;
4031
- for (int j = 0; j < c.length; j++) {
4032
- if (tokens.indexOf(c[j]) == -1) {
4033
- if (index != j) {
4034
- c[index] = c[j];
4035
- }
4036
- index++;
4037
- }
4038
- }
4039
- if (index != c.length) {
4040
- setString(row, column, new String(c, 0, index));
4041
- }
4042
- }
4043
- }
4044
- }
4045
-
4046
- /**
4047
- * @param columnName title of the column to process
4048
- */
4049
- public void removeTokens(String tokens, String columnName) {
4050
- removeTokens(tokens, getColumnIndex(columnName));
4051
- }
4052
-
4053
-
4054
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4055
-
4056
-
4057
- /**
4058
- * @webref table:method
4059
- * @brief Trims whitespace from values
4060
- * @see Table#removeTokens(String)
4061
- */
4062
- public void trim() {
4063
- columnTitles = PApplet.trim(columnTitles);
4064
- for (int col = 0; col < getColumnCount(); col++) {
4065
- trim(col);
4066
- }
4067
- // remove empty columns
4068
- int lastColumn = getColumnCount() - 1;
4069
- //while (isEmptyColumn(lastColumn) && lastColumn >= 0) {
4070
- while (isEmptyArray(getStringColumn(lastColumn)) && lastColumn >= 0) {
4071
- lastColumn--;
4072
- }
4073
- setColumnCount(lastColumn + 1);
4074
-
4075
- // trim() works from both sides
4076
- while (getColumnCount() > 0 && isEmptyArray(getStringColumn(0))) {
4077
- removeColumn(0);
4078
- }
4079
-
4080
- // remove empty rows (starting from the end)
4081
- int lastRow = lastRowIndex();
4082
- //while (isEmptyRow(lastRow) && lastRow >= 0) {
4083
- while (isEmptyArray(getStringRow(lastRow)) && lastRow >= 0) {
4084
- lastRow--;
4085
- }
4086
- setRowCount(lastRow + 1);
4087
-
4088
- while (getRowCount() > 0 && isEmptyArray(getStringRow(0))) {
4089
- removeRow(0);
4090
- }
4091
- }
4092
-
4093
-
4094
- protected boolean isEmptyArray(String[] contents) {
4095
- for (String entry : contents) {
4096
- if (entry != null && entry.length() > 0) {
4097
- return false;
4098
- }
4099
- }
4100
- return true;
4101
- }
4102
-
4103
-
4104
- /*
4105
- protected boolean isEmptyColumn(int column) {
4106
- String[] contents = getStringColumn(column);
4107
- for (String entry : contents) {
4108
- if (entry != null && entry.length() > 0) {
4109
- return false;
4110
- }
4111
- }
4112
- return true;
4113
- }
4114
-
4115
-
4116
- protected boolean isEmptyRow(int row) {
4117
- String[] contents = getStringRow(row);
4118
- for (String entry : contents) {
4119
- if (entry != null && entry.length() > 0) {
4120
- return false;
4121
- }
4122
- }
4123
- return true;
4124
- }
4125
- */
4126
-
4127
-
4128
- /**
4129
- * @param column ID number of the column to trim
4130
- */
4131
- public void trim(int column) {
4132
- if (columnTypes[column] == STRING) {
4133
- String[] stringData = (String[]) columns[column];
4134
- for (int row = 0; row < rowCount; row++) {
4135
- if (stringData[row] != null) {
4136
- stringData[row] = PApplet.trim(stringData[row]);
4137
- }
4138
- }
4139
- }
4140
- }
4141
-
4142
- /**
4143
- * @param columnName title of the column to trim
4144
- */
4145
- public void trim(String columnName) {
4146
- trim(getColumnIndex(columnName));
4147
- }
4148
-
4149
-
4150
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4151
-
4152
-
4153
- /** Make sure this is a legit column, and if not, expand the table. */
4154
- protected void ensureColumn(int col) {
4155
- if (col >= columns.length) {
4156
- setColumnCount(col + 1);
4157
- }
4158
- }
4159
-
4160
-
4161
- /** Make sure this is a legit row, and if not, expand the table. */
4162
- protected void ensureRow(int row) {
4163
- if (row >= rowCount) {
4164
- setRowCount(row + 1);
4165
- }
4166
- }
4167
-
4168
-
4169
- /** Make sure this is a legit row and column. If not, expand the table. */
4170
- protected void ensureBounds(int row, int col) {
4171
- ensureRow(row);
4172
- ensureColumn(col);
4173
- }
4174
-
4175
-
4176
- /** Throw an error if this row doesn't exist. */
4177
- protected void checkRow(int row) {
4178
- if (row < 0 || row >= rowCount) {
4179
- throw new ArrayIndexOutOfBoundsException("Row " + row + " does not exist.");
4180
- }
4181
- }
4182
-
4183
-
4184
- /** Throw an error if this column doesn't exist. */
4185
- protected void checkColumn(int column) {
4186
- if (column < 0 || column >= columns.length) {
4187
- throw new ArrayIndexOutOfBoundsException("Column " + column + " does not exist.");
4188
- }
4189
- }
4190
-
4191
-
4192
- /** Throw an error if this entry is out of bounds. */
4193
- protected void checkBounds(int row, int column) {
4194
- checkRow(row);
4195
- checkColumn(column);
4196
- }
4197
-
4198
-
4199
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4200
-
4201
-
4202
- static class HashMapBlows {
4203
- HashMap<String,Integer> dataToIndex = new HashMap<>();
4204
- ArrayList<String> indexToData = new ArrayList<>();
4205
-
4206
- HashMapBlows() { }
4207
-
4208
- HashMapBlows(DataInputStream input) throws IOException {
4209
- read(input);
4210
- }
4211
-
4212
- /** gets the index, and creates one if it doesn't already exist. */
4213
- int index(String key) {
4214
- Integer value = dataToIndex.get(key);
4215
- if (value != null) {
4216
- return value;
4217
- }
4218
-
4219
- int v = dataToIndex.size();
4220
- dataToIndex.put(key, v);
4221
- indexToData.add(key);
4222
- return v;
4223
- }
4224
-
4225
- String key(int index) {
4226
- return indexToData.get(index);
4227
- }
4228
-
4229
- boolean hasCategory(int index) {
4230
- return index < size() && indexToData.get(index) != null;
4231
- }
4232
-
4233
- void setCategory(int index, String name) {
4234
- while (indexToData.size() <= index) {
4235
- indexToData.add(null);
4236
- }
4237
- indexToData.set(index, name);
4238
- dataToIndex.put(name, index);
4239
- }
4240
-
4241
- int size() {
4242
- return dataToIndex.size();
4243
- }
4244
-
4245
- void write(DataOutputStream output) throws IOException {
4246
- output.writeInt(size());
4247
- for (String str : indexToData) {
4248
- output.writeUTF(str);
4249
- }
4250
- }
4251
-
4252
- private void writeln(PrintWriter writer) throws IOException {
4253
- for (String str : indexToData) {
4254
- writer.println(str);
4255
- }
4256
- writer.flush();
4257
- writer.close();
4258
- }
4259
-
4260
- void read(DataInputStream input) throws IOException {
4261
- int count = input.readInt();
4262
- //System.out.println("found " + count + " entries in category map");
4263
- dataToIndex = new HashMap<>(count);
4264
- for (int i = 0; i < count; i++) {
4265
- String str = input.readUTF();
4266
- //System.out.println(i + " " + str);
4267
- dataToIndex.put(str, i);
4268
- indexToData.add(str);
4269
- }
4270
- }
4271
- }
4272
-
4273
-
4274
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4275
-
4276
-
4277
- // class HashMapSucks extends HashMap<String,Integer> {
4278
- //
4279
- // void increment(String what) {
4280
- // Integer value = get(what);
4281
- // if (value == null) {
4282
- // put(what, 1);
4283
- // } else {
4284
- // put(what, value + 1);
4285
- // }
4286
- // }
4287
- //
4288
- // void check(String what) {
4289
- // if (get(what) == null) {
4290
- // put(what, 0);
4291
- // }
4292
- // }
4293
- // }
4294
-
4295
-
4296
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4297
-
4298
- /**
4299
- * Sorts (orders) a table based on the values in a column.
4300
- *
4301
- * @webref table:method
4302
- * @brief Orders a table based on the values in a column
4303
- * @param columnName the name of the column to sort
4304
- * @see Table#trim()
4305
- */
4306
- public void sort(String columnName) {
4307
- sort(getColumnIndex(columnName), false);
4308
- }
4309
-
4310
- /**
4311
- * @param column the column ID, e.g. 0, 1, 2
4312
- */
4313
- public void sort(int column) {
4314
- sort(column, false);
4315
- }
4316
-
4317
-
4318
- public void sortReverse(String columnName) {
4319
- sort(getColumnIndex(columnName), true);
4320
- }
4321
-
4322
-
4323
- public void sortReverse(int column) {
4324
- sort(column, true);
4325
- }
4326
-
4327
-
4328
- protected void sort(final int column, final boolean reverse) {
4329
- final int[] order = IntList.fromRange(getRowCount()).array();
4330
- Sort s = new Sort() {
4331
-
4332
- @Override
4333
- public int size() {
4334
- return getRowCount();
4335
- }
4336
-
4337
- @Override
4338
- public int compare(int index1, int index2) {
4339
- int a = reverse ? order[index2] : order[index1];
4340
- int b = reverse ? order[index1] : order[index2];
4341
-
4342
- switch (getColumnType(column)) {
4343
- case INT:
4344
- return getInt(a, column) - getInt(b, column);
4345
- case LONG:
4346
- long diffl = getLong(a, column) - getLong(b, column);
4347
- return diffl == 0 ? 0 : (diffl < 0 ? -1 : 1);
4348
- case FLOAT:
4349
- float difff = getFloat(a, column) - getFloat(b, column);
4350
- return difff == 0 ? 0 : (difff < 0 ? -1 : 1);
4351
- case DOUBLE:
4352
- double diffd = getDouble(a, column) - getDouble(b, column);
4353
- return diffd == 0 ? 0 : (diffd < 0 ? -1 : 1);
4354
- case STRING:
4355
- String string1 = getString(a, column);
4356
- if (string1 == null) {
4357
- string1 = ""; // avoid NPE when cells are left empty
4358
- }
4359
- String string2 = getString(b, column);
4360
- if (string2 == null) {
4361
- string2 = "";
4362
- }
4363
- return string1.compareToIgnoreCase(string2);
4364
- case CATEGORY:
4365
- return getInt(a, column) - getInt(b, column);
4366
- default:
4367
- throw new IllegalArgumentException("Invalid column type: " + getColumnType(column));
4368
- }
4369
- }
4370
-
4371
- @Override
4372
- public void swap(int a, int b) {
4373
- int temp = order[a];
4374
- order[a] = order[b];
4375
- order[b] = temp;
4376
- }
4377
-
4378
- };
4379
- s.run();
4380
-
4381
- //Object[] newColumns = new Object[getColumnCount()];
4382
- for (int col = 0; col < getColumnCount(); col++) {
4383
- switch (getColumnType(col)) {
4384
- case INT:
4385
- case CATEGORY:
4386
- int[] oldInt = (int[]) columns[col];
4387
- int[] newInt = new int[rowCount];
4388
- for (int row = 0; row < getRowCount(); row++) {
4389
- newInt[row] = oldInt[order[row]];
4390
- }
4391
- columns[col] = newInt;
4392
- break;
4393
- case LONG:
4394
- long[] oldLong = (long[]) columns[col];
4395
- long[] newLong = new long[rowCount];
4396
- for (int row = 0; row < getRowCount(); row++) {
4397
- newLong[row] = oldLong[order[row]];
4398
- }
4399
- columns[col] = newLong;
4400
- break;
4401
- case FLOAT:
4402
- float[] oldFloat = (float[]) columns[col];
4403
- float[] newFloat = new float[rowCount];
4404
- for (int row = 0; row < getRowCount(); row++) {
4405
- newFloat[row] = oldFloat[order[row]];
4406
- }
4407
- columns[col] = newFloat;
4408
- break;
4409
- case DOUBLE:
4410
- double[] oldDouble = (double[]) columns[col];
4411
- double[] newDouble = new double[rowCount];
4412
- for (int row = 0; row < getRowCount(); row++) {
4413
- newDouble[row] = oldDouble[order[row]];
4414
- }
4415
- columns[col] = newDouble;
4416
- break;
4417
- case STRING:
4418
- String[] oldString = (String[]) columns[col];
4419
- String[] newString = new String[rowCount];
4420
- for (int row = 0; row < getRowCount(); row++) {
4421
- newString[row] = oldString[order[row]];
4422
- }
4423
- columns[col] = newString;
4424
- break;
4425
- }
4426
- }
4427
- }
4428
-
4429
-
4430
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4431
-
4432
-
4433
- public String[] getUnique(String columnName) {
4434
- return getUnique(getColumnIndex(columnName));
4435
- }
4436
-
4437
-
4438
- public String[] getUnique(int column) {
4439
- StringList list = new StringList(getStringColumn(column));
4440
- return list.getUnique();
4441
- }
4442
-
4443
-
4444
- public IntDict getTally(String columnName) {
4445
- return getTally(getColumnIndex(columnName));
4446
- }
4447
-
4448
-
4449
- public IntDict getTally(int column) {
4450
- StringList list = new StringList(getStringColumn(column));
4451
- return list.getTally();
4452
- }
4453
-
4454
-
4455
- public IntDict getOrder(String columnName) {
4456
- return getOrder(getColumnIndex(columnName));
4457
- }
4458
-
4459
-
4460
- public IntDict getOrder(int column) {
4461
- StringList list = new StringList(getStringColumn(column));
4462
- return list.getOrder();
4463
- }
4464
-
4465
-
4466
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4467
-
4468
-
4469
- public IntList getIntList(String columnName) {
4470
- return new IntList(getIntColumn(columnName));
4471
- }
4472
-
4473
-
4474
- public IntList getIntList(int column) {
4475
- return new IntList(getIntColumn(column));
4476
- }
4477
-
4478
-
4479
- public FloatList getFloatList(String columnName) {
4480
- return new FloatList(getFloatColumn(columnName));
4481
- }
4482
-
4483
-
4484
- public FloatList getFloatList(int column) {
4485
- return new FloatList(getFloatColumn(column));
4486
- }
4487
-
4488
-
4489
- public StringList getStringList(String columnName) {
4490
- return new StringList(getStringColumn(columnName));
4491
- }
4492
-
4493
-
4494
- public StringList getStringList(int column) {
4495
- return new StringList(getStringColumn(column));
4496
- }
4497
-
4498
-
4499
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4500
-
4501
-
4502
- public IntDict getIntDict(String keyColumnName, String valueColumnName) {
4503
- return new IntDict(getStringColumn(keyColumnName),
4504
- getIntColumn(valueColumnName));
4505
- }
4506
-
4507
-
4508
- public IntDict getIntDict(int keyColumn, int valueColumn) {
4509
- return new IntDict(getStringColumn(keyColumn),
4510
- getIntColumn(valueColumn));
4511
- }
4512
-
4513
-
4514
- public FloatDict getFloatDict(String keyColumnName, String valueColumnName) {
4515
- return new FloatDict(getStringColumn(keyColumnName),
4516
- getFloatColumn(valueColumnName));
4517
- }
4518
-
4519
-
4520
- public FloatDict getFloatDict(int keyColumn, int valueColumn) {
4521
- return new FloatDict(getStringColumn(keyColumn),
4522
- getFloatColumn(valueColumn));
4523
- }
4524
-
4525
-
4526
- public StringDict getStringDict(String keyColumnName, String valueColumnName) {
4527
- return new StringDict(getStringColumn(keyColumnName),
4528
- getStringColumn(valueColumnName));
4529
- }
4530
-
4531
-
4532
- public StringDict getStringDict(int keyColumn, int valueColumn) {
4533
- return new StringDict(getStringColumn(keyColumn),
4534
- getStringColumn(valueColumn));
4535
- }
4536
-
4537
-
4538
- public Map<String, TableRow> getRowMap(String columnName) {
4539
- int col = getColumnIndex(columnName);
4540
- return (col == -1) ? null : getRowMap(col);
4541
- }
4542
-
4543
-
4544
- /**
4545
- * Return a mapping that connects the entry from a column back to the row
4546
- * from which it came. For instance:
4547
- * <pre>
4548
- * Table t = loadTable("country-data.tsv", "header");
4549
- * // use the contents of the 'country' column to index the table
4550
- * Map<String, TableRow> lookup = t.getRowMap("country");
4551
- * // get the row that has "us" in the "country" column:
4552
- * TableRow usRow = lookup.get("us");
4553
- * // get an entry from the 'population' column
4554
- * int population = usRow.getInt("population");
4555
- * </pre>
4556
- */
4557
- public Map<String, TableRow> getRowMap(int column) {
4558
- Map<String, TableRow> outgoing = new HashMap<>();
4559
- for (int row = 0; row < getRowCount(); row++) {
4560
- String id = getString(row, column);
4561
- outgoing.put(id, new RowPointer(this, row));
4562
- }
4563
- // for (TableRow row : rows()) {
4564
- // String id = row.getString(column);
4565
- // outgoing.put(id, row);
4566
- // }
4567
- return outgoing;
4568
- }
4569
-
4570
-
4571
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4572
-
4573
-
4574
- // /**
4575
- // * Return an object that maps the String values in one column back to the
4576
- // * row from which they came. For instance, if the "name" of each row is
4577
- // * found in the first column, getColumnRowLookup(0) would return an object
4578
- // * that would map each name back to its row.
4579
- // */
4580
- // protected HashMap<String,Integer> getRowLookup(int col) {
4581
- // HashMap<String,Integer> outgoing = new HashMap<String, Integer>();
4582
- // for (int row = 0; row < getRowCount(); row++) {
4583
- // outgoing.put(getString(row, col), row);
4584
- // }
4585
- // return outgoing;
4586
- // }
4587
-
4588
-
4589
- // incomplete, basically this is silly to write all this repetitive code when
4590
- // it can be implemented in ~3 lines of code...
4591
- // /**
4592
- // * Return an object that maps the data from one column to the data of found
4593
- // * in another column.
4594
- // */
4595
- // public HashMap<?,?> getLookup(int col1, int col2) {
4596
- // HashMap outgoing = null;
4597
- //
4598
- // switch (columnTypes[col1]) {
4599
- // case INT: {
4600
- // if (columnTypes[col2] == INT) {
4601
- // outgoing = new HashMap<Integer, Integer>();
4602
- // for (int row = 0; row < getRowCount(); row++) {
4603
- // outgoing.put(getInt(row, col1), getInt(row, col2));
4604
- // }
4605
- // } else if (columnTypes[col2] == LONG) {
4606
- // outgoing = new HashMap<Integer, Long>();
4607
- // for (int row = 0; row < getRowCount(); row++) {
4608
- // outgoing.put(getInt(row, col1), getLong(row, col2));
4609
- // }
4610
- // } else if (columnTypes[col2] == FLOAT) {
4611
- // outgoing = new HashMap<Integer, Float>();
4612
- // for (int row = 0; row < getRowCount(); row++) {
4613
- // outgoing.put(getInt(row, col1), getFloat(row, col2));
4614
- // }
4615
- // } else if (columnTypes[col2] == DOUBLE) {
4616
- // outgoing = new HashMap<Integer, Double>();
4617
- // for (int row = 0; row < getRowCount(); row++) {
4618
- // outgoing.put(getInt(row, col1), getDouble(row, col2));
4619
- // }
4620
- // } else if (columnTypes[col2] == STRING) {
4621
- // outgoing = new HashMap<Integer, String>();
4622
- // for (int row = 0; row < getRowCount(); row++) {
4623
- // outgoing.put(getInt(row, col1), get(row, col2));
4624
- // }
4625
- // }
4626
- // break;
4627
- // }
4628
- // }
4629
- // return outgoing;
4630
- // }
4631
-
4632
-
4633
- // public StringIntPairs getColumnRowLookup(int col) {
4634
- // StringIntPairs sc = new StringIntPairs();
4635
- // String[] column = getStringColumn(col);
4636
- // for (int i = 0; i < column.length; i++) {
4637
- // sc.set(column[i], i);
4638
- // }
4639
- // return sc;
4640
- // }
4641
-
4642
-
4643
- // public String[] getUniqueEntries(int column) {
4644
- //// HashMap indices = new HashMap();
4645
- //// for (int row = 0; row < rowCount; row++) {
4646
- //// indices.put(data[row][column], this); // 'this' is a dummy
4647
- //// }
4648
- // StringIntPairs sc = getStringCount(column);
4649
- // return sc.keys();
4650
- // }
4651
- //
4652
- //
4653
- // public StringIntPairs getStringCount(String columnName) {
4654
- // return getStringCount(getColumnIndex(columnName));
4655
- // }
4656
- //
4657
- //
4658
- // public StringIntPairs getStringCount(int column) {
4659
- // StringIntPairs outgoing = new StringIntPairs();
4660
- // for (int row = 0; row < rowCount; row++) {
4661
- // String entry = data[row][column];
4662
- // if (entry != null) {
4663
- // outgoing.increment(entry);
4664
- // }
4665
- // }
4666
- // return outgoing;
4667
- // }
4668
- //
4669
- //
4670
- // /**
4671
- // * Return an object that maps the String values in one column back to the
4672
- // * row from which they came. For instance, if the "name" of each row is
4673
- // * found in the first column, getColumnRowLookup(0) would return an object
4674
- // * that would map each name back to its row.
4675
- // */
4676
- // public StringIntPairs getColumnRowLookup(int col) {
4677
- // StringIntPairs sc = new StringIntPairs();
4678
- // String[] column = getStringColumn(col);
4679
- // for (int i = 0; i < column.length; i++) {
4680
- // sc.set(column[i], i);
4681
- // }
4682
- // return sc;
4683
- // }
4684
-
4685
-
4686
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4687
-
4688
-
4689
- // TODO naming/whether to include
4690
- protected Table createSubset(int[] rowSubset) {
4691
- Table newbie = new Table();
4692
- newbie.setColumnTitles(columnTitles); // also sets columns.length
4693
- newbie.columnTypes = columnTypes;
4694
- newbie.setRowCount(rowSubset.length);
4695
-
4696
- for (int i = 0; i < rowSubset.length; i++) {
4697
- int row = rowSubset[i];
4698
- for (int col = 0; col < columns.length; col++) {
4699
- switch (columnTypes[col]) {
4700
- case STRING: newbie.setString(i, col, getString(row, col)); break;
4701
- case INT: newbie.setInt(i, col, getInt(row, col)); break;
4702
- case LONG: newbie.setLong(i, col, getLong(row, col)); break;
4703
- case FLOAT: newbie.setFloat(i, col, getFloat(row, col)); break;
4704
- case DOUBLE: newbie.setDouble(i, col, getDouble(row, col)); break;
4705
- }
4706
- }
4707
- }
4708
- return newbie;
4709
- }
4710
-
4711
-
4712
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4713
-
4714
-
4715
- /**
4716
- * Searches the entire table for float values.
4717
- * Returns missing float (Float.NaN by default) if no valid numbers found.
4718
- */
4719
- protected float getMaxFloat() {
4720
- boolean found = false;
4721
- float max = PConstants.MIN_FLOAT;
4722
- for (int row = 0; row < getRowCount(); row++) {
4723
- for (int col = 0; col < getColumnCount(); col++) {
4724
- float value = getFloat(row, col);
4725
- if (!Float.isNaN(value)) { // TODO no, this should be comparing to the missing value
4726
- if (!found) {
4727
- max = value;
4728
- found = true;
4729
- } else if (value > max) {
4730
- max = value;
4731
- }
4732
- }
4733
- }
4734
- }
4735
- return found ? max : missingFloat;
4736
- }
4737
-
4738
-
4739
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4740
-
4741
-
4742
- // converts a TSV or CSV file to binary.. do not use
4743
- protected void convertBasic(BufferedReader reader, boolean tsv,
4744
- File outputFile) throws IOException {
4745
- FileOutputStream fos = new FileOutputStream(outputFile);
4746
- BufferedOutputStream bos = new BufferedOutputStream(fos, 16384);
4747
- DataOutputStream output = new DataOutputStream(bos);
4748
- output.writeInt(0); // come back for row count
4749
- output.writeInt(getColumnCount());
4750
- if (columnTitles != null) {
4751
- output.writeBoolean(true);
4752
- for (String title : columnTitles) {
4753
- output.writeUTF(title);
4754
- }
4755
- } else {
4756
- output.writeBoolean(false);
4757
- }
4758
- for (int type : columnTypes) {
4759
- output.writeInt(type);
4760
- }
4761
-
4762
- String line = null;
4763
- //setRowCount(1);
4764
- int prev = -1;
4765
- int row = 0;
4766
- while ((line = reader.readLine()) != null) {
4767
- convertRow(output, tsv ? PApplet.split(line, '\t') : splitLineCSV(line, reader));
4768
- row++;
4769
-
4770
- if (row % 10000 == 0) {
4771
- if (row < rowCount) {
4772
- int pct = (100 * row) / rowCount;
4773
- if (pct != prev) {
4774
- System.out.println(pct + "%");
4775
- prev = pct;
4776
- }
4777
- }
4778
- // try {
4779
- // Thread.sleep(5);
4780
- // } catch (InterruptedException e) {
4781
- // e.printStackTrace();
4782
- // }
4783
- }
4784
- }
4785
- // shorten or lengthen based on what's left
4786
- // if (row != getRowCount()) {
4787
- // setRowCount(row);
4788
- // }
4789
-
4790
- // has to come afterwards, since these tables get built out during the conversion
4791
- int col = 0;
4792
- for (HashMapBlows hmb : columnCategories) {
4793
- if (hmb == null) {
4794
- output.writeInt(0);
4795
- } else {
4796
- hmb.write(output);
4797
- hmb.writeln(PApplet.createWriter(new File(columnTitles[col] + ".categories")));
4798
- // output.writeInt(hmb.size());
4799
- // for (Map.Entry<String,Integer> e : hmb.entrySet()) {
4800
- // output.writeUTF(e.getKey());
4801
- // output.writeInt(e.getValue());
4802
- // }
4803
- }
4804
- col++;
4805
- }
4806
-
4807
- output.flush();
4808
- output.close();
4809
-
4810
- // come back and write the row count
4811
- RandomAccessFile raf = new RandomAccessFile(outputFile, "rw");
4812
- raf.writeInt(rowCount);
4813
- raf.close();
4814
- }
4815
-
4816
-
4817
- protected void convertRow(DataOutputStream output, String[] pieces) throws IOException {
4818
- if (pieces.length > getColumnCount()) {
4819
- throw new IllegalArgumentException("Row with too many columns: " +
4820
- PApplet.join(pieces, ","));
4821
- }
4822
- // pieces.length may be less than columns.length, so loop over pieces
4823
- for (int col = 0; col < pieces.length; col++) {
4824
- switch (columnTypes[col]) {
4825
- case STRING:
4826
- output.writeUTF(pieces[col]);
4827
- break;
4828
- case INT:
4829
- output.writeInt(PApplet.parseInt(pieces[col], missingInt));
4830
- break;
4831
- case LONG:
4832
- try {
4833
- output.writeLong(Long.parseLong(pieces[col]));
4834
- } catch (NumberFormatException nfe) {
4835
- output.writeLong(missingLong);
4836
- }
4837
- break;
4838
- case FLOAT:
4839
- output.writeFloat(PApplet.parseFloat(pieces[col], missingFloat));
4840
- break;
4841
- case DOUBLE:
4842
- try {
4843
- output.writeDouble(Double.parseDouble(pieces[col]));
4844
- } catch (NumberFormatException nfe) {
4845
- output.writeDouble(missingDouble);
4846
- }
4847
- break;
4848
- case CATEGORY:
4849
- String peace = pieces[col];
4850
- if (peace.equals(missingString)) {
4851
- output.writeInt(missingCategory);
4852
- } else {
4853
- output.writeInt(columnCategories[col].index(peace));
4854
- }
4855
- break;
4856
- }
4857
- }
4858
- for (int col = pieces.length; col < getColumnCount(); col++) {
4859
- switch (columnTypes[col]) {
4860
- case STRING:
4861
- output.writeUTF("");
4862
- break;
4863
- case INT:
4864
- output.writeInt(missingInt);
4865
- break;
4866
- case LONG:
4867
- output.writeLong(missingLong);
4868
- break;
4869
- case FLOAT:
4870
- output.writeFloat(missingFloat);
4871
- break;
4872
- case DOUBLE:
4873
- output.writeDouble(missingDouble);
4874
- break;
4875
- case CATEGORY:
4876
- output.writeInt(missingCategory);
4877
- break;
4878
-
4879
- }
4880
- }
4881
- }
4882
-
4883
-
4884
- /*
4885
- private void convertRowCol(DataOutputStream output, int row, int col, String piece) {
4886
- switch (columnTypes[col]) {
4887
- case STRING:
4888
- String[] stringData = (String[]) columns[col];
4889
- stringData[row] = piece;
4890
- break;
4891
- case INT:
4892
- int[] intData = (int[]) columns[col];
4893
- intData[row] = PApplet.parseInt(piece, missingInt);
4894
- break;
4895
- case LONG:
4896
- long[] longData = (long[]) columns[col];
4897
- try {
4898
- longData[row] = Long.parseLong(piece);
4899
- } catch (NumberFormatException nfe) {
4900
- longData[row] = missingLong;
4901
- }
4902
- break;
4903
- case FLOAT:
4904
- float[] floatData = (float[]) columns[col];
4905
- floatData[row] = PApplet.parseFloat(piece, missingFloat);
4906
- break;
4907
- case DOUBLE:
4908
- double[] doubleData = (double[]) columns[col];
4909
- try {
4910
- doubleData[row] = Double.parseDouble(piece);
4911
- } catch (NumberFormatException nfe) {
4912
- doubleData[row] = missingDouble;
4913
- }
4914
- break;
4915
- default:
4916
- throw new IllegalArgumentException("That's not a valid column type.");
4917
- }
4918
- }
4919
- */
4920
-
4921
-
4922
- /** Make a copy of the current table */
4923
- public Table copy() {
4924
- return new Table(rows());
4925
- }
4926
-
4927
-
4928
- public void write(PrintWriter writer) {
4929
- writeTSV(writer);
4930
- }
4931
-
4932
-
4933
- public void print() {
4934
- writeTSV(new PrintWriter(System.out));
4935
- }
4936
- }