Merge remote-tracking branch 'origin/master' into sheet
authorJohn Darrington <john@darrington.wattle.id.au>
Sun, 10 Jul 2016 05:47:34 +0000 (07:47 +0200)
committerJohn Darrington <john@darrington.wattle.id.au>
Sun, 10 Jul 2016 05:47:34 +0000 (07:47 +0200)
37 files changed:
NEWS
README.Git
doc/statistics.texi
src/data/casereader-filter.c
src/data/gnumeric-reader.c
src/data/ods-reader.c
src/language/data-io/.gitignore [deleted file]
src/language/data-io/automake.mk
src/language/data-io/file-handle.c [new file with mode: 0644]
src/language/data-io/file-handle.q [deleted file]
src/language/data-io/get-data.c
src/language/expressions/helpers.c
src/language/lexer/format-parser.c
src/language/stats/crosstabs.q
src/language/stats/frequencies.c
src/language/stats/glm.c
src/output/charts/scatterplot-cairo.c
src/output/tab.c
src/ui/gui/automake.mk
src/ui/gui/data-editor.ui
src/ui/gui/help-menu.c
src/ui/gui/psppire-dialog-action-indep-samps.c
src/ui/gui/psppire-dialog-action-indep-samps.h
src/ui/gui/psppire-dialog-action-recode-different.c [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-recode-different.h [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-recode-same.c [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-recode-same.h [new file with mode: 0644]
src/ui/gui/psppire-dialog-action-recode.c
src/ui/gui/psppire-dialog-action-recode.h
src/ui/gui/psppire-dialog-action-var-info.c
src/ui/gui/psppire-window.c
src/ui/gui/widgets.c
tests/language/data-io/get-data-txt.at
tests/language/stats/crosstabs.at
tests/language/stats/frequencies.at
tests/language/stats/glm.at
tests/testsuite.in

diff --git a/NEWS b/NEWS
index 3b37cd78cf1ffe8595b69682e47df2b4adc6f962..7391ff4cc5495ef87838d547282dde952de39131 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,10 +3,29 @@ Copyright (C) 1996-2000, 2008-2016 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
+
 Changes from 0.10.1 to 0.10.2:
 
- (nothing yet)
+ * CROSSTABS implements a new COUNT subcommand to round case or cell
+   weights.
+
+ * Help will be opened as HTML in default browser if yelp
+   is not available.
+
+ * When plotting scatterplots with only one dataset (the simple case)
+   the colour used for the dataset is now black.  The previous default
+   from the Tango palette was too faint to see easily.
+
+ * Bug fixes, including the following:
+
+   - T-test with independent samples GUI crashed with string
+     type variable as group variable.
+
+   - The variable info dialog showed the previous selected variable
+     superimposed with the currently selected one.
+
+   - The GLM command did not properly deal with missing values.  This
+     has been fixed.
 
 Changes from 0.10.0 to 0.10.1:
 
index 8333600457eba7e3b99a3be97e16a1b302e1f03d..123665095b0e9a0f3d623251e414cf8c5385146b 100644 (file)
@@ -36,14 +36,11 @@ This version of PSPP should work with the Gnulib commit shown below.
 Gnulib does not maintain a stable API or ABI, so it is possible that
 PSPP will not work with older or newer versions of Gnulib.
 
-       commit c5c4f53b31f1ad04f4033a6124120ffec9257847
-       Author: Pádraig Brady <P@draigBrady.com>
-       Date:   Sat Dec 6 01:14:02 2014 +0000
+       commit baef0a4b9433d00e59c586b9eaad67d8461d7324
+       Author: Karl Berry <karl@freefriends.org>
+       Date:   Tue Jun 14 09:05:27 2016 -0700
 
-           vasnprintf: fix potential use after free
-
-           * lib/vasnprintf.c (VASNPRINTF): Fix free-memory read,
-           flagged by clang-analyzer 3.4.2.
+           autoupdate
 
 To clone Gnulib into a directory named "gnulib" using Git, and then
 check out this particular commit, run these commands:
index 9774c514aa7435081336084ae32e4f196fe8b8e6..e18c6109dba73f69aed403bcd4c677980ab48690 100644 (file)
@@ -597,6 +597,8 @@ CROSSTABS
                 @{BOX,NOBOX@}
         /CELLS=@{COUNT,ROW,COLUMN,TOTAL,EXPECTED,RESIDUAL,SRESIDUAL,
                 ASRESIDUAL,ALL,NONE@}
+        /COUNT=@{ASIS,CASE,CELL@}
+               @{ROUND,TRUNCATE@}
         /STATISTICS=@{CHISQ,PHI,CC,LAMBDA,UC,BTAU,CTAU,RISK,GAMMA,D,
                      KAPPA,ETA,CORR,ALL,NONE@}
         /BARCHART
@@ -696,6 +698,15 @@ Suppress cells entirely.
 If @subcmd{CELLS} is not specified at all then only @subcmd{COUNT}
 will be selected.
 
+By default, crosstabulation and statistics use raw case weights,
+without rounding.  Use the @subcmd{/COUNT} subcommand to perform
+rounding: CASE rounds the weights of individual weights as cases are
+read, CELL rounds the weights of cells within each crosstabulation
+table after it has been constructed, and ASIS explicitly specifies the
+default non-rounding behavior.  When rounding is requested, ROUND, the
+default, rounds to the nearest integer and TRUNCATE rounds toward
+zero.
+
 The @subcmd{STATISTICS} subcommand selects statistics for computation:
 
 @table @asis
@@ -940,12 +951,13 @@ implies the model
 
 The @subcmd{MISSING} subcommand determines the handling of missing
 variables.  
-If @subcmd{INCLUDE} is set, then user-missing values are included in the
-calculations, but system-missing values are not.
-If @subcmd{EXCLUDE} is set, which is the default, user-missing
-values are excluded as well as system-missing values. 
-This is the default.
-
+If @subcmd{INCLUDE} is set then, for the purposes of GLM analysis,
+only system-missing values are considered
+to be missing; user-missing values are not regarded as missing.
+If @subcmd{EXCLUDE} is set, which is the default, then user-missing
+values are considered to be missing as well as system-missing values. 
+A case for which any dependent variable or any factor
+variable has a missing value is excluded from the analysis.
 
 @node LOGISTIC REGRESSION
 @section LOGISTIC REGRESSION
index 15fa4a5e6701605ec107fe43a599fab71d48f043..5b6cf06b72cbd92c17dd3697f9b863b1de8461da 100644 (file)
@@ -266,7 +266,7 @@ static bool casereader_filter_missing_destroy (void *);
    is destroyed.
 
    If N_MISSING is non-null, then after reading, it will be filled
-   with the totla number of dropped cases.
+   with the total number of dropped cases.
 
    After this function is called, READER must not ever again
    be referenced directly.  It will be destroyed automatically
index 7033448d8b4dc23a7c63b2d967854d551e0f47d9..ba4218ff77ef093999b73c24d62e2f19052f30ee 100644 (file)
@@ -38,6 +38,19 @@ gnumeric_open_reader (const struct spreadsheet_read_options *opts, struct dictio
   return NULL;
 }
 
+struct casereader *
+gnumeric_make_reader (struct spreadsheet *spreadsheet,
+                     const struct spreadsheet_read_options *opts)
+{
+  return NULL;
+}
+
+void
+gnumeric_unref (struct spreadsheet *r)
+{
+}
+
+
 #else
 
 #include "data/gnumeric-reader.h"
index 2f058b044d8ac8892115ff53b498a96e7f8c78bf..c2e7a0e354933309d4610574a73007342ec8d61b 100644 (file)
@@ -43,6 +43,19 @@ ods_open_reader (const struct spreadsheet_read_options *opts,
   return NULL;
 }
 
+struct casereader *
+ods_make_reader (struct spreadsheet *spreadsheet,
+                const struct spreadsheet_read_options *opts)
+{
+  return NULL;
+}
+
+
+void
+ods_unref (struct spreadsheet *r)
+{
+}
+
 #else
 
 #include "libpspp/zip-reader.h"
diff --git a/src/language/data-io/.gitignore b/src/language/data-io/.gitignore
deleted file mode 100644 (file)
index cd41310..0000000
+++ /dev/null
@@ -1 +0,0 @@
-file-handle.c
index 906a8ed15816e2f2bbb62d9268f45eb29e1fc4ab..770300ee7739005cd7e41bf5b8a8893b602adb16 100644 (file)
@@ -1,8 +1,5 @@
 ## Process this file with automake to produce Makefile.in  -*- makefile -*-
 
-src_language_data_io_built_sources = \
-       src/language/data-io/file-handle.c
-
 language_data_io_sources = \
        src/language/data-io/combine-files.c \
        src/language/data-io/data-list.c \
@@ -13,6 +10,7 @@ language_data_io_sources = \
        src/language/data-io/data-writer.c \
        src/language/data-io/data-writer.h \
        src/language/data-io/dataset.c \
+       src/language/data-io/file-handle.c \
        src/language/data-io/file-handle.h \
        src/language/data-io/get-data.c \
        src/language/data-io/get.c \
@@ -27,7 +25,3 @@ language_data_io_sources = \
        src/language/data-io/save.c \
        src/language/data-io/trim.c \
        src/language/data-io/trim.h
-
-all_q_sources += $(src_language_data_io_built_sources:.c=.q)
-EXTRA_DIST += $(src_language_data_io_built_sources:.c=.q)
-CLEANFILES += $(src_language_data_io_built_sources)
diff --git a/src/language/data-io/file-handle.c b/src/language/data-io/file-handle.c
new file mode 100644 (file)
index 0000000..8d65418
--- /dev/null
@@ -0,0 +1,378 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-2000, 2006, 2010-2013, 2016 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "data/file-handle-def.h"
+
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "data/file-name.h"
+#include "data/session.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
+
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+int
+cmd_file_handle (struct lexer *lexer, struct dataset *ds UNUSED)
+{
+  enum cmd_result result = CMD_CASCADING_FAILURE;
+  char *handle_name = NULL;
+  char *file_name = NULL;
+  int lrecl = 0;
+  int tabwidth = -1;
+  enum { MODE_DEFAULT, MODE_CHARACTER, MODE_BINARY, MODE_IMAGE, MODE_360 }
+      mode = MODE_DEFAULT;
+  int ends = -1;
+  enum { RECFORM_FIXED = 1, RECFORM_VARIABLE, RECFORM_SPANNED } recform = 0;
+  char *encoding = NULL;
+
+  if (!lex_force_id (lexer))
+    goto exit;
+
+  handle_name = xstrdup (lex_tokcstr (lexer));
+  if (fh_from_id (handle_name))
+    {
+      msg (SE, _("File handle %s is already defined.  "
+                 "Use %s before redefining a file handle."),
+          handle_name, "CLOSE FILE HANDLE");
+      goto exit;
+    }
+
+  lex_get (lexer);
+  if (!lex_force_match (lexer, T_SLASH))
+    goto exit;
+
+  while (lex_token (lexer) != T_ENDCMD)
+    {
+      if (lex_match_id (lexer, "NAME"))
+        {
+          if (file_name)
+            {
+              lex_sbc_only_once ("NAME");
+              goto exit;
+            }
+
+          lex_match (lexer, T_EQUALS);
+          if (!lex_force_string (lexer))
+            goto exit;
+          free (file_name);
+          file_name = ss_xstrdup (lex_tokss (lexer));
+          lex_get (lexer);
+        }
+      else if (lex_match_id (lexer, "LRECL"))
+        {
+          if (lrecl)
+            {
+              lex_sbc_only_once ("LRECL");
+              goto exit;
+            }
+
+          lex_match (lexer, T_EQUALS);
+          if (!lex_force_int (lexer))
+            goto exit;
+          lrecl = lex_integer (lexer);
+          lex_get (lexer);
+        }
+      else if (lex_match_id (lexer, "TABWIDTH"))
+        {
+          if (tabwidth >= 0)
+            {
+              lex_sbc_only_once ("TABWIDTH");
+              goto exit;
+            }
+          lex_match (lexer, T_EQUALS);
+
+          if (!lex_force_int (lexer))
+            goto exit;
+          tabwidth = lex_integer (lexer);
+          lex_get (lexer);
+        }
+      else if (lex_match_id (lexer, "MODE"))
+        {
+          if (mode != MODE_DEFAULT)
+            {
+              lex_sbc_only_once ("MODE");
+              goto exit;
+            }
+          lex_match (lexer, T_EQUALS);
+
+          if (lex_match_id (lexer, "CHARACTER"))
+            mode = MODE_CHARACTER;
+          else if (lex_match_id (lexer, "BINARY"))
+            mode = MODE_BINARY;
+          else if (lex_match_id (lexer, "IMAGE"))
+            mode = MODE_IMAGE;
+          else if (lex_match_int (lexer, 360))
+            mode = MODE_360;
+          else
+            {
+              lex_error (lexer, NULL);
+              goto exit;
+            }
+        }
+      else if (lex_match_id (lexer, "ENDS"))
+        {
+          if (ends >= 0)
+            {
+              lex_sbc_only_once ("ENDS");
+              goto exit;
+            }
+          lex_match (lexer, T_EQUALS);
+
+          if (lex_match_id (lexer, "LF"))
+            ends = FH_END_LF;
+          else if (lex_match_id (lexer, "CRLF"))
+            ends = FH_END_CRLF;
+          else
+            {
+              lex_error (lexer, NULL);
+              goto exit;
+            }
+        }
+      else if (lex_match_id (lexer, "RECFORM"))
+        {
+          if (recform)
+            {
+              lex_sbc_only_once ("RECFORM");
+              goto exit;
+            }
+          lex_match (lexer, T_EQUALS);
+          if (lex_match_id (lexer, "FIXED") || lex_match_id (lexer, "F"))
+            recform = RECFORM_FIXED;
+          else if (lex_match_id (lexer, "VARIABLE")
+                   || lex_match_id (lexer, "V"))
+            recform = RECFORM_VARIABLE;
+          else if (lex_match_id (lexer, "SPANNED")
+                   || lex_match_id (lexer, "VS"))
+            recform = RECFORM_SPANNED;
+          else
+            {
+              lex_error (lexer, NULL);
+              goto exit;
+            }
+        }
+      else if (lex_match_id (lexer, "ENCODING"))
+        {
+          if (encoding)
+            {
+              lex_sbc_only_once ("ENCODING");
+              goto exit;
+            }
+
+          lex_match (lexer, T_EQUALS);
+          if (!lex_force_string (lexer))
+            goto exit;
+          free (encoding);
+          encoding = ss_xstrdup (lex_tokss (lexer));
+          lex_get (lexer);
+        }
+      if (!lex_match (lexer, T_SLASH))
+        break;
+    }
+
+  if (lex_end_of_command (lexer) != CMD_SUCCESS)
+    goto exit;
+
+  struct fh_properties properties = *fh_default_properties ();
+  if (file_name == NULL)
+    {
+      lex_sbc_missing ("NAME");
+      goto exit;
+    }
+
+  switch (mode)
+    {
+    case MODE_DEFAULT:
+    case MODE_CHARACTER:
+      properties.mode = FH_MODE_TEXT;
+      if (tabwidth >= 0)
+        properties.tab_width = tabwidth;
+      if (ends)
+        properties.line_ends = ends;
+      break;
+    case MODE_IMAGE:
+      properties.mode = FH_MODE_FIXED;
+      break;
+    case MODE_BINARY:
+      properties.mode = FH_MODE_VARIABLE;
+      break;
+    case MODE_360:
+      properties.encoding = CONST_CAST (char *, "EBCDIC-US");
+      if (recform == RECFORM_FIXED)
+        properties.mode = FH_MODE_FIXED;
+      else if (recform == RECFORM_VARIABLE)
+        {
+          properties.mode = FH_MODE_360_VARIABLE;
+          properties.record_width = 8192;
+        }
+      else if (recform == RECFORM_SPANNED)
+        {
+          properties.mode = FH_MODE_360_SPANNED;
+          properties.record_width = 8192;
+        }
+      else
+        {
+          msg (SE, _("%s must be specified with %s."), "RECFORM", "MODE=360");
+          goto exit;
+        }
+      break;
+    default:
+      NOT_REACHED ();
+    }
+
+  if (properties.mode == FH_MODE_FIXED || lrecl)
+    {
+      if (!lrecl)
+        msg (SE, _("The specified file mode requires LRECL.  "
+                   "Assuming %zu-character records."),
+             properties.record_width);
+      else if (lrecl < 1 || lrecl >= (1UL << 31))
+        msg (SE, _("Record length (%d) must be between 1 and %lu bytes.  "
+                   "Assuming %zu-character records."),
+             lrecl, (1UL << 31) - 1, properties.record_width);
+      else
+        properties.record_width = lrecl;
+    }
+
+  if (encoding)
+    properties.encoding = encoding;
+
+  fh_create_file (handle_name, file_name, lex_get_encoding (lexer),
+                  &properties);
+
+  result = CMD_SUCCESS;
+
+exit:
+  free (handle_name);
+  free (file_name);
+  free (encoding);
+  return result;
+}
+
+int
+cmd_close_file_handle (struct lexer *lexer, struct dataset *ds UNUSED)
+{
+  struct file_handle *handle;
+
+  if (!lex_force_id (lexer))
+    return CMD_CASCADING_FAILURE;
+  handle = fh_from_id (lex_tokcstr (lexer));
+  if (handle == NULL)
+    return CMD_CASCADING_FAILURE;
+
+  fh_unname (handle);
+  return CMD_SUCCESS;
+}
+
+/* Returns the name for REFERENT. */
+static const char *
+referent_name (enum fh_referent referent)
+{
+  switch (referent)
+    {
+    case FH_REF_FILE:
+      return _("file");
+    case FH_REF_INLINE:
+      return _("inline file");
+    case FH_REF_DATASET:
+      return _("dataset");
+    default:
+      NOT_REACHED ();
+    }
+}
+
+/* Parses a file handle name:
+
+      - If SESSION is nonnull, then the parsed syntax may be the name of a
+        dataset within SESSION.  Dataset names take precedence over file handle
+        names.
+
+      - If REFERENT_MASK includes FH_REF_FILE, the parsed syntax may be a file
+        name as a string or a file handle name as an identifier.
+
+      - If REFERENT_MASK includes FH_REF_INLINE, the parsed syntax may be the
+        identifier INLINE to represent inline data.
+
+   Returns the file handle when successful, a null pointer on failure.
+
+   The caller is responsible for fh_unref()'ing the returned file handle when
+   it is no longer needed. */
+struct file_handle *
+fh_parse (struct lexer *lexer, enum fh_referent referent_mask,
+          struct session *session)
+{
+  struct file_handle *handle;
+
+  if (session != NULL && lex_token (lexer) == T_ID)
+    {
+      struct dataset *ds;
+
+      ds = session_lookup_dataset (session, lex_tokcstr (lexer));
+      if (ds != NULL)
+        {
+          lex_get (lexer);
+          return fh_create_dataset (ds);
+        }
+    }
+
+  if (lex_match_id (lexer, "INLINE"))
+    handle = fh_inline_file ();
+  else
+    {
+      if (lex_token (lexer) != T_ID && !lex_is_string (lexer))
+        {
+          lex_error (lexer, _("expecting a file name or handle name"));
+          return NULL;
+        }
+
+      handle = NULL;
+      if (lex_token (lexer) == T_ID)
+        handle = fh_from_id (lex_tokcstr (lexer));
+      if (handle == NULL)
+       handle = fh_create_file (NULL, lex_tokcstr (lexer), lex_get_encoding (lexer),
+                                     fh_default_properties ());
+      lex_get (lexer);
+    }
+
+  if (!(fh_get_referent (handle) & referent_mask))
+    {
+      msg (SE, _("Handle for %s not allowed here."),
+           referent_name (fh_get_referent (handle)));
+      fh_unref (handle);
+      return NULL;
+    }
+
+  return handle;
+}
+
+/*
+   Local variables:
+   mode: c
+   End:
+*/
diff --git a/src/language/data-io/file-handle.q b/src/language/data-io/file-handle.q
deleted file mode 100644 (file)
index 7ac20a0..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include "data/file-handle-def.h"
-
-#include <limits.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "data/file-name.h"
-#include "data/session.h"
-#include "data/variable.h"
-#include "language/command.h"
-#include "language/data-io/file-handle.h"
-#include "language/lexer/lexer.h"
-#include "libpspp/assertion.h"
-#include "libpspp/cast.h"
-#include "libpspp/message.h"
-#include "libpspp/str.h"
-
-#include "gl/xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* (headers) */
-
-
-/* (specification)
-   "FILE HANDLE" (fh_):
-     name=string;
-     lrecl=integer;
-     tabwidth=integer;
-     mode=mode:!character/binary/image/360;
-     ends=ends:lf/crlf;
-     recform=recform:fixed/f/variable/v/spanned/vs;
-     encoding=string.
-*/
-/* (declarations) */
-/* (functions) */
-
-int
-cmd_file_handle (struct lexer *lexer, struct dataset *ds)
-{
-  struct fh_properties properties;
-  struct cmd_file_handle cmd;
-  struct file_handle *handle;
-  enum cmd_result result;
-  char *handle_name;
-
-  result = CMD_CASCADING_FAILURE;
-  if (!lex_force_id (lexer))
-    goto exit;
-
-  handle_name = xstrdup (lex_tokcstr (lexer));
-  handle = fh_from_id (handle_name);
-  if (handle != NULL)
-    {
-      msg (SE, _("File handle %s is already defined.  "
-                 "Use %s before redefining a file handle."),
-          handle_name, "CLOSE FILE HANDLE");
-      goto exit_free_handle_name;
-    }
-
-  lex_get (lexer);
-  if (!lex_force_match (lexer, T_SLASH))
-    goto exit_free_handle_name;
-
-  if (!parse_file_handle (lexer, ds, &cmd, NULL))
-    goto exit_free_handle_name;
-
-  if (lex_end_of_command (lexer) != CMD_SUCCESS)
-    goto exit_free_cmd;
-
-  properties = *fh_default_properties ();
-  if (cmd.s_name == NULL)
-    {
-      lex_sbc_missing ("NAME");
-      goto exit_free_cmd;
-    }
-
-  switch (cmd.mode)
-    {
-    case FH_CHARACTER:
-      properties.mode = FH_MODE_TEXT;
-      if (cmd.sbc_tabwidth)
-        {
-          if (cmd.n_tabwidth[0] >= 0)
-            properties.tab_width = cmd.n_tabwidth[0];
-          else
-            msg (SE, _("%s must not be negative."), "TABWIDTH");
-        }
-      if (cmd.ends == FH_LF)
-        properties.line_ends = FH_END_LF;
-      else if (cmd.ends == FH_CRLF)
-        properties.line_ends = FH_END_CRLF;
-      break;
-    case FH_IMAGE:
-      properties.mode = FH_MODE_FIXED;
-      break;
-    case FH_BINARY:
-      properties.mode = FH_MODE_VARIABLE;
-      break;
-    case FH_360:
-      properties.encoding = CONST_CAST (char *, "EBCDIC-US");
-      if (cmd.recform == FH_FIXED || cmd.recform == FH_F)
-        properties.mode = FH_MODE_FIXED;
-      else if (cmd.recform == FH_VARIABLE || cmd.recform == FH_V)
-        {
-          properties.mode = FH_MODE_360_VARIABLE;
-          properties.record_width = 8192;
-        }
-      else if (cmd.recform == FH_SPANNED || cmd.recform == FH_VS)
-        {
-          properties.mode = FH_MODE_360_SPANNED;
-          properties.record_width = 8192;
-        }
-      else
-        {
-          msg (SE, _("%s must be specified with %s."), "RECFORM", "MODE=360");
-          goto exit_free_cmd;
-        }
-      break;
-    default:
-      NOT_REACHED ();
-    }
-
-  if (properties.mode == FH_MODE_FIXED || cmd.n_lrecl[0] != LONG_MIN)
-    {
-      if (cmd.n_lrecl[0] == LONG_MIN)
-        msg (SE, _("The specified file mode requires LRECL.  "
-                   "Assuming %zu-character records."),
-             properties.record_width);
-      else if (cmd.n_lrecl[0] < 1 || cmd.n_lrecl[0] >= (1UL << 31))
-        msg (SE, _("Record length (%ld) must be between 1 and %lu bytes.  "
-                   "Assuming %zu-character records."),
-             cmd.n_lrecl[0], (1UL << 31) - 1, properties.record_width);
-      else
-        properties.record_width = cmd.n_lrecl[0];
-    }
-
-  if (cmd.s_encoding != NULL)
-    properties.encoding = cmd.s_encoding;
-
-  fh_create_file (handle_name, cmd.s_name, lex_get_encoding (lexer), &properties);
-
-  result = CMD_SUCCESS;
-
-exit_free_cmd:
-  free_file_handle (&cmd);
-exit_free_handle_name:
-  free (handle_name);
-exit:
-  return result;
-}
-
-int
-cmd_close_file_handle (struct lexer *lexer, struct dataset *ds UNUSED)
-{
-  struct file_handle *handle;
-
-  if (!lex_force_id (lexer))
-    return CMD_CASCADING_FAILURE;
-  handle = fh_from_id (lex_tokcstr (lexer));
-  if (handle == NULL)
-    return CMD_CASCADING_FAILURE;
-
-  fh_unname (handle);
-  return CMD_SUCCESS;
-}
-
-/* Returns the name for REFERENT. */
-static const char *
-referent_name (enum fh_referent referent)
-{
-  switch (referent)
-    {
-    case FH_REF_FILE:
-      return _("file");
-    case FH_REF_INLINE:
-      return _("inline file");
-    case FH_REF_DATASET:
-      return _("dataset");
-    default:
-      NOT_REACHED ();
-    }
-}
-
-/* Parses a file handle name:
-
-      - If SESSION is nonnull, then the parsed syntax may be the name of a
-        dataset within SESSION.  Dataset names take precedence over file handle
-        names.
-
-      - If REFERENT_MASK includes FH_REF_FILE, the parsed syntax may be a file
-        name as a string or a file handle name as an identifier.
-
-      - If REFERENT_MASK includes FH_REF_INLINE, the parsed syntax may be the
-        identifier INLINE to represent inline data.
-
-   Returns the file handle when successful, a null pointer on failure.
-
-   The caller is responsible for fh_unref()'ing the returned file handle when
-   it is no longer needed. */
-struct file_handle *
-fh_parse (struct lexer *lexer, enum fh_referent referent_mask,
-          struct session *session)
-{
-  struct file_handle *handle;
-
-  if (session != NULL && lex_token (lexer) == T_ID)
-    {
-      struct dataset *ds;
-
-      ds = session_lookup_dataset (session, lex_tokcstr (lexer));
-      if (ds != NULL)
-        {
-          lex_get (lexer);
-          return fh_create_dataset (ds);
-        }
-    }
-
-  if (lex_match_id (lexer, "INLINE"))
-    handle = fh_inline_file ();
-  else
-    {
-      if (lex_token (lexer) != T_ID && !lex_is_string (lexer))
-        {
-          lex_error (lexer, _("expecting a file name or handle name"));
-          return NULL;
-        }
-
-      handle = NULL;
-      if (lex_token (lexer) == T_ID)
-        handle = fh_from_id (lex_tokcstr (lexer));
-      if (handle == NULL)
-       handle = fh_create_file (NULL, lex_tokcstr (lexer), lex_get_encoding (lexer),
-                                     fh_default_properties ());
-      lex_get (lexer);
-    }
-
-  if (!(fh_get_referent (handle) & referent_mask))
-    {
-      msg (SE, _("Handle for %s not allowed here."),
-           referent_name (fh_get_referent (handle)));
-      fh_unref (handle);
-      return NULL;
-    }
-
-  return handle;
-}
-
-/*
-   Local variables:
-   mode: c
-   End:
-*/
index e3a93b1738d0324be41f34c49200b7c5b5b3b0ce..13eebe6c3aaabe840a155c4e405fa797e99af295 100644 (file)
@@ -52,9 +52,6 @@ static const bool odf_read_support = true;
 #else
 static const bool odf_read_support = false;
 struct spreadsheet *ods_probe (const char *filename, bool report_errors){}
-struct casereader * ods_make_reader (struct spreadsheet *spreadsheet,
-                                         const struct spreadsheet_read_options *opts){}
-void ods_unref (struct spreadsheet *r){}
 #endif
 
 #ifdef GNM_READ_SUPPORT
@@ -62,10 +59,6 @@ static const bool gnm_read_support = true;
 #else
 static const bool gnm_read_support = false;
 struct spreadsheet *gnumeric_probe (const char *filename, bool report_errors){}
-struct casereader * gnumeric_make_reader (struct spreadsheet *spreadsheet,
-                                         const struct spreadsheet_read_options *opts){}
-void gnumeric_unref (struct spreadsheet *r){}
-
 #endif
 
 static bool parse_spreadsheet (struct lexer *lexer, char **filename,
@@ -617,18 +610,20 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
           lex_get (lexer);
         }
 
-      if (!lex_force_id (lexer)
-          || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
-        goto error;
       name = xstrdup (lex_tokcstr (lexer));
+      if (!lex_force_id (lexer)
+          || !dict_id_is_valid (dict, name, true))
+       {
+         goto error;
+       }
       lex_get (lexer);
-
       if (type == DP_DELIMITED)
         {
           if (!parse_format_specifier (lexer, &input)
-              || !fmt_check_input (&input))
-            goto error;
-
+             || !fmt_check_input (&input))
+           {
+             goto error;
+           }
           output = fmt_for_output_from_input (&input);
         }
       else
@@ -648,14 +643,12 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
               msg (SE, _("Unknown format type `%s'."), fmt_type_name);
               goto error;
             }
-
           /* Compose input format. */
           input.type = fmt_type;
           input.w = lc - fc + 1;
           input.d = 0;
           if (!fmt_check_input (&input))
             goto error;
-
           /* Compose output format. */
           if (w != 0)
             {
@@ -668,7 +661,6 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
           else
             output = fmt_for_output_from_input (&input);
         }
-
       v = dict_create_var (dict, name, fmt_var_width (&input));
       if (v == NULL)
         {
@@ -676,7 +668,6 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
           goto error;
         }
       var_set_both_formats (v, &output);
-
       if (type == DP_DELIMITED)
         data_parser_add_delimited_field (parser, &input,
                                          var_get_case_index (v),
index 6e73887285a8d79543b21573ee84d7fc09c415ed..c69e440e4bde0f9c8747296884c0cf83e9ce2b45 100644 (file)
@@ -664,7 +664,7 @@ npdf_beta (double x, double a, double b, double lambda)
     }
 }
 
-double
+static double
 round__ (double x, double mult, double fuzzbits, double adjustment)
 {
   if (fuzzbits <= 0)
index 78af09da311e2d2af24f5c9a410e68311f6f769a..2c05335ff984fa711bacba8920f682cb01c358ee 100644 (file)
@@ -40,7 +40,7 @@ parse_abstract_format_specifier__ (struct lexer *lexer,
   struct substring type_ss, width_ss, decimals_ss;
   bool has_decimals;
 
-  if (lex_token (lexer) != T_ID)
+  if (lex_token (lexer) != T_ID && lex_token (lexer) != T_STRING)
     goto error;
 
   /* Extract pieces. */
index 7b0c6c345e5e4a1dae7a27160c9030979ba2cabe..6e87c0260b856173bb4debbcd07dbabbd6036f7f 100644 (file)
@@ -74,6 +74,8 @@
      *^tables=custom;
      +variables=custom;
      missing=miss:!table/include/report;
+     count=roundwhat:asis/case/!cell,
+           roundhow:!round/truncate;
      +write[wr_]=none,cells,all;
      +format=val:!avalue/dvalue,
             indx:!noindex/index,
@@ -182,6 +184,11 @@ struct crosstabs_proc
     unsigned int cells;         /* Bit k is 1 if cell k is requested. */
     int a_cells[CRS_CL_count];  /* 0...n_cells-1 are the requested cells. */
 
+    /* Rounding of cells. */
+    bool round_case_weights;    /* Round case weights? */
+    bool round_cells;           /* If !round_case_weights, round cells? */
+    bool round_down;            /* Round down? (otherwise to nearest) */
+
     /* STATISTICS. */
     unsigned int statistics;    /* Bit k is 1 if statistic k is requested. */
 
@@ -200,6 +207,12 @@ static void tabulate_integer_case (struct pivot_table *, const struct ccase *,
 static void postcalc (struct crosstabs_proc *);
 static void submit (struct pivot_table *, struct tab_table *);
 
+static double
+round_weight (const struct crosstabs_proc *proc, double weight)
+{
+  return proc->round_down ? floor (weight) : floor (weight + 0.5);
+}
+
 /* Parses and executes the CROSSTABS procedure. */
 int
 cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
@@ -236,6 +249,10 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
 
   proc.descending = cmd.val == CRS_DVALUE;
 
+  proc.round_case_weights = cmd.sbc_count && cmd.roundwhat == CRS_CASE;
+  proc.round_cells = cmd.sbc_count && cmd.roundwhat == CRS_CELL;
+  proc.round_down = cmd.roundhow == CRS_TRUNCATE;
+
   /* CELLS. */
   if (!cmd.sbc_cells)
     proc.cells = 1u << CRS_CL_COUNT;
@@ -316,6 +333,12 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
           {
             double weight = dict_get_case_weight (dataset_dict (ds), c,
                                                   &proc.bad_warn);
+            if (cmd.roundwhat == CRS_CASE)
+              {
+                weight = round_weight (&proc, weight);
+                if (weight == 0.)
+                  continue;
+              }
             if (should_tabulate_case (pt, c, proc.exclude))
               {
                 if (proc.mode == GENERAL)
@@ -677,17 +700,36 @@ static bool find_crosstab (struct pivot_table *, size_t *row0p, size_t *row1p);
 static void
 postcalc (struct crosstabs_proc *proc)
 {
-  struct pivot_table *pt;
+
+  /* Round hash table entries, if requested
+
+     If this causes any of the cell counts to fall to zero, delete those
+     cells. */
+  if (proc->round_cells)
+    for (struct pivot_table *pt = proc->pivots;
+         pt < &proc->pivots[proc->n_pivots]; pt++)
+      {
+        struct freq *e, *next;
+        HMAP_FOR_EACH_SAFE (e, next, struct freq, node, &pt->data)
+          {
+            e->count = round_weight (proc, e->count);
+            if (e->count == 0.0)
+              {
+                hmap_delete (&pt->data, &e->node);
+                free (e);
+              }
+          }
+      }
 
   /* Convert hash tables into sorted arrays of entries. */
-  for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
+  for (struct pivot_table *pt = proc->pivots;
+       pt < &proc->pivots[proc->n_pivots]; pt++)
     {
       struct freq *e;
-      size_t i;
 
       pt->n_entries = hmap_count (&pt->data);
       pt->entries = xnmalloc (pt->n_entries, sizeof *pt->entries);
-      i = 0;
+      size_t i = 0;
       HMAP_FOR_EACH (e, struct freq, node, &pt->data)
         pt->entries[i++] = e;
       hmap_destroy (&pt->data);
@@ -701,7 +743,8 @@ postcalc (struct crosstabs_proc *proc)
   make_summary_table (proc);
 
   /* Output each pivot table. */
-  for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
+  for (struct pivot_table *pt = proc->pivots;
+       pt < &proc->pivots[proc->n_pivots]; pt++)
     {
       if (proc->pivot || pt->n_vars == 2)
         output_pivot_table (proc, pt);
@@ -721,10 +764,9 @@ postcalc (struct crosstabs_proc *proc)
     }
 
   /* Free output and prepare for next split file. */
-  for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
+  for (struct pivot_table *pt = proc->pivots;
+       pt < &proc->pivots[proc->n_pivots]; pt++)
     {
-      size_t i;
-
       pt->missing = 0.0;
 
       /* Free the members that were allocated in this function(and the values
@@ -734,7 +776,7 @@ postcalc (struct crosstabs_proc *proc)
          lower level (in output_pivot_table), or both allocated and destroyed
          at a higher level (in crs_custom_tables and free_proc,
          respectively). */
-      for (i = 0; i < pt->n_vars; i++)
+      for (size_t i = 0; i < pt->n_vars; i++)
         {
           int width = var_get_width (pt->vars[i]);
           if (value_needs_init (width))
@@ -746,7 +788,7 @@ postcalc (struct crosstabs_proc *proc)
             }
         }
 
-      for (i = 0; i < pt->n_entries; i++)
+      for (size_t i = 0; i < pt->n_entries; i++)
         free (pt->entries[i]);
       free (pt->entries);
     }
index 34da71c8aaf00b776d0c6a77731b077b310f5c0b..675a02319aaebf1ca6f8d3b91cb323106eb1e929 100644 (file)
@@ -1124,6 +1124,7 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
        frq.percentiles[frq.n_percentiles].show = true;
 
        frq.n_percentiles++;
+        frq.n_show_percentiles++;
     }
 
 
@@ -1212,19 +1213,20 @@ cmd_frequencies (struct lexer *lexer, struct dataset *ds)
     frq.n_show_percentiles = 0;
     for (i = o = 0; i < frq.n_percentiles; ++i)
       {
-       frq.percentiles[o].p = frq.percentiles[i].p;
-
-       if (frq.percentiles[i].show)
-         frq.percentiles[o].show = true;
-
-       if (frq.percentiles[i].p != previous_p)
-         {
-           if (frq.percentiles[i].show)
-             frq.n_show_percentiles++;
-
-           o++;
-         }
-
+        if (frq.percentiles[i].p != previous_p)
+          {
+            frq.percentiles[o].p = frq.percentiles[i].p;
+            frq.percentiles[o].show = frq.percentiles[i].show;
+            if (frq.percentiles[i].show)
+              frq.n_show_percentiles++;
+            o++;
+          }
+        else if (frq.percentiles[i].show &&
+                 !frq.percentiles[o].show)
+          {
+            frq.percentiles[o].show = true;
+            frq.n_show_percentiles++;
+          }
        previous_p = frq.percentiles[i].p;
       }
 
index 625de2d2a9f9200986f98e453cb3fcf5a7d4513b..9ac3150c0a9385aac91e544d0fc6c2c4c25d8617 100644 (file)
@@ -587,6 +587,16 @@ run_glm (struct glm_spec *cmd, struct casereader *input,
   struct glm_workspace ws;
   struct covariance *cov;
 
+  input  = casereader_create_filter_missing (input,
+                                            cmd->dep_vars, cmd->n_dep_vars,
+                                            cmd->exclude,
+                                            NULL,  NULL);
+
+  input  = casereader_create_filter_missing (input,
+                                            cmd->factor_vars, cmd->n_factor_vars,
+                                            cmd->exclude,
+                                            NULL,  NULL);
+  
   ws.cats = categoricals_create (cmd->interactions, cmd->n_interactions,
                                 cmd->wv, cmd->exclude, MV_ANY);
 
index 736d5e2ae7102c210f4022bf89ef6a37c77fd9aa..211d2d60dcdf8b2fca15713f0da53ad952f9c1ae 100644 (file)
@@ -28,6 +28,7 @@
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
+static const struct xrchart_colour black = {0,0,0};
 
 void
 xrchart_draw_scatterplot (const struct chart_item *chart_item, cairo_t *cr,
@@ -87,8 +88,11 @@ xrchart_draw_scatterplot (const struct chart_item *chart_item, cairo_t *cr,
                  i--;
                }
            }
+          colour = &data_colour[i % XRCHART_N_COLOURS];
        }
-      colour = &data_colour[i % XRCHART_N_COLOURS];
+      else
+        colour = &black;
+
       cairo_set_source_rgb (cr,
                             colour->red / 255.0,
                             colour->green / 255.0,
index db384bdfc93408b434b08211ac774c03f60251a4..733cc9854fd09de4b68f9509f4bc3c8b2a37cc00 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013, 2014, 2016 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 \f
+
+#if DEBUGGING
+static const bool debugging = true;
+#else
+static const bool debugging = false;
+#endif
+
 /* Cell options. */
 #define TAB_JOIN     (1u << TAB_FIRST_AVAILABLE)
 #define TAB_SUBTABLE (1u << (TAB_FIRST_AVAILABLE + 1))
 
 /* Joined cell. */
 struct tab_joined_cell
+{
+  int d[TABLE_N_AXES][2];       /* Table region, same as struct table_cell. */
+  union
   {
-    int d[TABLE_N_AXES][2];     /* Table region, same as struct table_cell. */
-    union
-      {
-        char *text;
-        struct table_item *subtable;
-      }
+    char *text;
+    struct table_item *subtable;
+  }
     u;
 
-    size_t n_footnotes;
-    char **footnotes;
-  };
+  size_t n_footnotes;
+  char **footnotes;
+};
 
 static const struct table_class tab_table_class;
 
-struct fmt_spec ugly [n_RC] = 
-  {
-    {FMT_F, 8, 0}, /* INTEGER */
-    {FMT_F, 8, 3}, /* WEIGHT (ignored) */
-    {FMT_F, 8, 3}, /* PVALUE */
-    {FMT_F, 8, 3}  /* OTHER (ignored) */
-  };
+struct fmt_spec ugly[n_RC] = {
+  {FMT_F, 8, 0},                /* INTEGER */
+  {FMT_F, 8, 3},                /* WEIGHT (ignored) */
+  {FMT_F, 8, 3},                /* PVALUE */
+  {FMT_F, 8, 3}                 /* OTHER (ignored) */
+};
 
 
 /* Creates and returns a new table with NC columns and NR rows and initially no
@@ -112,8 +118,9 @@ tab_create (int nc, int nr)
 }
 
 
-void 
-tab_set_format (struct tab_table *t, enum result_class rc, const struct fmt_spec *fmt)
+void
+tab_set_format (struct tab_table *t, enum result_class rc,
+                const struct fmt_spec *fmt)
 {
   t->fmtmap[rc] = *fmt;
 }
@@ -175,11 +182,12 @@ tab_realloc (struct tab_table *t, int nc, int nr)
       new_cc = pool_calloc (t->container, nr * nc, sizeof *new_cc);
       new_ct = pool_malloc (t->container, nr * nc);
       for (r = 0; r < mr1; r++)
-       {
-         memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)], mc1 * sizeof *t->cc);
-         memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], mc1);
-         memset (&new_ct[r * nc + tab_nc (t)], 0, nc - tab_nc (t));
-       }
+        {
+          memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)],
+                  mc1 * sizeof *t->cc);
+          memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], mc1);
+          memset (&new_ct[r * nc + tab_nc (t)], 0, nc - tab_nc (t));
+        }
       pool_free (t->container, t->cc);
       pool_free (t->container, t->ct);
       t->cc = new_cc;
@@ -195,11 +203,12 @@ tab_realloc (struct tab_table *t, int nc, int nr)
       t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
 
       if (nr > tab_nr (t))
-       {
-         memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0, (nr - tab_nr (t)) * nc);
-         memset (&t->rv[(nc + 1) * tab_nr (t)], TAL_GAP,
+        {
+          memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0,
+                  (nr - tab_nr (t)) * nc);
+          memset (&t->rv[(nc + 1) * tab_nr (t)], TAL_GAP,
                   (nr - tab_nr (t)) * (nc + 1));
-       }
+        }
     }
 
   memset (&t->ct[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)));
@@ -232,20 +241,20 @@ tab_headers (struct tab_table *table, int l, int r, int t, int b)
 void
 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
 {
-#if DEBUGGING
-  if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
-      || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
-      || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
+  if (debugging)
     {
-      printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
-               "table size (%d,%d)\n"),
-             x, t->col_ofs, x + t->col_ofs,
-             y1, t->row_ofs, y1 + t->row_ofs,
-             y2, t->row_ofs, y2 + t->row_ofs,
-             tab_nc (t), tab_nr (t));
-      return;
+      if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
+          || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
+          || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
+        {
+          printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
+                    "table size (%d,%d)\n"),
+                  x, t->col_ofs, x + t->col_ofs,
+                  y1, t->row_ofs, y1 + t->row_ofs,
+                  y2, t->row_ofs, y2 + t->row_ofs, tab_nc (t), tab_nr (t));
+          return;
+        }
     }
-#endif
 
   x += t->col_ofs;
   y1 += t->row_ofs;
@@ -268,22 +277,22 @@ tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
 /* Draws a horizontal line above cells at vertical position Y from X1
    to X2 inclusive in style STYLE, if style is not -1. */
 void
-tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
+tab_hline (struct tab_table *t, int style, int x1, int x2, int y)
 {
-#if DEBUGGING
-  if (y + t->row_ofs < 0 || y + t->row_ofs > tab_nr (t)
-      || x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
-      || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t))
+  if (debugging)
     {
-      printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in "
-               "table size (%d,%d)\n"),
-              x1, t->col_ofs, x1 + t->col_ofs,
-              x2, t->col_ofs, x2 + t->col_ofs,
-              y, t->row_ofs, y + t->row_ofs,
-             tab_nc (t), tab_nr (t));
-      return;
+      if (y + t->row_ofs < 0 || y + t->row_ofs > tab_nr (t)
+          || x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
+          || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t))
+        {
+          printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in "
+                    "table size (%d,%d)\n"),
+                  x1, t->col_ofs, x1 + t->col_ofs,
+                  x2, t->col_ofs, x2 + t->col_ofs,
+                  y, t->row_ofs, y + t->row_ofs, tab_nc (t), tab_nr (t));
+          return;
+        }
     }
-#endif
 
   x1 += t->col_ofs;
   x2 += t->col_ofs;
@@ -291,8 +300,8 @@ tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
 
   assert (y >= 0);
   assert (y <= tab_nr (t));
-  assert (x2 >= x1 );
-  assert (x1 >= 0 );
+  assert (x2 >= x1);
+  assert (x1 >= 0);
   assert (x2 < tab_nc (t));
 
   if (style != -1)
@@ -311,24 +320,24 @@ tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
    line. */
 void
 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
-        int x1, int y1, int x2, int y2)
+         int x1, int y1, int x2, int y2)
 {
-#if DEBUGGING
-  if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
-      || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
-      || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
-      || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
+  if (debugging)
     {
-      printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
-               "in table size (%d,%d)\n"),
-             x1, t->col_ofs, x1 + t->col_ofs,
-             y1, t->row_ofs, y1 + t->row_ofs,
-             x2, t->col_ofs, x2 + t->col_ofs,
-             y2, t->row_ofs, y2 + t->row_ofs,
-             tab_nc (t), tab_nr (t));
-      NOT_REACHED ();
+      if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
+          || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
+          || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
+          || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
+        {
+          printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
+                    "in table size (%d,%d)\n"),
+                  x1, t->col_ofs, x1 + t->col_ofs,
+                  y1, t->row_ofs, y1 + t->row_ofs,
+                  x2, t->col_ofs, x2 + t->col_ofs,
+                  y2, t->row_ofs, y2 + t->row_ofs, tab_nc (t), tab_nr (t));
+          NOT_REACHED ();
+        }
     }
