aboutsummaryrefslogblamecommitdiffstats
path: root/addressbook/printing/e-contact-print.c
blob: f86d2613b18d27b22e211bbda4dc5f9dc6d9d6e2 (plain) (tree)






























                                                                           
                                
                  



                                                                                


                                                          

                     





                                 
                    

                                  



                                       

  















































































































































































                                                                                                                                           
           
                                                                                                       
 

                                        

                                      













                                                                       


                                 







                                                                                              
     
           
                                                                                                              

                                   

                                                                      

                                   
      




























                                                       




























































                                                                                                                                                                                                              







                                                                             


                                                                                  
                                      
                                                                                                                         

                                                   

                                                                                                                                                                                




                                         




                                                                            


                                                 
                                       

                                                               




                                                                                    















                                                                                                                                
                                                                       
                                
                                                                           



                                                                                                              
         
                                                        






                                                                                  





                                                                                                                    
                                    











                                                                                                                                                                                                                                                                                                                



                                                                           
                                                                                                                    
                                                                                                
                                                                                                       
                                                                                   
















































                                                                                                                        
                         





























































































                                                                                                                                                                                                 

                 
                                                         



                                       
                                                                                           

                                

                          
                                      
                                                                                                                    
                             



                                                                            



                                                                         


                                                                                
                                
                                                                

                                                                                      
                                                               


                                                                                                                                                                                                       


                                                          

                                                                                

                                                    



                                                                                                                                                
                 




                                                                           
         


                                                 





                                            








                                                                                

                      























































                                                                        


                                                



                                                 

                                  
                                       

















                                                                   



                                 

                                                            


                                            
                                                            


                                            
                                             

                                                  
                                                                      









































































                                                                                                



















                                                                                      
                          







                                                                                          
                                


                                          










                                                                                                                                                 













                                                                                          
                                


                                          




                                                                                                                                                 
                




                                                                                                            

























                                                                                                                               
                                                                                     
                                              
                                                                                  

                      
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* 
 * e-contact-print.c
 * Copyright (C) 2000  Helix Code, Inc.
 * Author: Chris Lahey <clahey@helixcode.com>
 *
 * This library 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 2 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 library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include "e-contact-print.h"
#include <libgnomeprint/gnome-print.h>
#include <libgnomeprint/gnome-print-dialog.h>
#include <libgnomeprint/gnome-print-master.h>
#include <libgnomeprint/gnome-print-master-preview.h>
#include <libgnomeprint/gnome-print-multipage.h>
#include <gnome-xml/tree.h>
#include <gnome-xml/parser.h>
#include <gnome-xml/xmlmemory.h>
#include <ctype.h>

#define SCALE 5
#define HYPHEN_PIXELS 20
#define HYPHEN_PENALTY ( (SCALE) * (SCALE) * (HYPHEN_PIXELS) * (HYPHEN_PIXELS) )

typedef struct _EContactPrintContext EContactPrintContext;

static int cardcount;

struct _EContactPrintContext
{
    GnomePrintContext *pc;
    GnomePrintMaster *master;
    gdouble x;
    gdouble y;
    gint column;
    EContactPrintStyle *style;
    gboolean first_section;
    gchar first_char_on_page;
    gchar last_char_on_page;
    GnomeFont *letter_heading_font;
    GnomeFont *letter_tab_font;
};

