4
* Copyright 2016 Tony George <teejeetech@gmail.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
30
using TeeJee.FileSystem;
32
using TeeJee.ProcessManagement;
35
using TeeJee.GtkHelper;
37
public class FileItem : GLib.Object {
38
public string file_name = "";
39
public string file_location = "";
40
public string file_path = "";
41
public FileType file_type = FileType.REGULAR;
42
public DateTime modified;
44
public bool is_selected = false;
45
public bool is_symlink = false;
46
public string symlink_target = "";
48
public FileItem parent;
49
public Gee.HashMap<string, FileItem> children;
50
public Archive? task_ref;
52
public long file_count = 0;
53
public long dir_count = 0;
54
private int64 _size = 0;
55
private int64 _size_compressed = 0;
57
public long file_count_total = 0;
58
public long dir_count_total = 0;
60
public string permissions = "";
61
public string owner = "";
62
public string group = "";
64
public GLib.Icon icon;
66
public bool is_dummy = false;
69
children = new Gee.HashMap<string, FileItem>();
72
public FileItem.base_archive(Archive? _task_ref, string name = "New Archive") {
78
public FileItem.dummy(Archive? _task_ref, FileType _file_type) {
81
file_type = _file_type;
85
public FileItem.dummy_root() {
93
private FileItem.from_path_and_type(Archive? _task_ref, string _file_path, FileType _file_type) {
96
file_path = _file_path;
97
file_name = file_basename(_file_path);
98
file_location = file_parent(_file_path);
99
file_type = _file_type;
100
task_ref = _task_ref;
109
public int64 size_compressed {
111
return _size_compressed;
115
public FileItem add_child(string item_file_path, FileType item_file_type, int64 item_size, int64 item_size_compressed) {
117
var item = new FileItem.from_path_and_type(this.task_ref, item_file_path, item_file_type);
119
//set parent and child
122
bool existing_file = false;
123
if (!this.children.has_key(item.file_name)){
124
this.children[item.file_name] = item;
127
existing_file = true;
128
item = this.children[item.file_name];
131
if (item_file_type == FileType.REGULAR) {
135
item._size = item_size;
137
if (item_size_compressed > 0) {
138
item._size_compressed = item_size_compressed;
144
this.file_count_total++;
145
this._size += item_size;
146
this._size_compressed += item_size_compressed;
148
//update file count and size of parent dirs
150
while (temp.parent != null) {
151
temp.parent.file_count_total++;
152
temp.parent._size += item_size;
153
temp.parent._size_compressed += item_size_compressed;
159
item.icon = GLib.Icon.new_for_string("gtk-file");
162
log_error (e.message);
171
this.dir_count_total++;
172
//this.size += _size; //size will be updated when children are added
174
//update dir count of parent dirs
176
while (temp.parent != null) {
177
temp.parent.dir_count_total++;
183
item.icon = GLib.Icon.new_for_string("gtk-directory");
186
log_error (e.message);
190
//log_debug("%3ld %3ld %s".printf(file_count, dir_count, file_path));
195
public void clear_children() {
196
this.children.clear();
199
public void query_children(int depth = -1) {
200
FileEnumerator enumerator;
202
File file = File.parse_name (file_path);
204
if (!file.query_exists()) {
208
if ((file_type == FileType.DIRECTORY) && !is_symlink) {
215
enumerator = file.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0);
216
while ((info = enumerator.next_file()) != null) {
217
string child_name = info.get_name();
218
string child_path = "%s/%s".printf(file_path, child_name);
219
this.add_child_from_disk(child_path, depth - 1);
223
log_error (e.message);
228
public FileItem remove_child(string child_name) {
229
FileItem child = null;
231
if (this.children.has_key(child_name)) {
232
child = this.children[child_name];
233
this.children.unset(child_name);
235
if (child.file_type == FileType.REGULAR) {
238
this.file_count_total--;
240
//subtract child size
241
this._size -= child.size;
242
this._size_compressed -= child.size_compressed;
244
//update file count and size of parent dirs
246
while (temp.parent != null) {
247
temp.parent.file_count_total--;
249
temp.parent._size -= child.size;
250
temp.parent._size_compressed -= child.size_compressed;
258
this.dir_count_total--;
260
//subtract child counts
261
this.file_count_total -= child.file_count_total;
262
this.dir_count_total -= child.dir_count_total;
263
this._size -= child.size;
264
this._size_compressed -= child.size_compressed;
266
//update dir count of parent dirs
268
while (temp.parent != null) {
269
temp.parent.dir_count_total--;
271
temp.parent.file_count_total -= child.file_count_total;
272
temp.parent.dir_count_total -= child.dir_count_total;
273
temp.parent._size -= child.size;
274
temp.parent._size_compressed -= child.size_compressed;
281
//log_debug("%3ld %3ld %s".printf(file_count, dir_count, file_path));
286
public FileItem add_child_from_disk(string item_file_path, int depth = -1) {
287
FileItem item = null;
289
//log_debug("add_child_from_disk: %02d: %s".printf(depth, item_file_path));
292
FileEnumerator enumerator;
294
File file = File.parse_name (item_file_path);
296
GLib.Icon item_icon = null;
297
FileType item_file_type_actual = FileType.REGULAR;
298
FileType item_file_type_resolved = FileType.REGULAR;
299
bool item_is_symlink = false;
301
DateTime item_modified = null;
302
string item_target = "";
304
if (file.query_exists()) {
306
//get type without following symlinks
307
info = file.query_info("%s,%s,%s".printf(
308
FileAttribute.STANDARD_TYPE,
309
FileAttribute.STANDARD_ICON,
310
FileAttribute.STANDARD_SYMLINK_TARGET),
311
FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
313
item_file_type_actual = info.get_file_type();
314
if (item_file_type_actual == FileType.SYMBOLIC_LINK) {
315
item_icon = GLib.Icon.new_for_string("emblem-symbolic-link");
316
item_is_symlink = true;
317
item_target = info.get_symlink_target();
320
item_icon = info.get_icon();
321
item_is_symlink = false;
324
//get file info - follow symlinks
325
info = file.query_info("%s,%s,%s".printf(
326
FileAttribute.STANDARD_TYPE,
327
FileAttribute.STANDARD_SIZE,
328
FileAttribute.TIME_MODIFIED), 0);
331
item_file_type_resolved = info.get_file_type();
334
if (!item_is_symlink && (item_file_type_resolved == FileType.REGULAR)) {
335
item_size = info.get_size();
339
item_modified = (new DateTime.from_timeval_utc(info.get_modification_time())).to_local();
342
item = this.add_child(item_file_path, item_file_type_resolved, item_size, 0);
343
item.icon = item_icon;
344
item.is_symlink = item_is_symlink;
345
item.symlink_target = item_target;
346
item.modified = item_modified;
348
if ((item.file_type == FileType.DIRECTORY) && !item.is_symlink) {
351
enumerator = file.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0);
352
while ((info = enumerator.next_file()) != null) {
353
string child_path = "%s/%s".printf(item_file_path, info.get_name());
354
item.add_child_from_disk(child_path, depth - 1);
361
log_error (e.message);
367
public FileItem add_descendant(string file_path, FileType ? _file_type, int64 item_size, int64 item_size_compressed) {
368
string item_path = file_path.strip();
369
FileType item_type = (_file_type == null) ? FileType.REGULAR : _file_type;
371
if (item_path.has_suffix("/")) {
372
item_path = item_path[0:item_path.length - 1];
373
item_type = FileType.DIRECTORY;
376
string dir_name = "";
377
string dir_path = "";
379
//create dirs and find parent dir
380
FileItem current_dir = this;
381
string[] arr = item_path.split("/");
382
for (int i = 0; i < arr.length - 1; i++) {
387
if (!current_dir.children.keys.contains(dir_name)) {
388
dir_path = (current_dir.parent == null) ? "" : current_dir.file_path + "/";
389
dir_path = "%s%s".printf(dir_path, dir_name);
390
current_dir.add_child(dir_path, FileType.DIRECTORY, 0, 0);
393
current_dir = current_dir.children[dir_name];
397
string item_name = arr[arr.length - 1];
400
if (!current_dir.children.keys.contains(item_name)) {
401
current_dir.add_child(item_path, item_type, item_size, item_size_compressed);
404
return current_dir.children[item_name];
407
public void print(int level) {
414
stdout.printf("%s%s\n".printf(string.nfill(level * 2, ' '), file_name));
417
foreach (var key in this.children.keys) {
418
this.children[key].print(level + 1);