Logo Search packages:      
Sourcecode: yank version File versions  Download package

callbacks.c

/*
 * callbacks.c
 */

/*
 * yank  -  yet another NoteKeeper
 * Copyright (C) 1999, 2000, 2001 Michael Hu▀mann <m.hussmann@home.ins.de>
 *
 * 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 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 program; if not, write to the  Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "callbacks.h"

#include <gnome-xml/tree.h>
#include <gnome-xml/parser.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>

#include "app.h"
#include "daycalc.h"
#include "fileio.h"
#include "preferences.h"
#include "time_label.h"
#include "todolist.h"
#include "util.h"
#ifdef USE_GLADE_NOTES
#include "gdd_notes.h"
#endif /* USE_GLADE_NOTES */

/* external vars */
extern GtkWidget *title_entry;
extern GtkWidget *user_entry;
extern GtkWidget *text_entry;
extern GtkWidget *note_tree;
extern GtkWidget *b_ok;
extern GtkWidget *b_apply;
extern GtkWidget *b_cancel;
extern GtkWidget *pix_text_xpm;
extern GtkWidget *pix_box_xpm;
extern GtkWidget *pix_box2_xpm;
extern GtkWidget *pix_circle_xpm;
extern GtkWidget *pix_circle2_xpm;
extern GtkWidget *todolist;

typedef struct{
      GtkAdjustment*   used_days_adjust;
      GtkAdjustment*   estm_days_adjust;
      GtkAdjustment*   complete_adjust;
} adjustments;




/* type of current note we're dealing with */
static _notetype    notetype = None;

/* what should we do with the note? */
_editmode           editmode = NoMode;

/* selected node in the ctree on the left  -- for inserts */
GtkCTreeNode        *selected_node = NULL;

/* current opened node -- for edits */
static GtkCTreeNode *opened_node = NULL;

/* changed-data flag -- any notes modified since last save */
gint                modified = FALSE;

/* commit flag -- whether current opened node has uncommitted changes */
static gint         uncommitted = FALSE;

/* tree structure for cut, copy, paste operations on the tree widget */
GNode               *edit_tree = NULL;

/* flag toggled from cut, copy */
gboolean            edit_tree_free = FALSE;

#define YANK_HOMEPAGE "http://home.ins.de/~m.hussmann/software/yank/"

/*
 * prototypes
 */

gint calc_completion_status(GtkCTree *, GtkCTreeNode *);

/* ------------------------------------------------------ */
/*
 * about message
 */

void
cb_about(GtkWidget* widget, gpointer data)
{
    static GtkWidget *dialog = NULL;
    GtkWidget        *app;
    
    app = (GtkWidget*) data;
    
    if (dialog != NULL)
    {
        g_assert(GTK_WIDGET_REALIZED(dialog));
        gdk_window_show(dialog->window);
        gdk_window_raise(dialog->window);
    }
    else
    {
        const gchar *authors[] =
        {
            "Michael Hu▀mann <m.hussmann@home.ins.de>",
          "Thomas Schultz <tststs@gmx.de>",
            NULL
        };

        dialog = gnome_about_new (_(PACKAGE), VERSION,
                                  "(C) 1999, 2000, 2001 Michael Hu▀mann",
                                  authors, N_("yet another NoteKeeper - \
compiled: "__DATE__" "__TIME__"\n"YANK_HOMEPAGE""), "yank.png");
        gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
                           GTK_SIGNAL_FUNC(gtk_widget_destroyed), &dialog);
        
        gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(app));
        
        gtk_widget_show(dialog);
    }
}

/* ------------------------------------------------------ */
/*
 * exit with check
 */

void
cb_exit(GtkWidget *widget, gpointer data)
{
    static GtkWidget *dialog = NULL;
    gint             sel;
    yank_preferences *pref;
    
    /*
     * there's an error hidden here
     */

    ask_commit_changes();

    pref = get_preferences();

    if (pref->save_yank_geometry)
    {
#ifdef USE_GCONF
        GConfClient *client;

        client = pref_gconfclient();
        gconf_client_set_int(client, "/apps/yank/global/yank_height",
                             GTK_WIDGET(yank_root_win(NULL))->allocation.height,
                             NULL);
        gconf_client_set_int(client, "/apps/yank/global/yank_width",
                             GTK_WIDGET(yank_root_win(NULL))->allocation.width,
                             NULL);
        gconf_client_set_int(client, "/apps/yank/global/note_tree_width",
                             note_tree->parent->allocation.width, NULL);
        gconf_client_suggest_sync(client, NULL);

#else  /* USE_GCONF */
        gnome_config_push_prefix("/yank/Global/");
        gnome_config_set_int("yank height", GTK_WIDGET(yank_root_win(NULL))
                             ->allocation.height);
        gnome_config_set_int("yank width", GTK_WIDGET(yank_root_win(NULL))
                             ->allocation.width);
        gnome_config_set_int("note tree width",
                             note_tree->parent->allocation.width);
        gnome_config_pop_prefix();
        gnome_config_sync();
#endif /* USE_GCONF */
    }
    
    if (modified)
    {
        if (pref->auto_save_on_exit && get_filename())
        {
            cb_save_file(NULL, NULL);
        }
        
        if (dialog == NULL)
        {
            dialog = gnome_message_box_new(
                _("Notes modified. Do you want to save them?"),
                GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES,
                GNOME_STOCK_BUTTON_NO, GNOME_STOCK_BUTTON_CANCEL, NULL);
            gnome_dialog_set_default(GNOME_DIALOG(dialog), 2);
            gnome_dialog_set_parent(GNOME_DIALOG(dialog), yank_root_win(NULL));
            sel = gnome_dialog_run_and_close(GNOME_DIALOG(dialog));
            dialog = NULL;
            switch (sel)
            {
            case 0:
                cb_save_file(NULL, NULL);
                break;
            case 1:
            yank_app_exit((GtkWidget *) data);
                break;
            default:
                return;
                /* notreached */
                break;
            };
        }
        else
        {
            g_assert(GTK_WIDGET_REALIZED(dialog));
            gdk_window_show(dialog->window);
            gdk_window_raise(dialog->window);
          yank_app_exit((GtkWidget *) data);
        }
    }
    else
    {
      yank_app_exit((GtkWidget *) data);
    }
}

/* ------------------------------------------------------ */
/*
 * start adding a new text-note
 */

void
cb_new_text(GtkWidget *widget, gpointer data)
{
    prepare_add(TextNote, NULL);
}

/* ------------------------------------------------------ */
/*
 * start adding a new check-note
 */

void
cb_new_check(GtkWidget *widget, gpointer data)
{
    prepare_add(CheckNote, NULL);
}

/* ------------------------------------------------------ */
/*
 * start adding a new todo-note
 */

void
cb_new_todo(GtkWidget *widget, gpointer data)
{
    prepare_add(TodoNote, NULL);
}

/* ------------------------------------------------------ */
/*
 * generic stuff when starting to add a note
 */

void
prepare_add(_notetype typ,
            GtkWidget *widget)
{
    ask_commit_changes();
    notetype = typ;
    editmode = Add;
#ifdef USE_GLADE_NOTES
    if (typ == Testing)
    {
        gdd_notes_clear_gui(widget);
    }
#endif /* USE_GLADE_NOTES */
    clear_text_page(TRUE, &uncommitted);
    view_note_as(notetype, widget);
    gtk_widget_set_sensitive(b_ok, TRUE);
    gtk_widget_set_sensitive(b_apply, FALSE);
    gtk_widget_set_sensitive(b_cancel, TRUE);
    gtk_widget_grab_focus(title_entry);
    show_text_tab();
}

/* ------------------------------------------------------ */
/*
 * OK-button in the note has been clicked
 */

void
cb_b_ok(GtkWidget* widget, gpointer data)
{
    gint ret;
    
    if (notetype == TextNote || notetype == CheckNote || notetype == TodoNote
#ifdef USE_GLADE_NOTES
        || notetype == Testing
#endif /* USE_GLADE_NOTES */
        )
    {
        ret = ok_note();
        if (ret)
        {
            gnome_warning_dialog_parented(
                _("cb_b_ok(); Note has not been added!"), yank_root_win(NULL));
        }
    }
    else
    {
        g_warning(
            _("cb_b_ok(); You shouldn't see this warning - please report."));
    }
}

/* ------------------------------------------------------ */
/*
 * apply-button in the note has been clicked
 */

void
cb_b_apply(GtkWidget* widget, gpointer data)
{
    gint ret;
    
    if (notetype == TextNote || notetype == CheckNote || notetype == TodoNote
#ifdef USE_GLADE_NOTES
        || notetype == Testing
#endif /* USE_GLADE_NOTES */
        )
    {
        ret = apply_note();
        gtk_widget_grab_focus(title_entry);
        if (ret)
        {
            gnome_warning_dialog_parented(
                _("cb_b_apply(); Note has not been added!"),
                yank_root_win(NULL));
        }
    }
    else
    {
        g_warning(
            _("cb_b_apply(); You shouldn't see this warning - please report.")
            );
    }
}

/* ------------------------------------------------------ */
/*
 * cancel-button in the note has been clicked
 */

void
cb_b_cancel(GtkWidget* widget, gpointer data)
{
    editmode = NoMode;
    show_todo_tab();
    notetype = None;
}

/* ------------------------------------------------------ */
/*
 * add/ edit a note
 */

gint
apply_note(void)
{
    note_data *note;

    note = fill_note_data_from_page(notetype);
    if (note == NULL)
    {
        return (1);
        /* notreached */
    }
    if (editmode == Add)
    {
        note->id = create_note_id();
        opened_node = do_add_note(note, selected_node);
      editmode = Edit;
    }
    else
    {
        if (editmode == Edit)
        {
            do_edit_note(note, opened_node);
        }
    }
    uncommitted = FALSE;
    gtk_widget_set_sensitive(b_apply, FALSE);
    return (0);
}

/* ------------------------------------------------------ */
/*
 * 'OK' callback
 */

gint
ok_note(void)
{
    gint ret;
    
    if (uncommitted)
    {
        ret = apply_note();
    }
    else
    {
        ret = 0;
    }
    if (ret)
    {
        gnome_warning_dialog_parented(_("Note has not been added!"),
                                      yank_root_win(NULL));
    }        
    show_todo_tab();
    if (selected_node != NULL)
    {
        gtk_ctree_unselect(GTK_CTREE(note_tree), selected_node);
    }
    gtk_window_set_focus(yank_root_win(NULL), note_tree);
    notetype = None;
    return (ret);
}

/* ------------------------------------------------------ */
/*
 * somebody has clicked into the note_tree 
 */

void
note_tree_row_selected(GtkCTree *tree, GtkCTreeNode *node, gint col,
                       gpointer gpo)
{
    note_data *note;

    gtk_signal_handler_block_by_func(GTK_OBJECT(note_tree),
                                     GTK_SIGNAL_FUNC(note_tree_row_selected),
                                     NULL);
    ask_commit_changes();
    gtk_signal_handler_unblock_by_func(GTK_OBJECT(note_tree),
                                       GTK_SIGNAL_FUNC(note_tree_row_selected),
                                       NULL);

    selected_node = node;
    opened_node = node;
    clear_text_page(FALSE, &uncommitted);
    note = (note_data *)gtk_ctree_node_get_row_data(GTK_CTREE(note_tree),
                                                    selected_node);
    if (note != NULL)
    {
        GtkWidget *dialog;
        
        notetype = note->notetype;
        dialog = NULL;
#ifdef USE_GLADE_NOTES
        if (notetype == Testing)
        {
            dialog = ((gdd_note *)note->user)->widget;
        }
#endif /* USE_GLADE_NOTES */
        view_note_as(note->notetype, dialog);
        fill_page_from_note_data(note);
      gtk_widget_set_sensitive(b_ok, TRUE);
        gtk_widget_set_sensitive(b_apply, FALSE);
        gtk_widget_set_sensitive(b_cancel, TRUE);
      uncommitted = FALSE;
        editmode = Edit;
        show_text_tab();

        display_tree_path(tree, selected_node);
    }
    else
    {
        gnome_warning_dialog_parented(_("Critical error: Note without data!"),
                                      yank_root_win(NULL));
    }
}

/* ------------------------------------------------------ */
/*
 * somebody has unselected an item in the note_tree
 */

void
note_tree_row_unselected(GtkCTree *tree, GtkCTreeNode *node, gint col)
{
    /*
     * note_tree_row_selected has to be called _after_ ask_commit_changes
     */
    
    gtk_signal_handler_block_by_func(GTK_OBJECT(note_tree),
                                     GTK_SIGNAL_FUNC(note_tree_row_selected),
                                     NULL);
    ask_commit_changes();
    gtk_signal_handler_unblock_by_func(GTK_OBJECT(note_tree),
                                       GTK_SIGNAL_FUNC(note_tree_row_selected),
                                       NULL);
    if (get_preferences()->display_tree_path != 0)
    {
        set_status_text("");
    }
    selected_node = NULL;
    opened_node = NULL;
    show_todo_tab();
}


/* ------------------------------------------------------ */
/*
 * the note has been changed
 */

void
note_changed(void)
{
    uncommitted = TRUE;
    gtk_widget_set_sensitive(b_apply, TRUE);
}


/* ------------------------------------------------------ */
/*
 * got the delete-event from wm
 */

gint
cb_delete_event(GtkWidget* window, GdkEventAny* e, gpointer data)
{
    cb_exit(NULL, NULL);
    return (TRUE);
}

/* ------------------------------------------------------ */
/*
 * add a note to the tree
 */

GtkCTreeNode *
do_add_note(note_data *note, GtkCTreeNode *parent)
{
    gchar        *title[] = { NULL, NULL};
    GtkWidget    *icon;
    GtkCTreeNode *n_node;

    icon = choose_note_icon(note);
    title[0] = note->title;
    if (get_preferences()->no_icons_in_tree || icon == NULL)
    {
        n_node = gtk_ctree_insert_node(GTK_CTREE(note_tree), parent, NULL,
                                       title, 2, NULL, NULL, NULL, NULL, 
                                       FALSE, TRUE);
    }
    else
    {
        n_node = gtk_ctree_insert_node(GTK_CTREE(note_tree), parent,
                                       NULL, title, 2,
                                       GNOME_PIXMAP(icon)->pixmap,
                                       GNOME_PIXMAP(icon)->mask,
                                       GNOME_PIXMAP(icon)->pixmap,
                                       GNOME_PIXMAP(icon)->mask,
                                       FALSE, TRUE);
    }
    gtk_ctree_node_set_row_data(GTK_CTREE(note_tree), n_node, note);

    /*
     * update todolist
     */
    
    if (note->notetype == TodoNote && note->todo == 0)
    {
        add_todo_item(note);
    }

    if (get_preferences()->recursive_completion && parent != NULL)
    {
        tree_recursive_completion(GTK_CTREE(note_tree), parent);
    }
    
    modified = TRUE;
    
    return (n_node);
}

/* ------------------------------------------------------ */
/*
 * edit a note
 */

void
do_edit_note(note_data *n_note, GtkCTreeNode *node)
{
    static note_data *o_note;
    GtkWidget        *icon;
    gchar            *text;
    guint8           spacing;
    GdkPixmap        *pixmap_closed;
    GdkBitmap        *mask_closed;
    GdkPixmap        *pixmap_opened;
    GdkBitmap        *mask_opened;
    gboolean         is_leaf;
    gboolean         expanded;

    o_note = (note_data *) gtk_ctree_node_get_row_data(GTK_CTREE(note_tree),
                                                       GTK_CTREE_NODE(node));
    if (o_note != NULL)
    {
        /*
         * update todolist
         */
        
        if (n_note->notetype == TodoNote && n_note->todo == 1)
        {
            if (gtk_clist_find_row_from_data(GTK_CLIST(todolist), o_note)
                != -1)
            {
                delete_todo_item(o_note, TRUE);
            }
        }
        if (n_note->notetype == TodoNote && n_note->todo == 0)
        {
            edit_todo_item(o_note, n_note);
        }

        /*
         * update tree
         */
        
        icon = choose_note_icon(n_note);
        gtk_ctree_get_node_info(GTK_CTREE(note_tree),
                                GTK_CTREE_NODE(node), &text,
                                &spacing, &pixmap_closed, &mask_closed,
                                &pixmap_opened, &mask_opened, &is_leaf,
                                &expanded);
        if (get_preferences()->no_icons_in_tree || icon == NULL)
        {
            gtk_ctree_set_node_info(GTK_CTREE(note_tree),
                                    GTK_CTREE_NODE(node), n_note->title,
                                    2, NULL, NULL, NULL, NULL, 0, expanded);
        }
        else
        {
            gtk_ctree_set_node_info(GTK_CTREE(note_tree),
                                    GTK_CTREE_NODE(node), n_note->title,
                                    2, GNOME_PIXMAP(icon)->pixmap,
                                    GNOME_PIXMAP(icon)->mask,
                                    GNOME_PIXMAP(icon)->pixmap,
                                    GNOME_PIXMAP(icon)->mask, 0, expanded);
        }
        gtk_ctree_node_set_row_data(GTK_CTREE(note_tree), node, n_note);
        gtk_widget_queue_draw(note_tree);
        modified = TRUE;
        free_note(o_note);

        if (get_preferences()->recursive_completion &&
            GTK_CTREE_ROW(node)->parent != NULL)
        {
            tree_recursive_completion(GTK_CTREE(note_tree),
                                      GTK_CTREE_ROW(node)->parent);
        }
    }
    else
    {
        gnome_warning_dialog_parented(_("Trying to edit NULL note!"),
                                      yank_root_win(NULL));
    }
}

/* ------------------------------------------------------ */
/*
 * select an icon for a note
 */

GtkWidget *
choose_note_icon(note_data *note)
{
    GtkWidget *icon;
    
    switch (note->notetype)
    {
    case TextNote:
        icon = pix_text_xpm;
        break;
    case CheckNote:
        icon = note->todo ? pix_circle2_xpm : pix_circle_xpm;
        break;
    case TodoNote:
        icon = note->todo ? pix_box2_xpm : pix_box_xpm;
        break;
#ifdef USE_GLADE_NOTES
    case Testing:
        icon = gdd_notes_choose_icon(note);
        break;
#endif /* USE_GLADE_NOTES */
    default:
        icon = NULL;
        break;
    };
    return (icon);
}

/* ------------------------------------------------------ */
/*
 * remove note from mem
 */

void
free_note(note_data *data)
{
    if (data)
    {
        if (data->id)
        {
            free(data->id);
        }
        if (data->title)
        {
            free(data->title);
        }
        if (data->user)
        {
#ifdef USE_GLADE_NOTES
            if (data->notetype != Testing)
            {
                free(data->user);
            }
#else            
            free(data->user);
#endif /* USE_GLADE_NOTES */
        }
        if (data->text)
        {
#ifdef USE_GLADE_NOTES
            if (data->notetype != Testing)
            {
                free(data->text);
            }
            else
            {
                xmlFreeNode((xmlNodePtr) data->text);
            }
#else            
            free(data->text);
#endif /* USE_GLADE_NOTES */
        }
        free(data);
    }
}

/* ------------------------------------------------------ */
/*
 * double-click or space will open a note from the todo-list
 */

void
cb_todo_row_selected(GtkCList *list, gint row, gint col, GdkEvent *evt)
{
    note_data    *note;
    GtkCTreeNode *tnode;
    
    note = (note_data *)gtk_clist_get_row_data(GTK_CLIST(list), row);
    if (note == NULL)
    {
        gnome_warning_dialog_parented(_("Trying to select a NULL note!"),
                                      yank_root_win(NULL));
        return;
        /* notreached */
    }
    
    tnode = gtk_ctree_find_by_row_data(GTK_CTREE(note_tree), NULL, note);

    display_tree_path(GTK_CTREE(note_tree), tnode);
    
    if (((evt != NULL) && (evt->type == GDK_2BUTTON_PRESS))
        || (evt == NULL))
    {
        clear_text_page(FALSE, &uncommitted);
        if (tnode != NULL)
        {
            gtk_clist_freeze(GTK_CLIST(note_tree));
            gtk_ctree_unselect_recursive(GTK_CTREE(note_tree), NULL);
            gtk_ctree_select(GTK_CTREE(note_tree), tnode);
            gtk_clist_thaw(GTK_CLIST(note_tree));    
        }
    }
}

/* ------------------------------------------------------ */
/*
 * a todo-list column-title has been clicked
 */

void
cb_todo_col_selected(GtkCList *list, gint col)
{
   sort_by_sorting_mode(col + 1); /* sorting mode 0 means "no sorting" */
}

/* ------------------------------------------------------ */
/*
 * the todo list needs to be refreshed
 */

gint
cb_todo_timeout(gpointer p)
{
    time_t cur_time_t;
    struct tm *cur_time_tm;
    gint32 timeouttime;
    
    set_todolist_colors(); /* do the actual work */
    
    /* install a new timeout and stop this one */
    time(&cur_time_t);
    cur_time_tm = localtime(&cur_time_t);
    
    timeouttime = ((23 - cur_time_tm->tm_hour) * 3600000 +
               (59 - cur_time_tm->tm_min)  *   60000 +
               (60 - cur_time_tm->tm_sec)  *    1000);
    if (timeouttime <= 0) /* leap second */
      timeouttime = 1000;
    gtk_timeout_add(timeouttime, cb_todo_timeout, NULL);
    
    return FALSE;
}

/* ------------------------------------------------------ */
/*
 * sort the todolist by date
 */

void
cb_sort_todo_date(GtkWidget *w, gpointer p)
{
    sort_by_sorting_mode(1);
}

/* ------------------------------------------------------ */
/*
 * sort the todolist by priority
 */

void
cb_sort_todo_prio(GtkWidget *w, gpointer p)
{
    sort_by_sorting_mode(2);
}

/* ------------------------------------------------------ */
/*
 * sort the todolist by completion status
 */

void
cb_sort_todo_complete(GtkWidget *w, gpointer p)
{
    sort_by_sorting_mode(3);
}


/* ------------------------------------------------------ */
/*
 * sort the todolist by title
 */

void
cb_sort_todo_title(GtkWidget *w, gpointer p)
{
    sort_by_sorting_mode(4);
}

/* ------------------------------------------------------ */
/*
 * sort the todolist by user
 */
void
cb_sort_todo_user(GtkWidget *w, gpointer p)
{

    sort_by_sorting_mode(5);
}

/* ------------------------------------------------------ */
/*
 * sort the todolist by date, then priority
 */

void
cb_sort_todo_date_then_prio(GtkWidget *w, gpointer p)
{
    sort_by_sorting_mode(6);
}

/* ------------------------------------------------------ */
/*
 * sort the todolist by priority, then date
 */

void
cb_sort_todo_prio_then_date(GtkWidget *w, gpointer p)
{
    sort_by_sorting_mode(7);
}

/* ------------------------------------------------------ */
/*
 * proxy func
 */

void
cb_modify_text(GtkWidget *w, gpointer p)
{
    modify_selection(TextNote, GTK_CLIST(note_tree)->selection);
}

/* ------------------------------------------------------ */
/*
 * proxy func
 */

void
cb_modify_check(GtkWidget *w, gpointer p)
{
    modify_selection(CheckNote, GTK_CLIST(note_tree)->selection);
}

/* ------------------------------------------------------ */
/*
 * proxy func
 */

void
cb_modify_todo(GtkWidget *w, gpointer p)
{
    modify_selection(TodoNote, GTK_CLIST(note_tree)->selection);
}

/* ------------------------------------------------------ */
/*
 * general proxy
 */

void
modify_selection(_notetype t_type, GList *selection)
{
    GList *sel;

    if (selection == NULL)
    {
        gnome_ok_dialog_parented(_("Select a note first!"),
                                 yank_root_win(NULL));
        return;
        /* notreached */
    }
    
    for (sel = selection; sel != NULL; sel = g_list_next(sel))
    {
        modify_note(t_type, GTK_CTREE_NODE(sel->data));
    }
}

/* ------------------------------------------------------ */
/*
 * change a notes type
 */

void
modify_note(_notetype t_type, GtkCTreeNode *node)
{
    note_data *data;
    GtkWidget *icon;
    gchar     *text;
    guint8    spacing;
    GdkPixmap *pixmap_closed;
    GdkBitmap *mask_closed;
    GdkPixmap *pixmap_opened;
    GdkBitmap *mask_opened;
    gboolean  is_leaf;
    gboolean  expanded;

    if (node == NULL)
    {
        gnome_ok_dialog_parented(_("Select a note first!"),
                                 yank_root_win(NULL));
        return;
        /* notreached */
    }
    
    data = (note_data *) gtk_ctree_node_get_row_data(GTK_CTREE(note_tree),
                                                     GTK_CTREE_NODE(node));

    if (data)
    {
        data->changes++;
        data->changed = time(NULL);
        
        /*
         * update the todo-list
         */

        if (t_type == TodoNote && data->deadline == 0)
        {
            data->deadline = time(NULL);
        }

        if (t_type == TodoNote && data->todo == 0)
        {
            add_todo_item(data);
        }
        if (data->notetype == TodoNote && data->todo == 0)
        {
            delete_todo_item(data, TRUE);
        }
        
        data->notetype = t_type;
        
        modified = TRUE;

        /*
         * update the tree
         */
        
        icon = choose_note_icon(data);
        gtk_ctree_get_node_info(GTK_CTREE(note_tree), GTK_CTREE_NODE(node),
                                &text, &spacing, &pixmap_closed, &mask_closed,
                                &pixmap_opened, &mask_opened, &is_leaf,
                                &expanded);
        if (get_preferences()->no_icons_in_tree)
        {
            gtk_ctree_set_node_info(GTK_CTREE(note_tree), GTK_CTREE_NODE(node),
                                    data->title, 2, NULL, NULL, NULL, NULL, 0,
                                    expanded);
        }
        else
        {
            gtk_ctree_set_node_info(GTK_CTREE(note_tree), GTK_CTREE_NODE(node),
                                    data->title, 2, GNOME_PIXMAP(icon)->pixmap,
                                    GNOME_PIXMAP(icon)->mask,
                                    GNOME_PIXMAP(icon)->pixmap,
                                    GNOME_PIXMAP(icon)->mask, 0, expanded);
        }
        show_todo_tab();
    }
    else
    {
        gnome_warning_dialog_parented(_("Trying to modify NULL note!"),
                                      yank_root_win(NULL));
    }
}

/* ------------------------------------------------------ */
/*
 * drop-request on the text-entry
 */

void
cb_text_entry_drop(GtkWidget *entry, GdkDragContext *context, gint x, gint y,
                   GtkSelectionData *selection_data, guint info, guint time)
{
    GList *names;

    names = gnome_uri_list_extract_filenames((char *)selection_data->data);
    while (names)
    {
        txt_append_file(GTK_TEXT(entry), (gchar *)names->data);
        names = names->next;
    }
    note_changed();
}

/* ------------------------------------------------------ */
/*
 * drop-request on the todo-list
 */

void
cb_todo_list_drop(GtkWidget *todo, GdkDragContext *context, gint x, gint y,
                  GtkSelectionData *selection_data, guint info, guint time)
{
    GList     *names;
    note_data *note;
    
    names = gnome_uri_list_extract_filenames((char *)selection_data->data);
    while (names)
    {
        note = make_note_from_file((gchar *)names->data);
        do_add_note(note, selected_node);
        names = names->next;
    }
    modified = TRUE;
}

/* ------------------------------------------------------ */
/*
 * drop-request on the note-tree
 */

void
cb_note_tree_drop(GtkWidget *tree, GdkDragContext *context, gint x, gint y,
                  GtkSelectionData *selection_data, guint info, guint time)
{
    GList *names;
    
    names = gnome_uri_list_extract_filenames((char *)selection_data->data);
    while (names)
    {
        load_notes_from_cli((gchar *)names->data, GTK_CTREE(tree),
                            selected_node);
        names = names->next;
    }
    modified = TRUE;
}

/* ------------------------------------------------------ */
/*
 * activate-signal from title_entry, text_entry
 */

void
cb_finished_note(GtkWidget *w, gpointer p)
{
    if (GTK_WIDGET_IS_SENSITIVE(b_ok))
    {
        gtk_widget_grab_focus(b_ok);
    }
    else
    {
        gtk_widget_grab_focus(b_cancel);
    }
}

/* ------------------------------------------------------ */
/*
 * unselect row in tree to make adding new trees more easy
 */

void
cb_note_tree_col_selected(GtkCList *l, gint i)
{
    if (l->selection != NULL)
    {        
        gtk_clist_unselect_all(l);
    }
}

/* ------------------------------------------------------ */
/*
 * a row in note_tree was moved
 */

void
cb_note_tree_reordered(GtkWidget *tree, GdkDragContext *context, gint x,
        gint y, GtkSelectionData *selection_data, guint info, guint time)
{
    modified = TRUE;
}

/* ------------------------------------------------------ */
/*
 * proxy func
 */

void
cb_todo_modify_text(GtkWidget *w, gpointer p)
{
    modify_note(TextNote, tree_node_from_todo_selection());
}

/* ------------------------------------------------------ */
/*
 * proxy func
 */

void
cb_todo_modify_check(GtkWidget *w, gpointer p)
{
    modify_note(CheckNote, tree_node_from_todo_selection());
}

/* ------------------------------------------------------ */
/*
 * proxy func
 */

void
cb_todo_modify_todo(GtkWidget *w, gpointer p)
{
    modify_note(TodoNote, tree_node_from_todo_selection());
}

/* ------------------------------------------------------ */
/*
 * return the correspoding tree-node from the todolist
 */

GtkCTreeNode *
tree_node_from_todo_selection(void)
{
    GtkCTreeNode *snode;
    GList        *slist;
    gint         sitem;
    note_data    *note;
    
    snode = NULL;
    slist = GTK_CLIST(todolist)->selection;
    if (slist != NULL)
    {
        sitem = (gint) slist->data;
        note = (note_data *)gtk_clist_get_row_data(GTK_CLIST(todolist), sitem);
        snode = gtk_ctree_find_by_row_data(GTK_CTREE(note_tree), NULL, note);
    }
    
    return (snode);
}

/* ------------------------------------------------------ */
/*
 * return the correspoding tree-node from the todolist
 * and give a message if no note is selected
 */


GtkCTreeNode *
tree_node_from_todo_selection_msg(void)
{
    GtkCTreeNode *snode;

    snode = tree_node_from_todo_selection();
    if (snode == NULL)
    {
        gnome_ok_dialog_parented(_("Select a note first!"), 
                                 yank_root_win(NULL));
    }
    return (snode);
}

/* ------------------------------------------------------ */
/*
 * search corresponding note in tree, expand all parents and select it
 */

void
cb_todo_open_corr(GtkWidget *w, gpointer p)
{
    GtkCTreeNode *target;
    GtkCTreeNode *parent;

    target = tree_node_from_todo_selection_msg();
    if (target == NULL)
    {
        return;
        /* notreached */
    }

    if (gtk_ctree_node_is_visible(GTK_CTREE(note_tree), target)
        != GTK_VISIBILITY_FULL)
    {
        parent = GTK_CTREE_ROW(target)->parent;
        while (parent)
        {
            gtk_ctree_expand(GTK_CTREE(note_tree), parent);
            parent = GTK_CTREE_ROW(parent)->parent;
        }
    }
    gtk_ctree_node_moveto(GTK_CTREE(note_tree), target, 0, 0, 0);
    gtk_ctree_select(GTK_CTREE(note_tree), target);
}

/* ------------------------------------------------------ */
/*
 * ask whether to commit uncommitted changes
 */

void
ask_commit_changes(void)
{
    static GtkWidget *dialog = NULL;
    note_data        *data;
    gchar            *msg;
    gint             sel;
    yank_preferences *pref;
 
    pref = get_preferences();

    if ((notetype != None) && (uncommitted) && (editmode != Delete))
    {
      if (editmode == Add)
      {
          data = fill_note_data_from_page(notetype);
      }
      else
      {
          data = (note_data *)gtk_ctree_node_get_row_data(
                        GTK_CTREE(note_tree), selected_node);
      }
        if (! pref->auto_save_modified_notes)
      {
            msg = g_strdup_printf(
                _("Note '%s' modified. Do you want to commit changes?"),
                data->title);
            dialog = gnome_question_dialog_modal_parented(msg, NULL, NULL,
                                                          yank_root_win(NULL));
            gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
            sel = gnome_dialog_run_and_close(GNOME_DIALOG(dialog));
            g_free(msg);
      }
      else
        {
            sel = 0;
        }
        
      if (editmode == Add)
        free_note(data);
      
        if (sel == 0)
        {
            if (apply_note())
            {
                gnome_warning_dialog_parented(_("Note has not been modified!"),
                                              yank_root_win(NULL));
            }
        }
        if (sel == 1)
        {
            uncommitted = FALSE;
        }
    }
}

/* ------------------------------------------------------ */
/*
 * open text-selection as url
 */

void
cb_open_in_browser(GtkWidget *w, gpointer p)
{
    gchar     *url;
    
    url = get_text_selection(NULL);
    if (url)
    {
        gnome_url_show(url);
        g_free(url);
    }
}

/* ------------------------------------------------------ */
/*
 * return selection from title_entry or text_entry
 */

gchar*
get_text_selection(GtkWidget **widget)
{
    guint     sstart;
    guint     send;
    gchar     *ret;
    GtkWidget *entry;

    ret = NULL;
    entry = NULL;
    if (selected_node == NULL)
    {
        gnome_ok_dialog_parented(_("Select a note first!"),
                                 yank_root_win(NULL));
        return (NULL);
        /* notreached */
    }
    if (GTK_WIDGET_HAS_FOCUS(title_entry))
    {
        entry = title_entry;
    }
    if (GTK_WIDGET_HAS_FOCUS(text_entry))
    {
        entry = text_entry;
    }
    if (entry == NULL)
    {
        gnome_ok_dialog_parented(_("Select text first!"), yank_root_win(NULL));
        return (NULL);
        /* notreached */
    }
    sstart = GTK_EDITABLE(entry)->selection_start_pos;
    send = GTK_EDITABLE(entry)->selection_end_pos;
    if ((sstart - send) == 0)
    {
        gnome_ok_dialog_parented(_("Select text first!"), yank_root_win(NULL));
    }
    else
    {
        if (widget != NULL)
        {
            *widget = entry;
        }
        if (sstart > send)
        {
            guint tmp;
            
            tmp = send;
            send = sstart;
            sstart = tmp;
        }
        ret = gtk_editable_get_chars(GTK_EDITABLE(entry), sstart, send);
    }
    
    return (ret);
}

/* ------------------------------------------------------ */
/*
 * view selection as mime
 */

void
cb_view_as_mime(GtkWidget *w, gpointer p)
{
    gchar       *f_name;
    const gchar *mtype;
    const gchar *mprg;
    gchar       *cmd;
    gchar       *cmd_pos;
    gchar       *cmd_full;
    gchar       *cmd_msg;
    pid_t       mpid;
    
    f_name = get_text_selection(NULL);
    if (f_name)
    {
        mtype = gnome_mime_type(f_name);
        mprg = gnome_mime_program(mtype);
        cmd = g_strdup(mprg);
        
        /*
         * not sure if this is the right way to do it ..
         */
        
        cmd_pos = strstr(cmd, "%f");
        if (cmd_pos)
        {
            cmd_pos++;
            *cmd_pos = 's';
        }
        cmd_full = g_strdup_printf(cmd, f_name);
        mpid = fork();
        if (mpid == -1)
        {
            g_warning(_("Can't fork()\n"));
        }
        else
        {
            if (mpid == 0)
            {
                system(cmd_full);
                _exit(0);
            }
        }
        cmd_msg = g_strdup_printf(_("Running : %s"), cmd_full);
        set_status_text(cmd_msg);
        g_free(cmd);
        g_free(cmd_full);
        g_free(cmd_msg);
        g_free(f_name);
    }
}

/* ------------------------------------------------------ */
/*
 * run selection as a command
 */

void
cb_run_command(GtkWidget *w, gpointer p)
{
    gchar *command;
    pid_t pid;
    
    command = get_text_selection(NULL);
    if (command)
    {
        pid = fork();
        if (pid == -1)
        {
            g_warning(_("Can't fork()\n"));
        }
        else
        {
            if (pid == 0)
            {
                system(command);
                _exit(0);
            }
        }
        g_free(command);
    }
}

/* ------------------------------------------------------ */
/*
 * reads status from (any) child
 */
 
void
handle_sigchild(int signum)
{
    gint st;
    
    waitpid(-1, &st, 0);
}

/* ------------------------------------------------------ */
/*
 * find out on which widget in the note the operation should work
 */

GtkWidget*
get_note_cut_copy_paste_focus(void)
{
    GtkWidget *focus;

    focus = NULL;
    if (GTK_WIDGET_HAS_FOCUS(title_entry))
    {
        focus = title_entry;
    }
    else
    {
        if (GTK_WIDGET_HAS_FOCUS(text_entry))
        {
            focus = text_entry;
        }
        else
        {
            gnome_ok_dialog_parented(_("Select text first!"),
                                     yank_root_win(NULL));
        }
    }
    return (focus);
}

/* ------------------------------------------------------ */
/*
 * find out on which widget the operation should work
 */

GtkWidget*
get_cut_copy_paste_focus(void)
{
    GtkWidget *focus;

    focus = NULL;
    
    if (GTK_WIDGET_HAS_FOCUS(title_entry))
    {
        focus = title_entry;
    }
    else
    {
        if (GTK_WIDGET_HAS_FOCUS(text_entry))
        {
            focus = text_entry;
        }
        else
        {
            if (GTK_WIDGET_HAS_FOCUS(note_tree))
            {
                focus = note_tree;
            }
            else
            {
                gnome_ok_dialog_parented(_("Select note or text first!"),
                                         yank_root_win(NULL));
            }
        }
    }
    
    return (focus);
}

/* ------------------------------------------------------ */
/*
 * general cut function
 */

void
cb_edit_cut(GtkWidget *w, gpointer cbdata)
{
    GtkWidget *target;

    target = get_cut_copy_paste_focus();

    if (target == note_tree)
    {
        cb_edit_cut_tree(w, target);
    }
    else
    {
        if (target)
        {
            cb_edit_cut_note(w, target);
        }
    }
}

/* ------------------------------------------------------ */
/*
 * general copy function
 */

void
cb_edit_copy(GtkWidget *w, gpointer cbdata)
{
    GtkWidget *target;

    target = get_cut_copy_paste_focus();

    if (target == note_tree)
    {
        cb_edit_copy_tree(w, target);
    }
    else
    {
        if (target)
        {
            cb_edit_copy_note(w, target);
        }
    }
}
      
/* ------------------------------------------------------ */
/*
 * general paste function
 */

void
cb_edit_paste(GtkWidget *w, gpointer cbdata)
{
    GtkWidget    *target;
    
    target = get_cut_copy_paste_focus();

    if (target == note_tree)
    {
        cb_edit_paste_tree(w, target);
    }
    else
    {
        if (target)
        {
            cb_edit_paste_note(w, target);
        }
    }
}

/* ------------------------------------------------------ */
/*
 * general select function
 */

void
cb_edit_selall(GtkWidget *w, gpointer cbdata)
{
    GtkWidget *target;

    target = get_cut_copy_paste_focus();

    if (target == note_tree)
    {
        cb_edit_selall_tree(w, target);
    }
    else
    {
        if (target)
        {
            cb_edit_selall_note(w, target);
        }
    }    
}

/* ------------------------------------------------------ */
/*
 * cut text to clipboard
 */

void
cb_edit_cut_note(GtkWidget *widget, gpointer cbdata)
{
    GtkWidget *w;

    w = cbdata;
    if (!cbdata)
    {
        w = get_note_cut_copy_paste_focus();
    }
    if (w)
    {
        g_return_if_fail(GTK_IS_EDITABLE(w));
        gtk_editable_cut_clipboard(GTK_EDITABLE(w));
        set_status_text(_("Text selection Cut..."));
    }
}

/* ------------------------------------------------------ */
/*
 * copy text to clipboard
 */

void
cb_edit_copy_note(GtkWidget *widget, gpointer cbdata)
{
    GtkWidget *w;

    w = cbdata;
    if (!cbdata)
    {
        w = get_note_cut_copy_paste_focus();
    }
    if (w)
    {
        g_return_if_fail(GTK_IS_EDITABLE(w));
        gtk_editable_copy_clipboard(GTK_EDITABLE(w));
        set_status_text(_("Text selection Copied..."));
    }
}

/* ------------------------------------------------------ */
/*
 * paste text from clipboard
 */

void
cb_edit_paste_note(GtkWidget *widget, gpointer cbdata)
{
    GtkWidget *w;

    w = cbdata;
    if (!cbdata)
    {
        w = get_note_cut_copy_paste_focus();
    }
    if (w)
    {
        g_return_if_fail(GTK_IS_EDITABLE(w));
        gtk_editable_paste_clipboard(GTK_EDITABLE(w));
        set_status_text(_("Text selection Pasted..."));
    }
}

/* ------------------------------------------------------ */
/*
 * select all text in the note-widget
 * defaults to the text-entry
 */

void
cb_edit_selall_note(GtkWidget *widget, gpointer cbdata)
{
    GtkWidget *w;
    gint len;

    w = cbdata;
    
    if (!cbdata)
    {
        if (GTK_WIDGET_HAS_FOCUS(title_entry))
        {
            w = title_entry;
        }
        else
        {
            w = text_entry;
        }
    }
    
    g_return_if_fail(GTK_IS_EDITABLE(w));

    if (GTK_IS_ENTRY(w))
    {
        len = strlen(gtk_entry_get_text(GTK_ENTRY(w)));
        if (len)
        {
            gtk_entry_select_region(GTK_ENTRY(w), 0, len);
        }
    }
    else
    {
        if (GTK_IS_TEXT(w))
        {
            len = gtk_text_get_length(GTK_TEXT(w));
            if (len)
            {
                gtk_editable_select_region(GTK_EDITABLE(w), 0, len);
            }
        }    
    }
}

/* ------------------------------------------------------ */
/*
 * cut selected notes
 */

void
cb_edit_cut_tree(GtkWidget *w, gpointer cbdata)
{
    if (GTK_CLIST(note_tree)->selection == NULL)
    {
        return;
    }

    if (edit_tree != NULL)
    {
        edit_tree_node_clear(edit_tree, NULL);
    }
    edit_tree = g_node_new(NULL);
    gtk_ctree_pre_recursive(GTK_CTREE(note_tree), NULL, (GtkCTreeFunc)
                            (*tree_copy_selection), edit_tree);
    gtk_ctree_post_recursive(GTK_CTREE(note_tree), NULL, (GtkCTreeFunc)
                             (*tree_cut_selection), NULL);
    edit_tree_free = TRUE;
}

/* ------------------------------------------------------ */
/*
 * copy selected notes
 */

void
cb_edit_copy_tree(GtkWidget *w, gpointer cbdata)
{    
    if (GTK_CLIST(note_tree)->selection == NULL)
    {
        return;
    }

    if (edit_tree != NULL)
    {
        edit_tree_node_clear(edit_tree, NULL);
    }
    edit_tree = g_node_new(NULL);
    gtk_ctree_pre_recursive(GTK_CTREE(note_tree), NULL, (GtkCTreeFunc)
                            (*tree_copy_selection), edit_tree);
    edit_tree_free = FALSE;
}

/* ------------------------------------------------------ */
/*
 * paste notes from edit_tree
 */

void
cb_edit_paste_tree(GtkWidget *w, gpointer cbdata)
{
    static GList *sel_list = NULL;
    GList        *sel;
    GtkCTreeNode *node;

    sel = GTK_CLIST(note_tree)->selection;
    if (edit_tree != NULL && sel)
    {
        g_list_free(sel_list);
        sel_list = NULL;
        while (sel)
        {
            sel_list = g_list_append(sel_list, sel->data);
            sel = g_list_next(sel);
        }
        
        sel_list = g_list_first(sel_list);        
        while (sel_list)
        {
            node = GTK_CTREE_NODE(sel_list->data);
            tree_paste_selection(node, edit_tree);
            sel_list = g_list_next(sel_list);
        }
    }
}

/* ------------------------------------------------------ */
/*
 * select all tree items
 */

void
cb_edit_selall_tree(GtkWidget *widget, gpointer cbdata)
{
    gtk_signal_handler_block_by_func(GTK_OBJECT(note_tree),
                                     GTK_SIGNAL_FUNC(note_tree_row_selected),
                                     NULL);
    gtk_clist_freeze(GTK_CLIST(note_tree));
    gtk_clist_select_all(GTK_CLIST(note_tree));
    gtk_clist_thaw(GTK_CLIST(note_tree));
    gtk_signal_handler_unblock_by_func(GTK_OBJECT(note_tree),
                                       GTK_SIGNAL_FUNC(note_tree_row_selected),
                                       NULL);    
}

/* ------------------------------------------------------ */
/*
 * copy pointer of selected notes
 * this function is designed to waste cpu time
 */

void
tree_copy_selection(GtkCTree *source, GtkCTreeNode *node, gpointer dest)
{
    note_data    *data;
    GList        *selection;
    gint         found;
    GtkCTreeNode *n_parent;
    GNode        *parent;
    GNode        *new_node;
    
    g_return_if_fail(GTK_IS_CTREE(source));

    /*
     * only work on selected nodes (yes, this _is_ suboptimal)
     */
    
    selection = g_list_find(GTK_CLIST(source)->selection, node);

    if (selection)
    {
        /*
         * search 1.st parent in selection list
         */

        found = FALSE;
        n_parent = GTK_CTREE_NODE(selection->data);
        n_parent = GTK_CTREE_ROW(n_parent)->parent;
        while (n_parent && found != TRUE)
        {

            if (g_list_find(GTK_CLIST(source)->selection, n_parent))
            {
                found = TRUE;
            }
            else
            {
                n_parent = GTK_CTREE_ROW(n_parent)->parent;
            }

        }

        /*
         * find parent in edit tree
         */
        
        if (found)
        {
            data = gtk_ctree_node_get_row_data(
                source, GTK_CTREE_NODE(n_parent));
            parent = g_node_find((GNode*)dest, G_PRE_ORDER, G_TRAVERSE_ALL,
                                 data);
        }
        else
        {
            parent = (GNode*) dest;
        }

        /*
         * append pointer to copy-list
         */
        
        data = gtk_ctree_node_get_row_data(source,
                                           GTK_CTREE_NODE(selection->data));
        new_node = g_node_new(data);
        g_node_append(parent, new_node);
    }
}

/* ------------------------------------------------------ */
/*
 * clear gnode-tree from tree
 */

void
edit_tree_node_clear(GNode *tree, gpointer p)
{
    GNode *node;

    if (tree)
    {
        node = tree;
        if (node->children)
        {
            edit_tree_node_clear(node->children, NULL);
        }
        if (node->next);
        {
            edit_tree_node_clear(node->next, NULL);
        }

        if (edit_tree_free == TRUE)
        {
            free_note((note_data*)node->data);
        }
        g_node_destroy(node);
    }
}

/* ------------------------------------------------------ */
/*
 * return a pointer to a copy of the source
 */

note_data*
copy_note(note_data *source)
{
    note_data *note;

    if (source == NULL)
    {
        return (NULL);
        /* notreached */
    }
    
    note = (note_data *) malloc(sizeof (note_data));
    if (note == NULL)
    {
        g_warning(_("Error while allocating memory for note"));
        return (NULL);
        /* notreached */
    }
    note->notetype = source->notetype;
    note->title = g_strdup(source->title);
    note->user = g_strdup(source->user);
    note->text = g_strdup(source->text);
    note->expire = source->expire;
    note->id = create_note_id();
    note->created = time(NULL);
    note->changed = note->created;
    note->changes = 0;
    
    if (source->notetype == CheckNote || source->notetype == TodoNote)
    {
        note->todo = source->todo;
    }
    else
    {
        note->todo = 0;
    }    
    if (source->notetype == TodoNote)
    {
        note->deadline = source->deadline;
        note->prio = source->prio;
        note->complete = source->complete;
        note->estm_days = source->estm_days;
        note->used_days = source->used_days;

    }
    else
    {
        note->deadline = 0;
        note->prio = 0;
        note->complete = 0;
        note->estm_days = 0;
        note->used_days = 0;
    }
    
    return (note);
}

/* ------------------------------------------------------ */
/*
 * generate notes from source
 */

void
tree_paste_selection(GtkCTreeNode *parent, GNode *source)
{
    note_data    *new_data;
    GtkCTreeNode *new_child;
    
    if (source)
    {        
        new_data = NULL;
        new_child = parent;
        if (source->data)
        {
            new_data = copy_note((note_data*)source->data);
            new_child = do_add_note(new_data, parent);
        }

        if (source->children)
        {
            tree_paste_selection(new_child, source->children);
        }
        if (source->next)
        {
            tree_paste_selection(parent, source->next);
        }
    }
}

/* ------------------------------------------------------ */
/*
 * save all children of node by moving them to the parent
 */

void
tree_node_save_childs(GtkCTree *tree, GtkCTreeNode *node, gpointer p)
{
    GtkCTreeNode *childs;
    GtkCTreeNode *parent;

    g_return_if_fail(tree != NULL);
    g_return_if_fail(GTK_IS_CTREE(tree));
    g_return_if_fail(node != NULL);
    
    parent = GTK_CTREE_ROW(node)->parent;
    
    /* prevents gtk from warning us */
    if (GTK_CTREE_ROW(node)->children)
    {
        /* move childs */
        while ((childs = GTK_CTREE_ROW(node)->children) != NULL)
        {
            gtk_ctree_expand_recursive(GTK_CTREE(tree),
                                       GTK_CTREE_ROW(childs)->parent);
            gtk_ctree_move(GTK_CTREE(tree), childs, parent, NULL);
        }
    }    
}

/* ------------------------------------------------------ */
/*
 * cut selected notes from the tree
 */

void
tree_cut_selection(GtkCTree *source, GtkCTreeNode *node, gpointer p)
{
    static note_data *data;
    GList            *selection;

    g_return_if_fail(source != NULL);
    g_return_if_fail(GTK_IS_CTREE(source));
    g_return_if_fail(node != NULL);

    /*
     * only work on selected nodes (yes, this _is_ suboptimal)
     */

    selection = g_list_find(GTK_CLIST(source)->selection, node);
    
    if (selection)
    {
        tree_node_save_childs(source, GTK_CTREE_NODE(selection->data), NULL);

        /*
         * update todolist
         */
        
        data = gtk_ctree_node_get_row_data(source,
                                           GTK_CTREE_NODE(selection->data));
        if (data->notetype == TodoNote && data->todo == 0)
        {
            delete_todo_item(data, TRUE);
        }
        
        gtk_ctree_remove_node(source, GTK_CTREE_NODE(selection->data));

        modified = TRUE;
    }
}

/* ------------------------------------------------------ */
/*
 * sort subtrees of selected notes
 */

void
cb_sort_subtree(GtkWidget *w, gpointer p)
{
    GList *sel;
    
    sel = GTK_CLIST(note_tree)->selection;

    while (sel)
    {
        gtk_ctree_sort_node(GTK_CTREE(note_tree), GTK_CTREE_NODE(sel->data));
        sel = g_list_next(sel);
    }
}

/* ------------------------------------------------------ */
/*
 * toggle visibility of extra note flags
 */

void
cb_toggle_ext_flags(GtkWidget *button, gpointer box)
{
    GtkWidget *up;
    GtkWidget *down;
    
    g_return_if_fail(GTK_IS_BUTTON(button));
    g_return_if_fail(GTK_IS_HBOX(box));

    up = gtk_object_get_data(GTK_OBJECT(button), "up");
    down = gtk_object_get_data(GTK_OBJECT(button), "down");
    
    if (GTK_WIDGET_VISIBLE(GTK_WIDGET(box)) == FALSE)
    {
        gtk_widget_show(up);
        gtk_widget_hide(down);
        gtk_widget_show(GTK_WIDGET(box));
    }
    else
    {
        gtk_widget_show(down);
        gtk_widget_hide(up);
        gtk_widget_hide(GTK_WIDGET(box));
    }
}

/* ------------------------------------------------------ */
/*
 * auto-update done flag
 */

void
cb_complete_updates_done(GtkWidget *ad_complete, gpointer todo_check)
{
    if ((notetype == TodoNote)
        && (get_preferences()->completing_todo_note_sets_done))
    {
        gtk_toggle_button_set_active(
            GTK_TOGGLE_BUTTON(todo_check),
            ((GTK_ADJUSTMENT(ad_complete)->value == 100) ? 1 : 0));
    }
}

/* ------------------------------------------------------ */
/*
 * link the used days to the progress bar
 */

void
cb_updated_complete(GtkWidget * ad_complete, gpointer * extra_adjust)
{
  float       days_used;
  adjustments *my_adjustments;
  
  my_adjustments=(adjustments*) (extra_adjust);
  days_used=0;
  if (notetype == TodoNote)
  {
      days_used = my_adjustments->complete_adjust->value / 100
          * my_adjustments->estm_days_adjust->value;
      gtk_adjustment_set_value(my_adjustments->used_days_adjust,days_used);
  }
}
      
/* ------------------------------------------------------ */

void
cb_updated_used_days(GtkWidget * dused_adjust,gpointer * extra_adjust)
{
  gfloat      complete;
  adjustments *my_adjustments;
  
  my_adjustments = (adjustments*) (extra_adjust);
  complete=0;
  if (notetype == TodoNote)
  {
      if (my_adjustments->estm_days_adjust->value == 0 )
      {
          complete = 0;
      }
      else
      {
          complete = 100 * my_adjustments->used_days_adjust->value /
              my_adjustments->estm_days_adjust->value;
      }
      gtk_adjustment_set_value(my_adjustments->complete_adjust,complete);
  }
}



/* ------------------------------------------------------ */
/*
 * guess what it does
 */

void
cb_yank_homepage(GtkWidget *w, gpointer p)
{
    gnome_url_show(YANK_HOMEPAGE);
}

/* ------------------------------------------------------ */
/*
 * walk backwards in the tree and recalculate the completion status
 */

void
tree_recursive_completion(GtkCTree *tree, GtkCTreeNode *node)
{
    note_data *note;
    note_data *m_note;
    
    g_return_if_fail(tree != NULL);
    g_return_if_fail(GTK_IS_CTREE(tree));
    g_return_if_fail(node != NULL);

    if (calc_completion_status(tree, node) == 1)
    {
        /*
         * update note
         */
        
        note = (note_data *)gtk_ctree_node_get_row_data(tree, node);
        m_note = copy_note(note);
        if (m_note != NULL)
        {
            m_note->created = note->created;
            m_note->changed = time(NULL);
            m_note->changes = note->changes + 1;
            
            get_preferences()->recursive_completion = 0;
            do_edit_note(m_note, node);
            get_preferences()->recursive_completion = 1;
        }
        else
        {
            gnome_warning_dialog_parented(
                _("recursive completion: can't copy note"),
                yank_root_win(NULL));
        }
    }
    
    /*
     * continue with parent
     */
    
    if (GTK_CTREE_ROW(node)->parent != NULL)
    {
        tree_recursive_completion(tree, GTK_CTREE_ROW(node)->parent);
    }
}

/* ------------------------------------------------------ */
/*
 * calculate the completion status
 * returns:  0 - no changes
 *           1 - note changed
 *          -1 - error
 */

gint
calc_completion_status(GtkCTree *tree, GtkCTreeNode *node)
{
    GtkCTreeNode *child;
    note_data    *note;
    note_data    *c_note;
    glong        todonotes;
    glong        ttodonotes;
    gfloat       checknotes;
    gfloat       tchecknotes;
    glong        sum_todo_comp;
    gint         ret;
    gint         complete;
    gint         todo;
    gfloat       sum_used_days;
    gfloat       sum_estm_days;
    
    g_return_val_if_fail(tree != NULL, -1);
    g_return_val_if_fail(GTK_IS_CTREE(tree), -1);
    g_return_val_if_fail(node != NULL, -1);

    note = (note_data *)gtk_ctree_node_get_row_data(tree, node);
    
    if (note == NULL)
    {
        gnome_warning_dialog_parented(
            _("calc completion status: Note without data!"),
            yank_root_win(NULL));
        return (-1);
        /* notreached */
    }

    if ((note->notetype != CheckNote) && (note->notetype != TodoNote))
    {
        return (0);
        /* notreached */
    }
    
    child = GTK_CTREE_ROW(node)->children;
    if (child == NULL)
    {
        return (0);
        /* notreached */
    }
    
    ret = 0;

    todonotes = 0;
    ttodonotes = 0;
    checknotes = 0;
    tchecknotes = 0;
    sum_todo_comp = 0;
    sum_used_days = 0;
    sum_estm_days = 0;
    
    /*
     * scan childs
     */

    do
    {
        c_note = (note_data *)gtk_ctree_node_get_row_data(tree, child);
        if (c_note == NULL)
        {
            gnome_warning_dialog_parented(
                _("calc completion status (2): Note without data!"),
                yank_root_win(NULL));
            continue;
        }

        switch (c_note->notetype)
        {
        case CheckNote:
            checknotes++;
            if (c_note->todo == 0)
            {
                tchecknotes++;
            }
            break;
        case TodoNote:
            todonotes++;
            sum_todo_comp += c_note->complete;
            sum_used_days += c_note->used_days;
            sum_estm_days += c_note->estm_days;
            if (c_note->todo == 0)
            {
                ttodonotes++;
            }
            break;
        default:
            break;
        };
    } while ((child = GTK_CTREE_ROW(child)->sibling) != NULL);

    /*
     * guess todo/ completion values
     */
    
    switch (note->notetype)
    {
    case CheckNote:
        if ((checknotes + todonotes) > 0)
        {
            if (todonotes > 0)
            {
                todo = (((tchecknotes + ttodonotes) == 0) &&
                        ((sum_todo_comp / todonotes) == 100)) ? 1 : 0;
            }
            else
            {
                todo = ((tchecknotes + ttodonotes) == 0)  ? 1 : 0;
            }

            /*
             * update note
             */
            
            if (todo != note->todo)
            {
                note->todo = todo;
                ret = 1;
            }
        }
        break;

    case TodoNote:
        if (todonotes > 0)
        {
/*            complete = (sum_todo_comp / todonotes) - ttodonotes - tchecknotes;*/
          complete = ( gfloat) (sum_used_days/ sum_estm_days * 100.0) ;
          
        }
        else
        {
            if (checknotes > 0)
            {
                complete = (gfloat)((checknotes - tchecknotes) / checknotes) * 100;
            }
            else
            {
                complete = (gfloat)(100.0*note->used_days/note->estm_days);
            }
        }

        /*
         * update note
         */
        
        if (complete < 0)
        {
            complete = 0;
        }
        if (complete > 100)
        {
            complete = 100;
        }


        if (complete != note->complete)
        {
            note->complete = complete;
            ret = 1;
        }

        if (sum_used_days != note->used_days)
        {
            note->used_days = sum_used_days;
            ret = 1;
        }

        if (sum_estm_days != note->estm_days)
        {
            note->estm_days = sum_estm_days;
            ret = 1;
        }

        if (get_preferences()->completing_todo_note_sets_done)
        {
            todo = (complete == 100) ? 1 : 0;
        }
        else
        {
            todo = note->todo;
        }
        if (todo != note->todo)
        {
            note->todo = todo;
            ret = 1;
        }
        break;

    default:
        break;
    };
    
    return (ret);
}

/* ------------------------------------------------------ */
/*
 * return string-path to the note
 */

GString*
tree_path_to_node(GtkCTree *tree, GtkCTreeNode *node)
{
    GString   *path;
    note_data *note;
    
    g_return_val_if_fail(tree != NULL, NULL);
    g_return_val_if_fail(node != NULL, NULL);
    
    path = g_string_new(NULL);
    for (; node != NULL; node = GTK_CTREE_ROW(node)->parent)
    {
        note = (note_data *)gtk_ctree_node_get_row_data(tree, node);
        if (note == NULL)
        {
            continue;
            /* notreached */
        }
        if (note->title == NULL)
        {
            continue;
            /* notreached */
        }
        path = g_string_prepend(path, note->title);
        path = g_string_prepend(path, "/");
    }
    return (path);
}

/* ------------------------------------------------------ */
/*
 * display path in statusbar
 */

void
display_tree_path(GtkCTree *tree, GtkCTreeNode *node)
{
    GString *str;

    g_return_if_fail(tree != NULL);
    if (get_preferences()->display_tree_path == 0)
    {
        return;
        /* notreached */
    }
    str = tree_path_to_node(tree, node);
    if (str != NULL)
    {
        set_status_text(str->str);
        g_string_free(str, TRUE);
    }
}

/* ------------------------------------------------------ */
/*
 * sort clist
 */

void
cb_clist_sort_column(GtkCList *list, gint col)
{
    static GtkSortType st = GTK_SORT_DESCENDING;

    g_return_if_fail(list != NULL);
    g_return_if_fail(GTK_IS_CLIST(list));

    if (GTK_CLIST(list)->rows < 1)
    {
        return;
        /* notreached */
    }
    
    st = (st == GTK_SORT_ASCENDING) ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING;
    gtk_clist_set_sort_type(list, st);
    gtk_clist_set_sort_column(list, col);
    gtk_clist_sort(list);
}

    
/* ------------------------------------------------------ */
/*
 * generate notes from selected textlines
 */

void
cb_selection_fastgen(GtkWidget *w, gpointer p)
{
    note_data *note;
    gchar     *txt;
    gchar     *pos1;
    gchar     *pos2;
    gchar     buf;
    
    txt = get_text_selection(NULL);
    if (txt == NULL)
    {
        return;
        /* notreached */
    }

    pos1 = txt;
    buf = '\0';                  /* makes the compiler happy */

    do
    {
        pos2 = strchr(pos1, '\n');

        if (pos2 != NULL)
        {
            buf = (*pos2);
            (*pos2) = '\0';
        }

        if (strlen(pos1) > 0)    /* don't add empty notes */
        {
            note = (note_data *) malloc(sizeof (note_data));
            if (note == NULL)
            {
                g_warning(_("cb_selection_fastgen(): Error while allocating \
memory for note."));
                break;
                /* notreached */
            }
            note->notetype = TextNote;
            note->id = create_note_id();
            note->title = g_strdup(pos1);
            note->expire = -1;
            note->created = time(NULL);
            note->changed = note->created;
            note->changes = 0;
            note->text = NULL;
            do_add_note(note, selected_node);
        }
        
        if (pos2 != NULL)
        {
            (*pos2) = buf;
            pos1 = pos2 + 1;
        }
    } while (pos2 != NULL);

    g_free(txt);
}



/* ------------------------------------------------------ */

void cb_clear_todolist_all()
{
  clear_todolist_from_tree(GTK_CTREE(note_tree),NULL);
}

/* ------------------------------------------------------ */

void cb_build_todolist_all()
{
  build_todolist_from_tree(GTK_CTREE(note_tree),NULL);
}

/* ------------------------------------------------------ */

Generated by  Doxygen 1.6.0   Back to index