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

server-ui.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2002  Charles Kerr <charles@rebelbase.com>
 *
 * 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; version 2 of the License.
 *
 * 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
 */

/*********************
**********************  Includes
*********************/

#include <config.h>

#include <stdlib.h>
#include <string.h>

#include <glib.h>
#include <gtk/gtk.h>

#include <pan/base/pan-i18n.h>
#include <pan/base/pan-glib-extensions.h>
#include <pan/base/pan-config.h>
#include <pan/base/serverlist.h>

#include <pan/pan-file-entry.h>
#include <pan/queue.h>
#include <pan/server-ui.h>
#include <pan/server-menu-ui.h>
#include <pan/util.h>

/*********************
**********************  Defines / Enumerated types
*********************/

/*********************
**********************  Macros
*********************/

/*********************
**********************  Structures / Typedefs
*********************/

typedef struct
{
      Server * server;
      gboolean new_server;

      GtkWidget * dialog;

      GtkWidget * name_entry;
      GtkWidget * address_entry;
      GtkWidget * port_spin;
      GtkWidget * connection_limit_spin;

      GtkWidget * auth_checkbox;
      GtkWidget * auth_username_label;
      GtkWidget * auth_username_entry;
      GtkWidget * auth_password_label;
      GtkWidget * auth_password_entry;

      GtkWidget * newsrc_checkbox;
      GtkWidget * newsrc_filename_label;
      GtkWidget * newsrc_filename_entry;
}
ServerEditDialog;

enum
{
      SERVER_NAME_COLUMN,
      SERVER_DATA_COLUMN,
      N_COLUMNS
};

typedef struct
{
      GtkWidget * server_tree_view;
      GtkWidget * dialog;
      GtkListStore * servers_store;
      GtkWidget * remove_button;
      GtkWidget * edit_button;
}
ServerListDialog;

/*********************
**********************  Private Function Prototypes
*********************/

/*********************
**********************  Variables
*********************/

/***********
************  Extern
***********/

extern GtkTooltips * ttips;

/***********
************  Public
***********/

/***********
************  Private
***********/

/*********************
**********************  BEGINNING OF SOURCE
*********************/

/************
*************  EDIT DIALOG
************/

static void
edit_dialog_sensitize_newsrc (ServerEditDialog * d, gboolean enabled)
{
      gtk_widget_set_sensitive (d->newsrc_filename_label, enabled);
      gtk_widget_set_sensitive (d->newsrc_filename_entry, enabled);
}

static void
edit_dialog_newsrc_toggled_cb (GtkToggleButton * tb, gpointer user_data)
{
      ServerEditDialog * d = (ServerEditDialog*) user_data;
      gboolean checked = gtk_toggle_button_get_active (tb);
      edit_dialog_sensitize_newsrc (d, checked);
}

static void
edit_dialog_sensitize_authorization (ServerEditDialog * d, gboolean enabled)
{
      gtk_widget_set_sensitive (d->auth_username_label, enabled);
      gtk_widget_set_sensitive (d->auth_username_entry, enabled);
      gtk_widget_set_sensitive (d->auth_password_label, enabled);
      gtk_widget_set_sensitive (d->auth_password_entry, enabled);
}

static void
edit_dialog_auth_toggled_cb (GtkToggleButton * tb, gpointer user_data)
{
      ServerEditDialog * d = (ServerEditDialog*) user_data;
      gboolean checked = gtk_toggle_button_get_active (tb);
      edit_dialog_sensitize_authorization (d, checked);
}

static void
edit_dialog_populate (ServerEditDialog * d, Server * s)
{
      GtkAdjustment * a;
      const char * cpch;

      /* sanity clause */
      g_return_if_fail (d!=NULL);
      g_return_if_fail (GTK_IS_WIDGET(d->dialog));
      g_return_if_fail (server_is_valid(s));

      /* internal bits */
      d->server = s;

      /* server section */
      cpch = s->name.str;
      gtk_entry_set_text (GTK_ENTRY(d->name_entry), cpch ? cpch : "");
      cpch = s->address.str;
      gtk_entry_set_text (GTK_ENTRY(d->address_entry), cpch ? cpch : "");
      a = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON(d->port_spin));
      gtk_adjustment_set_value (a, s->port);
      a = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON(d->connection_limit_spin));
      gtk_adjustment_set_value (a, s->max_connections);

      /* authorization */
      cpch = s->username.str;
      gtk_entry_set_text (GTK_ENTRY(d->auth_username_entry), cpch ? cpch : "");
      cpch = s->password.str;
      gtk_entry_set_text (GTK_ENTRY(d->auth_password_entry), cpch ? cpch : "");
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->auth_checkbox), s->need_auth);
      edit_dialog_sensitize_authorization (d, s->need_auth);

      /* newsrc */
      pan_file_entry_set (d->newsrc_filename_entry, s->newsrc_filename.str);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(d->newsrc_checkbox), s->use_newsrc);
      edit_dialog_sensitize_newsrc (d, s->use_newsrc);
}

