mirror of
https://github.com/jmcnamara/libxlsxwriter
synced 2025-03-28 21:13:14 +00:00
parent
31a76c613a
commit
85dfccd734
5
.indent.pro
vendored
5
.indent.pro
vendored
@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
/* libxlsxwriter typedefs. */
|
/* libxlsxwriter typedefs. */
|
||||||
-T lxw_app
|
-T lxw_app
|
||||||
|
-T lxw_author_id
|
||||||
-T lxw_autofilter
|
-T lxw_autofilter
|
||||||
-T lxw_border
|
-T lxw_border
|
||||||
-T lxw_cell
|
-T lxw_cell
|
||||||
@ -84,6 +85,8 @@
|
|||||||
-T lxw_col_options
|
-T lxw_col_options
|
||||||
-T lxw_col_t
|
-T lxw_col_t
|
||||||
-T lxw_color_t
|
-T lxw_color_t
|
||||||
|
-T lxw_comment
|
||||||
|
-T lxw_comment_options
|
||||||
-T lxw_content_types
|
-T lxw_content_types
|
||||||
-T lxw_core
|
-T lxw_core
|
||||||
-T lxw_custom
|
-T lxw_custom
|
||||||
@ -132,6 +135,8 @@
|
|||||||
-T lxw_styles
|
-T lxw_styles
|
||||||
-T lxw_theme
|
-T lxw_theme
|
||||||
-T lxw_tuple
|
-T lxw_tuple
|
||||||
|
-T lxw_vml
|
||||||
|
-T lxw_vml_obj
|
||||||
-T lxw_workbook
|
-T lxw_workbook
|
||||||
-T lxw_workbook_options
|
-T lxw_workbook_options
|
||||||
-T lxw_worksheet
|
-T lxw_worksheet
|
||||||
|
20
examples/comments1.c
Normal file
20
examples/comments1.c
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* An example of writing cell comments to a worksheet using libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("comments1.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_write_string( worksheet, 0, 0, "Hello" , NULL);
|
||||||
|
|
||||||
|
worksheet_write_comment(worksheet, 0, 0, "This is a comment");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
76
include/xlsxwriter/comment.h
Normal file
76
include/xlsxwriter/comment.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* libxlsxwriter
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||||
|
*
|
||||||
|
* comment - A libxlsxwriter library for creating Excel XLSX comment files.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __LXW_COMMENT_H__
|
||||||
|
#define __LXW_COMMENT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "worksheet.h"
|
||||||
|
|
||||||
|
/* Define the tree.h RB structs for the red-black head types. */
|
||||||
|
RB_HEAD(lxw_author_ids, lxw_author_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Struct to represent a comment object.
|
||||||
|
*/
|
||||||
|
typedef struct lxw_comment {
|
||||||
|
|
||||||
|
FILE *file;
|
||||||
|
struct lxw_comment_objs *comment_objs;
|
||||||
|
struct lxw_author_ids *author_ids;
|
||||||
|
char *comment_author;
|
||||||
|
uint32_t author_id;
|
||||||
|
|
||||||
|
} lxw_comment;
|
||||||
|
|
||||||
|
/* Struct to an author id */
|
||||||
|
typedef struct lxw_author_id {
|
||||||
|
uint32_t id;
|
||||||
|
char *author;
|
||||||
|
|
||||||
|
RB_ENTRY (lxw_author_id) tree_pointers;
|
||||||
|
} lxw_author_id;
|
||||||
|
|
||||||
|
#define LXW_RB_GENERATE_AUTHOR_IDS(name, type, field, cmp) \
|
||||||
|
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
|
||||||
|
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
|
||||||
|
RB_GENERATE_INSERT(name, type, field, cmp, static) \
|
||||||
|
RB_GENERATE_REMOVE(name, type, field, static) \
|
||||||
|
RB_GENERATE_FIND(name, type, field, cmp, static) \
|
||||||
|
RB_GENERATE_NEXT(name, type, field, static) \
|
||||||
|
RB_GENERATE_MINMAX(name, type, field, static) \
|
||||||
|
/* Add unused struct to allow adding a semicolon */ \
|
||||||
|
struct lxw_rb_generate_author_ids{int unused;}
|
||||||
|
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
lxw_comment *lxw_comment_new();
|
||||||
|
void lxw_comment_free(lxw_comment *comment);
|
||||||
|
void lxw_comment_assemble_xml_file(lxw_comment *self);
|
||||||
|
|
||||||
|
/* Declarations required for unit testing. */
|
||||||
|
#ifdef TESTING
|
||||||
|
|
||||||
|
STATIC void _comment_xml_declaration(lxw_comment *self);
|
||||||
|
|
||||||
|
#endif /* TESTING */
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
#endif /* __LXW_COMMENT_H__ */
|
@ -94,6 +94,9 @@ typedef enum lxw_error {
|
|||||||
/** Unknown zip error when closing xlsx file. */
|
/** Unknown zip error when closing xlsx file. */
|
||||||
LXW_ERROR_ZIP_CLOSE,
|
LXW_ERROR_ZIP_CLOSE,
|
||||||
|
|
||||||
|
/** Feature is not currently supported in this configuration. */
|
||||||
|
LXW_ERROR_FEATURE_NOT_SUPPORTED,
|
||||||
|
|
||||||
/** NULL function parameter ignored. */
|
/** NULL function parameter ignored. */
|
||||||
LXW_ERROR_NULL_PARAMETER_IGNORED,
|
LXW_ERROR_NULL_PARAMETER_IGNORED,
|
||||||
|
|
||||||
|
@ -53,6 +53,10 @@ void lxw_ct_add_chart_name(lxw_content_types *content_types,
|
|||||||
const char *name);
|
const char *name);
|
||||||
void lxw_ct_add_drawing_name(lxw_content_types *content_types,
|
void lxw_ct_add_drawing_name(lxw_content_types *content_types,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
void lxw_ct_add_comment_name(lxw_content_types *content_types,
|
||||||
|
const char *name);
|
||||||
|
void lxw_ct_add_vml_name(lxw_content_types *content_types);
|
||||||
|
|
||||||
void lxw_ct_add_shared_strings(lxw_content_types *content_types);
|
void lxw_ct_add_shared_strings(lxw_content_types *content_types);
|
||||||
void lxw_ct_add_calc_chain(lxw_content_types *content_types);
|
void lxw_ct_add_calc_chain(lxw_content_types *content_types);
|
||||||
void lxw_ct_add_custom_properties(lxw_content_types *content_types);
|
void lxw_ct_add_custom_properties(lxw_content_types *content_types);
|
||||||
|
@ -1206,6 +1206,8 @@ void format_set_font_extend(lxw_format *format);
|
|||||||
void format_set_reading_order(lxw_format *format, uint8_t value);
|
void format_set_reading_order(lxw_format *format, uint8_t value);
|
||||||
void format_set_theme(lxw_format *format, uint8_t value);
|
void format_set_theme(lxw_format *format, uint8_t value);
|
||||||
void format_set_hyperlink(lxw_format *format);
|
void format_set_hyperlink(lxw_format *format);
|
||||||
|
void format_set_color_indexed(lxw_format *format, uint8_t value);
|
||||||
|
void format_set_font_only(lxw_format *format);
|
||||||
|
|
||||||
/* Declarations required for unit testing. */
|
/* Declarations required for unit testing. */
|
||||||
#ifdef TESTING
|
#ifdef TESTING
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "content_types.h"
|
#include "content_types.h"
|
||||||
#include "relationships.h"
|
#include "relationships.h"
|
||||||
|
#include "vml.h"
|
||||||
|
#include "comment.h"
|
||||||
|
|
||||||
#define LXW_ZIP_BUFFER_SIZE (16384)
|
#define LXW_ZIP_BUFFER_SIZE (16384)
|
||||||
|
|
||||||
|
55
include/xlsxwriter/vml.h
Normal file
55
include/xlsxwriter/vml.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* libxlsxwriter
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||||
|
*
|
||||||
|
* vml - A libxlsxwriter library for creating Excel XLSX vml files.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __LXW_VML_H__
|
||||||
|
#define __LXW_VML_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "worksheet.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Struct to represent a vml object.
|
||||||
|
*/
|
||||||
|
typedef struct lxw_vml {
|
||||||
|
|
||||||
|
FILE *file;
|
||||||
|
uint8_t type;
|
||||||
|
struct lxw_comment_objs *button_objs;
|
||||||
|
struct lxw_comment_objs *comment_objs;
|
||||||
|
struct lxw_comment_objs *image_objs;
|
||||||
|
char *vml_data_id_str;
|
||||||
|
uint32_t vml_shape_id;
|
||||||
|
uint8_t comment_display_default;
|
||||||
|
|
||||||
|
} lxw_vml;
|
||||||
|
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
lxw_vml *lxw_vml_new();
|
||||||
|
void lxw_vml_free(lxw_vml *vml);
|
||||||
|
void lxw_vml_assemble_xml_file(lxw_vml *self);
|
||||||
|
|
||||||
|
/* Declarations required for unit testing. */
|
||||||
|
#ifdef TESTING
|
||||||
|
|
||||||
|
#endif /* TESTING */
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
#endif /* __LXW_VML_H__ */
|
@ -298,6 +298,7 @@ typedef struct lxw_workbook {
|
|||||||
uint16_t num_xf_formats;
|
uint16_t num_xf_formats;
|
||||||
uint16_t num_format_count;
|
uint16_t num_format_count;
|
||||||
uint16_t drawing_count;
|
uint16_t drawing_count;
|
||||||
|
uint16_t comment_count;
|
||||||
|
|
||||||
uint16_t font_count;
|
uint16_t font_count;
|
||||||
uint16_t border_count;
|
uint16_t border_count;
|
||||||
@ -308,6 +309,7 @@ typedef struct lxw_workbook {
|
|||||||
uint8_t has_png;
|
uint8_t has_png;
|
||||||
uint8_t has_jpeg;
|
uint8_t has_jpeg;
|
||||||
uint8_t has_bmp;
|
uint8_t has_bmp;
|
||||||
|
uint8_t has_vml;
|
||||||
|
|
||||||
lxw_hash_table *used_xf_formats;
|
lxw_hash_table *used_xf_formats;
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include "styles.h"
|
#include "styles.h"
|
||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
#include "relationships.h"
|
||||||
|
|
||||||
#define LXW_ROW_MAX 1048576
|
#define LXW_ROW_MAX 1048576
|
||||||
#define LXW_COL_MAX 16384
|
#define LXW_COL_MAX 16384
|
||||||
@ -203,6 +204,20 @@ enum lxw_validation_error_types {
|
|||||||
LXW_VALIDATION_ERROR_TYPE_INFORMATION
|
LXW_VALIDATION_ERROR_TYPE_INFORMATION
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Set the display type for a cell comment. This is hidden by default but
|
||||||
|
* can be set to visible with the `worksheet_show_comments()` function. */
|
||||||
|
enum lxw_comment_display_types {
|
||||||
|
/** Default to the worksheet default which can be hidden or visible.*/
|
||||||
|
LXW_COMMENT_DISPLAY_DEFAULT,
|
||||||
|
|
||||||
|
/** Hide the cell comment. Usually the default. */
|
||||||
|
LXW_COMMENT_DISPLAY_HIDDEN,
|
||||||
|
|
||||||
|
/** Show the cell comment. Can also be set for the worksheet with the
|
||||||
|
* `worksheet_show_comments()` function.*/
|
||||||
|
LXW_COMMENT_DISPLAY_VISIBLE
|
||||||
|
};
|
||||||
|
|
||||||
enum cell_types {
|
enum cell_types {
|
||||||
NUMBER_CELL = 1,
|
NUMBER_CELL = 1,
|
||||||
STRING_CELL,
|
STRING_CELL,
|
||||||
@ -260,14 +275,14 @@ struct lxw_table_rows {
|
|||||||
struct lxw_rb_generate_cell{int unused;}
|
struct lxw_rb_generate_cell{int unused;}
|
||||||
|
|
||||||
#define LXW_RB_GENERATE_DRAWING_REL_IDS(name, type, field, cmp) \
|
#define LXW_RB_GENERATE_DRAWING_REL_IDS(name, type, field, cmp) \
|
||||||
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
|
RB_GENERATE_INSERT_COLOR(name, type, field, static) \
|
||||||
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
|
RB_GENERATE_REMOVE_COLOR(name, type, field, static) \
|
||||||
RB_GENERATE_INSERT(name, type, field, cmp, static) \
|
RB_GENERATE_INSERT(name, type, field, cmp, static) \
|
||||||
RB_GENERATE_REMOVE(name, type, field, static) \
|
RB_GENERATE_REMOVE(name, type, field, static) \
|
||||||
RB_GENERATE_FIND(name, type, field, cmp, static) \
|
RB_GENERATE_FIND(name, type, field, cmp, static) \
|
||||||
RB_GENERATE_NEXT(name, type, field, static) \
|
RB_GENERATE_NEXT(name, type, field, static) \
|
||||||
RB_GENERATE_MINMAX(name, type, field, static) \
|
RB_GENERATE_MINMAX(name, type, field, static) \
|
||||||
/* Add unused struct to allow adding a semicolon */ \
|
/* Add unused struct to allow adding a semicolon */ \
|
||||||
struct lxw_rb_generate_drawing_rel_ids{int unused;}
|
struct lxw_rb_generate_drawing_rel_ids{int unused;}
|
||||||
|
|
||||||
STAILQ_HEAD(lxw_merged_ranges, lxw_merged_range);
|
STAILQ_HEAD(lxw_merged_ranges, lxw_merged_range);
|
||||||
@ -275,6 +290,7 @@ STAILQ_HEAD(lxw_selections, lxw_selection);
|
|||||||
STAILQ_HEAD(lxw_data_validations, lxw_data_val_obj);
|
STAILQ_HEAD(lxw_data_validations, lxw_data_val_obj);
|
||||||
STAILQ_HEAD(lxw_image_props, lxw_object_properties);
|
STAILQ_HEAD(lxw_image_props, lxw_object_properties);
|
||||||
STAILQ_HEAD(lxw_chart_props, lxw_object_properties);
|
STAILQ_HEAD(lxw_chart_props, lxw_object_properties);
|
||||||
|
STAILQ_HEAD(lxw_comment_objs, lxw_vml_obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Options for rows and columns.
|
* @brief Options for rows and columns.
|
||||||
@ -658,6 +674,105 @@ typedef struct lxw_object_properties {
|
|||||||
STAILQ_ENTRY (lxw_object_properties) list_pointers;
|
STAILQ_ENTRY (lxw_object_properties) list_pointers;
|
||||||
} lxw_object_properties;
|
} lxw_object_properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Options for inserted comments.
|
||||||
|
*
|
||||||
|
* Options for modifying comments inserted via `worksheet_write_comment_opt()`.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct lxw_comment_options {
|
||||||
|
|
||||||
|
/** This option is used to make a cell comment visible when the worksheet
|
||||||
|
* is opened. The default behavior in Excel is that comments are
|
||||||
|
* initially hidden. However, it is also possible in Excel to make
|
||||||
|
* individual comments or all comments visible. You can make all
|
||||||
|
* comments in the worksheet visible using the
|
||||||
|
* `worksheet_show_comments()` function. Defaults to LXW_FALSE.*/
|
||||||
|
uint8_t visible;
|
||||||
|
|
||||||
|
/** This option is used to set the row in which the comment will
|
||||||
|
* appear. By default Excel displays comments one cell to the right and
|
||||||
|
* one cell above the cell to which the comment relates. The `start_row`
|
||||||
|
* and `start_col` options should both be set to 0 if not used.*/
|
||||||
|
lxw_row_t start_row;
|
||||||
|
|
||||||
|
/** This option is used to set the column in which the comment will
|
||||||
|
* appear. See the `start_row` option for more information. */
|
||||||
|
lxw_col_t start_col;
|
||||||
|
|
||||||
|
/** This option is used to set the width of the cell comment box
|
||||||
|
* explicitly in pixels. The default width is 128 pixels. */
|
||||||
|
uint16_t width;
|
||||||
|
|
||||||
|
/** This option is used to set the height of the cell comment box
|
||||||
|
* explicitly in pixels. The default height is 74 pixels. */
|
||||||
|
uint16_t height;
|
||||||
|
|
||||||
|
/** X scale of the comment as a decimal. */
|
||||||
|
double x_scale;
|
||||||
|
|
||||||
|
/** Y scale of the comment as a decimal. */
|
||||||
|
double y_scale;
|
||||||
|
|
||||||
|
/** Offset from the left of the cell in pixels. */
|
||||||
|
int32_t x_offset;
|
||||||
|
|
||||||
|
/** Offset from the top of the cell in pixels. */
|
||||||
|
int32_t y_offset;
|
||||||
|
|
||||||
|
/** This option is used to set the background color of cell comment
|
||||||
|
* box. The color should be an RGB integer value, see @ref
|
||||||
|
* working_with_colors. */
|
||||||
|
lxw_color_t color;
|
||||||
|
|
||||||
|
/** This option is used to set the font for the comment. The default font
|
||||||
|
* is 'Tahoma'. */
|
||||||
|
char *font_name;
|
||||||
|
|
||||||
|
/** This option is used to set the font size for the comment. The default
|
||||||
|
* is 8. */
|
||||||
|
double font_size;
|
||||||
|
|
||||||
|
/** This option is used to set the font family number for the comment.
|
||||||
|
* Not required very often. Set to 0. */
|
||||||
|
uint8_t font_family;
|
||||||
|
|
||||||
|
/** This option is used to indicate the author of the cell comment. Excel
|
||||||
|
* displays the author in the status bar at the bottom of the
|
||||||
|
* worksheet. The default author for all cell comments in a worksheet can
|
||||||
|
* be set using the `worksheet_set_comments_author()` function. Set to
|
||||||
|
* NULL if not required.*/
|
||||||
|
char *author;
|
||||||
|
|
||||||
|
} lxw_comment_options;
|
||||||
|
|
||||||
|
/* Internal structure for VML object options. */
|
||||||
|
typedef struct lxw_vml_obj {
|
||||||
|
|
||||||
|
lxw_row_t row;
|
||||||
|
lxw_col_t col;
|
||||||
|
lxw_row_t start_row;
|
||||||
|
lxw_col_t start_col;
|
||||||
|
int32_t x_offset;
|
||||||
|
int32_t y_offset;
|
||||||
|
uint32_t col_absolute;
|
||||||
|
uint32_t row_absolute;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
lxw_color_t color;
|
||||||
|
uint8_t font_family;
|
||||||
|
uint8_t visible;
|
||||||
|
uint32_t author_id;
|
||||||
|
double font_size;
|
||||||
|
struct lxw_drawing_coords from;
|
||||||
|
struct lxw_drawing_coords to;
|
||||||
|
char *author;
|
||||||
|
char *font_name;
|
||||||
|
char *text;
|
||||||
|
STAILQ_ENTRY (lxw_vml_obj) list_pointers;
|
||||||
|
|
||||||
|
} lxw_vml_obj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Header and footer options.
|
* @brief Header and footer options.
|
||||||
*
|
*
|
||||||
@ -790,6 +905,7 @@ typedef struct lxw_worksheet {
|
|||||||
struct lxw_image_props *image_props;
|
struct lxw_image_props *image_props;
|
||||||
struct lxw_chart_props *chart_data;
|
struct lxw_chart_props *chart_data;
|
||||||
struct lxw_drawing_rel_ids *drawing_rel_ids;
|
struct lxw_drawing_rel_ids *drawing_rel_ids;
|
||||||
|
struct lxw_comment_objs *comment_objs;
|
||||||
|
|
||||||
lxw_row_t dim_rowmin;
|
lxw_row_t dim_rowmin;
|
||||||
lxw_row_t dim_rowmax;
|
lxw_row_t dim_rowmax;
|
||||||
@ -902,6 +1018,16 @@ typedef struct lxw_worksheet {
|
|||||||
lxw_drawing *drawing;
|
lxw_drawing *drawing;
|
||||||
lxw_format *default_url_format;
|
lxw_format *default_url_format;
|
||||||
|
|
||||||
|
uint8_t has_vml;
|
||||||
|
uint8_t has_comments;
|
||||||
|
uint8_t has_header_vml;
|
||||||
|
lxw_rel_tuple *external_vml_comment_link;
|
||||||
|
lxw_rel_tuple *external_comment_link;
|
||||||
|
char *comment_author;
|
||||||
|
char *vml_data_id_str;
|
||||||
|
uint32_t vml_shape_id;
|
||||||
|
uint8_t comment_display_default;
|
||||||
|
|
||||||
STAILQ_ENTRY (lxw_worksheet) list_pointers;
|
STAILQ_ENTRY (lxw_worksheet) list_pointers;
|
||||||
|
|
||||||
} lxw_worksheet;
|
} lxw_worksheet;
|
||||||
@ -935,6 +1061,8 @@ typedef struct lxw_row {
|
|||||||
uint8_t row_changed;
|
uint8_t row_changed;
|
||||||
uint8_t data_changed;
|
uint8_t data_changed;
|
||||||
uint8_t height_changed;
|
uint8_t height_changed;
|
||||||
|
uint8_t has_comments;
|
||||||
|
|
||||||
struct lxw_table_cells *cells;
|
struct lxw_table_cells *cells;
|
||||||
|
|
||||||
/* tree management pointers for tree.h. */
|
/* tree management pointers for tree.h. */
|
||||||
@ -947,6 +1075,7 @@ typedef struct lxw_cell {
|
|||||||
lxw_col_t col_num;
|
lxw_col_t col_num;
|
||||||
enum cell_types type;
|
enum cell_types type;
|
||||||
lxw_format *format;
|
lxw_format *format;
|
||||||
|
lxw_vml_obj *comment;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
double number;
|
double number;
|
||||||
@ -1547,6 +1676,14 @@ lxw_error worksheet_write_rich_string(lxw_worksheet *worksheet,
|
|||||||
lxw_rich_string_tuple *rich_string[],
|
lxw_rich_string_tuple *rich_string[],
|
||||||
lxw_format *format);
|
lxw_format *format);
|
||||||
|
|
||||||
|
lxw_error worksheet_write_comment_opt(lxw_worksheet *worksheet,
|
||||||
|
lxw_row_t row_num, lxw_col_t col_num,
|
||||||
|
char *string,
|
||||||
|
lxw_comment_options *options);
|
||||||
|
|
||||||
|
lxw_error worksheet_write_comment(lxw_worksheet *worksheet,
|
||||||
|
lxw_row_t row, lxw_col_t col, char *string);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the properties for a row of cells.
|
* @brief Set the properties for a row of cells.
|
||||||
*
|
*
|
||||||
@ -3417,6 +3554,11 @@ void worksheet_set_default_row(lxw_worksheet *worksheet, double height,
|
|||||||
*/
|
*/
|
||||||
lxw_error worksheet_set_vba_name(lxw_worksheet *worksheet, const char *name);
|
lxw_error worksheet_set_vba_name(lxw_worksheet *worksheet, const char *name);
|
||||||
|
|
||||||
|
void worksheet_set_comments_author(lxw_worksheet *worksheet,
|
||||||
|
const char *author);
|
||||||
|
|
||||||
|
void worksheet_show_comments(lxw_worksheet *worksheet);
|
||||||
|
|
||||||
lxw_worksheet *lxw_worksheet_new(lxw_worksheet_init_data *init_data);
|
lxw_worksheet *lxw_worksheet_new(lxw_worksheet_init_data *init_data);
|
||||||
void lxw_worksheet_free(lxw_worksheet *worksheet);
|
void lxw_worksheet_free(lxw_worksheet *worksheet);
|
||||||
void lxw_worksheet_assemble_xml_file(lxw_worksheet *worksheet);
|
void lxw_worksheet_assemble_xml_file(lxw_worksheet *worksheet);
|
||||||
@ -3431,9 +3573,14 @@ void lxw_worksheet_prepare_chart(lxw_worksheet *worksheet,
|
|||||||
lxw_object_properties *object_props,
|
lxw_object_properties *object_props,
|
||||||
uint8_t is_chartsheet);
|
uint8_t is_chartsheet);
|
||||||
|
|
||||||
lxw_row *lxw_worksheet_find_row(lxw_worksheet *worksheet, lxw_row_t row_num);
|
uint32_t lxw_worksheet_prepare_vml_objects(lxw_worksheet *worksheet,
|
||||||
lxw_cell *lxw_worksheet_find_cell(lxw_row *row, lxw_col_t col_num);
|
uint32_t vml_data_id,
|
||||||
|
uint32_t vml_shape_id,
|
||||||
|
uint32_t vml_drawing_id,
|
||||||
|
uint32_t comment_id);
|
||||||
|
|
||||||
|
lxw_row *lxw_worksheet_find_row(lxw_worksheet *worksheet, lxw_row_t row_num);
|
||||||
|
lxw_cell *lxw_worksheet_find_cell_in_row(lxw_row *row, lxw_col_t col_num);
|
||||||
/*
|
/*
|
||||||
* External functions to call intern XML methods shared with chartsheet.
|
* External functions to call intern XML methods shared with chartsheet.
|
||||||
*/
|
*/
|
||||||
|
443
src/comment.c
Normal file
443
src/comment.c
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* comment - A library for creating Excel XLSX comment files.
|
||||||
|
*
|
||||||
|
* Used in conjunction with the libxlsxwriter library.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter/xmlwriter.h"
|
||||||
|
#include "xlsxwriter/comment.h"
|
||||||
|
#include "xlsxwriter/utility.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forward declarations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
STATIC int _author_id_cmp(lxw_author_id *tuple1, lxw_author_id *tuple2);
|
||||||
|
|
||||||
|
#ifndef __clang_analyzer__
|
||||||
|
LXW_RB_GENERATE_AUTHOR_IDS(lxw_author_ids, lxw_author_id,
|
||||||
|
tree_pointers, _author_id_cmp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Private functions.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Comparator for the author ids.
|
||||||
|
*/
|
||||||
|
STATIC int
|
||||||
|
_author_id_cmp(lxw_author_id *author_id1, lxw_author_id *author_id2)
|
||||||
|
{
|
||||||
|
return strcmp(author_id1->author, author_id2->author);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if an author already existing in the author/id table.
|
||||||
|
*/
|
||||||
|
STATIC uint8_t
|
||||||
|
_check_author(lxw_comment *self, char *author)
|
||||||
|
{
|
||||||
|
lxw_author_id tmp_author_id;
|
||||||
|
lxw_author_id *existing_author = NULL;
|
||||||
|
|
||||||
|
if (!author)
|
||||||
|
return LXW_TRUE;
|
||||||
|
|
||||||
|
tmp_author_id.author = author;
|
||||||
|
existing_author = RB_FIND(lxw_author_ids,
|
||||||
|
self->author_ids, &tmp_author_id);
|
||||||
|
|
||||||
|
if (existing_author)
|
||||||
|
return LXW_TRUE;
|
||||||
|
else
|
||||||
|
return LXW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the index used for an author name.
|
||||||
|
*/
|
||||||
|
STATIC uint32_t
|
||||||
|
_get_author_index(lxw_comment *self, char *author)
|
||||||
|
{
|
||||||
|
lxw_author_id tmp_author_id;
|
||||||
|
lxw_author_id *existing_author = NULL;
|
||||||
|
lxw_author_id *new_author_id = NULL;
|
||||||
|
|
||||||
|
if (!author)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tmp_author_id.author = author;
|
||||||
|
existing_author = RB_FIND(lxw_author_ids,
|
||||||
|
self->author_ids, &tmp_author_id);
|
||||||
|
|
||||||
|
if (existing_author) {
|
||||||
|
return existing_author->id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_author_id = calloc(1, sizeof(lxw_author_id));
|
||||||
|
|
||||||
|
if (new_author_id) {
|
||||||
|
new_author_id->id = self->author_id;
|
||||||
|
new_author_id->author = lxw_strdup(author);
|
||||||
|
self->author_id++;
|
||||||
|
|
||||||
|
RB_INSERT(lxw_author_ids, self->author_ids, new_author_id);
|
||||||
|
|
||||||
|
return new_author_id->id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new comment object.
|
||||||
|
*/
|
||||||
|
lxw_comment *
|
||||||
|
lxw_comment_new()
|
||||||
|
{
|
||||||
|
lxw_comment *comment = calloc(1, sizeof(lxw_comment));
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(comment, mem_error);
|
||||||
|
|
||||||
|
comment->author_ids = calloc(1, sizeof(struct lxw_author_ids));
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(comment->author_ids, mem_error);
|
||||||
|
RB_INIT(comment->author_ids);
|
||||||
|
|
||||||
|
return comment;
|
||||||
|
|
||||||
|
mem_error:
|
||||||
|
lxw_comment_free(comment);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free a comment object.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lxw_comment_free(lxw_comment *comment)
|
||||||
|
{
|
||||||
|
struct lxw_author_id *author_id;
|
||||||
|
struct lxw_author_id *next_author_id;
|
||||||
|
|
||||||
|
if (!comment)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (comment->author_ids) {
|
||||||
|
for (author_id =
|
||||||
|
RB_MIN(lxw_author_ids, comment->author_ids);
|
||||||
|
author_id; author_id = next_author_id) {
|
||||||
|
|
||||||
|
next_author_id =
|
||||||
|
RB_NEXT(lxw_author_ids, worksheet->author_id, author_id);
|
||||||
|
RB_REMOVE(lxw_author_ids, comment->author_ids, author_id);
|
||||||
|
free(author_id->author);
|
||||||
|
free(author_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(comment->author_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* XML functions.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the XML declaration.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_xml_declaration(lxw_comment *self)
|
||||||
|
{
|
||||||
|
lxw_xml_declaration(self->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* XML file assembly functions.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <t> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_text_t(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
lxw_xml_data_element(self->file, "t", comment_obj->text, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <family> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_family(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_INT("val", comment_obj->font_family);
|
||||||
|
|
||||||
|
lxw_xml_empty_tag(self->file, "family", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <rFont> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_r_font(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
char font_name[LXW_ATTR_32];
|
||||||
|
|
||||||
|
if (comment_obj->font_name)
|
||||||
|
lxw_snprintf(font_name, LXW_ATTR_32, "%s", comment_obj->font_name);
|
||||||
|
else
|
||||||
|
lxw_snprintf(font_name, LXW_MAX_ATTRIBUTE_LENGTH, "Tahoma");
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_STR("val", font_name);
|
||||||
|
|
||||||
|
lxw_xml_empty_tag(self->file, "rFont", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <color> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_color(lxw_comment *self)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
char indexed[] = "81";
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_STR("indexed", indexed);
|
||||||
|
|
||||||
|
lxw_xml_empty_tag(self->file, "color", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <sz> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_sz(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_DBL("val", comment_obj->font_size);
|
||||||
|
|
||||||
|
lxw_xml_empty_tag(self->file, "sz", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <rPr> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_r_pr(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
lxw_xml_start_tag(self->file, "rPr", NULL);
|
||||||
|
|
||||||
|
/* Write the sz element. */
|
||||||
|
_comment_write_sz(self, comment_obj);
|
||||||
|
|
||||||
|
/* Write the color element. */
|
||||||
|
_comment_write_color(self);
|
||||||
|
|
||||||
|
/* Write the rFont element. */
|
||||||
|
_comment_write_r_font(self, comment_obj);
|
||||||
|
|
||||||
|
/* Write the family element. */
|
||||||
|
_comment_write_family(self, comment_obj);
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "rPr");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <r> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_r(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
lxw_xml_start_tag(self->file, "r", NULL);
|
||||||
|
|
||||||
|
/* Write the rPr element. */
|
||||||
|
_comment_write_r_pr(self, comment_obj);
|
||||||
|
|
||||||
|
/* Write the t element. */
|
||||||
|
_comment_write_text_t(self, comment_obj);
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <text> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_text(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
lxw_xml_start_tag(self->file, "text", NULL);
|
||||||
|
|
||||||
|
/* Write the r element. */
|
||||||
|
_comment_write_r(self, comment_obj);
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "text");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <comment> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_comment(lxw_comment *self, lxw_vml_obj *comment_obj)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
char ref[LXW_MAX_CELL_NAME_LENGTH];
|
||||||
|
|
||||||
|
lxw_rowcol_to_cell(ref, comment_obj->row, comment_obj->col);
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_STR("ref", ref);
|
||||||
|
LXW_PUSH_ATTRIBUTES_INT("authorId", comment_obj->author_id);
|
||||||
|
|
||||||
|
lxw_xml_start_tag(self->file, "comment", &attributes);
|
||||||
|
|
||||||
|
/* Write the text element. */
|
||||||
|
_comment_write_text(self, comment_obj);
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "comment");
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <commentList> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_comment_list(lxw_comment *self)
|
||||||
|
{
|
||||||
|
lxw_vml_obj *comment_obj;
|
||||||
|
|
||||||
|
lxw_xml_start_tag(self->file, "commentList", NULL);
|
||||||
|
|
||||||
|
STAILQ_FOREACH(comment_obj, self->comment_objs, list_pointers) {
|
||||||
|
/* Write the comment element. */
|
||||||
|
_comment_write_comment(self, comment_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "commentList");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <author> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_author(lxw_comment *self, char *author)
|
||||||
|
{
|
||||||
|
lxw_xml_data_element(self->file, "author", author, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <authors> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_authors(lxw_comment *self)
|
||||||
|
{
|
||||||
|
lxw_vml_obj *comment_obj;
|
||||||
|
char *author;
|
||||||
|
|
||||||
|
lxw_xml_start_tag(self->file, "authors", NULL);
|
||||||
|
|
||||||
|
/* Set the default author (from worksheet_set_comments_author()). */
|
||||||
|
if (self->comment_author) {
|
||||||
|
_get_author_index(self, self->comment_author);
|
||||||
|
_comment_write_author(self, self->comment_author);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_get_author_index(self, "");
|
||||||
|
_comment_write_author(self, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
STAILQ_FOREACH(comment_obj, self->comment_objs, list_pointers) {
|
||||||
|
author = comment_obj->author;
|
||||||
|
|
||||||
|
if (author) {
|
||||||
|
|
||||||
|
if (!_check_author(self, author))
|
||||||
|
_comment_write_author(self, author);
|
||||||
|
|
||||||
|
comment_obj->author_id = _get_author_index(self, author);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "authors");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <comments> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_comment_write_comments(lxw_comment *self)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
char xmlns[] =
|
||||||
|
"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
|
||||||
|
|
||||||
|
lxw_xml_start_tag(self->file, "comments", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assemble and write the XML file.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lxw_comment_assemble_xml_file(lxw_comment *self)
|
||||||
|
{
|
||||||
|
/* Write the XML declaration. */
|
||||||
|
_comment_xml_declaration(self);
|
||||||
|
|
||||||
|
/* Write the comments element. */
|
||||||
|
_comment_write_comments(self);
|
||||||
|
|
||||||
|
/* Write the authors element. */
|
||||||
|
_comment_write_authors(self);
|
||||||
|
|
||||||
|
/* Write the commentList element. */
|
||||||
|
_comment_write_comment_list(self);
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "comments");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Public functions.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
@ -322,6 +322,25 @@ lxw_ct_add_drawing_name(lxw_content_types *self, const char *name)
|
|||||||
lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawing+xml");
|
lxw_ct_add_override(self, name, LXW_APP_DOCUMENT "drawing+xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the name of a VML drawing to the ContentTypes overrides.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lxw_ct_add_vml_name(lxw_content_types *self)
|
||||||
|
{
|
||||||
|
lxw_ct_add_default(self, "vml", LXW_APP_DOCUMENT "vmlDrawing");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the name of a comment to the ContentTypes overrides.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
lxw_ct_add_comment_name(lxw_content_types *self, const char *name)
|
||||||
|
{
|
||||||
|
lxw_ct_add_override(self, name,
|
||||||
|
LXW_APP_DOCUMENT "spreadsheetml.comments+xml");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the sharedStrings link to the ContentTypes overrides.
|
* Add the sharedStrings link to the ContentTypes overrides.
|
||||||
*/
|
*/
|
||||||
|
30
src/format.c
30
src/format.c
@ -117,18 +117,6 @@ lxw_format_free(lxw_format *format)
|
|||||||
format = NULL;
|
format = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check a user input color.
|
|
||||||
*/
|
|
||||||
lxw_color_t
|
|
||||||
lxw_format_check_colorz(lxw_color_t color)
|
|
||||||
{
|
|
||||||
if (color == LXW_COLOR_UNSET)
|
|
||||||
return color;
|
|
||||||
else
|
|
||||||
return color & LXW_COLOR_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check a user input border.
|
* Check a user input border.
|
||||||
*/
|
*/
|
||||||
@ -728,6 +716,24 @@ format_set_theme(lxw_format *self, uint8_t value)
|
|||||||
self->theme = value;
|
self->theme = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color_indexed property.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
format_set_color_indexed(lxw_format *self, uint8_t value)
|
||||||
|
{
|
||||||
|
self->color_indexed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the font_only property.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
format_set_font_only(lxw_format *self)
|
||||||
|
{
|
||||||
|
self->font_only = LXW_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the theme property.
|
* Set the theme property.
|
||||||
*/
|
*/
|
||||||
|
143
src/packager.c
143
src/packager.c
@ -445,6 +445,120 @@ _get_drawing_count(lxw_packager *self)
|
|||||||
return drawing_count;
|
return drawing_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the comment/header VML files.
|
||||||
|
*/
|
||||||
|
STATIC lxw_error
|
||||||
|
_write_vml_files(lxw_packager *self)
|
||||||
|
{
|
||||||
|
lxw_workbook *workbook = self->workbook;
|
||||||
|
lxw_sheet *sheet;
|
||||||
|
lxw_worksheet *worksheet;
|
||||||
|
lxw_vml *vml;
|
||||||
|
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
||||||
|
uint32_t index = 1;
|
||||||
|
lxw_error err;
|
||||||
|
|
||||||
|
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
|
||||||
|
if (sheet->is_chartsheet)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
worksheet = sheet->u.worksheet;
|
||||||
|
|
||||||
|
if (!worksheet->has_vml)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vml = lxw_vml_new();
|
||||||
|
if (!vml)
|
||||||
|
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||||
|
|
||||||
|
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||||
|
"xl/drawings/vmlDrawing%d.vml", index++);
|
||||||
|
|
||||||
|
vml->file = lxw_tmpfile(self->tmpdir);
|
||||||
|
if (!vml->file) {
|
||||||
|
lxw_vml_free(vml);
|
||||||
|
return LXW_ERROR_CREATING_TMPFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vml->comment_objs = worksheet->comment_objs;
|
||||||
|
vml->vml_shape_id = worksheet->vml_shape_id;
|
||||||
|
vml->comment_display_default = worksheet->comment_display_default;
|
||||||
|
|
||||||
|
if (worksheet->vml_data_id_str) {
|
||||||
|
vml->vml_data_id_str = worksheet->vml_data_id_str;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fclose(vml->file);
|
||||||
|
lxw_vml_free(vml);
|
||||||
|
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
lxw_vml_assemble_xml_file(vml);
|
||||||
|
|
||||||
|
err = _add_file_to_zip(self, vml->file, filename);
|
||||||
|
|
||||||
|
fclose(vml->file);
|
||||||
|
lxw_vml_free(vml);
|
||||||
|
|
||||||
|
RETURN_ON_ERROR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LXW_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the comment files.
|
||||||
|
*/
|
||||||
|
STATIC lxw_error
|
||||||
|
_write_comment_files(lxw_packager *self)
|
||||||
|
{
|
||||||
|
lxw_workbook *workbook = self->workbook;
|
||||||
|
lxw_sheet *sheet;
|
||||||
|
lxw_worksheet *worksheet;
|
||||||
|
lxw_comment *comment;
|
||||||
|
char filename[LXW_FILENAME_LENGTH] = { 0 };
|
||||||
|
uint32_t index = 1;
|
||||||
|
lxw_error err;
|
||||||
|
|
||||||
|
STAILQ_FOREACH(sheet, workbook->sheets, list_pointers) {
|
||||||
|
if (sheet->is_chartsheet)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
worksheet = sheet->u.worksheet;
|
||||||
|
|
||||||
|
if (!worksheet->has_comments)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comment = lxw_comment_new();
|
||||||
|
if (!comment)
|
||||||
|
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||||
|
|
||||||
|
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||||
|
"xl/comments%d.xml", index++);
|
||||||
|
|
||||||
|
comment->file = lxw_tmpfile(self->tmpdir);
|
||||||
|
if (!comment->file) {
|
||||||
|
lxw_comment_free(comment);
|
||||||
|
return LXW_ERROR_CREATING_TMPFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
comment->comment_objs = worksheet->comment_objs;
|
||||||
|
comment->comment_author = worksheet->comment_author;
|
||||||
|
|
||||||
|
lxw_comment_assemble_xml_file(comment);
|
||||||
|
|
||||||
|
err = _add_file_to_zip(self, comment->file, filename);
|
||||||
|
|
||||||
|
fclose(comment->file);
|
||||||
|
lxw_comment_free(comment);
|
||||||
|
|
||||||
|
RETURN_ON_ERROR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LXW_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the sharedStrings.xml file.
|
* Write the sharedStrings.xml file.
|
||||||
*/
|
*/
|
||||||
@ -792,6 +906,15 @@ _write_content_types_file(lxw_packager *self)
|
|||||||
lxw_ct_add_drawing_name(content_types, filename);
|
lxw_ct_add_drawing_name(content_types, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (workbook->has_vml)
|
||||||
|
lxw_ct_add_vml_name(content_types);
|
||||||
|
|
||||||
|
for (index = 1; index <= workbook->comment_count; index++) {
|
||||||
|
lxw_snprintf(filename, LXW_FILENAME_LENGTH,
|
||||||
|
"/xl/comments%d.xml", index);
|
||||||
|
lxw_ct_add_comment_name(content_types, filename);
|
||||||
|
}
|
||||||
|
|
||||||
if (workbook->sst->string_count)
|
if (workbook->sst->string_count)
|
||||||
lxw_ct_add_shared_strings(content_types);
|
lxw_ct_add_shared_strings(content_types);
|
||||||
|
|
||||||
@ -898,7 +1021,9 @@ _write_worksheet_rels_file(lxw_packager *self)
|
|||||||
index++;
|
index++;
|
||||||
|
|
||||||
if (STAILQ_EMPTY(worksheet->external_hyperlinks) &&
|
if (STAILQ_EMPTY(worksheet->external_hyperlinks) &&
|
||||||
STAILQ_EMPTY(worksheet->external_drawing_links))
|
STAILQ_EMPTY(worksheet->external_drawing_links) &&
|
||||||
|
!worksheet->external_vml_comment_link &&
|
||||||
|
!worksheet->external_comment_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rels = lxw_relationships_new();
|
rels = lxw_relationships_new();
|
||||||
@ -919,6 +1044,16 @@ _write_worksheet_rels_file(lxw_packager *self)
|
|||||||
rel->target_mode);
|
rel->target_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rel = worksheet->external_vml_comment_link;
|
||||||
|
if (rel)
|
||||||
|
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
|
||||||
|
rel->target_mode);
|
||||||
|
|
||||||
|
rel = worksheet->external_comment_link;
|
||||||
|
if (rel)
|
||||||
|
lxw_add_worksheet_relationship(rels, rel->type, rel->target,
|
||||||
|
rel->target_mode);
|
||||||
|
|
||||||
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
|
lxw_snprintf(sheetname, LXW_FILENAME_LENGTH,
|
||||||
"xl/worksheets/_rels/sheet%d.xml.rels", index);
|
"xl/worksheets/_rels/sheet%d.xml.rels", index);
|
||||||
|
|
||||||
@ -1228,6 +1363,12 @@ lxw_create_package(lxw_packager *self)
|
|||||||
error = _write_drawing_files(self);
|
error = _write_drawing_files(self);
|
||||||
RETURN_ON_ERROR(error);
|
RETURN_ON_ERROR(error);
|
||||||
|
|
||||||
|
error = _write_vml_files(self);
|
||||||
|
RETURN_ON_ERROR(error);
|
||||||
|
|
||||||
|
error = _write_comment_files(self);
|
||||||
|
RETURN_ON_ERROR(error);
|
||||||
|
|
||||||
error = _write_shared_strings_file(self);
|
error = _write_shared_strings_file(self);
|
||||||
RETURN_ON_ERROR(error);
|
RETURN_ON_ERROR(error);
|
||||||
|
|
||||||
|
36
src/styles.c
36
src/styles.c
@ -240,6 +240,23 @@ _write_font_color_rgb(lxw_styles *self, int32_t rgb)
|
|||||||
LXW_FREE_ATTRIBUTES();
|
LXW_FREE_ATTRIBUTES();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <color> element for indexed colors.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_write_font_color_indexed(lxw_styles *self, uint8_t index)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_INT("indexed", index);
|
||||||
|
|
||||||
|
lxw_xml_empty_tag(self->file, "color", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the <name> element.
|
* Write the <name> element.
|
||||||
*/
|
*/
|
||||||
@ -386,6 +403,8 @@ _write_font(lxw_styles *self, lxw_format *format, uint8_t is_rich_string)
|
|||||||
|
|
||||||
if (format->theme)
|
if (format->theme)
|
||||||
_write_font_color_theme(self, format->theme);
|
_write_font_color_theme(self, format->theme);
|
||||||
|
else if (format->color_indexed)
|
||||||
|
_write_font_color_indexed(self, format->color_indexed);
|
||||||
else if (format->font_color != LXW_COLOR_UNSET)
|
else if (format->font_color != LXW_COLOR_UNSET)
|
||||||
_write_font_color_rgb(self, format->font_color);
|
_write_font_color_rgb(self, format->font_color);
|
||||||
else
|
else
|
||||||
@ -1051,14 +1070,27 @@ _write_cell_xfs(lxw_styles *self)
|
|||||||
struct xml_attribute_list attributes;
|
struct xml_attribute_list attributes;
|
||||||
struct xml_attribute *attribute;
|
struct xml_attribute *attribute;
|
||||||
lxw_format *format;
|
lxw_format *format;
|
||||||
|
uint32_t count = self->xf_count;
|
||||||
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
/* If the last format is "font_only" it is for the comment font and
|
||||||
|
* shouldn't be counted. This is a workaround to get the last object
|
||||||
|
* in the list since STAILQ_LAST() requires __containerof and isn't
|
||||||
|
* ANSI compatible. */
|
||||||
|
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
|
||||||
|
i++;
|
||||||
|
if (i == self->xf_count && format->font_only)
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
LXW_INIT_ATTRIBUTES();
|
LXW_INIT_ATTRIBUTES();
|
||||||
LXW_PUSH_ATTRIBUTES_INT("count", self->xf_count);
|
LXW_PUSH_ATTRIBUTES_INT("count", count);
|
||||||
|
|
||||||
lxw_xml_start_tag(self->file, "cellXfs", &attributes);
|
lxw_xml_start_tag(self->file, "cellXfs", &attributes);
|
||||||
|
|
||||||
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
|
STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
|
||||||
_write_xf(self, format);
|
if (!format->font_only)
|
||||||
|
_write_xf(self, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
lxw_xml_end_tag(self->file, "cellXfs");
|
lxw_xml_end_tag(self->file, "cellXfs");
|
||||||
|
@ -27,6 +27,7 @@ char *error_strings[LXW_MAX_ERRNO + 1] = {
|
|||||||
"Zip error ZIP_INTERNALERROR while creating the xlsx file.",
|
"Zip error ZIP_INTERNALERROR while creating the xlsx file.",
|
||||||
"File error or unknown zip error when adding sub file to xlsx file.",
|
"File error or unknown zip error when adding sub file to xlsx file.",
|
||||||
"Unknown zip error when closing xlsx file.",
|
"Unknown zip error when closing xlsx file.",
|
||||||
|
"Feature is not currently supported in this configuration.",
|
||||||
"NULL function parameter ignored.",
|
"NULL function parameter ignored.",
|
||||||
"Function parameter validation error.",
|
"Function parameter validation error.",
|
||||||
"Worksheet name exceeds Excel's limit of 31 characters.",
|
"Worksheet name exceeds Excel's limit of 31 characters.",
|
||||||
|
@ -767,7 +767,7 @@ _populate_range_data_cache(lxw_workbook *self, lxw_series_range *range)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_obj = lxw_worksheet_find_cell(row_obj, col_num);
|
cell_obj = lxw_worksheet_find_cell_in_row(row_obj, col_num);
|
||||||
|
|
||||||
if (cell_obj) {
|
if (cell_obj) {
|
||||||
if (cell_obj->type == NUMBER_CELL) {
|
if (cell_obj->type == NUMBER_CELL) {
|
||||||
@ -1000,6 +1000,65 @@ _prepare_drawings(lxw_workbook *self)
|
|||||||
self->drawing_count = drawing_id;
|
self->drawing_count = drawing_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate through the worksheets and set up the VML objects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
STATIC void
|
||||||
|
_prepare_vml(lxw_workbook *self)
|
||||||
|
{
|
||||||
|
lxw_worksheet *worksheet;
|
||||||
|
lxw_sheet *sheet;
|
||||||
|
uint32_t comment_id = 0;
|
||||||
|
uint32_t vml_drawing_id = 0;
|
||||||
|
uint32_t vml_data_id = 1;
|
||||||
|
uint32_t vml_shape_id = 1024;
|
||||||
|
lxw_format *format;
|
||||||
|
uint32_t comment_count = 0;
|
||||||
|
|
||||||
|
STAILQ_FOREACH(sheet, self->sheets, list_pointers) {
|
||||||
|
if (sheet->is_chartsheet)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
worksheet = sheet->u.worksheet;
|
||||||
|
|
||||||
|
if (!worksheet->has_vml && !worksheet->has_header_vml)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (worksheet->has_vml) {
|
||||||
|
self->has_vml = LXW_TRUE;
|
||||||
|
if (worksheet->has_comments) {
|
||||||
|
self->comment_count += 1;
|
||||||
|
comment_id += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vml_drawing_id += 1;
|
||||||
|
|
||||||
|
comment_count = lxw_worksheet_prepare_vml_objects(worksheet,
|
||||||
|
vml_data_id,
|
||||||
|
vml_shape_id,
|
||||||
|
vml_drawing_id,
|
||||||
|
comment_id);
|
||||||
|
|
||||||
|
/* Each VML should start with a shape id incremented by 1024. */
|
||||||
|
vml_data_id += 1 * ((1024 + comment_count) / 1024);
|
||||||
|
vml_shape_id += 1024 * ((1024 + comment_count) / 1024);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->comment_count) {
|
||||||
|
/* Add a font format for cell comments. */
|
||||||
|
format = workbook_add_format(self);
|
||||||
|
format_set_font_name(format, "Tahoma");
|
||||||
|
format_set_font_size(format, 8);
|
||||||
|
format_set_color_indexed(format, 81);
|
||||||
|
format_set_font_only(format);
|
||||||
|
/* Initialize its index. */
|
||||||
|
lxw_format_get_xf_index(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iterate through the worksheets and store any defined names used for print
|
* Iterate through the worksheets and store any defined names used for print
|
||||||
* ranges or repeat rows/columns.
|
* ranges or repeat rows/columns.
|
||||||
@ -1821,6 +1880,9 @@ workbook_close(lxw_workbook *self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prepare the worksheet VML elements such as comments. */
|
||||||
|
_prepare_vml(self);
|
||||||
|
|
||||||
/* Set the defined names for the worksheets such as Print Titles. */
|
/* Set the defined names for the worksheets such as Print Titles. */
|
||||||
_prepare_defined_names(self);
|
_prepare_defined_names(self);
|
||||||
|
|
||||||
@ -2250,8 +2312,6 @@ workbook_unset_default_url_format(lxw_workbook *self)
|
|||||||
self->default_url_format->theme = 0;
|
self->default_url_format->theme = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lxw_format *default_url_format;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate the worksheet name based on Excel's rules.
|
* Validate the worksheet name based on Excel's rules.
|
||||||
*/
|
*/
|
||||||
|
518
src/worksheet.c
518
src/worksheet.c
@ -11,7 +11,6 @@
|
|||||||
#include "xlsxwriter/worksheet.h"
|
#include "xlsxwriter/worksheet.h"
|
||||||
#include "xlsxwriter/format.h"
|
#include "xlsxwriter/format.h"
|
||||||
#include "xlsxwriter/utility.h"
|
#include "xlsxwriter/utility.h"
|
||||||
#include "xlsxwriter/relationships.h"
|
|
||||||
#include "xlsxwriter/third_party/md5.h"
|
#include "xlsxwriter/third_party/md5.h"
|
||||||
|
|
||||||
#define LXW_STR_MAX 32767
|
#define LXW_STR_MAX 32767
|
||||||
@ -48,27 +47,27 @@ LXW_RB_GENERATE_DRAWING_REL_IDS(lxw_drawing_rel_ids, lxw_drawing_rel_id,
|
|||||||
lxw_row *
|
lxw_row *
|
||||||
lxw_worksheet_find_row(lxw_worksheet *self, lxw_row_t row_num)
|
lxw_worksheet_find_row(lxw_worksheet *self, lxw_row_t row_num)
|
||||||
{
|
{
|
||||||
lxw_row row;
|
lxw_row tmp_row;
|
||||||
|
|
||||||
row.row_num = row_num;
|
tmp_row.row_num = row_num;
|
||||||
|
|
||||||
return RB_FIND(lxw_table_rows, self->table, &row);
|
return RB_FIND(lxw_table_rows, self->table, &tmp_row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find but don't create a cell object for a given row object and col number.
|
* Find but don't create a cell object for a given row object and col number.
|
||||||
*/
|
*/
|
||||||
lxw_cell *
|
lxw_cell *
|
||||||
lxw_worksheet_find_cell(lxw_row *row, lxw_col_t col_num)
|
lxw_worksheet_find_cell_in_row(lxw_row *row, lxw_col_t col_num)
|
||||||
{
|
{
|
||||||
lxw_cell cell;
|
lxw_cell tmp_cell;
|
||||||
|
|
||||||
if (!row)
|
if (!row)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
cell.col_num = col_num;
|
tmp_cell.col_num = col_num;
|
||||||
|
|
||||||
return RB_FIND(lxw_table_cells, row->cells, &cell);
|
return RB_FIND(lxw_table_cells, row->cells, &tmp_cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -122,6 +121,10 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|||||||
GOTO_LABEL_ON_MEM_ERROR(worksheet->chart_data, mem_error);
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->chart_data, mem_error);
|
||||||
STAILQ_INIT(worksheet->chart_data);
|
STAILQ_INIT(worksheet->chart_data);
|
||||||
|
|
||||||
|
worksheet->comment_objs = calloc(1, sizeof(struct lxw_comment_objs));
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->comment_objs, mem_error);
|
||||||
|
STAILQ_INIT(worksheet->comment_objs);
|
||||||
|
|
||||||
worksheet->selections = calloc(1, sizeof(struct lxw_selections));
|
worksheet->selections = calloc(1, sizeof(struct lxw_selections));
|
||||||
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
|
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
|
||||||
STAILQ_INIT(worksheet->selections);
|
STAILQ_INIT(worksheet->selections);
|
||||||
@ -205,6 +208,7 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
|
|||||||
worksheet->outline_right = LXW_FALSE;
|
worksheet->outline_right = LXW_FALSE;
|
||||||
worksheet->tab_color = LXW_COLOR_UNSET;
|
worksheet->tab_color = LXW_COLOR_UNSET;
|
||||||
worksheet->max_url_length = 2079;
|
worksheet->max_url_length = 2079;
|
||||||
|
worksheet->comment_display_default = LXW_COMMENT_DISPLAY_HIDDEN;
|
||||||
|
|
||||||
if (init_data) {
|
if (init_data) {
|
||||||
worksheet->name = init_data->name;
|
worksheet->name = init_data->name;
|
||||||
@ -227,6 +231,22 @@ mem_error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free a worksheet data_validation.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_free_vml_object(lxw_vml_obj *vml_obj)
|
||||||
|
{
|
||||||
|
if (!vml_obj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(vml_obj->author);
|
||||||
|
free(vml_obj->font_name);
|
||||||
|
free(vml_obj->text);
|
||||||
|
|
||||||
|
free(vml_obj);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free a worksheet cell.
|
* Free a worksheet cell.
|
||||||
*/
|
*/
|
||||||
@ -245,6 +265,8 @@ _free_cell(lxw_cell *cell)
|
|||||||
free(cell->user_data1);
|
free(cell->user_data1);
|
||||||
free(cell->user_data2);
|
free(cell->user_data2);
|
||||||
|
|
||||||
|
_free_vml_object(cell->comment);
|
||||||
|
|
||||||
free(cell);
|
free(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,6 +331,22 @@ _free_data_validation(lxw_data_val_obj *data_validation)
|
|||||||
free(data_validation);
|
free(data_validation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free a relationship structure.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_free_relationship(lxw_rel_tuple *relationship)
|
||||||
|
{
|
||||||
|
if (!relationship)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(relationship->type);
|
||||||
|
free(relationship->target);
|
||||||
|
free(relationship->target_mode);
|
||||||
|
|
||||||
|
free(relationship);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free a worksheet object.
|
* Free a worksheet object.
|
||||||
*/
|
*/
|
||||||
@ -394,6 +432,9 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|||||||
free(worksheet->chart_data);
|
free(worksheet->chart_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Just free the list. The list objects are free elsewhere. */
|
||||||
|
free(worksheet->comment_objs);
|
||||||
|
|
||||||
if (worksheet->selections) {
|
if (worksheet->selections) {
|
||||||
while (!STAILQ_EMPTY(worksheet->selections)) {
|
while (!STAILQ_EMPTY(worksheet->selections)) {
|
||||||
selection = STAILQ_FIRST(worksheet->selections);
|
selection = STAILQ_FIRST(worksheet->selections);
|
||||||
@ -417,30 +458,21 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|||||||
while (!STAILQ_EMPTY(worksheet->external_hyperlinks)) {
|
while (!STAILQ_EMPTY(worksheet->external_hyperlinks)) {
|
||||||
relationship = STAILQ_FIRST(worksheet->external_hyperlinks);
|
relationship = STAILQ_FIRST(worksheet->external_hyperlinks);
|
||||||
STAILQ_REMOVE_HEAD(worksheet->external_hyperlinks, list_pointers);
|
STAILQ_REMOVE_HEAD(worksheet->external_hyperlinks, list_pointers);
|
||||||
free(relationship->type);
|
_free_relationship(relationship);
|
||||||
free(relationship->target);
|
|
||||||
free(relationship->target_mode);
|
|
||||||
free(relationship);
|
|
||||||
}
|
}
|
||||||
free(worksheet->external_hyperlinks);
|
free(worksheet->external_hyperlinks);
|
||||||
|
|
||||||
while (!STAILQ_EMPTY(worksheet->external_drawing_links)) {
|
while (!STAILQ_EMPTY(worksheet->external_drawing_links)) {
|
||||||
relationship = STAILQ_FIRST(worksheet->external_drawing_links);
|
relationship = STAILQ_FIRST(worksheet->external_drawing_links);
|
||||||
STAILQ_REMOVE_HEAD(worksheet->external_drawing_links, list_pointers);
|
STAILQ_REMOVE_HEAD(worksheet->external_drawing_links, list_pointers);
|
||||||
free(relationship->type);
|
_free_relationship(relationship);
|
||||||
free(relationship->target);
|
|
||||||
free(relationship->target_mode);
|
|
||||||
free(relationship);
|
|
||||||
}
|
}
|
||||||
free(worksheet->external_drawing_links);
|
free(worksheet->external_drawing_links);
|
||||||
|
|
||||||
while (!STAILQ_EMPTY(worksheet->drawing_links)) {
|
while (!STAILQ_EMPTY(worksheet->drawing_links)) {
|
||||||
relationship = STAILQ_FIRST(worksheet->drawing_links);
|
relationship = STAILQ_FIRST(worksheet->drawing_links);
|
||||||
STAILQ_REMOVE_HEAD(worksheet->drawing_links, list_pointers);
|
STAILQ_REMOVE_HEAD(worksheet->drawing_links, list_pointers);
|
||||||
free(relationship->type);
|
_free_relationship(relationship);
|
||||||
free(relationship->target);
|
|
||||||
free(relationship->target_mode);
|
|
||||||
free(relationship);
|
|
||||||
}
|
}
|
||||||
free(worksheet->drawing_links);
|
free(worksheet->drawing_links);
|
||||||
|
|
||||||
@ -461,6 +493,9 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|||||||
free(worksheet->drawing_rel_ids);
|
free(worksheet->drawing_rel_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_free_relationship(worksheet->external_vml_comment_link);
|
||||||
|
_free_relationship(worksheet->external_comment_link);
|
||||||
|
|
||||||
if (worksheet->array) {
|
if (worksheet->array) {
|
||||||
for (col = 0; col < LXW_COL_MAX; col++) {
|
for (col = 0; col < LXW_COL_MAX; col++) {
|
||||||
_free_cell(worksheet->array[col]);
|
_free_cell(worksheet->array[col]);
|
||||||
@ -479,6 +514,8 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
|
|||||||
free(worksheet->name);
|
free(worksheet->name);
|
||||||
free(worksheet->quoted_name);
|
free(worksheet->quoted_name);
|
||||||
free(worksheet->vba_codename);
|
free(worksheet->vba_codename);
|
||||||
|
free(worksheet->vml_data_id_str);
|
||||||
|
free(worksheet->comment_author);
|
||||||
|
|
||||||
free(worksheet);
|
free(worksheet);
|
||||||
worksheet = NULL;
|
worksheet = NULL;
|
||||||
@ -758,6 +795,7 @@ _insert_cell_list(struct lxw_table_cells *cell_list,
|
|||||||
/* If existing_cell is not NULL, then that cell already existed. */
|
/* If existing_cell is not NULL, then that cell already existed. */
|
||||||
/* Remove existing_cell and add new one in again. */
|
/* Remove existing_cell and add new one in again. */
|
||||||
if (existing_cell) {
|
if (existing_cell) {
|
||||||
|
existing_cell->comment = NULL;
|
||||||
RB_REMOVE(lxw_table_cells, cell_list, existing_cell);
|
RB_REMOVE(lxw_table_cells, cell_list, existing_cell);
|
||||||
|
|
||||||
/* Add it in again. */
|
/* Add it in again. */
|
||||||
@ -776,6 +814,7 @@ _insert_cell(lxw_worksheet *self, lxw_row_t row_num, lxw_col_t col_num,
|
|||||||
lxw_cell *cell)
|
lxw_cell *cell)
|
||||||
{
|
{
|
||||||
lxw_row *row = _get_row(self, row_num);
|
lxw_row *row = _get_row(self, row_num);
|
||||||
|
lxw_vml_obj *existing_comment = NULL;
|
||||||
|
|
||||||
if (!self->optimize) {
|
if (!self->optimize) {
|
||||||
row->data_changed = LXW_TRUE;
|
row->data_changed = LXW_TRUE;
|
||||||
@ -786,10 +825,14 @@ _insert_cell(lxw_worksheet *self, lxw_row_t row_num, lxw_col_t col_num,
|
|||||||
row->data_changed = LXW_TRUE;
|
row->data_changed = LXW_TRUE;
|
||||||
|
|
||||||
/* Overwrite an existing cell if necessary. */
|
/* Overwrite an existing cell if necessary. */
|
||||||
if (self->array[col_num])
|
if (self->array[col_num]) {
|
||||||
|
existing_comment = self->array[col_num]->comment;
|
||||||
|
self->array[col_num]->comment = NULL;
|
||||||
_free_cell(self->array[col_num]);
|
_free_cell(self->array[col_num]);
|
||||||
|
}
|
||||||
|
|
||||||
self->array[col_num] = cell;
|
self->array[col_num] = cell;
|
||||||
|
self->array[col_num]->comment = existing_comment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -891,6 +934,9 @@ _cell_cmp(lxw_cell *cell1, lxw_cell *cell2)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Comparator for the image/hyperlink relationship ids.
|
||||||
|
*/
|
||||||
STATIC int
|
STATIC int
|
||||||
_drawing_rel_id_cmp(lxw_drawing_rel_id *rel_id1, lxw_drawing_rel_id *rel_id2)
|
_drawing_rel_id_cmp(lxw_drawing_rel_id *rel_id1, lxw_drawing_rel_id *rel_id2)
|
||||||
{
|
{
|
||||||
@ -2087,6 +2133,154 @@ _worksheet_position_object_emus(lxw_worksheet *self,
|
|||||||
drawing_object->row_absolute *= 9525;
|
drawing_object->row_absolute *= 9525;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function handles the additional optional parameters to
|
||||||
|
* worksheet_write_comment_opt() as well as calculating the comment object
|
||||||
|
* position and vertices.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_get_comment_params(lxw_vml_obj *comment, lxw_comment_options *options)
|
||||||
|
{
|
||||||
|
|
||||||
|
lxw_row_t start_row;
|
||||||
|
lxw_col_t start_col;
|
||||||
|
int32_t x_offset;
|
||||||
|
int32_t y_offset;
|
||||||
|
uint32_t height = 74;
|
||||||
|
uint32_t width = 128;
|
||||||
|
double x_scale = 1.0;
|
||||||
|
double y_scale = 1.0;
|
||||||
|
lxw_row_t row = comment->row;
|
||||||
|
lxw_col_t col = comment->col;;
|
||||||
|
|
||||||
|
/* Set the default start cell and offsets for the comment. These are
|
||||||
|
* generally fixed in relation to the parent cell. However there are some
|
||||||
|
* edge cases for cells at the, er, edges. */
|
||||||
|
if (row == 0)
|
||||||
|
y_offset = 2;
|
||||||
|
else if (row == LXW_ROW_MAX - 3)
|
||||||
|
y_offset = 16;
|
||||||
|
else if (row == LXW_ROW_MAX - 2)
|
||||||
|
y_offset = 16;
|
||||||
|
else if (row == LXW_ROW_MAX - 1)
|
||||||
|
y_offset = 14;
|
||||||
|
else
|
||||||
|
y_offset = 10;
|
||||||
|
|
||||||
|
if (col == LXW_COL_MAX - 3)
|
||||||
|
x_offset = 49;
|
||||||
|
else if (col == LXW_COL_MAX - 2)
|
||||||
|
x_offset = 49;
|
||||||
|
else if (col == LXW_COL_MAX - 1)
|
||||||
|
x_offset = 49;
|
||||||
|
else
|
||||||
|
x_offset = 15;
|
||||||
|
|
||||||
|
if (row == 0)
|
||||||
|
start_row = 0;
|
||||||
|
else if (row == LXW_ROW_MAX - 3)
|
||||||
|
start_row = LXW_ROW_MAX - 7;
|
||||||
|
else if (row == LXW_ROW_MAX - 2)
|
||||||
|
start_row = LXW_ROW_MAX - 6;
|
||||||
|
else if (row == LXW_ROW_MAX - 1)
|
||||||
|
start_row = LXW_ROW_MAX - 5;
|
||||||
|
else
|
||||||
|
start_row = row - 1;
|
||||||
|
|
||||||
|
if (col == LXW_COL_MAX - 3)
|
||||||
|
start_col = LXW_COL_MAX - 6;
|
||||||
|
else if (col == LXW_COL_MAX - 2)
|
||||||
|
start_col = LXW_COL_MAX - 5;
|
||||||
|
else if (col == LXW_COL_MAX - 1)
|
||||||
|
start_col = LXW_COL_MAX - 4;
|
||||||
|
else
|
||||||
|
start_col = col + 1;
|
||||||
|
|
||||||
|
/* Set the default font properties. */
|
||||||
|
comment->font_size = 8;
|
||||||
|
comment->font_family = 2;
|
||||||
|
|
||||||
|
/* Set any user defined options. */
|
||||||
|
if (options) {
|
||||||
|
|
||||||
|
if (options->width > 0.0)
|
||||||
|
width = options->width;
|
||||||
|
|
||||||
|
if (options->height > 0.0)
|
||||||
|
height = options->height;
|
||||||
|
|
||||||
|
if (options->x_scale > 0.0)
|
||||||
|
x_scale = options->x_scale;
|
||||||
|
|
||||||
|
if (options->y_scale > 0.0)
|
||||||
|
y_scale = options->y_scale;
|
||||||
|
|
||||||
|
if (options->x_offset != 0)
|
||||||
|
x_offset = options->x_offset;
|
||||||
|
|
||||||
|
if (options->y_offset != 0)
|
||||||
|
y_offset = options->y_offset;
|
||||||
|
|
||||||
|
if (options->start_row > 0 || options->start_col > 0) {
|
||||||
|
start_row = options->start_row;
|
||||||
|
start_col = options->start_col;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options->font_size > 0.0)
|
||||||
|
comment->font_size = options->font_size;
|
||||||
|
|
||||||
|
if (options->font_family > 0)
|
||||||
|
comment->font_family = options->font_family;
|
||||||
|
|
||||||
|
comment->visible = options->visible;
|
||||||
|
comment->color = options->color;
|
||||||
|
comment->author = lxw_strdup(options->author);
|
||||||
|
comment->font_name = lxw_strdup(options->font_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scale the width/height to the default/user scale and round to the
|
||||||
|
* nearest pixel. */
|
||||||
|
width = (uint32_t) (0.5 + x_scale * width);
|
||||||
|
height = (uint32_t) (0.5 + y_scale * height);
|
||||||
|
|
||||||
|
comment->width = width;
|
||||||
|
comment->height = height;
|
||||||
|
comment->start_col = start_col;
|
||||||
|
comment->start_row = start_row;
|
||||||
|
comment->x_offset = x_offset;
|
||||||
|
comment->y_offset = y_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the comment object position and vertices.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
_worksheet_position_vml_object(lxw_worksheet *self, lxw_vml_obj *comment)
|
||||||
|
{
|
||||||
|
lxw_object_properties object_props;
|
||||||
|
lxw_drawing_object drawing_object;
|
||||||
|
|
||||||
|
object_props.col = comment->start_col;
|
||||||
|
object_props.row = comment->start_row;
|
||||||
|
object_props.x_offset = comment->x_offset;
|
||||||
|
object_props.y_offset = comment->y_offset;
|
||||||
|
object_props.width = comment->width;
|
||||||
|
object_props.height = comment->height;
|
||||||
|
|
||||||
|
_worksheet_position_object_pixels(self, &object_props, &drawing_object);
|
||||||
|
|
||||||
|
comment->from.col = drawing_object.from.col;
|
||||||
|
comment->from.row = drawing_object.from.row;
|
||||||
|
comment->from.col_offset = drawing_object.from.col_offset;
|
||||||
|
comment->from.row_offset = drawing_object.from.row_offset;
|
||||||
|
comment->to.col = drawing_object.to.col;
|
||||||
|
comment->to.row = drawing_object.to.row;
|
||||||
|
comment->to.col_offset = drawing_object.to.col_offset;
|
||||||
|
comment->to.row_offset = drawing_object.to.row_offset;
|
||||||
|
comment->col_absolute = drawing_object.col_absolute;
|
||||||
|
comment->row_absolute = drawing_object.row_absolute;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up image/drawings.
|
* Set up image/drawings.
|
||||||
*/
|
*/
|
||||||
@ -2142,7 +2336,6 @@ lxw_worksheet_prepare_image(lxw_worksheet *self,
|
|||||||
width *= 96.0 / object_props->x_dpi;
|
width *= 96.0 / object_props->x_dpi;
|
||||||
height *= 96.0 / object_props->y_dpi;
|
height *= 96.0 / object_props->y_dpi;
|
||||||
|
|
||||||
/* Convert to the nearest pixel. */
|
|
||||||
object_props->width = width;
|
object_props->width = width;
|
||||||
object_props->height = height;
|
object_props->height = height;
|
||||||
|
|
||||||
@ -2187,7 +2380,7 @@ lxw_worksheet_prepare_image(lxw_worksheet *self,
|
|||||||
relationship->target =
|
relationship->target =
|
||||||
lxw_escape_url_characters(url + 1, LXW_TRUE);
|
lxw_escape_url_characters(url + 1, LXW_TRUE);
|
||||||
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
|
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
|
||||||
strncpy(relationship->target, "file:///", sizeof("file:///") - 1);
|
memcpy(relationship->target, "file:///", sizeof("file:///") - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
relationship->target_mode = lxw_strdup("External");
|
relationship->target_mode = lxw_strdup("External");
|
||||||
@ -2345,6 +2538,124 @@ mem_error:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up VML objects, such as comments, in the worksheet.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
lxw_worksheet_prepare_vml_objects(lxw_worksheet *self,
|
||||||
|
uint32_t vml_data_id,
|
||||||
|
uint32_t vml_shape_id,
|
||||||
|
uint32_t vml_drawing_id,
|
||||||
|
uint32_t comment_id)
|
||||||
|
{
|
||||||
|
lxw_row *row;
|
||||||
|
lxw_cell *cell;
|
||||||
|
lxw_rel_tuple *relationship;
|
||||||
|
char filename[LXW_FILENAME_LENGTH];
|
||||||
|
uint32_t comment_count = 0;
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t tmp_data_id;
|
||||||
|
size_t data_str_len = 0;
|
||||||
|
size_t used = 0;
|
||||||
|
char *vml_data_id_str;
|
||||||
|
|
||||||
|
RB_FOREACH(row, lxw_table_rows, self->table) {
|
||||||
|
|
||||||
|
if (row->has_comments) {
|
||||||
|
RB_FOREACH(cell, lxw_table_cells, row->cells) {
|
||||||
|
if (cell->comment) {
|
||||||
|
/* Calculate the worksheet position of the comment. */
|
||||||
|
_worksheet_position_vml_object(self, cell->comment);
|
||||||
|
|
||||||
|
/* Store comment in a simple list for use by packager. */
|
||||||
|
STAILQ_INSERT_TAIL(self->comment_objs, cell->comment,
|
||||||
|
list_pointers);
|
||||||
|
comment_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the VML relationship for comments/buttons/header images. */
|
||||||
|
relationship = calloc(1, sizeof(lxw_rel_tuple));
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
|
||||||
|
|
||||||
|
relationship->type = lxw_strdup("/vmlDrawing");
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
|
||||||
|
|
||||||
|
lxw_snprintf(filename, 32, "../drawings/vmlDrawing%d.vml",
|
||||||
|
vml_drawing_id);
|
||||||
|
|
||||||
|
relationship->target = lxw_strdup(filename);
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
|
||||||
|
|
||||||
|
self->external_vml_comment_link = relationship;
|
||||||
|
|
||||||
|
if (self->has_comments) {
|
||||||
|
/* Only need this relationship object for comment VMLs. */
|
||||||
|
|
||||||
|
relationship = calloc(1, sizeof(lxw_rel_tuple));
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(relationship, mem_error);
|
||||||
|
|
||||||
|
relationship->type = lxw_strdup("/comments");
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(relationship->type, mem_error);
|
||||||
|
|
||||||
|
lxw_snprintf(filename, 32, "../comments%d.xml", comment_id);
|
||||||
|
|
||||||
|
relationship->target = lxw_strdup(filename);
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(relationship->target, mem_error);
|
||||||
|
|
||||||
|
self->external_comment_link = relationship;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The vml.c <o:idmap> element data id contains a comma separated range
|
||||||
|
* when there is more than one 1024 block of comments, like this:
|
||||||
|
* data="1,2,3". Since this could potentially (but unlikely) exceed
|
||||||
|
* LXW_MAX_ATTRIBUTE_LENGTH we need to allocate space dynamically. */
|
||||||
|
|
||||||
|
/* Calculate the total space required for the ID for each 1024 block. */
|
||||||
|
for (i = 0; i <= comment_count / 1024; i++) {
|
||||||
|
tmp_data_id = vml_data_id + i;
|
||||||
|
|
||||||
|
/* Calculate the space required for the digits in the id. */
|
||||||
|
while (tmp_data_id) {
|
||||||
|
data_str_len++;
|
||||||
|
tmp_data_id /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an extra char for comma separator or '\O'. */
|
||||||
|
data_str_len++;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* If this allocation fails it will be dealt with in packager.c. */
|
||||||
|
vml_data_id_str = calloc(1, data_str_len);
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(vml_data_id_str, mem_error);
|
||||||
|
|
||||||
|
/* Create the CSV list in the allocated space. */
|
||||||
|
for (i = 0; i <= comment_count / 1024; i++) {
|
||||||
|
tmp_data_id = vml_data_id + i;
|
||||||
|
lxw_snprintf(vml_data_id_str + used, data_str_len - used, "%d,",
|
||||||
|
tmp_data_id);
|
||||||
|
|
||||||
|
used = strlen(vml_data_id_str);
|
||||||
|
};
|
||||||
|
|
||||||
|
self->vml_shape_id = vml_shape_id;
|
||||||
|
self->vml_data_id_str = vml_data_id_str;
|
||||||
|
|
||||||
|
return comment_count;
|
||||||
|
|
||||||
|
mem_error:
|
||||||
|
if (relationship) {
|
||||||
|
free(relationship->type);
|
||||||
|
free(relationship->target);
|
||||||
|
free(relationship->target_mode);
|
||||||
|
free(relationship);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract width and height information from a PNG file.
|
* Extract width and height information from a PNG file.
|
||||||
*/
|
*/
|
||||||
@ -2986,7 +3297,8 @@ _write_cell(lxw_worksheet *self, lxw_cell *cell, lxw_format *row_format)
|
|||||||
lxw_xml_end_tag(self->file, "c");
|
lxw_xml_end_tag(self->file, "c");
|
||||||
}
|
}
|
||||||
else if (cell->type == BLANK_CELL) {
|
else if (cell->type == BLANK_CELL) {
|
||||||
lxw_xml_empty_tag(self->file, "c", &attributes);
|
if (cell->format)
|
||||||
|
lxw_xml_empty_tag(self->file, "c", &attributes);
|
||||||
}
|
}
|
||||||
else if (cell->type == BOOLEAN_CELL) {
|
else if (cell->type == BOOLEAN_CELL) {
|
||||||
LXW_PUSH_ATTRIBUTES_STR("t", "b");
|
LXW_PUSH_ATTRIBUTES_STR("t", "b");
|
||||||
@ -3032,10 +3344,13 @@ _worksheet_write_rows(lxw_worksheet *self)
|
|||||||
|
|
||||||
_write_row(self, row, spans);
|
_write_row(self, row, spans);
|
||||||
|
|
||||||
RB_FOREACH(cell, lxw_table_cells, row->cells) {
|
if (row->data_changed) {
|
||||||
_write_cell(self, cell, row->format);
|
RB_FOREACH(cell, lxw_table_cells, row->cells) {
|
||||||
|
_write_cell(self, cell, row->format);
|
||||||
|
}
|
||||||
|
|
||||||
|
lxw_xml_end_tag(self->file, "row");
|
||||||
}
|
}
|
||||||
lxw_xml_end_tag(self->file, "row");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3257,10 +3572,10 @@ _worksheet_write_header_footer(lxw_worksheet *self)
|
|||||||
|
|
||||||
lxw_xml_start_tag(self->file, "headerFooter", NULL);
|
lxw_xml_start_tag(self->file, "headerFooter", NULL);
|
||||||
|
|
||||||
if (self->header[0] != '\0')
|
if (*self->header)
|
||||||
_worksheet_write_odd_header(self);
|
_worksheet_write_odd_header(self);
|
||||||
|
|
||||||
if (self->footer[0] != '\0')
|
if (*self->footer)
|
||||||
_worksheet_write_odd_footer(self);
|
_worksheet_write_odd_footer(self);
|
||||||
|
|
||||||
lxw_xml_end_tag(self->file, "headerFooter");
|
lxw_xml_end_tag(self->file, "headerFooter");
|
||||||
@ -3696,6 +4011,31 @@ _worksheet_write_sheet_protection(lxw_worksheet *self,
|
|||||||
LXW_FREE_ATTRIBUTES();
|
LXW_FREE_ATTRIBUTES();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the <legacyDrawing> element.
|
||||||
|
*/
|
||||||
|
STATIC void
|
||||||
|
_worksheet_write_legacy_drawing(lxw_worksheet *self)
|
||||||
|
{
|
||||||
|
struct xml_attribute_list attributes;
|
||||||
|
struct xml_attribute *attribute;
|
||||||
|
char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
|
||||||
|
|
||||||
|
if (!self->has_vml)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
self->rel_count++;
|
||||||
|
|
||||||
|
lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", self->rel_count);
|
||||||
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
|
||||||
|
|
||||||
|
lxw_xml_empty_tag(self->file, "legacyDrawing", &attributes);
|
||||||
|
|
||||||
|
LXW_FREE_ATTRIBUTES();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the <drawing> element.
|
* Write the <drawing> element.
|
||||||
*/
|
*/
|
||||||
@ -3707,9 +4047,7 @@ _worksheet_write_drawing(lxw_worksheet *self, uint16_t id)
|
|||||||
char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
|
char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
|
||||||
|
|
||||||
lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", id);
|
lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", id);
|
||||||
|
|
||||||
LXW_INIT_ATTRIBUTES();
|
LXW_INIT_ATTRIBUTES();
|
||||||
|
|
||||||
LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
|
LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
|
||||||
|
|
||||||
lxw_xml_empty_tag(self->file, "drawing", &attributes);
|
lxw_xml_empty_tag(self->file, "drawing", &attributes);
|
||||||
@ -4065,6 +4403,9 @@ lxw_worksheet_assemble_xml_file(lxw_worksheet *self)
|
|||||||
/* Write the drawing element. */
|
/* Write the drawing element. */
|
||||||
_worksheet_write_drawings(self);
|
_worksheet_write_drawings(self);
|
||||||
|
|
||||||
|
/* Write the legacyDrawing element. */
|
||||||
|
_worksheet_write_legacy_drawing(self);
|
||||||
|
|
||||||
/* Close the worksheet tag. */
|
/* Close the worksheet tag. */
|
||||||
lxw_xml_end_tag(self->file, "worksheet");
|
lxw_xml_end_tag(self->file, "worksheet");
|
||||||
}
|
}
|
||||||
@ -4316,10 +4657,6 @@ worksheet_write_blank(lxw_worksheet *self,
|
|||||||
lxw_cell *cell;
|
lxw_cell *cell;
|
||||||
lxw_error err;
|
lxw_error err;
|
||||||
|
|
||||||
/* Blank cells without formatting are ignored by Excel. */
|
|
||||||
if (!format)
|
|
||||||
return LXW_NO_ERROR;
|
|
||||||
|
|
||||||
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@ -4343,7 +4680,6 @@ worksheet_write_boolean(lxw_worksheet *self,
|
|||||||
lxw_error err;
|
lxw_error err;
|
||||||
|
|
||||||
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -4473,6 +4809,7 @@ worksheet_write_url_opt(lxw_worksheet *self,
|
|||||||
found_string = strchr(url_copy, '#');
|
found_string = strchr(url_copy, '#');
|
||||||
|
|
||||||
if (found_string) {
|
if (found_string) {
|
||||||
|
free(url_string);
|
||||||
url_string = lxw_strdup(found_string + 1);
|
url_string = lxw_strdup(found_string + 1);
|
||||||
GOTO_LABEL_ON_MEM_ERROR(url_string, mem_error);
|
GOTO_LABEL_ON_MEM_ERROR(url_string, mem_error);
|
||||||
|
|
||||||
@ -4735,6 +5072,96 @@ mem_error:
|
|||||||
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a comment to a worksheet cell in Excel.
|
||||||
|
*/
|
||||||
|
lxw_error
|
||||||
|
worksheet_write_comment_opt(lxw_worksheet *self,
|
||||||
|
lxw_row_t row_num, lxw_col_t col_num,
|
||||||
|
char *text, lxw_comment_options *options)
|
||||||
|
{
|
||||||
|
lxw_row *row;
|
||||||
|
lxw_cell *cell;
|
||||||
|
lxw_error err;
|
||||||
|
lxw_vml_obj *comment;
|
||||||
|
uint8_t data_changed = LXW_FALSE;
|
||||||
|
|
||||||
|
if (self->optimize) {
|
||||||
|
LXW_WARN("worksheet_write_comment/opt(): "
|
||||||
|
"Not supported in 'constant_memory' mode.");
|
||||||
|
|
||||||
|
return LXW_ERROR_FEATURE_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!text)
|
||||||
|
return LXW_ERROR_NULL_PARAMETER_IGNORED;
|
||||||
|
|
||||||
|
if (lxw_utf8_strlen(text) > LXW_STR_MAX)
|
||||||
|
return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;
|
||||||
|
|
||||||
|
comment = calloc(1, sizeof(lxw_vml_obj));
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(comment, mem_error);
|
||||||
|
|
||||||
|
comment->text = lxw_strdup(text);
|
||||||
|
GOTO_LABEL_ON_MEM_ERROR(comment->text, mem_error);
|
||||||
|
|
||||||
|
row = lxw_worksheet_find_row(self, row_num);
|
||||||
|
if (row)
|
||||||
|
data_changed = row->data_changed;
|
||||||
|
|
||||||
|
cell = lxw_worksheet_find_cell_in_row(row, col_num);
|
||||||
|
if (cell) {
|
||||||
|
free(cell->comment);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* If there isn't an existing cell we use a new blank cell. */
|
||||||
|
cell = _new_blank_cell(row_num, col_num, NULL);
|
||||||
|
_insert_cell(self, row_num, col_num, cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
comment->row = row_num;
|
||||||
|
comment->col = col_num;
|
||||||
|
|
||||||
|
/* Set user and default parameters for the comment. */
|
||||||
|
_get_comment_params(comment, options);
|
||||||
|
|
||||||
|
cell->comment = comment;
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
row = lxw_worksheet_find_row(self, row_num);
|
||||||
|
row->data_changed = LXW_FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
row->data_changed = data_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
row->has_comments = LXW_TRUE;
|
||||||
|
self->has_vml = LXW_TRUE;
|
||||||
|
self->has_comments = LXW_TRUE;
|
||||||
|
|
||||||
|
return LXW_NO_ERROR;
|
||||||
|
|
||||||
|
mem_error:
|
||||||
|
if (comment)
|
||||||
|
_free_vml_object(comment);
|
||||||
|
|
||||||
|
return LXW_ERROR_MEMORY_MALLOC_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a comment to a worksheet cell in Excel.
|
||||||
|
*/
|
||||||
|
lxw_error
|
||||||
|
worksheet_write_comment(lxw_worksheet *self,
|
||||||
|
lxw_row_t row_num, lxw_col_t col_num, char *string)
|
||||||
|
{
|
||||||
|
return worksheet_write_comment_opt(self, row_num, col_num, string, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the properties of a single column or a range of columns with options.
|
* Set the properties of a single column or a range of columns with options.
|
||||||
*/
|
*/
|
||||||
@ -5960,7 +6387,6 @@ worksheet_insert_chart_opt(lxw_worksheet *self,
|
|||||||
object_props->row = row_num;
|
object_props->row = row_num;
|
||||||
object_props->col = col_num;
|
object_props->col = col_num;
|
||||||
|
|
||||||
/* TODO. Read defaults from chart. */
|
|
||||||
object_props->width = 480;
|
object_props->width = 480;
|
||||||
object_props->height = 288;
|
object_props->height = 288;
|
||||||
|
|
||||||
@ -6289,3 +6715,21 @@ worksheet_set_vba_name(lxw_worksheet *self, const char *name)
|
|||||||
|
|
||||||
return LXW_NO_ERROR;
|
return LXW_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the default author of the cell comments.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
worksheet_set_comments_author(lxw_worksheet *self, const char *author)
|
||||||
|
{
|
||||||
|
self->comment_author = lxw_strdup(author);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make any comments in the worksheet visible, unless explicitly hidden.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
worksheet_show_comments(lxw_worksheet *self)
|
||||||
|
{
|
||||||
|
self->comment_display_default = LXW_COMMENT_DISPLAY_VISIBLE;
|
||||||
|
}
|
||||||
|
23
test/functional/src/test_comment01.c
Normal file
23
test/functional/src/test_comment01.c
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment01.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet, CELL("B2"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
24
test/functional/src/test_comment02.c
Normal file
24
test/functional/src/test_comment02.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment02.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet, CELL("B2"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("D17"), "More text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
24
test/functional/src/test_comment03.c
Normal file
24
test/functional/src/test_comment03.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment03.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet, CELL("A1"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("XFD1048576"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
31
test/functional/src/test_comment04.c
Normal file
31
test/functional/src/test_comment04.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment04.xlsx");
|
||||||
|
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
(void)worksheet2;
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet1, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet1, CELL("B2"), "Some text");
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet3, CELL("A1"), "Bar", NULL);
|
||||||
|
worksheet_write_comment(worksheet3, CELL("C7"), "More text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet1, "John");
|
||||||
|
worksheet_set_comments_author(worksheet3, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
33
test/functional/src/test_comment05.c
Normal file
33
test/functional/src/test_comment05.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment05.xlsx");
|
||||||
|
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
uint32_t row;
|
||||||
|
uint16_t col;
|
||||||
|
|
||||||
|
(void)worksheet2;
|
||||||
|
|
||||||
|
for (row = 0; row <= 127; row++)
|
||||||
|
for (col = 0; col <= 15; col++)
|
||||||
|
worksheet_write_comment(worksheet1, row, col, "Some text");
|
||||||
|
|
||||||
|
worksheet_write_comment(worksheet3, CELL("A1"), "More text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet1, "John");
|
||||||
|
worksheet_set_comments_author(worksheet3, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
31
test/functional/src/test_comment06.c
Normal file
31
test/functional/src/test_comment06.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment06.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
lxw_comment_options options = {.visible = LXW_COMMENT_DISPLAY_VISIBLE};
|
||||||
|
|
||||||
|
|
||||||
|
worksheet_write_comment(worksheet, CELL("A1"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A2"), "Some text");
|
||||||
|
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("A3"), "Some text", &options);
|
||||||
|
|
||||||
|
worksheet_write_comment(worksheet, CELL("A4"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A5"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
28
test/functional/src/test_comment07.c
Normal file
28
test/functional/src/test_comment07.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment07.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_write_comment(worksheet, CELL("A1"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A2"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A3"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A4"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A5"), "Some text");
|
||||||
|
|
||||||
|
worksheet_show_comments(worksheet);
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
31
test/functional/src/test_comment08.c
Normal file
31
test/functional/src/test_comment08.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment08.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
lxw_comment_options options1 = {.visible = LXW_COMMENT_DISPLAY_HIDDEN};
|
||||||
|
lxw_comment_options options2 = {.visible = LXW_COMMENT_DISPLAY_VISIBLE};
|
||||||
|
|
||||||
|
worksheet_write_comment(worksheet, CELL("A1"), "Some text");
|
||||||
|
worksheet_write_comment(worksheet, CELL("A2"), "Some text");
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("A3"), "Some text", &options1);
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("A4"), "Some text", &options2);
|
||||||
|
worksheet_write_comment(worksheet, CELL("A5"), "Some text");
|
||||||
|
|
||||||
|
worksheet_show_comments(worksheet);
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
28
test/functional/src/test_comment09.c
Normal file
28
test/functional/src/test_comment09.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment09.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
lxw_comment_options options1 = {.author = "John"};
|
||||||
|
lxw_comment_options options2 = {.author = "Perl"};
|
||||||
|
|
||||||
|
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("A1"), "Some text", &options1);
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("A2"), "Some text", &options2);
|
||||||
|
worksheet_write_comment(worksheet, CELL("A3"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
25
test/functional/src/test_comment10.c
Normal file
25
test/functional/src/test_comment10.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment10.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
lxw_comment_options options = {.color = 0x98FE97};
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("B2"), "Some text", &options);
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
26
test/functional/src/test_comment11.c
Normal file
26
test/functional/src/test_comment11.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment11.xlsx");
|
||||||
|
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
(void)worksheet1;
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet2, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet2, CELL("B2"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet2, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
26
test/functional/src/test_comment12.c
Normal file
26
test/functional/src/test_comment12.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment12.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_set_row(worksheet, 0, 21, NULL);
|
||||||
|
worksheet_set_column(worksheet, 1, 1, 10, NULL);
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet, CELL("A1"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
26
test/functional/src/test_comment13.c
Normal file
26
test/functional/src/test_comment13.c
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment13.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
lxw_comment_options options = {.font_name = "Courier", .font_size = 10, .font_family = 3};
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
|
||||||
|
worksheet_write_comment_opt(worksheet, CELL("B2"), "Some text", &options);
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
25
test/functional/src/test_comment14.c
Normal file
25
test/functional/src/test_comment14.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Test cases for libxlsxwriter.
|
||||||
|
*
|
||||||
|
* Test to compare output against Excel files.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xlsxwriter.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
lxw_workbook *workbook = workbook_new("test_comment14.xlsx");
|
||||||
|
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
|
||||||
|
|
||||||
|
worksheet_write_string(worksheet, CELL("A1"), "Foo", NULL);
|
||||||
|
worksheet_write_comment(worksheet, CELL("B2"), "Some text");
|
||||||
|
|
||||||
|
worksheet_set_column(worksheet, 2, 2, 13, NULL);
|
||||||
|
|
||||||
|
worksheet_set_comments_author(worksheet, "John");
|
||||||
|
|
||||||
|
return workbook_close(workbook);
|
||||||
|
}
|
57
test/functional/test_comment.py
Normal file
57
test/functional/test_comment.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Tests for libxlsxwriter.
|
||||||
|
#
|
||||||
|
# Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
#
|
||||||
|
|
||||||
|
import base_test_class
|
||||||
|
|
||||||
|
class TestCompareXLSXFiles(base_test_class.XLSXBaseTest):
|
||||||
|
"""
|
||||||
|
Test file created with libxlsxwriter against a file created by Excel.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_comment01(self):
|
||||||
|
self.run_exe_test('test_comment01')
|
||||||
|
|
||||||
|
def test_comment02(self):
|
||||||
|
self.run_exe_test('test_comment02')
|
||||||
|
|
||||||
|
def test_comment03(self):
|
||||||
|
self.run_exe_test('test_comment03')
|
||||||
|
|
||||||
|
def test_comment04(self):
|
||||||
|
self.run_exe_test('test_comment04')
|
||||||
|
|
||||||
|
def test_comment05(self):
|
||||||
|
self.run_exe_test('test_comment05')
|
||||||
|
|
||||||
|
def test_comment06(self):
|
||||||
|
self.run_exe_test('test_comment06')
|
||||||
|
|
||||||
|
def test_comment07(self):
|
||||||
|
self.run_exe_test('test_comment07')
|
||||||
|
|
||||||
|
def test_comment08(self):
|
||||||
|
self.run_exe_test('test_comment08')
|
||||||
|
|
||||||
|
def test_comment09(self):
|
||||||
|
self.run_exe_test('test_comment09')
|
||||||
|
|
||||||
|
def test_comment10(self):
|
||||||
|
self.run_exe_test('test_comment10')
|
||||||
|
|
||||||
|
def test_comment11(self):
|
||||||
|
self.run_exe_test('test_comment11')
|
||||||
|
|
||||||
|
def test_comment12(self):
|
||||||
|
self.run_exe_test('test_comment12')
|
||||||
|
|
||||||
|
def test_comment13(self):
|
||||||
|
self.ignore_files = ['xl/styles.xml']
|
||||||
|
self.run_exe_test('test_comment13')
|
||||||
|
|
||||||
|
def test_comment14(self):
|
||||||
|
self.run_exe_test('test_comment14')
|
BIN
test/functional/xlsx_files/comment01.xlsx
Normal file
BIN
test/functional/xlsx_files/comment01.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment02.xlsx
Normal file
BIN
test/functional/xlsx_files/comment02.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment03.xlsx
Normal file
BIN
test/functional/xlsx_files/comment03.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment04.xlsx
Normal file
BIN
test/functional/xlsx_files/comment04.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment05.xlsx
Normal file
BIN
test/functional/xlsx_files/comment05.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment06.xlsx
Normal file
BIN
test/functional/xlsx_files/comment06.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment07.xlsx
Normal file
BIN
test/functional/xlsx_files/comment07.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment08.xlsx
Normal file
BIN
test/functional/xlsx_files/comment08.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment09.xlsx
Normal file
BIN
test/functional/xlsx_files/comment09.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment10.xlsx
Normal file
BIN
test/functional/xlsx_files/comment10.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment11.xlsx
Normal file
BIN
test/functional/xlsx_files/comment11.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment12.xlsx
Normal file
BIN
test/functional/xlsx_files/comment12.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment13.xlsx
Normal file
BIN
test/functional/xlsx_files/comment13.xlsx
Normal file
Binary file not shown.
BIN
test/functional/xlsx_files/comment14.xlsx
Normal file
BIN
test/functional/xlsx_files/comment14.xlsx
Normal file
Binary file not shown.
@ -38,6 +38,8 @@ SRCS += $(wildcard drawing/test*.c)
|
|||||||
SRCS += $(wildcard chart/test*.c)
|
SRCS += $(wildcard chart/test*.c)
|
||||||
SRCS += $(wildcard custom/test*.c)
|
SRCS += $(wildcard custom/test*.c)
|
||||||
SRCS += $(wildcard chartsheet/test*.c)
|
SRCS += $(wildcard chartsheet/test*.c)
|
||||||
|
SRCS += $(wildcard vml/test*.c)
|
||||||
|
SRCS += $(wildcard comment/test*.c)
|
||||||
# End of SRCS
|
# End of SRCS
|
||||||
|
|
||||||
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
@ -72,6 +74,8 @@ all :
|
|||||||
$(Q)$(MAKE) -C chart
|
$(Q)$(MAKE) -C chart
|
||||||
$(Q)$(MAKE) -C custom
|
$(Q)$(MAKE) -C custom
|
||||||
$(Q)$(MAKE) -C chartsheet
|
$(Q)$(MAKE) -C chartsheet
|
||||||
|
$(Q)$(MAKE) -C vml
|
||||||
|
$(Q)$(MAKE) -C comment
|
||||||
# END make all
|
# END make all
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
@ -90,6 +94,8 @@ clean :
|
|||||||
$(Q)$(MAKE) clean -C chart
|
$(Q)$(MAKE) clean -C chart
|
||||||
$(Q)$(MAKE) clean -C custom
|
$(Q)$(MAKE) clean -C custom
|
||||||
$(Q)$(MAKE) clean -C chartsheet
|
$(Q)$(MAKE) clean -C chartsheet
|
||||||
|
$(Q)$(MAKE) clean -C vml
|
||||||
|
$(Q)$(MAKE) clean -C comment
|
||||||
# END make clean
|
# END make clean
|
||||||
|
|
||||||
|
|
||||||
|
8
test/unit/comment/Makefile
Normal file
8
test/unit/comment/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Makefile for libxlsxwriter library.
|
||||||
|
#
|
||||||
|
# Copyright 2014-2015, John McNamara, jmcnamara@cpan.org
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Makefile.unit
|
15
test/unit/comment/main.c
Normal file
15
test/unit/comment/main.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Test runner for xmlwriter using ctest.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019 John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define CTEST_MAIN
|
||||||
|
|
||||||
|
#include "../ctest.h"
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
return ctest_main(argc, argv);
|
||||||
|
}
|
||||||
|
|
28
test/unit/comment/test_comment_xml_declaration.c
Normal file
28
test/unit/comment/test_comment_xml_declaration.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Tests for the libxlsxwriter library.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../ctest.h"
|
||||||
|
#include "../helper.h"
|
||||||
|
|
||||||
|
#include "xlsxwriter/comment.h"
|
||||||
|
|
||||||
|
// Test _xml_declaration().
|
||||||
|
CTEST(comment, xml_declaration) {
|
||||||
|
|
||||||
|
char* got;
|
||||||
|
char exp[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
||||||
|
FILE* testfile = tmpfile();
|
||||||
|
|
||||||
|
lxw_comment *comment = lxw_comment_new();
|
||||||
|
comment->file = testfile;
|
||||||
|
|
||||||
|
_comment_xml_declaration(comment);
|
||||||
|
|
||||||
|
RUN_XLSX_STREQ(exp, got);
|
||||||
|
|
||||||
|
lxw_comment_free(comment);
|
||||||
|
}
|
8
test/unit/vml/Makefile
Normal file
8
test/unit/vml/Makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# Makefile for libxlsxwriter library.
|
||||||
|
#
|
||||||
|
# Copyright 2014-2019, John McNamara, jmcnamara@cpan.org
|
||||||
|
#
|
||||||
|
|
||||||
|
include ../Makefile.unit
|
15
test/unit/vml/main.c
Normal file
15
test/unit/vml/main.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Test runner for xmlwriter using ctest.
|
||||||
|
*
|
||||||
|
* Copyright 2014-2019 John McNamara, jmcnamara@cpan.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define CTEST_MAIN
|
||||||
|
|
||||||
|
#include "../ctest.h"
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
return ctest_main(argc, argv);
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user