static gint
e_contact_divide_text(GnomePrintContext *pc, GnomeFont *font, double width, gchar *text, GList **return_val /* Of type char[] */)
{
    if ( width == -1 || gnome_font_get_width_string(font, text) <= width ) {
        if ( return_val ) {
            *return_val = g_list_append(*return_val, g_strdup(text));
        }
        return 1;
    } else {
#if 1
        int i, l;
        double x = 0;
        int lastend = 0;
        int linestart = 0;
        int firstword = 1;
        int linecount = 0;
        l = strlen(text);
        for ( i = 0; i < l; i++ ) {
            if ( text[i] == ' ' ) {
                if ( (!firstword) && x + gnome_font_get_width_string_n(font, text + lastend, i - lastend) > width ) {
                    if (return_val) {
                        *return_val = g_list_append(*return_val, g_strndup(text + linestart, lastend - linestart));
                    }
                    x = gnome_font_get_width_string(font, "    ");
                    linestart = lastend + 1;
                    x += gnome_font_get_width_string_n(font, text + linestart, i - linestart);
                    lastend = i;
                    linecount ++;
                } else {
                    x += gnome_font_get_width_string_n(font, text + lastend, i - lastend);
                    lastend = i;
                }
                firstword = 0;
            } else if ( text[i] == '\n' ) {
                if ( (!firstword) && x + gnome_font_get_width_string_n(font, text + lastend, i - lastend) > width ) {
                    if (return_val) {
                        *return_val = g_list_append(*return_val, g_strndup(text + linestart, lastend - linestart));
                    }
                    linestart = lastend + 1;
                    lastend = i;
                    linecount ++;
                }
                if (return_val) {
                    *return_val = g_list_append(*return_val, g_strndup(text + linestart, i - linestart));
                }
                linestart = i + 1;
                lastend = i + 1;
                linecount ++;
                x = gnome_font_get_width_string(font, "    ");

                firstword = 1;
            }
        }
        if ( (!firstword) && x + gnome_font_get_width_string_n(font, text + lastend, i - lastend) > width ) {
            if (return_val) {
                *return_val = g_list_append(*return_val, g_strndup(text + linestart, lastend - linestart));
            }
            linestart = lastend + 1;
            lastend = i;
            linecount ++;
        }
        if (return_val) {
            *return_val = g_list_append(*return_val, g_strndup(text + linestart, i - linestart));
        }
        linecount ++;
        return(linecount);
#else
        HnjBreak *breaks;
        gint *result;
        gint *is;
        gint n_breaks = 0, n_actual_breaks = 0;
        gint i;
        gint l;
        gchar *hyphenation;
        double x = - gnome_font_get_width_string(font, "    ") * SCALE;
        HnjParams hnjparams;

        hnjparams.set_width = width * SCALE + x;
        hnjparams.max_neg_space = 0;
        hnjparams.tab_width = 0;

        l = strlen(text);
    
        /* find possible line breaks. */
        for (i = 0; i < l; i++) {
            if (text[i] == '-')
                n_breaks++;
            else if (text[i] == ' ')
                n_breaks++;
#if 0
            else if (hyphenation[i] & 1)
                n_breaks++;
#endif
        }

        breaks = g_new( HnjBreak, n_breaks + 1 );
        result = g_new( gint, n_breaks + 1 );
        is = g_new( gint, n_breaks + 1 );
        n_breaks = 0;
        /* find possible line breaks. */
    
        for (i = 0; i < l; i++) {
            if ( text[i] == '-' ) {
                x += gnome_font_get_width(font, text[i]) * SCALE;
                breaks[n_breaks].x0 = x;
                breaks[n_breaks].x1 = x;
                breaks[n_breaks].penalty = HYPHEN_PENALTY;
                breaks[n_breaks].flags = HNJ_JUST_FLAG_ISHYPHEN;
                is[n_breaks] = i + 1;
                n_breaks++;
            } else if ( text[i] == ' ' ) {
                breaks[ n_breaks ].x0 = x;
                x += gnome_font_get_width(font, text[i]) * SCALE;
                breaks[ n_breaks ].x1 = x;
                breaks[ n_breaks ].penalty = 0;
                breaks[ n_breaks ].flags = HNJ_JUST_FLAG_ISSPACE;
                is[ n_breaks ] = i + 1;
                n_breaks++;
#if 0
            } else if (word->hyphenation[i] & 1) {
                breaks[n_breaks].x0 = x + gnome_font_get_width(font, '-') * SCALE;
                breaks[n_breaks].x1 = x;
                breaks[n_breaks].penalty = HYPHEN_PENALTY;
                breaks[n_breaks].flags = HNJ_JUST_FLAG_ISHYPHEN;
                is[n_breaks] = i + 1;
                n_breaks++;
#endif
            } else
                x += gnome_font_get_width(font, text[i]) * SCALE;

        }
        is[n_breaks] = i;
        breaks[n_breaks].flags = 0;
        n_breaks++;

        /* Calculate optimal line breaks. */
        n_actual_breaks = hnj_hs_just (breaks, n_breaks,
                           &hnjparams, result);

        if ( return_val ) {
            gchar *next_val;
            if ( breaks[result[0]].flags == HNJ_JUST_FLAG_ISHYPHEN && text[is[result[0]]] != '-' ) {
                next_val = g_new(gchar, is[result[0]] + 2);
                strncpy(next_val, text, is[result[0]]);
                next_val[is[result[0]]] = 0;
                strcat(next_val, "-");
            } else {
                next_val = g_new(gchar, is[result[0]] + 1);
                strncpy(next_val, text, is[result[0]]);
                next_val[is[result[0]]] = 0;
            }
            *return_val = g_list_append(*return_val, next_val);
            
            for ( i = 1; i < n_actual_breaks; i++ ) {
                if ( (breaks[result[i]].flags & HNJ_JUST_FLAG_ISHYPHEN) && (text[is[result[i]]] != '-') ) {
                    next_val = g_new(gchar, is[result[i]] - is[result[i - 1]] + 2);
                    strncpy(next_val, text + is[result[i - 1]], is[result[i]] - is[result[i - 1]]);
                    next_val[is[result[i]] - is[result[i - 1]]] = 0;
                    strcat(next_val, "-");
                } else {
                    next_val = g_new(gchar, is[result[i]] - is[result[i - 1]] + 1);
                    strncpy(next_val, text + is[result[i - 1]], is[result[i]] - is[result[i - 1]]);
                    next_val[is[result[i]] - is[result[i - 1]]] = 0;
                }
                *return_val = g_list_append(*return_val, next_val);
            }
        }
        
        g_free (breaks);
        g_free (result);
        g_free (is);
        return n_actual_breaks;
#endif
    }
}