-#endif
 
   x1 += t->col_ofs;
   x2 += t->col_ofs;
@@ -366,24 +375,24 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
       int y;
 
       for (y = y1 + 1; y <= y2; y++)
-       {
-         int x;
+        {
+          int x;
 
           for (x = x1; x <= x2; x++)
             t->rh[x + t->cf * y] = i_h;
-       }
+        }
     }
   if (i_v != -1)
     {
       int x;
 
       for (x = x1 + 1; x <= x2; x++)
-       {
-         int y;
+        {
+          int y;
 
           for (y = y1; y <= y2; y++)
             t->rv[x + (t->cf + 1) * y] = i_v;
-       }
+        }
     }
 }
 \f
@@ -393,24 +402,25 @@ tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
    from V, displayed with format spec F. */
 void
 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
-          const union value *v, const struct variable *var,
-          const struct fmt_spec *f)
+           const union value *v, const struct variable *var,
+           const struct fmt_spec *f)
 {
   char *contents;
 
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= tab_nc (table)
-      || r + table->row_ofs >= tab_nr (table))
+  if (debugging)
     {
-      printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
-             "(%d,%d)\n",
-             c, table->col_ofs, c + table->col_ofs,
-             r, table->row_ofs, r + table->row_ofs,
-             tab_nc (table), tab_nr (table));
-      return;
+      if (c + table->col_ofs < 0 || r + table->row_ofs < 0
+          || c + table->col_ofs >= tab_nc (table)
+          || r + table->row_ofs >= tab_nr (table))
+        {
+          printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
+                  "(%d,%d)\n",
+                  c, table->col_ofs, c + table->col_ofs,
+                  r, table->row_ofs, r + table->row_ofs,
+                  tab_nc (table), tab_nr (table));
+          return;
+        }
     }
