]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkprinteroptionwidget.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkprinteroptionwidget.c
index fdc2e1dac55209389c771b80e717935acc2640c2..44c54adf7c5f265fb7f8bc9abd4191847cecbd64 100644 (file)
@@ -12,9 +12,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
 #include "gtkcelllayout.h"
 #include "gtkcellrenderertext.h"
 #include "gtkcombobox.h"
-#include "gtkfilechooserbutton.h"
+#include "gtkfilechooserdialog.h"
 #include "gtkimage.h"
 #include "gtklabel.h"
 #include "gtkliststore.h"
 #include "gtkradiobutton.h"
 #include "gtkstock.h"
-#include "gtktable.h"
+#include "gtkgrid.h"
 #include "gtktogglebutton.h"
 #include "gtkorientable.h"
 #include "gtkprivate.h"
 #define GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE(o)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidgetPrivate))
 
+/* This defines the max file length that the file chooser
+ * button should display. The total length will be
+ * FILENAME_LENGTH_MAX+3 because the truncated name is prefixed
+ * with "...".
+ */
+#define FILENAME_LENGTH_MAX 27
+
 static void gtk_printer_option_widget_finalize (GObject *object);
 
 static void deconstruct_widgets (GtkPrinterOptionWidget *widget);
-static void construct_widgets (GtkPrinterOptionWidget *widget);
-static void update_widgets (GtkPrinterOptionWidget *widget);
+static void construct_widgets   (GtkPrinterOptionWidget *widget);
+static void update_widgets      (GtkPrinterOptionWidget *widget);
+
+static gchar *trim_long_filename (const gchar *filename);
 
 struct GtkPrinterOptionWidgetPrivate
 {
   GtkPrinterOption *source;
   gulong source_changed_handler;
-  
+
   GtkWidget *check;
   GtkWidget *combo;
   GtkWidget *entry;
   GtkWidget *image;
   GtkWidget *label;
   GtkWidget *info_label;
-  GtkWidget *filechooser;
   GtkWidget *box;
+  GtkWidget *button;
+
+  /* the last location for save to file, that the user selected */
+  gchar *last_location;
 };
 
 enum {
@@ -88,7 +98,7 @@ static void gtk_printer_option_widget_get_property (GObject      *object,
                                                    GValue       *value,
                                                    GParamSpec   *pspec);
 static gboolean gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
-                                                             gboolean  group_cycling);
+                                                            gboolean   group_cycling);
 
 static void
 gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
@@ -203,6 +213,8 @@ gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
     return gtk_widget_mnemonic_activate (priv->combo, group_cycling);
   if (priv->entry)
     return gtk_widget_mnemonic_activate (priv->entry, group_cycling);
+  if (priv->button)
+    return gtk_widget_mnemonic_activate (priv->button, group_cycling);
 
   return FALSE;
 }
@@ -366,8 +378,8 @@ combo_box_set (GtkWidget   *combo,
   gtk_tree_model_foreach (model, set_cb, &set_data);
 }
 
-static char *
-combo_box_get (GtkWidget *combo)
+static gchar *
+combo_box_get (GtkWidget *combo, gboolean *custom)
 {
   GtkTreeModel *model;
   gchar *value;
@@ -377,7 +389,41 @@ combo_box_get (GtkWidget *combo)
 
   value = NULL;
   if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
-     gtk_tree_model_get (model, &iter, VALUE_COLUMN, &value, -1);
+    {
+      gtk_tree_model_get (model, &iter, VALUE_COLUMN, &value, -1);
+      *custom = FALSE;
+    }
+  else
+    {
+      if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (combo)))
+        {
+          value = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)))));
+          *custom = TRUE;
+        }
+
+      if (!value || !gtk_tree_model_get_iter_first (model, &iter))
+        return value;
+
+      /* If the user entered an item from the dropdown list manually, return
+       * the non-custom option instead. */
+      do
+        {
+          gchar *val, *name;
+          gtk_tree_model_get (model, &iter, VALUE_COLUMN, &val,
+                                            NAME_COLUMN, &name, -1);
+          if (g_str_equal (value, name))
+            {
+              *custom = FALSE;
+              g_free (name);
+              g_free (value);
+              return val;
+            }
+
+          g_free (val);
+          g_free (name);
+        }
+      while (gtk_tree_model_iter_next (model, &iter));
+    }
 
   return value;
 }
@@ -406,14 +452,6 @@ deconstruct_widgets (GtkPrinterOptionWidget *widget)
       priv->entry = NULL;
     }
 