static void
edit_dialog_populate_server (ServerEditDialog * d, Server * s, GError ** err)
{
      gboolean b;
      PString name;
      const char * cpch;

      /* sanity clause */
      g_return_if_fail (d!=NULL);
      g_return_if_fail (GTK_IS_WIDGET(d->dialog));
      g_return_if_fail (server_is_valid(s));
      g_return_if_fail (err!=NULL);
      g_return_if_fail (*err==NULL);

      /* server section */
      name = pstring_shallow (gtk_entry_get_text (GTK_ENTRY(d->name_entry)), -1);
      server_set_name (s, &name, err);
      cpch = gtk_entry_get_text (GTK_ENTRY(d->address_entry));
      pstring_set (&s->address, cpch, -1);
      pstring_strstrip (&s->address);
      if (!s->address.len) {
            *err = g_error_new (g_quark_from_string("server-ui"), 1, _("You must specify an address."));
            return;
      }
      s->port = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->port_spin));
      s->max_connections = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(d->connection_limit_spin));

      /* authorization */
      b = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->auth_checkbox));
      s->need_auth = b;
      cpch = gtk_entry_get_text (GTK_ENTRY(d->auth_username_entry));
      pstring_set (&s->username, cpch, -1);
      pstring_strstrip (&s->username);
      if (s->need_auth && !s->username.len) {
            *err = g_error_new (g_quark_from_string("server-ui"), 1, _("You must specify a username or disable authorization."));
            return;
      }
      cpch = gtk_entry_get_text (GTK_ENTRY(d->auth_password_entry));
      pstring_set (&s->password, cpch, -1);
      if (s->need_auth && !s->password.len) {
            *err = g_error_new (g_quark_from_string("server-ui"), 1, _("You must specify a password or disable authorization."));
            return;
      }

      /* newsrc */
      b = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(d->newsrc_checkbox));
      s->use_newsrc = b;
      cpch = pan_file_entry_get (d->newsrc_filename_entry);
      pstring_set (&s->newsrc_filename, cpch, -1);
      pstring_strstrip (&s->newsrc_filename);
      if (s->use_newsrc && !s->newsrc_filename.len) {
            *err = g_error_new (g_quark_from_string("server-ui"), 1, _("You must specify a .newsrc filename or disable newsrc support."));
            return;
      }
}

static void
server_edit_response_cb (GtkDialog * w, int response, gpointer user_data)
{
      gboolean destroy = TRUE;
      ServerEditDialog * d = (ServerEditDialog*) user_data;

      if (response == GTK_RESPONSE_OK)
      {
            GError * err = NULL;
            edit_dialog_populate_server (d, d->server, &err);

            if (d->new_server && err==NULL)
                  serverlist_add_server (d->server, &err);

            if (err == NULL)
                  queue_wakeup (); /* wake up the queue in case user changed "max connections" field */
            else {
                  pan_error_dialog_parented (GTK_WINDOW(d->dialog), "%s", err->message);
                  g_error_free (err);
                  destroy = FALSE;
            }

      }
      else /* cancel, destroy */
      {
            if (d->new_server)
                  pan_object_unref (PAN_OBJECT(d->server));
      }

      if (destroy)
            gtk_widget_destroy (GTK_WIDGET(w));
}