-#endif
 
   contents = data_out_stretchy (v, var_get_encoding (var),
                                 f != NULL ? f : var_get_print_format (var),
@@ -426,9 +436,9 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt,
 */
 void
 tab_double (struct tab_table *table, int c, int r, unsigned char opt,
-           double val, const struct fmt_spec *fmt, enum result_class rc)
+            double val, const struct fmt_spec *fmt, enum result_class rc)
 {
-  union value double_value ;
+  union value double_value;
   char *s;
 
   assert (c >= 0);
@@ -438,22 +448,23 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
 
   if (fmt == NULL)
     fmt = &table->fmtmap[rc];
-  
+
   fmt_check_output (fmt);
 
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= tab_nc (table)
-      || r + table->row_ofs >= tab_nr (table))
+  if (debugging)
     {
-      printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
-             "(%d,%d)\n",
-             c, table->col_ofs, c + table->col_ofs,
-             r, table->row_ofs, r + table->row_ofs,
-             tab_nc (table), tab_nr (table));
-      return;
+      if (c + table->col_ofs < 0 || r + table->row_ofs < 0
+          || c + table->col_ofs >= tab_nc (table)
+          || r + table->row_ofs >= tab_nr (table))
+        {
+          printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
+                  "(%d,%d)\n",
+                  c, table->col_ofs, c + table->col_ofs,
+                  r, table->row_ofs, r + table->row_ofs,
+                  tab_nc (table), tab_nr (table));
+          return;
+        }
     }