static void
e_contact_output(GnomePrintContext *pc, GnomeFont *font, double x, double y, double width, gchar *text)
{
    GList *list = NULL, *list_start;
    int first_line = 1;
    gnome_print_gsave(pc);
    gnome_print_setfont(pc, font);
    e_contact_divide_text(pc, font, width, text, &list);
    for ( list_start = list; list; list = g_list_next(list)) {
        y -= gnome_font_get_ascender(font);
        gnome_print_moveto(pc, x, y);
        gnome_print_show(pc, (char *)list->data);
        y -= gnome_font_get_descender(font);
        y -= .2 * font->size;
        if ( first_line ) {
            x += gnome_font_get_width_string(font, "    ");
            first_line = 0;
        }
    }
    g_list_foreach( list_start, (GFunc) g_free, NULL );
    g_list_free( list_start );
    gnome_print_grestore(pc);
}

static gdouble
e_contact_text_height(GnomePrintContext *pc, GnomeFont *font, double width, gchar *text)
{
    int line_count = e_contact_divide_text(pc, font, width, text, NULL);
    return line_count * (gnome_font_get_ascender(font) + gnome_font_get_descender(font)) +
        line_count * .2 * font->size;
}

#if 0
static void
e_contact_output_and_advance(EContactPrintContext *ctxt, GnomeFont *font, double x, double width, gchar *text)
{
    ctxt->y -= .1 * font->size;
    e_contact_output(ctxt->pc, font, x, ctxt->y, width, text);
    ctxt->y -= e_contact_text_height(ctxt->pc, font, width, text);
    ctxt->y -= .1 * font->size;
}
#endif

static void
e_contact_rectangle(GnomePrintContext *pc, 
           gdouble x0,
           gdouble y0,
           gdouble x1,
           gdouble y1,
           gdouble r,
           gdouble g,
           gdouble b)
{
    gnome_print_gsave(pc);
    gnome_print_setrgbcolor(pc, r, g, b);
    gnome_print_moveto(pc, x0, y0);
    gnome_print_lineto(pc, x1, y0);
    gnome_print_lineto(pc, x1, y1);
    gnome_print_lineto(pc, x0, y1);
    gnome_print_lineto(pc, x0, y0);
    gnome_print_fill(pc);
    gnome_print_grestore(pc);
}

static gchar *e_card_get_string(void *card, gchar *key)
{
    return key;
}

static gchar *e_card_get_string_fileas(void *card)
{
    if (cardcount < 4)
        return "Lahey, Chris";
    else if (cardcount < 20)
        return "Rasputin";
    else if (cardcount < 24)
        return "Wow, this guy has a really long name.  Can you believe it?";
    else
        return "Zamboni";
}

static double
e_contact_get_letter_tab_width (EContactPrintContext *ctxt)
{
    return gnome_font_get_width_string(ctxt->letter_tab_font, "123") + 4 + 18;
}

static double
e_contact_print_letter_tab (EContactPrintContext *ctxt)
{
    char character;
    gdouble x, y;
    gdouble page_width = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble tab_height, tab_width;
    gdouble font_size;
    tab_height = 72 * (ctxt->style->page_height - ctxt->style->top_margin - ctxt->style->bottom_margin) / 27.0;
    font_size = tab_height / 2;
    tab_width = e_contact_get_letter_tab_width(ctxt) - 18;
    x = page_width + 72 * (ctxt->style->left_margin) - tab_width;
    y = 72 * (ctxt->style->page_height - ctxt->style->top_margin);


    gnome_print_gsave( ctxt->pc );
    if ( ctxt->style->print_using_grey )
        e_contact_rectangle( ctxt->pc, x, 72 * (ctxt->style->page_height - ctxt->style->top_margin), x + tab_width, ctxt->style->bottom_margin * 72, .85, .85, .85 );
    for ( character = 'A' - 1; character <= 'Z'; character ++ ) {
        char string[] = "123";
        if ( character >= 'A' ) {
            string[0] = tolower(character);
            string[1] = 0;
        }
        if ( character >= ctxt->first_char_on_page && character <= ctxt->last_char_on_page ) {
            e_contact_rectangle( ctxt->pc, x + 1, y - 1, x + tab_width - 1, y - (tab_height - 1), 0, 0, 0 );
            gnome_print_setrgbcolor( ctxt->pc, 1, 1, 1 );
            e_contact_output( ctxt->pc, ctxt->letter_tab_font, x + tab_width / 2 - gnome_font_get_width_string(ctxt->letter_tab_font, string) / 2, y - (tab_height - font_size) / 2, -1, string );
        } else {
            gnome_print_setrgbcolor( ctxt->pc, 0, 0, 0 );
            e_contact_output( ctxt->pc, ctxt->letter_tab_font, x + tab_width / 2 - gnome_font_get_width_string(ctxt->letter_tab_font, string) / 2, y - (tab_height - font_size) / 2, -1, string );
        }
        y -= tab_height;
    }
    gnome_print_grestore( ctxt->pc );
    return gnome_font_get_width_string(ctxt->style->body_font, "123") + ctxt->style->body_font->size / 5;
}

static double
e_contact_get_letter_heading_height (EContactPrintContext *ctxt)
{
    gdouble ascender, descender;
    ascender = gnome_font_get_ascender(ctxt->letter_heading_font);
    descender = gnome_font_get_descender(ctxt->letter_heading_font);
    return ascender + descender + 9;
}

static void
e_contact_print_letter_heading (EContactPrintContext *ctxt, gchar *character)
{
    gdouble ascender, descender;
    gdouble width;

    width = gnome_font_get_width_string(ctxt->letter_heading_font, "m") * 1.7;
    ascender = gnome_font_get_ascender(ctxt->letter_heading_font);
    descender = gnome_font_get_descender(ctxt->letter_heading_font);
    gnome_print_gsave( ctxt->pc );
    e_contact_rectangle( ctxt->pc, ctxt->x, ctxt->y, ctxt->x + width, ctxt->y - (ascender + descender + 6), 0, 0, 0);
    gnome_print_setrgbcolor(ctxt->pc, 1, 1, 1);
    ctxt->y -= 4;
    e_contact_output(ctxt->pc, ctxt->letter_heading_font, ctxt->x + (width - gnome_font_get_width_string(ctxt->letter_heading_font, character))/ 2, ctxt->y, -1, character);
    ctxt->y -= ascender + descender;
    ctxt->y -= 2;
    ctxt->y -= 3;
    gnome_print_grestore( ctxt->pc );
}

static void
e_contact_start_new_page(EContactPrintContext *ctxt)
{
    ctxt->x = ctxt->style->left_margin * 72;
    ctxt->y = (ctxt->style->page_height - ctxt->style->top_margin) * 72;
    ctxt->column = 0;
    if ( ctxt->style->letter_tabs )
        e_contact_print_letter_tab(ctxt);
    gnome_print_showpage(ctxt->pc);

    ctxt->first_char_on_page = ctxt->last_char_on_page + 1;
}

static double
e_contact_get_card_size(void *card, EContactPrintContext *ctxt, GList *shown_fields)
{
    gdouble height = 0;
    gdouble page_width  = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble column_width;
    if ( ctxt->style->letter_tabs )
        page_width -= e_contact_get_letter_tab_width(ctxt);
    column_width = (page_width + 18) / ctxt->style->num_columns - 18;

    height += ctxt->style->headings_font->size * .2;

    height += ctxt->style->headings_font->size * .2;

    height += e_contact_text_height(ctxt->pc, ctxt->style->headings_font, column_width - 4, e_card_get_string_fileas(card));
    height += ctxt->style->headings_font->size * .2;

    height += ctxt->style->headings_font->size * .2;
    
    for(; shown_fields; shown_fields = g_list_next(shown_fields)) {
        double xoff = 0;
        gchar *field = e_card_get_string(card, shown_fields->data);
        xoff += gnome_font_get_width_string(ctxt->style->body_font, shown_fields->data);
        xoff += gnome_font_get_width_string(ctxt->style->body_font, ":  ");
        height += e_contact_text_height(ctxt->pc, ctxt->style->body_font, column_width - xoff, field);
        height += .2 * ctxt->style->body_font->size;
    }
    height += ctxt->style->headings_font->size * .4;
    return height;
}


static void
e_contact_print_card (void *card, EContactPrintContext *ctxt, GList *shown_fields)
{
    gdouble page_width  = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble column_width;
    if ( ctxt->style->letter_tabs )
        page_width -= e_contact_get_letter_tab_width(ctxt);
    column_width = (page_width + 18) / ctxt->style->num_columns - 18;

    gnome_print_gsave(ctxt->pc);

    ctxt->y -= ctxt->style->headings_font->size * .2;

    ctxt->y -= ctxt->style->headings_font->size * .2;

    if (ctxt->style->print_using_grey)
        e_contact_rectangle(ctxt->pc, ctxt->x, ctxt->y + ctxt->style->headings_font->size * .2, ctxt->x + column_width, ctxt->y - e_contact_text_height(ctxt->pc, ctxt->style->headings_font, column_width - 4, e_card_get_string_fileas(card)) - ctxt->style->headings_font->size * .2, .85, .85, .85);
    e_contact_output(ctxt->pc, ctxt->style->headings_font, ctxt->x + 2, ctxt->y, column_width - 4, e_card_get_string_fileas(card));
    ctxt->y -= e_contact_text_height(ctxt->pc, ctxt->style->headings_font, column_width - 4, e_card_get_string_fileas(card));
    ctxt->y -= ctxt->style->headings_font->size * .2;

    ctxt->y -= ctxt->style->headings_font->size * .2;
    
    for(; shown_fields; shown_fields = g_list_next(shown_fields)) {
        double xoff = 0;
        gchar *field = e_card_get_string(card, shown_fields->data);
        e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, shown_fields->data);
        xoff += gnome_font_get_width_string(ctxt->style->body_font, shown_fields->data);
        e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, ":  ");
        xoff += gnome_font_get_width_string(ctxt->style->body_font, ":  ");
        e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, column_width - xoff, field);
        ctxt->y -= e_contact_text_height(ctxt->pc, ctxt->style->body_font, column_width - xoff, field);
        ctxt->y -= .2 * ctxt->style->body_font->size;
    }
    ctxt->y -= ctxt->style->headings_font->size * .4;
    gnome_print_grestore(ctxt->pc);
}

static void
e_contact_start_new_column (EContactPrintContext *ctxt)
{
    gdouble page_width  = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble column_offset;
    if ( ctxt->style->letter_tabs ) 
        page_width -= e_contact_get_letter_tab_width(ctxt);
    column_offset = (page_width + 18) / ctxt->style->num_columns;
    ctxt->column ++;
    if (ctxt->column >= ctxt->style->num_columns) {
        e_contact_start_new_page(ctxt);
        ctxt->column = 0;
    }
    ctxt->x = (72 * ctxt->style->left_margin) + column_offset * ctxt->column;
    ctxt->y = 72 * (ctxt->style->page_height - ctxt->style->top_margin);
}

static void
e_contact_do_print_cards (void *book, EContactPrintContext *ctxt, GList *shown_fields)
{
    gchar *character = NULL;
    void *card = NULL;
    gboolean first_contact = TRUE;
    gdouble page_width  = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble column_width;
    ctxt->y = (ctxt->style->page_height - ctxt->style->top_margin) * 72;
    ctxt->x = (ctxt->style->left_margin) * 72;
    if ( ctxt->style->letter_tabs ) 
        page_width -= e_contact_get_letter_tab_width(ctxt);
    
    ctxt->first_char_on_page = 'A' - 1;

    column_width = (page_width + 18) / ctxt->style->num_columns - 18;
    /*
    for(card = e_book_get_first(book); card; card = e_book_get_next(book)) {
    */
    for (cardcount=0; cardcount < 30; cardcount++) {
        gchar *file_as = e_card_get_string_fileas(card);
        if ( file_as && (!character || *character != tolower(*file_as)) ) {
            if (ctxt->style->sections_start_new_page && ! first_contact) {
                e_contact_start_new_page(ctxt);
            }
            else if ((!first_contact) && (ctxt->y - e_contact_get_letter_heading_height(ctxt) - e_contact_get_card_size(card, ctxt, shown_fields) < ctxt->style->bottom_margin * 72))
                e_contact_start_new_column(ctxt);
            if (!character)
                character = g_strdup(" ");
            *character = tolower(*file_as);
            if ( ctxt->style->letter_headings )
                e_contact_print_letter_heading(ctxt, character);
            ctxt->first_section = FALSE;
        } 
        else if ( (!first_contact) && (ctxt->y - e_contact_get_card_size(card, ctxt, shown_fields) < ctxt->style->bottom_margin * 72)) {
            e_contact_start_new_column(ctxt);
            if ( ctxt->style->letter_headings )
                e_contact_print_letter_heading(ctxt, character);
        }
        ctxt->last_char_on_page = toupper(*file_as);
        if ( ctxt->last_char_on_page < ctxt->first_char_on_page )
            ctxt->first_char_on_page = ctxt->last_char_on_page;
        e_contact_print_card(card, ctxt, shown_fields);
        first_contact = FALSE;
    }
    ctxt->last_char_on_page = 'Z';
    if ( ctxt->style->letter_tabs )
        e_contact_print_letter_tab(ctxt);
    gnome_print_showpage(ctxt->pc);
    gnome_print_context_close(ctxt->pc);
    g_free(character);
}

static double
e_contact_get_phone_list_size(void *card, EContactPrintContext *ctxt, GList *shown_fields)
{
    double height = 0;

    height += ctxt->style->headings_font->size * .2;

    height += ctxt->style->headings_font->size * .2;
    
    for(; shown_fields; shown_fields = g_list_next(shown_fields)) {
        if ( 1 ) /* field is a phone field. */ {
            gchar *field = e_card_get_string(card, shown_fields->data);
            height += e_contact_text_height(ctxt->pc, ctxt->style->body_font, 100, field);
            height += .2 * ctxt->style->body_font->size;
        }
    }
    height += ctxt->style->headings_font->size * .4;
    return height;
}


static void
e_contact_print_phone_list (void *card, EContactPrintContext *ctxt, GList *shown_fields)
{
    gdouble page_width  = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble column_width;
    double xoff, dotwidth;
    int dotcount;
    char *dots;
    int i;
    if ( ctxt->style->letter_tabs )
        page_width -= e_contact_get_letter_tab_width(ctxt);
    column_width = (page_width + 18) / ctxt->style->num_columns - 18;

    gnome_print_gsave(ctxt->pc);

    ctxt->y -= ctxt->style->headings_font->size * .2;

    ctxt->y -= ctxt->style->headings_font->size * .2;

    e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x, ctxt->y, -1, e_card_get_string_fileas(card));
    
    xoff = column_width - 9 * ctxt->style->body_font->size;
    dotwidth = xoff - 
        gnome_font_get_width_string(ctxt->style->body_font, e_card_get_string_fileas(card)) - 
        gnome_font_get_width_string(ctxt->style->body_font, " ");
    dotcount = dotwidth / gnome_font_get_width(ctxt->style->body_font, '.');
    dots = g_new(gchar, dotcount + 1);
    for (i = 0; i < dotcount; i++)
        dots[i] = '.';
    dots[dotcount] = 0;
    e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff - dotcount * gnome_font_get_width(ctxt->style->body_font, '.'), ctxt->y, -1, dots);
    g_free(dots);
        
    for(; shown_fields; shown_fields = g_list_next(shown_fields)) {
        if ( 1 ) /* field is a phone field. */ {
            gchar *field = e_card_get_string(card, shown_fields->data);
            e_contact_output(ctxt->pc, ctxt->style->body_font, ctxt->x + xoff, ctxt->y, -1, shown_fields->data);
            e_contact_output(ctxt->pc, ctxt->style->body_font, 
                     ctxt->x + column_width - gnome_font_get_width_string(ctxt->style->body_font, 
                                                  field),
                     ctxt->y,
                     -1,
                     field);
            ctxt->y -= e_contact_text_height(ctxt->pc, ctxt->style->body_font, 100, field);
            ctxt->y -= .2 * ctxt->style->body_font->size;
        }
    }
    ctxt->y -= ctxt->style->headings_font->size * .4;
    gnome_print_grestore(ctxt->pc);
}

static void
e_contact_do_print_phone_list (void *book, EContactPrintContext *ctxt, GList *shown_fields)
{
    gchar *character = NULL;
    void *card = NULL;
    int i;
    gboolean first_contact = TRUE;
    gdouble page_width  = 72 * (ctxt->style->page_width - ctxt->style->left_margin - ctxt->style->right_margin);
    gdouble column_width;
    ctxt->y = (ctxt->style->page_height - ctxt->style->top_margin) * 72;
    ctxt->x = (ctxt->style->left_margin) * 72;
    if ( ctxt->style->letter_tabs ) 
        page_width -= e_contact_get_letter_tab_width(ctxt);
    
    ctxt->first_char_on_page = 'A' - 1;

    column_width = (page_width + 18) / ctxt->style->num_columns - 18;
    /*
    for(card = e_book_get_first(book); card; card = e_book_get_next(book)) {
    */
    for (i=0; i < 30; i++) {
        gchar *file_as = e_card_get_string_fileas(card);
        if ( file_as && (!character || *character != tolower(*file_as)) ) {
            if (ctxt->style->sections_start_new_page && ! first_contact) {
                e_contact_start_new_page(ctxt);
            }
            else if ((!first_contact) && (ctxt->y - e_contact_get_letter_heading_height(ctxt) - e_contact_get_phone_list_size(card, ctxt, shown_fields) < ctxt->style->bottom_margin * 72))
                e_contact_start_new_column(ctxt);
            if (!character)
                character = g_strdup(" ");
            *character = tolower(*file_as);
            if ( ctxt->style->letter_headings )
                e_contact_print_letter_heading(ctxt, character);
            ctxt->first_section = FALSE;
        } 
        else if ( (!first_contact) && (ctxt->y - e_contact_get_card_size(card, ctxt, shown_fields) < ctxt->style->bottom_margin * 72)) {
            e_contact_start_new_column(ctxt);
            if ( ctxt->style->letter_headings )
                e_contact_print_letter_heading(ctxt, character);
        }
        ctxt->last_char_on_page = toupper(*file_as);
        if ( ctxt->last_char_on_page < ctxt->first_char_on_page )
            ctxt->first_char_on_page = ctxt->last_char_on_page;
        e_contact_print_phone_list(card, ctxt, shown_fields);
        first_contact = FALSE;
    }
    ctxt->last_char_on_page = 'Z';
    if ( ctxt->style->letter_tabs )
        e_contact_print_letter_tab(ctxt);
    gnome_print_showpage(ctxt->pc);
    gnome_print_context_close(ctxt->pc);
    g_free(character);
}

static void
e_contact_do_print (void *book, EContactPrintContext *ctxt, GList *shown_fields)
{
    switch ( ctxt->style->type ) {
    case E_CONTACT_PRINT_TYPE_CARDS:
        e_contact_do_print_cards( book, ctxt, shown_fields );
        break;
    case E_CONTACT_PRINT_TYPE_PHONE_LIST:
        e_contact_do_print_phone_list( book, ctxt, shown_fields );
        break;
    default:
        break;
    }
}

static void lowify( char *data )
{
    for ( ; *data; data++ )
        *data = tolower(*data);
}

static gboolean get_bool( char *data )
{
    if ( data ) {
        lowify ( data );
        return ! strcmp(data, "true");
    } else
        return FALSE;
}

static void get_string( char *data, char **variable )
{
    g_free ( *variable );
    if ( data )
        *variable = g_strdup( data );
    else
        *variable = g_strdup( "" );
}

static int get_integer( char *data )
{
    if ( data )
        return atoi(data);
    else 
        return 0;
}

static double get_float( char *data )
{
    if ( data )
        return atof(data);
    else 
        return 0;
}

static void get_font( char *data, GnomeFont **variable )
{
    if ( data ) {
        GnomeFont *font = gnome_font_new_from_full_name( data );
        if ( font ) {
            gtk_object_unref( GTK_OBJECT(*variable) );
            *variable = font;
        }
    }
}