-  /* make sure entry and combo are destroyed first */
-  /* as we use the two of them to create the filechooser */
-  if (priv->filechooser)
-    {
-      gtk_widget_destroy (priv->filechooser);
-      priv->filechooser = NULL;
-    }
-
   if (priv->image)
     {
       gtk_widget_destroy (priv->image);
@@ -446,64 +484,100 @@ check_toggled_cb (GtkToggleButton        *toggle_button,
 }
 
 static void
-filesave_changed_cb (GtkWidget              *button,
-                     GtkPrinterOptionWidget *widget)
+dialog_response_callback (GtkDialog              *dialog,
+                          gint                    response_id,
+                          GtkPrinterOptionWidget *widget)
 {
   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
-  gchar *uri, *file;
-  gchar *directory;
+  gchar *uri = NULL;
+  gchar *new_location = NULL;
 
-  file = g_filename_from_utf8 (gtk_entry_get_text (GTK_ENTRY (priv->entry)),
-                              -1, NULL, NULL, NULL);
-  if (file == NULL)
-    return;
+  if (response_id == GTK_RESPONSE_ACCEPT)
+    {
+      gchar *filename;
+      gchar *filename_utf8;
+      gchar *filename_short;
+
+      new_location = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+      filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+      filename_short = trim_long_filename (filename_utf8);
+      gtk_button_set_label (GTK_BUTTON (priv->button), filename_short);
+      g_free (filename_short);
+      g_free (filename_utf8);
+      g_free (filename);
+    }
 
-  /* combine the value of the chooser with the value of the entry */
-  g_signal_handler_block (priv->source, priv->source_changed_handler);  
+  gtk_widget_destroy (GTK_WIDGET (dialog));
 
-  directory = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (priv->combo));
+  if (new_location)
+    uri = new_location;
+  else
+    uri = priv->last_location;
 
-  if ((g_uri_parse_scheme (file) == NULL) && (directory != NULL))
+  if (uri)
     {
-      if (g_path_is_absolute (file))
-        uri = g_filename_to_uri (file, NULL, NULL);
-      else
-        {
-          gchar *path;
+      gtk_printer_option_set (priv->source, uri);
+      emit_changed (widget);
+    }
 
-#ifdef G_OS_UNIX
-          if (file[0] == '~' && file[1] == '/')
-            {
-              path = g_build_filename (g_get_home_dir (), file + 2, NULL);
-            }
-          else
-#endif
-            {
-              path = g_build_filename (directory, file, NULL);
-            }
+  g_free (new_location);
+  g_free (priv->last_location);
+  priv->last_location = NULL;
 
-          uri = g_filename_to_uri (path, NULL, NULL);
+  /* unblock the handler which was blocked in the filesave_choose_cb function */
+  g_signal_handler_unblock (priv->source, priv->source_changed_handler);
+}
 
-          g_free (path);
-        }
-    }
-  else
+static void
+filesave_choose_cb (GtkWidget              *button,
+                    GtkPrinterOptionWidget *widget)
+{
+  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
+  gchar *last_location = NULL;
+  GtkWidget *dialog;
+  GtkWindow *toplevel;
+
+  /* this will be unblocked in the dialog_response_callback function */
+  g_signal_handler_block (priv->source, priv->source_changed_handler);
+
+  toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
+  dialog = gtk_file_chooser_dialog_new (_("Select a filename"),
+                                        toplevel,
+                                        GTK_FILE_CHOOSER_ACTION_SAVE,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        _("_Select"), GTK_RESPONSE_ACCEPT,
+                                        NULL);
+
+  /* The confirmation dialog will appear, when the user clicks print */
+  gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), FALSE);
+
+  /* select the current filename in the dialog */
+  if (priv->source != NULL)
     {
-      if (g_uri_parse_scheme (file) != NULL)
-        uri = g_strdup (file);
-      else
-        uri = g_build_path ("/", gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (priv->combo)), file, NULL);
+      priv->last_location = last_location = g_strdup (priv->source->value);
+      if (last_location)
+        {
+          GFile *file;
+          gchar *basename;
+          gchar *basename_utf8;
+
+          gtk_file_chooser_select_uri (GTK_FILE_CHOOSER (dialog), last_location);
+          file = g_file_new_for_uri (last_location);
+          basename = g_file_get_basename (file);
+          basename_utf8 = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
+          gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), basename_utf8);
+          g_free (basename_utf8);
+          g_free (basename);
+          g_object_unref (file);
+        }
     }
-  if (uri)
-    gtk_printer_option_set (priv->source, uri);
 
-  g_free (uri);
-  g_free (file);
-  g_free (directory);
-
-  g_signal_handler_unblock (priv->source, priv->source_changed_handler);
-  emit_changed (widget);
+  g_signal_connect (dialog, "response",
+                    G_CALLBACK (dialog_response_callback), widget);
+  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+  gtk_window_present (GTK_WINDOW (dialog));
 }
 
 static gchar *