-#endif
 
   double_value.f = val;
   s = data_out_stretchy (&double_value, C_ENCODING, fmt, table->container);
@@ -465,24 +476,25 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
 static void
 do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
 {
-  assert (c >= 0 );
-  assert (r >= 0 );
+  assert (c >= 0);
+  assert (r >= 0);
   assert (c < tab_nc (table));
   assert (r < tab_nr (table));
 
-#if DEBUGGING
-  if (c + table->col_ofs < 0 || r + table->row_ofs < 0
-      || c + table->col_ofs >= tab_nc (table)
-      || r + table->row_ofs >= tab_nr (table))
+  if (debugging)
     {
-      printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
-             "(%d,%d)\n",
-             c, table->col_ofs, c + table->col_ofs,
-             r, table->row_ofs, r + table->row_ofs,
-             tab_nc (table), tab_nr (table));
-      return;
+      if (c + table->col_ofs < 0 || r + table->row_ofs < 0
+          || c + table->col_ofs >= tab_nc (table)
+          || r + table->row_ofs >= tab_nr (table))
+        {
+          printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
+                  "(%d,%d)\n",
+                  c, table->col_ofs, c + table->col_ofs,
+                  r, table->row_ofs, r + table->row_ofs,
+                  tab_nc (table), tab_nr (table));
+          return;
+        }
     }
-#endif
 
   table->cc[c + r * table->cf] = text;
   table->ct[c + r * table->cf] = opt;
@@ -524,22 +536,23 @@ add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
   assert (y2 + table->row_ofs < tab_nr (table));
   assert (x2 + table->col_ofs < tab_nc (table));
 
-#if DEBUGGING
-  if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
-      || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
-      || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
-      || y2 < y2 || y2 + table->row_ofs >= tab_nr (table))
+  if (debugging)
     {
-      printf ("tab_joint_text(): bad cell "
-             "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
-             x1, table->col_ofs, x1 + table->col_ofs,
-             y1, table->row_ofs, y1 + table->row_ofs,
-             x2, table->col_ofs, x2 + table->col_ofs,
-             y2, table->row_ofs, y2 + table->row_ofs,
-             tab_nc (table), tab_nr (table));
-      return;
+      if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
+          || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
+          || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
+          || y2 < y1 || y2 + table->row_ofs >= tab_nr (table))
+        {
+          printf ("tab_joint_text(): bad cell "
+                  "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
+                  x1, table->col_ofs, x1 + table->col_ofs,
+                  y1, table->row_ofs, y1 + table->row_ofs,
+                  x2, table->col_ofs, x2 + table->col_ofs,
+                  y2, table->row_ofs, y2 + table->row_ofs,
+                  tab_nc (table), tab_nr (table));
+          return NULL;
+        }
     }
-#endif
 
   tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
 
@@ -560,16 +573,16 @@ add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
 
     for (y = y1; y < y2; y++)
       {
-       int x;
+        int x;
 
-       for (x = x1; x < x2; x++)
-         {
-           *cc++ = j;
-           *ct++ = opt | TAB_JOIN;
-         }
+        for (x = x1; x < x2; x++)
+          {
+            *cc++ = j;
+            *ct++ = opt | TAB_JOIN;
+          }
 
-       cc += ofs;
-       ct += ofs;
+        cc += ofs;
+        ct += ofs;
       }
   }
 
@@ -590,8 +603,8 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
    with options OPT to have text value FORMAT, which is formatted
    as if passed to printf. */
 void
-tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2, int y2,
-                       unsigned opt, const char *format, ...)
+tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2,
+                       int y2, unsigned opt, const char *format, ...)
 {
   va_list args;
   char *s;
@@ -625,7 +638,8 @@ tab_footnote (struct tab_table *table, int x, int y, const char *format, ...)
                            (j->n_footnotes + 1) * sizeof *j->footnotes);
 
   va_start (args, format);
-  j->footnotes[j->n_footnotes++] = pool_vasprintf (table->container, format, args);
+  j->footnotes[j->n_footnotes++] =
+    pool_vasprintf (table->container, format, args);
   va_end (args);
 }
 
@@ -712,18 +726,20 @@ tab_offset (struct tab_table *t, int col, int row)
 {
   int diff = 0;
 
-#if DEBUGGING
-  if (row < -1 || row > tab_nr (t))
+  if (debugging)
     {
-      printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
-      NOT_REACHED ();
-    }
-  if (col < -1 || col > tab_nc (t))
-    {
-      printf ("tab_offset(): col=%d in %d-column table\n", col, tab_nc (t));
-      NOT_REACHED ();
+      if (row < -1 || row > tab_nr (t))
+        {
+          printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
+          NOT_REACHED ();
+        }
+      if (col < -1 || col > tab_nc (t))
+        {
+          printf ("tab_offset(): col=%d in %d-column table\n", col,
+                  tab_nc (t));
+          NOT_REACHED ();
+        }
     }
-#endif
 
   if (row != -1)
     diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
@@ -790,7 +806,8 @@ tab_destroy (struct table *table)
 }
 
 static void
-tab_get_cell (const struct table *table, int x, int y, struct table_cell *cell)
+tab_get_cell (const struct table *table, int x, int y,
+              struct table_cell *cell)
 {
   const struct tab_table *t = tab_cast (table);
   int index = x + y * t->cf;
@@ -858,18 +875,16 @@ tab_get_rule (const struct table *table, enum table_axis axis, int x, int y)
 {
   const struct tab_table *t = tab_cast (table);
   return (axis == TABLE_VERT
-          ? t->rh[x + t->cf * y]
-          : t->rv[x + (t->cf + 1) * y]);
+          ? t->rh[x + t->cf * y] : t->rv[x + (t->cf + 1) * y]);
 }
 
-static const struct table_class tab_table_class =
-  {
-    tab_destroy,
-    tab_get_cell,
-    tab_get_rule,
-    NULL,                       /* paste */
-    NULL,                       /* select */
-  };
+static const struct table_class tab_table_class = {
+  tab_destroy,
+  tab_get_cell,
+  tab_get_rule,
+  NULL,                         /* paste */
+  NULL,                         /* select */
+};
 
 struct tab_table *
 tab_cast (const struct table *table)
index 2d6862857ccd43be94a619d997a779c284f7d28d..1155cf70db779a1b41dd91f9f030b1e9bdc3bd91 100644 (file)
@@ -242,6 +242,10 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-dialog-action-rank.h \
        src/ui/gui/psppire-dialog-action-recode.c \
        src/ui/gui/psppire-dialog-action-recode.h \
+       src/ui/gui/psppire-dialog-action-recode-same.c \
+       src/ui/gui/psppire-dialog-action-recode-same.h \
+       src/ui/gui/psppire-dialog-action-recode-different.c \
+       src/ui/gui/psppire-dialog-action-recode-different.h \
        src/ui/gui/psppire-dialog-action-regression.c \
        src/ui/gui/psppire-dialog-action-regression.h \
        src/ui/gui/psppire-dialog-action-reliability.c \
index 27262d972ee8c327feca59a1a4987ff866902ced..048ba0bbb15669c0988a3e0bb776deaf76eea040 100644 (file)
           </object>
         </child>
         <child>
-          <object class="PsppireDialogActionRecode" id="transform_recode-same">
+          <object class="PsppireDialogActionRecodeSame" id="transform_recode-same">
             <property name="name">transform_recode-same</property>
            <property name="manager">uimanager1</property>
-           <property name="recode-to-new-variable">FALSE</property>
             <property name="label" translatable="yes">Recode into _Same Variables...</property>
             <property name="stock-id">transform-in-to-same-variables</property>
           </object>
         </child>
         <child>
-          <object class="PsppireDialogActionRecode" id="transform_recode-different">
+          <object class="PsppireDialogActionRecodeDifferent" id="transform_recode-different">
            <property name="manager">uimanager1</property>
-           <property name="recode-to-new-variable">TRUE</property>
             <property name="name">transform_recode-different</property>
             <property name="label" translatable="yes">Recode into _Different Variables...</property>
             <property name="stock-id">transform-in-to-different-variables</property>
index 61b9140d1e5e11b0e400b88f62d171188950659e..aeef8c10c44ba2deb1d4762177fc3b56d964211e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013, 2015  Free Software Foundation
+   Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013, 2015, 2016  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
+/* Try to open html documentation uri via the default
+   browser on the operating system */
+#ifdef __APPLE__
+#define HTMLOPENARGV {"open", 0, 0}
+#elif  _WIN32
+#define HTMLOPENARGV {"wscript", 0, 0}
+#else
+#define HTMLOPENARGV {"xdg-open", 0, 0}
+#endif
 
 static const gchar *artists[] = { "Bastián DĂ­az", "Hugo Alejandro", NULL};
 
@@ -80,32 +89,130 @@ about_new (GtkMenuItem *mmm, GtkWindow *parent)
   gtk_widget_hide (about);
 }
 
-/* Open the manual at PAGE */
+
+/* Opening the htmluri in windows via cmd /start uri opens
+   the windows command shell for a moment. The alternative is
+   to start a script via wscript. This will not be visible*/
+#ifdef _WIN32
+static gboolean open_windows_help (const gchar *helpuri,
+                                   GError **err)
+{
+  gchar *vbsfilename = NULL;
+  gchar *vbs = NULL;
+  gboolean result;
+  vbsfilename = g_build_filename (g_get_tmp_dir (),
+                                  "pspp-help-open.vbs",
+                                  NULL);
+  vbs = g_strdup_printf("CreateObject(\"WScript.Shell\").Run \"%s\"",
+                        helpuri);
+  result = g_file_set_contents (vbsfilename,
+                                vbs,
+                                strlen(vbs),
+                                err);
+  g_free (vbs);
+  if (!result)
+    goto error;
+
+  gchar *argv[] = {"wscript",vbsfilename,0};
+
+  result = g_spawn_async (NULL, argv,
+                          NULL, G_SPAWN_SEARCH_PATH,
+                          NULL, NULL, NULL, err);
+ error:
+  g_free (vbsfilename);
+  return result;
+}
+#endif
+
+/* Open the manual at PAGE with the following priorities
+   First: local yelp help system
+   Second: browser with local html doc dir in path pspp.html/<helppage>.html
+   Third:  browers with Internet html help at gnu.org */
 void
 online_help (const char *page)
 {
   GError *err = NULL;
-  gchar *cmd = NULL;
-
+  GError *htmlerr = NULL;
   gchar *argv[3] = { "yelp", 0, 0};
+  gchar *htmlargv[3] = HTMLOPENARGV;
+  gchar *htmlfilename = NULL;
+  gchar *htmlfullname = NULL;
+  gchar *htmluri = NULL;
 
   if (page == NULL)
-    argv[1] = g_strdup_printf ("file://%s", relocate (DOCDIR "/pspp.xml"));
+    {
+      argv[1] = g_strdup_printf ("file://%s", relocate (DOCDIR "/pspp.xml"));
+      htmlfilename = g_strdup ("index.html");
+    }
   else
-    argv[1] = g_strdup_printf ("file://%s#%s", relocate (DOCDIR "/pspp.xml"), page);
-
-  if (! g_spawn_async (NULL, argv,
-                      NULL, G_SPAWN_SEARCH_PATH,
-                      NULL, NULL,   NULL,   &err))
     {
-      msg (ME, _("Cannot open reference manual: %s.  The PSPP user manual is "
-                 "also available at %s"),
+      gchar **tokens = NULL;
+      const int maxtokens = 5;
+      int idx = 0;
+      argv[1] = g_strdup_printf ("file://%s#%s",
+                                 relocate (DOCDIR "/pspp.xml"), page);
+      /* The page will be translated to the htmlfilename
+         page                   htmlfilename
+         GRAPH#SCATTERPLOT      SCATTERPLOT.html
+         QUICK-CLUSTER          QUICK-CLUSTER.html
+         which is valid for the multiple page html doc*/
+      tokens = g_strsplit (page, "#", maxtokens);
+      for(;tokens[idx] && idx < maxtokens;idx++);
+      htmlfilename = g_strdup_printf ("%s.html", tokens[idx-1]);
+      g_strfreev (tokens);
+    }
+  /* Hint: pspp.html is a directory...*/
+  htmlfullname = g_strdup_printf ("%s/%s", relocate (DOCDIR "/pspp.html"),
+                                  htmlfilename);
+  if (g_file_test (relocate (DOCDIR "/pspp.html"), G_FILE_TEST_IS_DIR))
+    {
+      GError *urierr = NULL;
+      htmluri =  g_filename_to_uri (htmlfullname,NULL, &urierr);
+      if (!htmluri)
+        {
+          msg (ME, _("Help path conversion error: %s"), urierr->message);
+          htmluri = htmlfullname;
+        }
+      g_clear_error (&urierr);
+    }
+  else
+    htmluri = g_strdup_printf (PACKAGE_URL "manual/html_node/%s",
+                               htmlfilename);
+  g_free (htmlfullname);
+  g_free (htmlfilename);
+  htmlargv[1] = htmluri;
+
+  /* The following **SHOULD** work but it does not on 28.5.2016
+     g_app_info_launch_default_for_uri (htmluri, NULL, &err);
+     osx: wine is started to launch the uri...
+     windows: not so bad, but the first access does not work*/
+
+  if (! (g_spawn_async (NULL, argv,
+                        NULL, G_SPAWN_SEARCH_PATH,
+                        NULL, NULL,   NULL,   &err) ||
+#ifdef _WIN32
+         open_windows_help (htmluri, &htmlerr))
+#else
+         g_spawn_async (NULL, htmlargv,
+                        NULL, G_SPAWN_SEARCH_PATH,
+                        NULL, NULL,   NULL,   &htmlerr))
+#endif
+      )
+    {
+      msg (ME, _("Cannot open reference manual via yelp: %s. "
+                 "Cannot open via html: %s "
+                 "with uri: %s "
+                 "The PSSP manual is also available at %s"),
                   err->message,
+                  htmlerr->message,
+                  htmluri,
                   PACKAGE_URL "documentation.html");
     }
 
-  g_free (cmd);
+  g_free (argv[1]);
+  g_free (htmluri);
   g_clear_error (&err);
+  g_clear_error (&htmlerr);
 }
 
 static void