static GtkWidget*
server_edit_dialog (GtkWidget * window, Server * server)
{
      GtkObject * a;
      GtkWidget * dialog;
      GtkWidget * w;
      GtkWidget * t;
      ServerEditDialog * d;
      int row;
      const int DEFAULT_MAX_PER_SERVER = 4;

      d = g_new0 (ServerEditDialog, 1);

      /* create the dialog */
      dialog = gtk_dialog_new_with_buttons (_("Pan: Edit Server"),
                                            GTK_WINDOW(window),
                                            GTK_DIALOG_DESTROY_WITH_PARENT,
                                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                            GTK_STOCK_OK, GTK_RESPONSE_OK,
                                            NULL);
      d->dialog = dialog;
      g_object_set_data_full (G_OBJECT(dialog), "dialog", d, g_free);
      g_signal_connect (dialog, "response", G_CALLBACK(server_edit_response_cb), d);

      /**
      ***  workarea
      **/

      row = 0;
      t = pan_hig_workarea_create ();
      gtk_box_pack_start (GTK_BOX(GTK_DIALOG(d->dialog)->vbox), t, TRUE, TRUE, 0);
      pan_hig_workarea_add_section_title (t, &row, _("Server"));

            pan_hig_workarea_add_section_spacer (t, row, 5);

            w = d->name_entry = gtk_entry_new ();
            gtk_tooltips_set_tip (GTK_TOOLTIPS(ttips), w, _("Short name for Pan to show, e.g. \"mynewsserver\""), NULL);
            pan_hig_workarea_add_row (t, &row, _("_Name:"), w, NULL);

            w = d->address_entry = gtk_entry_new ();
            gtk_tooltips_set_tip (GTK_TOOLTIPS(ttips), w, _("The news server's actual address, e.g. \"news.mynewsserver.com\""), NULL);
            pan_hig_workarea_add_row (t, &row, _("_Address:"), w, NULL);

            a = gtk_adjustment_new (1.0, 1.0, ULONG_MAX, 1.0, 1.0, 1.0);
            w = d->port_spin = gtk_spin_button_new (GTK_ADJUSTMENT(a), 1.0, 0u);
            gtk_tooltips_set_tip (GTK_TOOLTIPS(ttips), w, _("The news server's port.  This is almost always 119."), NULL);
            pan_hig_workarea_add_row (t, &row, _("Por_t:"), w, NULL);

      pan_hig_workarea_add_section_divider (t, &row);
      pan_hig_workarea_add_section_title (t, &row, _("Connections"));

            pan_hig_workarea_add_section_spacer (t, row, 3);

            a = gtk_adjustment_new (1.0, 1.0, DEFAULT_MAX_PER_SERVER, 1.0, 1.0, 1.0);
            d->connection_limit_spin = w = gtk_spin_button_new (GTK_ADJUSTMENT(a), 1.0, 0u);
            pan_hig_workarea_add_row (t, &row, _("Connection _Limit:"), w, NULL);

      pan_hig_workarea_add_section_divider (t, &row);
      pan_hig_workarea_add_section_title (t, &row, _("Login"));

            pan_hig_workarea_add_section_spacer (t, row, 3);

            w = d->auth_checkbox = pan_hig_workarea_add_wide_checkbutton (t, &row, _("Server requires authori_zation"), FALSE);
            g_signal_connect (w, "toggled", G_CALLBACK(edit_dialog_auth_toggled_cb), d);

            w = d->auth_username_entry = gtk_entry_new ();
            d->auth_username_label = pan_hig_workarea_add_row (t, &row, _("_Username:"), w, NULL);

            w = d->auth_password_entry = gtk_entry_new ();
            gtk_entry_set_visibility (GTK_ENTRY(w), FALSE);
            d->auth_password_label = pan_hig_workarea_add_row (t, &row, _("_Password:"), w, NULL);

      pan_hig_workarea_add_section_divider (t, &row);
      pan_hig_workarea_add_section_title (t, &row, _("Newsrc"));

            pan_hig_workarea_add_section_spacer (t, row, 2);

            w = d->newsrc_checkbox = pan_hig_workarea_add_wide_checkbutton (t, &row, _("Us_e .newsrc file"), FALSE);
            g_signal_connect (w, "toggled", G_CALLBACK(edit_dialog_newsrc_toggled_cb), d);

            w = d->newsrc_filename_entry = pan_file_entry_new (_("Select .newsrc File"));
            gtk_widget_set_usize (w, 300u, 0u); 
            d->newsrc_filename_label = pan_hig_workarea_add_row (t, &row, _("_Filename:"), w, pan_file_entry_gtk_entry(w));

      if (server == NULL) {
            d->new_server = TRUE;
            server = server_new ();
            pstring_set (&server->name, _("New Server"), -1);
            server->port = 119;
      }

      edit_dialog_populate (d, server);
      gtk_widget_show_all (d->dialog);
      return d->dialog;
}


/************
*************  LIST DIALOG
************/