@@ -558,25 +632,29 @@ combo_changed_cb (GtkWidget              *combo,
   gchar *value;
   gchar *filtered_val = NULL;
   gboolean changed;
+  gboolean custom = TRUE;
 
   g_signal_handler_block (priv->source, priv->source_changed_handler);
   
-  value = combo_box_get (combo);
+  value = combo_box_get (combo, &custom);
 
-  /* handle some constraints */
-  switch (priv->source->type)
+  /* Handle constraints if the user entered a custom value. */
+  if (custom)
     {
-    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
-      filtered_val = filter_numeric (value, FALSE, FALSE, &changed);
-      break;   
-    case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
-      filtered_val = filter_numeric (value, TRUE, FALSE, &changed);
-      break;
-    case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
-      filtered_val = filter_numeric (value, TRUE, TRUE, &changed);
-      break;
-    default:
-      break;
+      switch (priv->source->type)
+        {
+        case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
+          filtered_val = filter_numeric (value, FALSE, FALSE, &changed);
+          break;
+        case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
+          filtered_val = filter_numeric (value, TRUE, FALSE, &changed);
+          break;
+        case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
+          filtered_val = filter_numeric (value, TRUE, TRUE, &changed);
+          break;
+        default:
+          break;
+        }
     }
 
   if (filtered_val)
@@ -727,12 +805,11 @@ construct_widgets (GtkPrinterOptionWidget *widget)
               gtk_entry_set_visibility (entry, FALSE); 
            }
         }
-       
 
       for (i = 0; i < source->num_choices; i++)
-         combo_box_append (priv->combo,
-                           source->choices_display[i],
-                           source->choices[i]);
+        combo_box_append (priv->combo,
+                          source->choices_display[i],
+                          source->choices[i]);
       gtk_widget_show (priv->combo);
       gtk_box_pack_start (GTK_BOX (widget), priv->combo, TRUE, TRUE, 0);
       g_signal_connect (priv->combo, "changed", G_CALLBACK (combo_changed_cb), widget);
@@ -749,11 +826,16 @@ construct_widgets (GtkPrinterOptionWidget *widget)
       gtk_widget_show (priv->box);
       gtk_box_pack_start (GTK_BOX (widget), priv->box, TRUE, TRUE, 0);
       for (i = 0; i < source->num_choices; i++)
-       group = alternative_append (priv->box,
-                                   source->choices_display[i],
-                                   source->choices[i],
-                                   widget,
-                                   group);
+        {
+         group = alternative_append (priv->box,
+                                      source->choices_display[i],
+                                      source->choices[i],
+                                      widget,
+                                      group);
+          /* for mnemonic activation */
+          if (i == 0)
+            priv->button = group->data;
+        }
 
       if (source->display_text)
        {
@@ -780,55 +862,16 @@ construct_widgets (GtkPrinterOptionWidget *widget)
       break;
 
     case GTK_PRINTER_OPTION_TYPE_FILESAVE:
-      {
-        GtkWidget *label;
-        
-        priv->filechooser = gtk_table_new (2, 2, FALSE);
-        gtk_table_set_row_spacings (GTK_TABLE (priv->filechooser), 6);
-        gtk_table_set_col_spacings (GTK_TABLE (priv->filechooser), 12);
-
-        /* TODO: make this a gtkfilechooserentry once we move to GTK */
-        priv->entry = gtk_entry_new ();
-        priv->combo = gtk_file_chooser_button_new (_("Select a folder"),
-                                                   GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
-
-        g_object_set (priv->combo, "local-only", FALSE, NULL);
-        gtk_entry_set_activates_default (GTK_ENTRY (priv->entry),
-                                         gtk_printer_option_get_activates_default (source));
+      priv->button = gtk_button_new ();
+      gtk_widget_show (priv->button);
+      gtk_box_pack_start (GTK_BOX (widget), priv->button, TRUE, TRUE, 0);
+      g_signal_connect (priv->button, "clicked", G_CALLBACK (filesave_choose_cb), widget);
 
-        label = gtk_label_new_with_mnemonic (_("_Name:"));
-        gtk_widget_set_halign (label, GTK_ALIGN_START);
-        gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->entry);
-
-        gtk_table_attach (GTK_TABLE (priv->filechooser), label,
-                          0, 1, 0, 1, GTK_FILL, 0,
-                          0, 0);
-
-        gtk_table_attach (GTK_TABLE (priv->filechooser), priv->entry,
-                          1, 2, 0, 1, GTK_FILL, 0,
-                          0, 0);
-
-        label = gtk_label_new_with_mnemonic (_("_Save in folder:"));
-        gtk_widget_set_halign (label, GTK_ALIGN_START);
-        gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->combo);
-
-        gtk_table_attach (GTK_TABLE (priv->filechooser), label,
-                          0, 1, 1, 2, GTK_FILL, 0,
-                          0, 0);
-
-        gtk_table_attach (GTK_TABLE (priv->filechooser), priv->combo,
-                          1, 2, 1, 2, GTK_FILL, 0,
-                          0, 0);
-
-        gtk_widget_show_all (priv->filechooser);
-        gtk_box_pack_start (GTK_BOX (widget), priv->filechooser, TRUE, TRUE, 0);
-
-        g_signal_connect (priv->entry, "changed", G_CALLBACK (filesave_changed_cb), widget);
+      text = g_strdup_printf ("%s:", source->display_text);
+      priv->label = gtk_label_new_with_mnemonic (text);
+      g_free (text);
+      gtk_widget_show (priv->label);
 
-        g_signal_connect (priv->combo, "selection-changed", G_CALLBACK (filesave_changed_cb), widget);
-      }
       break;
 
     case GTK_PRINTER_OPTION_TYPE_INFO:
@@ -852,6 +895,45 @@ construct_widgets (GtkPrinterOptionWidget *widget)
   gtk_box_pack_start (GTK_BOX (widget), priv->image, FALSE, FALSE, 0);
 }
 
+/**
+ * If the filename exceeds FILENAME_LENGTH_MAX, then trim it and replace
+ * the first three letters with three dots.
+ */
+static gchar *
+trim_long_filename (const gchar *filename)
+{
+  const gchar *home;
+  gint len, offset;
+  gchar *result;
+
+  home = g_get_home_dir ();
+  if (g_str_has_prefix (filename, home))
+    {
+      gchar *homeless_filename;
+
+      offset = g_utf8_strlen (home, -1);
+      len = g_utf8_strlen (filename, -1);
+      homeless_filename = g_utf8_substring (filename, offset, len);
+      result = g_strconcat ("~", homeless_filename, NULL);
+      g_free (homeless_filename);
+    }
+  else
+    result = g_strdup (filename);
+
+  len = g_utf8_strlen (result, -1);
+  if (len > FILENAME_LENGTH_MAX)
+    {
+      gchar *suffix;
+
+      suffix = g_utf8_substring (result, len - FILENAME_LENGTH_MAX, len);
+      g_free (result);
+      result = g_strconcat ("...", suffix, NULL);
+      g_free (suffix);
+    }
+
+  return result;
+}
+
 static void
 update_widgets (GtkPrinterOptionWidget *widget)
 {
@@ -883,30 +965,46 @@ update_widgets (GtkPrinterOptionWidget *widget)
     case GTK_PRINTER_OPTION_TYPE_STRING:
       gtk_entry_set_text (GTK_ENTRY (priv->entry), source->value);
       break;
+    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD:
+    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
+    case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
+    case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
+    case GTK_PRINTER_OPTION_TYPE_PICKONE_STRING:
+      {
+        GtkEntry *entry;
+
+        entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->combo)));
+        if (gtk_printer_option_has_choice (source, source->value))
+          combo_box_set (priv->combo, source->value);
+        else
+          gtk_entry_set_text (entry, source->value);
+
+        break;
+      }
     case GTK_PRINTER_OPTION_TYPE_FILESAVE:
       {
-        gchar *filename = g_filename_from_uri (source->value, NULL, NULL);
+        gchar *text;
+        gchar *filename;
+
+        filename = g_filename_from_uri (source->value, NULL, NULL);
         if (filename != NULL)
           {
-            gchar *basename, *dirname, *text;
+            text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+            if (text != NULL)
+              {
+                gchar *short_filename;
 
-            basename = g_path_get_basename (filename);
-            dirname = g_path_get_dirname (filename);
-            text = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
+                short_filename = trim_long_filename (text);
+                gtk_button_set_label (GTK_BUTTON (priv->button), short_filename);
+                g_free (short_filename);
+              }
 
-            if (text != NULL)
-              gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
-            if (g_path_is_absolute (dirname))
-              gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (priv->combo),
-                                                   dirname);
             g_free (text);
-            g_free (basename);
-            g_free (dirname);
             g_free (filename);
           }
-       else
-         gtk_entry_set_text (GTK_ENTRY (priv->entry), source->value);
-       break;
+        else
+          gtk_button_set_label (GTK_BUTTON (priv->button), source->value);
+        break;
       }
     case GTK_PRINTER_OPTION_TYPE_INFO:
       gtk_label_set_text (GTK_LABEL (priv->info_label), source->value);
@@ -940,6 +1038,6 @@ gtk_printer_option_widget_get_value (GtkPrinterOptionWidget *widget)
 
   if (priv->source)
     return priv->source->value;
-  
+
   return "";
 }