index 1d647092b5d55f0b0753628b8e76d2b77fec94da..a1fed40abff9148844c7e4c6e8e9ee733b6d9d79 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2007, 2009, 2010, 2011, 2012  Free Software Foundation
+   Copyright (C) 2007, 2009, 2010, 2011, 2012, 2016  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -49,10 +49,10 @@ dialog_state_valid (gpointer data)
   if (NULL == act->grp_var)
     return FALSE;
 
-  if ( 0 == gtk_tree_model_get_iter_first (vars, &notused))
+  if (0 == gtk_tree_model_get_iter_first (vars, &notused))
     return FALSE;
 
-  if ( act->group_defn == GROUPS_UNDEF)
+  if (act->group_defn == GROUPS_UNDEF)
     return FALSE;
 
   return TRUE;
@@ -70,11 +70,12 @@ refresh (PsppireDialogAction *da)
 
   if (act->grp_var)
     {
-      int width = var_get_width (act->grp_var);
+      const int width = act->grp_var_width;
       value_destroy (&act->cut_point, width);
       value_destroy (&act->grp_val[0], width);
       value_destroy (&act->grp_val[1], width);
       act->grp_var = NULL;
+      act->grp_var_width = -1;
     }
 
   psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (act->dg_grp_entry[0]), NULL);
@@ -101,7 +102,7 @@ value_entry_contains_invalid (PsppireValueEntry *ve, const struct variable *var)
       const int width = var_get_width (var);
       value_init (&val, width);
 
-      if ( psppire_value_entry_get_value (ve, &val, width))
+      if (psppire_value_entry_get_value (ve, &val, width))
        {
          if (var_is_value_missing (var, &val, MV_SYSTEM))
            {
@@ -124,6 +125,9 @@ define_groups_state_valid (gpointer data)
 {
   PsppireDialogActionIndepSamps *act = data;
 
+  if (act->grp_var == NULL)
+    return FALSE;
+
   if (gtk_toggle_button_get_active
       (GTK_TOGGLE_BUTTON (act->dg_values_toggle_button)))
     {
@@ -153,14 +157,16 @@ run_define_groups (PsppireDialogActionIndepSamps *act)
   PsppireDialogAction *da = PSPPIRE_DIALOG_ACTION (act);
   GtkWidget *parent1 = gtk_widget_get_parent (act->dg_table1);
   GtkWidget *parent2 = gtk_widget_get_parent (act->dg_table2);
-
+  
+  g_return_if_fail (act->grp_var);
+  
   if (parent1)
     gtk_container_remove (GTK_CONTAINER (parent1), act->dg_table1);
 
   if (parent2)
     gtk_container_remove (GTK_CONTAINER (parent2), act->dg_table2);
 
-  if ( var_is_numeric (act->grp_var))
+  if (var_is_numeric (act->grp_var))
     {
       gtk_grid_attach (GTK_GRID (act->dg_table1), act->dg_table2,
                       1, 1, 1, 1);
@@ -181,7 +187,7 @@ run_define_groups (PsppireDialogActionIndepSamps *act)
   psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (act->dg_grp_entry[1]), act->grp_var);
   psppire_value_entry_set_variable (PSPPIRE_VALUE_ENTRY (act->dg_cut_point_entry), act->grp_var);
 
-  if ( act->group_defn != GROUPS_CUT_POINT )
+  if (act->group_defn != GROUPS_CUT_POINT )
     {
       gtk_toggle_button_set_active
        (GTK_TOGGLE_BUTTON (act->dg_cut_point_toggle_button), TRUE);
@@ -237,13 +243,13 @@ on_grp_var_change (GtkEntry *entry, PsppireDialogActionIndepSamps *act)
   PsppireDialogAction *da = PSPPIRE_DIALOG_ACTION (act);
   const gchar *text = gtk_entry_get_text (entry);
 
-  const struct variable *v = psppire_dict_lookup_var (da->dict, text);
+  const struct variable *v = da->dict ? psppire_dict_lookup_var (da->dict, text) : NULL;
 
   gtk_widget_set_sensitive (act->define_groups_button, v != NULL);
 
   if (act->grp_var)
     {
-      int width = var_get_width (act->grp_var);
+      const int width = act->grp_var_width;
       value_destroy (&act->cut_point, width);
       value_destroy (&act->grp_val[0], width);
       value_destroy (&act->grp_val[1], width);
@@ -264,13 +270,14 @@ on_grp_var_change (GtkEntry *entry, PsppireDialogActionIndepSamps *act)
         }
       else
         {
-          act->cut_point.short_string[0] = '\0';
-          act->grp_val[0].short_string[0] = '\0';
-          act->grp_val[1].short_string[0] = '\0';
+         value_str_rw (&act->cut_point, width)[0] = '\0';
+         value_str_rw (&act->grp_val[0], width)[0] = '\0';
+         value_str_rw (&act->grp_val[1], width)[0] = '\0';
         }
     }
 
   act->grp_var = v;
+  act->grp_var_width = v ? var_get_width (v) : -1;
 }
 
 static void
@@ -345,6 +352,8 @@ psppire_dialog_action_indep_samps_activate (PsppireDialogAction *a)
   g_signal_connect (act->group_var_entry, "changed",
                    G_CALLBACK (on_grp_var_change), act);
 
+  on_grp_var_change (GTK_ENTRY (act->group_var_entry), act);
+
   if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_indep_samps_parent_class)->activate)
     PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_indep_samps_parent_class)->activate (pda);
 }
@@ -427,6 +436,7 @@ static void
 psppire_dialog_action_indep_samps_init (PsppireDialogActionIndepSamps *act)
 {
   act->grp_var = NULL;
+  act->grp_var_width = -1;
   act->group_defn = GROUPS_UNDEF;
 }
 
index 359640df7e7629c668fa1ca63dbae71b123051df..672a40307448f3e0fdcb1abd9a65c157c40d73f5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2012  Free Software Foundation
+   Copyright (C) 2012, 2016  Free Software Foundation
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -76,6 +76,7 @@ struct _PsppireDialogActionIndepSamps
 
   /* The variable which determines to which group a datum belongs */
   const struct variable *grp_var;
+  int grp_var_width;
 
   /* The GtkEntry which holds the reference to the above variable */
   GtkWidget *group_var_entry;
