All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.rabanti.nanoxlsx4j.styles.NumberFormat Maven / Gradle / Ivy

Go to download

NanoXLSX4j is a small Java library to create and read XLSX files (Microsoft Excel 2007 or newer) in an easy and native way. The library is originated form PicoXLSX4j and has basic support of reading spreadsheets

There is a newer version: 2.5.1
Show newest version
/*
 * NanoXLSX4j is a small Java library to write and read XLSX (Microsoft Excel 2007 or newer) files in an easy and native way
 * Copyright Raphael Stoeckli © 2024
 * This library is licensed under the MIT License.
 * You find a copy of the license in project folder or on: http://opensource.org/licenses/MIT
 */
package ch.rabanti.nanoxlsx4j.styles;

import ch.rabanti.nanoxlsx4j.exceptions.FormatException;
import ch.rabanti.nanoxlsx4j.exceptions.StyleException;

import java.util.Arrays;
import java.util.Optional;

/**
 * Class representing a NumberFormat entry. The NumberFormat entry is used to define cell formats like currency or date
 *
 * @author Raphael Stoeckli
 */
public class NumberFormat extends AbstractStyle {
    // ### C O N S T A N T S ###
    /**
     * Start ID for custom number formats as constant (value 164)
     */
    public static final int CUSTOMFORMAT_START_NUMBER = 164;

    /**
     * Default format number as constant
     */
    public static final FormatNumber DEFAULT_NUMBER = FormatNumber.none;

    // ### E N U M S ###

    /**
     * Enum for the defined number formats
     */
    public enum FormatNumber {
        /**
         * No format / Default
         */
        none(0),
        /**
         * Format: 0
         */
        format_1(1),
        /**
         * Format: 0.00
         */
        format_2(2),
        /**
         * Format: #,##0
         */
        format_3(3),
        /**
         * Format: #,##0.00
         */
        format_4(4),
        /**
         * Format: $#,##0_);($#,##0)
         */
        format_5(5),
        /**
         * Format: $#,##0_);[Red]($#,##0)
         */
        format_6(6),
        /**
         * Format: $#,##0.00_);($#,##0.00)
         */
        format_7(7),
        /**
         * Format: $#,##0.00_);[Red]($#,##0.00)
         */
        format_8(8),
        /**
         * Format: 0%
         */
        format_9(9),
        /**
         * Format: 0.00%
         */
        format_10(10),
        /**
         * Format: 0.00E+00
         */
        format_11(11),
        /**
         * Format: # ?/?
         */
        format_12(12),
        /**
         * Format: # ??/??
         */
        format_13(13),
        /**
         * Format: m/d/yyyy
         */
        format_14(14),
        /**
         * Format: d-mmm-yy
         */
        format_15(15),
        /**
         * Format: d-mmm
         */
        format_16(16),
        /**
         * Format: mmm-yy
         */
        format_17(17),
        /**
         * Format: mm AM/PM
         */
        format_18(18),
        /**
         * Format: h:mm:ss AM/PM
         */
        format_19(19),
        /**
         * Format: h:mm
         */
        format_20(20),
        /**
         * Format: h:mm:ss
         */
        format_21(21),
        /**
         * Format: m/d/yyyy h:mm
         */
        format_22(22),
        /**
         * Format: #,##0_);(#,##0)
         */
        format_37(37),
        /**
         * Format: #,##0_);[Red](#,##0)
         */
        format_38(38),
        /**
         * Format: #,##0.00_);(#,##0.00)
         */
        format_39(39),
        /**
         * Format: #,##0.00_);[Red](#,##0.00)
         */
        format_40(40),
        /**
         * Format: mm:ss
         */
        format_45(45),
        /**
         * Format: [h]:mm:ss
         */
        format_46(46),
        /**
         * Format: mm:ss.0
         */
        format_47(47),
        /**
         * Format: ##0.0E+0
         */
        format_48(48),
        /**
         * Format: #
         */
        format_49(49),
        /**
         * Custom Format (ID 164 and higher)
         */
        custom(164);

