VARIABLE ROLE: New command. 20130826030511/pspp
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 26 Aug 2013 05:57:56 +0000 (22:57 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 26 Aug 2013 05:57:56 +0000 (22:57 -0700)
Also adds GUI support.

The system file representation for variable roles is really just an
educated guess.  I am going to ask for assistance in confirming the
representation.

16 files changed:
NEWS
doc/language.texi
doc/variables.texi
perl-module/t/Pspp.t
src/data/sys-file-reader.c
src/data/sys-file-writer.c
src/data/variable.c
src/data/variable.h
src/language/command.def
src/language/dictionary/sys-file-info.c
src/language/dictionary/variable-display.c
src/ui/gui/psppire-var-sheet.c
src/ui/gui/text-data-import-dialog.c
tests/data/sys-file-reader.at
tests/language/dictionary/variable-display.at
tests/perl-module.at

diff --git a/NEWS b/NEWS
index c522d1871dafaf927a7bd66f90b593be9b981556..352b6bfa65bcc318e70d9c64cef44c178c92baf3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,12 +6,18 @@ Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
 
 Changes after 0.8.0:
 
+ * New commands:
+
+   - VARIABLE ROLE.
+
  * PSPPIRE graphical user interface improvements:
 
    - Syntax windows now parse syntax in "auto" mode, which in practice
      should mean that both "batch" and "interactive" syntax now works,
      instead of just "interactive" syntax.
 
+   - The variable pane of data windows now include a Role column.
+
  * Notable bug fixes:
 
    - System files written by IBM SPSS 21 are now read without warnings.
index a6964ed03501e3fc6bcb7b592c0f829759d72803..e344de301919fd1c3e9a405dcffbcc49e42cdbf5 100644 (file)
@@ -502,6 +502,11 @@ Similar to print format, but used by the @cmd{WRITE} command
 @item Custom attributes
 User-defined associations between names and values.  @xref{VARIABLE
 ATTRIBUTE}.
+
+@cindex variable role
+@item Role
+The intended role of a variable for use in dialog boxes in graphical
+user interfaces.  @xref{VARIABLE ROLE}.
 @end table
 
 @node System Variables
index f4ed4449dd52aeb713b8fb1959dceb63278b8c07..1db8f034a66fc79c5334addb348e6baed606d92f 100644 (file)
@@ -23,6 +23,7 @@ several utility functions for examining and adjusting them.
 * VARIABLE ALIGNMENT::          Set the alignment for display.
 * VARIABLE WIDTH::              Set the display width.
 * VARIABLE LEVEL::              Set the measurement level.
+* VARIABLE ROLE::               Set the role that a variable fills in analysis.
 * VECTOR::                      Declare an array of variables.
 * WRITE FORMATS::               Set variable write formats.
 @end menu
@@ -646,6 +647,42 @@ VARIABLE LEVEL
 Currently, this has no effect except for certain third party software.
 
 
+@node VARIABLE ROLE
+@section VARIABLE ROLE
+@vindex VARIABLE ROLE
+@display
+VARIABLE ROLE
+        /@var{role} @var{var_list}
+        [/@var{role} @var{var_list}]@dots{}
+@end display
+
+@cmd{VARIABLE ROLE} sets the intended role of a variable for use in
+dialog boxes in graphical user interfaces.  Each @var{role} specifies
+one of the following roles for the variables that follow it:
+
+@table @code
+@item INPUT
+An input variable, such as an independent variable.
+
+@item TARGET
+An output variable, such as an dependent variable.
+
+@item BOTH
+A variable used for input and output.
+
+@item NONE
+No role assigned.  (This is a variable's default role.)
+
+@item PARTITION
+Used to break the data into groups for testing.
+
+@item SPLIT
+No meaning except for certain third party software.  (This role's
+meaning is unrelated to @cmd{SPLIT FILE}.)
+@end table
+
+The PSPPIRE GUI does not yet use variable roles as intended.
+
 @node VECTOR
 @section VECTOR
 @vindex VECTOR
index a7fb9578da8dc90efbe00dbb103c9c6b5057db30..a2d42889892b580b4a7c08d63fab8e98376ec591 100644 (file)
@@ -591,7 +591,7 @@ SYNTAX
 
     open (MYFILE, ">$tempdir/out.txt");
 
-    foreach $k (keys %$attr)
+    foreach $k (sort (keys (%$attr)))
     {
        my $ll = $attr->{$k};
        print MYFILE "$k =>";
@@ -600,7 +600,8 @@ SYNTAX
 
     close (MYFILE);
 
-    ok (compare ("$tempdir/out.txt", <<EOF), "Custom Attributes");
+    ok (compare ("$tempdir/out.txt", <<'EOF'), "Custom Attributes");
+$@Role =>0
 colour =>blue, pink, violet
 nationality =>foreign
 size =>large
index b3315b1e17381bcd1cbbed241ba6acf4d53ab633..d38113e2883a47fb237548b856ab95cceb57e55a 100644 (file)
@@ -295,6 +295,7 @@ static void parse_data_file_attributes (struct sfm_reader *,
 static void parse_variable_attributes (struct sfm_reader *,
                                        const struct sfm_extension_record *,
                                        struct dictionary *);
+static void assign_variable_roles (struct sfm_reader *, struct dictionary *);
 static void parse_long_string_value_labels (struct sfm_reader *,
                                             const struct sfm_extension_record *,
                                             struct dictionary *);
@@ -524,7 +525,12 @@ sfm_open_reader (struct file_handle *fh, const char *volatile encoding,
 
   /* The following records use long names, so they need to follow renaming. */
   if (extensions[EXT_VAR_ATTRS] != NULL)
-    parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
+    {
+      parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
+
+      /* Roles use the $@Role attribute.  */
+      assign_variable_roles (r, dict);
+    }
 
   if (extensions[EXT_LONG_LABELS] != NULL)
     parse_long_string_value_labels (r, extensions[EXT_LONG_LABELS], dict);
@@ -1896,6 +1902,64 @@ parse_variable_attributes (struct sfm_reader *r,
   close_text_record (r, text);
 }
 
+static void
+assign_variable_roles (struct sfm_reader *r, struct dictionary *dict)
+{
+  size_t n_warnings = 0;
+  size_t i;
+
+  for (i = 0; i < dict_get_var_cnt (dict); i++)
+    {
+      struct variable *var = dict_get_var (dict, i);
+      struct attrset *attrs = var_get_attributes (var);
+      const struct attribute *attr = attrset_lookup (attrs, "$@Role");
+      if (attr != NULL)
+        {
+          int value = atoi (attribute_get_value (attr, 0));
+          enum var_role role;
+
+          switch (value)
+            {
+            case 0:
+              role = ROLE_NONE;
+              break;
+
+            case 1:
+              role = ROLE_INPUT;
+              break;
+
+            case 2:
+              role = ROLE_OUTPUT;
+              break;
+
+            case 3:
+              role = ROLE_BOTH;
+              break;
+
+            case 4:
+              role = ROLE_PARTITION;
+              break;
+
+            case 5:
+              role = ROLE_SPLIT;
+              break;
+
+            default:
+              role = ROLE_NONE;
+              if (n_warnings++ == 0)
+                sys_warn (r, 0, _("Invalid role for variable %s."),
+                          var_get_name (var));
+            }
+
+          var_set_role (var, role);
+        }
+    }
+
+  if (n_warnings > 1)
+    sys_warn (r, 0, _("%zu other variables had invalid roles."),
+              n_warnings - 1);
+}
+
 static void
 check_overflow (struct sfm_reader *r,
                 const struct sfm_extension_record *record,
index d02369856f356a08b33e3a9e5f4a7ac8d21eb5c6..1b73e737c1bca6efcaf1ccecf799ae0c8d2c18bf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-2000, 2006-2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-2000, 2006-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
@@ -259,9 +259,12 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
 
   write_long_string_value_labels (w, d);
 
-  if (attrset_count (dict_get_attributes (d)))
-    write_data_file_attributes (w, d);
-  write_variable_attributes (w, d);
+  if (opts.version >= 3)
+    {
+      if (attrset_count (dict_get_attributes (d)))
+        write_data_file_attributes (w, d);
+      write_variable_attributes (w, d);
+    }
 
   write_mrsets (w, d, false);
 
@@ -680,6 +683,46 @@ write_data_file_attributes (struct sfm_writer *w,
   ds_destroy (&s);
 }
 
+static void
+add_role_attribute (enum var_role role, struct attrset *attrs)
+{
+  struct attribute *attr;
+  const char *s;
+
+  switch (role)
+    {
+    case ROLE_NONE:
+    default:
+      s = "0";
+      break;
+
+    case ROLE_INPUT:
+      s = "1";
+      break;
+
+    case ROLE_OUTPUT:
+      s = "2";
+      break;
+
+    case ROLE_BOTH:
+      s = "3";
+      break;
+
+    case ROLE_PARTITION:
+      s = "4";
+      break;
+
+    case ROLE_SPLIT:
+      s = "5";
+      break;
+    }
+  attrset_delete (attrs, "$@Role");
+
+  attr = attribute_create ("$@Role");
+  attribute_add_value (attr, s);
+  attrset_add (attrs, attr);
+}
+
 static void
 write_variable_attributes (struct sfm_writer *w, const struct dictionary *d)
 {
@@ -691,14 +734,16 @@ write_variable_attributes (struct sfm_writer *w, const struct dictionary *d)
   for (i = 0; i < n_vars; i++)
     { 
       struct variable *v = dict_get_var (d, i);
-      struct attrset *attrs = var_get_attributes (v);
-      if (attrset_count (attrs)) 
-        {
-          if (n_attrsets++)
-            ds_put_byte (&s, '/');
-          ds_put_format (&s, "%s:", var_get_name (v));
-          put_attrset (&s, attrs);
-        }
+      struct attrset attrs;
+
+      attrset_clone (&attrs, var_get_attributes (v));
+
+      add_role_attribute (var_get_role (v), &attrs);
+      if (n_attrsets++)
+        ds_put_byte (&s, '/');
+      ds_put_format (&s, "%s:", var_get_name (v));
+      put_attrset (&s, &attrs);
+      attrset_destroy (&attrs);
     }
   if (n_attrsets)
     write_utf8_record (w, dict_get_encoding (d), &s, 18);
index 720def8e6c6708d655db98ced2e51b995daf4bfc..d3f9addc4c1c4d1a4dbc23d7491ae756a748d3c8 100644 (file)
@@ -58,6 +58,7 @@ struct variable
 
     /* GUI information. */
     enum measure measure;       /* Nominal, ordinal, or continuous. */
+    enum var_role role;         /* Intended use. */
     int display_width;          /* Width of data editor column. */
     enum alignment alignment;   /* Alignment of data in GUI. */
 
@@ -102,6 +103,7 @@ var_create (const char *name, int width)
   type = val_type_from_width (width);
   v->alignment = var_default_alignment (type);
   v->measure = var_default_measure (type);
+  v->role = ROLE_NONE;
   v->display_width = var_default_display_width (width);
   v->print = v->write = var_default_formats (width);
   attrset_init (&v->attributes);
@@ -820,6 +822,27 @@ measure_to_string (enum measure m)
     }
 }
 
+/* Returns a string version of measurement level M, for use in PSPP command
+   syntax. */
+const char *
+measure_to_syntax (enum measure m)
+{
+  switch (m)
+    {
+    case MEASURE_NOMINAL:
+      return "NOMINAL";
+
+    case MEASURE_ORDINAL:
+      return "ORDINAL";
+
+    case MEASURE_SCALE:
+      return "SCALE";
+
+    default:
+      return "Invalid";
+    }
+}
+
 /* Returns V's measurement level. */
 enum measure
 var_get_measure (const struct variable *v)
@@ -856,6 +879,109 @@ var_default_measure (enum val_type type)
   return type == VAL_NUMERIC ? MEASURE_SCALE : MEASURE_NOMINAL;
 }
 \f
+/* Returns true if M is a valid variable role,
+   false otherwise. */
+bool
+var_role_is_valid (enum var_role role)
+{
+  switch (role)
+    {
+    case ROLE_NONE:
+    case ROLE_INPUT:
+    case ROLE_OUTPUT:
+    case ROLE_BOTH:
+    case ROLE_PARTITION:
+    case ROLE_SPLIT:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Returns a string version of ROLE, for display to a user. */
+const char *
+var_role_to_string (enum var_role role)
+{
+  switch (role)
+    {
+    case ROLE_NONE:
+      return _("None");
+
+    case ROLE_INPUT:
+      return _("Input");
+
+    case ROLE_OUTPUT:
+      return _("Output");
+
+    case ROLE_BOTH:
+      return _("Both");
+
+    case ROLE_PARTITION:
+      return _("Partition");
+
+    case ROLE_SPLIT:
+      return _("Split");
+
+    default:
+      return "Invalid";
+    }
+}
+
+/* Returns a string version of ROLE, for use in PSPP comamnd syntax. */
+const char *
+var_role_to_syntax (enum var_role role)
+{
+  switch (role)
+    {
+    case ROLE_NONE:
+      return "NONE";
+
+    case ROLE_INPUT:
+      return "INPUT";
+
+    case ROLE_OUTPUT:
+      return "TARGET";
+
+    case ROLE_BOTH:
+      return "BOTH";
+
+    case ROLE_PARTITION:
+      return "PARTITION";
+
+    case ROLE_SPLIT:
+      return "SPLIT";
+
+    default:
+      return "<invalid>";
+    }
+}
+
+/* Returns V's role. */
+enum var_role
+var_get_role (const struct variable *v)
+{
+  return v->role;
+}
+
+/* Sets V's role to ROLE. */
+static void
+var_set_role_quiet (struct variable *v, enum var_role role)
+{
+  assert (var_role_is_valid (role));
+  v->role = role;
+}
+
+
+/* Sets V's role to ROLE. */
+void
+var_set_role (struct variable *v, enum var_role role)
+{
+  struct variable *ov = var_clone (v);
+  var_set_role_quiet (v, role);
+  dict_var_changed (v, VAR_TRAIT_ROLE, ov);
+}
+\f
 /* Returns V's display width, which applies only to GUIs. */
 int
 var_get_display_width (const struct variable *v)
@@ -919,6 +1045,26 @@ alignment_to_string (enum alignment a)
     }
 }
 
+/* Returns a string version of alignment A, for use in PSPP command syntax. */
+const char *
+alignment_to_syntax (enum alignment a)
+{
+  switch (a)
+    {
+    case ALIGN_LEFT:
+      return "LEFT";
+
+    case ALIGN_RIGHT:
+      return "RIGHT";
+
+    case ALIGN_CENTRE:
+      return "CENTER";
+
+    default:
+      return "Invalid";
+    }
+}
+
 /* Returns V's display alignment, which applies only to GUIs. */
 enum alignment
 var_get_alignment (const struct variable *v)
@@ -1150,6 +1296,7 @@ var_clone (const struct variable *old_var)
   var_set_value_labels_quiet (new_var, var_get_value_labels (old_var));
   var_set_label_quiet (new_var, var_get_label (old_var), false);
   var_set_measure_quiet (new_var, var_get_measure (old_var));
+  var_set_role_quiet (new_var, var_get_role (old_var));
   var_set_display_width_quiet (new_var, var_get_display_width (old_var));
   var_set_alignment_quiet (new_var, var_get_alignment (old_var));
   var_set_leave_quiet (new_var, var_get_leave (old_var));
index a62902882f9fdb1e058dc902dd8b2ebeee124cb1..e8f5f101469c1514587b0f24d9b053df5919f3fa 100644 (file)
@@ -27,7 +27,7 @@
 
 #define VAR_TRAIT_NAME             0x0001
 #define VAR_TRAIT_WIDTH            0x0002
-/* Available for reuse: 0x0004 */
+#define VAR_TRAIT_ROLE             0x0004
 #define VAR_TRAIT_LABEL            0x0008
 #define VAR_TRAIT_VALUE_LABELS     0x0010
 #define VAR_TRAIT_MISSING_VALUES   0x0020
@@ -135,12 +135,31 @@ enum measure
 
 bool measure_is_valid (enum measure);
 const char *measure_to_string (enum measure);
+const char *measure_to_syntax (enum measure);
 
 enum measure var_get_measure (const struct variable *);
 void var_set_measure (struct variable *, enum measure);
 
 enum measure var_default_measure (enum val_type);
 
+/* Intended usage of a variable, for populating dialogs. */
+enum var_role
+  {
+    ROLE_NONE,
+    ROLE_INPUT,
+    ROLE_OUTPUT,
+    ROLE_BOTH,
+    ROLE_PARTITION,
+    ROLE_SPLIT
+  };
+
+bool var_role_is_valid (enum var_role);
+const char *var_role_to_string (enum var_role);
+const char *var_role_to_syntax (enum var_role);
+
+enum var_role var_get_role (const struct variable *);
+void var_set_role (struct variable *, enum var_role);
+
 /* GUI display width. */
 int var_get_display_width (const struct variable *);
 void var_set_display_width (struct variable *, int display_width);
@@ -157,6 +176,7 @@ enum alignment
 
 bool alignment_is_valid (enum alignment);
 const char *alignment_to_string (enum alignment);
+const char *alignment_to_syntax (enum alignment);
 
 enum alignment var_get_alignment (const struct variable *);
 void var_set_alignment (struct variable *, enum alignment);
index 5191e522d758a3354cb691f49e21f5940aa91b4e..5192d0cbf22601e485cb2209545eeb2d4548af44 100644 (file)
@@ -95,6 +95,7 @@ DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ALIGNMENT", cmd_variable_alignme
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ATTRIBUTE", cmd_variable_attribute)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LABELS", cmd_variable_labels)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE LEVEL", cmd_variable_level)
+DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE ROLE", cmd_variable_role)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VARIABLE WIDTH", cmd_variable_width)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "VECTOR", cmd_vector)
 DEF_CMD (S_DATA | S_INPUT_PROGRAM, 0, "WEIGHT", cmd_weight)
index 441054e209b29b3dfdb7434038083dd6df11ce32..1ce94aa91fab83aee356ad0bf15bf31b39550f76 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 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
@@ -442,7 +442,7 @@ describe_variable (const struct variable *v, struct tab_table *t, int r,
   /* Make sure that enough rows are allocated. */
   need_rows = 1;
   if (flags & ~(DF_DICT_INDEX | DF_VARIABLE_LABELS))
-    need_rows += 15;
+    need_rows += 16;
   if (flags & DF_VALUE_LABELS)
     need_rows += val_labs_count (var_get_value_labels (v));
   if (flags & (DF_ATTRIBUTES | DF_AT_ATTRIBUTES))
@@ -494,24 +494,28 @@ describe_variable (const struct variable *v, struct tab_table *t, int r,
         }
     }
   
-  /* Measurement level, display width, alignment. */
+  /* Measurement level, role, display width, alignment. */
   if (flags & DF_MISC) 
     {
-      enum measure m = var_get_measure (v);
-      enum alignment a = var_get_alignment (v);
+      enum var_role role = var_get_role (v);
 
       tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
                              _("Measure: %s"),
-                             m == MEASURE_NOMINAL ? _("Nominal")
-                             : m == MEASURE_ORDINAL ? _("Ordinal")
-                             : _("Scale"));
+                             measure_to_string (var_get_measure (v)));
       r++;