static Server*
get_selected_server (ServerListDialog * d)
{
      Server * retval = NULL; 
      GtkTreeSelection * selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (d->server_tree_view));
      GtkTreeIter iter;
        GtkTreeModel *model;

        if (gtk_tree_selection_get_selected (selection, &model, &iter))
                gtk_tree_model_get (model, &iter, SERVER_DATA_COLUMN, &retval, -1);

      return retval;
}

static void
button_refresh (ServerListDialog * d)
{
      const gboolean have_sel = (get_selected_server (d) != NULL);

      pan_lock ();
      gtk_widget_set_sensitive (d->edit_button, have_sel);
      gtk_widget_set_sensitive (d->remove_button, have_sel);
      pan_unlock ();
}

static GPtrArray*
get_public_server_array (void)
{
      int i;
      GPtrArray * a = g_ptr_array_new ();
      serverlist_get_servers (a);

      /* skip the internal folder... */
      for (i=0; i<a->len; ++i)
            if (pstring_equal (&INTERNAL_SERVER_NAME, &SERVER(g_ptr_array_index(a,i))->name))
                  break;
      if (i!=a->len)
            g_ptr_array_remove_index (a, i);

      return a;
}

static void
server_tree_view_refresh (ServerListDialog * d)
{
      GtkTreeSelection * selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (d->server_tree_view));
      gboolean found_selected = FALSE;
      GtkTreeIter selected_iter;
      Server * selected_server = get_selected_server (d);
      GPtrArray * a = get_public_server_array ();
      int i;

      pan_lock ();      
      gtk_list_store_clear (d->servers_store);
                  
      for (i=0; i<a->len; ++i)
      {
            GtkTreeIter iter;
            Server * server = SERVER (g_ptr_array_index (a, i));

            gtk_list_store_append (d->servers_store, &iter);
            gtk_list_store_set (d->servers_store, &iter,
                            SERVER_NAME_COLUMN, server->name.str,
                            SERVER_DATA_COLUMN, server,
                            -1);
            
            if (server == selected_server) {
                  found_selected = TRUE;
                  selected_iter = iter;
            }
      }

      if (found_selected)
            gtk_tree_selection_select_iter (selection, &selected_iter);

      pan_unlock ();

      g_ptr_array_free (a, TRUE);
}

/*****
******
*****/

static void
server_list_dialog_response_cb (GtkDialog * dialog, int response, gpointer user_data)
{
      gtk_widget_destroy (GTK_WIDGET(dialog));
}

static void
server_list_dialog_destroy_cb (GtkWidget * w, gpointer user_data)
{
      server_menu_update ();
}


/**
***  Add
**/

static void
remove_button_clicked_cb (GtkButton * button, gpointer data)
{
      ServerListDialog * d = (ServerListDialog*) data;
      Server * selected_server = get_selected_server (d);

      if (selected_server != NULL) {
            serverlist_remove_server (selected_server);
            server_tree_view_refresh (d);
            button_refresh (d);
      }
}

static void
server_edit_dialog_destroy_cb (GtkWidget * w, gpointer user_data)
{
      if (GTK_IS_WIDGET (user_data))
      {
            ServerListDialog * d = (ServerListDialog*) g_object_get_data (G_OBJECT(user_data), "dialog");
            server_tree_view_refresh (d);
      }
}

static void
add_button_clicked_cb (GtkButton * button, gpointer data)
{
      GtkWidget * list_dialog = GTK_WIDGET (data);
      GtkWidget * edit_dialog = server_edit_dialog (list_dialog, NULL);
      g_signal_connect (edit_dialog, "destroy", G_CALLBACK(server_edit_dialog_destroy_cb), list_dialog);
      gtk_widget_show_all (edit_dialog);
}

/**
***  Edit
**/

static void
edit_button_clicked_cb (GtkButton * button, gpointer user_data)
{
      GtkWidget * list_dialog = GTK_WIDGET (user_data);
      ServerListDialog * d = (ServerListDialog*) g_object_get_data (G_OBJECT(list_dialog), "dialog");
      Server * selected_server = get_selected_server (d);
      if (selected_server != NULL) {
            GtkWidget * edit_dialog = server_edit_dialog (list_dialog, selected_server);
            g_signal_connect (GTK_OBJECT(edit_dialog), "destroy", G_CALLBACK(server_edit_dialog_destroy_cb), list_dialog);
            gtk_widget_show_all (edit_dialog);
      }
}

