1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3
* Copyright (C) 2010 ammonkey
5
* This library is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU Lesser General Public License
7
* version 3.0 as published by the Free Software Foundation.
9
* This library 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 Lesser General Public License version 3.0 for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library. If not, see
16
* <http://www.gnu.org/licenses/>.
18
* Author: ammonkey <am.monkeyd@gmail.com>
24
#include "nautilus-icon-info.h"
25
#include "marlin-global-preferences.h"
30
/*struct _GOFFilePrivate {
31
GFileInfo* _file_info;
35
//#define gof_FILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GOF_TYPE_FILE, GOFFilePrivate))
37
gof_FILE_DUMMY_PROPERTY,
44
FM_LIST_MODEL_FILE_COLUMN,
46
FM_LIST_MODEL_FILENAME,
49
FM_LIST_MODEL_MODIFIED,
50
/*FM_LIST_MODEL_SUBDIRECTORY_COLUMN,
51
FM_LIST_MODEL_SMALLEST_ICON_COLUMN,
52
FM_LIST_MODEL_SMALLER_ICON_COLUMN,
53
FM_LIST_MODEL_SMALL_ICON_COLUMN,
54
FM_LIST_MODEL_STANDARD_ICON_COLUMN,
55
FM_LIST_MODEL_LARGE_ICON_COLUMN,
56
FM_LIST_MODEL_LARGER_ICON_COLUMN,
57
FM_LIST_MODEL_LARGEST_ICON_COLUMN,
58
FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN,
59
FM_LIST_MODEL_SMALLER_EMBLEM_COLUMN,
60
FM_LIST_MODEL_SMALL_EMBLEM_COLUMN,
61
FM_LIST_MODEL_STANDARD_EMBLEM_COLUMN,
62
FM_LIST_MODEL_LARGE_EMBLEM_COLUMN,
63
FM_LIST_MODEL_LARGER_EMBLEM_COLUMN,
64
FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN,
65
FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN,*/
66
FM_LIST_MODEL_NUM_COLUMNS
70
//static void gof_file_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec);
71
//static void gof_file_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec);
73
G_DEFINE_TYPE (GOFFile, gof_file, G_TYPE_OBJECT)
75
#define SORT_LAST_CHAR1 '.'
76
#define SORT_LAST_CHAR2 '#'
79
static int _vala_strcmp0 (const char * str1, const char * str2) {
81
return -(str1 != str2);
86
return strcmp (str1, str2);
90
gint gof_file_NameCompareFunc (GOFFile* a, GOFFile* b) {
92
g_return_val_if_fail (a != NULL, 0);
93
g_return_val_if_fail (b != NULL, 0);
94
if (gof_file_get_directory (a) != gof_file_get_directory (b)) {
95
result = ((gint) gof_file_get_directory (b)) - ((gint) gof_file_get_directory (a));
98
char* _tmp1_ = g_utf8_casefold (gof_file_get_name (b), -1);
99
char* _tmp0_ = g_utf8_casefold (gof_file_get_name (a), -1);
100
if (_vala_strcmp0 (_tmp0_, _tmp1_) < 0) {
108
if ((_tmp5_ = _vala_strcmp0 (_tmp3_ = g_utf8_casefold (gof_file_get_name (a), -1), _tmp4_ = g_utf8_casefold (gof_file_get_name (b), -1)) == 0, _g_free0 (_tmp4_), _g_free0 (_tmp3_), _tmp5_)) {
119
gint gof_file_SizeCompareFunc (GOFFile* a, GOFFile* b) {
121
g_return_val_if_fail (a != NULL, 0);
122
g_return_val_if_fail (b != NULL, 0);
123
if (gof_file_get_directory (a) != gof_file_get_directory (b)) {
124
result = ((gint) gof_file_get_directory (b)) - ((gint) gof_file_get_directory (a));
127
if (gof_file_get_size (a) < gof_file_get_size (b)) {
131
if (gof_file_get_size (a) > gof_file_get_size (b)) {
143
//GOFFile* gof_file_new (GFileInfo* file_info, GFileEnumerator *enumerator)
144
GOFFile* gof_file_new (GFileInfo* file_info, GFile *dir)
147
NautilusIconInfo *nicon;
149
g_return_val_if_fail (file_info != NULL, NULL);
150
self = (GOFFile*) g_object_new (GOF_TYPE_FILE, NULL);
151
self->info = file_info;
152
//self->parent_dir = g_file_enumerator_get_container (enumerator);
153
self->directory = dir;
154
//printf ("test parent_dir %s\n", g_file_get_uri(self->directory));
155
//g_object_ref (self->directory);
156
self->name = g_file_info_get_name (file_info);
157
self->location = g_file_get_child(self->directory, self->name);
158
self->ftype = g_file_info_get_attribute_string (file_info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
159
self->utf8_collation_key = g_utf8_collate_key (self->name, -1);
160
self->size = (guint64) g_file_info_get_size (file_info);
161
self->format_size = g_format_size_for_display(self->size);
162
self->file_type = g_file_info_get_file_type(file_info);
163
//self->is_directory = (self->file_type & G_FILE_TYPE_DIRECTORY) != 0;
164
self->is_directory = (self->file_type == G_FILE_TYPE_DIRECTORY);
165
self->icon = g_content_type_get_icon (self->ftype);
166
self->is_hidden = g_file_info_get_is_hidden (file_info);
167
self->modified = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
169
nicon = nautilus_icon_info_lookup (self->icon, 16);
170
self->pix = nautilus_icon_info_get_pixbuf_nodefault (nicon);
171
g_object_unref (nicon);
177
GFileInfo* gof_file_get_file_info (GOFFile* self) {
179
g_return_val_if_fail (self != NULL, NULL);
184
static void gof_file_init (GOFFile *self) {
188
static void gof_file_finalize (GObject* obj) {
191
file = GOF_FILE (obj);
192
printf ("%s %s\n", G_STRFUNC, file->name);
193
_g_object_unref0 (file->info);
194
_g_object_unref0 (file->location);
195
g_free(file->utf8_collation_key);
196
g_free(file->format_size);
197
_g_object_unref0 (file->icon);
198
_g_object_unref0 (file->pix);
200
G_OBJECT_CLASS (gof_file_parent_class)->finalize (obj);
203
static void gof_file_class_init (GOFFileClass * klass) {
204
gof_file_parent_class = g_type_class_peek_parent (klass);
205
//g_type_class_add_private (klass, sizeof (GOFFilePrivate));
206
/*G_OBJECT_CLASS (klass)->get_property = gof_file_get_property;
207
G_OBJECT_CLASS (klass)->set_property = gof_file_set_property;*/
208
G_OBJECT_CLASS (klass)->finalize = gof_file_finalize;
209
/*g_object_class_install_property (G_OBJECT_CLASS (klass), gof_FILE_NAME, g_param_spec_string ("name", "name", "name", NULL, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
210
g_object_class_install_property (G_OBJECT_CLASS (klass), gof_FILE_SIZE, g_param_spec_uint64 ("size", "size", "size", 0, G_MAXUINT64, 0U, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));
211
g_object_class_install_property (G_OBJECT_CLASS (klass), gof_FILE_DIRECTORY, g_param_spec_boolean ("directory", "directory", "directory", FALSE, G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_READABLE));*/
215
static void gof_file_instance_init (GOFFile * self) {
216
self->priv = gof_FILE_GET_PRIVATE (self);
220
GType gof_file_get_type (void) {
221
static volatile gsize gof_file_type_id__volatile = 0;
222
if (g_once_init_enter (&gof_file_type_id__volatile)) {
223
static const GTypeInfo g_define_type_info = { sizeof (GOFFileClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gof_file_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GOFFile), 0, (GInstanceInitFunc) gof_file_instance_init, NULL };
224
GType gof_file_type_id;
225
gof_file_type_id = g_type_register_static (G_TYPE_OBJECT, "GOFFile", &g_define_type_info, 0);
226
g_once_init_leave (&gof_file_type_id__volatile, gof_file_type_id);
228
return gof_file_type_id__volatile;
233
static void gof_file_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
235
self = GOF_FILE (object);
236
switch (property_id) {
238
g_value_set_string (value, gof_file_get_name (self));
241
g_value_set_uint64 (value, gof_file_get_size (self));
243
case gof_FILE_DIRECTORY:
244
g_value_set_boolean (value, gof_file_get_directory (self));
247
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
253
static void gof_file_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) {
255
self = GOF_FILE (object);
256
switch (property_id) {
258
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
265
compare_files_by_time (GOFFile *file1, GOFFile *file2)
267
if (file1->modified < file2->modified)
269
else if (file1->modified > file2->modified)
276
compare_by_time (GOFFile *file1, GOFFile *file2)
278
if (file1->is_directory && !file2->is_directory)
280
if (file2->is_directory && !file1->is_directory)
283
return compare_files_by_time (file1, file2);
287
compare_by_type (GOFFile *file1, GOFFile *file2)
289
/*char *type_string_1;
293
/* Directories go first. Then, if mime types are identical,
294
* don't bother getting strings (for speed). This assumes
295
* that the string is dependent entirely on the mime type,
296
* which is true now but might not be later.
298
if (file1->is_directory && file2->is_directory)
300
if (file1->is_directory)
302
if (file2->is_directory)
305
if (file1->ftype != NULL && file2->ftype != NULL &&
306
strcmp (eel_ref_str_peek (file_1->details->mime_type),
307
eel_ref_str_peek (file_2->details->mime_type)) == 0) {
311
type_string_1 = nautilus_file_get_type_as_string (file_1);
312
type_string_2 = nautilus_file_get_type_as_string (file_2);
314
result = g_utf8_collate (type_string_1, type_string_2);
316
g_free (type_string_1);
317
g_free (type_string_2);
319
return (strcmp (file1->utf8_collation_key, file2->utf8_collation_key));
324
compare_by_display_name (GOFFile *file1, GOFFile *file2)
326
const char *name_1, *name_2;
327
gboolean sort_last_1, sort_last_2;
330
name_1 = file1->name;
331
name_2 = file2->name;
333
sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2;
334
sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2;
336
if (sort_last_1 && !sort_last_2) {
338
} else if (!sort_last_1 && sort_last_2) {
341
compare = strcmp (file1->utf8_collation_key, file2->utf8_collation_key);
348
compare_files_by_size (GOFFile *file1, GOFFile *file2)
350
if (file1->size < file2->size) {
353
else if (file1->size > file2->size) {
361
compare_by_size (GOFFile *file1, GOFFile *file2)
363
if (file1->is_directory && !file2->is_directory)
365
if (file2->is_directory && !file1->is_directory)
368
/*if (file1->is_directory) {
369
return compare_directories_by_count (file1, file2);
371
return compare_files_by_size (file1, file2);
376
gof_file_compare_for_sort_internal (GOFFile *file1,
378
gboolean directories_first,
381
if (directories_first) {
382
if (file1->is_directory && !file2->is_directory) {
385
if (file2->is_directory && !file1->is_directory) {
390
/*if (file1->details->sort_order < file2->details->sort_order) {
391
return reversed ? 1 : -1;
392
} else if (file_1->details->sort_order > file_2->details->sort_order) {
393
return reversed ? -1 : 1;
400
gof_file_compare_for_sort (GOFFile *file1,
403
gboolean directories_first,
408
if (file1 == file2) {
412
result = gof_file_compare_for_sort_internal (file1, file2, directories_first, reversed);
413
//printf ("res %d %s %s\n", result, file1->name, file2->name);
417
case FM_LIST_MODEL_FILENAME:
418
result = compare_by_display_name (file1, file2);
420
result = compare_by_directory_name (file_1, file_2);
423
case FM_LIST_MODEL_SIZE:
424
result = compare_by_size (file1, file2);
426
case FM_LIST_MODEL_TYPE:
427
result = compare_by_type (file1, file2);
429
case FM_LIST_MODEL_MODIFIED:
430
result = compare_by_time (file1, file2);
441
case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME:
442
result = compare_by_display_name (file_1, file_2);
444
result = compare_by_directory_name (file_1, file_2);
447
case NAUTILUS_FILE_SORT_BY_DIRECTORY:
448
result = compare_by_full_path (file_1, file_2);
450
case NAUTILUS_FILE_SORT_BY_SIZE:
451
/* Compare directory sizes ourselves, then if necessary
452
* use GnomeVFS to compare file sizes.
454
result = compare_by_size (file_1, file_2);
456
result = compare_by_full_path (file_1, file_2);
459
case NAUTILUS_FILE_SORT_BY_TYPE:
460
/* GnomeVFS doesn't know about our special text for certain
461
* mime types, so we handle the mime-type sorting ourselves.
463
result = compare_by_type (file_1, file_2);
465
result = compare_by_full_path (file_1, file_2);
468
case NAUTILUS_FILE_SORT_BY_MTIME:
469
result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_MODIFIED);
471
result = compare_by_full_path (file_1, file_2);
474
case NAUTILUS_FILE_SORT_BY_ATIME:
475
result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_ACCESSED);
477
result = compare_by_full_path (file_1, file_2);
480
case NAUTILUS_FILE_SORT_BY_TRASHED_TIME:
481
result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_TRASHED);
483
result = compare_by_full_path (file_1, file_2);
486
case NAUTILUS_FILE_SORT_BY_EMBLEMS:
487
/* GnomeVFS doesn't know squat about our emblems, so
488
* we handle comparing them here, before falling back
491
result = compare_by_emblems (file_1, file_2);
493
result = compare_by_full_path (file_1, file_2);
497
g_return_val_if_reached (0);
509
gof_file_ref (GOFFile *file)
514
g_return_val_if_fail (GOF_IS_FILE (file), NULL);
516
return g_object_ref (file);
520
gof_file_unref (GOFFile *file)
526
g_return_if_fail (GOF_IS_FILE (file));
528
g_object_unref (file);
531
static const char *TODAY_TIME_FORMATS [] = {
532
/* Today, use special word.
533
* strftime patterns preceeded with the widest
534
* possible resulting string for that pattern.
536
* Note to localizers: You can look at man strftime
537
* for details on the format, but you should only use
538
* the specifiers from the C standard, not extensions.
539
* These include "%" followed by one of
540
* "aAbBcdHIjmMpSUwWxXyYZ". There are two extensions
541
* in the Nautilus version of strftime that can be
542
* used (and match GNU extensions). Putting a "-"
543
* between the "%" and any numeric directive will turn
544
* off zero padding, and putting a "_" there will use
545
* space padding instead of zero padding.
547
N_("today at 00:00:00 PM"),
548
N_("today at %-I:%M:%S %p"),
550
N_("today at 00:00 PM"),
551
N_("today at %-I:%M %p"),
553
N_("today, 00:00 PM"),
554
N_("today, %-I:%M %p"),
562
static const char *YESTERDAY_TIME_FORMATS [] = {
563
/* Yesterday, use special word.
564
* Note to localizers: Same issues as "today" string.
566
N_("yesterday at 00:00:00 PM"),
567
N_("yesterday at %-I:%M:%S %p"),
569
N_("yesterday at 00:00 PM"),
570
N_("yesterday at %-I:%M %p"),
572
N_("yesterday, 00:00 PM"),
573
N_("yesterday, %-I:%M %p"),
581
static const char *CURRENT_WEEK_TIME_FORMATS [] = {
582
/* Current week, include day of week.
583
* Note to localizers: Same issues as "today" string.
584
* The width measurement templates correspond to
585
* the day/month name with the most letters.
587
N_("Wednesday, September 00 0000 at 00:00:00 PM"),
588
N_("%A, %B %-d %Y at %-I:%M:%S %p"),
590
N_("Mon, Oct 00 0000 at 00:00:00 PM"),
591
N_("%a, %b %-d %Y at %-I:%M:%S %p"),
593
N_("Mon, Oct 00 0000 at 00:00 PM"),
594
N_("%a, %b %-d %Y at %-I:%M %p"),
596
N_("Oct 00 0000 at 00:00 PM"),
597
N_("%b %-d %Y at %-I:%M %p"),
599
N_("Oct 00 0000, 00:00 PM"),
600
N_("%b %-d %Y, %-I:%M %p"),
602
N_("00/00/00, 00:00 PM"),
603
N_("%m/%-d/%y, %-I:%M %p"),
612
gof_file_get_date_as_string (guint64 d)
614
//time_t file_time_raw;
615
struct tm *file_time;
616
const char **formats;
617
const char *width_template;
623
guint32 file_date_age;
626
file_time = localtime (&d);
628
gchar *date_format_pref = g_settings_get_string(settings, MARLIN_PREFERENCES_DATE_FORMAT);
630
if (!strcmp (date_format_pref, "locale"))
631
return eel_strdup_strftime ("%c", file_time);
632
else if (!strcmp (date_format_pref, "iso"))
633
return eel_strdup_strftime ("%Y-%m-%d %H:%M:%S", file_time);
635
file_date = eel_g_date_new_tm (file_time);
637
today = g_date_new ();
638
g_date_set_time_t (today, time (NULL));
640
/* Overflow results in a large number; fine for our purposes. */
641
file_date_age = (g_date_get_julian (today) -
642
g_date_get_julian (file_date));
644
g_date_free (file_date);
647
/* Format varies depending on how old the date is. This minimizes
648
* the length (and thus clutter & complication) of typical dates
649
* while providing sufficient detail for recent dates to make
650
* them maximally understandable at a glance. Keep all format
651
* strings separate rather than combining bits & pieces for
652
* internationalization's sake.
655
if (file_date_age == 0) {
656
formats = TODAY_TIME_FORMATS;
657
} else if (file_date_age == 1) {
658
formats = YESTERDAY_TIME_FORMATS;
659
} else if (file_date_age < 7) {
660
formats = CURRENT_WEEK_TIME_FORMATS;
662
formats = CURRENT_WEEK_TIME_FORMATS;
665
/* Find the date format that just fits the required width. Instead of measuring
666
* the resulting string width directly, measure the width of a template that represents
667
* the widest possible version of a date in a given format. This is done by using M, m
668
* and 0 for the variable letters/digits respectively.
672
for (i = 0; ; i += 2) {
673
width_template = (formats [i] ? _(formats [i]) : NULL);
674
if (width_template == NULL) {
675
/* no more formats left */
676
g_assert (format != NULL);
678
/* Can't fit even the shortest format -- return an ellipsized form in the
682
date_string = eel_strdup_strftime (format, file_time);
687
format = _(formats [i + 1]);
689
/* don't care about fitting the width */
693
return eel_strdup_strftime (format, file_time);
697
gof_file_list_unref (GList *list)
699
g_list_foreach (list, (GFunc) gof_file_unref, NULL);
703
gof_file_list_free (GList *list)
705
gof_file_list_unref (list);