+
+      if (role != ROLE_NONE)
+        {
+          tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
+                                 _("Role: %s"), var_role_to_string (role));
+          r++;
+        }
+
       tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
                              _("Display Alignment: %s"),
-                             a == ALIGN_LEFT ? _("Left")
-                             : a == ALIGN_CENTRE ? _("Center")
-                             : _("Right"));
+                             alignment_to_string (var_get_alignment (v)));
       r++;
+
       tab_joint_text_format (t, 1, r, 2, r, TAB_LEFT,
                              _("Display Width: %d"),
                              var_get_display_width (v));
index 1ff5f465200a549c678c4c6eb17133079a7dc9ce..9e50551c92b9a17359af658d947014762fb78bc2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011, 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
@@ -183,3 +183,40 @@ cmd_variable_level (struct lexer *lexer, struct dataset *ds)
   while (lex_token (lexer) != T_ENDCMD);
   return CMD_SUCCESS;
 }
+
+/* Set variables' role */
+int
+cmd_variable_role (struct lexer *lexer, struct dataset *ds)
+{
+  while (lex_match (lexer, T_SLASH))
+    {
+      struct variable **v;
+      size_t nv;
+      enum var_role role;
+      size_t i;
+
+      if ( lex_match_id (lexer, "INPUT"))
+        role = ROLE_INPUT;
+      else if ( lex_match_id (lexer, "TARGET"))
+        role = ROLE_OUTPUT;
+      else if ( lex_match_id (lexer, "BOTH"))
+        role = ROLE_BOTH;
+      else if ( lex_match_id (lexer, "NONE"))
+        role = ROLE_NONE;
+      else if ( lex_match_id (lexer, "PARTITION"))
+        role = ROLE_PARTITION;
+      else if ( lex_match_id (lexer, "SPLIT"))
+        role = ROLE_SPLIT;
+      else
+        return CMD_FAILURE;
+
+      if (!parse_variables (lexer, dataset_dict (ds), &v, &nv, PV_NONE))
+        return CMD_FAILURE;
+
+      for (i = 0; i < nv; i++)
+       var_set_role (v[i], role);
+      free (v);
+    }
+
+  return CMD_SUCCESS;
+}
index 3a2d232002adb8d8a83e7aba6a24ee1233b78db2..df4718696dbd29faf01b8432287c34ff5f4a3c03 100644 (file)
@@ -54,7 +54,8 @@ enum vs_column
     VS_MISSING,
     VS_COLUMNS,
     VS_ALIGN,
