1 /*
2 * Copyright 2017 LarsGit223
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 /*
20 * Code for the WORKBENCH structure.
21 */
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <glib.h>
27 #include <glib/gstdio.h>
28 #include <geanyplugin.h>
29 #include "workbench.h"
30 #include "sidebar.h"
31 #include "wb_project.h"
32 #include "wb_monitor.h"
33 #include "utils.h"
34
35 typedef struct
36 {
37 PROJECT_ENTRY_STATUS status;
38 gchar *abs_filename;
39 gchar *rel_filename;
40 gboolean use_abs;
41 WB_PROJECT *project;
42 }WB_PROJECT_ENTRY;
43
44 struct S_WORKBENCH
45 {
46 gchar *filename;
47 gchar *name;
48 gboolean modified;
49 gboolean rescan_projects_on_open;
50 gboolean enable_live_update;
51 gboolean expand_on_hover;
52 gboolean enable_tree_lines;
53 GPtrArray *projects;
54 GPtrArray *bookmarks;
55 WB_MONITOR *monitor;
56 };
57
58 /* Create a new, empty workbench project entry */
wb_project_entry_new(void)59 static WB_PROJECT_ENTRY *wb_project_entry_new(void)
60 {
61 WB_PROJECT_ENTRY *new_entry;
62
63 new_entry = g_new(WB_PROJECT_ENTRY, 1);
64 memset(new_entry, 0, sizeof(*new_entry));
65 new_entry->status = PROJECT_ENTRY_STATUS_UNKNOWN;
66
67 return new_entry;
68 }
69
70
71 /* Free a workbench entry */
wb_project_entry_free(WB_PROJECT_ENTRY * entry)72 static void wb_project_entry_free(WB_PROJECT_ENTRY *entry)
73 {
74 wb_project_free(entry->project);
75 g_free(entry->abs_filename);
76 g_free(entry->rel_filename);
77 g_free(entry);
78 }
79
80
81 /** Create a new empty workbench.
82 *
83 * @return Address of the new structure.
84 *
85 **/
workbench_new(void)86 WORKBENCH *workbench_new(void)
87 {
88 WORKBENCH *new_wb;
89
90 new_wb = g_new0(WORKBENCH, 1);
91 memset(new_wb, 0, sizeof(*new_wb));
92 new_wb->modified = FALSE;
93 new_wb->rescan_projects_on_open = TRUE;
94 new_wb->enable_live_update = TRUE;
95 new_wb->projects = g_ptr_array_new();
96 new_wb->bookmarks = g_ptr_array_new();
97 new_wb->monitor = wb_monitor_new();
98
99 return new_wb;
100 }
101
102
103 /** Free a workbench.
104 *
105 * @param wb The workbench
106 *
107 **/
workbench_free(WORKBENCH * wb)108 void workbench_free(WORKBENCH *wb)
109 {
110 WB_PROJECT_ENTRY *entry;
111 guint index;
112
113 if (wb == NULL)
114 {
115 return;
116 }
117
118 /* Free projects and project entries first */
119 for (index = 0 ; index < wb->projects->len ; index++)
120 {
121 entry = g_ptr_array_index(wb->projects, index);
122 if (entry != NULL)
123 {
124 wb_project_entry_free(entry);
125 }
126 }
127
128 wb_monitor_free(wb->monitor);
129 g_ptr_array_free (wb->projects, TRUE);
130 g_free(wb);
131 }
132
133
134 /** Is the workbench empty?
135 *
136 * @param wb The workbench
137 * @return TRUE is workbench is empty or wb == NULL,
138 * FALSE otherwise.
139 *
140 **/
workbench_is_empty(WORKBENCH * wb)141 gboolean workbench_is_empty(WORKBENCH *wb)
142 {
143 if (wb != NULL)
144 {
145 return (wb->projects->len == 0);
146 }
147 return TRUE;
148 }
149
150
151 /** Get the project count.
152 *
153 * @param wb The workbench
154 * @return TRUE is workbench is empty or wb == NULL,
155 * FALSE otherwise.
156 *
157 **/
workbench_get_project_count(WORKBENCH * wb)158 guint workbench_get_project_count(WORKBENCH *wb)
159 {
160 if (wb != NULL)
161 {
162 return wb->projects->len;
163 }
164 return 0;
165 }
166
167
168 /** Is the workbench modified?
169 *
170 * @param wb The workbench
171 * @return TRUE if the workbench is modified,
172 * FALSE if not or wb == NULL
173 *
174 **/
workbench_is_modified(WORKBENCH * wb)175 gboolean workbench_is_modified(WORKBENCH *wb)
176 {
177 if (wb != NULL)
178 {
179 return wb->modified;
180 }
181 return FALSE;
182 }
183
184
185 /** Set the "Rescan projects on open" option.
186 *
187 * @param wb The workbench
188 * @param value The value to set
189 *
190 **/
workbench_set_rescan_projects_on_open(WORKBENCH * wb,gboolean value)191 void workbench_set_rescan_projects_on_open(WORKBENCH *wb, gboolean value)
192 {
193 if (wb != NULL)
194 {
195 if (wb->rescan_projects_on_open != value)
196 {
197 wb->rescan_projects_on_open = value;
198 wb->modified = TRUE;
199 }
200 }
201 }
202
203
204 /** Get the "Rescan projects on open" option.
205 *
206 * @param wb The workbench
207 * @return TRUE = rescan all projects after opening the workbench,
208 * FALSE = don't
209 *
210 **/
workbench_get_rescan_projects_on_open(WORKBENCH * wb)211 gboolean workbench_get_rescan_projects_on_open(WORKBENCH *wb)
212 {
213 if (wb != NULL)
214 {
215 return wb->rescan_projects_on_open;
216 }
217 return FALSE;
218 }
219
220
221 /** Set the "Enable live update" option.
222 *
223 * @param wb The workbench
224 * @param value The value to set
225 *
226 **/
workbench_set_enable_live_update(WORKBENCH * wb,gboolean value)227 void workbench_set_enable_live_update(WORKBENCH *wb, gboolean value)
228 {
229 if (wb != NULL)
230 {
231 if (wb->enable_live_update != value)
232 {
233 wb->enable_live_update = value;
234 wb->modified = TRUE;
235 }
236 }
237 }
238
239
240 /** Get the "Enable live update" option.
241 *
242 * @param wb The workbench
243 * @return TRUE = use file monitoring for live update of the file list,
244 * FALSE = don't
245 *
246 **/
workbench_get_enable_live_update(WORKBENCH * wb)247 gboolean workbench_get_enable_live_update(WORKBENCH *wb)
248 {
249 if (wb != NULL)
250 {
251 return wb->enable_live_update;
252 }
253 return FALSE;
254 }
255
256
257 /** Set the "Expand on hover" option.
258 *
259 * @param wb The workbench
260 * @param value The value to set
261 *
262 **/
workbench_set_expand_on_hover(WORKBENCH * wb,gboolean value)263 void workbench_set_expand_on_hover(WORKBENCH *wb, gboolean value)
264 {
265 if (wb != NULL)
266 {
267 if (wb->expand_on_hover != value)
268 {
269 wb->expand_on_hover = value;
270 wb->modified = TRUE;
271 }
272 }
273 }
274
275
276 /** Get the "Expand on hover" option.
277 *
278 * @param wb The workbench
279 * @return TRUE = expand a tree-node on hovering over it,
280 * FALSE = don't
281 *
282 **/
workbench_get_expand_on_hover(WORKBENCH * wb)283 gboolean workbench_get_expand_on_hover(WORKBENCH *wb)
284 {
285 if (wb != NULL)
286 {
287 return wb->expand_on_hover;
288 }
289 return FALSE;
290 }
291
292
293 /** Set the "Enable Tree Lines" option.
294 *
295 * @param wb The workbench
296 * @param value The value to set
297 *
298 **/
workbench_set_enable_tree_lines(WORKBENCH * wb,gboolean value)299 void workbench_set_enable_tree_lines(WORKBENCH *wb, gboolean value)
300 {
301 if (wb != NULL)
302 {
303 if (wb->enable_tree_lines != value)
304 {
305 wb->enable_tree_lines = value;
306 wb->modified = TRUE;
307 }
308 }
309 }
310
311
312 /** Get the "Enable Tree Lines" option.
313 *
314 * @param wb The workbench
315 * @return TRUE = show tree lines,
316 * FALSE = don't
317 *
318 **/
workbench_get_enable_tree_lines(WORKBENCH * wb)319 gboolean workbench_get_enable_tree_lines(WORKBENCH *wb)
320 {
321 if (wb != NULL)
322 {
323 return wb->enable_tree_lines;
324 }
325 return FALSE;
326 }
327
328
329 /** Set the filename.
330 *
331 * @param wb The workbench
332 * @param filename Name of the workbench file
333 *
334 **/
workbench_set_filename(WORKBENCH * wb,const gchar * filename)335 void workbench_set_filename(WORKBENCH *wb, const gchar *filename)
336 {
337 if (wb != NULL)
338 {
339 guint offset;
340 gchar *ext;
341
342 wb->filename = g_strdup(filename);
343 wb->name = g_path_get_basename (filename);
344 ext = g_strrstr(wb->name, ".geanywb");
345 if(ext != NULL)
346 {
347 offset = strlen(wb->name);
348 offset -= strlen(".geanywb");
349 if (ext == wb->name + offset)
350 {
351 /* Strip of file extension by overwriting
352 '.' with string terminator. */
353 wb->name[offset] = '\0';
354 }
355 }
356 }
357 }
358
359
360 /** Get the filename.
361 *
362 * @param wb The workbench
363 * @return The filename or NULL
364 *
365 **/
workbench_get_filename(WORKBENCH * wb)366 const gchar *workbench_get_filename(WORKBENCH *wb)
367 {
368 if (wb != NULL)
369 {
370 return wb->filename;
371 }
372 return NULL;
373 }
374
375
376 /** Get the monitor.
377 *
378 * @param wb The workbench
379 * @return Reference to the WB_MONITOR (can be NULL).
380 *
381 **/
workbench_get_monitor(WORKBENCH * wb)382 WB_MONITOR *workbench_get_monitor(WORKBENCH *wb)
383 {
384 if (wb != NULL)
385 {
386 return wb->monitor;
387 }
388 return NULL;
389 }
390
391
392 /** Get the name.
393 *
394 * @param wb The workbench
395 * @return The name or NULL
396 *
397 **/
workbench_get_name(WORKBENCH * wb)398 gchar *workbench_get_name(WORKBENCH *wb)
399 {
400 if (wb != NULL)
401 {
402 return wb->name;
403 }
404 return NULL;
405 }
406
407
408 /** Get the project stored in the workbench at @a index.
409 *
410 * @param wb The workbench
411 * @param index The index
412 * @return Adress of the WB_PROJECT structure or NULL
413 * if wb == NULL or an invalid index
414 *
415 **/
workbench_get_project_at_index(WORKBENCH * wb,guint index)416 WB_PROJECT *workbench_get_project_at_index (WORKBENCH *wb, guint index)
417 {
418 if (wb != NULL)
419 {
420 WB_PROJECT_ENTRY *entry;
421 entry = g_ptr_array_index(wb->projects, index);
422 if (entry == NULL)
423 {
424 return NULL;
425 }
426 return entry->project;
427 }
428 return NULL;
429 }
430
431
432 /** Get the project status in the workbench at @a index.
433 *
434 * Actually the project status just gives information about wheter
435 * the project file for the project at @a index was found or not.
436 *
437 * @param wb The workbench
438 * @param index The index
439 * @return the status or PROJECT_ENTRY_STATUS_UNKNOWN if wb == NULL
440 *
441 **/
workbench_get_project_status_at_index(WORKBENCH * wb,guint index)442 PROJECT_ENTRY_STATUS workbench_get_project_status_at_index (WORKBENCH *wb, guint index)
443 {
444 if (wb != NULL)
445 {
446 WB_PROJECT_ENTRY *entry;
447 entry = g_ptr_array_index(wb->projects, index);
448 if (entry == NULL)
449 {
450 return PROJECT_ENTRY_STATUS_UNKNOWN;
451 }
452 return entry->status;
453 }
454 return PROJECT_ENTRY_STATUS_UNKNOWN;
455 }
456
457
458 /** Get the project status in the workbench by address.
459 *
460 * Actually the project status just gives information about wheter
461 * the project file for the project at @a index was found or not.
462 *
463 * @param wb The workbench
464 * @param address Location of the project
465 * @return the status or PROJECT_ENTRY_STATUS_UNKNOWN if wb == NULL
466 *
467 **/
workbench_get_project_status_by_address(WORKBENCH * wb,WB_PROJECT * address)468 PROJECT_ENTRY_STATUS workbench_get_project_status_by_address (WORKBENCH *wb, WB_PROJECT *address)
469 {
470 guint index;
471 if (wb != NULL || address == NULL)
472 {
473 WB_PROJECT_ENTRY *entry;
474 for (index = 0 ; index < wb->projects->len ; index++)
475 {
476 entry = g_ptr_array_index(wb->projects, index);
477 if (entry != NULL && entry->project == address)
478 {
479 return entry->status;
480 }
481 }
482 }
483 return PROJECT_ENTRY_STATUS_UNKNOWN;
484 }
485
486
487 /** Add a project to the workbench.
488 *
489 * @param wb The workbench
490 * @param filename Project file
491 * @return TRUE on success, FALSE otherwise
492 *
493 **/
workbench_add_project(WORKBENCH * wb,const gchar * filename)494 gboolean workbench_add_project(WORKBENCH *wb, const gchar *filename)
495 {
496 if (wb != NULL)
497 {
498 GStatBuf buf;
499 WB_PROJECT *project;
500 WB_PROJECT_ENTRY *entry;
501
502 entry = wb_project_entry_new();
503 if (entry == NULL)
504 {
505 return FALSE;
506 }
507 project = wb_project_new(filename);
508 if (project == NULL)
509 {
510 wb_project_entry_free(entry);
511 return FALSE;
512 }
513
514 /* Set entry data:
515 - absolute and relative filename (relative to workbench file)
516 - per default use relative path
517 - check status of project file
518 - pointer to the project data */
519 entry->abs_filename = g_strdup(filename);
520 entry->rel_filename = get_any_relative_path
521 (wb->filename, filename);
522 entry->use_abs = FALSE;
523 entry->project = project;
524 if (g_stat (filename, &buf) == 0)
525 {
526 entry->status = PROJECT_ENTRY_STATUS_OK;
527 }
528 else
529 {
530 entry->status = PROJECT_ENTRY_STATUS_NOT_FOUND;
531 }
532 g_ptr_array_add (wb->projects, entry);
533
534 /* Load project to import base path. */
535 wb_project_load(project, filename, NULL);
536
537 /* Start immediate scan if enabled. */
538 if (wb->rescan_projects_on_open == TRUE)
539 {
540 wb_project_rescan(project);
541 }
542
543 wb->modified = TRUE;
544 return TRUE;
545 }
546 return FALSE;
547 }
548
549
550 /** Remove a project from the workbench.
551 *
552 * @param wb The workbench
553 * @param project The Project
554 * @return TRUE on success, FALSE otherwise
555 *
556 **/
workbench_remove_project_with_address(WORKBENCH * wb,WB_PROJECT * project)557 gboolean workbench_remove_project_with_address(WORKBENCH *wb, WB_PROJECT *project)
558 {
559 if (wb != NULL && wb->projects != NULL)
560 {
561 guint index;
562 WB_PROJECT_ENTRY *current;
563
564 for (index = 0 ; index < wb->projects->len ; index++)
565 {
566 current = g_ptr_array_index(wb->projects, index);
567 if (current != NULL && current->project == project)
568 {
569 g_ptr_array_remove_index (wb->projects, index);
570 wb_project_entry_free(current);
571 wb->modified = TRUE;
572 return TRUE;
573 }
574 }
575 }
576 return FALSE;
577 }
578
579
580 /** Is the file included in the workbench?
581 *
582 * @param wb The workbench
583 * @param filename The file
584 * @return Address of project in which the file is included.
585 * NULL if the file is not included in any workbench project.
586 *
587 **/
workbench_file_is_included(WORKBENCH * wb,const gchar * filename)588 WB_PROJECT *workbench_file_is_included (WORKBENCH *wb, const gchar *filename)
589 {
590 if (wb != NULL)
591 {
592 guint index;
593 WB_PROJECT_ENTRY *current;
594
595 for (index = 0 ; index < wb->projects->len ; index++)
596 {
597 current = g_ptr_array_index(wb->projects, index);
598 if (current != NULL && wb_project_file_is_included(current->project, filename) == TRUE)
599 {
600 return current->project;
601 }
602 }
603 }
604 return NULL;
605 }
606
607
608 /* Add a workbench bookmark */
workbench_add_bookmark_int(WORKBENCH * wb,const gchar * filename)609 static gboolean workbench_add_bookmark_int(WORKBENCH *wb, const gchar *filename)
610 {
611 if (wb != NULL && filename != NULL)
612 {
613 gchar *new;
614
615 new = g_strdup(filename);
616 g_ptr_array_add (wb->bookmarks, new);
617 return TRUE;
618 }
619 return FALSE;
620 }
621
622
623 /** Add a bookmark to a workbench.
624 *
625 * @param wb The workbench
626 * @param filename File to bookmark
627 * @return TRUE on success, FALSE otherwise
628 *
629 **/
workbench_add_bookmark(WORKBENCH * wb,const gchar * filename)630 gboolean workbench_add_bookmark(WORKBENCH *wb, const gchar *filename)
631 {
632 if (workbench_add_bookmark_int(wb, filename) == TRUE)
633 {
634 wb->modified = TRUE;
635 return TRUE;
636 }
637 return FALSE;
638 }
639
640
641 /** Remove a bookmark from a workbench by filename address.
642 *
643 * @param wb The workbench
644 * @param filename File to remove
645 * @return TRUE on success, FALSE otherwise
646 *
647 **/
workbench_remove_bookmark(WORKBENCH * wb,const gchar * filename)648 gboolean workbench_remove_bookmark(WORKBENCH *wb, const gchar *filename)
649 {
650 if (wb != NULL)
651 {
652 guint index;
653 gchar *current;
654
655 for (index = 0 ; index < wb->bookmarks->len ; index++)
656 {
657 current = g_ptr_array_index(wb->bookmarks, index);
658 if (current == filename)
659 {
660 g_ptr_array_remove_index (wb->bookmarks, index);
661 wb->modified = TRUE;
662 return TRUE;
663 }
664 }
665 }
666 return FALSE;
667 }
668
669
670 /** Get the bookmark at @a index.
671 *
672 * @param wb The workbench
673 * @param index The index
674 * @return Address of filename or NULL
675 *
676 **/
workbench_get_bookmark_at_index(WORKBENCH * wb,guint index)677 gchar *workbench_get_bookmark_at_index (WORKBENCH *wb, guint index)
678 {
679 if (wb != NULL)
680 {
681 gchar *file;
682 file = g_ptr_array_index(wb->bookmarks, index);
683 if (file == NULL)
684 {
685 return NULL;
686 }
687 return file;
688 }
689 return NULL;
690 }
691
692
693 /** Get the number of bookmarks in a workbench.
694 *
695 * @param wb The workbench
696 * @return The number of bookmarks or 0 if wb == NULL
697 *
698 **/
workbench_get_bookmarks_count(WORKBENCH * wb)699 guint workbench_get_bookmarks_count(WORKBENCH *wb)
700 {
701 if (wb != NULL && wb->bookmarks != NULL)
702 {
703 return wb->bookmarks->len;
704 }
705 return 0;
706 }
707
708
709 /** Save a workbench.
710 *
711 * @param wb The workbench
712 * @param error Location for returning an GError
713 * @return TRUE on success, FALSE otherwise
714 *
715 **/
workbench_save(WORKBENCH * wb,GError ** error)716 gboolean workbench_save(WORKBENCH *wb, GError **error)
717 {
718 gboolean success = FALSE;
719
720 if (wb != NULL)
721 {
722 GKeyFile *kf;
723 guint index;
724 gchar *contents;
725 gchar group[20];
726 gsize length, boomarks_size;
727 WB_PROJECT_ENTRY *entry;
728
729 kf = g_key_file_new ();
730
731 /* Save common, simple values */
732 g_key_file_set_string(kf, "General", "filetype", "workbench");
733 g_key_file_set_string(kf, "General", "version", "1.0");
734 g_key_file_set_boolean(kf, "General", "RescanProjectsOnOpen", wb->rescan_projects_on_open);
735 g_key_file_set_boolean(kf, "General", "EnableLiveUpdate", wb->enable_live_update);
736 g_key_file_set_boolean(kf, "General", "ExpandOnHover", wb->expand_on_hover);
737 g_key_file_set_boolean(kf, "General", "EnableTreeLines", wb->enable_tree_lines);
738
739 /* Save Workbench bookmarks as string list */
740 boomarks_size = workbench_get_bookmarks_count(wb);
741 if (boomarks_size > 0)
742 {
743 gchar **bookmarks_strings, *file, *rel_path;
744
745 bookmarks_strings = g_new0(gchar *, boomarks_size+1);
746 for (index = 0 ; index < boomarks_size ; index++ )
747 {
748 file = workbench_get_bookmark_at_index(wb, index);
749 rel_path = get_any_relative_path(wb->filename, file);
750
751 bookmarks_strings[index] = rel_path;
752 }
753 g_key_file_set_string_list
754 (kf, "General", "Bookmarks", (const gchar **)bookmarks_strings, boomarks_size);
755 for (index = 0 ; index < boomarks_size ; index++ )
756 {
757 g_free (bookmarks_strings[index]);
758 }
759 g_free(bookmarks_strings);
760 }
761
762 /* Save projects data */
763 for (index = 0 ; index < wb->projects->len ; index++)
764 {
765 entry = g_ptr_array_index(wb->projects, index);
766 g_snprintf(group, sizeof(group), "Project-%u", (index+1));
767 g_key_file_set_string(kf, group, "AbsFilename", entry->abs_filename);
768 g_key_file_set_string(kf, group, "RelFilename", entry->rel_filename);
769 g_key_file_set_boolean(kf, group, "UseAbsFilename", entry->use_abs);
770 }
771 contents = g_key_file_to_data (kf, &length, error);
772 if (contents != NULL && *error == NULL)
773 {
774 g_key_file_free(kf);
775
776 success = g_file_set_contents (wb->filename, contents, length, error);
777 if (success)
778 {
779 wb->modified = FALSE;
780 }
781 g_free (contents);
782 }
783 }
784 else if (error != NULL)
785 {
786 g_set_error (error, 0, 0,
787 "Internal error: param missing (file: %s, line %d)",
788 __FILE__, __LINE__);
789 }
790
791 return success;
792 }
793
794
795 /** Load a workbench file.
796 *
797 * The function loads the workbench settings from file @a filename and
798 * stores it into @a wb.
799 *
800 * @param wb The workbench
801 * @param filename File to load from
802 * @param error Location for returning an GError
803 * @return TRUE on success, FALSE otherwise
804 *
805 **/
workbench_load(WORKBENCH * wb,const gchar * filename,GError ** error)806 gboolean workbench_load(WORKBENCH *wb, const gchar *filename, GError **error)
807 {
808 gboolean success = FALSE;
809
810 if (wb != NULL)
811 {
812 GKeyFile *kf;
813 gboolean valid = TRUE;
814 guint index;
815 gchar *contents, **bookmarks_strings;
816 gchar group[20];
817 gsize length;
818 WB_PROJECT_ENTRY *entry;
819
820 if (!g_file_get_contents (filename, &contents, &length, error))
821 {
822 return FALSE;
823 }
824
825 kf = g_key_file_new ();
826
827 if (!g_key_file_load_from_data (kf, contents, length,
828 G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS,
829 error))
830 {
831 g_key_file_free (kf);
832 g_free (contents);
833 return FALSE;
834 }
835
836 if (g_key_file_has_key (kf, "General", "filetype", NULL)
837 && g_key_file_has_key (kf, "General", "version", NULL))
838 {
839 gchar *check;
840 check = g_key_file_get_string (kf, "General", "filetype", error);
841 if (check == NULL || g_strcmp0(check, "workbench") != 0)
842 {
843 valid = FALSE;
844 }
845 g_free(check);
846 }
847 else
848 {
849 valid = FALSE;
850 }
851
852 if (!valid)
853 {
854 g_set_error (error, 0, 0,
855 _("File %s is not a valid workbench file!"),
856 filename);
857 return FALSE;
858 }
859 workbench_set_filename(wb, filename);
860 wb->rescan_projects_on_open = g_key_file_get_boolean(kf, "General", "RescanProjectsOnOpen", error);
861 if (g_key_file_has_key (kf, "General", "EnableLiveUpdate", error))
862 {
863 wb->enable_live_update = g_key_file_get_boolean(kf, "General", "EnableLiveUpdate", error);
864 }
865 else
866 {
867 /* Not found. Might happen if the workbench was created with an older version of the plugin.
868 Initialize with TRUE. */
869 wb->enable_live_update = TRUE;
870 }
871 if (g_key_file_has_key (kf, "General", "ExpandOnHover", error))
872 {
873 wb->expand_on_hover = g_key_file_get_boolean(kf, "General", "ExpandOnHover", error);
874 }
875 else
876 {
877 /* Not found. Might happen if the workbench was created with an older version of the plugin.
878 Initialize with FALSE. */
879 wb->expand_on_hover = FALSE;
880 }
881 if (g_key_file_has_key (kf, "General", "EnableTreeLines", error))
882 {
883 wb->enable_tree_lines = g_key_file_get_boolean(kf, "General", "EnableTreeLines", error);
884 }
885 else
886 {
887 /* Not found. Might happen if the workbench was created with an older version of the plugin.
888 Initialize with FALSE. */
889 wb->enable_tree_lines = FALSE;
890 }
891
892 /* Load Workbench bookmarks from string list */
893 bookmarks_strings = g_key_file_get_string_list (kf, "General", "Bookmarks", NULL, error);
894 if (bookmarks_strings != NULL)
895 {
896 gchar **file, *abs_path;
897
898 file = bookmarks_strings;
899 while (*file != NULL)
900 {
901 abs_path = get_combined_path(wb->filename, *file);
902 if (abs_path != NULL)
903 {
904 workbench_add_bookmark_int(wb, abs_path);
905 g_free(abs_path);
906 }
907 file++;
908 }
909 g_strfreev(bookmarks_strings);
910 }
911
912 /* Load projects data */
913 for (index = 0 ; index < 1024 ; index++)
914 {
915 g_snprintf(group, sizeof(group), "Project-%u", (index+1));
916 if (g_key_file_has_key (kf, group, "AbsFilename", NULL))
917 {
918 gchar *prj_filename;
919 entry = wb_project_entry_new();
920 if (entry == NULL)
921 {
922 continue;
923 }
924 entry->abs_filename = g_key_file_get_string(kf, group, "AbsFilename", error);
925 entry->rel_filename = g_key_file_get_string(kf, group, "RelFilename", error);
926 entry->use_abs = g_key_file_get_boolean(kf, group, "UseAbsFilename", error);
927 if (entry->use_abs == TRUE)
928 {
929 prj_filename = entry->abs_filename;
930 }
931 else
932 {
933 prj_filename = get_combined_path
934 (wb->filename, entry->rel_filename);
935 }
936 if (prj_filename != NULL)
937 {
938 GStatBuf buf;
939
940 entry->project = wb_project_new(prj_filename);
941 if (g_stat (prj_filename, &buf) == 0)
942 {
943 entry->status = PROJECT_ENTRY_STATUS_OK;
944
945 /* ToDo: collect and handle project load errors */
946 wb_project_load(entry->project, prj_filename, error);
947 }
948 else
949 {
950 entry->status = PROJECT_ENTRY_STATUS_NOT_FOUND;
951 }
952 g_ptr_array_add (wb->projects, entry);
953
954 if (wb->rescan_projects_on_open == TRUE)
955 {
956 wb_project_rescan(entry->project);
957 }
958 }
959 }
960 else
961 {
962 break;
963 }
964 }
965
966 g_key_file_free(kf);
967 g_free (contents);
968 success = TRUE;
969 }
970 else if (error != NULL)
971 {
972 g_set_error (error, 0, 0,
973 "Internal error: param missing (file: %s, line %d)",
974 __FILE__, __LINE__);
975 }
976
977 return success;
978 }
979
980
981 /* Check if the given pointers are still valid references. */
workbench_references_are_valid(WORKBENCH * wb,WB_PROJECT * prj,WB_PROJECT_DIR * dir)982 static gboolean workbench_references_are_valid(WORKBENCH *wb, WB_PROJECT *prj, WB_PROJECT_DIR *dir)
983 {
984 guint index;
985 WB_PROJECT_ENTRY *entry;
986
987 if (wb == NULL)
988 {
989 return FALSE;
990 }
991
992 /* Try to find the project. */
993 for (index = 0 ; index < wb->projects->len ; index++)
994 {
995 entry = g_ptr_array_index(wb->projects, index);
996 if (((WB_PROJECT_ENTRY *)entry)->project == prj)
997 {
998 break;
999 }
1000 }
1001 if (index >= wb->projects->len)
1002 {
1003 return FALSE;
1004 }
1005
1006 /* Project exists in this workbench, let the project validate
1007 the directory. */
1008 return wb_project_is_valid_dir_reference(prj, dir);
1009 }
1010
1011
1012 /** Process the add file event.
1013 *
1014 * The function processes the add file event. The pointers are checked for
1015 * validity and on success the task is passed on to the project dir. file can
1016 * be the path of a regular file or a directory.
1017 *
1018 * @param wb The workbench
1019 * @param prj The project
1020 * @param dir The directory
1021 * @param file The new file to add to project/directory
1022 *
1023 **/
workbench_process_add_file_event(WORKBENCH * wb,WB_PROJECT * prj,WB_PROJECT_DIR * dir,const gchar * file)1024 void workbench_process_add_file_event(WORKBENCH *wb, WB_PROJECT *prj, WB_PROJECT_DIR *dir, const gchar *file)
1025 {
1026 if (workbench_references_are_valid(wb, prj, dir) == FALSE)
1027 {
1028 /* Should not happen, log a message and return. */
1029 g_message("%s: invalid references: wb: %p, prj: %p, dir: %p",
1030 G_STRFUNC, wb, prj, dir);
1031 return;
1032 }
1033
1034 wb_project_dir_add_file(prj, dir, file);
1035 }
1036
1037
1038 /** Process the remove file event.
1039 *
1040 * The function processes the remove file event. The pointers are checked for
1041 * validity and on success the task is passed on to the project dir. file can
1042 * be the path of a regular file or a directory.
1043 *
1044 * @param wb The workbench
1045 * @param prj The project
1046 * @param dir The directory
1047 * @param file The file to remove from project/directory
1048 *
1049 **/
workbench_process_remove_file_event(WORKBENCH * wb,WB_PROJECT * prj,WB_PROJECT_DIR * dir,const gchar * file)1050 void workbench_process_remove_file_event(WORKBENCH *wb, WB_PROJECT *prj, WB_PROJECT_DIR *dir, const gchar *file)
1051 {
1052 if (workbench_references_are_valid(wb, prj, dir) == FALSE)
1053 {
1054 /* Should not happen, log a message and return. */
1055 g_message("%s: invalid references: wb: %p, prj: %p, dir: %p",
1056 G_STRFUNC, wb, prj, dir);
1057 return;
1058 }
1059
1060 wb_project_dir_remove_file(prj, dir, file);
1061 }
1062
1063
1064 /* Foreach callback function for creating file monitors. */
workbench_enable_live_update_foreach_cb(SIDEBAR_CONTEXT * context,gpointer userdata)1065 static void workbench_enable_live_update_foreach_cb(SIDEBAR_CONTEXT *context,
1066 gpointer userdata)
1067 {
1068 gchar *dirpath = NULL;
1069 gchar *abs_path = NULL;
1070 WB_MONITOR *monitor;
1071
1072 if (context->project != NULL && context->directory != NULL)
1073 {
1074 if (context->subdir != NULL)
1075 {
1076 dirpath = context->subdir;
1077 }
1078 else
1079 {
1080 abs_path = get_combined_path(wb_project_get_filename(context->project),
1081 wb_project_dir_get_base_dir(context->directory));
1082 dirpath = abs_path;
1083 }
1084 }
1085
1086 if (dirpath != NULL)
1087 {
1088 monitor = userdata;
1089 wb_monitor_add_dir(monitor, context->project, context->directory, dirpath);
1090 }
1091
1092 g_free(abs_path);
1093 }
1094
1095
1096 /** Enable live update.
1097 *
1098 * The function enables live update of the workbench by creating file
1099 * monitors for all directories in the sidebars file tree.
1100 *
1101 * @param wb The workbench
1102 *
1103 **/
workbench_enable_live_update(WORKBENCH * wb)1104 void workbench_enable_live_update(WORKBENCH *wb)
1105 {
1106 if (wb != NULL)
1107 {
1108 sidebar_call_foreach(DATA_ID_DIRECTORY,
1109 workbench_enable_live_update_foreach_cb, wb->monitor);
1110 sidebar_call_foreach(DATA_ID_SUB_DIRECTORY,
1111 workbench_enable_live_update_foreach_cb, wb->monitor);
1112 }
1113 }
1114
1115
1116 /** Disable live update.
1117 *
1118 * The function disables live update of the workbench by freeing all
1119 * file monitors.
1120 *
1121 * @param wb The workbench
1122 *
1123 **/
workbench_disable_live_update(WORKBENCH * wb)1124 void workbench_disable_live_update(WORKBENCH *wb)
1125 {
1126 if (wb != NULL)
1127 {
1128 wb_monitor_free(wb->monitor);
1129 }
1130 }
1131