/* 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 . */
#include
#include "psppire-dialog-action-crosstabs.h"
#include "psppire-value-entry.h"
#include "dialog-common.h"
#include "helper.h"
#include
#include "psppire-var-view.h"
#include "psppire-dialog.h"
#include "builder-wrapper.h"
#include "psppire-checkbox-treeview.h"
#include "psppire-dict.h"
#include "libpspp/str.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
static void
psppire_dialog_action_crosstabs_class_init (PsppireDialogActionCrosstabsClass *class);
G_DEFINE_TYPE (PsppireDialogActionCrosstabs, psppire_dialog_action_crosstabs, PSPPIRE_TYPE_DIALOG_ACTION);
static gboolean
dialog_state_valid (gpointer data)
{
PsppireDialogActionCrosstabs *cd = PSPPIRE_DIALOG_ACTION_CROSSTABS (data);
GtkTreeModel *row_vars = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->dest_rows));
GtkTreeModel *col_vars = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->dest_cols));
GtkTreeIter notused;
return (gtk_tree_model_get_iter_first (row_vars, ¬used)
&& gtk_tree_model_get_iter_first (col_vars, ¬used));
}
static void
refresh (PsppireDialogAction *rd_)
{
PsppireDialogActionCrosstabs *cd = PSPPIRE_DIALOG_ACTION_CROSSTABS (rd_);
GtkTreeModel *liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->dest_rows));
gtk_list_store_clear (GTK_LIST_STORE (liststore));
liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (cd->dest_cols));
gtk_list_store_clear (GTK_LIST_STORE (liststore));
}
#define CROSSTABS_STATS \
CS (CHISQ, N_("Chisq"), N_("Pearson chi-square, " \
"likelihood ratio, Fisher’s exact test, continuity correction, " \
"linear-by-linear association.")) \
CS (PHI, N_("Phi"), NULL) \
CS (CC, N_("CC"), N_("Contingency coefficient")) \
CS (LAMBDA, N_("Lambda"), NULL) \
CS (UC, N_("UC"), N_("Uncertainty coefficient")) \
CS (BTAU, N_("BTau"), N_("Kendall's Tau-b")) \
CS (CTAU, N_("CTau"), N_("Kendall's Tau-c")) \
CS (RISK, N_("Risk"), N_("Relative Risk estimate")) \
CS (GAMMA, N_("Gamma"), NULL) \
CS (D, N_("D"), N_("Somer's d")) \
CS (KAPPA, N_("Kappa"), N_("Cohen's Kappa")) \
CS (ETA, N_("Eta"), NULL) \
CS (CORR, N_("Corr"), N_("Spearman correlation, Pearson's r")) \
CS (STATS_NONE, N_("None"), NULL)
#define CROSSTABS_CELLS \
CS (COUNT, N_("Count"), N_("Frequency Count")) \
CS (ROW, N_("Row"), N_("Row percent")) \
CS (COLUMN, N_("Column"), N_("Column percent")) \
CS (TOTAL, N_("Total"), N_("Total percent")) \
CS (EXPECTED, N_("Expected"), N_("Expected value")) \
CS (RESIDUAL, N_("Residual"), NULL) \
CS (SRESIDUAL, N_("Std. Residual"), N_("Standardized Residual")) \
CS (ASRESIDUAL, N_("Adjusted Std. Residual"), NULL) \
CS (CELLS_NONE, N_("None"), NULL)
enum
{
#define CS(NAME, LABEL, TOOLTIP) CS_##NAME,
CROSSTABS_STATS
#undef CS
N_CROSSTABS_STATS
};
enum
{
#define CS(NAME, LABEL, TOOLTIP) CS_##NAME,
CROSSTABS_CELLS
#undef CS
N_CROSSTABS_CELLS
};
enum
{
#define CS(NAME, LABEL, TOOLTIP) B_CS_##NAME = 1u << CS_##NAME,
CROSSTABS_STATS
CROSSTABS_CELLS
#undef CS
B_CS_STATS_ALL = (1u << N_CROSSTABS_STATS) - 1,
B_CS_CELLS_ALL = (1u << N_CROSSTABS_CELLS) - 1,
B_CS_STATS_DEFAULT = B_CS_CHISQ,
B_CS_CELL_DEFAULT = B_CS_COUNT | B_CS_ROW | B_CS_COLUMN | B_CS_TOTAL,
B_CS_NONE
};
static const struct checkbox_entry_item stats[] =
{
#define CS(NAME, LABEL, TOOLTIP) {#NAME, LABEL, TOOLTIP},
CROSSTABS_STATS \
CS(NONE, N_("None"), NULL)
#undef CS
};
static const struct checkbox_entry_item cells[] =
{
#define CS(NAME, LABEL, TOOLTIP) {#NAME, LABEL, TOOLTIP},
CROSSTABS_CELLS \
CS(NONE, N_("None"), NULL)
#undef CS
};
static void
on_format_clicked (PsppireDialogActionCrosstabs *cd)
{
int ret;
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->avalue_button), cd->format_options_avalue);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->table_button), cd->format_options_table);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->pivot_button), cd->format_options_pivot);
ret = psppire_dialog_run (PSPPIRE_DIALOG (cd->format_dialog));
if (ret == PSPPIRE_RESPONSE_CONTINUE)
{
cd->format_options_avalue =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->avalue_button));
cd->format_options_table =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->table_button));
cd->format_options_pivot =
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (cd->pivot_button));
}
}
static void
on_cell_clicked (PsppireDialogActionCrosstabs *cd)
{
GtkListStore *liststore = clone_list_store (GTK_LIST_STORE (cd->cell));
gint ret = psppire_dialog_run (PSPPIRE_DIALOG (cd->cell_dialog));
if (ret == PSPPIRE_RESPONSE_CONTINUE)
{
g_object_unref (liststore);
}
else
{
gtk_tree_view_set_model (GTK_TREE_VIEW (cd->cell_view) , GTK_TREE_MODEL (liststore));
cd->cell = GTK_TREE_MODEL (liststore);
}
}
static void
on_statistics_clicked (PsppireDialogActionCrosstabs *cd)
{
GtkListStore *liststore = clone_list_store (GTK_LIST_STORE (cd->stat));
gint ret = psppire_dialog_run (PSPPIRE_DIALOG (cd->stat_dialog));
if (ret == PSPPIRE_RESPONSE_CONTINUE)
{
g_object_unref (liststore);
}
else
{
gtk_tree_view_set_model (GTK_TREE_VIEW (cd->stat_view) , GTK_TREE_MODEL (liststore));
cd->stat = GTK_TREE_MODEL (liststore);
}
}
static GtkBuilder *
psppire_dialog_action_crosstabs_activate (PsppireDialogAction *a, GVariant *param)
{
PsppireDialogActionCrosstabs *act = PSPPIRE_DIALOG_ACTION_CROSSTABS (a);
PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
GtkBuilder *xml = builder_new ("crosstabs.ui");
pda->dialog = get_widget_assert (xml, "crosstabs-dialog");
pda->source = get_widget_assert (xml, "dict-treeview");
act->dest_rows = get_widget_assert (xml, "rows");
act->dest_cols = get_widget_assert (xml, "cols");
act->format_button = get_widget_assert (xml, "format-button");
act->stat_button = get_widget_assert (xml, "stats-button");
act->cell_button = get_widget_assert (xml, "cell-button");
act->stat_view = get_widget_assert (xml, "stats-view");
act->cell_view = get_widget_assert (xml, "cell-view");
act->cell_dialog = get_widget_assert (xml, "cell-dialog");
act->stat_dialog = get_widget_assert (xml, "stat-dialog");
act->format_dialog = get_widget_assert (xml, "format-dialog");
act->avalue_button = get_widget_assert (xml, "ascending");
act->table_button = get_widget_assert (xml, "print-tables");
act->pivot_button = get_widget_assert (xml, "pivot");
act->format_options_avalue = TRUE;
act->format_options_table = TRUE;
act->format_options_pivot = TRUE;
psppire_checkbox_treeview_populate (PSPPIRE_CHECKBOX_TREEVIEW (act->cell_view),
B_CS_CELL_DEFAULT,
N_CROSSTABS_CELLS,
cells);
act->cell = gtk_tree_view_get_model (GTK_TREE_VIEW (act->cell_view));
psppire_checkbox_treeview_populate (PSPPIRE_CHECKBOX_TREEVIEW (act->stat_view),
B_CS_STATS_DEFAULT,
N_CROSSTABS_STATS,
stats);
act->stat = gtk_tree_view_get_model (GTK_TREE_VIEW (act->stat_view));
psppire_dialog_action_set_refresh (pda, refresh);
psppire_dialog_action_set_valid_predicate (pda,
dialog_state_valid);
g_signal_connect_swapped (act->cell_button, "clicked",
G_CALLBACK (on_cell_clicked), act);
g_signal_connect_swapped (act->stat_button, "clicked",
G_CALLBACK (on_statistics_clicked), act);
g_signal_connect_swapped (act->format_button, "clicked",
G_CALLBACK (on_format_clicked), act);
return xml;
}
static char *
generate_syntax (const PsppireDialogAction *a)
{
PsppireDialogActionCrosstabs *cd = PSPPIRE_DIALOG_ACTION_CROSSTABS (a);
gchar *text = NULL;
int i, n;
guint selected;
GString *string = g_string_new ("CROSSTABS ");
gboolean ok;
GtkTreeIter iter;
g_string_append (string, "\n\t/TABLES=");
psppire_var_view_append_names (PSPPIRE_VAR_VIEW (cd->dest_rows), 0, string);
g_string_append (string, "\tBY\t");
psppire_var_view_append_names (PSPPIRE_VAR_VIEW (cd->dest_cols), 0, string);
g_string_append (string, "\n\t/FORMAT=");
if (cd->format_options_avalue)
g_string_append (string, "AVALUE");
else
g_string_append (string, "DVALUE");
g_string_append (string, " ");
if (cd->format_options_table)
g_string_append (string, "TABLES");
else
g_string_append (string, "NOTABLES");
g_string_append (string, " ");
if (cd->format_options_pivot)
g_string_append (string, "PIVOT");
else
g_string_append (string, "NOPIVOT");
selected = 0;
for (i = 0, ok = gtk_tree_model_get_iter_first (cd->stat, &iter); ok;
i++, ok = gtk_tree_model_iter_next (cd->stat, &iter))
{
gboolean toggled;
gtk_tree_model_get (cd->stat, &iter,
CHECKBOX_COLUMN_SELECTED, &toggled, -1);
if (toggled)
selected |= 1u << i;
else
selected &= ~(1u << i);
}
if (!(selected & (1u << CS_STATS_NONE)))
{
if (selected)
{
g_string_append (string, "\n\t/STATISTICS=");
n = 0;
for (i = 0; i < N_CROSSTABS_STATS; i++)
if (selected & (1u << i))
{
if (n++)
g_string_append (string, " ");
g_string_append (string, stats[i].name);
}
}
}
selected = 0;
for (i = 0, ok = gtk_tree_model_get_iter_first (cd->cell, &iter); ok;
i++, ok = gtk_tree_model_iter_next (cd->cell, &iter))
{
gboolean toggled;
gtk_tree_model_get (cd->cell, &iter,
CHECKBOX_COLUMN_SELECTED, &toggled, -1);
if (toggled)
selected |= 1u << i;
else
selected &= ~(1u << i);
}
g_string_append (string, "\n\t/CELLS=");
if (selected & (1u << CS_CELLS_NONE))
g_string_append (string, "NONE");
else
{
n = 0;
for (i = 0; i < N_CROSSTABS_CELLS; i++)
if (selected & (1u << i))
{
if (n++)
g_string_append (string, " ");
g_string_append (string, cells[i].name);
}
}
g_string_append (string, ".\n");
text = string->str;
g_string_free (string, FALSE);
return text;
}
static void
psppire_dialog_action_crosstabs_class_init (PsppireDialogActionCrosstabsClass *class)
{
PSPPIRE_DIALOG_ACTION_CLASS (class)->initial_activate = psppire_dialog_action_crosstabs_activate;
PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
}
static void
psppire_dialog_action_crosstabs_init (PsppireDialogActionCrosstabs *act)
{
}