-    VS_MEASURE
+    VS_MEASURE,
+    VS_ROLE
   };
 
 G_DEFINE_TYPE (PsppireVarSheet, psppire_var_sheet, PSPP_TYPE_SHEET_VIEW);
@@ -274,6 +275,21 @@ on_var_column_edited (GtkCellRendererText *cell,
       else if (!strcmp (new_text, measure_to_string (MEASURE_SCALE)))
         var_set_measure (var, MEASURE_SCALE);
       break;
+
+    case VS_ROLE:
+      if (!strcmp (new_text, var_role_to_string (ROLE_NONE)))
+        var_set_role (var, ROLE_NONE);
+      else if (!strcmp (new_text, var_role_to_string (ROLE_INPUT)))
+        var_set_role (var, ROLE_INPUT);
+      else if (!strcmp (new_text, var_role_to_string (ROLE_OUTPUT)))
+        var_set_role (var, ROLE_OUTPUT);
+      else if (!strcmp (new_text, var_role_to_string (ROLE_BOTH)))
+        var_set_role (var, ROLE_BOTH);
+      else if (!strcmp (new_text, var_role_to_string (ROLE_PARTITION)))
+        var_set_role (var, ROLE_PARTITION);
+      else if (!strcmp (new_text, var_role_to_string (ROLE_SPLIT)))
+        var_set_role (var, ROLE_SPLIT);
+      break;
     }
 }
 
@@ -452,6 +468,13 @@ render_var_cell (PsppSheetViewColumn *tree_column,
                       psppire_dict_view_get_var_measurement_stock_id (var),
                       NULL);
       break;
+
+    case VS_ROLE:
+      g_object_set (cell,
+                    "text", var_role_to_string (var_get_role (var)),
+                    "editable", TRUE,
+                    NULL);
+      break;
     }
 }
 
@@ -1276,6 +1299,15 @@ psppire_var_sheet_init (PsppireVarSheet *obj)
   pspp_sheet_view_column_set_cell_data_func (
     column, cell, render_var_cell, obj, NULL);
 
+  add_combo_column (obj, VS_ROLE, _("Role"), 12,
+                    var_role_to_string (ROLE_NONE), ROLE_NONE,
+                    var_role_to_string (ROLE_INPUT), ROLE_INPUT,
+                    var_role_to_string (ROLE_OUTPUT), ROLE_OUTPUT,
+                    var_role_to_string (ROLE_BOTH), ROLE_BOTH,
+                    var_role_to_string (ROLE_PARTITION), ROLE_PARTITION,
+                    var_role_to_string (ROLE_SPLIT), ROLE_SPLIT,
+                    NULL);
+
   pspp_sheet_view_set_rubber_banding (sheet_view, TRUE);
   pspp_sheet_selection_set_mode (pspp_sheet_view_get_selection (sheet_view),
                                  PSPP_SHEET_SELECTION_MULTIPLE);
index 2559cf8b36e4539b56635c0c83baf8786ec13b36..198a1687a847dc5ab9b4f60115cd4f177c6ea05c 100644 (file)
@@ -162,6 +162,7 @@ apply_dict (const struct dictionary *dict, struct string *s)
       enum val_type type = var_get_type (var);
       int width = var_get_width (var);
       enum measure measure = var_get_measure (var);
+      enum var_role role = var_get_role (var);
       enum alignment alignment = var_get_alignment (var);
       const struct fmt_spec *format = var_get_print_format (var);
 
@@ -212,16 +213,13 @@ apply_dict (const struct dictionary *dict, struct string *s)
                          name, var_get_label (var));
       if (measure != var_default_measure (type))
         syntax_gen_pspp (s, "VARIABLE LEVEL %ss (%ss).\n",
-                         name,
-                         (measure == MEASURE_NOMINAL ? "NOMINAL"
-                          : measure == MEASURE_ORDINAL ? "ORDINAL"
-                          : "SCALE"));
+                         name, measure_to_syntax (measure));
+      if (role != ROLE_NONE)
+        syntax_gen_pspp (s, "VARIABLE ROLE /%ss %ss.\n",
+                         var_role_to_syntax (role), name);
       if (alignment != var_default_alignment (type))
         syntax_gen_pspp (s, "VARIABLE ALIGNMENT %ss (%ss).\n",
-                         name,
-                         (alignment == ALIGN_LEFT ? "LEFT"
-                          : alignment == ALIGN_CENTRE ? "CENTER"
-                          : "RIGHT"));
+                         name, alignment_to_syntax (alignment));
       if (var_get_display_width (var) != var_default_display_width (width))
         syntax_gen_pspp (s, "VARIABLE WIDTH %ss (%d).\n",
                          name, var_get_display_width (var));
index 35281f22e3e5d911afa8ae29315662402c48edfa..ab7251537ea9f2bb21ec4b7fe5f8b4e92e8f831b 100644 (file)
@@ -1062,6 +1062,7 @@ dnl Variable attributes record.
 "FirstVariable:";
   "ad"; i8 232; "le('23'"; i8 10; "'34'"; i8 10; ")";
   "bert('123'"; i8 10; ")";
+  "$@Role('1'"; i8 10; ")";
 "/S"; i8 233; "condVariable:";
   "xyzzy('quux'"; i8 10; ")";
 );
@@ -1074,26 +1075,51 @@ dnl Dictionary termination record.
 999; 0;
 ])
 for variant in \
-       "be c7cae57af35662acec3b945abcf7927c" \
-       "le eb6b4ab9c27bfa0daa49bf2770bccb70"
+       "be 7fff0c04f697adf45f55d8be4aaa8712" \
+       "le 7331339199344aa58bc60d7d05d538a7"
 do
   set $variant
   AT_CHECK_UNQUOTED([sack --$[1] sys-file.sack > sys-file.sav], [0], [], [$[2]
 ])
   AT_DATA([sys-file.sps], [dnl
 GET FILE='sys-file.sav'.
-DISPLAY ATTRIBUTES.
+DISPLAY @ATTRIBUTES.
 ])
   AT_CHECK([pspp -o pspp.csv sys-file.sps])
   AT_CHECK([cat pspp.csv], [0],
 [[Variable,Description,
 FirstVariable,Custom attributes:,
+,$@Role,1
 ,adèle[1],23
 ,adèle[2],34
 ,bert,123
 SécondVariable,Custom attributes:,
 ,xyzzy,quux
 
+Table: Custom data file attributes.
+Attribute,Value
+Attr1[1],Value1
+Attr1[2],'déclaration'
+SécondAttr[1],123
+SécondAttr[2],456
+]])
+  AT_DATA([sys-file.sps], [dnl
+GET FILE='sys-file.sav'.
+DISPLAY DICTIONARY.
+])
+  AT_CHECK([pspp -o pspp.csv sys-file.sps])
+  AT_CHECK([grep -v Measure pspp.csv | grep -v Display], [0],
+[[Variable,Description,,Position
+FirstVariable,Format: F8.0,,1
+,Role: Input,,
+,Custom attributes:,,
+,adèle[1],23,
+,adèle[2],34,
+,bert,123,
+SécondVariable,Format: F8.0,,2
+,Custom attributes:,,
+,xyzzy,quux,
+
 Table: Custom data file attributes.
 Attribute,Value
 Attr1[1],Value1
index f4d76eb94b4851675057868ffddf6bb1b2682768..ef545d9d16ed3933b0115e015fd10a52cf93aca8 100644 (file)
@@ -6,6 +6,7 @@ DATA LIST FREE /x y z.
 VARIABLE ALIGNMENT x (LEFT)/y (RIGHT)/z (CENTER).
 VARIABLE WIDTH x (10)/y (12)/z (14).
 VARIABLE LEVEL x (SCALE)/y (ORDINAL)/z (NOMINAL).
+VARIABLE ROLE /INPUT x /TARGET y /BOTH z.
 DISPLAY DICTIONARY.
 ])
 AT_CHECK([pspp -o pspp.csv var-display.sps])
@@ -13,14 +14,17 @@ AT_CHECK([cat pspp.csv], [0], [dnl
 Variable,Description,,Position
 x,Format: F8.2,,1
 ,Measure: Scale,,
+,Role: Input,,
 ,Display Alignment: Left,,
 ,Display Width: 10,,
 y,Format: F8.2,,2
 ,Measure: Ordinal,,
+,Role: Output,,
 ,Display Alignment: Right,,
 ,Display Width: 12,,
 z,Format: F8.2,,3
 ,Measure: Nominal,,
+,Role: Both,,
 ,Display Alignment: Center,,
 ,Display Width: 14,,
 ])
index 1f4a96288c53fc5a7b875bd8abdb90d13cd76988..81fca4a5910e8ddde4bc78918b78a18f8f854f23 100644 (file)
@@ -686,7 +686,7 @@ AT_DATA([test.pl],
 
     my $attr = $var->get_attributes ();
 
-    foreach my $k (keys %$attr)
+    foreach my $k (sort (keys (%$attr)))
     {
        my $ll = $attr->{$k};
        print "$k =>";
@@ -694,7 +694,8 @@ AT_DATA([test.pl],
     }
 ]])
 AT_CHECK([RUN_PERL_MODULE test.pl], [0],
-  [[colour =>blue, pink, violet
+  [[$@Role =>0
+colour =>blue, pink, violet
 nationality =>foreign
 size =>large
 ]])