1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* logview-manager.c - manager for the opened log objects
3  *
4  * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
19  * USA.
20  */
21 
22 /* logview-manager.c */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include "logview-manager.h"
29 
30 #include <glib/gi18n.h>
31 
32 #include "logview-prefs.h"
33 #include "logview-app.h"
34 
35 enum {
36   LOG_ADDED,
37   LOG_CLOSED,
38   ACTIVE_CHANGED,
39   LAST_SIGNAL
40 };
41 
42 typedef struct {
43   LogviewManager *manager;
44   gboolean set_active;
45   gboolean is_multiple;
46   GFile *file;
47 } CreateCBData;
48 
49 typedef struct {
50   int total;
51   int current;
52   GPtrArray *errors;
53 } MultipleCreation;
54 
55 struct _LogviewManagerPrivate {
56   GHashTable *logs;
57   LogviewLog *active_log;
58 };
59 
60 static LogviewManager *singleton = NULL;
61 static MultipleCreation *op = NULL;
62 static guint signals[LAST_SIGNAL] = { 0 };
63 
64 G_DEFINE_TYPE (LogviewManager, logview_manager, G_TYPE_OBJECT);
65 
66 #define GET_PRIVATE(o) \
67   (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_MANAGER, LogviewManagerPrivate))
68 
69 static void
logview_manager_finalize(GObject * object)70 logview_manager_finalize (GObject *object)
71 {
72   LogviewManager *manager;
73 
74   manager = LOGVIEW_MANAGER (object);
75 
76   if (manager->priv->active_log) {
77    g_object_unref (manager->priv->active_log);
78   }
79 
80   g_hash_table_destroy (manager->priv->logs);
81 
82   G_OBJECT_CLASS (logview_manager_parent_class)->finalize (object);
83 }
84 
85 static void
logview_manager_class_init(LogviewManagerClass * klass)86 logview_manager_class_init (LogviewManagerClass *klass)
87 {
88   GObjectClass *object_class = G_OBJECT_CLASS (klass);
89 
90   object_class->finalize = logview_manager_finalize;
91 
92   signals[LOG_ADDED] = g_signal_new ("log-added",
93                                      G_OBJECT_CLASS_TYPE (object_class),
94                                      G_SIGNAL_RUN_LAST,
95                                      G_STRUCT_OFFSET (LogviewManagerClass, log_added),
96                                      NULL, NULL,
97                                      g_cclosure_marshal_VOID__OBJECT,
98                                      G_TYPE_NONE, 1,
99                                      LOGVIEW_TYPE_LOG);
100 
101   signals[LOG_CLOSED] = g_signal_new ("log-closed",
102                                       G_OBJECT_CLASS_TYPE (object_class),
103                                       G_SIGNAL_RUN_LAST,
104                                       G_STRUCT_OFFSET (LogviewManagerClass, log_closed),
105                                       NULL, NULL,
106                                       g_cclosure_marshal_VOID__OBJECT,
107                                       G_TYPE_NONE, 1,
108                                       LOGVIEW_TYPE_LOG);
109 
110   signals[ACTIVE_CHANGED] = g_signal_new ("active-changed",
111                                           G_OBJECT_CLASS_TYPE (object_class),
112                                           G_SIGNAL_RUN_LAST,
113                                           G_STRUCT_OFFSET (LogviewManagerClass, active_changed),
114                                           NULL, NULL, NULL,
115                                           G_TYPE_NONE, 2,
116                                           LOGVIEW_TYPE_LOG,
117                                           LOGVIEW_TYPE_LOG);
118 
119   g_type_class_add_private (klass, sizeof (LogviewManagerPrivate));
120 }
121 
122 static void
logview_manager_init(LogviewManager * self)123 logview_manager_init (LogviewManager *self)
124 {
125   LogviewManagerPrivate *priv = self->priv = GET_PRIVATE (self);
126 
127   priv->active_log = NULL;
128   priv->logs = g_hash_table_new_full (g_str_hash, g_str_equal,
129                                       (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
130 }
131 
132 static MultipleCreation *
multiple_creation_op_new(int total)133 multiple_creation_op_new (int total)
134 {
135   MultipleCreation *retval;
136 
137   retval = g_slice_new0 (MultipleCreation);
138   retval->total = total;
139   retval->current = 0;
140   retval->errors = g_ptr_array_new ();
141 
142   return retval;
143 }
144 
145 static void
multiple_creation_op_free(MultipleCreation * mc)146 multiple_creation_op_free (MultipleCreation *mc)
147 {
148   g_ptr_array_foreach (mc->errors, (GFunc) g_strfreev, NULL);
149   g_ptr_array_free (mc->errors, TRUE);
150 
151   g_slice_free (MultipleCreation, mc);
152 }
153 
154 static void
create_log_cb(LogviewLog * log,GError * error,gpointer user_data)155 create_log_cb (LogviewLog *log,
156                GError *error,
157                gpointer user_data)
158 {
159   CreateCBData *data = user_data;
160 
161   if (log) {
162     char *log_uri;
163     LogviewPrefs *prefs;
164     GFile *file;
165 
166     log_uri = logview_log_get_uri (log);
167 
168     /* creation went well, store the log and notify */
169     g_hash_table_insert (data->manager->priv->logs,
170                          log_uri, log);
171 
172     prefs = logview_prefs_get ();
173     file = logview_log_get_gfile (log);
174     logview_prefs_store_log (prefs, file);
175 
176     g_object_unref (file);
177 
178     g_signal_emit (data->manager, signals[LOG_ADDED], 0, log, NULL);
179 
180     if (data->set_active) {
181       logview_manager_set_active_log (data->manager, log);
182     }
183   } else {
184     char *path;
185 
186     /* notify the error */
187     path = g_file_get_path (data->file);
188 
189     if (!data->is_multiple) {
190       logview_app_add_error (LOGVIEW_APP (g_application_get_default ()),
191                              path, error->message);
192     } else {
193       char **error_arr = g_new0 (char *, 3);
194 
195       error_arr[0] = g_strdup (path);
196       error_arr[1] = g_strdup (error->message);
197       error_arr[2] = NULL;
198 
199       g_ptr_array_add (op->errors, error_arr);
200     }
201 
202     g_free (path);
203   }
204 
205   if (data->is_multiple) {
206     op->current++;
207 
208     if (op->total == op->current) {
209       logview_app_add_errors (LOGVIEW_APP (g_application_get_default ()),
210                               op->errors);
211       multiple_creation_op_free (op);
212       op = NULL;
213     }
214   }
215 
216   g_object_unref (data->file);
217   g_slice_free (CreateCBData, data);
218 }
219 
220 static void
add_log_from_gfile_internal(LogviewManager * manager,GFile * file,gboolean set_active,gboolean is_multiple)221 add_log_from_gfile_internal (LogviewManager *manager,
222                              GFile *file,
223                              gboolean set_active,
224                              gboolean is_multiple)
225 {
226   char *file_uri;
227   LogviewLog *log;
228   CreateCBData *data;
229 
230   file_uri = g_file_get_uri (file);
231 
232   if (set_active == FALSE) {
233     /* if it's the first log being added, set it as active anyway */
234     set_active = (manager->priv->logs == NULL);
235   }
236 
237   if ((log = g_hash_table_lookup (manager->priv->logs, file_uri)) != NULL) {
238     /* log already exists, don't load it */
239     if (set_active) {
240       logview_manager_set_active_log (manager, log);
241     }
242   } else {
243     data = g_slice_new0 (CreateCBData);
244     data->manager = manager;
245     data->set_active = set_active;
246     data->is_multiple = is_multiple;
247     data->file = g_object_ref (file);
248 
249     logview_log_create_from_gfile (file, create_log_cb, data);
250   }
251 
252   g_free (file_uri);
253 }
254 
255 static void
logview_manager_add_log_from_name(LogviewManager * manager,const char * filename,gboolean set_active,gboolean is_multiple)256 logview_manager_add_log_from_name (LogviewManager *manager,
257                                    const char *filename, gboolean set_active,
258                                    gboolean is_multiple)
259 {
260   GFile *file;
261 
262   file = g_file_new_for_path (filename);
263 
264   add_log_from_gfile_internal (manager, file, set_active, is_multiple);
265 
266   g_object_unref (file);
267 }
268 
269 /* public methods */
270 
271 LogviewManager*
logview_manager_get(void)272 logview_manager_get (void)
273 {
274   if (!singleton) {
275     singleton = g_object_new (LOGVIEW_TYPE_MANAGER, NULL);
276   }
277 
278   return singleton;
279 }
280 
281 void
logview_manager_set_active_log(LogviewManager * manager,LogviewLog * log)282 logview_manager_set_active_log (LogviewManager *manager,
283                                 LogviewLog *log)
284 {
285   LogviewLog *old_log = NULL;
286   GFile *file;
287   char *path;
288 
289   g_assert (LOGVIEW_IS_MANAGER (manager));
290 
291   if (manager->priv->active_log) {
292     old_log = manager->priv->active_log;
293   }
294 
295   manager->priv->active_log = g_object_ref (log);
296 
297   file = logview_log_get_gfile (log);
298   path = g_file_get_path (file);
299   logview_prefs_store_active_logfile (logview_prefs_get (), path);
300   g_free (path);
301   g_object_unref (file);
302 
303   g_signal_emit (manager, signals[ACTIVE_CHANGED], 0, log, old_log, NULL);
304 
305   if (old_log) {
306     g_object_unref (old_log);
307   }
308 }
309 
310 LogviewLog *
logview_manager_get_active_log(LogviewManager * manager)311 logview_manager_get_active_log (LogviewManager *manager)
312 {
313   g_assert (LOGVIEW_IS_MANAGER (manager));
314 
315   return manager->priv->active_log;
316 }
317 
318 void
logview_manager_add_log_from_gfile(LogviewManager * manager,GFile * file,gboolean set_active)319 logview_manager_add_log_from_gfile (LogviewManager *manager,
320                                     GFile *file,
321                                     gboolean set_active)
322 {
323   g_assert (LOGVIEW_IS_MANAGER (manager));
324 
325   add_log_from_gfile_internal (manager, file, set_active, FALSE);
326 }
327 
328 void
logview_manager_add_logs_from_name_list(LogviewManager * manager,GSList * names,const char * active)329 logview_manager_add_logs_from_name_list (LogviewManager *manager,
330                                          GSList *names,
331                                          const char *active)
332 {
333   GSList *l;
334 
335   g_assert (LOGVIEW_IS_MANAGER (manager));
336   g_assert (op == NULL);
337 
338   op = multiple_creation_op_new (g_slist_length (names));
339 
340   for (l = names; l; l = l->next) {
341     logview_manager_add_log_from_name (manager, l->data,
342                                        (g_ascii_strcasecmp (active, l->data) == 0),
343                                        TRUE);
344   }
345 }
346 
347 void
logview_manager_add_logs_from_names(LogviewManager * manager,char ** names,const gchar * active)348 logview_manager_add_logs_from_names (LogviewManager *manager,
349                                      char ** names,
350                                      const gchar *active)
351 {
352   int i;
353   gboolean set_active;
354 
355   g_assert (LOGVIEW_IS_MANAGER (manager));
356   g_assert (op == NULL);
357 
358   op = multiple_creation_op_new (g_strv_length (names));
359 
360   for (i = 0; names[i]; i++) {
361     set_active = (active != NULL) && (!g_ascii_strcasecmp (active, names[i]));
362     logview_manager_add_log_from_name (manager, names[i], set_active,
363                                        TRUE);
364   }
365 }
366 
367 int
logview_manager_get_log_count(LogviewManager * manager)368 logview_manager_get_log_count (LogviewManager *manager)
369 {
370   g_assert (LOGVIEW_IS_MANAGER (manager));
371 
372   return g_hash_table_size (manager->priv->logs);
373 }
374 
375 LogviewLog *
logview_manager_get_if_loaded(LogviewManager * manager,char * uri)376 logview_manager_get_if_loaded (LogviewManager *manager, char *uri)
377 {
378   LogviewLog *log;
379 
380   g_assert (LOGVIEW_IS_MANAGER (manager));
381 
382   log = g_hash_table_lookup (manager->priv->logs, uri);
383 
384   if (log != NULL) {
385     return g_object_ref (log);
386   }
387 
388   return NULL;
389 }
390 
391 void
logview_manager_close_active_log(LogviewManager * manager)392 logview_manager_close_active_log (LogviewManager *manager)
393 {
394   LogviewLog *active_log;
395   char *log_uri;
396   GFile *file;
397 
398   g_assert (LOGVIEW_IS_MANAGER (manager));
399 
400   active_log = manager->priv->active_log;
401   if (active_log == NULL) {
402     return;
403   }
404 
405   log_uri = logview_log_get_uri (active_log);
406   file = logview_log_get_gfile (active_log);
407 
408   g_signal_emit (manager, signals[LOG_CLOSED], 0, active_log, NULL);
409 
410   logview_prefs_remove_stored_log (logview_prefs_get (), file);
411 
412   g_object_unref (file);
413 
414   /* drop the hash table ref */
415   g_hash_table_remove (manager->priv->logs, log_uri);
416 
417   g_free (log_uri);
418 
419   /* someone else will take care of setting the next active log to us */
420 }
421 
422 gboolean
logview_manager_log_is_active(LogviewManager * manager,LogviewLog * log)423 logview_manager_log_is_active (LogviewManager *manager,
424                                LogviewLog *log)
425 {
426   g_assert (LOGVIEW_IS_MANAGER (manager));
427 
428   return (manager->priv->active_log == log);
429 }
430