diff --git a/demo/demo.jar b/demo/demo.jar index 4b743ea7..f1f9392e 100644 Binary files a/demo/demo.jar and b/demo/demo.jar differ diff --git a/eclipse/src/com/google/zxing/BarcodeFormat.java b/eclipse/src/com/google/zxing/BarcodeFormat.java index 266c9a15..24b56e3a 100644 --- a/eclipse/src/com/google/zxing/BarcodeFormat.java +++ b/eclipse/src/com/google/zxing/BarcodeFormat.java @@ -23,9 +23,6 @@ */ public enum BarcodeFormat { - /** Aztec 2D barcode format. */ - AZTEC, - /** CODABAR 1D format. */ CODABAR, diff --git a/eclipse/src/com/google/zxing/MultiFormatReader.java b/eclipse/src/com/google/zxing/MultiFormatReader.java index 229ae0e0..f84f1507 100644 --- a/eclipse/src/com/google/zxing/MultiFormatReader.java +++ b/eclipse/src/com/google/zxing/MultiFormatReader.java @@ -16,7 +16,6 @@ package com.google.zxing; -import com.google.zxing.aztec.AztecReader; import com.google.zxing.datamatrix.DataMatrixReader; import com.google.zxing.maxicode.MaxiCodeReader; import com.google.zxing.oned.MultiFormatOneDReader; @@ -136,9 +135,6 @@ public void setHints(Map hints) { if (formats.contains(BarcodeFormat.DATA_MATRIX)) { readers.add(new DataMatrixReader()); } - if (formats.contains(BarcodeFormat.AZTEC)) { - readers.add(new AztecReader()); - } if (formats.contains(BarcodeFormat.MAXICODE)) { readers.add(new MaxiCodeReader()); } @@ -154,7 +150,6 @@ public void setHints(Map hints) { readers.add(new QRCodeReader()); readers.add(new DataMatrixReader()); - readers.add(new AztecReader()); readers.add(new MaxiCodeReader()); if (tryHarder) { diff --git a/eclipse/src/com/google/zxing/MultiFormatWriter.java b/eclipse/src/com/google/zxing/MultiFormatWriter.java index 37446280..82a626bd 100644 --- a/eclipse/src/com/google/zxing/MultiFormatWriter.java +++ b/eclipse/src/com/google/zxing/MultiFormatWriter.java @@ -16,7 +16,6 @@ package com.google.zxing; -import com.google.zxing.aztec.AztecWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.datamatrix.DataMatrixWriter; import com.google.zxing.oned.CodaBarWriter; @@ -77,9 +76,6 @@ public BitMatrix encode(String contents, BarcodeFormat format, int width, case DATA_MATRIX: writer = new DataMatrixWriter(); break; - case AZTEC: - writer = new AztecWriter(); - break; default: throw new IllegalArgumentException( "No encoder available for format " + format); diff --git a/eclipse/src/com/google/zxing/aztec/AztecDetectorResult.java b/eclipse/src/com/google/zxing/aztec/AztecDetectorResult.java deleted file mode 100644 index d50a5838..00000000 --- a/eclipse/src/com/google/zxing/aztec/AztecDetectorResult.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec; - -import com.google.zxing.ResultPoint; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.DetectorResult; - -public final class AztecDetectorResult extends DetectorResult { - - private final boolean compact; - private final int nbDatablocks; - private final int nbLayers; - - public AztecDetectorResult(BitMatrix bits, ResultPoint[] points, - boolean compact, int nbDatablocks, int nbLayers) { - super(bits, points); - this.compact = compact; - this.nbDatablocks = nbDatablocks; - this.nbLayers = nbLayers; - } - - public int getNbLayers() { - return nbLayers; - } - - public int getNbDatablocks() { - return nbDatablocks; - } - - public boolean isCompact() { - return compact; - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/AztecReader.java b/eclipse/src/com/google/zxing/aztec/AztecReader.java deleted file mode 100644 index 6c23c6ee..00000000 --- a/eclipse/src/com/google/zxing/aztec/AztecReader.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.BinaryBitmap; -import com.google.zxing.DecodeHintType; -import com.google.zxing.FormatException; -import com.google.zxing.NotFoundException; -import com.google.zxing.Reader; -import com.google.zxing.Result; -import com.google.zxing.ResultMetadataType; -import com.google.zxing.ResultPoint; -import com.google.zxing.ResultPointCallback; -import com.google.zxing.aztec.decoder.Decoder; -import com.google.zxing.aztec.detector.Detector; -import com.google.zxing.common.DecoderResult; - -import java.util.List; -import java.util.Map; - -/** - * This implementation can detect and decode Aztec codes in an image. - * - * @author David Olivier - */ -public final class AztecReader implements Reader { - - /** - * Locates and decodes a Data Matrix code in an image. - * - * @return a String representing the content encoded by the Data Matrix code - * @throws NotFoundException - * if a Data Matrix code cannot be found - * @throws FormatException - * if a Data Matrix code cannot be decoded - */ - @Override - public Result decode(BinaryBitmap image) throws NotFoundException, - FormatException { - return decode(image, null); - } - - @Override - public Result decode(BinaryBitmap image, Map hints) - throws NotFoundException, FormatException { - - NotFoundException notFoundException = null; - FormatException formatException = null; - Detector detector = new Detector(image.getBlackMatrix()); - ResultPoint[] points = null; - DecoderResult decoderResult = null; - try { - AztecDetectorResult detectorResult = detector.detect(false); - points = detectorResult.getPoints(); - decoderResult = new Decoder().decode(detectorResult); - } catch (NotFoundException e) { - notFoundException = e; - } catch (FormatException e) { - formatException = e; - } - if (decoderResult == null) { - try { - AztecDetectorResult detectorResult = detector.detect(true); - points = detectorResult.getPoints(); - decoderResult = new Decoder().decode(detectorResult); - } catch (NotFoundException | FormatException e) { - if (notFoundException != null) { - throw notFoundException; - } - if (formatException != null) { - throw formatException; - } - throw e; - } - } - - if (hints != null) { - ResultPointCallback rpcb = (ResultPointCallback) hints - .get(DecodeHintType.NEED_RESULT_POINT_CALLBACK); - if (rpcb != null) { - for (ResultPoint point : points) { - rpcb.foundPossibleResultPoint(point); - } - } - } - - Result result = new Result(decoderResult.getText(), - decoderResult.getRawBytes(), points, BarcodeFormat.AZTEC); - - List byteSegments = decoderResult.getByteSegments(); - if (byteSegments != null) { - result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); - } - String ecLevel = decoderResult.getECLevel(); - if (ecLevel != null) { - result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, - ecLevel); - } - - return result; - } - - @Override - public void reset() { - // do nothing - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/AztecWriter.java b/eclipse/src/com/google/zxing/aztec/AztecWriter.java deleted file mode 100644 index b7744666..00000000 --- a/eclipse/src/com/google/zxing/aztec/AztecWriter.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.EncodeHintType; -import com.google.zxing.Writer; -import com.google.zxing.aztec.encoder.AztecCode; -import com.google.zxing.aztec.encoder.Encoder; -import com.google.zxing.common.BitMatrix; - -import java.nio.charset.Charset; -import java.util.Map; - -public final class AztecWriter implements Writer { - - private static final Charset DEFAULT_CHARSET = Charset - .forName("ISO-8859-1"); - - @Override - public BitMatrix encode(String contents, BarcodeFormat format, int width, - int height) { - return encode(contents, format, width, height, null); - } - - @Override - public BitMatrix encode(String contents, BarcodeFormat format, int width, - int height, Map hints) { - String charset = hints == null ? null : (String) hints - .get(EncodeHintType.CHARACTER_SET); - Number eccPercent = hints == null ? null : (Number) hints - .get(EncodeHintType.ERROR_CORRECTION); - Number layers = hints == null ? null : (Number) hints - .get(EncodeHintType.AZTEC_LAYERS); - return encode( - contents, - format, - width, - height, - charset == null ? DEFAULT_CHARSET : Charset.forName(charset), - eccPercent == null ? Encoder.DEFAULT_EC_PERCENT : eccPercent - .intValue(), - layers == null ? Encoder.DEFAULT_AZTEC_LAYERS : layers - .intValue()); - } - - private static BitMatrix encode(String contents, BarcodeFormat format, - int width, int height, Charset charset, int eccPercent, int layers) { - if (format != BarcodeFormat.AZTEC) { - throw new IllegalArgumentException( - "Can only encode AZTEC, but got " + format); - } - AztecCode aztec = Encoder.encode(contents.getBytes(charset), - eccPercent, layers); - return renderResult(aztec, width, height); - } - - private static BitMatrix renderResult(AztecCode code, int width, int height) { - BitMatrix input = code.getMatrix(); - if (input == null) { - throw new IllegalStateException(); - } - int inputWidth = input.getWidth(); - int inputHeight = input.getHeight(); - int outputWidth = Math.max(width, inputWidth); - int outputHeight = Math.max(height, inputHeight); - - int multiple = Math.min(outputWidth / inputWidth, outputHeight - / inputHeight); - int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; - int topPadding = (outputHeight - (inputHeight * multiple)) / 2; - - BitMatrix output = new BitMatrix(outputWidth, outputHeight); - - for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { - // Write the contents of this row of the barcode - for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { - if (input.get(inputX, inputY)) { - output.setRegion(outputX, outputY, multiple, multiple); - } - } - } - return output; - } -} diff --git a/eclipse/src/com/google/zxing/aztec/decoder/Decoder.java b/eclipse/src/com/google/zxing/aztec/decoder/Decoder.java deleted file mode 100644 index 669dd315..00000000 --- a/eclipse/src/com/google/zxing/aztec/decoder/Decoder.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.decoder; - -import com.google.zxing.FormatException; -import com.google.zxing.aztec.AztecDetectorResult; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.DecoderResult; -import com.google.zxing.common.reedsolomon.GenericGF; -import com.google.zxing.common.reedsolomon.ReedSolomonDecoder; -import com.google.zxing.common.reedsolomon.ReedSolomonException; - -import java.util.Arrays; - -/** - *

- * The main class which implements Aztec Code decoding -- as opposed to locating - * and extracting the Aztec Code from an image. - *

- * - * @author David Olivier - */ -public final class Decoder { - - private enum Table { - UPPER, LOWER, MIXED, DIGIT, PUNCT, BINARY - } - - private static final String[] UPPER_TABLE = { "CTRL_PS", " ", "A", "B", - "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", - "CTRL_ML", "CTRL_DL", "CTRL_BS" }; - - private static final String[] LOWER_TABLE = { "CTRL_PS", " ", "a", "b", - "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", - "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", - "CTRL_ML", "CTRL_DL", "CTRL_BS" }; - - private static final String[] MIXED_TABLE = { "CTRL_PS", " ", "\1", "\2", - "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n", "\13", "\f", "\r", - "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_", "`", "|", - "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS" }; - - private static final String[] PUNCT_TABLE = { "", "\r", "\r\n", ". ", ", ", - ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", - "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", - "CTRL_UL" }; - - private static final String[] DIGIT_TABLE = { "CTRL_PS", " ", "0", "1", - "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", - "CTRL_US" }; - - private AztecDetectorResult ddata; - - public DecoderResult decode(AztecDetectorResult detectorResult) - throws FormatException { - ddata = detectorResult; - BitMatrix matrix = detectorResult.getBits(); - boolean[] rawbits = extractBits(matrix); - boolean[] correctedBits = correctBits(rawbits); - String result = getEncodedData(correctedBits); - return new DecoderResult(null, result, null, null); - } - - // This method is used for testing the high-level encoder - public static String highLevelDecode(boolean[] correctedBits) { - return getEncodedData(correctedBits); - } - - /** - * Gets the string encoded in the aztec code bits - * - * @return the decoded string - */ - private static String getEncodedData(boolean[] correctedBits) { - int endIndex = correctedBits.length; - Table latchTable = Table.UPPER; // table most recently latched to - Table shiftTable = Table.UPPER; // table to use for the next read - StringBuilder result = new StringBuilder(20); - int index = 0; - while (index < endIndex) { - if (shiftTable == Table.BINARY) { - if (endIndex - index < 5) { - break; - } - int length = readCode(correctedBits, index, 5); - index += 5; - if (length == 0) { - if (endIndex - index < 11) { - break; - } - length = readCode(correctedBits, index, 11) + 31; - index += 11; - } - for (int charCount = 0; charCount < length; charCount++) { - if (endIndex - index < 8) { - index = endIndex; // Force outer loop to exit - break; - } - int code = readCode(correctedBits, index, 8); - result.append((char) code); - index += 8; - } - // Go back to whatever mode we had been in - shiftTable = latchTable; - } else { - int size = shiftTable == Table.DIGIT ? 4 : 5; - if (endIndex - index < size) { - break; - } - int code = readCode(correctedBits, index, size); - index += size; - String str = getCharacter(shiftTable, code); - if (str.startsWith("CTRL_")) { - // Table changes - shiftTable = getTable(str.charAt(5)); - if (str.charAt(6) == 'L') { - latchTable = shiftTable; - } - } else { - result.append(str); - // Go back to whatever mode we had been in - shiftTable = latchTable; - } - } - } - return result.toString(); - } - - /** - * gets the table corresponding to the char passed - */ - private static Table getTable(char t) { - switch (t) { - case 'L': - return Table.LOWER; - case 'P': - return Table.PUNCT; - case 'M': - return Table.MIXED; - case 'D': - return Table.DIGIT; - case 'B': - return Table.BINARY; - case 'U': - default: - return Table.UPPER; - } - } - - /** - * Gets the character (or string) corresponding to the passed code in the - * given table - * - * @param table - * the table used - * @param code - * the code of the character - */ - private static String getCharacter(Table table, int code) { - switch (table) { - case UPPER: - return UPPER_TABLE[code]; - case LOWER: - return LOWER_TABLE[code]; - case MIXED: - return MIXED_TABLE[code]; - case PUNCT: - return PUNCT_TABLE[code]; - case DIGIT: - return DIGIT_TABLE[code]; - default: - // Should not reach here. - throw new IllegalStateException("Bad table"); - } - } - - /** - *

- * Performs RS error correction on an array of bits. - *

- * - * @return the corrected array - * @throws FormatException - * if the input contains too many errors - */ - private boolean[] correctBits(boolean[] rawbits) throws FormatException { - GenericGF gf; - int codewordSize; - - if (ddata.getNbLayers() <= 2) { - codewordSize = 6; - gf = GenericGF.AZTEC_DATA_6; - } else if (ddata.getNbLayers() <= 8) { - codewordSize = 8; - gf = GenericGF.AZTEC_DATA_8; - } else if (ddata.getNbLayers() <= 22) { - codewordSize = 10; - gf = GenericGF.AZTEC_DATA_10; - } else { - codewordSize = 12; - gf = GenericGF.AZTEC_DATA_12; - } - - int numDataCodewords = ddata.getNbDatablocks(); - int numCodewords = rawbits.length / codewordSize; - if (numCodewords < numDataCodewords) { - throw FormatException.getFormatInstance(); - } - int offset = rawbits.length % codewordSize; - int numECCodewords = numCodewords - numDataCodewords; - - int[] dataWords = new int[numCodewords]; - for (int i = 0; i < numCodewords; i++, offset += codewordSize) { - dataWords[i] = readCode(rawbits, offset, codewordSize); - } - - try { - ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf); - rsDecoder.decode(dataWords, numECCodewords); - } catch (ReedSolomonException ignored) { - throw FormatException.getFormatInstance(); - } - - // Now perform the unstuffing operation. - // First, count how many bits are going to be thrown out as stuffing - int mask = (1 << codewordSize) - 1; - int stuffedBits = 0; - for (int i = 0; i < numDataCodewords; i++) { - int dataWord = dataWords[i]; - if (dataWord == 0 || dataWord == mask) { - throw FormatException.getFormatInstance(); - } else if (dataWord == 1 || dataWord == mask - 1) { - stuffedBits++; - } - } - // Now, actually unpack the bits and remove the stuffing - boolean[] correctedBits = new boolean[numDataCodewords * codewordSize - - stuffedBits]; - int index = 0; - for (int i = 0; i < numDataCodewords; i++) { - int dataWord = dataWords[i]; - if (dataWord == 1 || dataWord == mask - 1) { - // next codewordSize-1 bits are all zeros or all ones - Arrays.fill(correctedBits, index, index + codewordSize - 1, - dataWord > 1); - index += codewordSize - 1; - } else { - for (int bit = codewordSize - 1; bit >= 0; --bit) { - correctedBits[index++] = (dataWord & (1 << bit)) != 0; - } - } - } - return correctedBits; - } - - /** - * Gets the array of bits from an Aztec Code matrix - * - * @return the array of bits - */ - boolean[] extractBits(BitMatrix matrix) { - boolean compact = ddata.isCompact(); - int layers = ddata.getNbLayers(); - int baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not - // including - // alignment - // lines - int[] alignmentMap = new int[baseMatrixSize]; - boolean[] rawbits = new boolean[totalBitsInLayer(layers, compact)]; - - if (compact) { - for (int i = 0; i < alignmentMap.length; i++) { - alignmentMap[i] = i; - } - } else { - int matrixSize = baseMatrixSize + 1 + 2 - * ((baseMatrixSize / 2 - 1) / 15); - int origCenter = baseMatrixSize / 2; - int center = matrixSize / 2; - for (int i = 0; i < origCenter; i++) { - int newOffset = i + i / 15; - alignmentMap[origCenter - i - 1] = center - newOffset - 1; - alignmentMap[origCenter + i] = center + newOffset + 1; - } - } - for (int i = 0, rowOffset = 0; i < layers; i++) { - int rowSize = compact ? (layers - i) * 4 + 9 - : (layers - i) * 4 + 12; - // The top-left most point of this layer is (not - // including alignment lines) - int low = i * 2; - // The bottom-right most point of this layer is (not - // including alignment lines) - int high = baseMatrixSize - 1 - low; - // We pull bits from the two 2 x rowSize columns and two rowSize x 2 - // rows - for (int j = 0; j < rowSize; j++) { - int columnOffset = j * 2; - for (int k = 0; k < 2; k++) { - // left column - rawbits[rowOffset + columnOffset + k] = matrix.get( - alignmentMap[low + k], alignmentMap[low + j]); - // bottom row - rawbits[rowOffset + 2 * rowSize + columnOffset + k] = matrix - .get(alignmentMap[low + j], alignmentMap[high - k]); - // right column - rawbits[rowOffset + 4 * rowSize + columnOffset + k] = matrix - .get(alignmentMap[high - k], alignmentMap[high - j]); - // top row - rawbits[rowOffset + 6 * rowSize + columnOffset + k] = matrix - .get(alignmentMap[high - j], alignmentMap[low + k]); - } - } - rowOffset += rowSize * 8; - } - return rawbits; - } - - /** - * Reads a code of given length and at given index in an array of bits - */ - private static int readCode(boolean[] rawbits, int startIndex, int length) { - int res = 0; - for (int i = startIndex; i < startIndex + length; i++) { - res <<= 1; - if (rawbits[i]) { - res |= 0x01; - } - } - return res; - } - - private static int totalBitsInLayer(int layers, boolean compact) { - return ((compact ? 88 : 112) + 16 * layers) * layers; - } -} diff --git a/eclipse/src/com/google/zxing/aztec/detector/Detector.java b/eclipse/src/com/google/zxing/aztec/detector/Detector.java deleted file mode 100644 index a558f605..00000000 --- a/eclipse/src/com/google/zxing/aztec/detector/Detector.java +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright 2010 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.detector; - -import com.google.zxing.NotFoundException; -import com.google.zxing.ResultPoint; -import com.google.zxing.aztec.AztecDetectorResult; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.GridSampler; -import com.google.zxing.common.detector.MathUtils; -import com.google.zxing.common.detector.WhiteRectangleDetector; -import com.google.zxing.common.reedsolomon.GenericGF; -import com.google.zxing.common.reedsolomon.ReedSolomonDecoder; -import com.google.zxing.common.reedsolomon.ReedSolomonException; - -/** - * Encapsulates logic that can detect an Aztec Code in an image, even if the - * Aztec Code is rotated or skewed, or partially obscured. - * - * @author David Olivier - * @author Frank Yellin - */ -public final class Detector { - - private final BitMatrix image; - - private boolean compact; - private int nbLayers; - private int nbDataBlocks; - private int nbCenterLayers; - private int shift; - - public Detector(BitMatrix image) { - this.image = image; - } - - public AztecDetectorResult detect() throws NotFoundException { - return detect(false); - } - - /** - * Detects an Aztec Code in an image. - * - * @param isMirror - * if true, image is a mirror-image of original - * @return {@link AztecDetectorResult} encapsulating results of detecting an - * Aztec Code - * @throws NotFoundException - * if no Aztec Code can be found - */ - public AztecDetectorResult detect(boolean isMirror) - throws NotFoundException { - - // 1. Get the center of the aztec matrix - Point pCenter = getMatrixCenter(); - - // 2. Get the center points of the four diagonal points just outside the - // bull's eye - // [topRight, bottomRight, bottomLeft, topLeft] - ResultPoint[] bullsEyeCorners = getBullsEyeCorners(pCenter); - - if (isMirror) { - ResultPoint temp = bullsEyeCorners[0]; - bullsEyeCorners[0] = bullsEyeCorners[2]; - bullsEyeCorners[2] = temp; - } - - // 3. Get the size of the matrix and other parameters from the bull's - // eye - extractParameters(bullsEyeCorners); - - // 4. Sample the grid - BitMatrix bits = sampleGrid(image, bullsEyeCorners[shift % 4], - bullsEyeCorners[(shift + 1) % 4], - bullsEyeCorners[(shift + 2) % 4], - bullsEyeCorners[(shift + 3) % 4]); - - // 5. Get the corners of the matrix. - ResultPoint[] corners = getMatrixCornerPoints(bullsEyeCorners); - - return new AztecDetectorResult(bits, corners, compact, nbDataBlocks, - nbLayers); - } - - /** - * Extracts the number of data layers and data blocks from the layer around - * the bull's eye. - * - * @param bullsEyeCorners - * the array of bull's eye corners - * @throws NotFoundException - * in case of too many errors or invalid parameters - */ - private void extractParameters(ResultPoint[] bullsEyeCorners) - throws NotFoundException { - if (!isValid(bullsEyeCorners[0]) || !isValid(bullsEyeCorners[1]) - || !isValid(bullsEyeCorners[2]) || !isValid(bullsEyeCorners[3])) { - throw NotFoundException.getNotFoundInstance(); - } - int length = 2 * nbCenterLayers; - // Get the bits around the bull's eye - int[] sides = { - sampleLine(bullsEyeCorners[0], bullsEyeCorners[1], length), // Right - // side - sampleLine(bullsEyeCorners[1], bullsEyeCorners[2], length), // Bottom - sampleLine(bullsEyeCorners[2], bullsEyeCorners[3], length), // Left - // side - sampleLine(bullsEyeCorners[3], bullsEyeCorners[0], length) // Top - }; - - // bullsEyeCorners[shift] is the corner of the bulls'eye that has three - // orientation marks. - // sides[shift] is the row/column that goes from the corner with three - // orientation marks to the corner with two. - shift = getRotation(sides, length); - - // Flatten the parameter bits into a single 28- or 40-bit long - long parameterData = 0; - for (int i = 0; i < 4; i++) { - int side = sides[(shift + i) % 4]; - if (compact) { - // Each side of the form ..XXXXXXX. where Xs are parameter data - parameterData <<= 7; - parameterData += (side >> 1) & 0x7F; - } else { - // Each side of the form ..XXXXX.XXXXX. where Xs are parameter - // data - parameterData <<= 10; - parameterData += ((side >> 2) & (0x1f << 5)) - + ((side >> 1) & 0x1F); - } - } - - // Corrects parameter data using RS. Returns just the data portion - // without the error correction. - int correctedData = getCorrectedParameterData(parameterData, compact); - - if (compact) { - // 8 bits: 2 bits layers and 6 bits data blocks - nbLayers = (correctedData >> 6) + 1; - nbDataBlocks = (correctedData & 0x3F) + 1; - } else { - // 16 bits: 5 bits layers and 11 bits data blocks - nbLayers = (correctedData >> 11) + 1; - nbDataBlocks = (correctedData & 0x7FF) + 1; - } - } - - private static final int[] EXPECTED_CORNER_BITS = { 0xee0, // 07340 XXX .XX - // X.. ... - 0x1dc, // 00734 ... XXX .XX X.. - 0x83b, // 04073 X.. ... XXX .XX - 0x707, // 03407 .XX X.. ... XXX - }; - - private static int getRotation(int[] sides, int length) - throws NotFoundException { - // In a normal pattern, we expect to See - // ** .* D A - // * * - // - // . * - // .. .. C B - // - // Grab the 3 bits from each of the sides the form the locator pattern - // and concatenate - // into a 12-bit integer. Start with the bit at A - int cornerBits = 0; - for (int side : sides) { - // XX......X where X's are orientation marks - int t = ((side >> (length - 2)) << 1) + (side & 1); - cornerBits = (cornerBits << 3) + t; - } - // Mov the bottom bit to the top, so that the three bits of the locator - // pattern at A are - // together. cornerBits is now: - // 3 orientation bits at A || 3 orientation bits at B || ... || 3 - // orientation bits at D - cornerBits = ((cornerBits & 1) << 11) + (cornerBits >> 1); - // The result shift indicates which element of BullsEyeCorners[] goes - // into the top-left - // corner. Since the four rotation values have a Hamming distance of 8, - // we - // can easily tolerate two errors. - for (int shift = 0; shift < 4; shift++) { - if (Integer.bitCount(cornerBits ^ EXPECTED_CORNER_BITS[shift]) <= 2) { - return shift; - } - } - throw NotFoundException.getNotFoundInstance(); - } - - /** - * Corrects the parameter bits using Reed-Solomon algorithm. - * - * @param parameterData - * parameter bits - * @param compact - * true if this is a compact Aztec code - * @throws NotFoundException - * if the array contains too many errors - */ - private static int getCorrectedParameterData(long parameterData, - boolean compact) throws NotFoundException { - int numCodewords; - int numDataCodewords; - - if (compact) { - numCodewords = 7; - numDataCodewords = 2; - } else { - numCodewords = 10; - numDataCodewords = 4; - } - - int numECCodewords = numCodewords - numDataCodewords; - int[] parameterWords = new int[numCodewords]; - for (int i = numCodewords - 1; i >= 0; --i) { - parameterWords[i] = (int) parameterData & 0xF; - parameterData >>= 4; - } - try { - ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder( - GenericGF.AZTEC_PARAM); - rsDecoder.decode(parameterWords, numECCodewords); - } catch (ReedSolomonException ignored) { - throw NotFoundException.getNotFoundInstance(); - } - // Toss the error correction. Just return the data as an integer - int result = 0; - for (int i = 0; i < numDataCodewords; i++) { - result = (result << 4) + parameterWords[i]; - } - return result; - } - - /** - * Finds the corners of a bull-eye centered on the passed point. This - * returns the centers of the diagonal points just outside the bull's eye - * Returns [topRight, bottomRight, bottomLeft, topLeft] - * - * @param pCenter - * Center point - * @return The corners of the bull-eye - * @throws NotFoundException - * If no valid bull-eye can be found - */ - private ResultPoint[] getBullsEyeCorners(Point pCenter) - throws NotFoundException { - - Point pina = pCenter; - Point pinb = pCenter; - Point pinc = pCenter; - Point pind = pCenter; - - boolean color = true; - - for (nbCenterLayers = 1; nbCenterLayers < 9; nbCenterLayers++) { - Point pouta = getFirstDifferent(pina, color, 1, -1); - Point poutb = getFirstDifferent(pinb, color, 1, 1); - Point poutc = getFirstDifferent(pinc, color, -1, 1); - Point poutd = getFirstDifferent(pind, color, -1, -1); - - // d a - // - // c b - - if (nbCenterLayers > 2) { - float q = distance(poutd, pouta) * nbCenterLayers - / (distance(pind, pina) * (nbCenterLayers + 2)); - if (q < 0.75 || q > 1.25 - || !isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd)) { - break; - } - } - - pina = pouta; - pinb = poutb; - pinc = poutc; - pind = poutd; - - color = !color; - } - - if (nbCenterLayers != 5 && nbCenterLayers != 7) { - throw NotFoundException.getNotFoundInstance(); - } - - compact = nbCenterLayers == 5; - - // Expand the square by .5 pixel in each direction so that we're on the - // border - // between the white square and the black square - ResultPoint pinax = new ResultPoint(pina.getX() + 0.5f, - pina.getY() - 0.5f); - ResultPoint pinbx = new ResultPoint(pinb.getX() + 0.5f, - pinb.getY() + 0.5f); - ResultPoint pincx = new ResultPoint(pinc.getX() - 0.5f, - pinc.getY() + 0.5f); - ResultPoint pindx = new ResultPoint(pind.getX() - 0.5f, - pind.getY() - 0.5f); - - // Expand the square so that its corners are the centers of the points - // just outside the bull's eye. - return expandSquare(new ResultPoint[] { pinax, pinbx, pincx, pindx }, - 2 * nbCenterLayers - 3, 2 * nbCenterLayers); - } - - /** - * Finds a candidate center point of an Aztec code from an image - * - * @return the center point - */ - private Point getMatrixCenter() { - - ResultPoint pointA; - ResultPoint pointB; - ResultPoint pointC; - ResultPoint pointD; - - // Get a white rectangle that can be the border of the matrix in center - // bull's eye or - try { - - ResultPoint[] cornerPoints = new WhiteRectangleDetector(image) - .detect(); - pointA = cornerPoints[0]; - pointB = cornerPoints[1]; - pointC = cornerPoints[2]; - pointD = cornerPoints[3]; - - } catch (NotFoundException e) { - - // This exception can be in case the initial rectangle is white - // In that case, surely in the bull's eye, we try to expand the - // rectangle. - int cx = image.getWidth() / 2; - int cy = image.getHeight() / 2; - pointA = getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1) - .toResultPoint(); - pointB = getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1) - .toResultPoint(); - pointC = getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1) - .toResultPoint(); - pointD = getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1) - .toResultPoint(); - - } - - // Compute the center of the rectangle - int cx = MathUtils - .round((pointA.getX() + pointD.getX() + pointB.getX() + pointC - .getX()) / 4.0f); - int cy = MathUtils - .round((pointA.getY() + pointD.getY() + pointB.getY() + pointC - .getY()) / 4.0f); - - // Redetermine the white rectangle starting from previously computed - // center. - // This will ensure that we end up with a white rectangle in center - // bull's eye - // in order to compute a more accurate center. - try { - ResultPoint[] cornerPoints = new WhiteRectangleDetector(image, 15, - cx, cy).detect(); - pointA = cornerPoints[0]; - pointB = cornerPoints[1]; - pointC = cornerPoints[2]; - pointD = cornerPoints[3]; - } catch (NotFoundException e) { - // This exception can be in case the initial rectangle is white - // In that case we try to expand the rectangle. - pointA = getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1) - .toResultPoint(); - pointB = getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1) - .toResultPoint(); - pointC = getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1) - .toResultPoint(); - pointD = getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1) - .toResultPoint(); - } - - // Recompute the center of the rectangle - cx = MathUtils - .round((pointA.getX() + pointD.getX() + pointB.getX() + pointC - .getX()) / 4.0f); - cy = MathUtils - .round((pointA.getY() + pointD.getY() + pointB.getY() + pointC - .getY()) / 4.0f); - - return new Point(cx, cy); - } - - /** - * Gets the Aztec code corners from the bull's eye corners and the - * parameters. - * - * @param bullsEyeCorners - * the array of bull's eye corners - * @return the array of aztec code corners - */ - private ResultPoint[] getMatrixCornerPoints(ResultPoint[] bullsEyeCorners) { - return expandSquare(bullsEyeCorners, 2 * nbCenterLayers, getDimension()); - } - - /** - * Creates a BitMatrix by sampling the provided image. topLeft, topRight, - * bottomRight, and bottomLeft are the centers of the squares on the - * diagonal just outside the bull's eye. - */ - private BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, - ResultPoint topRight, ResultPoint bottomRight, - ResultPoint bottomLeft) throws NotFoundException { - - GridSampler sampler = GridSampler.getInstance(); - int dimension = getDimension(); - - float low = dimension / 2.0f - nbCenterLayers; - float high = dimension / 2.0f + nbCenterLayers; - - return sampler.sampleGrid(image, dimension, dimension, - low, - low, // topleft - high, - low, // topright - high, - high, // bottomright - low, - high, // bottomleft - topLeft.getX(), topLeft.getY(), topRight.getX(), - topRight.getY(), bottomRight.getX(), bottomRight.getY(), - bottomLeft.getX(), bottomLeft.getY()); - } - - /** - * Samples a line. - * - * @param p1 - * start point (inclusive) - * @param p2 - * end point (exclusive) - * @param size - * number of bits - * @return the array of bits as an int (first bit is high-order bit of - * result) - */ - private int sampleLine(ResultPoint p1, ResultPoint p2, int size) { - int result = 0; - - float d = distance(p1, p2); - float moduleSize = d / size; - float px = p1.getX(); - float py = p1.getY(); - float dx = moduleSize * (p2.getX() - p1.getX()) / d; - float dy = moduleSize * (p2.getY() - p1.getY()) / d; - for (int i = 0; i < size; i++) { - if (image.get(MathUtils.round(px + i * dx), - MathUtils.round(py + i * dy))) { - result |= 1 << (size - i - 1); - } - } - return result; - } - - /** - * @return true if the border of the rectangle passed in parameter is - * compound of white points only or black points only - */ - private boolean isWhiteOrBlackRectangle(Point p1, Point p2, Point p3, - Point p4) { - - int corr = 3; - - p1 = new Point(p1.getX() - corr, p1.getY() + corr); - p2 = new Point(p2.getX() - corr, p2.getY() - corr); - p3 = new Point(p3.getX() + corr, p3.getY() - corr); - p4 = new Point(p4.getX() + corr, p4.getY() + corr); - - int cInit = getColor(p4, p1); - - if (cInit == 0) { - return false; - } - - int c = getColor(p1, p2); - - if (c != cInit) { - return false; - } - - c = getColor(p2, p3); - - if (c != cInit) { - return false; - } - - c = getColor(p3, p4); - - return c == cInit; - - } - - /** - * Gets the color of a segment - * - * @return 1 if segment more than 90% black, -1 if segment is more than 90% - * white, 0 else - */ - private int getColor(Point p1, Point p2) { - float d = distance(p1, p2); - float dx = (p2.getX() - p1.getX()) / d; - float dy = (p2.getY() - p1.getY()) / d; - int error = 0; - - float px = p1.getX(); - float py = p1.getY(); - - boolean colorModel = image.get(p1.getX(), p1.getY()); - - for (int i = 0; i < d; i++) { - px += dx; - py += dy; - if (image.get(MathUtils.round(px), MathUtils.round(py)) != colorModel) { - error++; - } - } - - float errRatio = error / d; - - if (errRatio > 0.1f && errRatio < 0.9f) { - return 0; - } - - return (errRatio <= 0.1f) == colorModel ? 1 : -1; - } - - /** - * Gets the coordinate of the first point with a different color in the - * given direction - */ - private Point getFirstDifferent(Point init, boolean color, int dx, int dy) { - int x = init.getX() + dx; - int y = init.getY() + dy; - - while (isValid(x, y) && image.get(x, y) == color) { - x += dx; - y += dy; - } - - x -= dx; - y -= dy; - - while (isValid(x, y) && image.get(x, y) == color) { - x += dx; - } - x -= dx; - - while (isValid(x, y) && image.get(x, y) == color) { - y += dy; - } - y -= dy; - - return new Point(x, y); - } - - /** - * Expand the square represented by the corner points by pushing out equally - * in all directions - * - * @param cornerPoints - * the corners of the square, which has the bull's eye at its - * center - * @param oldSide - * the original length of the side of the square in the target - * bit matrix - * @param newSide - * the new length of the size of the square in the target bit - * matrix - * @return the corners of the expanded square - */ - private static ResultPoint[] expandSquare(ResultPoint[] cornerPoints, - float oldSide, float newSide) { - float ratio = newSide / (2 * oldSide); - float dx = cornerPoints[0].getX() - cornerPoints[2].getX(); - float dy = cornerPoints[0].getY() - cornerPoints[2].getY(); - float centerx = (cornerPoints[0].getX() + cornerPoints[2].getX()) / 2.0f; - float centery = (cornerPoints[0].getY() + cornerPoints[2].getY()) / 2.0f; - - ResultPoint result0 = new ResultPoint(centerx + ratio * dx, centery - + ratio * dy); - ResultPoint result2 = new ResultPoint(centerx - ratio * dx, centery - - ratio * dy); - - dx = cornerPoints[1].getX() - cornerPoints[3].getX(); - dy = cornerPoints[1].getY() - cornerPoints[3].getY(); - centerx = (cornerPoints[1].getX() + cornerPoints[3].getX()) / 2.0f; - centery = (cornerPoints[1].getY() + cornerPoints[3].getY()) / 2.0f; - ResultPoint result1 = new ResultPoint(centerx + ratio * dx, centery - + ratio * dy); - ResultPoint result3 = new ResultPoint(centerx - ratio * dx, centery - - ratio * dy); - - return new ResultPoint[] { result0, result1, result2, result3 }; - } - - private boolean isValid(int x, int y) { - return x >= 0 && x < image.getWidth() && y > 0 && y < image.getHeight(); - } - - private boolean isValid(ResultPoint point) { - int x = MathUtils.round(point.getX()); - int y = MathUtils.round(point.getY()); - return isValid(x, y); - } - - private static float distance(Point a, Point b) { - return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY()); - } - - private static float distance(ResultPoint a, ResultPoint b) { - return MathUtils.distance(a.getX(), a.getY(), b.getX(), b.getY()); - } - - private int getDimension() { - if (compact) { - return 4 * nbLayers + 11; - } - if (nbLayers <= 4) { - return 4 * nbLayers + 15; - } - return 4 * nbLayers + 2 * ((nbLayers - 4) / 8 + 1) + 15; - } - - static final class Point { - private final int x; - private final int y; - - ResultPoint toResultPoint() { - return new ResultPoint(getX(), getY()); - } - - Point(int x, int y) { - this.x = x; - this.y = y; - } - - int getX() { - return x; - } - - int getY() { - return y; - } - - @Override - public String toString() { - return "<" + x + ' ' + y + '>'; - } - } -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/AztecCode.java b/eclipse/src/com/google/zxing/aztec/encoder/AztecCode.java deleted file mode 100644 index bd94d759..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/AztecCode.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import com.google.zxing.common.BitMatrix; - -/** - * Aztec 2D code representation - * - * @author Rustam Abdullaev - */ -public final class AztecCode { - - private boolean compact; - private int size; - private int layers; - private int codeWords; - private BitMatrix matrix; - - /** - * @return {@code true} if compact instead of full mode - */ - public boolean isCompact() { - return compact; - } - - public void setCompact(boolean compact) { - this.compact = compact; - } - - /** - * @return size in pixels (width and height) - */ - public int getSize() { - return size; - } - - public void setSize(int size) { - this.size = size; - } - - /** - * @return number of levels - */ - public int getLayers() { - return layers; - } - - public void setLayers(int layers) { - this.layers = layers; - } - - /** - * @return number of data codewords - */ - public int getCodeWords() { - return codeWords; - } - - public void setCodeWords(int codeWords) { - this.codeWords = codeWords; - } - - /** - * @return the symbol image - */ - public BitMatrix getMatrix() { - return matrix; - } - - public void setMatrix(BitMatrix matrix) { - this.matrix = matrix; - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/BinaryShiftToken.java b/eclipse/src/com/google/zxing/aztec/encoder/BinaryShiftToken.java deleted file mode 100644 index 585ca00f..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/BinaryShiftToken.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import com.google.zxing.common.BitArray; - -final class BinaryShiftToken extends Token { - - private final short binaryShiftStart; - private final short binaryShiftByteCount; - - BinaryShiftToken(Token previous, int binaryShiftStart, - int binaryShiftByteCount) { - super(previous); - this.binaryShiftStart = (short) binaryShiftStart; - this.binaryShiftByteCount = (short) binaryShiftByteCount; - } - - @Override - public void appendTo(BitArray bitArray, byte[] text) { - for (int i = 0; i < binaryShiftByteCount; i++) { - if (i == 0 || (i == 31 && binaryShiftByteCount <= 62)) { - // We need a header before the first character, and before - // character 31 when the total byte code is <= 62 - bitArray.appendBits(31, 5); // BINARY_SHIFT - if (binaryShiftByteCount > 62) { - bitArray.appendBits(binaryShiftByteCount - 31, 16); - } else if (i == 0) { - // 1 <= binaryShiftByteCode <= 62 - bitArray.appendBits(Math.min(binaryShiftByteCount, 31), 5); - } else { - // 32 <= binaryShiftCount <= 62 and i == 31 - bitArray.appendBits(binaryShiftByteCount - 31, 5); - } - } - bitArray.appendBits(text[binaryShiftStart + i], 8); - } - } - - @Override - public String toString() { - return "<" + binaryShiftStart + "::" - + (binaryShiftStart + binaryShiftByteCount - 1) + '>'; - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/Encoder.java b/eclipse/src/com/google/zxing/aztec/encoder/Encoder.java deleted file mode 100644 index 1bb4157d..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/Encoder.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import com.google.zxing.common.BitArray; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.reedsolomon.GenericGF; -import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; - -/** - * Generates Aztec 2D barcodes. - * - * @author Rustam Abdullaev - */ -public final class Encoder { - - public static final int DEFAULT_EC_PERCENT = 33; // default minimal - // percentage of error - // check words - public static final int DEFAULT_AZTEC_LAYERS = 0; - private static final int MAX_NB_BITS = 32; - private static final int MAX_NB_BITS_COMPACT = 4; - - private static final int[] WORD_SIZE = { 4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12 }; - - private Encoder() { - } - - /** - * Encodes the given binary content as an Aztec symbol - * - * @param data - * input data string - * @return Aztec symbol matrix with metadata - */ - public static AztecCode encode(byte[] data) { - return encode(data, DEFAULT_EC_PERCENT, DEFAULT_AZTEC_LAYERS); - } - - /** - * Encodes the given binary content as an Aztec symbol - * - * @param data - * input data string - * @param minECCPercent - * minimal percentage of error check words (According to ISO/IEC - * 24778:2008, a minimum of 23% + 3 words is recommended) - * @param userSpecifiedLayers - * if non-zero, a user-specified value for the number of layers - * @return Aztec symbol matrix with metadata - */ - public static AztecCode encode(byte[] data, int minECCPercent, - int userSpecifiedLayers) { - // High-level encode - BitArray bits = new HighLevelEncoder(data).encode(); - - // stuff bits and choose symbol size - int eccBits = bits.getSize() * minECCPercent / 100 + 11; - int totalSizeBits = bits.getSize() + eccBits; - boolean compact; - int layers; - int totalBitsInLayer; - int wordSize; - BitArray stuffedBits; - if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS) { - compact = userSpecifiedLayers < 0; - layers = Math.abs(userSpecifiedLayers); - if (layers > (compact ? MAX_NB_BITS_COMPACT : MAX_NB_BITS)) { - throw new IllegalArgumentException(String.format( - "Illegal value %s for layers", userSpecifiedLayers)); - } - totalBitsInLayer = totalBitsInLayer(layers, compact); - wordSize = WORD_SIZE[layers]; - int usableBitsInLayers = totalBitsInLayer - - (totalBitsInLayer % wordSize); - stuffedBits = stuffBits(bits, wordSize); - if (stuffedBits.getSize() + eccBits > usableBitsInLayers) { - throw new IllegalArgumentException( - "Data to large for user specified layer"); - } - if (compact && stuffedBits.getSize() > wordSize * 64) { - // Compact format only allows 64 data words, though C4 can hold - // more words than that - throw new IllegalArgumentException( - "Data to large for user specified layer"); - } - } else { - wordSize = 0; - stuffedBits = null; - // We look at the possible table sizes in the order Compact1, - // Compact2, Compact3, - // Compact4, Normal4,... Normal(i) for i < 4 isn't typically used - // since Compact(i+1) - // is the same size, but has more data. - for (int i = 0;; i++) { - if (i > MAX_NB_BITS) { - throw new IllegalArgumentException( - "Data too large for an Aztec code"); - } - compact = i <= 3; - layers = compact ? i + 1 : i; - totalBitsInLayer = totalBitsInLayer(layers, compact); - if (totalSizeBits > totalBitsInLayer) { - continue; - } - // [Re]stuff the bits if this is the first opportunity, or if - // the - // wordSize has changed - if (wordSize != WORD_SIZE[layers]) { - wordSize = WORD_SIZE[layers]; - stuffedBits = stuffBits(bits, wordSize); - } - int usableBitsInLayers = totalBitsInLayer - - (totalBitsInLayer % wordSize); - if (compact && stuffedBits.getSize() > wordSize * 64) { - // Compact format only allows 64 data words, though C4 can - // hold more words than that - continue; - } - if (stuffedBits.getSize() + eccBits <= usableBitsInLayers) { - break; - } - } - } - BitArray messageBits = generateCheckWords(stuffedBits, - totalBitsInLayer, wordSize); - - // generate mode message - int messageSizeInWords = stuffedBits.getSize() / wordSize; - BitArray modeMessage = generateModeMessage(compact, layers, - messageSizeInWords); - - // allocate symbol - int baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not - // including - // alignment - // lines - int[] alignmentMap = new int[baseMatrixSize]; - int matrixSize; - if (compact) { - // no alignment marks in compact mode, alignmentMap is a no-op - matrixSize = baseMatrixSize; - for (int i = 0; i < alignmentMap.length; i++) { - alignmentMap[i] = i; - } - } else { - matrixSize = baseMatrixSize + 1 + 2 - * ((baseMatrixSize / 2 - 1) / 15); - int origCenter = baseMatrixSize / 2; - int center = matrixSize / 2; - for (int i = 0; i < origCenter; i++) { - int newOffset = i + i / 15; - alignmentMap[origCenter - i - 1] = center - newOffset - 1; - alignmentMap[origCenter + i] = center + newOffset + 1; - } - } - BitMatrix matrix = new BitMatrix(matrixSize); - - // draw data bits - for (int i = 0, rowOffset = 0; i < layers; i++) { - int rowSize = compact ? (layers - i) * 4 + 9 - : (layers - i) * 4 + 12; - for (int j = 0; j < rowSize; j++) { - int columnOffset = j * 2; - for (int k = 0; k < 2; k++) { - if (messageBits.get(rowOffset + columnOffset + k)) { - matrix.set(alignmentMap[i * 2 + k], alignmentMap[i * 2 - + j]); - } - if (messageBits.get(rowOffset + rowSize * 2 + columnOffset - + k)) { - matrix.set(alignmentMap[i * 2 + j], - alignmentMap[baseMatrixSize - 1 - i * 2 - k]); - } - if (messageBits.get(rowOffset + rowSize * 4 + columnOffset - + k)) { - matrix.set( - alignmentMap[baseMatrixSize - 1 - i * 2 - k], - alignmentMap[baseMatrixSize - 1 - i * 2 - j]); - } - if (messageBits.get(rowOffset + rowSize * 6 + columnOffset - + k)) { - matrix.set( - alignmentMap[baseMatrixSize - 1 - i * 2 - j], - alignmentMap[i * 2 + k]); - } - } - } - rowOffset += rowSize * 8; - } - - // draw mode message - drawModeMessage(matrix, compact, matrixSize, modeMessage); - - // draw alignment marks - if (compact) { - drawBullsEye(matrix, matrixSize / 2, 5); - } else { - drawBullsEye(matrix, matrixSize / 2, 7); - for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16) { - for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2) { - matrix.set(matrixSize / 2 - j, k); - matrix.set(matrixSize / 2 + j, k); - matrix.set(k, matrixSize / 2 - j); - matrix.set(k, matrixSize / 2 + j); - } - } - } - - AztecCode aztec = new AztecCode(); - aztec.setCompact(compact); - aztec.setSize(matrixSize); - aztec.setLayers(layers); - aztec.setCodeWords(messageSizeInWords); - aztec.setMatrix(matrix); - return aztec; - } - - private static void drawBullsEye(BitMatrix matrix, int center, int size) { - for (int i = 0; i < size; i += 2) { - for (int j = center - i; j <= center + i; j++) { - matrix.set(j, center - i); - matrix.set(j, center + i); - matrix.set(center - i, j); - matrix.set(center + i, j); - } - } - matrix.set(center - size, center - size); - matrix.set(center - size + 1, center - size); - matrix.set(center - size, center - size + 1); - matrix.set(center + size, center - size); - matrix.set(center + size, center - size + 1); - matrix.set(center + size, center + size - 1); - } - - static BitArray generateModeMessage(boolean compact, int layers, - int messageSizeInWords) { - BitArray modeMessage = new BitArray(); - if (compact) { - modeMessage.appendBits(layers - 1, 2); - modeMessage.appendBits(messageSizeInWords - 1, 6); - modeMessage = generateCheckWords(modeMessage, 28, 4); - } else { - modeMessage.appendBits(layers - 1, 5); - modeMessage.appendBits(messageSizeInWords - 1, 11); - modeMessage = generateCheckWords(modeMessage, 40, 4); - } - return modeMessage; - } - - private static void drawModeMessage(BitMatrix matrix, boolean compact, - int matrixSize, BitArray modeMessage) { - int center = matrixSize / 2; - if (compact) { - for (int i = 0; i < 7; i++) { - int offset = center - 3 + i; - if (modeMessage.get(i)) { - matrix.set(offset, center - 5); - } - if (modeMessage.get(i + 7)) { - matrix.set(center + 5, offset); - } - if (modeMessage.get(20 - i)) { - matrix.set(offset, center + 5); - } - if (modeMessage.get(27 - i)) { - matrix.set(center - 5, offset); - } - } - } else { - for (int i = 0; i < 10; i++) { - int offset = center - 5 + i + i / 5; - if (modeMessage.get(i)) { - matrix.set(offset, center - 7); - } - if (modeMessage.get(i + 10)) { - matrix.set(center + 7, offset); - } - if (modeMessage.get(29 - i)) { - matrix.set(offset, center + 7); - } - if (modeMessage.get(39 - i)) { - matrix.set(center - 7, offset); - } - } - } - } - - private static BitArray generateCheckWords(BitArray bitArray, - int totalBits, int wordSize) { - // bitArray is guaranteed to be a multiple of the wordSize, so no - // padding needed - int messageSizeInWords = bitArray.getSize() / wordSize; - ReedSolomonEncoder rs = new ReedSolomonEncoder(getGF(wordSize)); - int totalWords = totalBits / wordSize; - int[] messageWords = bitsToWords(bitArray, wordSize, totalWords); - rs.encode(messageWords, totalWords - messageSizeInWords); - int startPad = totalBits % wordSize; - BitArray messageBits = new BitArray(); - messageBits.appendBits(0, startPad); - for (int messageWord : messageWords) { - messageBits.appendBits(messageWord, wordSize); - } - return messageBits; - } - - private static int[] bitsToWords(BitArray stuffedBits, int wordSize, - int totalWords) { - int[] message = new int[totalWords]; - int i; - int n; - for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) { - int value = 0; - for (int j = 0; j < wordSize; j++) { - value |= stuffedBits.get(i * wordSize + j) ? (1 << wordSize - j - - 1) : 0; - } - message[i] = value; - } - return message; - } - - private static GenericGF getGF(int wordSize) { - switch (wordSize) { - case 4: - return GenericGF.AZTEC_PARAM; - case 6: - return GenericGF.AZTEC_DATA_6; - case 8: - return GenericGF.AZTEC_DATA_8; - case 10: - return GenericGF.AZTEC_DATA_10; - case 12: - return GenericGF.AZTEC_DATA_12; - default: - return null; - } - } - - static BitArray stuffBits(BitArray bits, int wordSize) { - BitArray out = new BitArray(); - - int n = bits.getSize(); - int mask = (1 << wordSize) - 2; - for (int i = 0; i < n; i += wordSize) { - int word = 0; - for (int j = 0; j < wordSize; j++) { - if (i + j >= n || bits.get(i + j)) { - word |= 1 << (wordSize - 1 - j); - } - } - if ((word & mask) == mask) { - out.appendBits(word & mask, wordSize); - i--; - } else if ((word & mask) == 0) { - out.appendBits(word | 1, wordSize); - i--; - } else { - out.appendBits(word, wordSize); - } - } - return out; - } - - private static int totalBitsInLayer(int layers, boolean compact) { - return ((compact ? 88 : 112) + 16 * layers) * layers; - } -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/HighLevelEncoder.java b/eclipse/src/com/google/zxing/aztec/encoder/HighLevelEncoder.java deleted file mode 100644 index 28de6cfd..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/HighLevelEncoder.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import com.google.zxing.common.BitArray; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** - * This produces nearly optimal encodings of text into the first-level of - * encoding used by Aztec code. - * - * It uses a dynamic algorithm. For each prefix of the string, it determines a - * set of encodings that could lead to this prefix. We repeatedly add a - * character and generate a new set of optimal encodings until we have read - * through the entire input. - * - * @author Frank Yellin - * @author Rustam Abdullaev - */ -public final class HighLevelEncoder { - - static final String[] MODE_NAMES = { "UPPER", "LOWER", "DIGIT", "MIXED", - "PUNCT" }; - - static final int MODE_UPPER = 0; // 5 bits - static final int MODE_LOWER = 1; // 5 bits - static final int MODE_DIGIT = 2; // 4 bits - static final int MODE_MIXED = 3; // 5 bits - static final int MODE_PUNCT = 4; // 5 bits - - // The Latch Table shows, for each pair of Modes, the optimal method for - // getting from one mode to another. In the worst possible case, this can - // be up to 14 bits. In the best possible case, we are already there! - // The high half-word of each entry gives the number of bits. - // The low half-word of each entry are the actual bits necessary to change - static final int[][] LATCH_TABLE = { { 0, (5 << 16) + 28, // UPPER -> LOWER - (5 << 16) + 30, // UPPER -> DIGIT - (5 << 16) + 29, // UPPER -> MIXED - (10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT - }, { (9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER - 0, (5 << 16) + 30, // LOWER -> DIGIT - (5 << 16) + 29, // LOWER -> MIXED - (10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT - }, { (4 << 16) + 14, // DIGIT -> UPPER - (9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER - 0, (9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED - (14 << 16) + (14 << 10) + (29 << 5) + 30, - // DIGIT -> UPPER -> MIXED -> PUNCT - }, { (5 << 16) + 29, // MIXED -> UPPER - (5 << 16) + 28, // MIXED -> LOWER - (10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT - 0, (5 << 16) + 30, // MIXED -> PUNCT - }, { (5 << 16) + 31, // PUNCT -> UPPER - (10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER - (10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT - (10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED - 0, }, }; - - // A reverse mapping from [mode][char] to the encoding for that character - // in that mode. An entry of 0 indicates no mapping exists. - private static final int[][] CHAR_MAP = new int[5][256]; - static { - CHAR_MAP[MODE_UPPER][' '] = 1; - for (int c = 'A'; c <= 'Z'; c++) { - CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2; - } - CHAR_MAP[MODE_LOWER][' '] = 1; - for (int c = 'a'; c <= 'z'; c++) { - CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2; - } - CHAR_MAP[MODE_DIGIT][' '] = 1; - for (int c = '0'; c <= '9'; c++) { - CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2; - } - CHAR_MAP[MODE_DIGIT][','] = 12; - CHAR_MAP[MODE_DIGIT]['.'] = 13; - int[] mixedTable = { '\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', - '\7', '\b', '\t', '\n', '\13', '\f', '\r', '\33', '\34', '\35', - '\36', '\37', '@', '\\', '^', '_', '`', '|', '~', '\177' }; - for (int i = 0; i < mixedTable.length; i++) { - CHAR_MAP[MODE_MIXED][mixedTable[i]] = i; - } - int[] punctTable = { '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', - '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', - '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}' }; - for (int i = 0; i < punctTable.length; i++) { - if (punctTable[i] > 0) { - CHAR_MAP[MODE_PUNCT][punctTable[i]] = i; - } - } - } - - // A map showing the available shift codes. (The shifts to BINARY are not - // shown - static final int[][] SHIFT_TABLE = new int[6][6]; // mode shift codes, per - // table - static { - for (int[] table : SHIFT_TABLE) { - Arrays.fill(table, -1); - } - SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0; - - SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0; - SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28; - - SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0; - - SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0; - SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15; - } - - private final byte[] text; - - public HighLevelEncoder(byte[] text) { - this.text = text; - } - - /** - * @return text represented by this encoder encoded as a {@link BitArray} - */ - public BitArray encode() { - Collection states = Collections - .singletonList(State.INITIAL_STATE); - for (int index = 0; index < text.length; index++) { - int pairCode; - int nextChar = index + 1 < text.length ? text[index + 1] : 0; - switch (text[index]) { - case '\r': - pairCode = nextChar == '\n' ? 2 : 0; - break; - case '.': - pairCode = nextChar == ' ' ? 3 : 0; - break; - case ',': - pairCode = nextChar == ' ' ? 4 : 0; - break; - case ':': - pairCode = nextChar == ' ' ? 5 : 0; - break; - default: - pairCode = 0; - } - if (pairCode > 0) { - // We have one of the four special PUNCT pairs. Treat them - // specially. - // Get a new set of states for the two new characters. - states = updateStateListForPair(states, index, pairCode); - index++; - } else { - // Get a new set of states for the new character. - states = updateStateListForChar(states, index); - } - } - // We are left with a set of states. Find the shortest one. - State minState = Collections.min(states, new Comparator() { - @Override - public int compare(State a, State b) { - return a.getBitCount() - b.getBitCount(); - } - }); - // Convert it to a bit array, and return. - return minState.toBitArray(text); - } - - // We update a set of states for a new character by updating each state - // for the new character, merging the results, and then removing the - // non-optimal states. - private Collection updateStateListForChar(Iterable states, - int index) { - Collection result = new LinkedList<>(); - for (State state : states) { - updateStateForChar(state, index, result); - } - return simplifyStates(result); - } - - // Return a set of states that represent the possible ways of updating this - // state for the next character. The resulting set of states are added to - // the "result" list. - private void updateStateForChar(State state, int index, - Collection result) { - char ch = (char) (text[index] & 0xFF); - boolean charInCurrentTable = CHAR_MAP[state.getMode()][ch] > 0; - State stateNoBinary = null; - for (int mode = 0; mode <= MODE_PUNCT; mode++) { - int charInMode = CHAR_MAP[mode][ch]; - if (charInMode > 0) { - if (stateNoBinary == null) { - // Only create stateNoBinary the first time it's required. - stateNoBinary = state.endBinaryShift(index); - } - // Try generating the character by latching to its mode - if (!charInCurrentTable || mode == state.getMode() - || mode == MODE_DIGIT) { - // If the character is in the current table, we don't want - // to latch to - // any other mode except possibly digit (which uses only 4 - // bits). Any - // other latch would be equally successful *after* this - // character, and - // so wouldn't save any bits. - State latch_state = stateNoBinary.latchAndAppend(mode, - charInMode); - result.add(latch_state); - } - // Try generating the character by switching to its mode. - if (!charInCurrentTable - && SHIFT_TABLE[state.getMode()][mode] >= 0) { - // It never makes sense to temporarily shift to another mode - // if the - // character exists in the current mode. That can never save - // bits. - State shift_state = stateNoBinary.shiftAndAppend(mode, - charInMode); - result.add(shift_state); - } - } - } - if (state.getBinaryShiftByteCount() > 0 - || CHAR_MAP[state.getMode()][ch] == 0) { - // It's never worthwhile to go into binary shift mode if you're not - // already - // in binary shift mode, and the character exists in your current - // mode. - // That can never save bits over just outputting the char in the - // current mode. - State binaryState = state.addBinaryShiftChar(index); - result.add(binaryState); - } - } - - private static Collection updateStateListForPair( - Iterable states, int index, int pairCode) { - Collection result = new LinkedList<>(); - for (State state : states) { - updateStateForPair(state, index, pairCode, result); - } - return simplifyStates(result); - } - - private static void updateStateForPair(State state, int index, - int pairCode, Collection result) { - State stateNoBinary = state.endBinaryShift(index); - // Possibility 1. Latch to MODE_PUNCT, and then append this code - result.add(stateNoBinary.latchAndAppend(MODE_PUNCT, pairCode)); - if (state.getMode() != MODE_PUNCT) { - // Possibility 2. Shift to MODE_PUNCT, and then append this code. - // Every state except MODE_PUNCT (handled above) can shift - result.add(stateNoBinary.shiftAndAppend(MODE_PUNCT, pairCode)); - } - if (pairCode == 3 || pairCode == 4) { - // both characters are in DIGITS. Sometimes better to just add two - // digits - State digit_state = stateNoBinary.latchAndAppend(MODE_DIGIT, - 16 - pairCode) // period or comma in DIGIT - .latchAndAppend(MODE_DIGIT, 1); // space in DIGIT - result.add(digit_state); - } - if (state.getBinaryShiftByteCount() > 0) { - // It only makes sense to do the characters as binary if we're - // already - // in binary mode. - State binaryState = state.addBinaryShiftChar(index) - .addBinaryShiftChar(index + 1); - result.add(binaryState); - } - } - - private static Collection simplifyStates(Iterable states) { - List result = new LinkedList<>(); - for (State newState : states) { - boolean add = true; - for (Iterator iterator = result.iterator(); iterator - .hasNext();) { - State oldState = iterator.next(); - if (oldState.isBetterThanOrEqualTo(newState)) { - add = false; - break; - } - if (newState.isBetterThanOrEqualTo(oldState)) { - iterator.remove(); - } - } - if (add) { - result.add(newState); - } - } - return result; - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/SimpleToken.java b/eclipse/src/com/google/zxing/aztec/encoder/SimpleToken.java deleted file mode 100644 index 39dbd241..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/SimpleToken.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import com.google.zxing.common.BitArray; - -final class SimpleToken extends Token { - - // For normal words, indicates value and bitCount - private final short value; - private final short bitCount; - - SimpleToken(Token previous, int value, int bitCount) { - super(previous); - this.value = (short) value; - this.bitCount = (short) bitCount; - } - - @Override - void appendTo(BitArray bitArray, byte[] text) { - bitArray.appendBits(value, bitCount); - } - - @Override - public String toString() { - int value = this.value & ((1 << bitCount) - 1); - value |= 1 << bitCount; - return '<' + Integer.toBinaryString(value | (1 << bitCount)).substring( - 1) + '>'; - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/State.java b/eclipse/src/com/google/zxing/aztec/encoder/State.java deleted file mode 100644 index d80f1760..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/State.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import java.util.Deque; -import java.util.LinkedList; - -import com.google.zxing.common.BitArray; - -/** - * State represents all information about a sequence necessary to generate the - * current output. Note that a state is immutable. - */ -final class State { - - static final State INITIAL_STATE = new State(Token.EMPTY, - HighLevelEncoder.MODE_UPPER, 0, 0); - - // The current mode of the encoding (or the mode to which we'll return if - // we're in Binary Shift mode. - private final int mode; - // The list of tokens that we output. If we are in Binary Shift mode, this - // token list does *not* yet included the token for those bytes - private final Token token; - // If non-zero, the number of most recent bytes that should be output - // in Binary Shift mode. - private final int binaryShiftByteCount; - // The total number of bits generated (including Binary Shift). - private final int bitCount; - - private State(Token token, int mode, int binaryBytes, int bitCount) { - this.token = token; - this.mode = mode; - this.binaryShiftByteCount = binaryBytes; - this.bitCount = bitCount; - // Make sure we match the token - // int binaryShiftBitCount = (binaryShiftByteCount * 8) + - // (binaryShiftByteCount == 0 ? 0 : - // binaryShiftByteCount <= 31 ? 10 : - // binaryShiftByteCount <= 62 ? 20 : 21); - // assert this.bitCount == token.getTotalBitCount() + - // binaryShiftBitCount; - } - - int getMode() { - return mode; - } - - Token getToken() { - return token; - } - - int getBinaryShiftByteCount() { - return binaryShiftByteCount; - } - - int getBitCount() { - return bitCount; - } - - // Create a new state representing this state with a latch to a (not - // necessary different) mode, and then a code. - State latchAndAppend(int mode, int value) { - // assert binaryShiftByteCount == 0; - int bitCount = this.bitCount; - Token token = this.token; - if (mode != this.mode) { - int latch = HighLevelEncoder.LATCH_TABLE[this.mode][mode]; - token = token.add(latch & 0xFFFF, latch >> 16); - bitCount += latch >> 16; - } - int latchModeBitCount = mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5; - token = token.add(value, latchModeBitCount); - return new State(token, mode, 0, bitCount + latchModeBitCount); - } - - // Create a new state representing this state, with a temporary shift - // to a different mode to output a single value. - State shiftAndAppend(int mode, int value) { - // assert binaryShiftByteCount == 0 && this.mode != mode; - Token token = this.token; - int thisModeBitCount = this.mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5; - // Shifts exist only to UPPER and PUNCT, both with tokens size 5. - token = token.add(HighLevelEncoder.SHIFT_TABLE[this.mode][mode], - thisModeBitCount); - token = token.add(value, 5); - return new State(token, this.mode, 0, this.bitCount + thisModeBitCount - + 5); - } - - // Create a new state representing this state, but an additional character - // output in Binary Shift mode. - State addBinaryShiftChar(int index) { - Token token = this.token; - int mode = this.mode; - int bitCount = this.bitCount; - if (this.mode == HighLevelEncoder.MODE_PUNCT - || this.mode == HighLevelEncoder.MODE_DIGIT) { - // assert binaryShiftByteCount == 0; - int latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER]; - token = token.add(latch & 0xFFFF, latch >> 16); - bitCount += latch >> 16; - mode = HighLevelEncoder.MODE_UPPER; - } - int deltaBitCount = (binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 - : (binaryShiftByteCount == 62) ? 9 : 8; - State result = new State(token, mode, binaryShiftByteCount + 1, - bitCount + deltaBitCount); - if (result.binaryShiftByteCount == 2047 + 31) { - // The string is as long as it's allowed to be. We should end it. - result = result.endBinaryShift(index + 1); - } - return result; - } - - // Create the state identical to this one, but we are no longer in - // Binary Shift mode. - State endBinaryShift(int index) { - if (binaryShiftByteCount == 0) { - return this; - } - Token token = this.token; - token = token.addBinaryShift(index - binaryShiftByteCount, - binaryShiftByteCount); - // assert token.getTotalBitCount() == this.bitCount; - return new State(token, mode, 0, this.bitCount); - } - - // Returns true if "this" state is better (or equal) to be in than "that" - // state under all possible circumstances. - boolean isBetterThanOrEqualTo(State other) { - int mySize = this.bitCount - + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16); - if (other.binaryShiftByteCount > 0 - && (this.binaryShiftByteCount == 0 || this.binaryShiftByteCount > other.binaryShiftByteCount)) { - mySize += 10; // Cost of entering Binary Shift mode. - } - return mySize <= other.bitCount; - } - - BitArray toBitArray(byte[] text) { - // Reverse the tokens, so that they are in the order that they should - // be output - Deque symbols = new LinkedList<>(); - for (Token token = endBinaryShift(text.length).token; token != null; token = token - .getPrevious()) { - symbols.addFirst(token); - } - BitArray bitArray = new BitArray(); - // Add each token to the result. - for (Token symbol : symbols) { - symbol.appendTo(bitArray, text); - } - // assert bitArray.getSize() == this.bitCount; - return bitArray; - } - - @Override - public String toString() { - return String.format("%s bits=%d bytes=%d", - HighLevelEncoder.MODE_NAMES[mode], bitCount, - binaryShiftByteCount); - } - -} diff --git a/eclipse/src/com/google/zxing/aztec/encoder/Token.java b/eclipse/src/com/google/zxing/aztec/encoder/Token.java deleted file mode 100644 index 38864e2f..00000000 --- a/eclipse/src/com/google/zxing/aztec/encoder/Token.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.aztec.encoder; - -import com.google.zxing.common.BitArray; - -abstract class Token { - - static final Token EMPTY = new SimpleToken(null, 0, 0); - - private final Token previous; - - Token(Token previous) { - this.previous = previous; - } - - final Token getPrevious() { - return previous; - } - - final Token add(int value, int bitCount) { - return new SimpleToken(this, value, bitCount); - } - - final Token addBinaryShift(int start, int byteCount) { - // int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= - // 62 ? 20 : 21); - return new BinaryShiftToken(this, start, byteCount); - } - - abstract void appendTo(BitArray bitArray, byte[] text); - -} diff --git a/eclipse/src/org/ripple/power/config/LSystem.java b/eclipse/src/org/ripple/power/config/LSystem.java index 5a1bc4d9..7892be58 100644 --- a/eclipse/src/org/ripple/power/config/LSystem.java +++ b/eclipse/src/org/ripple/power/config/LSystem.java @@ -443,7 +443,7 @@ public final static void callScreenRunnable(Runnable runnable) { public static final String applicationName = "RipplePower"; - public static final String applicationVersion = "Demo 0.1.2"; + public static final String applicationVersion = "Demo 0.1.3"; public static final String walletName = "ripple_wallet.dat"; diff --git a/eclipse/src/org/ripple/power/helper/HelperDialog.java b/eclipse/src/org/ripple/power/helper/HelperDialog.java index 4f233022..6ecaaf23 100644 --- a/eclipse/src/org/ripple/power/helper/HelperDialog.java +++ b/eclipse/src/org/ripple/power/helper/HelperDialog.java @@ -15,6 +15,7 @@ import org.ripple.power.config.LSystem; import org.ripple.power.config.Loop; +import org.ripple.power.config.Model; import org.ripple.power.i18n.LangConfig; import org.ripple.power.timer.LTimerContext; import org.ripple.power.txns.Updateable; @@ -241,6 +242,13 @@ public static void showDialog() { } } + public static boolean isSystemVisible() { + if (instance != null) { + return instance.isVisible(); + } + return false; + } + public synchronized static RPPushTool get() { if (instance == null) { instance = load(); @@ -404,11 +412,22 @@ private void drawLineString(Graphics g, String message, int x, int y) { } } - public static void main(String[] args) { - RPPushTool rpp = HelperDialog.get(); + public static void setHelperMessage(RPPushTool rpp, String message) { if ((rpp.obj != null) && (rpp.obj instanceof HelperDialog)) { HelperDialog dialog = (HelperDialog) rpp.obj; - dialog.setMessage("Hello, Ripple World ! Right and Justice are on our side !"); + dialog.setMessage(message); + } + } + + public static void setSystemHelperMessage(String message){ + if (LSystem.current == Model.Ripple) { + if (HelperDialog.isSystemVisible()) { + RPPushTool rpp = HelperDialog.get(); + HelperDialog + .setHelperMessage( + rpp, + message); + } } } diff --git a/eclipse/src/org/ripple/power/txns/btc/BTCLoader.java b/eclipse/src/org/ripple/power/txns/btc/BTCLoader.java index 5ae92c7d..518367f3 100644 --- a/eclipse/src/org/ripple/power/txns/btc/BTCLoader.java +++ b/eclipse/src/org/ripple/power/txns/btc/BTCLoader.java @@ -559,7 +559,7 @@ public static void shutdown() { if (propFile != null) { saveProperties(); } - log.info("JavaBitcoin shutdown completed"); + log.info("RipplePower shutdown completed"); if (LogManager.getLogManager() instanceof LogManagerOverride) ((LogManagerOverride) LogManager.getLogManager()).logShutdown(); @@ -568,7 +568,7 @@ public static void shutdown() { public static void saveProperties() { try { try (FileOutputStream out = new FileOutputStream(propFile)) { - properties.store(out, "JavaBitcoin Properties"); + properties.store(out, "RipplePower Properties"); } } catch (Exception exc) { ErrorLog.logException( @@ -578,15 +578,6 @@ public static void saveProperties() { private static void processArguments(String[] args) throws UnknownHostException { - // - // PROD indicates we should use the production network - // TEST indicates we should use the test network - // LOAD indicates we should load the block chain from the reference - // client data directory - // RETRY indicates we should retry a block that is currently held - // MIGRATE indicate we should migrate a LevelDB database to an H2 - // database - // switch (args[0].toLowerCase()) { case "bootstrap": createBootstrap = true; diff --git a/eclipse/src/org/ripple/power/ui/MainUI.java b/eclipse/src/org/ripple/power/ui/MainUI.java index afb953f1..f2869d22 100644 --- a/eclipse/src/org/ripple/power/ui/MainUI.java +++ b/eclipse/src/org/ripple/power/ui/MainUI.java @@ -333,11 +333,10 @@ public void action(Object o) { PriceMonitor.get(); if (LSystem.current == Model.Ripple) { RPPushTool rpp = HelperDialog.get(); - if ((rpp.obj != null) - && (rpp.obj instanceof HelperDialog)) { - HelperDialog dialog = (HelperDialog) rpp.obj; - dialog.setMessage("Hello, Ripple World ! Right and Justice are on our side ! This is a Java Version Ripple Desktop Client for interacting with the Ripple network ."); - } + HelperDialog + .setHelperMessage( + rpp, + "Hello, Ripple World ! Right and Justice are on our side ! This is a Java Version Ripple Desktop Client for interacting with the Ripple network ."); LSystem.sleep(LSystem.SECOND); } if (LSystem.current == Model.Ripple) { diff --git a/eclipse/src/org/ripple/power/ui/RPAccountInfoDialog.java b/eclipse/src/org/ripple/power/ui/RPAccountInfoDialog.java index 03945795..837ef53f 100644 --- a/eclipse/src/org/ripple/power/ui/RPAccountInfoDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPAccountInfoDialog.java @@ -21,6 +21,7 @@ import javax.swing.table.TableRowSorter; import org.ripple.power.config.LSystem; +import org.ripple.power.helper.HelperDialog; import org.ripple.power.helper.HelperWindow; import org.ripple.power.i18n.LangConfig; import org.ripple.power.txns.AccountFind; @@ -505,8 +506,10 @@ public void action(Object o) { } }); pack(); + + HelperDialog.setSystemHelperMessage("View the Ripple address detail data [ if your using a Ripple Labs public node , please update node to the s2.ripple.com view all history , s1.ripple.com only save one month's transactions ] . "); - }// + } private JPopupMenu _popMenu = new JPopupMenu(); diff --git a/eclipse/src/org/ripple/power/ui/RPChatServerDialog.java b/eclipse/src/org/ripple/power/ui/RPChatServerDialog.java index 0b3d4cd3..b6104d8a 100644 --- a/eclipse/src/org/ripple/power/ui/RPChatServerDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPChatServerDialog.java @@ -212,7 +212,10 @@ public void canceled() { } else if (obj == sysMessage || obj == sysMessageButton) { sendSystemMessage(); } else if (obj == myIP) { - info("Net IP:" + IP46Utils.getLocalIP()); + try { + info("Net IP:" + IP46Utils.getLocalIP()); + } catch (Exception exc) { + } } } diff --git a/eclipse/src/org/ripple/power/ui/RPExchangeDialog.java b/eclipse/src/org/ripple/power/ui/RPExchangeDialog.java index ba413844..411a0e0c 100644 --- a/eclipse/src/org/ripple/power/ui/RPExchangeDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPExchangeDialog.java @@ -26,6 +26,7 @@ import org.json.JSONObject; import org.ripple.power.config.LSystem; import org.ripple.power.config.Session; +import org.ripple.power.helper.HelperDialog; import org.ripple.power.helper.HelperWindow; import org.ripple.power.hft.TraderProcess; import org.ripple.power.i18n.LangConfig; @@ -325,6 +326,8 @@ public RPExchangeDialog(String text, JFrame parent, final WalletItem item) { this.setPreferredSize(dim); this.setSize(dim); this.initComponents(); + + HelperDialog.setSystemHelperMessage("In the Ripple network, Start online trading . "); } private void initComponents() { diff --git a/eclipse/src/org/ripple/power/ui/RPGatewayDialog.java b/eclipse/src/org/ripple/power/ui/RPGatewayDialog.java index d9d82faf..bbc41998 100644 --- a/eclipse/src/org/ripple/power/ui/RPGatewayDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPGatewayDialog.java @@ -23,6 +23,7 @@ import org.json.JSONObject; import org.ripple.power.config.LSystem; +import org.ripple.power.helper.HelperDialog; import org.ripple.power.helper.HelperWindow; import org.ripple.power.i18n.LangConfig; import org.ripple.power.txns.AccountFind; @@ -132,6 +133,8 @@ public RPGatewayDialog(String text, JFrame parent, final WalletItem item) { setPreferredSize(dim); setSize(dim); initComponents(); + + HelperDialog.setSystemHelperMessage("Set or Add and Create Ripple Gateway . "); } diff --git a/eclipse/src/org/ripple/power/ui/RPOtherServicesDialog.java b/eclipse/src/org/ripple/power/ui/RPOtherServicesDialog.java index c0e0c12f..9b4430e8 100644 --- a/eclipse/src/org/ripple/power/ui/RPOtherServicesDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPOtherServicesDialog.java @@ -30,6 +30,8 @@ public class RPOtherServicesDialog extends JPanel { private RPCButton _ripple_bitcoin_news; private RPCButton _script_editor; private RPCButton _p2pchat; + private RPCButton _btc38forRippleFox; + private RPCButton _botTraded; private static RPPushTool instance = null; @@ -63,7 +65,7 @@ private static RPPushTool load() { RPOtherServicesDialog services = new RPOtherServicesDialog(); return RPPushTool.pop(new Point( (size.width - services.getWidth()) - 10, size.getHeight()), - (int) (screenInsets.bottom + services.getHeight() + 150), + (int) (screenInsets.bottom + services.getHeight() + 70), "Other Apps/Services", services); } else { RPOtherServicesDialog services = new RPOtherServicesDialog(); @@ -75,7 +77,7 @@ private static RPPushTool load() { } public RPOtherServicesDialog() { - Dimension dim = new Dimension(246, 465); + Dimension dim = new Dimension(246, 565); setPreferredSize(dim); setSize(dim); initComponents(); @@ -94,14 +96,17 @@ private void initComponents() { _script_editor = new RPCButton(); _downloader = new RPCButton(); _p2pchat = new RPCButton(); + _btc38forRippleFox = new RPCButton(); + _botTraded = new RPCButton(); setLayout(null); + int size = 10; _rippleTrade.setText(LangConfig.get(this, "rl", "RippleTrade(RL Server)")); _rippleTrade.setFont(font); add(_rippleTrade); - _rippleTrade.setBounds(10, 10, 224, 34); + _rippleTrade.setBounds(10, size, 224, 34); _rippleTrade.addActionListener(new ActionListener() { @Override @@ -111,10 +116,58 @@ public void actionPerformed(ActionEvent e) { } }); + _botTraded.setText("BOT Trading"); + _botTraded.setFont(font); + add(_botTraded); + _botTraded.setBounds(10, size += 50, 224, 34); + _botTraded.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (LSystem.applicationMain != null) { + UIMessage.infoMessage(LSystem.applicationMain, + "The next version open function......"); + } + } + }); + + _btc2ripple_sn.setText(LangConfig.get(this, "pay", "Pay Money")); + _btc2ripple_sn.setFont(font); + add(_btc2ripple_sn); + _btc2ripple_sn.setBounds(10, size += 50, 224, 34); + _btc2ripple_sn.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + RPPayPortDialog + .showDialog("Pay Money", LSystem.applicationMain); + } + }); + + _btc2ripple_co.setText(LangConfig.get(this, "todo", "Encryp Todo")); + _btc2ripple_co.setFont(font); + add(_btc2ripple_co); + _btc2ripple_co.setBounds(10, size += 50, 224, 34); + _btc2ripple_co.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + LSystem.postThread(new Updateable() { + + @Override + public void action(Object o) { + RPTodoFrame.get(); + } + }); + + } + }); + _xrp2vpn.setText(LangConfig.get(this, "vpn", "XRP Buy VPN")); _xrp2vpn.setFont(font); add(_xrp2vpn); - _xrp2vpn.setBounds(10, 160, 224, 34); + _xrp2vpn.setBounds(10, size += 50, 224, 34); _xrp2vpn.addActionListener(new ActionListener() { @Override @@ -124,11 +177,24 @@ public void actionPerformed(ActionEvent e) { } }); + _btc38forRippleFox.setText("RippleFox Send to BTC38"); + _btc38forRippleFox.setFont(font); + add(_btc38forRippleFox); + _btc38forRippleFox.setBounds(10, size += 50, 224, 34); + _btc38forRippleFox.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + LSystem.openURL("https://ripplefox.com/cny/btc38"); + + } + }); + _ripple_bitcoin_news.setText(LangConfig.get(this, "news", "Ripple/Bitcoin News")); _ripple_bitcoin_news.setFont(font); add(_ripple_bitcoin_news); - _ripple_bitcoin_news.setBounds(10, 210, 224, 34); + _ripple_bitcoin_news.setBounds(10, size += 50, 224, 34); _ripple_bitcoin_news.addActionListener(new ActionListener() { @Override @@ -142,7 +208,7 @@ public void actionPerformed(ActionEvent e) { "Ripple Script Editor")); _script_editor.setFont(font); add(_script_editor); - _script_editor.setBounds(10, 260, 224, 34); + _script_editor.setBounds(10, size += 50, 224, 34); _script_editor.addActionListener(new ActionListener() { @Override @@ -155,7 +221,7 @@ public void actionPerformed(ActionEvent e) { "Ripple Trading Tools")); _activeRipple.setFont(font); add(_activeRipple); - _activeRipple.setBounds(10, 310, 224, 34); + _activeRipple.setBounds(10, size += 50, 224, 34); _activeRipple.addActionListener(new ActionListener() { @Override @@ -169,7 +235,7 @@ public void actionPerformed(ActionEvent e) { _downloader.setText(LangConfig.get(this, "download", "Downloader")); _downloader.setFont(font); add(_downloader); - _downloader.setBounds(10, 360, 224, 34); + _downloader.setBounds(10, size += 50, 224, 34); _downloader.addActionListener(new ActionListener() { @Override @@ -181,7 +247,7 @@ public void actionPerformed(ActionEvent e) { _p2pchat.setText(LangConfig.get(this, "chat", "Ripple P2P Chat")); _p2pchat.setFont(font); add(_p2pchat); - _p2pchat.setBounds(10, 410, 224, 34); + _p2pchat.setBounds(10, size += 50, 224, 34); _p2pchat.addActionListener(new ActionListener() { @Override @@ -191,39 +257,6 @@ public void actionPerformed(ActionEvent e) { } }); - _btc2ripple_sn.setText(LangConfig.get(this, "pay", "Pay Money")); - _btc2ripple_sn.setFont(font); - add(_btc2ripple_sn); - _btc2ripple_sn.setBounds(10, 60, 224, 34); - _btc2ripple_sn.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - RPPayPortDialog - .showDialog("Pay Money", LSystem.applicationMain); - } - }); - - _btc2ripple_co.setText(LangConfig.get(this, "todo", "Encryp Todo")); - _btc2ripple_co.setFont(font); - add(_btc2ripple_co); - _btc2ripple_co.setBounds(10, 110, 224, 34); - _btc2ripple_co.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - - LSystem.postThread(new Updateable() { - - @Override - public void action(Object o) { - RPTodoFrame.get(); - } - }); - - } - }); - setBackground(UIConfig.dialogbackground); } } diff --git a/eclipse/src/org/ripple/power/ui/RPSelectAddressDialog.java b/eclipse/src/org/ripple/power/ui/RPSelectAddressDialog.java index 9a35e1fc..44ebdb60 100644 --- a/eclipse/src/org/ripple/power/ui/RPSelectAddressDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPSelectAddressDialog.java @@ -11,6 +11,7 @@ import org.ripple.power.RippleBlobObj; import org.ripple.power.config.LSystem; +import org.ripple.power.helper.HelperDialog; import org.ripple.power.ui.graphics.LImage; import org.ripple.power.ui.view.RPToast; import org.ripple.power.ui.view.WaitDialog; @@ -115,6 +116,8 @@ public void actionPerformed(ActionEvent e) { this.setBackground(UIConfig.dialogbackground); this.tool = RPDialogTool.show(parent, text, this, -1, -1, false, LSystem.MINUTE); + + HelperDialog.setSystemHelperMessage("Ripple secret create or import , The Ripple secret is stored Your Computer . Your are the sole owner , will not be uploaded to the Ripple network ."); } } diff --git a/eclipse/src/org/ripple/power/ui/RPSelectMoneyDialog.java b/eclipse/src/org/ripple/power/ui/RPSelectMoneyDialog.java index 1798e9a5..021358c9 100644 --- a/eclipse/src/org/ripple/power/ui/RPSelectMoneyDialog.java +++ b/eclipse/src/org/ripple/power/ui/RPSelectMoneyDialog.java @@ -11,6 +11,7 @@ import javax.swing.JPanel; import org.ripple.power.config.LSystem; +import org.ripple.power.helper.HelperDialog; import org.ripple.power.i18n.LangConfig; import org.ripple.power.ui.graphics.LImage; import org.ripple.power.ui.view.RPToast; @@ -141,6 +142,8 @@ public RPSelectMoneyDialog(String text, Window parent, WalletItem item) { setBackground(UIConfig.dialogbackground); this.tool = RPDialogTool.show(parent, text, this, -1, -1, false, LSystem.MINUTE); + + HelperDialog.setSystemHelperMessage("Send XRP / IOU to the specified Ripple address or Ripple account name . "); } @Override diff --git a/eclipse/src/org/ripple/power/ui/btc/BTCTopPanel.java b/eclipse/src/org/ripple/power/ui/btc/BTCCmdPanel.java similarity index 64% rename from eclipse/src/org/ripple/power/ui/btc/BTCTopPanel.java rename to eclipse/src/org/ripple/power/ui/btc/BTCCmdPanel.java index 22126a75..ecd9829a 100644 --- a/eclipse/src/org/ripple/power/ui/btc/BTCTopPanel.java +++ b/eclipse/src/org/ripple/power/ui/btc/BTCCmdPanel.java @@ -22,7 +22,7 @@ import org.ripple.power.ui.graphics.chart.LineChartCanvas; import org.ripple.power.utils.GraphicsUtils; -public class BTCTopPanel extends JPanel { +public class BTCCmdPanel extends JPanel { /** * @@ -32,6 +32,16 @@ public class BTCTopPanel extends JPanel { private ImageIcon blocks = new ImageIcon(new LImage("icons/web.png") .scaledInstance(48, 48).getBufferedImage()); + private ImageIcon wallet = new ImageIcon(new LImage("icons/wallet.png") + .scaledInstance(48, 48).getBufferedImage()); + + private ImageIcon brain = new ImageIcon(new LImage("icons/safe.png") + .scaledInstance(48, 48).getBufferedImage()); + + private ImageIcon exchange = new ImageIcon(new LImage("icons/post.png") + .scaledInstance(48, 48).getBufferedImage()); + + private BTCPricePanel price; private LineChartCanvas btcChartCanvas; private ChartValueSerie btcChart = new ChartValueSerie(LColor.red, 1); @@ -52,8 +62,8 @@ public void start() { price.start(); } } - - public BTCTopPanel() { + + public BTCCmdPanel() { super(null); frameWidth = LSystem.applicationMain.getWidth(); frameHeight = LSystem.applicationMain.getHeight() - 200; @@ -69,7 +79,7 @@ public BTCTopPanel() { downloadBlockButton.setText("Download Blocks"); downloadBlockButton.setFont(GraphicsUtils.getFont( LangConfig.getFontName(), 1, 20)); - downloadBlockButton.setBounds(20, price.getHeight() + 50, 350, 100); + downloadBlockButton.setBounds(30, price.getHeight() + 50, 320, 100); downloadBlockButton.addActionListener(new ActionListener() { @Override @@ -89,6 +99,58 @@ public void run() { }); add(downloadBlockButton); + RPCButton walletButton = new RPCButton(wallet); + walletButton.setText("Bitcoin Wallet"); + walletButton.setFont(GraphicsUtils.getFont(LangConfig.getFontName(), 1, + 20)); + walletButton.setBounds( + downloadBlockButton.getX() + downloadBlockButton.getWidth() + + 20, price.getHeight() + 50, 320, 100); + walletButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + + BTCLoader.start(new String[] {}); + LSystem.invokeLater(new Runnable() { + + @Override + public void run() { + + BitcoinWalletDialog.showDialog("Bitcoin Wallet", + LSystem.applicationMain); + } + }); + + + } + }); + add(walletButton); + + + //Brain wallet hacker + /** + * BTC transactions for monitoring, found the wallet in line dictionaries brain immediately send to your address...... + */ + RPCButton brainButton = new RPCButton(brain); + brainButton.setText("Brain wallet hacker"); + brainButton.setFont(GraphicsUtils.getFont(LangConfig.getFontName(), 1, + 20)); + brainButton.setBounds( + walletButton.getX() + walletButton.getWidth() + + 20, price.getHeight() + 50, 320, 100); + add(brainButton); + + //Exchange BTC to XRP + RPCButton toXrpButton = new RPCButton(exchange); + toXrpButton.setText("Exchange BTC to XRP"); + toXrpButton.setFont(GraphicsUtils.getFont(LangConfig.getFontName(), 1, + 20)); + toXrpButton.setBounds( + brainButton.getX() + brainButton.getWidth() + + 20, price.getHeight() + 50, 320, 100); + add(toXrpButton); + final int width = frameWidth - price.getWidth() - 70; if (!isRunning) { @@ -121,8 +183,8 @@ public void action(Object o) { } - private LineChartCanvas addChart(LineChartCanvas canvas, int w, - int h, ChartValueSerie my) { + private LineChartCanvas addChart(LineChartCanvas canvas, int w, int h, + ChartValueSerie my) { if (canvas == null) { canvas = new LineChartCanvas(w, h); canvas.setTextVis(false, false, true, true); @@ -135,7 +197,7 @@ private LineChartCanvas addChart(LineChartCanvas canvas, int w, @Override public void run() { - BTCTopPanel.this.repaint(); + BTCCmdPanel.this.repaint(); tmp.validate(); tmp.repaint(); } @@ -145,7 +207,7 @@ public void run() { return canvas; } - private void addData(ChartValueSerie chart, int day, String cur) + private void addData(ChartValueSerie chart, int day, String cur) throws Exception { ArrayMap arrays = OtherData.getCapitalization(day, cur); if (arrays != null && arrays.size() > 0) { diff --git a/eclipse/src/org/ripple/power/ui/btc/BTCPanel.java b/eclipse/src/org/ripple/power/ui/btc/BTCPanel.java index 260d778d..e7ca0060 100644 --- a/eclipse/src/org/ripple/power/ui/btc/BTCPanel.java +++ b/eclipse/src/org/ripple/power/ui/btc/BTCPanel.java @@ -15,14 +15,14 @@ public class BTCPanel extends RoundedPanel { */ private static final long serialVersionUID = 1L; - private BTCTopPanel panel; + private BTCCmdPanel panel; public BTCPanel() { super(new BorderLayout()); setOpaque(true); setBackground(UIConfig.background); setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - panel = new BTCTopPanel(); + panel = new BTCCmdPanel(); add(panel); } diff --git a/eclipse/src/org/ripple/power/ui/btc/BTCWallet.java b/eclipse/src/org/ripple/power/ui/btc/BTCWallet.java deleted file mode 100644 index 2c7f06d4..00000000 --- a/eclipse/src/org/ripple/power/ui/btc/BTCWallet.java +++ /dev/null @@ -1,426 +0,0 @@ -package org.ripple.power.ui.btc; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.JFrame; -import javax.swing.JMenuBar; -import javax.swing.JOptionPane; -import javax.swing.WindowConstants; - -import org.ripple.power.config.LSystem; -import org.ripple.power.txns.btc.AddressFormatException; -import org.ripple.power.txns.btc.BTCLoader; -import org.ripple.power.txns.btc.BlockStoreException; -import org.ripple.power.txns.btc.BlockStoreListener; -import org.ripple.power.txns.btc.ConnectionListener; -import org.ripple.power.txns.btc.DumpedPrivateKey; -import org.ripple.power.txns.btc.ECKey; -import org.ripple.power.txns.btc.InventoryItem; -import org.ripple.power.txns.btc.InventoryMessage; -import org.ripple.power.txns.btc.Message; -import org.ripple.power.txns.btc.Peer; -import org.ripple.power.txns.btc.SendTransaction; -import org.ripple.power.txns.btc.StoredHeader; -import org.ripple.power.ui.errors.ErrorLog; -import org.ripple.power.ui.view.Menus; - -public final class BTCWallet extends JFrame implements ActionListener, ConnectionListener, BlockStoreListener { - - /** - * - */ - private static final long serialVersionUID = 1L; - - private boolean windowMinimized = false; - - private boolean synchronizingTitle = false; - - private boolean txBroadcastDone = false; - - private boolean rescanChain = false; - - private final TransactionPanel transactionPanel; - - public BTCWallet() { - super("Bitcoin Wallet"); - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - int frameX = 320; - int frameY = 10; - String propValue = BTCLoader.properties.getProperty("window.main.position"); - if (propValue != null) { - int sep = propValue.indexOf(','); - frameX = Integer.parseInt(propValue.substring(0, sep)); - frameY = Integer.parseInt(propValue.substring(sep+1)); - } - setLocation(frameX, frameY); - int frameWidth = 840; - int frameHeight = 580; - propValue = BTCLoader.properties.getProperty("window.main.size"); - if (propValue != null) { - int sep = propValue.indexOf(','); - frameWidth = Math.max(frameWidth, Integer.parseInt(propValue.substring(0, sep))); - frameHeight = Math.max(frameHeight, Integer.parseInt(propValue.substring(sep+1))); - } - setPreferredSize(new Dimension(frameWidth, frameHeight)); - JMenuBar menuBar = new JMenuBar(); - menuBar.setOpaque(true); - menuBar.setBackground(new Color(230,230,230)); - menuBar.add(new Menus(this, "File", new String[] {"Exit", "exit"})); - menuBar.add(new Menus(this, "View", new String[] {"Receive Addresses", "view receive"}, - new String[] {"Send Addresses", "view send"})); - menuBar.add(new Menus(this, "Actions", new String[] {"Send Coins", "send coins"}, - new String[] {"Sign Message", "sign message"}, - new String[] {"Verify Message", "verify message"})); - menuBar.add(new Menus(this, "Tools", new String[] {"Export Keys", "export keys"}, - new String[] {"Import Keys", "import keys"}, - new String[] {"Rescan Block Chain", "rescan"})); - menuBar.add(new Menus(this, "Help", new String[] {"About", "about"})); - - setJMenuBar(menuBar); - - transactionPanel = new TransactionPanel(this); - setContentPane(transactionPanel); - - if (BTCLoader.networkChainHeight > BTCLoader.blockStore.getChainHeight()) { - setTitle("Bitcoin Wallet - Synchronizing with network"); - synchronizingTitle = true; - } - - addWindowListener(new ApplicationWindowListener()); - - BTCLoader.networkHandler.addListener(this); - - BTCLoader.databaseHandler.addListener(this); - } - - - @Override - public void addChainBlock(StoredHeader blockHeader) { - - LSystem.invokeLater(new Runnable() { - - @Override - public void run() { - - transactionPanel.statusChanged(); - if (synchronizingTitle && !rescanChain && - BTCLoader.networkChainHeight <= BTCLoader.blockStore.getChainHeight()) { - synchronizingTitle = false; - setTitle("Bitcoin Wallet"); - } - - } - }); - } - - @Override - public void txUpdated() { - LSystem.invokeLater(new Runnable() { - - @Override - public void run() { - - transactionPanel.walletChanged(); - - - } - }); - } - - @Override - public void rescanCompleted() { - - LSystem.invokeLater(new Runnable() { - - @Override - public void run() { - - rescanChain = false; - transactionPanel.statusChanged(); - if (synchronizingTitle && BTCLoader.networkChainHeight <= BTCLoader.blockStore.getChainHeight()) { - synchronizingTitle = false; - setTitle("Bitcoin Wallet"); - } - - } - }); - } - - @Override - public void actionPerformed(ActionEvent ae) { - try { - String action = ae.getActionCommand(); - switch (action) { - case "exit": - exitProgram(); - break; - case "view receive": - ReceiveAddressDialog.showDialog(this); - transactionPanel.statusChanged(); - break; - case "view send": - SendAddressDialog.showDialog(this); - transactionPanel.statusChanged(); - break; - case "send coins": - SendDialog.showDialog(this); - break; - case "sign message": - if (BTCLoader.keys.isEmpty()) - JOptionPane.showMessageDialog(this, "There are no keys defined", "Error", - JOptionPane.ERROR_MESSAGE); - else - SignDialog.showDialog(this); - break; - case "verify message": - VerifyDialog.showDialog(this); - break; - case "export keys": - exportPrivateKeys(); - break; - case "import keys": - importPrivateKeys(); - break; - case "rescan": - rescan(); - break; - } - } catch (IOException exc) { - ErrorLog.logException("Unable to process key file", exc); - } catch (AddressFormatException exc) { - ErrorLog.logException("Key format is not valid", exc); - } catch (BlockStoreException exc) { - ErrorLog.logException("Unable to perform database operation", exc); - } catch (Exception exc) { - ErrorLog.logException("Exception while processing action event", exc); - } - } - - private void exportPrivateKeys() throws IOException { - StringBuilder keyText = new StringBuilder(256); - File keyFile = new File(LSystem.getBitcionDirectory()+LSystem.FS+"BitcoinWallet.keys"); - if (keyFile.exists()){ - keyFile.delete(); - } - try (BufferedWriter out = new BufferedWriter(new FileWriter(keyFile))) { - for (ECKey key : BTCLoader.keys) { - String address = key.toAddress().toString(); - DumpedPrivateKey dumpedKey = key.getPrivKeyEncoded(); - keyText.append("Label:"); - keyText.append(key.getLabel()); - keyText.append("\nTime:"); - keyText.append(Long.toString(key.getCreationTime())); - keyText.append("\nAddress:"); - keyText.append(address); - keyText.append("\nPrivate:"); - keyText.append(dumpedKey.toString()); - keyText.append("\n\n"); - out.write(keyText.toString()); - keyText.delete(0,keyText.length()); - } - } - JOptionPane.showMessageDialog(this, "Keys exported to BitcoinWallet.keys", "Keys Exported", - JOptionPane.INFORMATION_MESSAGE); - } - - private void importPrivateKeys() throws IOException, AddressFormatException, BlockStoreException { - File keyFile = new File(LSystem.getBitcionDirectory()+LSystem.FS+"BitcoinWallet.keys"); - if (!keyFile.exists()) { - JOptionPane.showMessageDialog(this, "BitcoinWallet.keys does not exist", - "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - try (BufferedReader in = new BufferedReader(new FileReader(keyFile))) { - String line; - String importedLabel = ""; - String importedTime = ""; - String importedAddress = ""; - String encodedPrivateKey = ""; - boolean foundKey = false; - while ((line=in.readLine()) != null) { - - line = line.trim(); - - if (line.length() == 0 || line.charAt(0) == '#'){ - continue; - } - int sep = line.indexOf(':'); - if (sep <1 || line.length() == sep+1){ - continue; - } - String keyword = line.substring(0, sep); - String value = line.substring(sep+1); - switch (keyword) { - case "Label": - importedLabel = value; - break; - case "Time": - importedTime = value; - break; - case "Address": - importedAddress = value; - break; - case "Private": - encodedPrivateKey = value; - foundKey = true; - break; - } - - if (foundKey) { - DumpedPrivateKey dumpedKey = new DumpedPrivateKey(encodedPrivateKey); - ECKey key = dumpedKey.getKey(); - if (importedAddress.equals(key.toAddress().toString())) { - key.setLabel(importedLabel); - key.setCreationTime(Long.parseLong(importedTime)); - if (!BTCLoader.keys.contains(key)) { - BTCLoader.blockStore.storeKey(key); - synchronized(BTCLoader.lock) { - boolean added = false; - for (int i=0; i 0) { - BTCLoader.keys.add(i, key); - added = true; - break; - } - } - if (!added) - BTCLoader.keys.add(key); - BTCLoader.bloomFilter.insert(key.getPubKey()); - BTCLoader.bloomFilter.insert(key.getPubKeyHash()); - } - } - } else { - JOptionPane.showMessageDialog(this, - String.format("Address %s does not match imported private key", importedAddress), - "Error", JOptionPane.ERROR_MESSAGE); - } - - foundKey = false; - importedLabel = ""; - importedTime = ""; - importedAddress = ""; - encodedPrivateKey = ""; - } - } - } - JOptionPane.showMessageDialog(this, "Keys imported from BitcoinWallet.keys", "Keys Imported", - JOptionPane.INFORMATION_MESSAGE); - } - - private void rescan() throws BlockStoreException { - - long creationTime = System.currentTimeMillis()/1000; - for (ECKey key : BTCLoader.keys){ - creationTime = Math.min(creationTime, key.getCreationTime()); - } - - synchronizingTitle = true; - rescanChain = true; - setTitle("Bitcoin Wallet - Synchronizing with network"); - - BTCLoader.blockStore.deleteTransactions(creationTime); - transactionPanel.walletChanged(); - - BTCLoader.databaseHandler.rescanChain(creationTime); - } - - private void exitProgram() throws IOException { - - if (!windowMinimized) { - Point p = getLocation(); - Dimension d = getSize(); - BTCLoader.properties.setProperty("window.main.position", p.x+","+p.y); - BTCLoader.properties.setProperty("window.main.size", d.width+","+d.height); - } - BTCLoader.shutdown(); - } - - private class ApplicationWindowListener extends WindowAdapter { - - - public ApplicationWindowListener() { - } - - @Override - public void windowIconified(WindowEvent we) { - windowMinimized = true; - } - - @Override - public void windowDeiconified(WindowEvent we) { - windowMinimized = false; - } - - @Override - public void windowClosing(WindowEvent we) { - try { - exitProgram(); - } catch (Exception exc) { - ErrorLog.logException("Exception while closing application window", exc); - } - } - } - - @Override - public void connectionStarted(Peer peer, int count) { - - if (!synchronizingTitle && BTCLoader.networkChainHeight > BTCLoader.blockStore.getChainHeight()) { - synchronizingTitle = true; - LSystem.invokeLater(new Runnable() { - - @Override - public void run() { - - setTitle("Synchronizing bitcoin network"); - - - } - }); - } - - if (!txBroadcastDone) { - txBroadcastDone = true; - try { - List sendList = BTCLoader.blockStore.getSendTxList(); - if (!sendList.isEmpty()) { - List invList = new ArrayList(sendList.size()); - for (SendTransaction sendTx : sendList) { - int depth = BTCLoader.blockStore.getTxDepth(sendTx.getTxHash()); - if (depth == 0) - invList.add(new InventoryItem(InventoryItem.INV_TX, sendTx.getTxHash())); - } - if (!invList.isEmpty()) { - Message invMsg = InventoryMessage.buildInventoryMessage(peer, invList); - BTCLoader.networkHandler.sendMessage(invMsg); - BTCLoader.info(String.format("Pending transaction inventory sent to %s", - peer.getAddress().toString())); - } - } - } catch (BlockStoreException exc) { - ErrorLog.logException("Unable to get send transaction list", exc); - } - } - - - } - - @Override - public void connectionEnded(Peer peer, int count) { - - } -} diff --git a/eclipse/src/org/ripple/power/ui/btc/BitcoinWalletDialog.java b/eclipse/src/org/ripple/power/ui/btc/BitcoinWalletDialog.java new file mode 100644 index 00000000..19b4f49a --- /dev/null +++ b/eclipse/src/org/ripple/power/ui/btc/BitcoinWalletDialog.java @@ -0,0 +1,430 @@ +package org.ripple.power.ui.btc; + +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JDialog; +import javax.swing.JMenuBar; +import javax.swing.JOptionPane; + +import org.ripple.power.config.LSystem; +import org.ripple.power.helper.HelperWindow; +import org.ripple.power.txns.btc.AddressFormatException; +import org.ripple.power.txns.btc.BTCLoader; +import org.ripple.power.txns.btc.BlockStoreException; +import org.ripple.power.txns.btc.BlockStoreListener; +import org.ripple.power.txns.btc.ConnectionListener; +import org.ripple.power.txns.btc.DumpedPrivateKey; +import org.ripple.power.txns.btc.ECKey; +import org.ripple.power.txns.btc.InventoryItem; +import org.ripple.power.txns.btc.InventoryMessage; +import org.ripple.power.txns.btc.Message; +import org.ripple.power.txns.btc.Peer; +import org.ripple.power.txns.btc.SendTransaction; +import org.ripple.power.txns.btc.StoredHeader; +import org.ripple.power.ui.UIRes; +import org.ripple.power.ui.errors.ErrorLog; +import org.ripple.power.ui.view.Menus; +import org.ripple.power.utils.SwingUtils; + +public final class BitcoinWalletDialog extends JDialog implements + ActionListener, ConnectionListener, BlockStoreListener { + + /** + * + */ + private static final long serialVersionUID = 1L; + + private boolean synchronizingTitle = false; + + private boolean txBroadcastDone = false; + + private boolean rescanChain = false; + + private final TransactionPanel transactionPanel; + + public static BitcoinWalletDialog showDialog(String text, Window parent) { + BitcoinWalletDialog dialog = new BitcoinWalletDialog(text, parent); + dialog.pack(); + dialog.setLocationRelativeTo(parent); + dialog.setVisible(true); + return dialog; + } + + public BitcoinWalletDialog(String text, Window parent) { + super(LSystem.applicationMain, text, Dialog.ModalityType.DOCUMENT_MODAL); + addWindowListener(HelperWindow.get()); + setIconImage(UIRes.getIcon()); + setResizable(false); + int frameWidth = 900; + int frameHeight = 580; + if (LSystem.applicationMain != null) { + frameWidth = LSystem.applicationMain.getWidth() - 150; + frameHeight = LSystem.applicationMain.getHeight() - 150; + } + setPreferredSize(new Dimension(frameWidth, frameHeight)); + JMenuBar menuBar = new JMenuBar(); + menuBar.setOpaque(true); + menuBar.setBackground(new Color(230, 230, 230)); + menuBar.add(new Menus(this, "File", new String[] { "Exit", "exit" })); + menuBar.add(new Menus(this, "View", new String[] { "Receive Addresses", + "view receive" }, + new String[] { "Send Addresses", "view send" })); + menuBar.add(new Menus(this, "Actions", new String[] { "Send Coins", + "send coins" }, + new String[] { "Sign Message", "sign message" }, new String[] { + "Verify Message", "verify message" })); + menuBar.add(new Menus(this, "Tools", new String[] { "Export Keys", + "export keys" }, new String[] { "Import Keys", "import keys" }, + new String[] { "Rescan Block Chain", "rescan" })); + + setJMenuBar(menuBar); + transactionPanel = new TransactionPanel(this); + setContentPane(transactionPanel); + if (BTCLoader.networkChainHeight > BTCLoader.blockStore + .getChainHeight()) { + setTitle("Bitcoin Wallet - Synchronizing with network"); + synchronizingTitle = true; + } + addWindowListener(new ApplicationWindowListener()); + BTCLoader.networkHandler.addListener(this); + BTCLoader.databaseHandler.addListener(this); + } + + @Override + public void addChainBlock(StoredHeader blockHeader) { + LSystem.invokeLater(new Runnable() { + + @Override + public void run() { + + transactionPanel.statusChanged(); + if (synchronizingTitle + && !rescanChain + && BTCLoader.networkChainHeight <= BTCLoader.blockStore + .getChainHeight()) { + synchronizingTitle = false; + setTitle("Bitcoin Wallet"); + } + + } + }); + } + + @Override + public void txUpdated() { + LSystem.invokeLater(new Runnable() { + + @Override + public void run() { + + transactionPanel.walletChanged(); + + } + }); + } + + @Override + public void rescanCompleted() { + LSystem.invokeLater(new Runnable() { + + @Override + public void run() { + + rescanChain = false; + transactionPanel.statusChanged(); + if (synchronizingTitle + && BTCLoader.networkChainHeight <= BTCLoader.blockStore + .getChainHeight()) { + synchronizingTitle = false; + setTitle("Bitcoin Wallet"); + } + + } + }); + } + + @Override + public void actionPerformed(ActionEvent ae) { + try { + String action = ae.getActionCommand(); + switch (action) { + case "exit": + exit(); + break; + case "view receive": + ReceiveAddressDialog.showDialog(this); + transactionPanel.statusChanged(); + break; + case "view send": + SendAddressDialog.showDialog(this); + transactionPanel.statusChanged(); + break; + case "send coins": + SendDialog.showDialog(this); + break; + case "sign message": + if (BTCLoader.keys.isEmpty()) { + JOptionPane.showMessageDialog(this, + "There are no keys defined", "Error", + JOptionPane.ERROR_MESSAGE); + } else { + SignDialog.showDialog(this); + } + break; + case "verify message": + VerifyDialog.showDialog(this); + break; + case "export keys": + exportDefPrivateKeys(); + break; + case "import keys": + importDefPrivateKeys(); + break; + case "rescan": + rescan(); + break; + } + } catch (IOException exc) { + ErrorLog.logException("Unable to process key file", exc); + } catch (AddressFormatException exc) { + ErrorLog.logException("Key format is not valid", exc); + } catch (BlockStoreException exc) { + ErrorLog.logException("Unable to perform database operation", exc); + } catch (Exception exc) { + ErrorLog.logException("Exception while processing action event", + exc); + } + } + + private void exportDefPrivateKeys() throws IOException { + StringBuilder keyText = new StringBuilder(256); + File keyFile = new File(LSystem.getBitcionDirectory() + LSystem.FS + + "BTCWallet.keys"); + if (keyFile.exists()) { + keyFile.delete(); + } + try (BufferedWriter out = new BufferedWriter(new FileWriter(keyFile))) { + for (ECKey key : BTCLoader.keys) { + String address = key.toAddress().toString(); + DumpedPrivateKey dumpedKey = key.getPrivKeyEncoded(); + keyText.append("Label:"); + keyText.append(key.getLabel()); + keyText.append("\nTime:"); + keyText.append(Long.toString(key.getCreationTime())); + keyText.append("\nAddress:"); + keyText.append(address); + keyText.append("\nPrivate:"); + keyText.append(dumpedKey.toString()); + keyText.append("\n\n"); + out.write(keyText.toString()); + keyText.delete(0, keyText.length()); + } + } + JOptionPane.showMessageDialog(this, "Keys exported to BTCWallet.keys", + "Keys Exported", JOptionPane.INFORMATION_MESSAGE); + } + + private void importDefPrivateKeys() throws IOException, + AddressFormatException, BlockStoreException { + File keyFile = new File(LSystem.getBitcionDirectory() + LSystem.FS + + "BTCWallet.keys"); + if (!keyFile.exists()) { + JOptionPane.showMessageDialog(this, + "BTCWallet.keys does not exist", "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + + try (BufferedReader in = new BufferedReader(new FileReader(keyFile))) { + String line; + String importedLabel = ""; + String importedTime = ""; + String importedAddress = ""; + String encodedPrivateKey = ""; + boolean foundKey = false; + while ((line = in.readLine()) != null) { + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + int sep = line.indexOf(':'); + if (sep < 1 || line.length() == sep + 1) { + continue; + } + String keyword = line.substring(0, sep); + String value = line.substring(sep + 1); + switch (keyword) { + case "Label": + importedLabel = value; + break; + case "Time": + importedTime = value; + break; + case "Address": + importedAddress = value; + break; + case "Private": + encodedPrivateKey = value; + foundKey = true; + break; + } + if (foundKey) { + DumpedPrivateKey dumpedKey = new DumpedPrivateKey( + encodedPrivateKey); + ECKey key = dumpedKey.getKey(); + if (importedAddress.equals(key.toAddress().toString())) { + key.setLabel(importedLabel); + key.setCreationTime(Long.parseLong(importedTime)); + if (!BTCLoader.keys.contains(key)) { + BTCLoader.blockStore.storeKey(key); + synchronized (BTCLoader.lock) { + boolean added = false; + for (int i = 0; i < BTCLoader.keys.size(); i++) { + if (BTCLoader.keys.get(i).getLabel() + .compareToIgnoreCase(importedLabel) > 0) { + BTCLoader.keys.add(i, key); + added = true; + break; + } + } + if (!added) + BTCLoader.keys.add(key); + BTCLoader.bloomFilter.insert(key.getPubKey()); + BTCLoader.bloomFilter.insert(key + .getPubKeyHash()); + } + } + } else { + JOptionPane + .showMessageDialog( + this, + String.format( + "Address %s does not match imported private key", + importedAddress), "Error", + JOptionPane.ERROR_MESSAGE); + } + foundKey = false; + importedLabel = ""; + importedTime = ""; + importedAddress = ""; + encodedPrivateKey = ""; + } + } + } + JOptionPane.showMessageDialog(this, + "Keys imported from BTCWallet.keys", "Keys Imported", + JOptionPane.INFORMATION_MESSAGE); + } + + private void rescan() throws BlockStoreException { + long creationTime = System.currentTimeMillis() / 1000; + for (ECKey key : BTCLoader.keys) { + creationTime = Math.min(creationTime, key.getCreationTime()); + } + synchronizingTitle = true; + rescanChain = true; + setTitle("Bitcoin Wallet - Synchronizing with network"); + BTCLoader.blockStore.deleteTransactions(creationTime); + transactionPanel.walletChanged(); + BTCLoader.databaseHandler.rescanChain(creationTime); + } + + private void exit() throws IOException { + BTCLoader.shutdown(); + SwingUtils.close(this); + } + + private class ApplicationWindowListener extends WindowAdapter { + + public ApplicationWindowListener() { + } + + @Override + public void windowIconified(WindowEvent we) { + + } + + @Override + public void windowDeiconified(WindowEvent we) { + + } + + @Override + public void windowClosing(WindowEvent we) { + try { + exit(); + } catch (Exception exc) { + ErrorLog.logException( + "Exception while closing application window", exc); + } + } + } + + @Override + public void connectionStarted(Peer peer, int count) { + if (!synchronizingTitle + && BTCLoader.networkChainHeight > BTCLoader.blockStore + .getChainHeight()) { + synchronizingTitle = true; + LSystem.invokeLater(new Runnable() { + + @Override + public void run() { + + setTitle("Bitcoin Wallet - Synchronizing with network"); + + } + }); + } + if (!txBroadcastDone) { + txBroadcastDone = true; + try { + List sendList = BTCLoader.blockStore + .getSendTxList(); + if (!sendList.isEmpty()) { + List invList = new ArrayList( + sendList.size()); + for (SendTransaction sendTx : sendList) { + int depth = BTCLoader.blockStore.getTxDepth(sendTx + .getTxHash()); + if (depth == 0) + invList.add(new InventoryItem(InventoryItem.INV_TX, + sendTx.getTxHash())); + } + if (!invList.isEmpty()) { + Message invMsg = InventoryMessage + .buildInventoryMessage(peer, invList); + BTCLoader.networkHandler.sendMessage(invMsg); + BTCLoader.info(String.format( + "Pending transaction inventory sent to %s", + peer.getAddress().toString())); + } + } + } catch (BlockStoreException exc) { + ErrorLog.logException("Unable to get send transaction list", + exc); + } + } + + } + + @Override + public void connectionEnded(Peer peer, int count) { + + } +} diff --git a/eclipse/src/org/ripple/power/ui/btc/DownloadBlocksDialog.java b/eclipse/src/org/ripple/power/ui/btc/DownloadBlocksDialog.java index 017fef77..6dac5cda 100644 --- a/eclipse/src/org/ripple/power/ui/btc/DownloadBlocksDialog.java +++ b/eclipse/src/org/ripple/power/ui/btc/DownloadBlocksDialog.java @@ -15,6 +15,7 @@ import org.ripple.power.ui.UIRes; import org.ripple.power.ui.errors.ErrorLog; import org.ripple.power.ui.view.ABaseDialog; +import org.ripple.power.utils.SwingUtils; public final class DownloadBlocksDialog extends ABaseDialog implements ActionListener { @@ -56,7 +57,7 @@ public void actionPerformed(ActionEvent ae) { String action = ae.getActionCommand(); switch (action) { case "exit": - exitProgram(); + exit(); break; } } catch (Exception exc) { @@ -65,8 +66,9 @@ public void actionPerformed(ActionEvent ae) { } } - private void exitProgram() throws IOException { + private void exit() throws IOException { BTCLoader.shutdown(); + SwingUtils.close(this); } private class ApplicationWindowListener extends WindowAdapter { @@ -91,7 +93,7 @@ public void windowDeiconified(WindowEvent we) { @Override public void windowClosing(WindowEvent we) { try { - exitProgram(); + exit(); } catch (Exception exc) { ErrorLog.logException( "Exception while closing application window", exc); diff --git a/eclipse/src/org/ripple/power/ui/btc/ReceiveAddressDialog.java b/eclipse/src/org/ripple/power/ui/btc/ReceiveAddressDialog.java index 4e123606..dbdc7b64 100644 --- a/eclipse/src/org/ripple/power/ui/btc/ReceiveAddressDialog.java +++ b/eclipse/src/org/ripple/power/ui/btc/ReceiveAddressDialog.java @@ -12,7 +12,6 @@ import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -54,7 +53,7 @@ public class ReceiveAddressDialog extends JDialog implements ActionListener { private final JScrollPane scrollPane; - public ReceiveAddressDialog(JFrame parent) { + public ReceiveAddressDialog(JDialog parent) { super(parent, "Receive Addresses", Dialog.ModalityType.DOCUMENT_MODAL); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); tableModel = new AddressTableModel(columnNames, columnClasses); @@ -82,7 +81,7 @@ public ReceiveAddressDialog(JFrame parent) { setContentPane(contentPane); } - public static void showDialog(JFrame parent) { + public static void showDialog(JDialog parent) { try { JDialog dialog = new ReceiveAddressDialog(parent); dialog.pack(); diff --git a/eclipse/src/org/ripple/power/ui/btc/SendAddressDialog.java b/eclipse/src/org/ripple/power/ui/btc/SendAddressDialog.java index 52b5a84a..410d2ba2 100644 --- a/eclipse/src/org/ripple/power/ui/btc/SendAddressDialog.java +++ b/eclipse/src/org/ripple/power/ui/btc/SendAddressDialog.java @@ -12,7 +12,6 @@ import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -49,7 +48,7 @@ public class SendAddressDialog extends JDialog implements ActionListener { private final JScrollPane scrollPane; - public SendAddressDialog(JFrame parent) { + public SendAddressDialog(JDialog parent) { super(parent, "Send Addresses", Dialog.ModalityType.DOCUMENT_MODAL); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); @@ -82,7 +81,7 @@ public SendAddressDialog(JFrame parent) { setContentPane(contentPane); } - public static void showDialog(JFrame parent) { + public static void showDialog(JDialog parent) { try { JDialog dialog = new SendAddressDialog(parent); dialog.pack(); diff --git a/eclipse/src/org/ripple/power/ui/btc/SendDialog.java b/eclipse/src/org/ripple/power/ui/btc/SendDialog.java index 2c7cf0ed..0f11f13c 100644 --- a/eclipse/src/org/ripple/power/ui/btc/SendDialog.java +++ b/eclipse/src/org/ripple/power/ui/btc/SendDialog.java @@ -13,7 +13,6 @@ import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -55,7 +54,7 @@ public class SendDialog extends JDialog implements ActionListener { private BigInteger sendFee; - public SendDialog(JFrame parent) { + public SendDialog(JDialog parent) { super(parent, "Send Coins", Dialog.ModalityType.DOCUMENT_MODAL); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); if (BTCLoader.addresses.isEmpty()) { @@ -102,7 +101,7 @@ public SendDialog(JFrame parent) { setContentPane(contentPane); } - public static void showDialog(JFrame parent) { + public static void showDialog(JDialog parent) { try { JDialog dialog = new SendDialog(parent); dialog.pack(); diff --git a/eclipse/src/org/ripple/power/ui/btc/SignDialog.java b/eclipse/src/org/ripple/power/ui/btc/SignDialog.java index 648b660e..0e8f6932 100644 --- a/eclipse/src/org/ripple/power/ui/btc/SignDialog.java +++ b/eclipse/src/org/ripple/power/ui/btc/SignDialog.java @@ -13,7 +13,6 @@ import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -43,7 +42,7 @@ public class SignDialog extends JDialog implements ActionListener { private final JTextField signatureField; - public SignDialog(JFrame parent) { + public SignDialog(JDialog parent) { super(parent, "Sign Message", Dialog.ModalityType.DOCUMENT_MODAL); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); String[] keyLabels = new String[BTCLoader.keys.size()]; @@ -86,7 +85,7 @@ public SignDialog(JFrame parent) { setContentPane(contentPane); } - public static void showDialog(JFrame parent) { + public static void showDialog(JDialog parent) { try { JDialog dialog = new SignDialog(parent); dialog.pack(); diff --git a/eclipse/src/org/ripple/power/ui/btc/TransactionPanel.java b/eclipse/src/org/ripple/power/ui/btc/TransactionPanel.java index 793fab25..acded886 100644 --- a/eclipse/src/org/ripple/power/ui/btc/TransactionPanel.java +++ b/eclipse/src/org/ripple/power/ui/btc/TransactionPanel.java @@ -16,7 +16,7 @@ import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; -import javax.swing.JFrame; +import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -27,6 +27,7 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableRowSorter; +import org.ripple.power.config.LSystem; import org.ripple.power.txns.btc.Address; import org.ripple.power.txns.btc.BTCLoader; import org.ripple.power.txns.btc.BlockStoreException; @@ -34,403 +35,434 @@ import org.ripple.power.txns.btc.ECKey; import org.ripple.power.txns.btc.ReceiveTransaction; import org.ripple.power.txns.btc.SendTransaction; +import org.ripple.power.ui.UIConfig; import org.ripple.power.ui.errors.ErrorLog; import org.ripple.power.ui.table.AddressTable; import org.ripple.power.ui.view.ButtonPane; public class TransactionPanel extends JPanel implements ActionListener { - /** + /** * */ private static final long serialVersionUID = 1L; - private static final Class[] columnClasses = { - Date.class, String.class, String.class, String.class, BigInteger.class, BigInteger.class, - String.class, String.class}; - - private static final String[] columnNames = { - "Date", "Transaction ID", "Type", "Name/Address", "Amount", "Fee", - "Location", "Status"}; - - private static final int[] columnTypes = { - AddressTable.DATE, AddressTable.ADDRESS, AddressTable.TYPE, AddressTable.ADDRESS, AddressTable.AMOUNT, - AddressTable.AMOUNT, AddressTable.STATUS, AddressTable.STATUS}; - - private final JLabel walletLabel; - - private final JLabel safeLabel; - - private final JLabel blockLabel; - - private final JScrollPane scrollPane; - - private final JTable table; - - private final TransactionTableModel tableModel; - - private BigInteger safeBalance; - - private BigInteger walletBalance; - - public TransactionPanel(JFrame parentFrame) { - super(); - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - setOpaque(true); - setBackground(Color.WHITE); - setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); - - tableModel = new TransactionTableModel(columnNames, columnClasses); - table = new AddressTable(tableModel, columnTypes); - table.setRowSorter(new TableRowSorter<>(tableModel)); - table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - String frameSize = BTCLoader.properties.getProperty("window.main.size"); - if (frameSize != null) { - int sep = frameSize.indexOf(','); - int frameHeight = Integer.parseInt(frameSize.substring(sep+1)); - table.setPreferredScrollableViewportSize(new Dimension( - table.getPreferredScrollableViewportSize().width, - (frameHeight/table.getRowHeight())*table.getRowHeight())); - } - - scrollPane = new JScrollPane(table); - - JPanel statusPane = new JPanel(); - statusPane.setLayout(new BoxLayout(statusPane, BoxLayout.X_AXIS)); - statusPane.setBackground(Color.WHITE); - walletLabel = new JLabel(getWalletText(), SwingConstants.CENTER); - statusPane.add(walletLabel); - safeLabel = new JLabel(getSafeText(), SwingConstants.CENTER); - statusPane.add(safeLabel); - blockLabel = new JLabel(getBlockText(), SwingConstants.CENTER); - statusPane.add(blockLabel); - - JPanel buttonPane = new ButtonPane(this, 15, new String[] {"Copy TxID", "copy txid"}, - new String[] {"Move to Safe", "move to safe"}, - new String[] {"Move to Wallet", "move to blockStore"}); - buttonPane.setBackground(Color.white); - - add(statusPane); - add(Box.createVerticalStrut(15)); - add(scrollPane); - add(Box.createVerticalStrut(15)); - add(buttonPane); - } - - - @Override - public void actionPerformed(ActionEvent ae) { - try { - int row = table.getSelectedRow(); - if (row < 0) { - JOptionPane.showMessageDialog(this, "No transaction selected", "Error", JOptionPane.ERROR_MESSAGE); - } else { - row = table.convertRowIndexToModel(row); - String action = ae.getActionCommand(); - switch (action) { - case "copy txid": - String address = (String)tableModel.getValueAt(row, 1); - StringSelection sel = new StringSelection(address); - Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); - cb.setContents(sel, null); - break; - case "move to safe": - if (moveToSafe(row)) { - tableModel.fireTableRowsUpdated(row, row); - walletLabel.setText(getWalletText()); - safeLabel.setText(getSafeText()); - } - break; - case "move to blockStore": - if (moveToWallet(row)) { - tableModel.fireTableRowsUpdated(row, row); - walletLabel.setText(getWalletText()); - safeLabel.setText(getSafeText()); - } - break; - } - } - } catch (BlockStoreException exc) { - ErrorLog.logException("Unable to update blockStore", exc); - } catch (Exception exc) { - ErrorLog.logException("Exception while processing action event", exc); - } - } - - public void walletChanged() { - int row = table.getSelectedRow(); - tableModel.walletChanged(); - if (row >= 0 && row < table.getRowCount()){ - table.setRowSelectionInterval(row, row); - } - walletLabel.setText(getWalletText()); - safeLabel.setText(getSafeText()); - } - - public void statusChanged() { - blockLabel.setText(getBlockText()); - tableModel.fireTableDataChanged(); - } - - private boolean moveToSafe(int row) throws BlockStoreException { - BlockTransaction tx = tableModel.getTransaction(row); - if (!(tx instanceof ReceiveTransaction)) { - JOptionPane.showMessageDialog(this, "The safe contains coins that you have received and not spent", - "Error", JOptionPane.ERROR_MESSAGE); - return false; - } - ReceiveTransaction rcvTx = (ReceiveTransaction)tx; - if (rcvTx.inSafe()) { - JOptionPane.showMessageDialog(this, "The transaction is already in the safe", - "Error", JOptionPane.ERROR_MESSAGE); - return false; - } - if (rcvTx.isSpent()) { - JOptionPane.showMessageDialog(this, "The coins have already been spent", - "Error", JOptionPane.ERROR_MESSAGE); - return false; - } - BTCLoader.blockStore.setTxSafe(rcvTx.getTxHash(), rcvTx.getTxIndex(), true); - rcvTx.setSafe(true); - safeBalance = safeBalance.add(rcvTx.getValue()); - walletBalance = walletBalance.subtract(rcvTx.getValue()); - return true; - } - - private boolean moveToWallet(int row) throws BlockStoreException { - BlockTransaction tx = tableModel.getTransaction(row); - if (!(tx instanceof ReceiveTransaction)) { - JOptionPane.showMessageDialog(this, "The safe contains coins that you have received and not spent", - "Error", JOptionPane.ERROR_MESSAGE); - return false; - } - ReceiveTransaction rcvTx = (ReceiveTransaction)tx; - if (!rcvTx.inSafe()) { - JOptionPane.showMessageDialog(this, "The transaction is not in the safe", - "Error", JOptionPane.ERROR_MESSAGE); - return false; - } - BTCLoader.blockStore.setTxSafe(rcvTx.getTxHash(), rcvTx.getTxIndex(), false); - walletBalance = walletBalance.add(rcvTx.getValue()); - safeBalance = safeBalance.subtract(rcvTx.getValue()); - rcvTx.setSafe(false); - return true; - } - - private String getWalletText() { - return String.format("

Wallet %s BTC

", BTCLoader.satoshiToString(walletBalance)); - } - - private String getSafeText() { - return String.format("

Safe %s BTC

", BTCLoader.satoshiToString(safeBalance)); - } - - private String getBlockText() { - return String.format("

Block %d

", BTCLoader.blockStore.getChainHeight()); - } - - private class TransactionTableModel extends AbstractTableModel { - - /** + private static final Class[] columnClasses = { Date.class, String.class, + String.class, String.class, BigInteger.class, BigInteger.class, + String.class, String.class }; + + private static final String[] columnNames = { "Date", "Transaction ID", + "Type", "Name/Address", "Amount", "Fee", "Location", "Status" }; + + private static final int[] columnTypes = { AddressTable.DATE, + AddressTable.ADDRESS, AddressTable.TYPE, AddressTable.ADDRESS, + AddressTable.AMOUNT, AddressTable.AMOUNT, AddressTable.STATUS, + AddressTable.STATUS }; + + private final JLabel walletLabel; + + private final JLabel safeLabel; + + private final JLabel blockLabel; + + private final JScrollPane scrollPane; + + private final JTable table; + + private final TransactionTableModel tableModel; + + private BigInteger safeBalance; + + private BigInteger walletBalance; + + public TransactionPanel(JDialog parentFrame) { + super(); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setOpaque(true); + setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + + tableModel = new TransactionTableModel(columnNames, columnClasses); + table = new AddressTable(tableModel, columnTypes); + table.setRowSorter(new TableRowSorter<>(tableModel)); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + int frameHeight = 1200; + if (LSystem.applicationMain != null) { + frameHeight = LSystem.applicationMain.getHeight() + 50; + } + table.setPreferredScrollableViewportSize(new Dimension(table + .getPreferredScrollableViewportSize().width, + (frameHeight / table.getRowHeight()) * table.getRowHeight())); + + scrollPane = new JScrollPane(table); + + JPanel statusPane = new JPanel(); + statusPane.setLayout(new BoxLayout(statusPane, BoxLayout.X_AXIS)); + statusPane.setBackground(Color.WHITE); + walletLabel = new JLabel(getWalletText(), SwingConstants.CENTER); + statusPane.add(walletLabel); + safeLabel = new JLabel(getSafeText(), SwingConstants.CENTER); + statusPane.add(safeLabel); + blockLabel = new JLabel(getBlockText(), SwingConstants.CENTER); + statusPane.add(blockLabel); + + ButtonPane buttonPane = new ButtonPane(this, 20,new String[] { + "New Address", "new address" }, new String[] { + "Copy TxID", "copy txid" }, new String[] { "Move to Safe", + "move to safe" }, new String[] { "Move to Wallet", + "move to blockStore" }); + + buttonPane.setBackground(UIConfig.dialogbackground); + + add(statusPane); + add(Box.createVerticalStrut(5)); + add(scrollPane); + add(Box.createVerticalStrut(5)); + add(buttonPane); + + setBackground(UIConfig.dialogbackground); + } + + @Override + public void actionPerformed(ActionEvent ae) { + try { + int row = table.getSelectedRow(); + if (row < 0) { + JOptionPane.showMessageDialog(this, "No transaction selected", + "Error", JOptionPane.ERROR_MESSAGE); + } else { + row = table.convertRowIndexToModel(row); + String action = ae.getActionCommand(); + switch (action) { + case "new address": + + break; + case "copy txid": + String address = (String) tableModel.getValueAt(row, 1); + StringSelection sel = new StringSelection(address); + Clipboard cb = Toolkit.getDefaultToolkit() + .getSystemClipboard(); + cb.setContents(sel, null); + break; + case "move to safe": + if (moveToSafe(row)) { + tableModel.fireTableRowsUpdated(row, row); + walletLabel.setText(getWalletText()); + safeLabel.setText(getSafeText()); + } + break; + case "move to blockStore": + if (moveToWallet(row)) { + tableModel.fireTableRowsUpdated(row, row); + walletLabel.setText(getWalletText()); + safeLabel.setText(getSafeText()); + } + break; + } + } + } catch (BlockStoreException exc) { + ErrorLog.logException("Unable to update blockStore", exc); + } catch (Exception exc) { + ErrorLog.logException("Exception while processing action event", + exc); + } + } + + public void walletChanged() { + int row = table.getSelectedRow(); + tableModel.walletChanged(); + if (row >= 0 && row < table.getRowCount()) { + table.setRowSelectionInterval(row, row); + } + walletLabel.setText(getWalletText()); + safeLabel.setText(getSafeText()); + } + + public void statusChanged() { + blockLabel.setText(getBlockText()); + tableModel.fireTableDataChanged(); + } + + private boolean moveToSafe(int row) throws BlockStoreException { + BlockTransaction tx = tableModel.getTransaction(row); + if (!(tx instanceof ReceiveTransaction)) { + JOptionPane + .showMessageDialog( + this, + "The safe contains coins that you have received and not spent", + "Error", JOptionPane.ERROR_MESSAGE); + return false; + } + ReceiveTransaction rcvTx = (ReceiveTransaction) tx; + if (rcvTx.inSafe()) { + JOptionPane.showMessageDialog(this, + "The transaction is already in the safe", "Error", + JOptionPane.ERROR_MESSAGE); + return false; + } + if (rcvTx.isSpent()) { + JOptionPane.showMessageDialog(this, + "The coins have already been spent", "Error", + JOptionPane.ERROR_MESSAGE); + return false; + } + BTCLoader.blockStore.setTxSafe(rcvTx.getTxHash(), rcvTx.getTxIndex(), + true); + rcvTx.setSafe(true); + safeBalance = safeBalance.add(rcvTx.getValue()); + walletBalance = walletBalance.subtract(rcvTx.getValue()); + return true; + } + + private boolean moveToWallet(int row) throws BlockStoreException { + BlockTransaction tx = tableModel.getTransaction(row); + if (!(tx instanceof ReceiveTransaction)) { + JOptionPane + .showMessageDialog( + this, + "The safe contains coins that you have received and not spent", + "Error", JOptionPane.ERROR_MESSAGE); + return false; + } + ReceiveTransaction rcvTx = (ReceiveTransaction) tx; + if (!rcvTx.inSafe()) { + JOptionPane.showMessageDialog(this, + "The transaction is not in the safe", "Error", + JOptionPane.ERROR_MESSAGE); + return false; + } + BTCLoader.blockStore.setTxSafe(rcvTx.getTxHash(), rcvTx.getTxIndex(), + false); + walletBalance = walletBalance.add(rcvTx.getValue()); + safeBalance = safeBalance.subtract(rcvTx.getValue()); + rcvTx.setSafe(false); + return true; + } + + private String getWalletText() { + return String.format("

Wallet %s BTC

", + BTCLoader.satoshiToString(walletBalance)); + } + + private String getSafeText() { + return String.format("

Safe %s BTC

", + BTCLoader.satoshiToString(safeBalance)); + } + + private String getBlockText() { + return String.format("

Block %d

", + BTCLoader.blockStore.getChainHeight()); + } + + private class TransactionTableModel extends AbstractTableModel { + + /** * */ private static final long serialVersionUID = 1L; - private String[] columnNames; - - private Class[] columnClasses; - - private final List txList = new LinkedList<>(); - - public TransactionTableModel(String[] columnNames, Class[] columnClasses) { - super(); - if (columnNames.length != columnClasses.length) - throw new IllegalArgumentException("Number of names not same as number of classes"); - this.columnNames = columnNames; - this.columnClasses = columnClasses; - buildTxList(); - } - - private void buildTxList() { - txList.clear(); - walletBalance = BigInteger.ZERO; - safeBalance = BigInteger.ZERO; - try { - List sendList = BTCLoader.blockStore.getSendTxList(); - for (SendTransaction sendTx : sendList) { - long txTime = sendTx.getTxTime(); - walletBalance = walletBalance.subtract(sendTx.getValue()).subtract(sendTx.getFee()); - boolean added = false; - for (int i=0; i rcvList = BTCLoader.blockStore.getReceiveTxList(); - for (ReceiveTransaction rcvTx : rcvList) { - if (rcvTx.isChange()) - continue; - if (rcvTx.inSafe()) - safeBalance = safeBalance.add(rcvTx.getValue()); - else - walletBalance = walletBalance.add(rcvTx.getValue()); - long txTime = rcvTx.getTxTime(); - boolean added = false; - for (int i=0; i getColumnClass(int column) { - return columnClasses[column]; - } - - @Override - public String getColumnName(int column) { - return columnNames[column]; - } - - @Override - public int getRowCount() { - return txList.size(); - } - - @Override - public Object getValueAt(int row, int column) { - if (row >= txList.size()){ - throw new IndexOutOfBoundsException("Table row "+row+" is not valid"); - } - Object value; - BlockTransaction tx = txList.get(row); - switch (column) { - case 0: - value = new Date(tx.getTxTime()*1000); - break; - case 1: - value = tx.getTxHash().toString(); - break; - case 2: - if (tx instanceof ReceiveTransaction){ - value = "Received with"; - } - else{ - value = "Sent to"; - } - break; - case 3: - value = null; - Address addr = tx.getAddress(); - if (tx instanceof ReceiveTransaction) { - for (ECKey chkKey : BTCLoader.keys) { - if (Arrays.equals(chkKey.getPubKeyHash(), addr.getHash())) { - if (chkKey.getLabel().length() > 0){ - value = chkKey.getLabel(); - } - break; - } - } - } else { - for (Address chkAddr : BTCLoader.addresses) { - if (Arrays.equals(chkAddr.getHash(), addr.getHash())) { - if (chkAddr.getLabel().length() > 0){ - value = chkAddr.getLabel(); - } - break; - } - } - } - if (value == null){ - value = addr.toString(); - } - break; - case 4: - value = tx.getValue(); - break; - case 5: - if (tx instanceof SendTransaction){ - value = ((SendTransaction)tx).getFee(); - } - else{ - value = null; - } - break; - case 6: - if (tx instanceof ReceiveTransaction) { - if (((ReceiveTransaction)tx).inSafe()){ - value = "Safe"; - } - else{ - value = "Wallet"; - } - } else { - value = ""; - } - break; - case 7: // Status - try { - if (tx instanceof ReceiveTransaction && ((ReceiveTransaction)tx).isSpent()) { - value = "Spent"; - } else { - int depth = BTCLoader.blockStore.getTxDepth(tx.getTxHash()); - if ((tx instanceof ReceiveTransaction) && ((ReceiveTransaction)tx).isCoinBase()) { - if (depth == 0){ - value = "Pending"; - } - else if (depth < BTCLoader.COINBASE_MATURITY){ - value = "Immature"; - } - else{ - value = "Mature"; - } - } else if (depth == 0) { - value = "Pending"; - } else if (depth < BTCLoader.TRANSACTION_CONFIRMED) { - value = "Building"; - } else { - value = "Confirmed"; - } - } - } catch (BlockStoreException exc) { - ErrorLog.logException("Unable to get transaction depth", exc); - value = "Unknown"; - } - break; - default: - throw new IndexOutOfBoundsException("Table column "+column+" is not valid"); - } - return value; - } - - public void walletChanged() { - buildTxList(); - fireTableDataChanged(); - } - - public BlockTransaction getTransaction(int row) { - return txList.get(row); - } - - } + private String[] columnNames; + + private Class[] columnClasses; + + private final List txList = new LinkedList<>(); + + public TransactionTableModel(String[] columnNames, + Class[] columnClasses) { + super(); + if (columnNames.length != columnClasses.length) + throw new IllegalArgumentException( + "Number of names not same as number of classes"); + this.columnNames = columnNames; + this.columnClasses = columnClasses; + buildTxList(); + } + + private void buildTxList() { + txList.clear(); + walletBalance = BigInteger.ZERO; + safeBalance = BigInteger.ZERO; + try { + List sendList = BTCLoader.blockStore + .getSendTxList(); + for (SendTransaction sendTx : sendList) { + long txTime = sendTx.getTxTime(); + walletBalance = walletBalance.subtract(sendTx.getValue()) + .subtract(sendTx.getFee()); + boolean added = false; + for (int i = 0; i < txList.size(); i++) { + if (txList.get(i).getTxTime() <= txTime) { + txList.add(i, sendTx); + added = true; + break; + } + } + if (!added) + txList.add(sendTx); + } + List rcvList = BTCLoader.blockStore + .getReceiveTxList(); + for (ReceiveTransaction rcvTx : rcvList) { + if (rcvTx.isChange()) + continue; + if (rcvTx.inSafe()) + safeBalance = safeBalance.add(rcvTx.getValue()); + else + walletBalance = walletBalance.add(rcvTx.getValue()); + long txTime = rcvTx.getTxTime(); + boolean added = false; + for (int i = 0; i < txList.size(); i++) { + if (txList.get(i).getTxTime() <= txTime) { + txList.add(i, rcvTx); + added = true; + break; + } + } + if (!added) { + txList.add(rcvTx); + } + } + } catch (BlockStoreException exc) { + ErrorLog.logException("Unable to build transaction list", exc); + } + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Class getColumnClass(int column) { + return columnClasses[column]; + } + + @Override + public String getColumnName(int column) { + return columnNames[column]; + } + + @Override + public int getRowCount() { + return txList.size(); + } + + @Override + public Object getValueAt(int row, int column) { + if (row >= txList.size()) { + throw new IndexOutOfBoundsException("Table row " + row + + " is not valid"); + } + Object value; + BlockTransaction tx = txList.get(row); + switch (column) { + case 0: + value = new Date(tx.getTxTime() * 1000); + break; + case 1: + value = tx.getTxHash().toString(); + break; + case 2: + if (tx instanceof ReceiveTransaction) { + value = "Received with"; + } else { + value = "Sent to"; + } + break; + case 3: + value = null; + Address addr = tx.getAddress(); + if (tx instanceof ReceiveTransaction) { + for (ECKey chkKey : BTCLoader.keys) { + if (Arrays.equals(chkKey.getPubKeyHash(), + addr.getHash())) { + if (chkKey.getLabel().length() > 0) { + value = chkKey.getLabel(); + } + break; + } + } + } else { + for (Address chkAddr : BTCLoader.addresses) { + if (Arrays.equals(chkAddr.getHash(), addr.getHash())) { + if (chkAddr.getLabel().length() > 0) { + value = chkAddr.getLabel(); + } + break; + } + } + } + if (value == null) { + value = addr.toString(); + } + break; + case 4: + value = tx.getValue(); + break; + case 5: + if (tx instanceof SendTransaction) { + value = ((SendTransaction) tx).getFee(); + } else { + value = null; + } + break; + case 6: + if (tx instanceof ReceiveTransaction) { + if (((ReceiveTransaction) tx).inSafe()) { + value = "Safe"; + } else { + value = "Wallet"; + } + } else { + value = ""; + } + break; + case 7: // Status + try { + if (tx instanceof ReceiveTransaction + && ((ReceiveTransaction) tx).isSpent()) { + value = "Spent"; + } else { + int depth = BTCLoader.blockStore.getTxDepth(tx + .getTxHash()); + if ((tx instanceof ReceiveTransaction) + && ((ReceiveTransaction) tx).isCoinBase()) { + if (depth == 0) { + value = "Pending"; + } else if (depth < BTCLoader.COINBASE_MATURITY) { + value = "Immature"; + } else { + value = "Mature"; + } + } else if (depth == 0) { + value = "Pending"; + } else if (depth < BTCLoader.TRANSACTION_CONFIRMED) { + value = "Building"; + } else { + value = "Confirmed"; + } + } + } catch (BlockStoreException exc) { + ErrorLog.logException("Unable to get transaction depth", + exc); + value = "Unknown"; + } + break; + default: + throw new IndexOutOfBoundsException("Table column " + column + + " is not valid"); + } + return value; + } + + public void walletChanged() { + buildTxList(); + fireTableDataChanged(); + } + + public BlockTransaction getTransaction(int row) { + return txList.get(row); + } + + } } diff --git a/eclipse/src/org/ripple/power/ui/btc/VerifyDialog.java b/eclipse/src/org/ripple/power/ui/btc/VerifyDialog.java index 339e9724..a499376b 100644 --- a/eclipse/src/org/ripple/power/ui/btc/VerifyDialog.java +++ b/eclipse/src/org/ripple/power/ui/btc/VerifyDialog.java @@ -8,7 +8,6 @@ import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JDialog; -import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -37,7 +36,7 @@ public class VerifyDialog extends JDialog implements ActionListener { private final JTextField signatureField; - public VerifyDialog(JFrame parent) { + public VerifyDialog(JDialog parent) { super(parent, "Verify Message", Dialog.ModalityType.DOCUMENT_MODAL); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); addressField = new JTextField("", 34); @@ -72,7 +71,7 @@ public VerifyDialog(JFrame parent) { setContentPane(contentPane); } - public static void showDialog(JFrame parent) { + public static void showDialog(JDialog parent) { try { JDialog dialog = new VerifyDialog(parent); dialog.pack(); diff --git a/eclipse/src/org/ripple/power/utils/IP46Utils.java b/eclipse/src/org/ripple/power/utils/IP46Utils.java index a7ab4451..c269f9e9 100644 --- a/eclipse/src/org/ripple/power/utils/IP46Utils.java +++ b/eclipse/src/org/ripple/power/utils/IP46Utils.java @@ -1,5 +1,6 @@ package org.ripple.power.utils; +import java.io.IOException; import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; @@ -14,6 +15,7 @@ import java.util.regex.PatternSyntaxException; import org.ripple.power.config.LSystem; +import org.ripple.power.utils.HttpRequest.HttpRequestException; public class IP46Utils { @@ -272,7 +274,7 @@ public static InetAddress randomInetAddress() { : randomInet6Address(); } - public static String getLocalIP() { + public static String getLocalIP() throws HttpRequestException, IOException { String result = ""; String html = ""; html = getIpCheckReps("http://1111.ip138.com/ic.asp"); @@ -300,16 +302,12 @@ static String parseIpAddr(String html, int which) { return ip.trim(); } - public static String getIpCheckReps(String url) { + public static String getIpCheckReps(String url) throws HttpRequestException, IOException { HttpRequest request = HttpRequest.get(url); String result = ""; - try { if (request.ok()) { result = request.body(); } - } catch (Exception e) { - e.printStackTrace(); - } return result; } diff --git a/eclipse/src/res/config/gateways.json b/eclipse/src/res/config/gateways.json index e938aad8..fce504f9 100644 --- a/eclipse/src/res/config/gateways.json +++ b/eclipse/src/res/config/gateways.json @@ -338,5 +338,13 @@ }], "hotwallets": [], "domain": "" + },{ + "name": "Senderas", + "accounts": [{ + "address": "rJypGvB8H2JBj1QVYofUTU8kFtWLspNWqs", + "currencies": ["GBP"] + }], + "hotwallets": [], + "domain": "www.senderas.com" } ] \ No newline at end of file