diff --git a/src/ui/gui/psppire-dialog-action-recode-different.c b/src/ui/gui/psppire-dialog-action-recode-different.c
new file mode 100644 (file)
index 0000000..2d28146
--- /dev/null
@@ -0,0 +1,448 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2007, 2009, 2010, 2011, 2012, 2014, 2016  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "psppire-var-view.h"
+
+#include "psppire-dialog-action-recode-different.h"
+#include "builder-wrapper.h"
+#include <ui/gui/dialog-common.h>
+
+#include "psppire-acr.h"
+
+#include "psppire-selector.h"
+#include "psppire-val-chooser.h"
+
+#include "helper.h"
+#include <ui/syntax-gen.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+
+
+static gboolean
+difx_variable_treeview_is_populated (PsppireDialogActionRecode *rd)
+{
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+  GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
+  
+  if (g_hash_table_size (rdd->varmap) != gtk_tree_model_iter_n_children (model, NULL) )
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/* Dialog is valid iff at least one variable has been selected,
+   AND the list of mappings is not empty.
+*/
+static gboolean
+dialog_state_valid (gpointer data)
+{
+  PsppireDialogActionRecode *rd = data;
+  GtkTreeIter not_used;
+      
+  if ( ! rd->value_map )
+    return FALSE;
+
+  if ( ! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map),
+                                       &not_used) )
+    return FALSE;
+
+
+  return difx_variable_treeview_is_populated (rd);
+}
+
+
+\f
+
+static void
+psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class);
+
+G_DEFINE_TYPE (PsppireDialogActionRecodeDifferent, psppire_dialog_action_recode_different, PSPPIRE_TYPE_DIALOG_ACTION_RECODE);
+
+static void
+refresh (PsppireDialogAction *act)
+{
+  PsppireDialogActionRecode *rd = PSPPIRE_DIALOG_ACTION_RECODE (act);
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  psppire_dialog_action_recode_refresh (act);
+
+  if (rdd->varmap)
+    g_hash_table_remove_all (rdd->varmap);
+}
+
+
+static void
+on_old_new_show (PsppireDialogActionRecode *rd)
+{
+  gtk_toggle_button_set_active
+    (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE);
+
+  g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled");
+
+  gtk_widget_show (rd->toggle[BUTTON_NEW_COPY]);
+  gtk_widget_show (rd->new_copy_label);
+  gtk_widget_show (rd->strings_box);
+}
+
+\f
+
+/* Name-Label pair */
+struct nlp
+{
+  char *name;
+  char *label;
+};
+
+
+static struct nlp *
+nlp_create (const char *name, const char *label)
+{
+  struct nlp *nlp = xmalloc (sizeof *nlp);
+
+  nlp->name = g_strdup (name);
+
+  nlp->label = NULL;
+
+  if ( 0 != strcmp ("", label))
+    nlp->label = g_strdup (label);
+
+  return nlp;
+}
+
+static void
+nlp_destroy (gpointer data)
+{
+  struct nlp *nlp = data ;
+  if ( ! nlp )
+    return;
+
+  g_free (nlp->name);
+  g_free (nlp->label);
+  g_free (nlp);
+}
+
+\f
+
+static void
+render_new_var_name (GtkTreeViewColumn *tree_column,
+                    GtkCellRenderer *cell,
+                    GtkTreeModel *tree_model,
+                    GtkTreeIter *iter,
+                    gpointer data)
+{
+  struct nlp *nlp = NULL;
+  PsppireDialogActionRecode *rd = data;
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  struct variable *var = NULL;
+
+  gtk_tree_model_get (tree_model, iter, 
+                     0, &var,
+                     -1);
+
+  nlp = g_hash_table_lookup (rdd->varmap, var);
+
+  if ( nlp )
+    g_object_set (cell, "text", nlp->name, NULL);
+  else
+    g_object_set (cell, "text", "", NULL);
+}
+
+static void
+on_change_clicked (GObject *obj, gpointer data)
+{
+  PsppireDialogActionRecode *rd = data;
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  struct variable *var = NULL;
+  struct nlp *nlp;
+
+  GtkTreeModel *model =  gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
+
+  GtkTreeIter iter;
+  GtkTreeSelection *selection =
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (rd->variable_treeview));
+
+  GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
+
+  const gchar *dest_var_name =
+    gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
+
+  const gchar *dest_var_label =
+    gtk_entry_get_text (GTK_ENTRY (rd->new_label_entry));
+
+  if ( NULL == rows || rows->next != NULL)
+    goto finish;
+
+  gtk_tree_model_get_iter (model, &iter, rows->data);
+
+  gtk_tree_model_get (model, &iter, 0, &var, -1);
+
+  g_hash_table_remove (rdd->varmap, var);
+
+  nlp = nlp_create (dest_var_name, dest_var_label);
+
+  g_hash_table_insert (rdd->varmap, var, nlp);
+
+  gtk_tree_model_row_changed (model, rows->data, &iter);
+
+ finish:
+  g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
+  g_list_free (rows);
+}
+
+
+
+/* Callback which gets called when a new row is selected
+   in the variable treeview.
+   It sets the name and label entry widgets to reflect the
+   currently selected row.
+*/
+static void
+on_selection_change (GtkTreeSelection *selection, gpointer data)
+{
+  PsppireDialogActionRecode *rd = data;
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
+
+  GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
+
+  if ( rows && !rows->next)
+    {
+      /* Exactly one row is selected */
+      struct nlp *nlp;
+      struct variable *var;
+      gboolean ok;
+      GtkTreeIter iter;
+
+      gtk_widget_set_sensitive  (rd->change_button, TRUE);
+      gtk_widget_set_sensitive  (rd->new_name_entry, TRUE);
+      gtk_widget_set_sensitive  (rd->new_label_entry, TRUE);
+
+      ok = gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) rows->data);
+      g_return_if_fail (ok);
+
+      gtk_tree_model_get (model, &iter,
+                         0, &var, 
+                         -1);
+
+      nlp = g_hash_table_lookup (rdd->varmap, var);
+
+      if (nlp)
+       {
+         gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), nlp->name ? nlp->name : "");
+         gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), nlp->label ? nlp->label : "");
+       }
+      else
+       {
+         gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
+         gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
+       }
+    }
+  else
+    {
+      gtk_widget_set_sensitive  (rd->change_button, FALSE);
+      gtk_widget_set_sensitive  (rd->new_name_entry, FALSE);
+      gtk_widget_set_sensitive  (rd->new_label_entry, FALSE);
+
+      gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
+      gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
+    }
+
+
+  g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
+  g_list_free (rows);
+}
+
+
+
+
+static void
+populate_treeview (PsppireDialogActionRecode *act)
+{
+  GtkTreeSelection *sel;
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (act);
+  GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+  GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"),
+                                                                    renderer,
+                                                                    "text", NULL,
+                                                                    NULL);
+
+  gtk_tree_view_column_set_cell_data_func (col, renderer,
+                                          render_new_var_name,
+                                          act, NULL);
+
+  gtk_tree_view_append_column (GTK_TREE_VIEW (act->variable_treeview), col);
+
+  col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->variable_treeview), 0);
+
+  g_object_set (col, "title", _("Old"), NULL);
+
+  g_object_set (act->variable_treeview, "headers-visible", TRUE, NULL);
+
+  rdd->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy);
+
+  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->variable_treeview));
+
+  g_signal_connect (sel, "changed",
+                   G_CALLBACK (on_selection_change), act);
+
+  g_signal_connect (act->change_button, "clicked",
+                   G_CALLBACK (on_change_clicked),  act);
+}
+
+
+static void
+psppire_dialog_action_recode_different_activate (PsppireDialogAction *a)
+{
+  PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a);
+  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
+
+  psppire_dialog_action_recode_pre_activate (act, populate_treeview);
+
+  gtk_window_set_title (GTK_WINDOW (pda->dialog),
+                       _("Recode into Different Variables"));
+
+  gtk_window_set_title (GTK_WINDOW (act->old_and_new_dialog),
+                       _("Recode into Different Variables: Old and New Values "));
+
+  gtk_widget_show (act->output_variable_box);
+  
+  g_signal_connect_swapped (act->old_and_new_dialog, "show",
+                           G_CALLBACK (on_old_new_show), act);
+
+  psppire_dialog_action_set_refresh (pda, refresh);
+
+  psppire_dialog_action_set_valid_predicate (pda,
+                                            dialog_state_valid);
+
+  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_different_parent_class)->activate)
+    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_different_parent_class)->activate (pda);
+}
+
+static void
+append_into_clause (const PsppireDialogActionRecode *rd, struct string *dds)
+{
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  /* If applicable set the INTO clause which determines into which variables the new values go */
+  GtkTreeIter iter;
+  ds_put_cstr (dds, "\n\tINTO ");
+  gboolean ok;
+      
+  for (ok = psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter);
+       ok;
+       ok = psppire_var_view_get_iter_next (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter))
+    {
+      struct nlp *nlp = NULL;
+      const struct variable *var = psppire_var_view_get_variable (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &iter);
+
+      nlp = g_hash_table_lookup (rdd->varmap, var);
+           
+      ds_put_cstr (dds, nlp->name);
+      ds_put_cstr (dds, " ");
+    }
+}
+
+static void
+append_string_declarations (const PsppireDialogActionRecode *rd, struct string *dds)
+{
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  /* Declare new string variables if applicable */
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button)))
+    {
+      GHashTableIter iter;
+
+      struct variable *var = NULL;
+      struct nlp *nlp = NULL;
+
+      g_hash_table_iter_init (&iter, rdd->varmap);
+      while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
+       {
+         ds_put_cstr (dds, "\nSTRING ");
+         ds_put_cstr (dds, nlp->name);
+         ds_put_c_format (dds, " (A%d).",
+                          (int)
+                          gtk_spin_button_get_value (GTK_SPIN_BUTTON (rd->width_entry)));
+       }
+    }
+}
+
+static void
+append_new_value_labels (const PsppireDialogActionRecode *rd, struct string *dds)
+{
+  PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
+
+  /* If applicable, set labels for the new variables. */
+  GHashTableIter iter;
+
+  struct variable *var = NULL;
+  struct nlp *nlp = NULL;
+
+  g_hash_table_iter_init (&iter, rdd->varmap);
+  while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
+    {
+      if (nlp->label)
+       {
+         struct string sl;
+         ds_init_empty (&sl);
+         syntax_gen_string (&sl, ss_cstr (nlp->label));
+         ds_put_c_format (dds, "\nVARIABLE LABELS %s %s.",
+                          nlp->name, ds_cstr (&sl));
+
+         ds_destroy (&sl);
+       }
+    }
+}
+
+static char *
+diff_generate_syntax (const PsppireDialogAction *act)
+{
+  return psppire_dialog_action_recode_generate_syntax (act,
+                                                      append_string_declarations,
+                                                      append_into_clause,
+                                                      append_new_value_labels);
+}
+
+static gboolean
+target_is_string (const PsppireDialogActionRecode *rd)
+{
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button));
+}
+
+static void
+psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class)
+{
+  psppire_dialog_action_set_activation (class, psppire_dialog_action_recode_different_activate);
+
+  PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = diff_generate_syntax;
+  PSPPIRE_DIALOG_ACTION_RECODE_CLASS (class)->target_is_string = target_is_string;
+}
+
+
+static void
+psppire_dialog_action_recode_different_init (PsppireDialogActionRecodeDifferent *act)
+{
+}
+
diff --git a/src/ui/gui/psppire-dialog-action-recode-different.h b/src/ui/gui/psppire-dialog-action-recode-different.h
new file mode 100644 (file)
index 0000000..03e199f
--- /dev/null
@@ -0,0 +1,75 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2012  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include "psppire-dialog-action-recode.h"
+
+#ifndef __PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT_H__
+#define __PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT_H__
+
+G_BEGIN_DECLS
+
+
+#define PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT (psppire_dialog_action_recode_different_get_type ())
+
+#define PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT(obj)    \
+                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                                 PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, PsppireDialogActionRecodeDifferent))
+
+#define PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, \
+                                 PsppireDialogActionRecodeDifferentClass))
+
+
+#define PSPPIRE_IS_DIALOG_ACTION_RECODE_DIFFERENT(obj) \
+                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT))
+
+#define PSPPIRE_IS_DIALOG_ACTION_RECODE_DIFFERENT_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT))
+
+
+#define PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                  PSPPIRE_TYPE_DIALOG_ACTION_RECODE_DIFFERENT, \
+                                  PsppireDialogActionRecodeDifferentClass))
+
+typedef struct _PsppireDialogActionRecodeDifferent       PsppireDialogActionRecodeDifferent;
+typedef struct _PsppireDialogActionRecodeDifferentClass  PsppireDialogActionRecodeDifferentClass;
+
+
+struct _PsppireDialogActionRecodeDifferent
+{
+  PsppireDialogActionRecode parent;
+
+  /* A hash table of struct nlp's indexed by variable */
+  GHashTable *varmap;
+};
+
+
+struct _PsppireDialogActionRecodeDifferentClass
+{
+  PsppireDialogActionRecodeClass parent_class;
+};
+
+
+GType psppire_dialog_action_recode_different_get_type (void) ;
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT_H__ */
diff --git a/src/ui/gui/psppire-dialog-action-recode-same.c b/src/ui/gui/psppire-dialog-action-recode-same.c
new file mode 100644 (file)
index 0000000..975ff8c
--- /dev/null
@@ -0,0 +1,159 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2007, 2009, 2010, 2011, 2012, 2014, 2016  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+
+#include <config.h>
+
+#include "psppire-var-view.h"
+
+#include "psppire-dialog-action-recode-same.h"
+#include "builder-wrapper.h"
+#include <ui/gui/dialog-common.h>
+
+#include "psppire-acr.h"
+
+#include "psppire-selector.h"
+#include "psppire-val-chooser.h"
+
+#include "helper.h"
+#include <ui/syntax-gen.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+static gboolean
+difx_variable_treeview_is_populated (PsppireDialogActionRecode *rd)
+{
+  GtkTreeIter not_used;
+
+  GtkTreeModel *vars =
+    gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
+
+  if ( !gtk_tree_model_get_iter_first (vars, &not_used))
+    return FALSE;
+
+  return TRUE;
+}
+
+
+/* Dialog is valid iff at least one variable has been selected,
+   AND the list of mappings is not empty.
+ */
+static gboolean
+dialog_state_valid (gpointer data)
+{
+  PsppireDialogActionRecode *rd = data;
+  GtkTreeIter not_used;
+      
+  if ( ! rd->value_map )
+    return FALSE;
+
+  if ( ! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map),
+                                       &not_used) )
+    return FALSE;
+
+  return difx_variable_treeview_is_populated (rd);
+}
+
+
+\f
+
+static void
+psppire_dialog_action_recode_same_class_init (PsppireDialogActionRecodeSameClass *class);
+
+G_DEFINE_TYPE (PsppireDialogActionRecodeSame, psppire_dialog_action_recode_same, PSPPIRE_TYPE_DIALOG_ACTION_RECODE);
+
+static void
+refresh (PsppireDialogAction *rd)
+{
+  psppire_dialog_action_recode_refresh (rd);
+}
+
+static void
+on_old_new_show (PsppireDialogActionRecode *rd)
+{
+  gtk_toggle_button_set_active
+    (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE);
+
+  g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled");
+
+  gtk_widget_hide (rd->toggle[BUTTON_NEW_COPY]);
+  gtk_widget_hide (rd->new_copy_label);
+  gtk_widget_hide (rd->strings_box);
+}
+
+static void
+psppire_dialog_action_recode_same_activate (PsppireDialogAction *a)
+{
+  PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a);
+  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
+
+  psppire_dialog_action_recode_pre_activate (act, NULL);
+
+  gtk_window_set_title (GTK_WINDOW (pda->dialog),
+                       _("Recode into Same Variables"));
+  
+  g_signal_connect_swapped (act->old_and_new_dialog, "show",
+                           G_CALLBACK (on_old_new_show), act);
+
+  gtk_window_set_title (GTK_WINDOW (act->old_and_new_dialog),
+                       _("Recode into Same Variables: Old and New Values"));
+
+  gtk_widget_hide (act->output_variable_box);
+  
+  psppire_dialog_action_set_refresh (pda, refresh);
+
+  psppire_dialog_action_set_valid_predicate (pda,
+                                       dialog_state_valid);
+
+  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_same_parent_class)->activate)
+    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_same_parent_class)->activate (pda);
+}
+
+static void
+null_op (const PsppireDialogActionRecode *rd, struct string *dds)
+{
+}
+
+static char *
+same_generate_syntax (const PsppireDialogAction *act)
+{
+  return psppire_dialog_action_recode_generate_syntax (act, null_op, null_op, null_op);
+}
+
+static gboolean
+target_is_string (const PsppireDialogActionRecode *rd)
+{
+  return rd->input_var_is_string;
+}
+
+
+static void
+psppire_dialog_action_recode_same_class_init (PsppireDialogActionRecodeSameClass *class)
+{
+  psppire_dialog_action_set_activation (class, psppire_dialog_action_recode_same_activate);
+
+  PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = same_generate_syntax;
+  PSPPIRE_DIALOG_ACTION_RECODE_CLASS (class)->target_is_string = target_is_string;
+}
+
+
+static void
+psppire_dialog_action_recode_same_init (PsppireDialogActionRecodeSame *act)
+{
+}
+
diff --git a/src/ui/gui/psppire-dialog-action-recode-same.h b/src/ui/gui/psppire-dialog-action-recode-same.h
new file mode 100644 (file)
index 0000000..f2a9be5
--- /dev/null
@@ -0,0 +1,71 @@
+/* PSPPIRE - a graphical user interface for PSPP.
+   Copyright (C) 2012, 2016  Free Software Foundation
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+
+#include <glib-object.h>
+#include <glib.h>
+
+#include "psppire-dialog-action-recode.h"
+
+#ifndef __PSPPIRE_DIALOG_ACTION_RECODE_SAME_H__
+#define __PSPPIRE_DIALOG_ACTION_RECODE_SAME_H__
+
+G_BEGIN_DECLS
+
+#define PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME (psppire_dialog_action_recode_same_get_type ())
+
+#define PSPPIRE_DIALOG_ACTION_RECODE_SAME(obj) \
+                     (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                                 PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, PsppireDialogActionRecodeSame))
+
+#define PSPPIRE_DIALOG_ACTION_RECODE_SAME_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, \
+                                 PsppireDialogActionRecodeSameClass))
+
+
+#define PSPPIRE_IS_DIALOG_ACTION_RECODE_SAME(obj) \
+                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME))
+
+#define PSPPIRE_IS_DIALOG_ACTION_RECODE_SAME_CLASS(klass) \
+                     (G_TYPE_CHECK_CLASS_TYPE ((klass), PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME))
+
+
+#define PSPPIRE_DIALOG_ACTION_RECODE_SAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                  PSPPIRE_TYPE_DIALOG_ACTION_RECODE_SAME, \
+                                  PsppireDialogActionRecodeSameClass))
+
+typedef struct _PsppireDialogActionRecodeSame       PsppireDialogActionRecodeSame;
+typedef struct _PsppireDialogActionRecodeSameClass  PsppireDialogActionRecodeSameClass;
+
+
+struct _PsppireDialogActionRecodeSame
+{
+  PsppireDialogActionRecode parent;
+};
+
+
+struct _PsppireDialogActionRecodeSameClass
+{
+  PsppireDialogActionRecodeClass parent_class;
+};
+
+
+GType psppire_dialog_action_recode_same_get_type (void) ;
+
+G_END_DECLS
+
+#endif /* __PSPPIRE_DIALOG_ACTION_RECODE_SAME_H__ */
index d4066dbd06d378513aefec5102f58a9b7f3c1f53..6e8b222b47812273fdf77c6e5734777ec1680ebc 100644 (file)
@@ -122,7 +122,7 @@ new_value_to_string (const GValue *src, GValue *dest)
     }
 }
 
-static GType
+GType
 new_value_get_type (void)
 {
   static GType t = 0;
@@ -153,102 +153,6 @@ on_string_toggled (GtkToggleButton *b, PsppireDialogActionRecode *rd)
   gtk_widget_set_sensitive (rd->convert_button, !active);
 }
 
-/* Name-Label pair */
-struct nlp
-{
-  char *name;
-  char *label;
-};
-
-static struct nlp *
-nlp_create (const char *name, const char *label)
-{
-  struct nlp *nlp = xmalloc (sizeof *nlp);
-
-  nlp->name = g_strdup (name);
-
-  nlp->label = NULL;
-
-  if ( 0 != strcmp ("", label))
-    nlp->label = g_strdup (label);
-
-  return nlp;
-}
-
-static void
-nlp_destroy (gpointer data)
-{
-  struct nlp *nlp = data ;
-  if ( ! nlp )
-    return;
-
-  g_free (nlp->name);
-  g_free (nlp->label);
-  g_free (nlp);
-}
-
-
-/* Callback which gets called when a new row is selected
-   in the variable treeview.
-   It sets the name and label entry widgets to reflect the
-   currently selected row.
- */
-static void
-on_selection_change (GtkTreeSelection *selection, gpointer data)
-{
-  PsppireDialogActionRecode *rd = data;
-
-  GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
-
-  GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
-
-  if ( rows && !rows->next)
-    {
-      /* Exactly one row is selected */
-      struct nlp *nlp;
-      struct variable *var;
-      gboolean ok;
-      GtkTreeIter iter;
-
-      gtk_widget_set_sensitive  (rd->change_button, TRUE);
-      gtk_widget_set_sensitive  (rd->new_name_entry, TRUE);
-      gtk_widget_set_sensitive  (rd->new_label_entry, TRUE);
-
-      ok = gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) rows->data);
-      g_return_if_fail (ok);
-
-      gtk_tree_model_get (model, &iter,
-                         0, &var, 
-                         -1);
-
-      nlp = g_hash_table_lookup (rd->varmap, var);
-
-      if (nlp)
-       {
-         gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), nlp->name ? nlp->name : "");
-         gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), nlp->label ? nlp->label : "");
-       }
-      else
-       {
-         gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
-         gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
-       }
-    }
-  else
-    {
-      gtk_widget_set_sensitive  (rd->change_button, FALSE);
-      gtk_widget_set_sensitive  (rd->new_name_entry, FALSE);
-      gtk_widget_set_sensitive  (rd->new_label_entry, FALSE);
-
-      gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
-      gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
-    }
-
-
-  g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
-  g_list_free (rows);
-}
-
 
 static void
 on_convert_toggled (GtkToggleButton *b, PsppireDialogActionRecode *rd)
@@ -261,48 +165,6 @@ on_convert_toggled (GtkToggleButton *b, PsppireDialogActionRecode *rd)
   gtk_widget_set_sensitive (rd->string_button, !active);
 }
 