static void
e_contact_build_style(EContactPrintStyle *style)
{
    xmlDocPtr styledoc;
    style->title = g_strdup("");
    style->type = E_CONTACT_PRINT_TYPE_CARDS;
    style->sections_start_new_page = TRUE;
    style->num_columns = 2;
    style->blank_forms = 2;
    style->letter_tabs = TRUE;
    style->letter_headings = FALSE;
    style->headings_font = gnome_font_new("Helvetica-Bold", 8);
    style->body_font = gnome_font_new("Helvetica", 6);
    style->print_using_grey = TRUE;
    style->paper_type = 0;
    style->paper_width = 8.5;
    style->paper_height = 11;
    style->paper_source = 0;
    style->top_margin = .5;
    style->left_margin = .5;
    style->bottom_margin = .5;
    style->right_margin = .5;
    style->page_size = 0;
    style->page_width = 2.75;
    style->page_height = 4.25;
#if 0
    style->page_width = 4.25;
    style->page_height = 5.5;
#endif
#if 0
    style->page_width = 5.5;
    style->page_height = 8.5;
#endif
    style->orientation_portrait = FALSE;
    style->header_font = gnome_font_new("Helvetica", 6);
    style->left_header = g_strdup("");
    style->center_header = g_strdup("");
    style->right_header = g_strdup("");
    style->footer_font = gnome_font_new("Helvetica", 6);
    style->left_footer = g_strdup("");
    style->center_footer = g_strdup("");
    style->right_footer = g_strdup("");
    style->reverse_on_even_pages = FALSE;
    styledoc = xmlParseFile("smallbook.ecps");
    if (styledoc) {
        xmlNodePtr stylenode = xmlDocGetRootElement(styledoc);
        xmlNodePtr node;
        for (node = stylenode->childs; node; node = node->next) {
            char *data = xmlNodeGetContent ( node );
            if ( !strcmp( node->name, "title" ) ) {
                get_string(data, &(style->title));
            } else if ( !strcmp( node->name, "type" ) ) {
                lowify( data );
                if ( !strcmp( data, "cards" ) )
                    style->type = E_CONTACT_PRINT_TYPE_CARDS;
                else if ( !strcmp( data, "memo_style" ) )
                    style->type = E_CONTACT_PRINT_TYPE_MEMO_STYLE;
                else if ( !strcmp( data, "phone_list" ) )
                    style->type = E_CONTACT_PRINT_TYPE_PHONE_LIST;
            } else if ( !strcmp( node->name, "sections_start_new_page" ) ) {
                style->sections_start_new_page = get_bool(data);
            } else if ( !strcmp( node->name, "num_columns" ) ) {
                style->num_columns = get_integer(data);
            } else if ( !strcmp( node->name, "blank_forms" ) ) {
                style->blank_forms = get_integer(data);
            } else if ( !strcmp( node->name, "letter_tabs" ) ) {
                style->letter_tabs = get_bool(data);
            } else if ( !strcmp( node->name, "letter_headings" ) ) {
                style->letter_headings = get_bool(data);
            } else if ( !strcmp( node->name, "headings_font" ) ) {
                get_font( data, &(style->headings_font) );
            } else if ( !strcmp( node->name, "body_font" ) ) {
                get_font( data, &(style->body_font) );
            } else if ( !strcmp( node->name, "print_using_grey" ) ) {
                style->print_using_grey = get_bool(data);
            } else if ( !strcmp( node->name, "paper_width" ) ) {
                style->paper_width = get_float(data);
            } else if ( !strcmp( node->name, "paper_height" ) ) {
                style->paper_height = get_float(data);
            } else if ( !strcmp( node->name, "top_margin" ) ) {
                style->top_margin = get_float(data);
            } else if ( !strcmp( node->name, "left_margin" ) ) {
                style->left_margin = get_float(data);
            } else if ( !strcmp( node->name, "bottom_margin" ) ) {
                style->bottom_margin = get_float(data);
            } else if ( !strcmp( node->name, "right_margin" ) ) {
                style->right_margin = get_float(data);
            } else if ( !strcmp( node->name, "page_width" ) ) {
                style->page_width = get_float(data);
            } else if ( !strcmp( node->name, "page_height" ) ) {
                style->page_height = get_float(data);
            } else if ( !strcmp( node->name, "orientation" ) ) {
                if ( data ) {
                    lowify(data);
                    style->orientation_portrait = strcmp(data, "landscape");
                } else {
                    style->orientation_portrait = TRUE;
                }
            } else if ( !strcmp( node->name, "header_font" ) ) {
                get_font( data, &(style->header_font) );
            } else if ( !strcmp( node->name, "left_header" ) ) {
                get_string(data, &(style->left_header));
            } else if ( !strcmp( node->name, "center_header" ) ) {
                get_string(data, &(style->center_header));
            } else if ( !strcmp( node->name, "right_header" ) ) {
                get_string(data, &(style->right_header));
            } else if ( !strcmp( node->name, "footer_font" ) ) {
                get_font( data, &(style->footer_font) );
            } else if ( !strcmp( node->name, "left_footer" ) ) {
                get_string(data, &(style->left_footer));
            } else if ( !strcmp( node->name, "center_footer" ) ) {
                get_string(data, &(style->center_footer));
            } else if ( !strcmp( node->name, "right_footer" ) ) {
                get_string(data, &(style->right_footer));
            } else if ( !strcmp( node->name, "reverse_on_even_pages" ) ) {
                style->reverse_on_even_pages = get_bool(data);
            }
            if ( data )
                xmlFree (data);
        }
        xmlFreeDoc(styledoc);
    }
}

static gint
e_contact_print_close(GnomeDialog *dialog, gpointer data)
{
    return FALSE;
}

static void
e_contact_print_button(GnomeDialog *dialog, gint button, gpointer data)
{
    EContactPrintContext ctxt;
    EContactPrintStyle style;
    GnomePrintMaster *master;
    GtkWidget *preview;
    GnomePrintContext *pc;
    void *book = gtk_object_get_data(GTK_OBJECT(dialog), "book");
    GList *shown_fields = gtk_object_get_data(GTK_OBJECT(dialog), "shown_fields");
    gdouble font_size;
    switch( button ) {
    case GNOME_PRINT_PRINT:
        master = gnome_print_master_new_from_dialog( GNOME_PRINT_DIALOG(dialog) );
        pc = gnome_print_master_get_context( master );
        e_contact_build_style(&style);
        
        ctxt.x = 0;
        ctxt.y = 0;
        ctxt.column = 0;
        ctxt.style = &style;
        ctxt.master = master;
        ctxt.first_section = TRUE;
        ctxt.first_char_on_page = 'A' - 1;  

        font_size = 72 * ctxt.style->page_height / 27.0 / 2.0;
        ctxt.letter_heading_font = gnome_font_new(gnome_font_get_name(ctxt.style->headings_font), ctxt.style->headings_font->size * 1.5);
        ctxt.letter_tab_font = gnome_font_new(gnome_font_get_name(ctxt.style->headings_font), font_size);
    
        ctxt.pc = GNOME_PRINT_CONTEXT(gnome_print_multipage_new_from_sizes(pc, 
                                           72 * style.paper_width, 
                                           72 * style.paper_height,
                                           72 * style.page_width,
                                           72 * style.page_height));
        
        e_contact_do_print(book, &ctxt, shown_fields);
        gnome_print_master_print(master);
        gtk_object_unref(GTK_OBJECT(ctxt.pc));
        gtk_object_unref(GTK_OBJECT(master));
        gnome_dialog_close(dialog);
        break;
    case GNOME_PRINT_PREVIEW:
        master = gnome_print_master_new_from_dialog( GNOME_PRINT_DIALOG(dialog) );
        pc = gnome_print_master_get_context( master );
        e_contact_build_style(&style);
        
        ctxt.x = 0;
        ctxt.y = 0;
        ctxt.column = 0;
        ctxt.style = &style;
        ctxt.master = master;
        ctxt.first_section = TRUE;
        ctxt.first_char_on_page = 'A' - 1;

        font_size = 72 * ctxt.style->page_height / 27.0 / 2.0;
        ctxt.letter_heading_font = gnome_font_new(gnome_font_get_name(ctxt.style->headings_font), ctxt.style->headings_font->size * 1.5);
        ctxt.letter_tab_font = gnome_font_new(gnome_font_get_name(ctxt.style->headings_font), font_size);
        
        ctxt.pc = GNOME_PRINT_CONTEXT(gnome_print_multipage_new_from_sizes(pc, 
                                           72 * style.paper_width, 
                                           72 * style.paper_height,
                                           72 * style.page_width,
                                           72 * style.page_height));
        
        e_contact_do_print(book, &ctxt, shown_fields);
        preview = GTK_WIDGET(gnome_print_master_preview_new(master, "Print Preview"));
        gtk_widget_show_all(preview);
        gtk_object_unref(GTK_OBJECT(ctxt.pc));
        gtk_object_unref(GTK_OBJECT(master));
        break;
    case GNOME_PRINT_CANCEL:
        gnome_dialog_close(dialog);
        break;
    }
}

GtkWidget *
e_contact_print_dialog_new(void *book, GList *shown_fields)
{
    GtkWidget *dialog;
    
    
    dialog = gnome_print_dialog_new("Print cards", GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES);
    gnome_print_dialog_construct_range_any(GNOME_PRINT_DIALOG(dialog), GNOME_PRINT_RANGE_ALL | GNOME_PRINT_RANGE_SELECTION,
                           NULL, NULL, NULL);

    gtk_object_set_data(GTK_OBJECT(dialog), "book", book);
    gtk_object_set_data(GTK_OBJECT(dialog), "shown_fields", shown_fields);
    gtk_signal_connect(GTK_OBJECT(dialog),
               "clicked", GTK_SIGNAL_FUNC(e_contact_print_button), NULL);
    gtk_signal_connect(GTK_OBJECT(dialog),
               "close", GTK_SIGNAL_FUNC(e_contact_print_close), NULL);
    return dialog;
}