static void
server_tree_view_row_activated_cb (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
{
      edit_button_clicked_cb (NULL, user_data); 
}

static void
server_tree_view_selection_changed_cb (GtkTreeSelection * selection, gpointer user_data)
{
      button_refresh ((ServerListDialog*)user_data);
}

/************
*************  PUBLIC
************/

GtkWidget*
server_dialog_new (GtkWindow * parent)
{
      GtkWidget * w;
      GtkWidget * hbox;
      GtkWidget * bbox;
      GtkTreeViewColumn *column;
      GtkTreeSelection * selection;
      GtkCellRenderer * renderer;
      GtkTooltips * tips = gtk_tooltips_new ();
      ServerListDialog * d = g_new0 (ServerListDialog, 1);

      /* dialog */
      w = d->dialog = gtk_dialog_new_with_buttons (_("Pan: Servers"),
                                                   parent,
                                                   GTK_DIALOG_DESTROY_WITH_PARENT,
                                                   GTK_STOCK_CLOSE, GTK_RESPONSE_OK,
                                                   NULL);
      gtk_window_set_policy (GTK_WINDOW(w), TRUE, TRUE, TRUE);
      g_signal_connect (GTK_OBJECT(w), "response", G_CALLBACK(server_list_dialog_response_cb), d);
      g_signal_connect (GTK_OBJECT(w), "destroy", G_CALLBACK(server_list_dialog_destroy_cb), d);
      g_object_set_data_full (G_OBJECT(w), "dialog", d, g_free);

      /* workarea */
      hbox = gtk_hbox_new (FALSE, GUI_PAD);
      gtk_container_set_border_width (GTK_CONTAINER(hbox), 12);
      gtk_box_pack_start (GTK_BOX(GTK_DIALOG(w)->vbox), hbox, TRUE, TRUE, 0);


      /* Create the list_store */
      d->servers_store = gtk_list_store_new (N_COLUMNS,
                                  G_TYPE_STRING,
                                  G_TYPE_POINTER);
      
      /* Create the tree_view */
      w = d->server_tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (d->servers_store));

      /* Add the column to the view */
      renderer = gtk_cell_renderer_text_new ();
      column = gtk_tree_view_column_new_with_attributes (_("Servers"), renderer,
                                             "text", SERVER_NAME_COLUMN,
                                             NULL);
      gtk_tree_view_column_set_sort_column_id (column, SERVER_NAME_COLUMN);
      gtk_tree_view_append_column (GTK_TREE_VIEW (d->server_tree_view), column);

      /* Set the selection mode */
      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (d->server_tree_view));
      gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
      
      /* Add callbacks */
      g_signal_connect (GTK_TREE_VIEW (d->server_tree_view), "row-activated",
                    G_CALLBACK (server_tree_view_row_activated_cb),
                    d->dialog);
      g_signal_connect (G_OBJECT (selection), "changed",
                    G_CALLBACK (server_tree_view_selection_changed_cb),
                    d);


        w = gtk_scrolled_window_new (NULL, NULL);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
      gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(w), GTK_SHADOW_IN);
      gtk_container_add (GTK_CONTAINER(w), d->server_tree_view);
      gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0);
      gtk_widget_set_usize (w, 300, 300);

      /* button box */
      bbox = gtk_vbox_new (FALSE, GUI_PAD_SMALL);
      gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 0);

      /* add button */
      w = gtk_button_new_from_stock (GTK_STOCK_ADD);
      gtk_box_pack_start (GTK_BOX (bbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Add a new server"), NULL);
      g_signal_connect (w, "clicked", G_CALLBACK(add_button_clicked_cb), d->dialog);

      /* edit button */
      w = gtk_button_new_from_stock (GTK_STOCK_OPEN);
      gtk_box_pack_start (GTK_BOX (bbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Edit the selected server"), NULL);
      g_signal_connect (w, "clicked", G_CALLBACK(edit_button_clicked_cb), d->dialog);
      d->edit_button = w;

      /* remove button */
      w = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
      gtk_box_pack_start (GTK_BOX (bbox), w, FALSE, FALSE, 0);
      gtk_tooltips_set_tip (tips, w, _("Remove the selected server"), NULL);
      g_signal_connect (w, "clicked", G_CALLBACK(remove_button_clicked_cb), d);
      d->remove_button = w;

      server_tree_view_refresh (d);
      button_refresh (d);
      return d->dialog;
}

Generated by  Doxygen 1.6.0   Back to index