-static void
-on_change_clicked (GObject *obj, gpointer data)
-{
-  PsppireDialogActionRecode *rd = data;
-  struct variable *var = NULL;
-  struct nlp *nlp;
-
-  GtkTreeModel *model =  gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
-
-  GtkTreeIter iter;
-  GtkTreeSelection *selection =
-    gtk_tree_view_get_selection (GTK_TREE_VIEW (rd->variable_treeview));
-
-  GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
-
-  const gchar *dest_var_name =
-    gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
-
-  const gchar *dest_var_label =
-    gtk_entry_get_text (GTK_ENTRY (rd->new_label_entry));
-
-  if ( NULL == rows || rows->next != NULL)
-    goto finish;
-
-  gtk_tree_model_get_iter (model, &iter, rows->data);
-
-  gtk_tree_model_get (model, &iter, 0, &var, -1);
-
-  g_hash_table_remove (rd->varmap, var);
-
-  nlp = nlp_create (dest_var_name, dest_var_label);
-
-  g_hash_table_insert (rd->varmap, var, nlp);
-
-  gtk_tree_model_row_changed (model, rows->data, &iter);
-
- finish:
-  g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
-  g_list_free (rows);
-}
-
-
 static void
 focus_value_entry (GtkWidget *w, PsppireDialogActionRecode *rd)
 {
@@ -330,47 +192,12 @@ set_acr (PsppireDialogActionRecode *rd)
   psppire_acr_set_enabled (PSPPIRE_ACR (rd->acr), !g_str_equal (text, ""));
 }
 
-enum {
-  COL_VALUE_OLD,
-  COL_VALUE_NEW,
-  n_COL_VALUES
-};
-
-/* Dialog is valid iff at least one variable has been selected,
-   AND the list of mappings is not empty.
- */
-static gboolean
-dialog_state_valid (gpointer data)
-{
-  GtkTreeIter not_used;
-  PsppireDialogActionRecode *rd = data;
-
-  if ( ! rd->value_map )
-    return FALSE;
-
-  if ( ! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map),
-                                       &not_used) )
-    return FALSE;
-
-  if ( rd->different )
-    {
-      GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
-
-      if (g_hash_table_size (rd->varmap) != gtk_tree_model_iter_n_children (model, NULL) )
-       return FALSE;
-    }
-  else
-    {
-      GtkTreeModel *vars =
-       gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
-
-      if ( !gtk_tree_model_get_iter_first (vars, &not_used))
-       return FALSE;
-    }
-
-  return TRUE;
-}
-
+enum
+  {
+    COL_VALUE_OLD,
+    COL_VALUE_NEW,
+    n_COL_VALUES
+  };
 
 /* Callback which gets called when a new row is selected
    in the acr's variable treeview.
@@ -468,34 +295,26 @@ set_new_value (GValue *val, const PsppireDialogActionRecode *rd)
   const gchar *text = NULL;
   struct new_value nv;
 
-  if ( gtk_toggle_button_get_active
-       (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_VALUE])))
+  if (gtk_toggle_button_get_active
+      (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_VALUE])))
     {
       text = gtk_entry_get_text (GTK_ENTRY (rd->new_value_entry));
-
       nv.type = NV_NUMERIC;
-      if (
-         (! rd->different && rd->input_var_is_string) ||
-         ( rd->different &&
-           gtk_toggle_button_get_active
-              (GTK_TOGGLE_BUTTON (rd->string_button)))
-         )
-       {
-         nv.type = NV_STRING;
-       }
+
+      if (PSPPIRE_DIALOG_ACTION_RECODE_CLASS (G_OBJECT_GET_CLASS (rd))->target_is_string (rd))
+       nv.type = NV_STRING;
 
       if ( nv.type == NV_STRING )
        nv.v.s = g_strdup (text);
       else
        nv.v.v = g_strtod (text, 0);
     }
-  else if ( gtk_toggle_button_get_active
+  else if (gtk_toggle_button_get_active
            (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_COPY])))
     {
       nv.type = NV_COPY;
     }
-
-  else if ( gtk_toggle_button_get_active
+  else if (gtk_toggle_button_get_active
            (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_NEW_SYSMIS])))
     {
       nv.type = NV_SYSMIS;
@@ -540,13 +359,6 @@ run_old_and_new_dialog (PsppireDialogActionRecode *rd)
   psppire_acr_set_model (PSPPIRE_ACR (rd->acr), local_store);
   psppire_acr_set_get_value_func (PSPPIRE_ACR (rd->acr), set_value, rd);
 
-  gtk_window_set_title (GTK_WINDOW (rd->old_and_new_dialog),
-                       rd->different
-                       ? _("Recode into Different Variables: Old and New Values ")
-                       : _("Recode into Same Variables: Old and New Values")
-                       );
-
-
   {
     /* Find the type of the first variable (it's invariant that
        all variables are of the same type) */
@@ -588,24 +400,6 @@ run_old_and_new_dialog (PsppireDialogActionRecode *rd)
   psppire_dialog_notify_change (PSPPIRE_DIALOG (pda->dialog));
 }
 
-static void
-on_old_new_show (PsppireDialogActionRecode *rd)
-{
-  gtk_toggle_button_set_active
-    (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE);
-
-  g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled");
-
-  g_object_set (rd->toggle[BUTTON_NEW_COPY],
-               "visible", rd->different, NULL);
-
-  g_object_set (rd->new_copy_label,
-               "visible", rd->different, NULL);
-
-  g_object_set (rd->strings_box,
-               "visible", rd->different, NULL);
-}
-
 
 /* Sets the sensitivity of TARGET dependent upon the active status
    of BUTTON */
@@ -620,31 +414,6 @@ toggle_sensitivity (GtkToggleButton *button, GtkWidget *target)
   gtk_widget_set_sensitive (target, state);
 }
 
-static void
-render_new_var_name (GtkTreeViewColumn *tree_column,
-                    GtkCellRenderer *cell,
-                    GtkTreeModel *tree_model,
-                    GtkTreeIter *iter,
-                    gpointer data)
-{
-  struct nlp *nlp = NULL;
-  PsppireDialogActionRecode *rd = data;
-
-  struct variable *var = NULL;
-
-  gtk_tree_model_get (tree_model, iter, 
-                     0, &var,
-                     -1);
-
-  nlp = g_hash_table_lookup (rd->varmap, var);
-
-  if ( nlp )
-    g_object_set (cell, "text", nlp->name, NULL);
-  else
-    g_object_set (cell, "text", "", NULL);
-}
-
-
 
 \f
 
@@ -653,8 +422,8 @@ psppire_dialog_action_recode_class_init (PsppireDialogActionRecodeClass *class);
 
 G_DEFINE_TYPE (PsppireDialogActionRecode, psppire_dialog_action_recode, PSPPIRE_TYPE_DIALOG_ACTION);
 
-static void
-refresh (PsppireDialogAction *rd_)
+void
+psppire_dialog_action_recode_refresh (PsppireDialogAction *rd_)
 {
   PsppireDialogActionRecode *rd = PSPPIRE_DIALOG_ACTION_RECODE (rd_);
 
@@ -667,26 +436,29 @@ refresh (PsppireDialogAction *rd_)
   gtk_widget_set_sensitive (rd->new_name_entry, FALSE);
   gtk_widget_set_sensitive (rd->new_label_entry, FALSE);
 
-  if ( rd->different && rd->varmap )
-    g_hash_table_remove_all (rd->varmap);
-
   gtk_list_store_clear (GTK_LIST_STORE (rd->value_map));
 }
 
 
-
 static void
-psppire_dialog_action_recode_activate (PsppireDialogAction *a)
+psppire_dialog_action_recode_activate (PsppireDialogAction *act)
 {
-  PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a);
-  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
+  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_parent_class)->activate)
+    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_parent_class)->activate (act);
+}
+
+
+void
+psppire_dialog_action_recode_pre_activate (PsppireDialogActionRecode *act, void (*populate_treeview) (PsppireDialogActionRecode *))
+{
+  PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (act);
 
   GHashTable *thing = psppire_dialog_action_get_hash_table (pda);
-  GtkBuilder *xml = g_hash_table_lookup (thing, a);
+  GtkBuilder *xml = g_hash_table_lookup (thing, act);
   if (!xml)
     {
       xml = builder_new ("recode.ui");
-      g_hash_table_insert (thing, a, xml);
+      g_hash_table_insert (thing, act, xml);
 
       pda->dialog = get_widget_assert   (xml, "recode-dialog");
       pda->source = get_widget_assert   (xml, "treeview1");
@@ -696,10 +468,9 @@ psppire_dialog_action_recode_activate (PsppireDialogAction *a)
       GtkWidget *oldandnew = get_widget_assert (xml, "button1");
 
 
-      GtkWidget *output_variable_box = get_widget_assert (xml,"frame4");
+      act->output_variable_box = get_widget_assert (xml,"frame4");
 
       act->change_button = get_widget_assert (xml, "change-button");
-      act->varmap = NULL;
       act->variable_treeview =   get_widget_assert (xml, "treeview2");
       act->new_name_entry = get_widget_assert (xml, "dest-name-entry");
       act->new_label_entry = get_widget_assert (xml, "dest-label-entry");
@@ -708,51 +479,8 @@ psppire_dialog_action_recode_activate (PsppireDialogAction *a)
                                           old_value_get_type (),
                                           new_value_get_type ());
 
-      if (act->different)
-       gtk_window_set_title (GTK_WINDOW (pda->dialog),
-                             _("Recode into Different Variables"));
-      else
-       gtk_window_set_title (GTK_WINDOW (pda->dialog),
-                             _("Recode into Same Variables"));
-
-      g_object_set (output_variable_box, "visible", act->different, NULL);
-
-      if (act->different)
-       {
-         GtkTreeSelection *sel;
-
-         GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
-
-         GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"),
-                                                                            renderer,
-                                                                            "text", NULL,
-                                                                            NULL);
-
-         gtk_tree_view_column_set_cell_data_func (col, renderer,
-                                                  render_new_var_name,
-                                                  act, NULL);
-
-
-         gtk_tree_view_append_column (GTK_TREE_VIEW (act->variable_treeview), col);
-
-
-         col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->variable_treeview), 0);
-
-         g_object_set (col, "title", _("Old"), NULL);
-
-         g_object_set (act->variable_treeview, "headers-visible", TRUE, NULL);
-
-         act->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy);
-
-         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->variable_treeview));
-
-         g_signal_connect (sel, "changed",
-                           G_CALLBACK (on_selection_change), act);
-
-         g_signal_connect (act->change_button, "clicked",
-                           G_CALLBACK (on_change_clicked),  act);
-       }
-
+      if (populate_treeview)
+       populate_treeview (act);
       
       psppire_selector_set_allow (PSPPIRE_SELECTOR (selector), homogeneous_types);
 
@@ -835,19 +563,8 @@ psppire_dialog_action_recode_activate (PsppireDialogAction *a)
 
        g_signal_connect (act->convert_button, "toggled",
                          G_CALLBACK (on_convert_toggled), act);
-
-       g_signal_connect_swapped (act->old_and_new_dialog, "show",
-                                 G_CALLBACK (on_old_new_show), act);
       }
     }
-
-  psppire_dialog_action_set_refresh (pda, refresh);
-
-  psppire_dialog_action_set_valid_predicate (pda,
-                                       dialog_state_valid);
-
-  if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_parent_class)->activate)
-    PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_recode_parent_class)->activate (pda);
 }
 
 /* Generate a syntax fragment for NV and append it to STR */
@@ -877,8 +594,11 @@ new_value_append_syntax (struct string *dds, const struct new_value *nv)
 }
 
 
-static char *
-generate_syntax (const PsppireDialogAction *act)
+char *
+psppire_dialog_action_recode_generate_syntax (const PsppireDialogAction *act,
+                                             void (*append_string_decls) (const PsppireDialogActionRecode *, struct string *),
+                                             void (*append_into_clause) (const PsppireDialogActionRecode *, struct string *),
+                                             void (*append_new_value_labels) (const PsppireDialogActionRecode *, struct string *))
 {
   PsppireDialogActionRecode *rd = PSPPIRE_DIALOG_ACTION_RECODE (act);
   gboolean ok;
@@ -888,28 +608,8 @@ generate_syntax (const PsppireDialogAction *act)
 
   ds_init_empty (&dds);
 
-
-  /* Declare new string variables if applicable */
-  if ( rd->different &&
-       gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button)))
-    {
-      GHashTableIter iter;
-
-      struct variable *var = NULL;
-      struct nlp *nlp = NULL;
-
-      g_hash_table_iter_init (&iter, rd->varmap);
-      while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
-       {
-         ds_put_cstr (&dds, "\nSTRING ");
-         ds_put_cstr (&dds, nlp->name);
-         ds_put_c_format (&dds, " (A%d).",
-                                 (int)
-                                 gtk_spin_button_get_value (GTK_SPIN_BUTTON (rd->width_entry) )
-                                 );
-       }
-    }
-
+  append_string_decls (rd, &dds);
+  
   ds_put_cstr (&dds, "\nRECODE ");
 
   psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &dds);
@@ -950,53 +650,12 @@ generate_syntax (const PsppireDialogAction *act)
       g_value_unset (&nv_value);
     }
 
-
-  if ( rd->different )
-    {
-
-      GtkTreeIter iter;
-      ds_put_cstr (&dds, "\n\tINTO ");
-
-      for (ok = psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter);
-          ok;
-          ok = psppire_var_view_get_iter_next (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter))
-         {
-           struct nlp *nlp = NULL;
-           const struct variable *var = psppire_var_view_get_variable (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &iter);
-
-           nlp = g_hash_table_lookup (rd->varmap, var);
-           
-           ds_put_cstr (&dds, nlp->name);
-           ds_put_cstr (&dds, " ");
-         }
-    }
+  append_into_clause (rd, &dds);
 
   ds_put_cstr (&dds, ".");
 
-  /* If applicable, set labels for the new variables. */
-  if ( rd->different )
-    {
-      GHashTableIter iter;
-
-      struct variable *var = NULL;
-      struct nlp *nlp = NULL;
-
-      g_hash_table_iter_init (&iter, rd->varmap);
-      while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
-       {
-         if (nlp->label)
-           {
-             struct string sl;
-             ds_init_empty (&sl);
-             syntax_gen_string (&sl, ss_cstr (nlp->label));
-             ds_put_c_format (&dds, "\nVARIABLE LABELS %s %s.",
-                                     nlp->name, ds_cstr (&sl));
-
-             ds_destroy (&sl);
-           }
-       }
-    }
-
+  append_new_value_labels (rd, &dds);
+  
   ds_put_cstr (&dds, "\nEXECUTE.\n");
 
 
@@ -1008,75 +667,10 @@ generate_syntax (const PsppireDialogAction *act)
 }
 
 
-enum
-{
-  PROP_0,
-  PROP_DIFF
-};
-
-static void
-__set_property (GObject         *object,
-               guint            prop_id,
-               const GValue    *value,
-               GParamSpec      *pspec)
-{
-  PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (object);
-
-  switch (prop_id)
-    {
-    case PROP_DIFF:
-      act->different = g_value_get_boolean (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    };
-}
-
-
-static void
-__get_property (GObject         *object,
-               guint            prop_id,
-               GValue          *value,
-               GParamSpec      *pspec)
-{
-  PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (object);
-
-  switch (prop_id)
-    {
-    case PROP_DIFF:
-      g_value_set_boolean (value, act->different);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    };
-}
-
-
 static void
 psppire_dialog_action_recode_class_init (PsppireDialogActionRecodeClass *class)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (class);
-
   psppire_dialog_action_set_activation (class, psppire_dialog_action_recode_activate);
-
-  PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
-
-  GParamSpec *diff_spec =
-    g_param_spec_boolean ("recode-to-new-variable",
-                         "Recode to New Variable",
-                         "True iff the new values should be placed in a new variable",
-                         FALSE,
-                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
-
-
-  object_class->set_property = __set_property;
-  object_class->get_property = __get_property;
-  
-  g_object_class_install_property (object_class,
-                                   PROP_DIFF,
-                                   diff_spec);
 }
 
 
index 37d18d5c46ca1deccdd8e32ff021fef70592c87b..f46c34aaa628fea48a9f432dde18cc5bd38c1fce 100644 (file)
@@ -74,16 +74,13 @@ struct _PsppireDialogActionRecode
   GtkWidget *convert_button;
   GtkWidget *new_copy_label;
 
+
   GtkWidget *new_value_entry;
 
   GtkWidget *old_value_chooser;
 
   GtkListStore *value_map;
 
-  /* Indicates that the INTO {new variables} form of the dialog
-     is being used */
-  gboolean different;
-
   GtkWidget *acr;
 
   gboolean input_var_is_string;
@@ -92,22 +89,35 @@ struct _PsppireDialogActionRecode
   GtkWidget *new_label_entry;
   GtkWidget *change_button;
 
+  GtkWidget *output_variable_box;
+  
   GtkWidget *string_button;
   GtkWidget *width_entry;
-
-  /* A hash table of struct nlp's indexed by variable */
-  GHashTable *varmap;
 };
 
 
 struct _PsppireDialogActionRecodeClass
 {
   PsppireDialogActionClass parent_class;
-};
 
