1 /* EasyTAG - tag editor for audio files
2  * Copyright (C) 2014-2015  David King <amigadave@amigadave.com>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2 of the License, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 51
16  * Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include "config.h"
20 
21 #include "file_area.h"
22 
23 #include <glib/gi18n.h>
24 
25 #include "charset.h"
26 #include "et_core.h"
27 #include "log.h"
28 #include "setting.h"
29 #include "tag_area.h"
30 
31 typedef struct
32 {
33     GtkWidget *file_label;
34 
35     GtkWidget *index_label;
36     GtkWidget *name_entry;
37 
38     GtkWidget *header_grid;
39 
40     GtkWidget *version_label;
41     GtkWidget *version_value_label;
42     GtkWidget *bitrate_label;
43     GtkWidget *bitrate_value_label;
44     GtkWidget *samplerate_label;
45     GtkWidget *samplerate_value_label;
46     GtkWidget *mode_label;
47     GtkWidget *mode_value_label;
48     GtkWidget *size_label;
49     GtkWidget *size_value_label;
50     GtkWidget *duration_label;
51     GtkWidget *duration_value_label;
52 } EtFileAreaPrivate;
53 
G_DEFINE_TYPE_WITH_PRIVATE(EtFileArea,et_file_area,GTK_TYPE_BIN)54 G_DEFINE_TYPE_WITH_PRIVATE (EtFileArea, et_file_area, GTK_TYPE_BIN)
55 
56 static void
57 on_file_show_header_changed (EtFileArea *self,
58                              const gchar *key,
59                              GSettings *settings)
60 {
61     EtFileAreaPrivate *priv;
62 
63     priv = et_file_area_get_instance_private (self);
64 
65     if (g_settings_get_boolean (settings, key))
66     {
67         gtk_widget_show (priv->header_grid);
68     }
69     else
70     {
71         gtk_widget_hide (priv->header_grid);
72     }
73 }
74 
75 static void
et_file_area_init(EtFileArea * self)76 et_file_area_init (EtFileArea *self)
77 {
78     gtk_widget_init_template (GTK_WIDGET (self));
79 
80     g_signal_connect_swapped (MainSettings, "changed::file-show-header",
81                               G_CALLBACK (on_file_show_header_changed), self);
82     on_file_show_header_changed (self, "file-show-header", MainSettings);
83 }
84 
85 static void
et_file_area_class_init(EtFileAreaClass * klass)86 et_file_area_class_init (EtFileAreaClass *klass)
87 {
88     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
89 
90     gtk_widget_class_set_template_from_resource (widget_class,
91                                                  "/org/gnome/EasyTAG/file_area.ui");
92     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
93                                                   file_label);
94     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
95                                                   index_label);
96     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
97                                                   name_entry);
98     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
99                                                   header_grid);
100     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
101                                                   version_label);
102     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
103                                                   version_value_label);
104     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
105                                                   bitrate_label);
106     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
107                                                   bitrate_value_label);
108     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
109                                                   samplerate_label);
110     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
111                                                   samplerate_value_label);
112     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
113                                                   mode_label);
114     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
115                                                   mode_value_label);
116     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
117                                                   size_label);
118     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
119                                                   size_value_label);
120     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
121                                                   duration_label);
122     gtk_widget_class_bind_template_child_private (widget_class, EtFileArea,
123                                                   duration_value_label);
124     gtk_widget_class_bind_template_callback (widget_class,
125                                              on_entry_populate_popup);
126 }
127 
128 /*
129  * et_file_area_new:
130  *
131  * Create a new EtFileArea instance.
132  *
133  * Returns: a new #EtFileArea
134  */
135 GtkWidget *
et_file_area_new(void)136 et_file_area_new (void)
137 {
138     return g_object_new (ET_TYPE_FILE_AREA, NULL);
139 }
140 
141 void
et_file_area_clear(EtFileArea * self)142 et_file_area_clear (EtFileArea *self)
143 {
144     EtFileAreaPrivate *priv;
145     EtFileHeaderFields fields;
146     gchar *empty_str;
147 
148     g_return_if_fail (ET_FILE_AREA (self));
149 
150     priv = et_file_area_get_instance_private (self);
151 
152     empty_str = g_strdup ("");
153 
154     /* Default values are MPEG data. */
155     fields.description = _("File");
156     fields.version_label = _("Encoder:");
157     fields.version =  empty_str;
158     fields.bitrate = empty_str;
159     fields.samplerate = empty_str;
160     fields.mode_label = _("Mode:");
161     fields.mode = empty_str;
162     fields.size = empty_str;
163     fields.duration = empty_str;
164 
165     et_file_area_set_header_fields (self, &fields);
166 
167     gtk_entry_set_text (GTK_ENTRY (priv->name_entry), empty_str);
168     gtk_label_set_text (GTK_LABEL (priv->index_label), "0/0:");
169 
170     g_free (empty_str);
171 }
172 
173 void
et_file_area_set_header_fields(EtFileArea * self,EtFileHeaderFields * fields)174 et_file_area_set_header_fields (EtFileArea *self,
175                                 EtFileHeaderFields *fields)
176 {
177     EtFileAreaPrivate *priv;
178 
179     g_return_if_fail (ET_FILE_AREA (self));
180     g_return_if_fail (fields != NULL);
181 
182     priv = et_file_area_get_instance_private (self);
183 
184     gtk_label_set_text (GTK_LABEL (priv->file_label), fields->description);
185     gtk_label_set_text (GTK_LABEL (priv->version_label),
186                         fields->version_label);
187     gtk_label_set_text (GTK_LABEL (priv->version_value_label),
188                         fields->version);
189     gtk_label_set_text (GTK_LABEL (priv->bitrate_value_label),
190                         fields->bitrate);
191     gtk_label_set_text (GTK_LABEL (priv->samplerate_value_label),
192                         fields->samplerate);
193     gtk_label_set_text (GTK_LABEL (priv->mode_label), fields->mode_label);
194     gtk_label_set_text (GTK_LABEL (priv->mode_value_label), fields->mode);
195     gtk_label_set_text (GTK_LABEL (priv->size_value_label), fields->size);
196     gtk_label_set_text (GTK_LABEL (priv->duration_value_label),
197                         fields->duration);
198 }
199 
200 /* Toggle visibility of the small status icon if filename is read-only or not
201  * found. Show the position of the current file in the list, by using the index
202  * and list length. */
203 void
et_file_area_set_file_fields(EtFileArea * self,const ET_File * ETFile)204 et_file_area_set_file_fields (EtFileArea *self,
205                               const ET_File *ETFile)
206 {
207     EtFileAreaPrivate *priv;
208     GFile *file;
209     gchar *text;
210     const gchar *cur_filename;
211     gchar *basename_utf8;
212     gchar *pos;
213     GFileInfo *info;
214     GError *error = NULL;
215 
216     g_return_if_fail (ET_FILE_AREA (self));
217     g_return_if_fail (ETFile != NULL);
218 
219     priv = et_file_area_get_instance_private (self);
220 
221     cur_filename = ((File_Name *)((GList *)ETFile->FileNameCur)->data)->value;
222 
223     file = g_file_new_for_path (cur_filename);
224 
225     info = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_READ ","
226                               G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
227                               G_FILE_QUERY_INFO_NONE, NULL, &error);
228 
229     /* Show/hide 'AccessStatusIcon' */
230     if (!info)
231     {
232         if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
233         {
234             /* No such file or directory. */
235             GIcon *emblem_icon;
236 
237             emblem_icon = g_themed_icon_new ("emblem-unreadable");
238 
239             gtk_entry_set_icon_from_gicon (GTK_ENTRY (priv->name_entry),
240                                            GTK_ENTRY_ICON_SECONDARY,
241                                            emblem_icon);
242             gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv->name_entry),
243                                              GTK_ENTRY_ICON_SECONDARY,
244                                              _("File not found"));
245             g_object_unref (emblem_icon);
246         }
247         else
248         {
249             Log_Print (LOG_ERROR, _("Cannot query file information ‘%s’"),
250                        error->message);
251             g_error_free (error);
252             g_object_unref (file);
253             return;
254         }
255     }
256     else
257     {
258         gboolean readable, writable;
259 
260         readable = g_file_info_get_attribute_boolean (info,
261                                                       G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
262         writable = g_file_info_get_attribute_boolean (info,
263                                                       G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
264 
265         if (readable && writable)
266         {
267             /* User has all necessary permissions. */
268             gtk_entry_set_icon_from_gicon (GTK_ENTRY (priv->name_entry),
269                                            GTK_ENTRY_ICON_SECONDARY, NULL);
270         }
271         else if (!writable)
272         {
273             /* Read only file or permission denied. */
274             GIcon *emblem_icon;
275 
276             emblem_icon = g_themed_icon_new ("emblem-readonly");
277 
278             gtk_entry_set_icon_from_gicon (GTK_ENTRY (priv->name_entry),
279                                            GTK_ENTRY_ICON_SECONDARY,
280                                            emblem_icon);
281             gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv->name_entry),
282                                              GTK_ENTRY_ICON_SECONDARY,
283                                              _("Read-only file"));
284             g_object_unref (emblem_icon);
285 
286         }
287         else
288         {
289             /* Otherwise unreadable. */
290             GIcon *emblem_icon;
291 
292             emblem_icon = g_themed_icon_new ("emblem-unreadable");
293 
294             gtk_entry_set_icon_from_gicon (GTK_ENTRY (priv->name_entry),
295                                            GTK_ENTRY_ICON_SECONDARY,
296                                            emblem_icon);
297             gtk_entry_set_icon_tooltip_text (GTK_ENTRY (priv->name_entry),
298                                              GTK_ENTRY_ICON_SECONDARY,
299                                              _("File not found"));
300             g_object_unref (emblem_icon);
301         }
302 
303         g_object_unref (info);
304     }
305 
306 
307     /* Set new filename into name_entry. This matches the GFile edit name. */
308     basename_utf8 = g_filename_display_basename (((File_Name *)((GList *)ETFile->FileNameNew)->data)->value);
309 
310     /* Remove the extension. */
311     if ((pos = strrchr (basename_utf8, '.')) != NULL)
312     {
313         *pos = 0;
314     }
315 
316     gtk_entry_set_text (GTK_ENTRY (priv->name_entry), basename_utf8);
317     g_free (basename_utf8);
318 
319     /* Show position of current file in list */
320     text = g_strdup_printf ("%u/%u:", ETFile->IndexKey,
321                             ETCore->ETFileDisplayedList_Length);
322     gtk_label_set_text (GTK_LABEL (priv->index_label), text);
323     g_object_unref (file);
324     g_free (text);
325 }
326 
327 const gchar *
et_file_area_get_filename(EtFileArea * self)328 et_file_area_get_filename (EtFileArea *self)
329 {
330     EtFileAreaPrivate *priv;
331 
332     g_return_val_if_fail (ET_FILE_AREA (self), NULL);
333 
334     priv = et_file_area_get_instance_private (self);
335 
336     return gtk_entry_get_text (GTK_ENTRY (priv->name_entry));
337 }
338