/*

  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 "../import/import.h"
#include "logclass.H"
#include "menu.H"
#include "extern.H"

/*}}}*/

/*{{{  Create Menu  */
/*
  This function is called during initialisation to create
  the popup 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), 
			     NULL );
  gtk_signal_connect_object( GTK_OBJECT(load_config), "activate",
			     GTK_SIGNAL_FUNC(load_conf_proc), 
			     NULL );
  gtk_signal_connect_object( GTK_OBJECT(save_config), "activate",
			     GTK_SIGNAL_FUNC(save_conf_proc), 
			     NULL );
  gtk_signal_connect_object( GTK_OBJECT(customize_entry), "activate",
			     GTK_SIGNAL_FUNC(customize_entry_proc), 
			     NULL );
  gtk_signal_connect_object( GTK_OBJECT(quit_menu), "activate",
			     GTK_SIGNAL_FUNC(quit), 
			     NULL );

  // 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 == 2 )
    {      
      hide_show_buttons_proc();
      
      return TRUE;
    }

  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;
}
/*}}}*/

/*{{{  hide_show_buttons procedure  */
/* 
   This function toggles the buttonbox in the main window to be
   hidden or shown (toggle).
   It keeps the lower border of the text scrollbar on the same relative position
   to the end - everything else would probably be pretty annoying.
*/
void 
hide_show_buttons_proc()
{
  GtkWidget* bbox = (GtkWidget*) gtk_object_get_data( GTK_OBJECT(window), BUTTONBOX);  

  /* memorize old scrollbar position (lower border) relative to end */
  GtkAdjustment* ver_text_adj = (GtkAdjustment*) ( GTK_RANGE(textscrollbar)->adjustment );
  gfloat old_position = ver_text_adj->upper - ( ver_text_adj->value + ver_text_adj->page_size );
  
  if ( buttons_shown == TRUE )
    {
      gtk_widget_hide( bbox );
      buttons_shown = FALSE;
    } 
  else 
    {
      gtk_widget_show( bbox );
      buttons_shown = TRUE;
    }
  
  gtk_widget_realize(window);
  gtk_widget_realize(textwindow);
  gtk_widget_map(textwindow);
  gtk_widget_realize(textscrollbar);
  gtk_widget_map(textscrollbar);

  /* Now put scrollbar on same position relative to end */
  gtk_adjustment_set_value(ver_text_adj, 
			   ver_text_adj->upper - old_position - ver_text_adj->page_size);

}
/*}}}*/

/*{{{  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();
      return;
    }
  
  /* 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;

  fillups = 0;
  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(entry[i]->filename,
		entry[i]->buttontext,
		entry[i]->help,
		entry[i]->interval,
		entry[i]->mode,
		(Filter** )(entry[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 ( guint 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));

  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  */
/*
  This routine creates the filter menu part on each notebook page
*/
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;

  /*
    CLASS0 Filter buttons
  */

  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 );  

  /*
    CLASS1 Filter buttons
  */

  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 );

  /*
    special mode buttons
  */
  button = gtk_check_button_new_with_label ( "Invert");
  gtk_tooltips_set_tip(tooltips, button, "...invert sense of matching. If activated non-matching lines will trigger filter...", "...invert sense of matching. If activated non-matching lines will trigger filter...");
  gtk_table_attach(GTK_TABLE(table), button, 2, 3, 0, 1,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & INVERT )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_INVERT, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) INVERT );  
  
  button = gtk_check_button_new_with_label ( "Case-sensitive");
  gtk_tooltips_set_tip(tooltips, button, "...if activated matching will be performed case-sensitive...", "...if activated matching will be performed case-sensitive...");
  gtk_table_attach(GTK_TABLE(table), button, 1, 2, 0, 1,
                   GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  if ( mode & CASE_SENSITIVE )
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  else
    gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), FALSE);
  gtk_object_set_data( GTK_OBJECT(box), FILTER_MODE_CASE_SENSITIVE, (GtkWidget*) button);
  gtk_object_set_data( GTK_OBJECT(button), FILTER_BUTTON_MODE, (gpointer) CASE_SENSITIVE );  
  
  /*
    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);  

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_INVERT);
  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_CASE_SENSITIVE);
  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( " REGEX:" );
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_table_attach(GTK_TABLE(table), label, 0, 1, 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, "...a standard REGEX (see GNU regex manual) to be used for this filter, matching lines will trigger the filter...", "...a standard REGEX (see GNU regex manual) to be used for this filter, matching lines will trigger the filter...");
  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;
}
/*
  This function gets called when either the mode of the filter has been
  changed or the string has been entered (RETURN has been hit in
  GtkEntry) so basically every time the information needs to be
  updated.
*/
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;

  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_INVERT);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= INVERT;
  
  button = (GtkWidget*) 
    gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_CASE_SENSITIVE);
  if (GTK_TOGGLE_BUTTON (button)->active) filter->mode |= CASE_SENSITIVE;

  /* 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);

  /*
    Now test-calculate the REGEX to see whether it is correct
    error reporting is done in the subroutine so we don't need to care
    for it.
  */
  Filter* ftmp = new Filter;
  ftmp->init(filter->string, filter->mode | COMPILE_REGEX );
  delete ftmp;


  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 ( guint 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);

  button = (GtkWidget*) gtk_object_get_data( GTK_OBJECT( box ), FILTER_MODE_INVERT );
  if ( filter->mode & INVERT )
    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_CASE_SENSITIVE );
  if ( filter->mode & CASE_SENSITIVE )
    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_MODE_INVERT),
			   sensitive);
  gtk_widget_set_sensitive((GtkWidget*) gtk_object_get_data( GTK_OBJECT( box), FILTER_MODE_CASE_SENSITIVE),
			   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++] = '{';
  if ( tmp->mode & CASE_SENSITIVE )
    label[x++] = 'C';
  if ( tmp->mode & INVERT )
    label[x++] = 'I';
  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++] = '[';

  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;
}
/*}}}*/
