enum reader_state
{
- STATE_INIT = 0, /* Initial state */
+ STATE_PRE_INIT = 0, /* Initial state */
+ STATE_SHEET_COUNT, /* Found the sheet index */
+ STATE_INIT , /* Other Initial state */
STATE_SHEET_START, /* Found the start of a sheet */
STATE_SHEET_NAME, /* Found the sheet name */
STATE_MAXROW,
struct gnumeric_reader
{
+ struct spreadsheet spreadsheet;
+
xmlTextReaderPtr xtr;
enum reader_state state;
+
+ /* The total number of sheets in the "workbook" */
+ int sheet_total ;
+
int row;
int col;
int min_col;
switch ( r->state)
{
+ case STATE_PRE_INIT:
+ if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) &&
+ XML_READER_TYPE_ELEMENT == r->node_type)
+ {
+ r->state = STATE_SHEET_COUNT;
+ r->sheet_total = 0;
+ }
+ break;
+
+ case STATE_SHEET_COUNT:
+ if (0 == xmlStrcasecmp (name, _xml("gnm:SheetName")) &&
+ XML_READER_TYPE_ELEMENT == r->node_type)
+ {
+ r->sheet_total++;
+ }
+ else if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) &&
+ XML_READER_TYPE_END_ELEMENT == r->node_type)
+ {
+ r->state = STATE_INIT;
+ }
+ break;
+
case STATE_INIT:
if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) &&
XML_READER_TYPE_ELEMENT == r->node_type)
xmlChar *first_value;
};
+struct spreadsheet *
+gnumeric_probe (const char *filename)
+{
+ int ret;
+ struct gnumeric_reader *r = NULL;
+ xmlTextReaderPtr xtr;
+
+ gzFile gz = gzopen (filename, "r");
+
+ if (NULL == gz)
+ return NULL;
+
+ xtr = xmlReaderForIO ((xmlInputReadCallback) gzread,
+ (xmlInputCloseCallback) gzclose, gz,
+ NULL, NULL, 0);
+
+ if (xtr == NULL)
+ return NULL;
+
+ r = xzalloc (sizeof *r);
+
+ r->xtr = xtr;
+ r->sheet_total = -1;
+ r->state = STATE_PRE_INIT;
+
+
+ /* Advance to the start of the workbook.
+ This gives us some confidence that we are actually dealing with a gnumeric
+ spreadsheet.
+ */
+ while ( (r->state != STATE_INIT )
+ && 1 == (ret = xmlTextReaderRead (r->xtr)))
+ {
+ process_node (r);
+ }
+
+ if (ret != 1)
+ {
+ /* Not a gnumeric spreadsheet */
+ free (r);
+ gzclose (gz);
+ return NULL;
+ }
+
+ r->spreadsheet.type = SPREADSHEET_GNUMERIC;
+ r->spreadsheet.sheets = r->sheet_total;
+ r->spreadsheet.make_reader = NULL;
+
+
+ return &r->spreadsheet;
+}
+
struct casereader *
gnumeric_open_reader (const struct spreadsheet_read_info *gri,
struct spreadsheet_read_options *opts,
struct var_spec *var_spec = NULL;
int n_var_specs = 0;
+ struct spreadsheet * spreadsheet = NULL;
struct gnumeric_reader *r = NULL;
- gzFile gz = gzopen (gri->file_name, "r");
-
- if ( NULL == gz)
- {
- msg (ME, _("Error opening `%s' for reading as a Gnumeric file: %s."),
- gri->file_name, strerror (errno));
-
- goto error;
- }
-
- r = xzalloc (sizeof *r);
+ spreadsheet = gnumeric_probe (gri->file_name);
- r->xtr = xmlReaderForIO ((xmlInputReadCallback) gzread,
- (xmlInputCloseCallback) gzclose, gz,
- NULL, NULL, 0);
-
- if ( r->xtr == NULL )
+ if (spreadsheet == NULL)
goto error;
+ r = (struct gnumeric_reader *) (spreadsheet);
+
if ( opts->cell_range )
{
if ( ! convert_cell_ref (opts->cell_range,
r->stop_row = -1;
}
- r->state = STATE_INIT;
+
r->target_sheet = BAD_CAST opts->sheet_name;
r->target_sheet_index = opts->sheet_index;
r->row = r->col = -1;
struct spreadsheet_read_info;
struct spreadsheet_read_options;
+
+struct spreadsheet *gnumeric_probe (const char *filename);
+
struct casereader * gnumeric_open_reader (const struct spreadsheet_read_info *,
struct spreadsheet_read_options *,
struct dictionary **);
struct ods_reader
{
+ struct spreadsheet spreadsheet;
+
xmlTextReaderPtr xtr;
enum reader_state state;
#include <stdio.h>
#include <string.h>
+
+struct spreadsheet *
+spreadsheet_open (const char *filename)
+{
+ struct spreadsheet *ss = NULL;
+
+ ss = gnumeric_probe (filename);
+
+ return ss;
+}
+
+void
+spreadsheet_close (struct spreadsheet *spreadsheet)
+{
+}
+
+
+
/* Convert a string, which is an integer encoded in base26
IE, A=0, B=1, ... Z=25 to the integer it represents.
... except that in this scheme, digits with an exponent
#define _xmlchar_to_int(X) (atoi(CHAR_CAST (const char *, X)))
+enum spreadsheet_type
+ {
+ SPREADSHEET_GNUMERIC,
+ SPREADSHEET_ODS
+ };
+
+struct spreadsheet
+{
+ enum spreadsheet_type type;
+
+ struct casereader * (*make_reader) (struct spreadsheet *);
+
+ /* The total number of sheets in the "workbook" */
+ int sheets;
+
+ /* The dictionary */
+ struct dictionary *dict;
+};
+
+/*
+ Attempt to open the file called FILENAME as a spreadsheet.
+ It is not known a priori, what type of spreadsheet FILENAME is, or
+ even if it is a spreadsheet at all.
+ If it fails to open, then it will return NULL without any error or
+ warning messages.
+ */
+struct spreadsheet * spreadsheet_open (const char *filename);
+void spreadsheet_close (struct spreadsheet *);
+
+struct casereeader;
+struct casereader * spreadsheet_make_reader (struct spreadsheet *s);
+
+
+#define SPREADSHEET_CAST(X) ((struct spreadsheet *)(X))
#endif
else
gtk_widget_grab_focus (assistant->forward);
+
+ /* Prepare .... */
if (page == ia->separators.page)
prepare_separators_page (ia);
else if (page == ia->formats.page)
prepare_formats_page (ia);
+ else if (page == ia->sheet_spec.page)
+ prepare_sheet_spec_page (ia);
+
+
gtk_widget_show (ia->asst.reset_button);
if (page == ia->formats.page)
gtk_widget_show (ia->asst.paste_button);
{
enum { MAX_LINE_LEN = 16384 }; /* Max length of an acceptable line. */
struct file *file = &ia->file;
- struct casereader *creader = NULL;
- struct dictionary *dict = NULL;
+ struct sheet_spec_page *ssp = &ia->sheet_spec;
struct spreadsheet_read_info sri;
struct spreadsheet_read_options opts;
sri.read_names = true;
sri.asw = -1;
- if (!creader)
- {
- creader = gnumeric_open_reader (&sri, &opts, &dict);
- ia->file.type = FTYPE_GNUMERIC;
- }
-
- if (!creader)
+ ssp->spreadsheet = gnumeric_probe (sri.file_name);
+
+ if (ssp->spreadsheet)
{
- creader = ods_open_reader (&sri, &opts, &dict);
- ia->file.type = FTYPE_ODS;
- }
+ struct casereader *creader = NULL;
+ struct dictionary *dict = NULL;
+
+ if (ssp->spreadsheet->type == SPREADSHEET_GNUMERIC)
+ {
+ ia->file.type = FTYPE_GNUMERIC;
+ }
+ else if (ssp->spreadsheet->type == SPREADSHEET_ODS)
+ {
+ ia->file.type = FTYPE_ODS;
+ }
+ else
+ {
+ assert (0);
+ }
- if (creader && dict)
- {
- struct sheet_spec_page *ssp = &ia->sheet_spec;
- ssp->dict = dict;
- ssp->reader = creader;
+ {
+ struct sheet_spec_page *ssp = &ia->sheet_spec;
+ ssp->dict = dict;
+ ssp->reader = creader;
+
+ update_assistant (ia);
+ }
- update_assistant (ia);
}
else
{
}
+/* Prepares IA's sheet_spec page. */
+void
+prepare_sheet_spec_page (struct import_assistant *ia)
+{
+ struct sheet_spec_page *p = &ia->sheet_spec;
+
+ GtkBuilder *builder = ia->asst.builder;
+ GtkWidget *sheet_entry = get_widget_assert (builder, "sheet-entry");
+
+ printf ("%s %d\n", __FUNCTION__, p->spreadsheet->sheets);
+
+ gtk_spin_button_set_digits (GTK_SPIN_BUTTON (sheet_entry), 0);
+ gtk_spin_button_set_range (GTK_SPIN_BUTTON (sheet_entry), 1, p->spreadsheet->sheets);
+}
+
+
/* Resets IA's sheet_spec page to its initial state. */
void
reset_sheet_spec_page (struct import_assistant *ia)
GtkWidget *range_entry = get_widget_assert (builder, "cell-range-entry");
GtkWidget *readnames_checkbox = get_widget_assert (builder, "readnames-checkbox");
- gint num = atoi (gtk_entry_get_text (GTK_ENTRY (sheet_entry)));
+ gint num = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (sheet_entry));
const gchar *range = gtk_entry_get_text (GTK_ENTRY (range_entry));
-
if ( num < 1 )
num = 1;
ssp->opts.sheet_name = NULL;
- ssp->opts.cell_range = range;
+ ssp->opts.cell_range = NULL;
ssp->opts.sheet_index = num;
if ( convert_cell_ref (range, &col_start, &row_start, &col_stop, &row_stop))
GtkWidget *page;
struct casereader *reader;
struct dictionary *dict;
-
+ struct spreadsheet *spreadsheet;
+
struct spreadsheet_read_info sri;
struct spreadsheet_read_options opts;
};
void reset_intro_page (struct import_assistant *);
void init_sheet_spec_page (struct import_assistant *);
+void prepare_sheet_spec_page (struct import_assistant *ia);
void reset_sheet_spec_page (struct import_assistant *);
void post_sheet_spec_page (struct import_assistant *ia);
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkAdjustment" id="adjustment3">
+ <property name="value">1</property>
+ <property name="upper">100</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
<object class="GtkWindow" id="Sheet">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">12</property>
</packing>
</child>
<child>
- <object class="GtkEntry" id="sheet-entry">
+ <object class="GtkSpinButton" id="sheet-entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
+ <property name="adjustment">adjustment3</property>
</object>
<packing>
<property name="left_attach">1</property>