2007-05-30 Murray Cumming <murrayc@murrayc.com>
[modest] / src / modest-ui-dimming-rules.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29  
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <string.h>
35 #include "modest-ui-dimming-rules.h"
36 #include "modest-tny-folder.h"
37 #include <modest-runtime.h>
38
39
40 static gboolean _folder_is_any_of_type (TnyFolder *folder, TnyFolderType types[], guint ntypes);
41 static gboolean _invalid_msg_selected (ModestMainWindow *win, gboolean unique);
42 static gboolean _already_opened_msg (ModestWindow *win);
43 static gboolean _selected_msg_marked_as (ModestWindow *win, TnyHeaderFlags mask, gboolean opposite);
44 static gboolean _selected_folder_not_writeable (ModestMainWindow *win);
45 static gboolean _selected_folder_is_any_of_type (ModestMainWindow *win, TnyFolderType types[], guint ntypes);
46 static gboolean _selected_folder_is_root (ModestMainWindow *win);
47 static gboolean _msg_download_in_progress (ModestMsgViewWindow *win);
48
49
50 gboolean 
51 modest_ui_dimming_rules_on_new_msg (ModestWindow *win, gpointer user_data)
52 {
53         gboolean dimmed = FALSE;
54
55         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW(win), FALSE);
56                 
57         /* Check dimmed rule */ 
58         if (!dimmed)
59                 dimmed = _msg_download_in_progress (MODEST_MSG_VIEW_WINDOW(win));
60
61         return dimmed;
62 }
63
64 gboolean 
65 modest_ui_dimming_rules_on_new_folder (ModestWindow *win, gpointer user_data)
66 {
67         gboolean dimmed = FALSE;
68         GtkWidget *folder_view = NULL;
69         TnyFolderStore *parent_folder = NULL;
70
71         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
72
73
74         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
75                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
76         /* Get selected folder as parent of new folder to create */
77         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
78         if (!parent_folder)
79                 return TRUE;
80         
81         /* If it's the local account do not dim */
82         if (modest_tny_folder_store_is_virtual_local_folders (parent_folder)) {
83                 return FALSE;
84         } else if (TNY_IS_ACCOUNT (parent_folder)) {
85                 /* If it's the MMC root folder then dim it */
86                 if (!strcmp (tny_account_get_id (TNY_ACCOUNT (parent_folder)), MODEST_MMC_ACCOUNT_ID)) {
87                         dimmed = TRUE;
88                 } else {
89                         const gchar *proto_str = tny_account_get_proto (TNY_ACCOUNT (parent_folder));
90                         /* If it's POP then dim */
91                         dimmed = (modest_protocol_info_get_transport_store_protocol (proto_str) == 
92                                   MODEST_PROTOCOL_STORE_POP) ? TRUE : FALSE;
93                 }
94         } else {
95                 /* TODO: the specs say that only one level of subfolder is allowed, is this true ? */
96
97                 /* Apply folder rules */        
98                 dimmed = _selected_folder_not_writeable (MODEST_MAIN_WINDOW(win));
99         }
100
101         return dimmed;
102 }
103
104 gboolean 
105 modest_ui_dimming_rules_on_rename_folder (ModestWindow *win, gpointer user_data)
106 {
107         gboolean dimmed = FALSE;
108
109         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
110                 
111         /* Check dimmed rule */ 
112         if (!dimmed)
113                 dimmed = _selected_folder_not_writeable (MODEST_MAIN_WINDOW(win));
114         if (!dimmed)
115                 dimmed = _selected_folder_is_root (MODEST_MAIN_WINDOW(win));
116
117         return dimmed;
118 }
119
120 gboolean 
121 modest_ui_dimming_rules_on_open_msg (ModestWindow *win, gpointer user_data)
122 {
123         gboolean dimmed = FALSE;
124
125         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
126                 
127         /* Check dimmed rule */ 
128         if (!dimmed)
129                 dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), TRUE);
130
131         return dimmed;
132 }
133
134 gboolean 
135 modest_ui_dimming_rules_on_reply_msg (ModestWindow *win, gpointer user_data)
136 {
137         gboolean dimmed = FALSE;
138         TnyFolderType types[3];
139
140         /* main window dimming rules */
141         if (MODEST_IS_MAIN_WINDOW(win)) {
142                 
143                 types[0] = TNY_FOLDER_TYPE_DRAFTS; 
144                 types[1] = TNY_FOLDER_TYPE_OUTBOX;
145                 types[2] = TNY_FOLDER_TYPE_ROOT;
146                 
147                 /* Check dimmed rule */ 
148                 if (!dimmed)
149                         dimmed = _selected_folder_is_any_of_type (MODEST_MAIN_WINDOW(win), types, 3);
150                 
151                 if (!dimmed)
152                         dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), FALSE);
153
154         /* msg view window dimming rules */
155         } else if (MODEST_IS_MSG_VIEW_WINDOW(win)) {
156                 
157                 /* Check dimmed rule */ 
158                 if (!dimmed)
159                         dimmed = _msg_download_in_progress (MODEST_MSG_VIEW_WINDOW(win));
160         }
161         
162         return dimmed;
163 }
164
165
166 gboolean 
167 modest_ui_dimming_rules_on_contents_msg (ModestWindow *win, gpointer user_data)
168 {
169         gboolean dimmed = FALSE;
170
171         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
172                 
173         /* Check dimmed rule */ 
174         dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), FALSE);
175
176         return dimmed;
177 }
178
179 gboolean 
180 modest_ui_dimming_rules_always_dimmed (ModestWindow *win, gpointer user_data)
181 {
182         gboolean dimmed = FALSE;
183
184         g_return_val_if_fail (MODEST_IS_WINDOW(win), FALSE);
185                 
186         /* Check dimmed rule */ 
187         if (!dimmed)
188                 dimmed = TRUE;
189
190         return dimmed;
191 }
192
193 gboolean 
194 modest_ui_dimming_rules_on_delete_msg (ModestWindow *win, gpointer user_data)
195 {
196         gboolean dimmed = FALSE;
197         
198         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
199         
200         /* Check dimmed rule */ 
201         if (!dimmed)
202                 dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), FALSE);
203         if (!dimmed)
204                 dimmed = _already_opened_msg (win);
205         
206         return dimmed;
207 }
208
209 gboolean 
210 modest_ui_dimming_rules_on_details_msg (ModestWindow *win, gpointer user_data)
211 {
212         gboolean dimmed = FALSE;
213         
214         /* main window dimming rules */
215         if (MODEST_IS_MAIN_WINDOW(win)) {
216                 
217                 /* Check dimmed rule */ 
218                 if (!dimmed)
219                         dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), TRUE);
220
221         /* msg view window dimming rules */
222         } else {
223
224                 /* Check dimmed rule */ 
225                 if (!dimmed)
226                         dimmed = _msg_download_in_progress (MODEST_MSG_VIEW_WINDOW(win));
227         }
228
229         return dimmed;
230 }
231
232 gboolean 
233 modest_ui_dimming_rules_on_mark_as_read_msg (ModestWindow *win, gpointer user_data)
234 {
235         gboolean dimmed = FALSE;
236         TnyHeaderFlags flags;
237
238         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
239         
240         flags = TNY_HEADER_FLAG_SEEN; 
241
242         /* Check dimmed rule */ 
243         if (!dimmed)
244                 dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), FALSE);
245         if (!dimmed) 
246                 dimmed = _selected_msg_marked_as (win, flags, FALSE);
247         
248         return dimmed;
249 }
250
251 gboolean 
252 modest_ui_dimming_rules_on_mark_as_unread_msg (ModestWindow *win, gpointer user_data)
253 {
254         gboolean dimmed = FALSE;
255         TnyHeaderFlags flags;
256
257         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
258         
259         flags = TNY_HEADER_FLAG_SEEN; 
260
261         /* Check dimmed rule */ 
262         if (!dimmed)
263                 dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), FALSE);
264         if (!dimmed) 
265                 dimmed = _selected_msg_marked_as (win, flags, TRUE);
266
267         return dimmed;
268 }
269
270 gboolean 
271 modest_ui_dimming_rules_on_move_to (ModestWindow *win, gpointer user_data)
272 {
273         gboolean dimmed = FALSE;
274
275         if (MODEST_IS_MAIN_WINDOW (win)) 
276                 dimmed = modest_ui_dimming_rules_on_main_window_move_to (win, user_data);
277         else 
278                 dimmed = modest_ui_dimming_rules_on_view_window_move_to (win, user_data);
279
280         return dimmed;
281 }
282
283
284 gboolean 
285 modest_ui_dimming_rules_on_main_window_move_to (ModestWindow *win, gpointer user_data)
286 {
287         GtkWidget *folder_view = NULL;
288         GtkWidget *header_view = NULL;
289         gboolean dimmed = FALSE;
290         
291         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), TRUE);
292         
293         /* Get the folder view */
294         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
295                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
296
297         /* Get header view */
298         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
299                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
300
301         /* Check common diming rules */
302
303         /* Check diming rules for folder transfer  */
304         if (gtk_widget_is_focus (folder_view)) {
305                 if (!dimmed) 
306                         dimmed = _selected_folder_not_writeable(MODEST_MAIN_WINDOW(win));
307         }
308         /* Check diming rules for msg transfer  */
309         else if (gtk_widget_is_focus (header_view)) {
310                 if (!dimmed)
311                         dimmed = _invalid_msg_selected (MODEST_MAIN_WINDOW(win), FALSE);
312                 
313         }
314
315         return dimmed;
316 }
317
318 gboolean 
319 modest_ui_dimming_rules_on_view_window_move_to (ModestWindow *win, gpointer user_data)
320 {
321         gboolean dimmed = FALSE;
322
323         return dimmed;
324 }
325
326 gboolean 
327 modest_ui_dimming_rules_on_paste_msgs (ModestWindow *win, gpointer user_data)
328 {
329         TnyFolderType types[3];
330         gboolean dimmed = FALSE;
331
332         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
333
334         types[0] = TNY_FOLDER_TYPE_DRAFTS; 
335         types[1] = TNY_FOLDER_TYPE_OUTBOX;
336         types[2] = TNY_FOLDER_TYPE_SENT;
337         
338         /* Check dimmed rule */ 
339         if (!dimmed)
340                 dimmed = _selected_folder_is_any_of_type (MODEST_MAIN_WINDOW(win), types, 3);
341
342         return dimmed;
343 }
344
345 gboolean 
346 modest_ui_dimming_rules_on_delete_msgs (ModestWindow *win, gpointer user_data)
347 {
348         TnyFolderType types[5];
349         gboolean dimmed = FALSE;
350
351         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
352
353         types[0] = TNY_FOLDER_TYPE_DRAFTS; 
354         types[1] = TNY_FOLDER_TYPE_OUTBOX;
355         types[2] = TNY_FOLDER_TYPE_SENT;
356         types[3] = TNY_FOLDER_TYPE_INBOX;
357         types[4] = TNY_FOLDER_TYPE_ROOT;
358         
359         /* Check dimmed rule */ 
360         if (!dimmed)
361                 dimmed = _selected_folder_is_any_of_type (MODEST_MAIN_WINDOW(win), types, 5);
362
363         return dimmed;
364 }
365
366
367 /* *********************** static utility functions ******************** */
368
369 static gboolean
370 _selected_folder_not_writeable (ModestMainWindow *win)
371 {
372         GtkWidget *folder_view = NULL;
373         TnyFolderStore *parent_folder = NULL;
374         ModestTnyFolderRules rules;
375         gboolean result = FALSE;
376
377         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
378
379         /* Get folder view */
380         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
381                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
382         /* If no folder view, always dimmed */
383         if (!folder_view)
384                 return TRUE;
385         
386         /* Get selected folder as parent of new folder to create */
387         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
388         if (!(parent_folder || TNY_IS_FOLDER(parent_folder)))
389                 return TRUE;
390         
391         /* Check dimmed rule */ 
392         rules = modest_tny_folder_get_rules (TNY_FOLDER (parent_folder));
393         result = rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE;
394
395         /* free */
396         g_object_unref (parent_folder);
397
398         return result;
399 }
400
401 static gboolean
402 _selected_folder_is_root (ModestMainWindow *win)
403 {
404         TnyFolderType types[2];
405         gboolean result = FALSE;
406
407         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
408
409         types[0] = TNY_FOLDER_TYPE_ROOT; 
410         types[1] = TNY_FOLDER_TYPE_INBOX; 
411
412         /* Check folder type */
413         result = _selected_folder_is_any_of_type (win, types, 2);
414
415         return result;
416 }
417
418 static gboolean
419 _selected_folder_is_any_of_type (ModestMainWindow *win,
420                                  TnyFolderType types[], 
421                                  guint ntypes)
422 {
423         GtkWidget *folder_view = NULL;
424         TnyFolderStore *folder = NULL;
425         gboolean result = FALSE;
426
427         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
428
429         /* Get folder view */
430         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
431                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
432         /* If no folder view, always dimmed */
433         if (!folder_view)
434                 return TRUE;
435         
436         /* Get selected folder as parent of new folder to create */
437         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
438         if (!(folder || TNY_IS_FOLDER(folder)))
439                 return TRUE;
440         
441         /* Check folder type */
442         result = _folder_is_any_of_type (TNY_FOLDER(folder), types, ntypes);
443
444         /* free */
445         g_object_unref (folder);
446
447         return result;  
448 }
449
450 static gboolean
451 _folder_is_any_of_type (TnyFolder *folder,
452                         TnyFolderType types[], 
453                         guint ntypes)
454 {
455         TnyFolderType folder_type;
456         gboolean result = FALSE;
457         guint i;
458
459         g_return_val_if_fail (TNY_IS_FOLDER(folder), FALSE);
460
461         /* Get folder type */
462         if (modest_tny_folder_is_local_folder (folder))
463                 folder_type = modest_tny_folder_get_local_folder_type (folder);         
464         else 
465                 folder_type = modest_tny_folder_guess_folder_type (folder);             
466         
467         /* Check foler type */
468         for (i=0; i < ntypes; i++) {
469                 result = result || folder_type == types[i];
470         }
471
472         return result;
473 }
474
475
476
477 static gboolean
478 _invalid_msg_selected (ModestMainWindow *win,
479                        gboolean unique) 
480 {
481         GtkWidget *header_view = NULL;          
482         GtkWidget *folder_view = NULL;
483         TnyList *selected_headers = NULL;
484         gboolean result = FALSE;
485
486         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
487                 
488         /* Get header view to check selected messages */
489         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
490                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
491         
492         /* Get folder view to check focus */
493         folder_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (win),
494                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
495
496         /* Get selected headers */
497         selected_headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
498
499         /* Check dimmed rule (TODO: check focus on widgets */   
500         result = ((selected_headers == NULL) || 
501                   (GTK_WIDGET_HAS_FOCUS (folder_view)));
502         if (!result)
503                 result = tny_list_get_length (selected_headers) > 1;
504         
505         /* free */
506         if (selected_headers != NULL) 
507                 g_object_unref (selected_headers);
508
509         return result;
510 }
511
512 static gboolean
513 _already_opened_msg (ModestWindow *win)
514 {
515         ModestWindow *window = NULL;
516         ModestWindowMgr *mgr = NULL;
517         GtkWidget *header_view = NULL;          
518         TnyList *selected_headers = NULL;
519         TnyIterator *iter = NULL;
520         TnyHeader *header = NULL;
521         gboolean result = TRUE;
522
523         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(win), FALSE);
524                 
525         /* Get header view to check selected messages */
526         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
527                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
528
529         /* Get selected headers */
530         selected_headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
531         if (selected_headers == NULL) 
532                 return FALSE;
533
534         /* Check dimmed rule (TODO: check focus on widgets */   
535         mgr = modest_runtime_get_window_mgr ();
536         iter = tny_list_create_iterator (selected_headers);
537         while (!tny_iterator_is_done (iter) && result) {        
538                 header = TNY_HEADER (tny_iterator_get_current (iter));
539                 window = modest_window_mgr_find_window_by_msguid (mgr, tny_header_get_uid (header));
540                 result = result && (window != NULL);
541                         
542                 g_object_unref (header);
543                 tny_iterator_next (iter);
544         }
545         
546         /* free */
547         if (selected_headers != NULL) 
548                 g_object_unref (selected_headers);
549         if (iter != NULL)
550                 g_object_unref (iter);
551                 
552         return result;
553 }
554
555 static gboolean
556 _selected_msg_marked_as (ModestWindow *win, 
557                          TnyHeaderFlags mask, 
558                          gboolean opposite)
559 {
560         GtkWidget *header_view = NULL;
561         TnyList *selected_headers = NULL;
562         TnyIterator *iter = NULL;
563         TnyHeader *header = NULL;
564         TnyHeaderFlags flags;
565         gboolean result = FALSE;
566
567         /* Get header view to check selected messages */
568         header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
569                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
570
571         /* Get selected headers */
572         selected_headers = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
573         if (selected_headers == NULL) 
574                 return TRUE;
575         
576         /* Call the function for each header */
577         iter = tny_list_create_iterator (selected_headers);
578         while (!tny_iterator_is_done (iter) && !result) {
579                 header = TNY_HEADER (tny_iterator_get_current (iter));
580
581                 flags = tny_header_get_flags (header);
582                 if (opposite)
583                         result = (flags & mask) == 0; 
584                 else
585                         result = (flags & mask) != 0; 
586
587                 g_object_unref (header);
588                 tny_iterator_next (iter);
589         }
590
591         /* free */
592         if (selected_headers != NULL) 
593                 g_object_unref (selected_headers);
594         if (iter != NULL)
595                 g_object_unref (iter);
596
597         return result;
598 }
599
600 static gboolean
601 _msg_download_in_progress (ModestMsgViewWindow *win)
602 {
603         gboolean result = FALSE;
604
605         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), FALSE);
606
607         return result;
608 }