        private final int numVal;

        /**
         * Enum constructor with numeric value
         *
         * @param numVal Numeric value of the enum entry
         */
        FormatNumber(int numVal) {
            this.numVal = numVal;
        }

        /**
         * Gets the numeric value of the enum entry
         *
         * @return Numeric value of the enum entry
         */
        public int getValue() {
            return numVal;
        }
    }

    // ### P R I V A T E F I E L D S ###
    private FormatNumber number;
    private int customFormatID;
    private String customFormatCode;

    // ### G E T T E R S & S E T T E R S ###

    /**
     * Gets the format number. Set it to custom (164) in case of custom number formats
     *
     * @return Format number
     */
    public FormatNumber getNumber() {
        return number;
    }

    /**
     * Sets the format number. Set it to custom (164) in case of custom number formats
     *
     * @param number Format number
     */
    public void setNumber(FormatNumber number) {
        this.number = number;
    }

    /**
     * Gets the format number of the custom format. Must be higher or equal then predefined custom number (164)
     *
     * @return Format number of the custom format
     */
    public int getCustomFormatID() {
        return customFormatID;
    }

    /**
     * Sets the format number of the custom format. Must be higher or equal then predefined custom number (164)
     *
     * @param customFormatID Format number of the custom format
     */
    public void setCustomFormatID(int customFormatID) {

        if (customFormatID < CUSTOMFORMAT_START_NUMBER && !StyleRepository.getInstance().isImportInProgress()) {
            throw new StyleException("The number '" + customFormatID + "' is not a valid custom format ID. Must be at least " + CUSTOMFORMAT_START_NUMBER);
        }
        this.customFormatID = customFormatID;
    }

    /**
     * Gets the custom format code in the notation of Excel
     *
     * @return Custom format code
     */
    public String getCustomFormatCode() {
        return customFormatCode;
    }

    /**
     * Sets the raw custom format code in the notation of Excel. The code is not escaped or un-escaped (on workbook
     * loading)
     *
     * @param customFormatCode Custom format code
     * @throws FormatException thrown if the passed value is null or empty
     * @apiNote Currently, there is no auto-escaping applied to custom format strings. For instance, to add a white
     * space, internally it is escaped by a backspace (\ ). To get a valid custom format code, this escaping must be
     * applied manually, according to OOXML specs: Part 1 - Fundamentals And Markup Language Reference, Chapter 18.8.31
     */
    public void setCustomFormatCode(String customFormatCode) {
        if (customFormatCode == null || customFormatCode.isEmpty()) {
            throw new FormatException("A custom format code cannot be null or empty");
        }
        this.customFormatCode = customFormatCode;
    }

    /**
     * Gets whether this object is a custom format
     *
     * @return Returns true in case of a custom format (higher or equals 164)
     */
    public boolean isCustomFormat() {
        return number == FormatNumber.custom;
    }

    // ### C O N S T R U C T O R S ###

    /**
     * Default constructor
     */
    public NumberFormat() {
        this.number = DEFAULT_NUMBER;
        this.customFormatCode = "";
        this.customFormatID = CUSTOMFORMAT_START_NUMBER;
    }

    // ### M E T H O D S ###

    /**
     * Override toString method
     *
     * @return String of a class instance
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("\"NumberFormat\": {\n");
        addPropertyAsJson(sb, "CustomFormatCode", customFormatCode);
        addPropertyAsJson(sb, "CustomFormatID", customFormatID);
        addPropertyAsJson(sb, "Number", number);
        addPropertyAsJson(sb, "HashCode", this.hashCode(), true);
        sb.append("\n}");
        return sb.toString();
    }

    /**
     * Method to copy the current object to a new one
     *
     * @return Copy of the current object without the internal ID
     */
    @Override
    public NumberFormat copy() {
        NumberFormat copy = new NumberFormat();
        copy.customFormatCode = this.customFormatCode;
        copy.customFormatID = this.customFormatID;
        copy.setNumber(this.number);
        return copy;
    }

