1 /* ide-project-info.c
2 *
3 * Copyright 2015-2019 Christian Hergert <christian@hergert.me>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE
23 #endif
24
25 #define G_LOG_DOMAIN "ide-project-info"
26
27 #include "config.h"
28
29 #include <glib/gi18n.h>
30 #include <string.h>
31
32 #include "ide-gfile-private.h"
33
34 #include "ide-project-info.h"
35 #include "ide-project-info-private.h"
36
37 /**
38 * SECTION:ideprojectinfo:
39 * @title: IdeProjectInfo
40 * @short_description: Information about a project not yet loaded
41 *
42 * This class contains information about a project that can be loaded.
43 * This information should be used to display a list of available projects.
44 *
45 * Since: 3.32
46 */
47
48 struct _IdeProjectInfo
49 {
50 GObject parent_instance;
51
52 gchar *id;
53 IdeDoap *doap;
54 GDateTime *last_modified_at;
55 GFile *directory;
56 GFile *directory_translated;
57 GFile *file;
58 GFile *file_translated;
59 gchar *build_system_name;
60 gchar *build_system_hint;
61 gchar *name;
62 gchar *description;
63 gchar **languages;
64 gchar *vcs_uri;
65 GIcon *icon;
66
67 gint priority;
68
69 guint is_recent : 1;
70 };
71
72 G_DEFINE_FINAL_TYPE (IdeProjectInfo, ide_project_info, G_TYPE_OBJECT)
73
74 enum {
75 PROP_0,
76 PROP_BUILD_SYSTEM_HINT,
77 PROP_BUILD_SYSTEM_NAME,
78 PROP_DESCRIPTION,
79 PROP_DIRECTORY,
80 PROP_DOAP,
81 PROP_FILE,
82 PROP_ICON,
83 PROP_ICON_NAME,
84 PROP_ID,
85 PROP_IS_RECENT,
86 PROP_LANGUAGES,
87 PROP_LAST_MODIFIED_AT,
88 PROP_NAME,
89 PROP_PRIORITY,
90 PROP_VCS_URI,
91 LAST_PROP
92 };
93
94 static GParamSpec *properties [LAST_PROP];
95
96 /**
97 * ide_project_info_get_doap:
98 *
99 *
100 * Returns: (nullable) (transfer none): An #IdeDoap or %NULL.
101 *
102 * Since: 3.32
103 */
104 IdeDoap *
ide_project_info_get_doap(IdeProjectInfo * self)105 ide_project_info_get_doap (IdeProjectInfo *self)
106 {
107 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
108
109 return self->doap;
110 }
111
112 void
ide_project_info_set_doap(IdeProjectInfo * self,IdeDoap * doap)113 ide_project_info_set_doap (IdeProjectInfo *self,
114 IdeDoap *doap)
115 {
116 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
117 g_return_if_fail (!doap || IDE_IS_DOAP (doap));
118
119 if (g_set_object (&self->doap, doap))
120 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DOAP]);
121 }
122
123 /**
124 * ide_project_info_get_languages:
125 *
126 * Returns: (transfer none): An array of language names.
127 *
128 * Since: 3.32
129 */
130 const gchar * const *
ide_project_info_get_languages(IdeProjectInfo * self)131 ide_project_info_get_languages (IdeProjectInfo *self)
132 {
133 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
134
135 return (const gchar * const *)self->languages;
136 }
137
138 void
ide_project_info_set_languages(IdeProjectInfo * self,gchar ** languages)139 ide_project_info_set_languages (IdeProjectInfo *self,
140 gchar **languages)
141 {
142 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
143
144 if (languages != self->languages)
145 {
146 g_strfreev (self->languages);
147 self->languages = g_strdupv (languages);
148 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LANGUAGES]);
149 }
150 }
151
152 gint
ide_project_info_get_priority(IdeProjectInfo * self)153 ide_project_info_get_priority (IdeProjectInfo *self)
154 {
155 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), 0);
156
157 return self->priority;
158 }
159
160 void
ide_project_info_set_priority(IdeProjectInfo * self,gint priority)161 ide_project_info_set_priority (IdeProjectInfo *self,
162 gint priority)
163 {
164 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
165
166 if (self->priority != priority)
167 {
168 self->priority = priority;
169 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PRIORITY]);
170 }
171 }
172
173 /**
174 * ide_project_info_get_directory:
175 * @self: (in): an #IdeProjectInfo.
176 *
177 * Gets the #IdeProjectInfo:directory property.
178 * This is the directory containing the project (if known).
179 *
180 * Returns: (nullable) (transfer none): a #GFile.
181 *
182 * Since: 3.32
183 */
184 GFile *
ide_project_info_get_directory(IdeProjectInfo * self)185 ide_project_info_get_directory (IdeProjectInfo *self)
186 {
187 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
188
189 return self->directory_translated;
190 }
191
192 /**
193 * ide_project_info_get_file:
194 * @self: (in): an #IdeProjectInfo.
195 *
196 * Gets the #IdeProjectInfo:file property.
197 * This is the project file (such as configure.ac) of the project.
198 *
199 * Returns: (nullable) (transfer none): a #GFile.
200 *
201 * Since: 3.32
202 */
203 GFile *
ide_project_info_get_file(IdeProjectInfo * self)204 ide_project_info_get_file (IdeProjectInfo *self)
205 {
206 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
207
208 return self->file_translated;
209 }
210
211 /**
212 * ide_project_info_get_last_modified_at:
213 *
214 *
215 * Returns: (transfer none) (nullable): a #GDateTime or %NULL.
216 *
217 * Since: 3.32
218 */
219 GDateTime *
ide_project_info_get_last_modified_at(IdeProjectInfo * self)220 ide_project_info_get_last_modified_at (IdeProjectInfo *self)
221 {
222 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
223
224 return self->last_modified_at;
225 }
226
227 const gchar *
ide_project_info_get_build_system_hint(IdeProjectInfo * self)228 ide_project_info_get_build_system_hint (IdeProjectInfo *self)
229 {
230 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
231
232 return self->build_system_hint;
233 }
234
235 void
ide_project_info_set_build_system_hint(IdeProjectInfo * self,const gchar * build_system_hint)236 ide_project_info_set_build_system_hint (IdeProjectInfo *self,
237 const gchar *build_system_hint)
238 {
239 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
240
241 if (!ide_str_equal0 (self->build_system_hint, build_system_hint))
242 {
243 g_free (self->build_system_hint);
244 self->build_system_hint = g_strdup (build_system_hint);
245 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUILD_SYSTEM_HINT]);
246 }
247 }
248
249 const gchar *
ide_project_info_get_build_system_name(IdeProjectInfo * self)250 ide_project_info_get_build_system_name (IdeProjectInfo *self)
251 {
252 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
253
254 return self->build_system_name;
255 }
256
257 void
ide_project_info_set_build_system_name(IdeProjectInfo * self,const gchar * build_system_name)258 ide_project_info_set_build_system_name (IdeProjectInfo *self,
259 const gchar *build_system_name)
260 {
261 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
262
263 if (!ide_str_equal0 (self->build_system_name, build_system_name))
264 {
265 g_free (self->build_system_name);
266 self->build_system_name = g_strdup (build_system_name);
267 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUILD_SYSTEM_NAME]);
268 }
269 }
270
271 const gchar *
ide_project_info_get_description(IdeProjectInfo * self)272 ide_project_info_get_description (IdeProjectInfo *self)
273 {
274 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
275
276 return self->description;
277 }
278
279 void
ide_project_info_set_description(IdeProjectInfo * self,const gchar * description)280 ide_project_info_set_description (IdeProjectInfo *self,
281 const gchar *description)
282 {
283 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
284
285 if (!ide_str_equal0 (self->description, description))
286 {
287 g_free (self->description);
288 self->description = g_strdup (description);
289 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DESCRIPTION]);
290 }
291 }
292
293 const gchar *
ide_project_info_get_name(IdeProjectInfo * self)294 ide_project_info_get_name (IdeProjectInfo *self)
295 {
296 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
297
298 return self->name;
299 }
300
301 void
ide_project_info_set_name(IdeProjectInfo * self,const gchar * name)302 ide_project_info_set_name (IdeProjectInfo *self,
303 const gchar *name)
304 {
305 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
306
307 if (!ide_str_equal0 (self->name, name))
308 {
309 g_free (self->name);
310 self->name = g_strdup (name);
311 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_NAME]);
312 }
313 }
314
315 void
ide_project_info_set_directory(IdeProjectInfo * self,GFile * directory)316 ide_project_info_set_directory (IdeProjectInfo *self,
317 GFile *directory)
318 {
319 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
320 g_return_if_fail (!directory || G_IS_FILE (directory));
321
322 if (g_set_object (&self->directory, directory))
323 {
324 g_clear_object (&self->directory_translated);
325 self->directory_translated = _ide_g_file_readlink (directory);
326 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DIRECTORY]);
327 }
328 }
329
330 void
ide_project_info_set_file(IdeProjectInfo * self,GFile * file)331 ide_project_info_set_file (IdeProjectInfo *self,
332 GFile *file)
333 {
334 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
335 g_return_if_fail (!file || G_IS_FILE (file));
336
337 if (g_set_object (&self->file, file))
338 {
339 g_clear_object (&self->file_translated);
340 self->file_translated = _ide_g_file_readlink (file);
341 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_FILE]);
342 }
343 }
344
345 void
ide_project_info_set_last_modified_at(IdeProjectInfo * self,GDateTime * last_modified_at)346 ide_project_info_set_last_modified_at (IdeProjectInfo *self,
347 GDateTime *last_modified_at)
348 {
349 g_assert (IDE_IS_PROJECT_INFO (self));
350
351 if (last_modified_at != self->last_modified_at)
352 {
353 g_clear_pointer (&self->last_modified_at, g_date_time_unref);
354 self->last_modified_at = last_modified_at ? g_date_time_ref (last_modified_at) : NULL;
355 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LAST_MODIFIED_AT]);
356 }
357 }
358
359 gboolean
ide_project_info_get_is_recent(IdeProjectInfo * self)360 ide_project_info_get_is_recent (IdeProjectInfo *self)
361 {
362 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), FALSE);
363
364 return self->is_recent;
365 }
366
367 void
ide_project_info_set_is_recent(IdeProjectInfo * self,gboolean is_recent)368 ide_project_info_set_is_recent (IdeProjectInfo *self,
369 gboolean is_recent)
370 {
371 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
372
373 is_recent = !!is_recent;
374
375 if (self->is_recent != is_recent)
376 {
377 self->is_recent = is_recent;
378 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_IS_RECENT]);
379 }
380 }
381
382 static void
ide_project_info_finalize(GObject * object)383 ide_project_info_finalize (GObject *object)
384 {
385 IdeProjectInfo *self = (IdeProjectInfo *)object;
386
387 g_clear_pointer (&self->id, g_free);
388 g_clear_pointer (&self->last_modified_at, g_date_time_unref);
389 g_clear_pointer (&self->build_system_hint, g_free);
390 g_clear_pointer (&self->build_system_name, g_free);
391 g_clear_pointer (&self->description, g_free);
392 g_clear_pointer (&self->languages, g_strfreev);
393 g_clear_pointer (&self->vcs_uri, g_free);
394 g_clear_pointer (&self->name, g_free);
395 g_clear_object (&self->directory);
396 g_clear_object (&self->directory_translated);
397 g_clear_object (&self->file);
398 g_clear_object (&self->file_translated);
399 g_clear_object (&self->icon);
400
401 G_OBJECT_CLASS (ide_project_info_parent_class)->finalize (object);
402 }
403
404 static void
ide_project_info_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)405 ide_project_info_get_property (GObject *object,
406 guint prop_id,
407 GValue *value,
408 GParamSpec *pspec)
409 {
410 IdeProjectInfo *self = IDE_PROJECT_INFO (object);
411
412 switch (prop_id)
413 {
414 case PROP_BUILD_SYSTEM_HINT:
415 g_value_set_string (value, ide_project_info_get_build_system_hint (self));
416 break;
417
418 case PROP_BUILD_SYSTEM_NAME:
419 g_value_set_string (value, ide_project_info_get_build_system_name (self));
420 break;
421
422 case PROP_DESCRIPTION:
423 g_value_set_string (value, ide_project_info_get_description (self));
424 break;
425
426 case PROP_DIRECTORY:
427 g_value_set_object (value, ide_project_info_get_directory (self));
428 break;
429
430 case PROP_DOAP:
431 g_value_set_object (value, ide_project_info_get_doap (self));
432 break;
433
434 case PROP_FILE:
435 g_value_set_object (value, ide_project_info_get_file (self));
436 break;
437
438 case PROP_ICON:
439 g_value_set_object (value, ide_project_info_get_icon (self));
440 break;
441
442 case PROP_ID:
443 g_value_set_string (value, ide_project_info_get_id (self));
444 break;
445
446 case PROP_IS_RECENT:
447 g_value_set_boolean (value, ide_project_info_get_is_recent (self));
448 break;
449
450 case PROP_LANGUAGES:
451 g_value_set_boxed (value, ide_project_info_get_languages (self));
452 break;
453
454 case PROP_LAST_MODIFIED_AT:
455 g_value_set_boxed (value, ide_project_info_get_last_modified_at (self));
456 break;
457
458 case PROP_NAME:
459 g_value_set_string (value, ide_project_info_get_name (self));
460 break;
461
462 case PROP_PRIORITY:
463 g_value_set_int (value, ide_project_info_get_priority (self));
464 break;
465
466 case PROP_VCS_URI:
467 g_value_set_string (value, ide_project_info_get_vcs_uri (self));
468 break;
469
470 default:
471 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
472 }
473 }
474
475 static void
ide_project_info_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)476 ide_project_info_set_property (GObject *object,
477 guint prop_id,
478 const GValue *value,
479 GParamSpec *pspec)
480 {
481 IdeProjectInfo *self = IDE_PROJECT_INFO (object);
482
483 switch (prop_id)
484 {
485 case PROP_BUILD_SYSTEM_HINT:
486 ide_project_info_set_build_system_hint (self, g_value_get_string (value));
487 break;
488
489 case PROP_BUILD_SYSTEM_NAME:
490 ide_project_info_set_build_system_name (self, g_value_get_string (value));
491 break;
492
493 case PROP_DESCRIPTION:
494 ide_project_info_set_description (self, g_value_get_string (value));
495 break;
496
497 case PROP_DIRECTORY:
498 ide_project_info_set_directory (self, g_value_get_object (value));
499 break;
500
501 case PROP_DOAP:
502 ide_project_info_set_doap (self, g_value_get_object (value));
503 break;
504
505 case PROP_FILE:
506 ide_project_info_set_file (self, g_value_get_object (value));
507 break;
508
509 case PROP_ICON:
510 ide_project_info_set_icon (self, g_value_get_object (value));
511 break;
512
513 case PROP_ICON_NAME:
514 ide_project_info_set_icon_name (self, g_value_get_string (value));
515 break;
516
517 case PROP_ID:
518 ide_project_info_set_id (self, g_value_get_string (value));
519 break;
520
521 case PROP_IS_RECENT:
522 ide_project_info_set_is_recent (self, g_value_get_boolean (value));
523 break;
524
525 case PROP_LANGUAGES:
526 ide_project_info_set_languages (self, g_value_get_boxed (value));
527 break;
528
529 case PROP_LAST_MODIFIED_AT:
530 ide_project_info_set_last_modified_at (self, g_value_get_boxed (value));
531 break;
532
533 case PROP_NAME:
534 ide_project_info_set_name (self, g_value_get_string (value));
535 break;
536
537 case PROP_PRIORITY:
538 ide_project_info_set_priority (self, g_value_get_int (value));
539 break;
540
541 case PROP_VCS_URI:
542 ide_project_info_set_vcs_uri (self, g_value_get_string (value));
543 break;
544
545 default:
546 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
547 }
548 }
549
550 static void
ide_project_info_class_init(IdeProjectInfoClass * klass)551 ide_project_info_class_init (IdeProjectInfoClass *klass)
552 {
553 GObjectClass *object_class = G_OBJECT_CLASS (klass);
554
555 object_class->finalize = ide_project_info_finalize;
556 object_class->get_property = ide_project_info_get_property;
557 object_class->set_property = ide_project_info_set_property;
558
559 properties [PROP_BUILD_SYSTEM_HINT] =
560 g_param_spec_string ("build-system-hint",
561 "Build System hint",
562 "Build System hint",
563 NULL,
564 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
565
566 properties [PROP_BUILD_SYSTEM_NAME] =
567 g_param_spec_string ("build-system-name",
568 "Build System name",
569 "Build System name",
570 NULL,
571 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
572
573 properties [PROP_DESCRIPTION] =
574 g_param_spec_string ("description",
575 "Description",
576 "The project description.",
577 NULL,
578 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
579
580 properties [PROP_ICON] =
581 g_param_spec_object ("icon",
582 "Icon",
583 "The icon for the project",
584 G_TYPE_ICON,
585 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
586
587 properties [PROP_ICON_NAME] =
588 g_param_spec_string ("icon-name",
589 "Icon Name",
590 "The icon-name for the project",
591 NULL,
592 (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
593
594 properties [PROP_ID] =
595 g_param_spec_string ("id",
596 "Id",
597 "The identifier for the project",
598 NULL,
599 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
600
601 properties [PROP_NAME] =
602 g_param_spec_string ("name",
603 "Name",
604 "The project name.",
605 NULL,
606 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
607
608 properties [PROP_DIRECTORY] =
609 g_param_spec_object ("directory",
610 "Directory",
611 "The project directory.",
612 G_TYPE_FILE,
613 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
614
615 properties [PROP_DOAP] =
616 g_param_spec_object ("doap",
617 "DOAP",
618 "A DOAP describing the project.",
619 IDE_TYPE_DOAP,
620 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
621
622 properties [PROP_FILE] =
623 g_param_spec_object ("file",
624 "File",
625 "The toplevel project file.",
626 G_TYPE_FILE,
627 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
628
629 properties [PROP_IS_RECENT] =
630 g_param_spec_boolean ("is-recent",
631 "Is Recent",
632 "Is Recent",
633 FALSE,
634 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
635
636 properties [PROP_LANGUAGES] =
637 g_param_spec_boxed ("languages",
638 "Languages",
639 "Languages",
640 G_TYPE_STRV,
641 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
642
643 properties [PROP_LAST_MODIFIED_AT] =
644 g_param_spec_boxed ("last-modified-at",
645 "Last Modified At",
646 "Last Modified At",
647 G_TYPE_DATE_TIME,
648 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
649
650 properties [PROP_PRIORITY] =
651 g_param_spec_int ("priority",
652 "Priority",
653 "The priority of the project information type.",
654 G_MININT,
655 G_MAXINT,
656 0,
657 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
658
659 properties [PROP_VCS_URI] =
660 g_param_spec_string ("vcs-uri",
661 "Vcs Uri",
662 "The VCS URI of the project, in case it is not local",
663 NULL,
664 (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
665
666 g_object_class_install_properties (object_class, LAST_PROP, properties);
667 }
668
669 static void
ide_project_info_init(IdeProjectInfo * self)670 ide_project_info_init (IdeProjectInfo *self)
671 {
672 }
673
674 gint
ide_project_info_compare(IdeProjectInfo * info1,IdeProjectInfo * info2)675 ide_project_info_compare (IdeProjectInfo *info1,
676 IdeProjectInfo *info2)
677 {
678 const gchar *name1;
679 const gchar *name2;
680 GDateTime *dt1;
681 GDateTime *dt2;
682 gint ret;
683 gint prio1;
684 gint prio2;
685
686 g_assert (IDE_IS_PROJECT_INFO (info1));
687 g_assert (IDE_IS_PROJECT_INFO (info2));
688
689 if (info1 == info2)
690 return 0;
691
692 prio1 = ide_project_info_get_priority (info1);
693 prio2 = ide_project_info_get_priority (info2);
694
695 if (prio1 != prio2)
696 return prio1 - prio2;
697
698 dt1 = ide_project_info_get_last_modified_at (info1);
699 dt2 = ide_project_info_get_last_modified_at (info2);
700
701 ret = g_date_time_compare (dt2, dt1);
702
703 if (ret != 0)
704 return ret;
705
706 name1 = ide_project_info_get_name (info1);
707 name2 = ide_project_info_get_name (info2);
708
709 if (name1 == NULL)
710 return 1;
711 else if (name2 == NULL)
712 return -1;
713 else
714 return strcasecmp (name1, name2);
715 }
716
717 /**
718 * ide_project_info_get_vcs_uri:
719 * @self: an #IdeProjectInfo
720 *
721 * Gets the VCS URI for the project info. This should be set with the
722 * remote URI for the version control system. It can be used to clone the
723 * project when activated from the greeter.
724 *
725 * Returns: (transfer none) (nullable): a #IdeVcsUri or %NULL
726 *
727 * Since: 3.32
728 */
729 const gchar *
ide_project_info_get_vcs_uri(IdeProjectInfo * self)730 ide_project_info_get_vcs_uri (IdeProjectInfo *self)
731 {
732 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
733
734 return self->vcs_uri;
735 }
736
737 void
ide_project_info_set_vcs_uri(IdeProjectInfo * self,const gchar * vcs_uri)738 ide_project_info_set_vcs_uri (IdeProjectInfo *self,
739 const gchar *vcs_uri)
740 {
741 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
742
743 if (!ide_str_equal0 (self->vcs_uri, vcs_uri))
744 {
745 g_free (self->vcs_uri);
746 self->vcs_uri = g_strdup (vcs_uri);
747 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VCS_URI]);
748 }
749 }
750
751 IdeProjectInfo *
ide_project_info_new(void)752 ide_project_info_new (void)
753 {
754 return g_object_new (IDE_TYPE_PROJECT_INFO, NULL);
755 }
756
757 /**
758 * ide_project_info_equal:
759 * @self: a #IdeProjectInfo
760 * @other: a #IdeProjectInfo
761 *
762 * This function will check to see if information about @self and @other are
763 * similar enough that a request to open @other would instead activate
764 * @self. This is useful when a user tries to open the same project twice.
765 *
766 * However, some case is taken to ensure that things like the build system
767 * are the same so that a project may be opened twice with two build systems
768 * as is sometimes necessary when projects are porting to a new build
769 * system.
770 *
771 * Returns: %TRUE if @self and @other are the same project and similar
772 * enough to be considered equal.
773 *
774 * Since: 3.32
775 */
776 gboolean
ide_project_info_equal(IdeProjectInfo * self,IdeProjectInfo * other)777 ide_project_info_equal (IdeProjectInfo *self,
778 IdeProjectInfo *other)
779 {
780 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), FALSE);
781 g_return_val_if_fail (IDE_IS_PROJECT_INFO (other), FALSE);
782
783 if (!self->file || !other->file ||
784 !g_file_equal (self->file, other->file))
785 {
786 if (!self->directory || !other->directory ||
787 !g_file_equal (self->directory, other->directory))
788 return FALSE;
789 }
790
791 /* build-system only set in one of the project-info?
792 * That's fine, we'll consider them the same to avoid over
793 * activating a second workbench
794 */
795 if ((!self->build_system_name && other->build_system_name) ||
796 (self->build_system_name && !other->build_system_name))
797 return TRUE;
798
799 return ide_str_equal0 (self->build_system_name, other->build_system_name);
800 }
801
802 const gchar *
ide_project_info_get_id(IdeProjectInfo * self)803 ide_project_info_get_id (IdeProjectInfo *self)
804 {
805 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
806
807 if (!self->id && self->directory)
808 self->id = g_file_get_basename (self->directory);
809
810 if (!self->id && self->file)
811 {
812 if (g_file_query_file_type (self->file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
813 self->id = g_file_get_basename (self->file);
814 else
815 {
816 g_autoptr(GFile) parent = g_file_get_parent (self->file);
817 self->id = g_file_get_basename (parent);
818 }
819 }
820
821 if (!self->id && self->doap)
822 self->id = g_strdup (ide_doap_get_name (self->doap));
823
824 if (!self->id && self->vcs_uri)
825 {
826 const gchar *path = self->vcs_uri;
827
828 if (strstr (path, "//"))
829 path = strstr (path, "//") + 1;
830
831 if (strchr (path, '/'))
832 path = strchr (path, '/');
833 else if (strrchr (path, ':'))
834 path = strrchr (path, ':');
835
836 self->id = g_path_get_basename (path);
837 }
838
839 return self->id;
840 }
841
842 void
ide_project_info_set_id(IdeProjectInfo * self,const gchar * id)843 ide_project_info_set_id (IdeProjectInfo *self,
844 const gchar *id)
845 {
846 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
847
848 if (!ide_str_equal0 (id, self->id))
849 {
850 g_free (self->id);
851 self->id = g_strdup (id);
852 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
853 }
854 }
855
856 /**
857 * ide_project_info_get_icon:
858 * @self: a #IdeProjectInfo
859 *
860 * Gets the #IdeProjectInfo:icon property.
861 *
862 * Returns: (transfer none) (nullable): a #GIcon or %NULL
863 *
864 * Since: 3.32
865 */
866 GIcon *
ide_project_info_get_icon(IdeProjectInfo * self)867 ide_project_info_get_icon (IdeProjectInfo *self)
868 {
869 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
870
871 return self->icon;
872 }
873
874 void
ide_project_info_set_icon(IdeProjectInfo * self,GIcon * icon)875 ide_project_info_set_icon (IdeProjectInfo *self,
876 GIcon *icon)
877 {
878 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
879 g_return_if_fail (!icon || G_IS_ICON (icon));
880
881 if (g_set_object (&self->icon, icon))
882 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON]);
883 }
884
885 void
ide_project_info_set_icon_name(IdeProjectInfo * self,const gchar * icon_name)886 ide_project_info_set_icon_name (IdeProjectInfo *self,
887 const gchar *icon_name)
888 {
889 g_autoptr(GIcon) icon = NULL;
890
891 g_return_if_fail (IDE_IS_PROJECT_INFO (self));
892
893 if (icon_name != NULL)
894 icon = g_themed_icon_new (icon_name);
895 ide_project_info_set_icon (self, icon);
896 }
897
898 GFile *
_ide_project_info_get_real_file(IdeProjectInfo * self)899 _ide_project_info_get_real_file (IdeProjectInfo *self)
900 {
901 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
902 return self->file;
903 }
904
905 GFile *
_ide_project_info_get_real_directory(IdeProjectInfo * self)906 _ide_project_info_get_real_directory (IdeProjectInfo *self)
907 {
908 g_return_val_if_fail (IDE_IS_PROJECT_INFO (self), NULL);
909 return self->directory;
910 }
911