+  gboolean (*target_is_string) (const PsppireDialogActionRecode *);
+};
 
 GType psppire_dialog_action_recode_get_type (void) ;
 
+void psppire_dialog_action_recode_refresh (PsppireDialogAction *);
+
+void psppire_dialog_action_recode_pre_activate (PsppireDialogActionRecode *act, void (*populate_treeview) (PsppireDialogActionRecode *) );
+
+
+GType new_value_get_type (void);
+
+
+char *psppire_dialog_action_recode_generate_syntax (const PsppireDialogAction *act,
+                                                   void (*add_string_decls) (const PsppireDialogActionRecode *, struct string *),
+                                                   void (*add_into_clause) (const PsppireDialogActionRecode *, struct string *),
+                                                   void (*add_new_value_labels) (const PsppireDialogActionRecode *, struct string *));
+
 G_END_DECLS
 
 #endif /* __PSPPIRE_DIALOG_ACTION_RECODE_H__ */
index 21f9f0439ce52e8292ff2ea49eedc2198f572a2b..998f7bb45c73c6e02f92c216dc35664d2051a43e 100644 (file)
@@ -175,28 +175,29 @@ psppire_dialog_action_var_info_activate (PsppireDialogAction *a)
     {
       xml = builder_new ("variable-info.ui");
       g_hash_table_insert (thing, a, xml);
-    }
-
-  act->output = psppire_output_view_new (
-    GTK_LAYOUT (get_widget_assert (xml, "layout1")), NULL, NULL, NULL);
 
-  pda->dialog = get_widget_assert (xml, "variable-info-dialog");
-  pda->source = get_widget_assert (xml, "treeview2");
+      act->output =
+       psppire_output_view_new (GTK_LAYOUT (get_widget_assert (xml, "layout1")),
+                                NULL, NULL, NULL);
+  
+      pda->dialog = get_widget_assert (xml, "variable-info-dialog");
+      pda->source = get_widget_assert (xml, "treeview2");
 
-  g_object_set (pda->source,
-               "selection-mode", GTK_SELECTION_MULTIPLE,
-               NULL);
+      g_object_set (pda->source,
+                   "selection-mode", GTK_SELECTION_MULTIPLE,
+                   NULL);
 
-  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (pda->source)),
-                    "changed", G_CALLBACK (populate_output),
-                   act);
+      g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (pda->source)),
+                       "changed", G_CALLBACK (populate_output),
+                       act);
 
-  g_signal_connect (pda->dialog, "response", G_CALLBACK (jump_to),
-                   pda);
-
-  psppire_dialog_action_set_valid_predicate (pda,
-                                            treeview_item_selected);
+      g_signal_connect (pda->dialog, "response", G_CALLBACK (jump_to),
+                       pda);
 
+      psppire_dialog_action_set_valid_predicate (pda,
+                                                treeview_item_selected);
+    }
+  
   if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_var_info_parent_class)->activate)
     PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_var_info_parent_class)->activate (pda);
 }
index 6fb0b87c47209d6992d43db005dc0ecc9621cc29..f3c360b35e06d192e93ae1f92379824a9b223cf9 100644 (file)
@@ -111,8 +111,8 @@ psppire_window_set_title (PsppireWindow *window)
   int minor = 1;
   sscanf (bare_version, "%*d.%d.%*d", &minor);
   if (minor % 2)
-    g_string_append (title, " - UNRELEASED TEST SOFTWARE!  NOT FOR PRODUCTION USE.");
-
+    g_string_append_printf (title, " - Test version! Please report bugs to %s", PACKAGE_BUGREPORT);
+  
   gtk_window_set_title (GTK_WINDOW (window), title->str);
 
   g_string_free (title, TRUE);
index 042b8fcee76ddaafa2e409d27dbd042709a4f3ac..3f138291ec0dc43d06f318aa6c40d97840bdab99 100644 (file)
@@ -43,7 +43,8 @@
 #include "psppire-dialog-action-oneway.h"
 #include "psppire-means-layer.h"
 #include "psppire-dialog-action-rank.h"
-#include "psppire-dialog-action-recode.h"
+#include "psppire-dialog-action-recode-same.h"
+#include "psppire-dialog-action-recode-different.h"
 #include "psppire-dialog-action-regression.h"
 #include "psppire-dialog-action-reliability.h"
 #include "psppire-dialog-action-roc.h"
@@ -92,7 +93,8 @@ static const get_type_func dialog_action_types[]=
   psppire_dialog_action_indep_samps_get_type,
   psppire_dialog_action_var_info_get_type,
   psppire_dialog_action_rank_get_type,
-  psppire_dialog_action_recode_get_type,
+  psppire_dialog_action_recode_same_get_type,
+  psppire_dialog_action_recode_different_get_type,
   psppire_dialog_action_reliability_get_type,
   psppire_dialog_action_regression_get_type,
   psppire_dialog_action_roc_get_type,
index b0b2616f7ae44cbc02740f0b383f6c957e1cc3b2..53f5d4fddc26b83645ff26314c96a8b4939d7c7f 100644 (file)
@@ -343,3 +343,40 @@ AT_CHECK([pspp -o pspp.csv x.sps], [1], [ignore])
 AT_CLEANUP
 
 
+
+AT_SETUP([GET DATA /TYPE=txt bug])
+
+
+AT_DATA([thing.txt], [dnl
+foo, title, last
+1, this, 1
+2, that, 2
+3, other, 3
+])
+
+AT_DATA([x.sps], [dnl
+GET DATA
+  /TYPE=TXT
+  /FILE="thing.txt"
+  /ARRANGEMENT=DELIMITED
+  /DELCASE=LINE
+  /FIRSTCASE=2
+  /DELIMITERS=","
+  /VARIABLES=foo F1.0
+    title A8
+    last F2.0.
+
+list.
+])
+
+AT_CHECK([pspp -O format=csv x.sps], [0], [dnl
+Table: Data List
+foo,title,last
+1,this   ,1
+2,that   ,2
+3,other  ,3
+])
+
+AT_CLEANUP
+
+
index f7fccb434df5675d70a0eb7a1844ef3139b36c4d..9cd2a04f09d1f73d5a983f3bff026bf4bc51e0c0 100644 (file)
@@ -431,7 +431,112 @@ z,Category,Statistic,Type,Value,Asymp. Std. Error,Approx. T,Approx. Sig.
 ]])
 AT_CLEANUP
 
+AT_SETUP([CROSSTABS rounding weights with COUNT])
+AT_DATA([crosstabs.sps],
+  [[DATA LIST NOTABLE LIST /x y w.
+BEGIN DATA.
+1 1 1.4
+1 1 1.4
+1 2 1.6
+1 2 1.6
+2 1 1
+2 2 2
+END DATA.
+WEIGHT BY w.
+
+* These should have the same effect (no rounding).
+CROSSTABS /TABLES x BY y.
+CROSSTABS /TABLES x BY y /COUNT ASIS.
+
+* Round input weights.
+CROSSTABS /TABLES x BY y /COUNT CASE ROUND.
+CROSSTABS /TABLES x BY y /COUNT CASE TRUNCATE.
+
+* Round cell weights.
+CROSSTABS /TABLES x BY y /COUNT.
+CROSSTABS /TABLES x BY y /COUNT TRUNCATE.
+]])
+
+AT_CHECK([pspp -O format=csv crosstabs.sps], [0],
+  [[Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+
+Table: x * y [count].
+,y,,
+x,1.00,2.00,Total
+1.00,2.80,3.20,6.00
+2.00,1.00,2.00,3.00
+Total,3.80,5.20,9.00
+
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+
+Table: x * y [count].
+,y,,
+x,1.00,2.00,Total
+1.00,2.80,3.20,6.00
+2.00,1.00,2.00,3.00
+Total,3.80,5.20,9.00
+
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
 
+Table: x * y [count].
+,y,,
+x,1.00,2.00,Total
+1.00,2.00,4.00,6.00
+2.00,1.00,2.00,3.00
+Total,3.00,6.00,9.00
+
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,7.00,100.0%,.00,0.0%,7.00,100.0%
+
+Table: x * y [count].
+,y,,
+x,1.00,2.00,Total
+1.00,2.00,2.00,4.00
+2.00,1.00,2.00,3.00
+Total,3.00,4.00,7.00
+
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,9.00,100.0%,.00,0.0%,9.00,100.0%
+
+Table: x * y [count].
+,y,,
+x,1.00,2.00,Total
+1.00,3.00,3.00,6.00
+2.00,1.00,2.00,3.00
+Total,4.00,5.00,9.00
+
+Table: Summary.
+,Cases,,,,,
+,Valid,,Missing,,Total,
+,N,Percent,N,Percent,N,Percent
+x * y,8.00,100.0%,.00,0.0%,8.00,100.0%
+
+Table: x * y [count].
+,y,,
+x,1.00,2.00,Total
+1.00,2.00,3.00,5.00
+2.00,1.00,2.00,3.00
+Total,3.00,5.00,8.00
+]])
+AT_CLEANUP
 
 AT_SETUP([CROSSTABS descending sort order])
 AT_DATA([crosstabs-descending.sps],
index f0d81c321075d4edec21af52a38520acf88fd03a..7c55110c967adc581e852049890f53bf5bb1ed94 100644 (file)
@@ -761,3 +761,27 @@ FREQUENCIES
 AT_CHECK([pspp empty.sps -O format=csv], [0],  [ignore])
 
 AT_CLEANUP
+
+AT_SETUP([FREQUENCIES percentiles + histogram bug#48128])
+AT_DATA([bug.sps], [dnl
+SET FORMAT=F8.0.
+
+INPUT PROGRAM.
+       LOOP I=1 TO 10.
+               COMPUTE SCORE=EXP(NORMAL(1)).
+               END CASE.
+       END LOOP.
+       END FILE.
+END INPUT PROGRAM.
+
+FREQUENCIES VARIABLES=SCORE
+/FORMAT=NOTABLE
+/STATISTICS=ALL
+/PERCENTILES=1 10 20 30 40 50 60 70 80 90 99
+/HISTOGRAM.
+
+])
+
+AT_CHECK([pspp bug.sps], [0],  [ignore])
+
+AT_CLEANUP
index de1ad2a4bc64b3d97e0f69f8965b30aa152464fa..2ac5909fead71bcccace5230b33f0d698f8a91db 100644 (file)
@@ -326,3 +326,131 @@ Corrected Total,436.784,19,,,
 
 AT_CLEANUP
 
+
+AT_SETUP([GLM missing values])
+
+AT_DATA([glm.data], [dnl
+1 1 6  3.5
+1 2 2  8.9
+1 3 3  9.6
+1 4 4 10.5
+1 5 5  3.1
+1 6 1  5.9
+2 1 2  4.2
+2 2 6  1.9
+2 3 5  3.7
+2 4 3 10.2
+2 5 1  7.2
+2 6 4  7.6
+3 1 1  6.7
+3 2 4  5.8
+3 3 6 -2.7
+3 4 2  4.6
+3 5 3  4.0
+3 6 5 -0.7
+4 1 4  6.6
+4 2 1  4.5
+4 3 2  3.7
+4 4 5  3.7
+4 5 6 -3.3
+4 6 3  3.0
+5 1 3  4.1
+5 2 5  2.4
+5 3 4  6.0
+5 4 1  5.1
+5 5 2  3.5
+5 6 6  4.0
+6 1 5  3.8
+6 2 3  5.8
+6 3 1  7.0
+6 4 6  3.8
+6 5 4  5.0
+6 6 2  8.6
+])
+
+AT_DATA([glm-miss.sps], [dnl
+set format = F20.3.
+data list file='glm.data' notable  fixed /a 1 b 3 c 5 y 7-10(2).
+
+do if a=6.
+recode y (else=SYSMIS).
+end if.
+
+glm y by   b a c
+  /criteria=alpha(.05)
+  /design = a b c
+  .
+])
+
+AT_CHECK([pspp -O format=csv glm-miss.sps], [0],  [dnl
+Table: Tests of Between-Subjects Effects
+Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+Corrected Model,251.621,14,17.973,4.969,.002
+Intercept,628.376,1,628.376,173.737,.000
+a,72.929,4,18.232,5.041,.009
+b,20.703,5,4.141,1.145,.380
+c,135.179,5,27.036,7.475,.001
+Error,54.253,15,3.617,,
+Total,934.250,30,,,
+Corrected Total,305.874,29,,,
+])
+
+
+
+AT_DATA([glm-miss2.sps], [dnl
+set format = F20.3.
+data list file='glm.data' notable  fixed /a 1 b 3 c 5 y 7-10(2).
+
+select if a <> 6.
+
+glm y by   b a c
+  /criteria=alpha(.05)
+  /design = a b c
+  .
+])
+
+AT_CHECK([pspp -O format=csv glm-miss2.sps], [0],  [dnl
+Table: Tests of Between-Subjects Effects
+Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+Corrected Model,251.621,14,17.973,4.969,.002
+Intercept,628.376,1,628.376,173.737,.000
+a,72.929,4,18.232,5.041,.009
+b,20.703,5,4.141,1.145,.380
+c,135.179,5,27.036,7.475,.001
+Error,54.253,15,3.617,,
+Total,934.250,30,,,
+Corrected Total,305.874,29,,,
+])
+
+
+dnl Now for some missing values in the factor variables.
+
+AT_DATA([glm-miss3.sps], [dnl
+set format = F20.3.
+data list file=glm.data notable  fixed /a 1 b 3 c 5 y 7-10(2).
+
+do if a=6.
+recode a (else=SYSMIS).
+end if.
+
+glm y by   b a c
+  /criteria=alpha(.05)
+  /design = a b c
+  .
+])
+
+AT_CHECK([pspp -O format=csv glm-miss3.sps], [0],  [dnl
+Table: Tests of Between-Subjects Effects
+Source,Type III Sum of Squares,df,Mean Square,F,Sig.
+Corrected Model,251.621,14,17.973,4.969,.002
+Intercept,628.376,1,628.376,173.737,.000
+a,72.929,4,18.232,5.041,.009
+b,20.703,5,4.141,1.145,.380
+c,135.179,5,27.036,7.475,.001
+Error,54.253,15,3.617,,
+Total,934.250,30,,,
+Corrected Total,305.874,29,,,
+])
+
+AT_CLEANUP
+
index be9aa305f30d05f079c4d83b6a36d782bbd055eb..ef11e91931898359dfffadfaf847b7c1cd1642ca 100644 (file)
@@ -9,7 +9,7 @@ m4_ifndef([AT_SKIP_IF],
 m4_divert_text([PREPARE_TESTS], [dnl
 if test X"$RUNNER" != X; then
     wrapper_dir=`pwd`/wrappers
-    rm "$wrapper_dir"/*
+    rm -f "$wrapper_dir"/*
     test -d "$wrapper_dir" || mkdir "$wrapper_dir"
 
     wrap_dir () {