    /**
     * Override method to calculate the hash of this component
     *
     * @return Calculated hash as string
     * @implNote Note that autogenerated hashcode algorithms may cause collisions. Do not use 0 as fallback value for
     * every field
     */
    @Override
    public int hashCode() {
        int result = number != null ? number.hashCode() : 1;
        result = 31 * result + customFormatID;
        result = 31 * result + (customFormatCode != null ? customFormatCode.hashCode() : 2);
        return result;
    }

    /**
     * Tries to parse registered format numbers. If the parsing fails, it is assumed that the number is a custom format
     * number (164 or higher) and 'custom' is returned
     *
     * @param number Raw number to parse
     * @return Format range. Will return 'invalid' if out of any range (e.g. negative value)
     */
    public static NumberFormatEvaluation tryParseFormatNumber(int number) {
        NumberFormatEvaluation result = new NumberFormatEvaluation();
        Optional enumValue = Arrays.stream(FormatNumber.values()).filter(x -> x.getValue() == number).findFirst();
        if (enumValue.isPresent()) {
            result.setFormat(enumValue.get());
            result.setRange(NumberFormatEvaluation.FormatRange.defined_format);
        }
        else {
            if (number < 0) {
                result.setFormat(FormatNumber.none);
                result.setRange(NumberFormatEvaluation.FormatRange.invalid);
            }
            else if (number > 0 && number < CUSTOMFORMAT_START_NUMBER) {
                result.setFormat(FormatNumber.none);
                result.setRange(NumberFormatEvaluation.FormatRange.undefined);
            }
            else {
                result.setFormat(FormatNumber.custom);
                result.setRange(NumberFormatEvaluation.FormatRange.custom_format);
            }
        }
        return result;
    }

    /**
     * Determines whether a defined style format number represents a date (or date and time).
Note: Custom number * formats (higher than 164), as well as not officially defined numbers (below 164) are currently not considered * during the check and will return false * * @param number Format number to check * @return True if the format represents a date, otherwise false */ public static boolean isDateFormat(FormatNumber number) { switch (number) { case format_14: case format_15: case format_16: case format_17: case format_22: return true; default: return false; } } /** * Determines whether a defined style format number represents a time.
Note: Custom number formats (higher than * 164), as well as not officially defined numbers (below 164) are currently not considered during the check and * will return false * * @param number Format number to check * @return True if the format represents a time, otherwise false */ public static boolean isTimeFormat(FormatNumber number) { switch (number) { case format_18: case format_19: case format_20: case format_21: case format_45: case format_46: case format_47: return true; default: return false; } } // ### S U B - C L A S S E S ### /** * Class represents the evaluation of a number format (number) and its purpose */ public static class NumberFormatEvaluation { /** * Range or validity of the format number */ public enum FormatRange { /** * Format from 0 to 164 (with gaps) */ defined_format, /** * Custom defined formats from 165 and higher. Although 164 is already custom, it is still defined as enum * value */ custom_format, /** * Probably invalid format numbers (e.g. negative value) */ invalid, /** * Values between 0 and 164 that are not defined as enum value. This may be caused by changes of the OOXML * specifications or Excel versions that have encoded loaded files */ undefined, } private FormatNumber format; private FormatRange range; /** * Gets the evaluated Format * * @return Number format */ public FormatNumber getFormatNumber() { return format; } /** * Gets the range of the evaluated number format * * @return Format range */ public FormatRange getRange() { return range; } /** * Sets the evaluated Format * * @param format Number format */ public void setFormat(FormatNumber format) { this.format = format; } /** * Sets the range of the evaluated number format * * @param range Format range */ public void setRange(FormatRange range) { this.range = range; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy