[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[RFC] Support column alignment in (multi)select debconf questions



Hi!

Attached is a patch adding a new capability to cdebconf named "align",
following Anton's proposal [1] and as discussed during the september IRC
meeting [2].

 cdebconf/src/commands.c                                 |    5 
 cdebconf/src/frontend.c                                 |    6 
 cdebconf/src/frontend.h                                 |    2 
 cdebconf/src/modules/frontend/gtk/Makefile              |    4 
 cdebconf/src/modules/frontend/gtk/align_text_renderer.c |  284 ++++++++++++++++
 cdebconf/src/modules/frontend/gtk/align_text_renderer.h |   87 ++++
 cdebconf/src/modules/frontend/gtk/cdebconf_gtk.c        |    7 
 cdebconf/src/modules/frontend/gtk/cdebconf_gtk.h        |    7 
 cdebconf/src/modules/frontend/gtk/select_handlers.c     |  121 +++++-
 cdebconf/src/modules/frontend/gtk/ui.c                  |   19 +
 cdebconf/src/modules/frontend/gtk/ui.h                  |    2 
 cdebconf/src/modules/frontend/newt/newt.c               |   15 
 cdebconf/src/modules/frontend/text/text.c               |   37 --
 cdebconf/src/strutl.c                                   |   95 +++++
 cdebconf/src/strutl.h                                   |    3 
 cdebconf/src/test/align.config                          |   16 
 cdebconf/src/test/align.templates                       |   11 
 localechooser/debian/control                            |    2 
 localechooser/localechooser                             |    4 
 localechooser/mktemplates.language                      |    3 
 20 files changed, 682 insertions(+), 48 deletions(-)

This capability has been implemented in the three main frontends
(namely text, newt and gtk) that are currently used in cdebconf.

The current implementation differs from Anton's first proposal in two
ways:
 * There is no column titles: it was quite hard to implement, and after
   some review of the current d-i templates, they seemed not really
   needed to me.
 * The \t (TAB) character is the column separator.

This last point raised some concerns for Otavio as tabs might be more
difficult to spot while reviewing templates.  Christian confirmed my
feeling that it was a good idea though, as he told me that it was
totally unused in our templates and that we need to add comments before
those templates in any cases.

The patch also contains a small change to localechooser to make it
benefits from the new capability.  The next best candidate is probably
partman, and Anton told me that he would try to have a look in the next
days.

I wonder if those changes should be pushed in beta1.  I have a good
feeling about them and that would be a first real improvement to show up
in the graphical installer since Etch.  But, please, review and test
first! :)

[1] http://lists.debian.org/debian-boot/2007/07/msg00723.html
[2] http://people.debian.org/~lunar/d-i/irc-meeting-20070926/minutes

Cheers,
-- 
Jérémy Bobbio                        .''`. 
lunar@debian.org                    : :Ⓐ  :  # apt-get install anarchism
                                    `. `'` 
                                      `-   
commit 38baf0fa9580fe240aa01339599dca646f8ec834
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 12:58:03 2007 +0200

    Add a new "align" capability to the protocol.

diff --git a/packages/cdebconf/src/commands.c b/packages/cdebconf/src/commands.c
index 5529822..e2733f2 100644
--- a/packages/cdebconf/src/commands.c
+++ b/packages/cdebconf/src/commands.c
@@ -127,9 +127,12 @@ command_capb(struct confmodule *mod, char *arg)
             mod->frontend->capability |= DCF_CAPB_BACKUP;
         else if (strcmp(argv[i], "progresscancel") == 0)
             mod->frontend->capability |= DCF_CAPB_PROGRESSCANCEL;
+        else if (strcmp(argv[i], "align") == 0)
+            mod->frontend->capability |= DCF_CAPB_ALIGN;
     }
 
-    if (asprintf(&out, "%u multiselect backup progresscancel", CMDSTATUS_SUCCESS) == -1)
+    if (asprintf(&out, "%u multiselect backup progresscancel align",
+                 CMDSTATUS_SUCCESS) == -1)
         DIE("Out of memory");
 
     plugin_state = NULL;
diff --git a/packages/cdebconf/src/frontend.c b/packages/cdebconf/src/frontend.c
index 23e1b32..3e169cf 100644
--- a/packages/cdebconf/src/frontend.c
+++ b/packages/cdebconf/src/frontend.c
@@ -101,6 +101,11 @@ static bool frontend_can_cancel_progress(struct frontend *ui)
 	return false;
 }
 
+static bool frontend_can_align(struct frontend *ui)
+{
+	return false;
+}
+
 static void frontend_progress_start(struct frontend *ui, int min, int max, const char *title)
 {
 	DELETE(ui->progress_title);
@@ -208,6 +213,7 @@ struct frontend *frontend_new(struct configuration *cfg, struct template_db *tdb
 	SETMETHOD(can_go_back);
 	SETMETHOD(can_go_forward);
 	SETMETHOD(can_cancel_progress);
+	SETMETHOD(can_align);
 	SETMETHOD(progress_start);
 	SETMETHOD(progress_set);
 	SETMETHOD(progress_step);
diff --git a/packages/cdebconf/src/frontend.h b/packages/cdebconf/src/frontend.h
index 17aa3f3..d96c1b5 100644
--- a/packages/cdebconf/src/frontend.h
+++ b/packages/cdebconf/src/frontend.h
@@ -20,6 +20,7 @@ struct frontend;
 
 #define DCF_CAPB_BACKUP		(1UL << 0)
 #define DCF_CAPB_PROGRESSCANCEL	(1UL << 1)
+#define DCF_CAPB_ALIGN		(1UL << 2)
 
 struct frontend_module {
     int (*initialize)(struct frontend *, struct configuration *);
@@ -33,6 +34,7 @@ struct frontend_module {
     bool (*can_go_back)(struct frontend *, struct question *);
     bool (*can_go_forward)(struct frontend *, struct question *);
     bool (*can_cancel_progress)(struct frontend *);
+    bool (*can_align)(struct frontend *, struct question *);
 
     void (*progress_start)(struct frontend *fe, int min, int max, const char *title);
     int (*progress_set) (struct frontend *fe, int val);

commit 5195dc97c2fad3c57352941514a8d0866d3ad583
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 17:15:51 2007 +0200

    Move strpad() from text frontend to strutl.{c,h}.

diff --git a/packages/cdebconf/src/modules/frontend/text/text.c b/packages/cdebconf/src/modules/frontend/text/text.c
index d7f844a..19fe33a 100644
--- a/packages/cdebconf/src/modules/frontend/text/text.c
+++ b/packages/cdebconf/src/modules/frontend/text/text.c
@@ -78,30 +78,6 @@ typedef int (text_handler)(struct frontend *obj, struct question *q);
 #define ISEMPTY(buf) (buf[0] == 0)
 #endif
 
-/*  This function will be moved to strutl.c  */
-/*
- * Add spaces at the end of string so that strwidth(that) == maxsize
- * Input string must have been allocated with enough space.
- */
-int
-strpad (char *what, size_t maxsize)
-{
-    size_t pos;
-    int k;
-    char *p;
-    wchar_t c;
-
-    pos = 0;
-    for (p = what; (k = mbtowc (&c, p, MB_LEN_MAX)) > 0; p += k)
-        pos += wcwidth (c);
-    if (pos > maxsize)
-        return 0;
-    for (k = pos; k < maxsize; k++, p++)
-        *p = ' ';
-    *p = '\0';
-    return 1;
-}  
-
 /*
  * Function: getwidth
  * Input: none
diff --git a/packages/cdebconf/src/strutl.c b/packages/cdebconf/src/strutl.c
index 8b15a70..5f815de 100644
--- a/packages/cdebconf/src/strutl.c
+++ b/packages/cdebconf/src/strutl.c
@@ -540,6 +540,29 @@ strwidth (const char *what)
     return res;
 }  
 
+/*
+ * Add spaces at the end of string so that strwidth(that) == maxsize
+ * Input string must have been allocated with enough space.
+ */
+int
+strpad (char *what, size_t maxsize)
+{
+    size_t pos;
+    int k;
+    char *p;
+    wchar_t c;
+
+    pos = 0;
+    for (p = what; (k = mbtowc (&c, p, MB_LEN_MAX)) > 0; p += k)
+        pos += wcwidth (c);
+    if (pos > maxsize)
+        return 0;
+    for (k = pos; k < maxsize; k++, p++)
+        *p = ' ';
+    *p = '\0';
+    return 1;
+}
+
 int
 strtruncate (char *what, size_t maxsize)
 {
diff --git a/packages/cdebconf/src/strutl.h b/packages/cdebconf/src/strutl.h
index 710f794..fe16082 100644
--- a/packages/cdebconf/src/strutl.h
+++ b/packages/cdebconf/src/strutl.h
@@ -55,6 +55,7 @@ int strwrap(const char *str, const int width, char *lines[], int maxlines);
 int strlongest(char **strs, int count);
 
 size_t strwidth(const char *width);
+int strpad(char *what, size_t maxsize);
 int strtruncate (char *what, size_t maxsize);
 
 #endif

commit b2d38e4f9cfb277212501676476004152fd274b4
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 17:27:57 2007 +0200

    Add stralign() to strutl.{c,h}

diff --git a/packages/cdebconf/src/strutl.c b/packages/cdebconf/src/strutl.c
index 5f815de..7b4ba92 100644
--- a/packages/cdebconf/src/strutl.c
+++ b/packages/cdebconf/src/strutl.c
@@ -585,5 +585,75 @@ strtruncate (char *what, size_t maxsize)
         *p = '.';
     *p = '\0';
     return 1;
-}  
+}
+
+int stralign(char **strs, int count, const char *delim)
+{
+    unsigned int i;
+    unsigned int j;
+    unsigned int * cells_per_line;
+    unsigned int num_columns;
+    unsigned int * column_widths;
+    size_t * column_sizes;
+    char * next_cell;
+    char * cell;
+    size_t max_str_size;
+    char * new_str;
+
+    cells_per_line = malloc(sizeof (unsigned int) * count);
+    memset(cells_per_line, 0, sizeof (unsigned int) * count);
+
+    num_columns = 0;
+    column_widths = NULL;
+    column_sizes = NULL;
+    for (i = 0; i < count; i++) {
+        next_cell = strs[i];
+        for (j = 0; NULL != next_cell; j++) {
+            cells_per_line[i] = j + 1;
+            if (num_columns < cells_per_line[i]) {
+                num_columns = j + 1;
+                column_widths = realloc(column_widths,
+                                        sizeof (unsigned int) * num_columns);
+                column_widths[j] = 0;
+                column_sizes = realloc(column_sizes,
+                                        sizeof (size_t) * num_columns);
+                column_sizes[j] = 0;
+            }
+            cell = strsep(&next_cell, delim);
+            if (NULL != next_cell) {
+                column_widths[j] = MAX(column_widths[j], strwidth(cell));
+                column_sizes[j] = MAX(column_sizes[j],
+                                      strlen(cell) + 2 /* extra spaces */);
+            } else {
+                column_sizes[j] = MAX(column_sizes[j], strlen(cell));
+            }
+        }
+    }
+    max_str_size = 0;
+    for (j = 0; j < num_columns; j++) {
+        max_str_size += column_sizes[j];
+    }
+    free(column_sizes);
+    for (i = 0; i < count; i++) {
+        new_str = malloc(sizeof (char) * max_str_size + 1);
+        next_cell = new_str;
+        *next_cell = '\0';
+        cell = strs[i];
+        for (j = 0; j < cells_per_line[i]; j++) {
+            strcpy(next_cell, cell);
+            if (0 != column_widths[j]) {
+                strpad(next_cell, column_widths[j] + 2 /* extra space */);
+            }
+            next_cell += strlen(next_cell);
+            cell += strlen(cell) + 1;
+        }
+        free(strs[i]);
+        strs[i] = new_str;
+    }
+
+    free(column_widths);
+    free(cells_per_line);
+
+    return 0;
+}
 
diff --git a/packages/cdebconf/src/strutl.h b/packages/cdebconf/src/strutl.h
index fe16082..c877b8b 100644
--- a/packages/cdebconf/src/strutl.h
+++ b/packages/cdebconf/src/strutl.h
@@ -58,4 +58,6 @@ size_t strwidth(const char *width);
 int strpad(char *what, size_t maxsize);
 int strtruncate (char *what, size_t maxsize);
 
+int stralign(char **strs, int count, const char *delim);
+
 #endif

commit 7aeb871cd49ad24033a2e361067154ffcc462a44
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 17:45:12 2007 +0200

    Add tests for the "align" capability.

diff --git a/packages/cdebconf/src/test/align.config b/packages/cdebconf/src/test/align.config
new file mode 100755
index 0000000..73ae320
--- /dev/null
+++ b/packages/cdebconf/src/test/align.config
@@ -0,0 +1,16 @@
+#! /bin/sh -e
+# Test for column alignment support
+
+. ../client/confmodule
+
+db_capb align
+
+db_fset test-align/select seen false
+db_input critical test-align/select
+db_go
+
+db_fset test-align/multiselect seen false
+db_input critical test-align/multiselect
+db_go
+
+exit 0
diff --git a/packages/cdebconf/src/test/align.templates b/packages/cdebconf/src/test/align.templates
new file mode 100644
index 0000000..d810b59
--- /dev/null
+++ b/packages/cdebconf/src/test/align.templates
@@ -0,0 +1,11 @@
+Template: test-align/select
+Type: select
+Choices: qmqp-source (1)	- multi-threaded QMQP test generator	foo, quiz (6)	- random knowledge tests	barbar, sane-test (5)	- SANE backend for testing frontends with overflow, signbit (3)	- test sign of a real floating point number	baz, Very long cell that overflows the next one in line.
+Description: Select one option
+ This is the prompt for a select-type question
+
+Template: test-align/multiselect
+Type: multiselect
+Choices: qmqp-source (1)	- multi-threaded QMQP test generator	foo, quiz (6)	- random knowledge tests	barbar, sane-test (5)	- SANE backend for testing frontends with overflow, signbit (3)	- test sign of a real floating point number	baz, Very long cell that overflows the next one in line.
+Description: Select some options
+ This is the prompt for a multiselect-type question

commit fadc001b25e10da29e20c4a0468d9d2b3b77e2d3
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 17:46:10 2007 +0200

    Add support for the "align" capability to the text frontend

diff --git a/packages/cdebconf/src/modules/frontend/text/text.c b/packages/cdebconf/src/modules/frontend/text/text.c
index 19fe33a..161d002 100644
--- a/packages/cdebconf/src/modules/frontend/text/text.c
+++ b/packages/cdebconf/src/modules/frontend/text/text.c
@@ -208,6 +208,12 @@ printlist (struct frontend *obj, struct question *q, int count, char **choices_t
 		logcount++;
 	} while (i > 0);
 
+	if (obj->methods.can_align(obj, q)) {
+		stralign(choices_translated, count, "\t");
+		/* Display only one column to get meaningful alignment. */
+		width = 1;
+	}
+
 	/*  Set string arrays  */
 	for (i=0; i < count; i++)
 	{
@@ -766,6 +772,12 @@ text_can_go_back(struct frontend *obj, struct question *q)
 	return (obj->capability & DCF_CAPB_BACKUP);
 }
 
+static bool
+text_can_align(struct frontend *obj, struct question *q)
+{
+	return (obj->capability & DCF_CAPB_ALIGN);
+}
+
 /*
  * Function: text_go
  * Input: struct frontend *obj - frontend object
@@ -892,6 +904,7 @@ struct frontend_module debconf_frontend_module =
 {
 	initialize: text_initialize,
 	can_go_back: text_can_go_back,
+	can_align: text_can_align,
 	go: text_go,
 	progress_start: text_progress_start,
 	progress_set: text_progress_set,

commit 83ecbda76618a8437fc79f1c45982562d6a9cb52
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 17:51:14 2007 +0200

    Add support for the "align" capability to the newt frontend

diff --git a/packages/cdebconf/src/modules/frontend/newt/newt.c b/packages/cdebconf/src/modules/frontend/newt/newt.c
index d25e349..5b4e700 100644
--- a/packages/cdebconf/src/modules/frontend/newt/newt.c
+++ b/packages/cdebconf/src/modules/frontend/newt/newt.c
@@ -518,6 +518,10 @@ show_multiselect_window(struct frontend *obj, struct question *q, int show_ext_d
     if (strchoicesplitsort(q_get_choices_vals(q), q_get_choices(q), indices, choices, choices_trans, tindex, count) != count)
         return DC_NOTOK;
 
+    if (obj->methods.can_align(obj, q)) {
+        stralign(choices_trans, count, "\t");
+    }
+
     defvals = malloc(sizeof(char *) * count);
     defcount = strchoicesplit(question_getvalue(q, ""), defvals, count);
     answer = malloc(sizeof(char) * count);
@@ -674,6 +678,10 @@ show_select_window(struct frontend *obj, struct question *q, int show_ext_desc)
     if (strchoicesplitsort(q_get_choices_vals(q), q_get_choices(q), indices, choices, choices_trans, tindex, count) != count)
         return DC_NOTOK;
 
+    if (obj->methods.can_align(obj, q)) {
+        stralign(choices_trans, count, "\t");
+    }
+
     sel_height = count;
     form = cdebconf_newt_create_form(NULL);
 #ifdef HAVE_LIBTEXTWRAP
@@ -1139,6 +1147,12 @@ newt_can_cancel_progress(struct frontend *obj)
     return (obj->capability & DCF_CAPB_PROGRESSCANCEL);
 }
 
+static bool
+newt_can_align(struct frontend *obj)
+{
+    return (obj->capability & DCF_CAPB_ALIGN);
+}
+
 static void
 newt_make_progress_bar(struct frontend *obj, const char *info)
 {
@@ -1336,6 +1350,7 @@ shutdown: newt_shutdown,
 go: newt_go,
 can_go_back: newt_can_go_back,
 can_cancel_progress: newt_can_cancel_progress,
+can_align: newt_can_align,
 progress_start: newt_progress_start,
 progress_set:   newt_progress_set,
 progress_info:  newt_progress_info,

commit 2648bd19445b58937aea89b24098c8e3201a0904
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Thu Oct 11 19:04:48 2007 +0200

    Add support for the "align" capability to the GTK+ frontend

diff --git a/packages/cdebconf/src/modules/frontend/gtk/Makefile b/packages/cdebconf/src/modules/frontend/gtk/Makefile
index 7c13199..3e4c2d1 100644
--- a/packages/cdebconf/src/modules/frontend/gtk/Makefile
+++ b/packages/cdebconf/src/modules/frontend/gtk/Makefile
@@ -9,7 +9,9 @@ OBJS = cdebconf_gtk.opic \
        progress.opic \
        go.opic \
        handlers.opic \
-       ui.opic
+       ui.opic \
+       align_text_renderer.opic
+#       cellrendereraligntext.opic
 
 ifneq ($(strip $(filter -DDI_UDEB, $(CFLAGS))),)
 OBJS += screenshot.opic di.opic
diff --git a/packages/cdebconf/src/modules/frontend/gtk/align_text_renderer.c b/packages/cdebconf/src/modules/frontend/gtk/align_text_renderer.c
new file mode 100644
index 0000000..9576f81
--- /dev/null
+++ b/packages/cdebconf/src/modules/frontend/gtk/align_text_renderer.c
@@ -0,0 +1,284 @@
+/*****************************************************************************
+ *
+ * cdebconf - An implementation of the Debian Configuration Management
+ *            System
+ *
+ * $Id$
+ *
+ * cdebconf is (c) 2000-2007 Randolph Chung and others under the following
+ * license.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+/** @file align_text_renderer.c
+ * GtkCellRenderer for text aligned with tab stops
+ */
+
+#include "align_text_renderer.h"
+
+enum {
+    PROP_0,
+
+    PROP_TEXT
+};
+
+static gpointer cdebconf_gtk_align_text_renderer_parent_class;
+
+static void cdebconf_gtk_align_text_renderer_init(AlignTextRenderer * renderer)
+{
+    GTK_CELL_RENDERER(renderer)->xalign = 0.0;
+    GTK_CELL_RENDERER(renderer)->yalign = 0.5;
+    GTK_CELL_RENDERER(renderer)->xpad = 2;
+    GTK_CELL_RENDERER(renderer)->ypad = 2;
+    renderer->tab_array = NULL;
+}
+
+static void align_text_renderer_finalize(GObject * object)
+{
+    AlignTextRenderer * renderer = ALIGN_TEXT_RENDERER(object);
+
+    if (NULL != renderer->text) {
+        g_free(renderer->text);
+    }
+    if (NULL != renderer->tab_array) {
+        pango_tab_array_free(renderer->tab_array);
+    }
+
+    (* G_OBJECT_CLASS(
+        cdebconf_gtk_align_text_renderer_parent_class)->finalize)(object);
+}
+
+static void align_text_renderer_get_property(
+    GObject * object, guint param_id, GValue * value,
+    GParamSpec * param_spec)
+{
+    AlignTextRenderer * renderer = ALIGN_TEXT_RENDERER(object);
+
+    switch (param_id) {
+        case PROP_TEXT:
+            g_value_set_string(value, renderer->text);
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, param_spec);
+            break;
+    }
+}
+
+static void align_text_renderer_set_property(
+    GObject * object, guint param_id, const GValue * value,
+    GParamSpec * param_spec)
+{
+    AlignTextRenderer * renderer = ALIGN_TEXT_RENDERER(object);
+
+    switch (param_id) {
+        case PROP_TEXT:
+            if (NULL != renderer->text) {
+                g_free(renderer->text);
+            }
+            renderer->text = g_strdup(g_value_get_string(value));
+            g_object_notify(object, "text");
+            break;
+
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, param_spec);
+            break;
+    }
+}
+
+void cdebconf_gtk_align_text_renderer_set_tab_array(
+    AlignTextRenderer * renderer, PangoTabArray * tab_array)
+{
+    if (NULL != renderer->tab_array) {
+        pango_tab_array_free(renderer->tab_array);
+    }
+    renderer->tab_array = pango_tab_array_copy(tab_array);
+}
+
+GtkCellRenderer * cdebconf_gtk_align_text_renderer_new(void)
+{
+    return g_object_new(TYPE_ALIGN_TEXT_RENDERER, NULL);
+}
+
+static PangoLayout * get_layout(AlignTextRenderer * renderer,
+                                GtkWidget * widget)
+{
+    PangoLayout * layout;
+
+    layout = gtk_widget_create_pango_layout(widget, renderer->text);
+    pango_layout_set_width(layout, -1);
+    pango_layout_set_wrap(layout, PANGO_WRAP_CHAR);
+    /* XXX? pango_layout_set_alignment */
+    pango_layout_set_tabs(layout, renderer->tab_array);
+    return layout;
+}
+
+static void align_text_renderer_get_size(
+    GtkCellRenderer * cell, GtkWidget * widget, GdkRectangle * cell_area,
+    gint * x_offset, gint * y_offset, gint * width, gint * height)
+{
+    AlignTextRenderer * renderer = ALIGN_TEXT_RENDERER(cell);
+    PangoLayout * layout;
+    PangoRectangle rect;
+
+    layout = get_layout(renderer, widget);
+    pango_layout_get_pixel_extents(layout, NULL, &rect);
+    if (NULL != height) {
+        *height = cell->ypad * 2 + rect.height;
+    }
+    if (NULL != width) {
+        *width = cell->xpad * 2 + rect.x + rect.width;
+    }
+
+    if (NULL != cell_area) {
+        if (NULL != x_offset) {
+            *x_offset = cell_area->width - rect.x - rect.width -
+                        (2 * cell->xpad);
+            if (GTK_TEXT_DIR_RTL == gtk_widget_get_direction(widget)) {
+                *x_offset *= 1.0 - cell->xalign;
+            } else {
+                *x_offset *= cell->xalign;
+            }
+        }
+        if (NULL != y_offset) {
+            *y_offset = cell_area->height - rect.height - (2 * cell->ypad);
+            *y_offset = MAX(*y_offset * cell->yalign, 0);
+        }
+    }
+}
+
+static GtkStateType get_state(GtkCellRenderer * cell, GtkWidget * widget,
+                              GtkCellRendererState flags)
+{
+    if (!cell->sensitive) {
+        return GTK_STATE_INSENSITIVE;
+    }
+    if (GTK_CELL_RENDERER_SELECTED == (flags & GTK_CELL_RENDERER_SELECTED)) {
+        return GTK_WIDGET_HAS_FOCUS(widget) ?
+                   GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
+    }
+    if (GTK_CELL_RENDERER_PRELIT == (flags & GTK_CELL_RENDERER_PRELIT) &&
+        GTK_STATE_PRELIGHT == GTK_WIDGET_STATE(widget)) {
+        return GTK_STATE_PRELIGHT;
+    }
+    if (GTK_STATE_INSENSITIVE == GTK_WIDGET_STATE(widget)) {
+        return GTK_STATE_INSENSITIVE;
+    }
+    return GTK_STATE_NORMAL;
+}
+
+#if 0
+static void draw_background(GtkCellRendererText * text_renderer,
+                            GdkWindow * window, GdkRectangle * background_area,
+                            GdkRectangle * expose_area)
+{
+    cairo_t * cr = gdk_cairo_create(window);
+
+    if (NULL != expose_area) {
+        gdk_cairo_rectangle(cr, expose_area);
+        cairo_clip(cr);
+    }
+    gdk_cairo_rectangle(cr, background_area);
+    cairo_set_source_rgb(cr, text_renderer->background.red / 65535.,
+                         text_renderer->background.green / 65535.,
+                         text_renderer->background.blue / 65535.);
+    cairo_fill(cr);
+    cairo_destroy(cr);
+}
+#endif
+
+static void align_text_renderer_render(
+    GtkCellRenderer * cell, GdkWindow * window, GtkWidget * widget,
+    GdkRectangle * background_area, GdkRectangle * cell_area,
+    GdkRectangle * expose_area, guint flags)
+{
+    AlignTextRenderer * renderer = ALIGN_TEXT_RENDERER(cell);
+    PangoLayout * layout;
+    GtkStateType state;
+    gint x_offset;
+    gint y_offset;
+
+    layout = get_layout(renderer, widget);
+    align_text_renderer_get_size(cell, widget, cell_area, &x_offset,
+                                 &y_offset, NULL, NULL);
+
+    state = get_state(cell, widget, flags);
+    gtk_paint_layout(widget->style, window, state, TRUE, expose_area,
+                     widget, "align_text_renderer",
+                     cell_area->x + x_offset + cell->xpad,
+                     cell_area->y + y_offset + cell->ypad,
+                     layout);
+}
+
+static void cdebconf_gtk_align_text_renderer_class_init(
+    AlignTextRendererClass * klass)
+{
+    GObjectClass * object_class = G_OBJECT_CLASS(klass);
+    GtkCellRendererClass * cell_class = GTK_CELL_RENDERER_CLASS(klass);
+
+    cdebconf_gtk_align_text_renderer_parent_class =
+        g_type_class_peek_parent (klass);
+    object_class->finalize = align_text_renderer_finalize;
+    object_class->get_property = align_text_renderer_get_property;
+    object_class->set_property = align_text_renderer_set_property;
+
+    cell_class->get_size = align_text_renderer_get_size;
+    cell_class->render = align_text_renderer_render;
+
+    klass->set_tab_array = cdebconf_gtk_align_text_renderer_set_tab_array;
+
+    g_object_class_install_property(
+        object_class, PROP_TEXT,
+        g_param_spec_string("text", "Text", "Text to render", NULL,
+        G_PARAM_READWRITE));
+}
+
+GType cdebconf_gtk_align_text_renderer_get_type(void)
+{
+    static const GTypeInfo align_text_renderer_info = {
+        sizeof (AlignTextRendererClass),
+        NULL,                                                     /* base_init */
+        NULL,                                                     /* base_finalize */
+        (GClassInitFunc) cdebconf_gtk_align_text_renderer_class_init,
+        NULL,                                                     /* class_finalize */
+        NULL,                                                     /* class_data */
+        sizeof (AlignTextRenderer),
+        0,                                                        /* n_preallocs */
+        (GInstanceInitFunc) cdebconf_gtk_align_text_renderer_init,
+        NULL
+    };
+    static GType align_text_renderer_type = 0;
+
+    if (align_text_renderer_type) {
+        return align_text_renderer_type;
+    }
+
+    /* Derive from GtkCellRenderer */
+    align_text_renderer_type = g_type_register_static(
+        GTK_TYPE_CELL_RENDERER, "AlignTextRenderer",
+        &align_text_renderer_info, 0);
+    return align_text_renderer_type;
+}
diff --git a/packages/cdebconf/src/modules/frontend/gtk/align_text_renderer.h b/packages/cdebconf/src/modules/frontend/gtk/align_text_renderer.h
new file mode 100644
index 0000000..4f4ea62
--- /dev/null
+++ b/packages/cdebconf/src/modules/frontend/gtk/align_text_renderer.h
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ *
+ * cdebconf - An implementation of the Debian Configuration Management
+ *            System
+ *
+ * $Id$
+ *
+ * cdebconf is (c) 2000-2007 Randolph Chung and others under the following
+ * license.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+/** @file align_text_renderer.h
+ * GtkCellRenderer for text aligned with tab stops (header)
+ */
+
+#ifndef _ALIGN_TEXT_RENDERER_H_
+#define _ALIGN_TEXT_RENDERER_H_
+
+#include <gtk/gtk.h>
+
+#define TYPE_ALIGN_TEXT_RENDERER (cdebconf_gtk_align_text_renderer_get_type())
+
+#define ALIGN_TEXT_RENDERER(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST( \
+        (obj), TYPE_ALIGN_TEXT_RENDERER, AlignTextRenderer))
+#define ALIGN_TEXT_RENDERER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST((klass), \
+                             TYPE_ALIGN_TEXT_RENDERER, \
+			     AlignTextRendererClass))
+#define IS_TEXT_ALIGN_RENDERER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_TEXT_ALIGN_RENDERER))
+#define IS_TEXT_ALIGN_RENDERER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_TEXT_ALIGN_RENDERER))
+#define TEXT_ALIGN_RENDERER_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS((obj), \
+                               TYPE_ALIGN_TEXT_RENDERER, \
+                               AlignTextRendererClass))
+
+typedef struct _AlignTextRenderer AlignTextRenderer;
+typedef struct _AlignTextRendererClass AlignTextRendererClass;
+
+struct _AlignTextRenderer {
+    GtkCellRenderer parent;
+
+    gchar * text;
+    PangoTabArray * tab_array;
+};
+
+struct _AlignTextRendererClass {
+    GtkCellRendererClass parent_class;
+    void (* set_tab_array)(AlignTextRenderer * renderer,
+                           PangoTabArray * tab_array);
+};
+
+GType cdebconf_gtk_align_text_renderer_get_type(void);
+GtkCellRenderer * cdebconf_gtk_align_text_renderer_new(void);
+void cdebconf_gtk_align_text_renderer_set_tab_array(
+    AlignTextRenderer * renderer, PangoTabArray * tab_array);
+
+#endif /* ! _ALIGN_TEXT_RENDERER_H_ */
+
+/* vim: et sw=4 si
+ */
diff --git a/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.c b/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.c
index 9e56bd8..409874a 100644
--- a/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.c
+++ b/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.c
@@ -408,12 +408,19 @@ static bool cdebconf_gtk_can_go_back(struct frontend * fe,
     return DCF_CAPB_BACKUP == (fe->capability & DCF_CAPB_BACKUP);
 }
 
+static bool cdebconf_gtk_can_align(struct frontend * fe,
+                                   struct question * question)
+{
+    return DCF_CAPB_ALIGN == (fe->capability & DCF_CAPB_ALIGN);
+}
+
 /** Describe our frontend implementation to cdebconf.
  */
 struct frontend_module debconf_frontend_module = {
     initialize: cdebconf_gtk_initialize,
     shutdown: cdebconf_gtk_shutdown,
     can_go_back: cdebconf_gtk_can_go_back,
+    can_align: cdebconf_gtk_can_align,
     set_title: cdebconf_gtk_set_title,
     /* see go.c */
     go: cdebconf_gtk_go,
diff --git a/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.h b/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.h
index 8873467..80729e2 100644
--- a/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.h
+++ b/packages/cdebconf/src/modules/frontend/gtk/cdebconf_gtk.h
@@ -54,6 +54,9 @@
 /** Default padding used troughout the GTK+ frontend. */
 #define DEFAULT_PADDING 6
 
+/* Unused area between "aligned" columns in pango units. */
+#define COLUMN_SPACING 20000
+
 #ifdef DI_UDEB
 /** Paths to the directory containing images used by the GTK+ frontend. */
 # define BASE_IMAGE_PATH \
@@ -79,6 +82,10 @@
 #define CAN_GO_BACK(Frontend) \
     (Frontend->methods.can_go_back(Frontend, Frontend->questions))
 
+/** Should tab separated fields be aligned in select and multiselect? */
+#define CAN_ALIGN(Frontend) \
+    (Frontend->methods.can_align(Frontend, Frontend->questions))
+
 /** Is the question the only one in the current GO? */
 #define IS_QUESTION_SINGLE(Question) \
     (NULL == Question->prev && NULL == Question->next)
diff --git a/packages/cdebconf/src/modules/frontend/gtk/select_handlers.c b/packages/cdebconf/src/modules/frontend/gtk/select_handlers.c
index 2950b06..1c151fc 100644
--- a/packages/cdebconf/src/modules/frontend/gtk/select_handlers.c
+++ b/packages/cdebconf/src/modules/frontend/gtk/select_handlers.c
@@ -52,6 +52,7 @@
 #include "descriptions.h"
 #include "choice_model.h"
 #include "ui.h"
+#include "align_text_renderer.h"
 
 /** Setter function for the select handler in multiple questions form.
  *
@@ -227,6 +228,107 @@ static gboolean focus_path(GtkTreeView * view, GdkEventExpose * event,
     return FALSE; /* propagate the event */
 }
 
+/** Adjust tab stops in the given tab array to display all the given values.
+ *
+ * @param widget widget where the tabs will be renderered
+ * @param tab_array tab array to update
+ * @param NULL terminated list of values to be renderered
+ */
+static void adjust_tabs_for_choice(GtkWidget * widget,
+                                   PangoTabArray * tab_array, char ** values)
+{
+    gint columns;
+    gint value_width;
+    gint previous_location;
+    gint location;
+    gint i;
+
+    columns = g_strv_length(values);
+    if (pango_tab_array_get_size(tab_array) < columns - 1) {
+        pango_tab_array_resize(tab_array, columns - 1);
+    }
+    previous_location = 0;
+    for (i = 0; NULL != values[i + 1]; i++) {
+        value_width = cdebconf_gtk_get_text_width(widget, values[i])
+                      + COLUMN_SPACING;
+        pango_tab_array_get_tab(tab_array, i, NULL /* don't get alignment */,
+                                &location);
+        if (location - previous_location < value_width) {
+            location = previous_location + value_width;
+            pango_tab_array_set_tab(tab_array, i, PANGO_TAB_LEFT, location);
+        }
+        previous_location = location;
+    }
+
+#if 0
+    /* DEBUG: dump tabs */
+    g_warning("dump after value[0]: %s", values[i]);
+    for (i = 0; pango_tab_array_get_size(tab_array) > i; i++) {
+        pango_tab_array_get_tab(tab_array, i, NULL /* don't get alignment */,
+                                &location);
+        g_warning("%d: %d", i, location);
+    }
+#endif
+}
+
+/** Adjust tab stops in the given tab array to render all the "columns"
+ * (separated by a tab) in the translated choice of the given model.
+ *
+ * @param widget widget where the choices will be rendered
+ * @param tab_array tab array to update
+ * @param model a choice model
+ */
+static void adjust_tabs(GtkWidget * widget, PangoTabArray * tab_array,
+                        GtkTreeModel * model)
+{
+    char * choice;
+    char ** values;
+    GtkTreeIter iter;
+    gboolean valid;
+
+    valid = gtk_tree_model_get_iter_first(model, &iter);
+    while (valid) {
+        gtk_tree_model_get(model, &iter,
+            /* column: */ CHOICE_MODEL_TRANSLATED_VALUE, &choice,
+            -1 /* end of list */);
+        values = g_strsplit(choice, "\t", 0 /* split all */);
+        adjust_tabs_for_choice(widget, tab_array, values);
+        g_free(choice);
+        g_strfreev(values);
+        valid = gtk_tree_model_iter_next(model, &iter);
+    }
+}
+
+/** Insert the column displaying translated choices in the given GtkTreeView.
+ *
+ * @param fe frontend
+ * @param view column destination
+ */
+static void insert_choice_column(struct frontend * fe, GtkTreeView * view)
+{
+    GtkCellRenderer * renderer;
+    PangoTabArray * tab_array;
+
+    if (CAN_ALIGN(fe)) {
+        /* XXX: check NULL */
+        tab_array = pango_tab_array_new(0 /* start with no tabs */,
+                                        FALSE /* use pango unit */);
+        adjust_tabs(GTK_WIDGET(view), tab_array,
+                    gtk_tree_view_get_model(view));
+        renderer = cdebconf_gtk_align_text_renderer_new();
+        cdebconf_gtk_align_text_renderer_set_tab_array(
+            ALIGN_TEXT_RENDERER(renderer), tab_array);
+        pango_tab_array_free(tab_array);
+    } else {
+        renderer = gtk_cell_renderer_text_new();
+    }
+    gtk_tree_view_insert_column_with_attributes(
+        view, -1 /* insert at the end */,
+        NULL /* no title */, renderer,
+        "text", CHOICE_MODEL_TRANSLATED_VALUE,
+        NULL /* end of attribute list */);
+}
+
 /** Create widget for select question in single question form.
  *
  * This will also register the corresponding setter function.
@@ -245,8 +347,6 @@ static int create_select_list(struct frontend * fe, struct question * question,
     GtkWidget * view;
     GtkWidget * scroll;
     GtkWidget * frame;
-    GtkCellRenderer * text_renderer;
-    char * description;
 
     /* check NULL! */
     view = gtk_tree_view_new_with_model(model);
@@ -265,14 +365,7 @@ static int create_select_list(struct frontend * fe, struct question * question,
         hide_expanders(GTK_TREE_VIEW(view));
     }
 
-    description = q_get_description(question);
-    text_renderer = gtk_cell_renderer_text_new();
-    gtk_tree_view_insert_column_with_attributes(
-        GTK_TREE_VIEW(view), -1 /* insert at the end */,
-        description /* title */, text_renderer,
-        "text", CHOICE_MODEL_TRANSLATED_VALUE,
-        NULL /* end of attribute list */);
-    g_free(description);
+    insert_choice_column(fe, GTK_TREE_VIEW(view));
 
     g_signal_connect_swapped(G_OBJECT(view), "row-activated",
                              G_CALLBACK(cdebconf_gtk_set_answer_ok), fe);
@@ -460,7 +553,6 @@ static int create_multiselect_list(struct frontend * fe,
     GtkWidget * scroll;
     GtkWidget * frame;
     GtkCellRenderer * toggle_renderer;
-    GtkCellRenderer * text_renderer;
     GtkTreePath * path;
 
     view = gtk_tree_view_new_with_model(model);
@@ -476,12 +568,7 @@ static int create_multiselect_list(struct frontend * fe,
         "active", CHOICE_MODEL_SELECTED,
         NULL /* end of attribute list */);
 
-    text_renderer = gtk_cell_renderer_text_new();
-    gtk_tree_view_insert_column_with_attributes(
-        GTK_TREE_VIEW(view), -1 /* insert at the end */,
-        NULL /* no title */, text_renderer,
-        /* column: */ "text", CHOICE_MODEL_TRANSLATED_VALUE,
-        NULL /* end of list */);
+    insert_choice_column(fe, GTK_TREE_VIEW(view));
 
     if (!IS_SPECIAL_QUESTION(question)) {
         hide_expanders(GTK_TREE_VIEW(view));
diff --git a/packages/cdebconf/src/modules/frontend/gtk/ui.c b/packages/cdebconf/src/modules/frontend/gtk/ui.c
index 0eaa0e2..e90975e 100644
--- a/packages/cdebconf/src/modules/frontend/gtk/ui.c
+++ b/packages/cdebconf/src/modules/frontend/gtk/ui.c
@@ -593,5 +593,24 @@ void cdebconf_gtk_empty_target_box(struct frontend * fe)
                          (GtkCallback) gtk_widget_destroy, NULL /* no data */);
 }
 
+/** Returns the width (in pango units) of the given text.
+ *
+ * @param widget widget where the text will be renderered
+ * @param text text to be rendered
+ * @return width of the text in pango units
+ */
+gint cdebconf_gtk_get_text_width(GtkWidget * widget, gchar * text)
+{
+    PangoLayout * layout;
+    gint width;
+
+    layout = gtk_widget_create_pango_layout(widget, text);
+    pango_layout_get_size(layout, &width, NULL /* no height */);
+    g_object_unref(layout);
+
+    return width;
+}
+
+
 /* vim: et sw=4 si
  */
diff --git a/packages/cdebconf/src/modules/frontend/gtk/ui.h b/packages/cdebconf/src/modules/frontend/gtk/ui.h
index cf1eb47..3383afb 100644
--- a/packages/cdebconf/src/modules/frontend/gtk/ui.h
+++ b/packages/cdebconf/src/modules/frontend/gtk/ui.h
@@ -60,6 +60,8 @@ void cdebconf_gtk_hide_target_box(struct frontend * fe);
 
 void cdebconf_gtk_empty_target_box(struct frontend * fe);
 
+gint cdebconf_gtk_get_text_width(GtkWidget * widget, gchar * text);
+
 #endif /* !_UI_H_ */
 
 /* vim: et sw=4 si

commit 01dc8027a432c6678fc591511222db6c6826dcb0
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Fri Oct 12 12:38:36 2007 +0200

    Update cdebconf changelog.

diff --git a/packages/cdebconf/debian/changelog b/packages/cdebconf/debian/changelog
index ae1e6e1..c92b8f1 100644
--- a/packages/cdebconf/debian/changelog
+++ b/packages/cdebconf/debian/changelog
@@ -1,3 +1,11 @@
+cdebconf (0.126) UNRELEASED; urgency=low
+
+  * Add a new "align" capability to the protocol and to the text, newt and
+    GTK+ frontends.  This currently allows to "columnize" select and
+    multiselect questions by using TAB as a field separator.
+
+ -- Jérémy Bobbio <lunar@debian.org>  Fri, 12 Oct 2007 12:35:11 +0200
+
 cdebconf (0.125) unstable; urgency=low
 
   [ Jérémy Bobbio ]

commit 3bfe15d50a49ab47cde86fb118e9f2125d2a6c6b
Author: Lunar <lunar@selene.tanneries.taz>
Date:   Fri Oct 12 12:46:38 2007 +0200

    Use the "align" capability to display language-name-* templates

diff --git a/packages/localechooser/debian/changelog b/packages/localechooser/debian/changelog
index b631120..e018ed0 100644
--- a/packages/localechooser/debian/changelog
+++ b/packages/localechooser/debian/changelog
@@ -3,6 +3,7 @@ localechooser (1.42) UNRELEASED; urgency=low
   * Since /etc/default/locale is now a conffile provided by locales,
     sed changes into it rather than overwriting. (Fall back to writing to the
     file if necessary.)
+  * Use the "align" capability to display language-name-* templates.
 
  -- Joey Hess <joeyh@debian.org>  Wed, 05 Sep 2007 15:03:07 -0400
 
diff --git a/packages/localechooser/debian/control b/packages/localechooser/debian/control
index fa95237..8679257 100644
--- a/packages/localechooser/debian/control
+++ b/packages/localechooser/debian/control
@@ -10,6 +10,6 @@ Vcs-Svn: svn://svn.debian.org/d-i/trunk/packages/localechooser
 Package: localechooser
 XC-Package-Type: udeb
 Architecture: all
-Depends: cdebconf-udeb, iso-3166-udeb, di-utils (>= 1.15)
+Depends: cdebconf-udeb (>> 0.125), iso-3166-udeb, di-utils (>= 1.15)
 XB-Installer-Menu-Item: 1000
 Description: choose language/country/locale
diff --git a/packages/localechooser/localechooser b/packages/localechooser/localechooser
index 9433e9a..e097cb3 100755
--- a/packages/localechooser/localechooser
+++ b/packages/localechooser/localechooser
@@ -3,7 +3,7 @@ set -e
 
 . /usr/share/debconf/confmodule
 
-db_capb backup
+db_capb backup align
 
 localecode="debian-installer/locale"
 langname_ascii="languagechooser/language-name-ascii"
@@ -314,6 +314,8 @@ fi
 
 # BEGIN COUNTRY SELECTION
 
+db_capb backup
+
 # This is needed later in the script
 COUNTRYCODE_LANGUAGECHOOSER=$COUNTRY
 DEFAULT_COUNTRY=$(code2country $COUNTRY)
diff --git a/packages/localechooser/mktemplates.language b/packages/localechooser/mktemplates.language
index f5bda50..ea6eda4 100755
--- a/packages/localechooser/mktemplates.language
+++ b/packages/localechooser/mktemplates.language
@@ -63,8 +63,7 @@ sub get_translations {
 # Pro : "natural" sorting
 # Con : English looks useless
              $translation = $name .
-                            (" " x (22 - length($name))).
-			    "- $translation";
+			    "\t- $translation";
 # Layout 3 : Translated name
 # Pro : no useless English
 # Con : no sorting....giving a confusing screen

Attachment: signature.asc
Description: Digital signature


Reply to: