/*

  menu.cc

  menu subroutines for xlogmaster.cc
  Copyright (C) 1998 Georg C. F. Greve
  This is a GNU program
  
  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
  
  
  Contact: 
           mailto:xlogmaster-bugs@gnu.org
           http://www.gnu.org/software/xlogmaster/
  Secondary sources:
           http://porter.desy.de/~greve/xlogmaster/
           http://www.fusebox.hanse.de/xlogmaster/
	 
*/

/*{{{  Header  */

#include "../config.h"
#include "sysinc.H"
#include "logclass.H"
#include "menu.H"
#include "extern.H"

/*}}}*/

/*{{{  Create Menu  */
void fire_up_menu(GtkWidget* widget){
  // set up starting defaults for the menus:
  customizing = FALSE;

  // create menu, no need to "show" it
  menu = gtk_menu_new();

  // create entries
  load_config = gtk_menu_item_new_with_label("Load Configuration");
  save_config = gtk_menu_item_new_with_label("Save Configuration");
  customize_entry = gtk_menu_item_new_with_label("Customize Entries");
  about = gtk_menu_item_new_with_label("About Xlogmaster");
  quit_menu = gtk_menu_item_new_with_label("Quit");
  separator1 = gtk_menu_item_new();
  separator2 = gtk_menu_item_new();
  separator3 = gtk_menu_item_new();

  // and put them into the menu
  gtk_menu_append( GTK_MENU(menu), about );
  gtk_menu_append( GTK_MENU(menu), separator1 );
  gtk_menu_append( GTK_MENU(menu), customize_entry );
  gtk_menu_append( GTK_MENU(menu), separator2 );
  gtk_menu_append( GTK_MENU(menu), load_config );
  gtk_menu_append( GTK_MENU(menu), save_config );
  gtk_menu_append( GTK_MENU(menu), separator3 );
  gtk_menu_append( GTK_MENU(menu), quit_menu );

  // attach the callbacks:
  gtk_signal_connect_object( GTK_OBJECT(about), "activate",
			     GTK_SIGNAL_FUNC(about_proc), 
			     (gpointer) 0 );
  gtk_signal_connect_object( GTK_OBJECT(load_config), "activate",
			     GTK_SIGNAL_FUNC(load_conf_proc), 
			     (gpointer) 0 );
  gtk_signal_connect_object( GTK_OBJECT(save_config), "activate",
			     GTK_SIGNAL_FUNC(save_conf_proc), 
			     (gpointer) 0 );
  gtk_signal_connect_object( GTK_OBJECT(customize_entry), "activate",
			     GTK_SIGNAL_FUNC(customize_entry_proc), 
			     (gpointer) 0 );
  gtk_signal_connect_object( GTK_OBJECT(quit_menu), "activate",
			     GTK_SIGNAL_FUNC(quit), 
			     (gpointer) 0 );

  // and show the items:
  gtk_widget_show( about );
  gtk_widget_show( load_config );
  gtk_widget_show( save_config );
  gtk_widget_show( customize_entry );
  gtk_widget_show( quit_menu );
  gtk_widget_show( separator1 );
  gtk_widget_show(separator2 );
  gtk_widget_show(separator3 );

  // attach to handler for popup:
  gtk_signal_connect (GTK_OBJECT(widget), "button_press_event", 
		      GTK_SIGNAL_FUNC (popup_handler), 
		      menu);

}
/*}}}*/

/*{{{  Menu handling subroutines  */
static gint popup_handler(GtkWidget *widget, GdkEventButton *event, GtkWidget *menu){

  if (event->button == 3) {

    gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "button_press_event");

    gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
		    event->button, event->time);
    return TRUE;
  }
  return FALSE;
}
/*}}}*/

/*{{{  Load Configuration  */
void load_conf_proc(GtkWidget* widget, gpointer* data){
  if ( customizing == TRUE || filew != 0 ){    
    GList* buttons = g_list_alloc();
    GList* functions = g_list_alloc();
    buttons = g_list_append(buttons,
			    (gpointer) "\t   DISMISS   \t");
    functions = g_list_append(functions, NULL );
    
    popup_dialog("Erratic Request", "\n\t    Unable to load configuration     \t\n\t     at this point in program !     \t\n", buttons, functions);
    
    return;
  }

  if ( configuration_changed == FALSE ||
       terse == TRUE ) do_load();

  /* the configuration has been changed really load ? */
  
  GList* buttons = g_list_alloc();
  GList* functions = g_list_alloc();
  
  buttons = g_list_append(buttons,
			  (gpointer) "\t   YES   \t");
  functions = g_list_append(functions,
			    (gpointer) do_load );
  buttons = g_list_append(buttons,
			  (gpointer) "\t   NO   \t");
  functions = g_list_append(functions, NULL );

  popup_dialog
    ("Really Load ?", 
     "\n\t     There are unsaved changes     \t\n\t     loading will cause a loss of changes     \t\n\n\t     Proceed ?     \t\n",
     buttons, functions);
}
void do_load(){
  if ( customizing == TRUE || filew != 0 ){
    
    GList* buttons = g_list_alloc();
    GList* functions = g_list_alloc();
    buttons = g_list_append(buttons,
			    (gpointer) "\t   DISMISS   \t");
    functions = g_list_append(functions, NULL );
    
    popup_dialog("Erratic Request", "\n\t    Unable to load new configuration     \t\n\t     at this point in program execution !     \t\n", buttons, functions);
    
    return;
  }
  
  deactivate();
  disable();
  stop_watchdog();

  /* Create a new file selection widget */
  filew = gtk_file_selection_new ("Load configuration");

  gtk_widget_realize(filew);
  
  gtk_signal_connect (GTK_OBJECT (filew), "destroy",
		      (GtkSignalFunc) file_cancel_sel, &filew);
  gtk_signal_connect (GTK_OBJECT (filew), "delete_event",
		      GTK_SIGNAL_FUNC (delete_event), NULL);
  
  /* Connect the ok_button to file_ok_sel function */
  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
		      "clicked", (GtkSignalFunc) file_ok_sel, filew );
  
  /* Connect the cancel_button to file_cancel_sel function */
  gtk_signal_connect_object (GTK_OBJECT 
			     (GTK_FILE_SELECTION (filew)->cancel_button),
			     "clicked", (GtkSignalFunc) file_cancel_sel,
			     GTK_OBJECT (filew));
  
  char* fname = load_path;
  if ( fname == NULL ) fname = "config";
  gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
				   fname);

  gtk_window_position(GTK_WINDOW(filew), GTK_WIN_POS_MOUSE);
  gtk_window_set_policy(GTK_WINDOW(filew), TRUE, TRUE, TRUE);
  gtk_widget_show(filew);
}
void file_ok_sel (GtkWidget *w, GtkFileSelection *fs){
  char* fname = 
    new char[strlen(gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)))+2];
  strcpy(fname,gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
  gtk_widget_hide(filew);
  gtk_widget_destroy(filew);
  filew = 0;

  if ( load_path != NULL ) delete load_path;
  load_path = fname;

  if ( read_configuration(fname) == FALSE ){
    file_error(load_path);
    enable();
    start_watchdog();
    activate();
    return;
  } else {
    unsetup_logs();
    setup_logs();
    create_buttons();
    active = 0;
    enable();
    start_watchdog();
    activate();
    configuration_changed = FALSE;
    return;
  }
}
void file_cancel_sel (GtkWidget *w, GtkFileSelection *fs){
  gtk_widget_hide(filew);
  gtk_widget_destroy(filew);
  filew = 0;
  enable();
  start_watchdog();
  activate();
}
/*}}}*/

/*{{{  Save Configuration  */
void save_conf_proc(GtkWidget* widget, gpointer* data){
  if ( customizing == TRUE || filew != 0 ){
    GList* buttons = g_list_alloc();
    GList* functions = g_list_alloc();
    buttons = g_list_append(buttons,
			    (gpointer) "\t   DISMISS   \t");
    functions = g_list_append(functions, NULL );
    
    popup_dialog("Erratic Request", "\n\t    Unable to save configuration     \t\n\t     at this point in program !     \t\n", buttons, functions);
    
    return;
  }

  deactivate();
  disable();

  if ( save_path == NULL ){
    char* hdir = NULL;
    hdir = getenv("HOME");
    if ( hdir == NULL ) hdir = getenv("USER");
    if ( hdir == NULL ) hdir = getenv("PWD");
    if ( hdir == NULL ) hdir = ".";
    save_path = new char[ strlen(hdir) + strlen(CONFIGFILE) + 2 ];
    strcpy ( save_path, hdir );
    strcat ( save_path, "/" );
    strcat ( save_path, CONFIGFILE );
  }

  /* Create a new file selection widget */
  filew = gtk_file_selection_new ("Save configuration");
  
  gtk_widget_realize(filew);

  gtk_signal_connect (GTK_OBJECT (filew), "destroy",
		      (GtkSignalFunc) file_cancel_sel, &filew);
  gtk_signal_connect (GTK_OBJECT (filew), "delete_event",
		      GTK_SIGNAL_FUNC (delete_event), NULL);
  
  /* Connect the ok_button to file_save_ok function */
  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
		      "clicked", (GtkSignalFunc) file_save_ok, filew );
  
  /* Connect the cancel_button to file_cancel_sel function */
  gtk_signal_connect_object (GTK_OBJECT 
			     (GTK_FILE_SELECTION (filew)->cancel_button),
			     "clicked", (GtkSignalFunc) file_cancel_sel,
			     GTK_OBJECT (filew));
  
  gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
				   save_path);
  
  gtk_window_set_policy(GTK_WINDOW(filew), TRUE, TRUE, TRUE);
  gtk_window_position(GTK_WINDOW(filew), GTK_WIN_POS_MOUSE);
  gtk_widget_show(filew);
}
void file_save_ok (GtkWidget *w, GtkFileSelection *fs){
  char* fname = 
    new char[strlen(gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)))+2];
  strcpy(fname,gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
  gtk_widget_hide(filew);
  gtk_widget_destroy(filew);
  filew = 0;

  if ( save_path != NULL ) delete save_path;
  save_path = fname;
  
  if ( write_configuration(save_path) == FALSE ) file_error(save_path);
  else configuration_changed = FALSE;
  
  enable();
  activate();
}
/*}}}*/

/*{{{  Customize Entry  */
void customize_entry_proc(GtkWidget* widget, gpointer* data){
  if ( customizing == TRUE ) return;
  if ( filew != 0 ) return;

  /* create form for adding / editing entries */
  create_form();

  customizing = TRUE;
}
/*}}}*/

/*{{{  About Xlogmaster  */
void about_proc(GtkWidget* widget, gpointer* data){
  request_about();
}
/*}}}*/

/*{{{  Form subroutines  */
void create_form(){
  /* create window */
  form = gtk_window_new (GTK_WINDOW_DIALOG);
  gtk_signal_connect (GTK_OBJECT (form), "destroy",
		      GTK_SIGNAL_FUNC (form_popdown), NULL);
  gtk_signal_connect (GTK_OBJECT (form), "delete_event",
		      GTK_SIGNAL_FUNC (delete_event), NULL);
  gtk_window_set_title (GTK_WINDOW (form), "Customize");
  gtk_container_border_width(GTK_CONTAINER(form), 5);

  gtk_widget_realize(form);

  /* create boxes */
  big_box =  gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER (form), big_box);
  buttonbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_end(GTK_BOX(big_box), buttonbox, FALSE, FALSE, 2);

  /* show boxes */
  gtk_widget_show(big_box);
  gtk_widget_show(buttonbox);

  tooltips = gtk_tooltips_new();

/*{{{  Create buttons  */
  cancel_button = gtk_button_new_with_label ("\t  Cancel  \t");
  gtk_signal_connect (GTK_OBJECT (cancel_button), "clicked",
		      GTK_SIGNAL_FUNC (form_cancel), NULL );
  gtk_box_pack_end(GTK_BOX(buttonbox), cancel_button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, cancel_button, "...discard inputs...","...discard inputs...");
  gtk_widget_show(cancel_button);
  apply_button = gtk_button_new_with_label ("\t\b   OK   \t");
  gtk_signal_connect (GTK_OBJECT (apply_button), "clicked",
		      GTK_SIGNAL_FUNC (form_apply), NULL );
  gtk_box_pack_end(GTK_BOX(buttonbox), apply_button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, apply_button, "...apply inputs and leave customization...","...apply inputs and leave customization...");
  gtk_widget_show(apply_button);
  add_button = gtk_button_new_with_label ("\t  Insert  \t");
  gtk_signal_connect (GTK_OBJECT (add_button), "clicked",
		      GTK_SIGNAL_FUNC (form_add), NULL );
  gtk_box_pack_start(GTK_BOX(buttonbox), add_button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, add_button, "...insert entry...","...insert entry...");
  gtk_widget_show(add_button);
  move_up_button = gtk_button_new_with_label ("\t  Move Up  \t");
  gtk_signal_connect (GTK_OBJECT (move_up_button), "clicked",
		      GTK_SIGNAL_FUNC (form_move_up), NULL );
  gtk_box_pack_start(GTK_BOX(buttonbox), move_up_button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, move_up_button, "...move entry one step up...","...move entry one step up...");
  gtk_widget_show(move_up_button);
  move_down_button = gtk_button_new_with_label ("\t  Move Down  \t");
  gtk_signal_connect (GTK_OBJECT (move_down_button), "clicked",
		      GTK_SIGNAL_FUNC (form_move_down), NULL );
  gtk_box_pack_start(GTK_BOX(buttonbox), move_down_button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, move_down_button, "...move entry one step down...","...move entry one step down...");
  gtk_widget_show(move_down_button);
  delete_button = gtk_button_new_with_label ("\t  Delete  \t");
  gtk_signal_connect (GTK_OBJECT (delete_button), "clicked",
		      GTK_SIGNAL_FUNC (form_delete), NULL );
  gtk_box_pack_start(GTK_BOX(buttonbox), delete_button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, delete_button, "...delete entry...","...delete entry...");
  gtk_widget_show(delete_button);
  spacer = gtk_label_new ("        \t\t      ");
  gtk_box_pack_start(GTK_BOX(buttonbox), spacer, FALSE, FALSE, 5);
  gtk_widget_show(spacer);
/*}}}*/

  notebook = gtk_notebook_new ();
  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
  gtk_box_pack_end(GTK_BOX(big_box), notebook, TRUE, TRUE, 5);
  gtk_widget_show(notebook);
  for ( int i =  0 ; i < syslogs ; i++ )
    insert_page(syslog[i]->filename,
		syslog[i]->buttontext,
		syslog[i]->help,
		syslog[i]->interval,
		syslog[i]->mode,
		(Filter** )(syslog[i]->filter),
		i);
  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), active); // start at active entry

  gtk_window_position(GTK_WINDOW(form), GTK_WIN_POS_MOUSE);
  gtk_window_set_policy(GTK_WINDOW(form), TRUE, TRUE, FALSE);
  gtk_widget_show(form);
  gtk_window_activate_focus(GTK_WINDOW(form));
  gtk_widget_grab_focus(cancel_button);
}
/*{{{  Insert Notebook page  */
void insert_page(char* fname, char* btext, char* htext, int interval, int mode, Filter** filter, gint page){
  /* create notebook */
  GtkWidget *frame;
  GtkWidget* label;
  /* create title & flag */
  frame = gtk_frame_new (btext);
  gtk_container_border_width (GTK_CONTAINER (frame), 15);
  gtk_widget_show (frame);
  label = gtk_label_new (btext);
  gtk_notebook_insert_page (GTK_NOTEBOOK(notebook), frame, label, page);

  GtkWidget* box =  gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER (frame), box);

  label = gtk_label_new( "   " );
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  gtk_widget_show(label);
  create_textbox(box, 
		 " Filename: (absolute path)", 
		 fname,
		 "you can also use the 'select' button to browse your harddisk",
		 GTK_OBJECT( frame), LG_FILENAME);
  create_textbox(box, 
		 " Button text:", 
		 btext,
		 "Text to be shown on button",
		 GTK_OBJECT( frame), LG_BUTTON);
  create_textbox(box, 
		 " Help text: ", 
		 htext,
		 "Text to show up like this one...",
		 GTK_OBJECT( frame), LG_HELP);
  char* int_text = new char[20];
  ostrstream OSS(int_text, 20, ios::out );
  OSS.seekp(ios::beg);
  OSS << interval << ends;
  create_textbox(box, 
		 " Interval: (s/10) ", 
		 int_text,
		 "recommended value between 3 and 30",
		 GTK_OBJECT( frame), LG_INTERVAL);
  delete int_text;
  label = gtk_label_new( " Mode:" );
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  gtk_widget_show(label);
  GSList* group;
  GtkWidget* button;
  GtkWidget* bbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(bbox);
  gtk_box_pack_start (GTK_BOX (box), bbox, FALSE, FALSE, 0);
  button = gtk_radio_button_new_with_label (NULL, "TAIL-Mode  ");
  gtk_tooltips_set_tip(tooltips, button, "the standard 'tail -f' emulating mode", "the standard 'tail -f' emulating mode");
  gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_widget_grab_default (button);
  if ( mode == TAIL_FILE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_widget_show (button);  
  gtk_object_set_data( GTK_OBJECT( frame), LG_MODE, (GtkWidget*) button);
  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  button = gtk_radio_button_new_with_label(group, "CAT-Mode");
  if ( mode == CAT_FILE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_tooltips_set_tip(tooltips, button, "the cool 'cat' mode", "the cool 'cat' mode");
  gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
  gtk_widget_show (button);

  label = gtk_label_new( "   " );
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  gtk_widget_show(label);


  GtkWidget* filtersettings = create_filtermenu(box, filter);
  gtk_object_set_data( GTK_OBJECT( frame), LG_FILTER, (GtkWidget*) filtersettings );

  gtk_widget_show(box);  
}
void create_textbox( GtkWidget* box, char* title, char* def, char* tip, GtkObject* object, gchar* data_key ){  
  GtkWidget* label;
  GtkWidget* text;

  label = gtk_label_new( title );
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  if ( strcmp(data_key, LG_FILENAME) ){
    gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  } else {
    GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 3);
    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
    gtk_widget_show( hbox );
    GtkWidget* button = gtk_button_new_with_label ("\t  select  \t");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (select_file), NULL );
    gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 3);
    gtk_tooltips_set_tip(tooltips, button, "Browse for logfile/device","Browse for logfile/device");
    gtk_widget_show(button);
  }  
  gtk_widget_show(label);
  text = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(text), def);
  gtk_entry_set_editable (GTK_ENTRY(text),TRUE);
  gtk_box_pack_start(GTK_BOX(box), text, FALSE, FALSE, 0);
  gtk_tooltips_set_tip(tooltips, text, tip, tip);
  gtk_widget_show(text);
  gtk_signal_connect (GTK_OBJECT (text), "activate",
		      GTK_SIGNAL_FUNC (accept_it), NULL );
  gtk_object_set_data( object, data_key, (GtkWidget*) text);
  label = gtk_label_new ("      ");
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
  gtk_widget_show(label);

}
/*}}}*/

/*}}}*/
/*{{{  Maintenance routines  */

void form_popdown (GtkWidget *widget, gpointer *data){
  gtk_widget_hide(form);
  gtk_widget_destroy(form);
  form = 0;
}
void retrieve_data(char** fname, char** btext, char** htext, int* interval, int* mode, Filter *** filter_tmp,int page){
  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), page);
  GtkNotebook* nb = GTK_NOTEBOOK(notebook);
  GtkObject* frame = GTK_OBJECT ( nb->cur_page->child );

  GtkWidget* textwidget;
  gchar* entry_text;
  
  textwidget = (GtkWidget*) gtk_object_get_data( frame, LG_FILENAME );
  entry_text = gtk_entry_get_text(GTK_ENTRY(textwidget));
  *fname = new char[strlen(entry_text)+2];
  strcpy(*fname, entry_text);

  textwidget = (GtkWidget*) gtk_object_get_data( frame, LG_BUTTON );
  entry_text = gtk_entry_get_text(GTK_ENTRY(textwidget));
  *btext = new char[strlen(entry_text)+2];
  strcpy(*btext, entry_text);

  textwidget = (GtkWidget*) gtk_object_get_data( frame, LG_HELP );
  entry_text = gtk_entry_get_text(GTK_ENTRY(textwidget));
  *htext = new char[strlen(entry_text)+2];
  strcpy(*htext, entry_text);

  textwidget = (GtkWidget*) gtk_object_get_data( frame, LG_INTERVAL );
  entry_text = gtk_entry_get_text(GTK_ENTRY(textwidget));
  *interval = 0;
  int x = 0;
  while ( entry_text[x] != 0 ){
    int a = entry_text[x] - '0';
    if ( a >= 0 && a <= 9 ){
      *interval *= 10;
      *interval += a;
    }
    x++;
  }

  GtkWidget* buttonwidget = (GtkWidget*) gtk_object_get_data( frame, LG_MODE );
  if (GTK_TOGGLE_BUTTON (buttonwidget)->active)
    {
      /* If control reaches here, the toggle button is down */
      *mode = TAIL_FILE;
    } else {
      /* If control reaches here, the toggle button is up */
      *mode = CAT_FILE;
    }

  /* now retrieve filter settings: */
  GtkWidget* list = (GtkWidget*) gtk_object_get_data( frame, LG_FILTER );
  GList* list_items = GTK_LIST(list)->children;
  guint items = g_list_length(list_items);
  if ( items > 0 ){
    GtkWidget* last_active = (GtkWidget*) GTK_LIST(list)->selection->data;
    filter_item_select(GTK_LIST(list), last_active ); // store text changes to last active item 
  }


  list_items = g_list_first(list_items);

  (*filter_tmp) = new Filter*[items+1];
  for ( int z = 0 ; z < items ; z++ ){
    GtkWidget* active_item = (GtkWidget*) list_items->data;
    Filter* filter = (Filter*) gtk_object_get_data( GTK_OBJECT( active_item ), FILTER_LIST_ITEM_DATA );
    (*filter_tmp)[z] = new Filter;
    (*filter_tmp)[z]->init(filter->string, filter->mode);
    if ( filter->mode & EXECUTE ){
      (*filter_tmp)[z]->execline = new gchar[strlen(filter->execline)+1];
      strcpy ( (*filter_tmp)[z]->execline, filter->execline);
    } else (*filter_tmp)[z]->execline = NULL;
    list_items = list_items->next;
  }
  (*filter_tmp)[items] = NULL;
}
/*}}}*/
/*{{{  Functionality routines  */
void form_apply(GtkWidget *widget, gpointer *data){
  /* if fileselector  is still active: kill it ! */
  if ( filew != 0 ){
    gtk_widget_hide(filew);
    gtk_widget_destroy(filew);
    filew = 0;
  }

  /* now stop everything for reinitialisation */
  deactivate();
  disable();
  stop_watchdog();

  /* now retrieve data */
  gtk_widget_hide(notebook);
  fillups = 0;
  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 0);
  gint last_page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  if ( last_page != 0 ){
    form_popdown(widget, data);
    start_watchdog();
    enable();
    activate();
    return;
  }
  gtk_notebook_next_page(GTK_NOTEBOOK(notebook));
  gint page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  fillups = 1;
  while ( page > last_page && page != last_page ){
    fillups++;
    last_page = page;
    gtk_notebook_next_page(GTK_NOTEBOOK(notebook));
    page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  }

  mode = new int[fillups];
  filename = new char*[fillups];
  help = new char*[fillups];
  buttontext = new char*[fillups];
  interval = new int[fillups];
  commandline = new char**[fillups];
  filter = new char**[fillups];
  filter_exec = new char**[fillups];
  filter_mode = new int*[fillups];

  for ( int i = 0 ; i < fillups ; i++ ){
    char* fname;
    char* btext;
    char* htext;
    int interv;
    int mod;
    retrieve_data(&fname, &btext, &htext, &interv, &mod, &filter_tmp, i);

    mode[i] = mod;
    interval[i] = interv;
    commandline[i] = NULL;
    
    filename[i] = new char[strlen(fname)+2];
    strcpy(filename[i], fname);
    
    help[i] = new char[strlen(htext)+2];
    strcpy(help[i], htext);
    
    buttontext[i] = new char[strlen(btext)+2];
    strcpy(buttontext[i], btext);

    /* create the data array for creating the real filter objects */
    filter[i] = NULL;
    filter_exec[i] = NULL;
    filter_mode[i] = NULL;
    if ( filter_tmp != NULL ){
      int objects = 0;
      while ( filter_tmp[objects] != NULL ) objects++;
      filter[i] = new char*[objects+1];
      filter_exec[i] = new char*[objects+1];
      filter_mode[i] = new int[objects+1];
      char** filterstr = filter[i];
      char** filter_execstr = filter_exec[i];
      int* filterm = filter_mode[i];
      for ( int k = 0 ; k < objects ; k++ ){
	char* string = new char[ strlen(filter_tmp[k]->string) +1 ];
	strcpy( string, filter_tmp[k]->string );
	filterstr[k] = string;
	if ( ( filter_tmp[k]->mode & EXECUTE ) &&
	     ( filter_tmp[k]->execline != NULL )){
	  char* execstr = new char[ strlen(filter_tmp[k]->execline) +1 ];
	  strcpy( execstr, filter_tmp[k]->execline);
	  filter_execstr[k] = execstr;
	} else filter_execstr[k] = NULL;
	filterm[k] = filter_tmp[k]->mode;
      }
      filterstr[objects] = NULL;
      filter_execstr[objects] = NULL;
      filterm[objects] = 0;
    }
  }

  /* Delete temporary filter array */
  if ( filter_tmp != NULL ){
    int x = 0;
    while ( filter_tmp[x] != NULL ) delete filter_tmp[x++];
    delete filter_tmp;
    filter_tmp = NULL;
  }

  /* Now hide & destroy form */
  form_popdown(widget, data);
  
  /* setup stuff anew */
  unsetup_logs();
  setup_logs();
  create_buttons();
  if ( active >= syslogs ) active = syslogs-1;
  enable();
  start_watchdog();
  activate();

  configuration_changed = TRUE;
  customizing = FALSE;
}
void form_cancel(GtkWidget *widget, gpointer *data){
  if ( filew != 0 ){
    gtk_widget_hide(filew);
    gtk_widget_destroy(filew);
    filew = 0;
  }

  /* Now hide & destroy form */
  form_popdown(widget, data);

  customizing = FALSE;
}
void form_add(GtkWidget *widget, gpointer *data){
  gint page;
  page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  insert_page("","NEW","",INTERVAL, TAIL_FILE, NULL, page);
  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), page);
}
void form_move_up(GtkWidget *widget, gpointer *data){
  gint pageno;
  pageno = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  gint pages = g_list_length( (GList*) GTK_NOTEBOOK(notebook)->children );

  if ( pageno == 0 ) return;

  GtkWidget* page = GTK_NOTEBOOK(notebook)->cur_page->child;
  GtkWidget* label = GTK_NOTEBOOK(notebook)->cur_page->tab_label;

  gtk_widget_ref(page);
  gtk_widget_ref(label);

  gtk_notebook_remove_page( GTK_NOTEBOOK(notebook), pageno );

  pageno--;
  if ( pageno < 0 ) pageno = 0;

  gtk_notebook_insert_page( GTK_NOTEBOOK(notebook),
			    page,
			    label,
			    pageno);

  gtk_widget_unref(page);
  gtk_widget_unref(label);

  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), pageno);
  gtk_widget_draw(GTK_WIDGET(notebook), NULL);

  return;
}
void form_move_down(GtkWidget *widget, gpointer *data){
  gint pageno;
  pageno = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  gint pages = g_list_length( (GList*) GTK_NOTEBOOK(notebook)->children );

  if ( pageno == pages-1 ) return;

  GtkWidget* page = GTK_NOTEBOOK(notebook)->cur_page->child;
  GtkWidget* label = GTK_NOTEBOOK(notebook)->cur_page->tab_label;

  gtk_widget_ref(page);
  gtk_widget_ref(label);

  gtk_notebook_remove_page( GTK_NOTEBOOK(notebook), pageno );

  pageno++;
  if ( pageno > pages ) pageno = pages;

  gtk_notebook_insert_page( GTK_NOTEBOOK(notebook),
			    page,
			    label,
			    pageno);

  gtk_widget_unref(page);
  gtk_widget_unref(label);

  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), pageno);
  gtk_widget_draw(GTK_WIDGET(notebook), NULL);

  return;
}
void form_delete(GtkWidget *widget, gpointer *data){
  gint page;
  page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  gtk_notebook_remove_page (GTK_NOTEBOOK(notebook), page);
  /* Need to refresh the widget --
     This forces the widget to redraw itself. */
  gtk_widget_draw(GTK_WIDGET(notebook), NULL);
}
/*}}}*/
/*{{{  NotebookChild Subroutines  */
void select_file(GtkWidget*, gpointer*){
  if ( filew != 0 ) return;
  
  /* Create a new file selection widget */
  filew = gtk_file_selection_new ("Find Logfile");
  
  gtk_signal_connect (GTK_OBJECT (filew), "destroy",
		      (GtkSignalFunc) file_pc_cancel_sel, &filew);
  
  /* Connect the ok_button to file_ok_sel function */
  gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
		      "clicked", (GtkSignalFunc) file_pc_ok_sel, filew );
  
  /* Connect the cancel_button to file_cancel_sel function */
  gtk_signal_connect_object (GTK_OBJECT 
			     (GTK_FILE_SELECTION (filew)->cancel_button),
			     "clicked", (GtkSignalFunc) file_pc_cancel_sel,
			     GTK_OBJECT (filew));
  
  
  char* fname;
  fname = log_path;
  if ( fname == NULL ) fname = "logfile";

  gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
				   fname);

  gtk_window_set_policy(GTK_WINDOW(form), TRUE, TRUE, TRUE);
  gtk_window_position(GTK_WINDOW(filew), GTK_WIN_POS_MOUSE);
  gtk_widget_show(filew);
  gtk_widget_grab_focus(filew);
}
void file_pc_ok_sel (GtkWidget *w, GtkFileSelection *fs){
  char* finame = 
    new char[strlen(gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)))+2];
  strcpy(finame,gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
  gtk_widget_hide(filew);
  gtk_widget_destroy(filew);

  if ( log_path != NULL ) delete log_path;
  log_path = finame;

  filew = 0;
  /*
    Put selection into filename widget...
   */
  char* fname;
  char* btext;
  char* htext;
  int interv;
  int mode;
  gint page;
  page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));
  retrieve_data(&fname, &btext, &htext, &interv, &mode, &filter_tmp, page);
  gtk_notebook_remove_page (GTK_NOTEBOOK(notebook), page);
  insert_page(finame, btext, htext, interv, mode, filter_tmp, page);
  gtk_notebook_set_page (GTK_NOTEBOOK(notebook), page);
  gtk_widget_draw(GTK_WIDGET(notebook), NULL);
  delete fname;
  delete btext;
  delete htext;

  /* Delete temporary filter array */
  if ( filter_tmp != NULL ){
    int x = 0;
    while ( filter_tmp[x] != NULL ) delete filter_tmp[x++];
    delete filter_tmp;
    filter_tmp = NULL;
  }
}
void file_pc_cancel_sel (GtkWidget *w, GtkFileSelection *fs){
  gtk_widget_hide(filew);
  gtk_widget_destroy(filew);
  filew = 0;
}
void accept_it(GtkWidget*, gpointer*){
  gint page;
  page = gtk_notebook_current_page(GTK_NOTEBOOK(notebook));

  if ( page < 0 ) return;

  GtkWidget* label = (GtkWidget*) GTK_NOTEBOOK(notebook)->cur_page->tab_label;
  GtkObject* frame = GTK_OBJECT ( GTK_NOTEBOOK(notebook)->cur_page->child );

  gchar* entry_text;  

  GtkWidget* textwidget = (GtkWidget*) gtk_object_get_data( frame, LG_BUTTON );
  entry_text = gtk_entry_get_text(GTK_ENTRY(textwidget));
  gtk_label_set( GTK_LABEL(label), entry_text );
  
  gtk_widget_draw(GTK_WIDGET(notebook), NULL);
  return;
}
/*}}}*/

/*{{{  Filter Menu  */
GtkWidget* 
create_filtermenu(GtkWidget* box, Filter** filter)
{
  GtkWidget* separator = gtk_hseparator_new();
  gtk_widget_show(separator);
  gtk_box_pack_start(GTK_BOX(box), separator, TRUE, TRUE, 0);

  GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(vbox);
  gtk_box_pack_start(GTK_BOX(box), vbox, TRUE, TRUE, 0);

/*{{{  add/delete filter entry buttons  */

  GtkWidget* button_box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), button_box, FALSE, FALSE, 5);
  gtk_widget_show(button_box);
  spacer = gtk_label_new (" Filter:");
  gtk_misc_set_alignment (GTK_MISC (spacer), 0, 0);
  gtk_box_pack_start(GTK_BOX(button_box), spacer, FALSE, FALSE, 0);
  gtk_widget_show(spacer);
  GtkWidget* button = gtk_button_new_with_label ("\t  Delete  \t");
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (filter_delete), (GtkWidget*) box );
  gtk_box_pack_end(GTK_BOX(button_box), button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, button, "...delete filter entry...","...delete filter entry...");
  gtk_object_set_data( GTK_OBJECT(box), FILTER_DELETE, (GtkWidget*) button);
  gtk_widget_show(button);
  button = gtk_button_new_with_label ("\t   Add   \t");
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (filter_add), (GtkWidget*) box );
  gtk_box_pack_end(GTK_BOX(button_box), button, FALSE, FALSE, 5);
  gtk_tooltips_set_tip(tooltips, button, "...add filter entry...","...add filter entry...");
  gtk_widget_show(button);

/*}}}*/

  GtkWidget* hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);

  GtkWidget* table = gtk_table_new(3, 5, FALSE);
  gtk_widget_show(table);
  gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0);
  
/*{{{  Set up radio buttons  */
  gint mode = NO_CHANGE;
  if ( filter != NULL )
    if (filter[0] != NULL ) mode=filter[0]->mode;
  button = gtk_check_button_new_with_label ( "Raise");
  gtk_tooltips_set_tip(tooltips, button, "... the 'raising' mode... matching lines will be displayed in PRELIGHT color... (see gtkrc) ... ", "... the 'raising' mode... matching lines will be displayed in PRELIGHT color... (see gtkrc) ...");
  gtk_table_attach(GTK_TABLE(table), button, 0, 1, 2, 3,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & RAISE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_RAISE, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) RAISE );  

  button = gtk_check_button_new_with_label ( "Lower");
  gtk_tooltips_set_tip(tooltips, button, "... the 'lowering' mode... matching lines will be displayed in INSENSITIVE color... (see gtkrc) ... ", "... the 'lowering' mode... matching lines will be displayed in INSENSITIVE color... (see gtkrc) ...");
  gtk_table_attach(GTK_TABLE(table), button, 1, 2, 2, 3,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & LOWER )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_LOWER, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) LOWER );  

  button = gtk_check_button_new_with_label ( "Hide");
  gtk_tooltips_set_tip(tooltips, button, "... the 'hiding' mode, matching lines will be hidden ... ", "... the 'hiding' mode, matching lines will be hidden ...");
  gtk_table_attach(GTK_TABLE(table), button, 2, 3, 2, 3,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & HIDE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_HIDE, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) HIDE );  
  

  button = gtk_check_button_new_with_label ( "Alert");
  gtk_tooltips_set_tip(tooltips, button, "... the 'alert' mode, matching lines will trigger alert ... ", "... the 'alert' mode, matching lines will trigger alert ...");
  gtk_table_attach(GTK_TABLE(table), button, 0, 1, 3, 4,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & ALERT )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_ALERT, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) ALERT );  

  button = gtk_check_button_new_with_label ( "Notice");
  gtk_tooltips_set_tip(tooltips, button, "... the 'notice' mode, matching lines will create popup ... ", "... the 'notice' mode, matching lines will create popup ... ");
  gtk_table_attach(GTK_TABLE(table), button, 1, 2, 3, 4,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & NOTICE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_NOTICE, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) NOTICE );  

  button = gtk_check_button_new_with_label ( "UnIconify");
  gtk_tooltips_set_tip(tooltips, button, "... the 'UnIconify' mode, matching lines will force Xlogmaster to uniconify... ", "... the 'UnIconify' mode, matching lines will force Xlogmaster to uniconify ... ");
  gtk_table_attach(GTK_TABLE(table), button, 2, 3, 3, 4,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & UNICONIFY )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_UNICONIFY, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) UNICONIFY );

  button = gtk_check_button_new_with_label ( "Execute:");
  gtk_tooltips_set_tip(tooltips, button, "... the 'Execute' mode, matching lines will trigger execution of program ...", "... the 'Execute' mode, matching lines will trigger execution of program ...");
  gtk_table_attach(GTK_TABLE(table), button, 0, 1, 4, 5,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & EXECUTE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_EXECUTE, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) EXECUTE );

  /*
    Attach the signal handler AFTER everything is set up, otherwise
    it will call the function when stuff isn't set up properly...
  */
  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_RAISE);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_LOWER);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  
  
  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_HIDE);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  
  
  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_ALERT);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_NOTICE);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_UNICONIFY);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_EXECUTE);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  gtk_widget_show (button);  
  
/*}}}*/

/*{{{  Editable-Strings  */
  gchar* string = "";
  if ( filter != NULL )
    if (filter[0] != NULL ) string = filter[0]->string;
  GtkWidget* label = gtk_label_new( " Pattern string:" );
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_table_attach(GTK_TABLE(table), label, 0, 3, 0, 1,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_widget_show(label);
  GtkWidget* text = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(text), string);
  gtk_entry_set_editable (GTK_ENTRY(text),TRUE);
  gtk_table_attach(GTK_TABLE(table), text, 0, 3, 1, 2,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_tooltips_set_tip(tooltips, text, "... pattern string to search for ... may contain wildcards ...", "... pattern string to search for ... may contain wildcards ...");
  gtk_widget_show(text);
  gtk_object_set_data( GTK_OBJECT( box ), FILTER_STRING, (GtkWidget*) text);
  gtk_object_set_data( GTK_OBJECT( box ), FILTER_STRING_LABEL, (GtkWidget*) label);
  gtk_signal_connect (GTK_OBJECT (text), "activate",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );

  /* the execution line */
  if ( filter != NULL )
    if (filter[0] != NULL ) string = filter[0]->execline;
  if ( string == NULL ) string ="";
  text = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(text), string);
  gtk_entry_set_editable (GTK_ENTRY(text),TRUE);
  gtk_table_attach(GTK_TABLE(table), text, 1, 3, 4, 5,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_tooltips_set_tip(tooltips, text, "... program with parameters to execute on match. The following variables are defined:\n%F: absolute path to file [= $XLM_FILE]\n%H: helptext of entry [= $XLM_HELP]\n%L: line that triggered the execution [= $XLM_LINE]\n%M: mode of entry (TAIL/CAT) [= $XLM_MODE]\n%N: name of entry [= $XLM_NAME]\notherwise use like usual command and commandline...", "... program with parameters to execute on match. The following variables are defined:\n%F: absolute path to file [= $XLM_FILE]\n%H: helptext of entry [= $XLM_HELP]\n%L: line that triggered the execution [= $XLM_LINE]\n%M: mode of entry (TAIL/CAT) [= $XLM_MODE]\n%N: name of entry [= $XLM_NAME]\notherwise use like usual command and commandline...");
  gtk_widget_show(text);
  gtk_object_set_data( GTK_OBJECT( box ), FILTER_STRING_EXECUTE, (GtkWidget*) text);
  gtk_signal_connect (GTK_OBJECT (text), "activate",
		      GTK_SIGNAL_FUNC (mode_change), (gpointer) box );
  
/*}}}*/

  GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
				  GTK_POLICY_AUTOMATIC,
				  GTK_POLICY_AUTOMATIC);
  gtk_box_pack_start(GTK_BOX(hbox), scrolled_window, TRUE, TRUE, 0);
  gtk_widget_show(scrolled_window);
  gtk_widget_set_usize( GTK_WIDGET (scrolled_window), 110, 60);
  GtkWidget* list =  gtk_list_new();
  gtk_widget_show(list);
  gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_BROWSE);
  gtk_container_add(GTK_CONTAINER(scrolled_window), list);
  gtk_object_set_data( GTK_OBJECT( box ), FILTER_LIST, (GtkWidget*) list);
  gtk_object_set_data( GTK_OBJECT( list ), MENU_BOX, (GtkWidget*) box);

  GtkWidget* list_item;

  if ( filter != NULL ){
    int i = 0;
    while( filter[i] != NULL ){
      Filter* tmp = new Filter;
      tmp->init(filter[i]->string, filter[i]->mode);
      if ( filter[i]->execline != NULL ){
	tmp->execline = new gchar[strlen(filter[i]->execline)+1];
	strcpy(tmp->execline, filter[i]->execline);
      }
      char* listlabel = merge_label( get_list_label(tmp), tmp->string );
      list_item = gtk_list_item_new_with_label (listlabel);
      delete listlabel;
      gtk_widget_show (list_item);
      gtk_signal_connect (GTK_OBJECT (list_item), "destroy",
			  GTK_SIGNAL_FUNC (destroy_filter_entry), (gpointer) list);
      gtk_object_set_data( GTK_OBJECT( list_item ), FILTER_LIST_ITEM_DATA, (gpointer) tmp);
      gtk_container_add (GTK_CONTAINER(list), list_item); 
      i++;
    }
    if ( i != 0 ){
      gtk_list_select_item(GTK_LIST(list), 0);
      gtk_widget_realize(list);
      GtkWidget* active_item = (GtkWidget*) GTK_LIST(list)->selection->data;
      Filter* afilter = (Filter*) gtk_object_get_data( GTK_OBJECT( active_item ), FILTER_LIST_ITEM_DATA );
      gtk_object_set_data( GTK_OBJECT( list ), FILTER_LIST_LAST_ACTIVE, (gpointer) afilter);
    } else filter_set_sensitive(box, FALSE);
  } else filter_set_sensitive(box, FALSE);

  gtk_signal_connect (GTK_OBJECT (list), "select_child",
		      GTK_SIGNAL_FUNC (filter_item_select), (GtkWidget*) list );

  updating = FALSE;  

  gtk_widget_realize(box);
  gtk_widget_grab_focus(button);
  return list;
}
void mode_change(GtkWidget *widget, gpointer *data){
  if ( updating == TRUE ) return;
  gchar* string;
  gint mode;
  gint clicked = (gint) gtk_object_get_data( GTK_OBJECT( widget ), FILTER_BUTTON_MODE );
  GtkWidget* box = (GtkWidget*) data;
  GtkWidget* list = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_LIST);
  GList* selection = GTK_LIST(list)->selection;
  GtkWidget* active_item;
  if ( selection != NULL ) active_item = (GtkWidget*) selection->data;
  else {
    gtk_list_select_item(GTK_LIST(list), 0);
    return;
  }
  Filter* filter = 
    (Filter*) gtk_object_get_data( GTK_OBJECT( active_item ), FILTER_LIST_ITEM_DATA );

  filter->mode = NO_FILTER;

  GtkWidget* button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_RAISE);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= RAISE;
  
  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_LOWER);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= LOWER;

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_HIDE);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= HIDE;

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_ALERT);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= ALERT;

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_NOTICE);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= NOTICE;

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_UNICONIFY);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= UNICONIFY;

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_EXECUTE);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= EXECUTE;

  /* now legalize the settings - there may only be one of the RAISE/LOWER/HIDES */
  filter->mode = legalize(filter->mode, clicked);

  filter_item_select(GTK_LIST(list), active_item); // store text changes

  string = merge_label(get_list_label(filter), filter->string);

  gint position = gtk_list_child_position(GTK_LIST(list), active_item);

  gtk_object_set_data( GTK_OBJECT( list ), FILTER_LIST_LAST_ACTIVE, (gpointer) filter);
  GList* clist = gtk_container_children(GTK_CONTAINER(active_item));
  GtkWidget* label = (GtkWidget*) clist->data;
  gtk_label_set( GTK_LABEL(label), string);

  gtk_list_unselect_child(GTK_LIST(list), active_item);
  position_child(list, active_item);
  gtk_list_select_child(GTK_LIST(list), active_item);

  delete string;
  return;
}
void filter_item_select(GtkList* list, GtkWidget* child){
  GList* selection = GTK_LIST(list)->selection;
  GtkWidget* active_item;
  if ( selection != NULL ) active_item = (GtkWidget*) selection->data;
  else {
    gtk_list_select_item(GTK_LIST(list), 0);
    return;
  }
  GtkWidget* box = (GtkWidget*)
    gtk_object_get_data( GTK_OBJECT( list ), MENU_BOX );  
  GtkWidget* text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING );
  GtkWidget* exec_text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_EXECUTE );
  /* first save string - the user might have changed it */
  Filter* filter = (Filter*)
    gtk_object_get_data( GTK_OBJECT( list ), FILTER_LIST_LAST_ACTIVE );  
  if ( filter != NULL ){
    gchar* string = gtk_entry_get_text(GTK_ENTRY(text));
    gint mode = filter->mode;
    filter->purge();
    filter->init(string, mode);

    string = gtk_entry_get_text(GTK_ENTRY(exec_text));    
    if ( filter->mode & EXECUTE ){
      filter->execline = new gchar[strlen(string)+1];
      strcpy(filter->execline, string);
    }
    
  }

  /* now set the fields to the new entry */
  filter = (Filter*) gtk_object_get_data( GTK_OBJECT( active_item ), FILTER_LIST_ITEM_DATA );  
  update_filter_fields(filter, box);

  gtk_object_set_data( GTK_OBJECT( list ), FILTER_LIST_LAST_ACTIVE, (gpointer) filter); 
}
void filter_add(GtkWidget *widget, gpointer *data){
  GtkWidget* box = (GtkWidget*) data;
  GtkWidget* list = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_LIST );
  GtkWidget* text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING );  
 
  Filter* filter = new Filter;
  filter->init("<enter string here>", RAISE);
  char* listlabel = merge_label(get_list_label(filter), filter->string);
  GtkWidget* list_item = gtk_list_item_new_with_label (listlabel);
  delete listlabel;
  gtk_object_set_data( GTK_OBJECT( list_item ), FILTER_LIST_ITEM_DATA, (gpointer) filter);
  gtk_widget_show (list_item);
  gtk_signal_connect (GTK_OBJECT (list_item), "destroy",
		      GTK_SIGNAL_FUNC (destroy_filter_entry), (gpointer) list);

  if ( GTK_LIST(list)->selection != NULL ){
    gtk_container_add (GTK_CONTAINER(list), list_item);
  } else {
    filter_set_sensitive(box, TRUE);
    gtk_container_add (GTK_CONTAINER(list), list_item);
    update_filter_fields(filter, box);
    gtk_object_set_data( GTK_OBJECT( list ), FILTER_LIST_LAST_ACTIVE, (gpointer) filter);
  }

  position_child(list, list_item);
  gtk_list_select_child(GTK_LIST(list), list_item);
  
}
void filter_delete(GtkWidget *widget, gpointer *data){
  GtkWidget* box = (GtkWidget*) data;
  GtkWidget* list = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_LIST );
  GtkWidget* text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING );  
  GtkWidget* exec_text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_EXECUTE );
  GList* selection = GTK_LIST(list)->selection;
  GtkWidget* active_item;
  if ( selection != NULL ) active_item = (GtkWidget*) selection->data;
  else {
    gtk_list_select_item(GTK_LIST(list), 0);
    return;
  }

  gint position = gtk_list_child_position(GTK_LIST(list), active_item); 

  gtk_list_unselect_child(GTK_LIST(list), active_item);
  gtk_container_remove(GTK_CONTAINER(list), active_item);

  if ( position > 0 ) position--;
  gtk_list_select_item(GTK_LIST(list), position);

  if ( GTK_LIST(list)->selection == NULL ){
    gtk_entry_set_text(GTK_ENTRY(text), "");
    gtk_entry_set_text(GTK_ENTRY(exec_text), "");
    filter_set_sensitive(box, FALSE);
  }
}
void position_child(GtkWidget* list, GtkWidget* child){
  if ( updating == TRUE ) return;

  GList* glist = g_list_alloc();
  glist->next = NULL;
  glist->prev = NULL;
  glist->data = (gpointer) child;
  gtk_widget_ref (child);
  gtk_list_remove_items(GTK_LIST(list), glist);

  gint position = 0;

  GList* elements = GTK_LIST(list)->children;
  elements = g_list_first(elements);
  guint length = g_list_length(elements);

  Filter* filter = (Filter*) 
    gtk_object_get_data( GTK_OBJECT( child ), FILTER_LIST_ITEM_DATA );
  gint child_mode = filter->mode & CLASS0_MASK;

  for ( gint x = 0 ; x < length ; x++ ){
    GtkWidget* current_obj = (GtkWidget*) elements->data;
    filter = (Filter*) 
      gtk_object_get_data( GTK_OBJECT( current_obj ), FILTER_LIST_ITEM_DATA );

    gint curr_mode = filter->mode & CLASS0_MASK;
    
    if ( ( x == 0 ) && child_mode < curr_mode ) position = 0;
    else if ( child_mode >= curr_mode ) position = x+1;
    
    elements = elements->next;
  }
  
  gtk_list_insert_items(GTK_LIST(list), glist, position);
  gtk_widget_unref (child);
  gtk_widget_queue_draw(list);

  return;
}
void destroy_filter_entry(GtkWidget *widget, gpointer *data){
  GtkWidget* list = (GtkWidget*) data;
  Filter* filter = (Filter*) 
    gtk_object_get_data( GTK_OBJECT( widget ), FILTER_LIST_ITEM_DATA );
  gtk_object_set_data( GTK_OBJECT( list ), FILTER_LIST_LAST_ACTIVE, (gpointer) NULL);
  delete filter;
}
void update_filter_fields(Filter* filter, GtkWidget* box){
  updating = TRUE;
  GtkWidget* button;
  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_RAISE );
  if ( filter->mode & RAISE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);

  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_LOWER );
  if ( filter->mode & LOWER )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);
  
  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_HIDE );
  if ( filter->mode & HIDE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);
  
  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_ALERT );
  if ( filter->mode & ALERT )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);
  
  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_NOTICE );
  if ( filter->mode & NOTICE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);
  
  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_UNICONIFY );
  if ( filter->mode & UNICONIFY )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);

  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_EXECUTE );
  if ( filter->mode & EXECUTE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);
  
  GtkWidget* text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING );
  gtk_entry_set_text(GTK_ENTRY(text), filter->string);

  GtkWidget* exec_text = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_EXECUTE );
  if ( filter->execline != NULL ) gtk_entry_set_text(GTK_ENTRY(exec_text), filter->execline);
  else gtk_entry_set_text(GTK_ENTRY(exec_text), "");
  
  if ( filter->mode & EXECUTE )
    gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_EXECUTE),
			     TRUE);
  else
    gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_EXECUTE),
			     FALSE);
  
  updating = FALSE;
}
void filter_set_sensitive(GtkWidget* box, gint sensitive){
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_RAISE),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_LOWER),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_HIDE),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_ALERT),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_NOTICE),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_UNICONIFY),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_EXECUTE),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_EXECUTE),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_STRING_LABEL),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_DELETE),
			   sensitive);
}
char* get_list_label(Filter* tmp){
  char* label = new char[40];
  gint x = 0;
  label[x++] = '[';

  if ( tmp->mode & RAISE )
    label[x++] = 'R';
  else if ( tmp->mode & LOWER )
    label[x++] = 'L';
  else if ( tmp->mode & HIDE )
    label[x++] = 'H';
  else label[x++] = ' ';
  
  if ( tmp->mode & ALERT )
    label[x++] = 'A';
  else label[x++] = ' ';
  
  if ( tmp->mode & NOTICE )
    label[x++] = 'N';
  else label[x++] = ' ';
  
  if ( tmp->mode & UNICONIFY )
    label[x++] = 'U';
  else label[x++] = ' ';
  
  if ( tmp->mode & EXECUTE )
    label[x++] = 'E';
  else label[x++] = ' ';
  
  label[x++] = ']';
  label[x++] = 0;
  return label;
}
char* merge_label(char* label1, char* label2){
  char* result = new char [strlen(label1) + strlen(label2) + 6];
  int x,y;
  x = y = 0;

  while (label1[y] != 0 ) result[x++] = label1[y++];

  result[x++] = ' ';
  result[x++] = '[';

  y = 0;
  while (label2[y] != 0 ) result[x++] = label2[y++];

  result[x++] = ']';
  result[x] = 0;

  delete label1; // this one comes directly out of get_list_label
  return result;
}
/*}}}*/
