Merge lp:~matzipan/scratch/use-rename-event into lp:~elementary-apps/scratch/scratch

Proposed by Zisu Andrei
Status: Work in progress
Proposed branch: lp:~matzipan/scratch/use-rename-event
Merge into: lp:~elementary-apps/scratch/scratch
Diff against target: 1847 lines (+463/-1120)
16 files modified
plugins/CMakeLists.txt (+1/-2)
plugins/filemanager/CMakeLists.txt (+0/-29)
plugins/filemanager/File.vala (+0/-207)
plugins/filemanager/FileManagerPlugin.vala (+0/-113)
plugins/filemanager/FileView.vala (+0/-297)
plugins/filemanager/Settings.vala (+0/-36)
plugins/filemanager/filemanager.plugin (+0/-10)
plugins/folder-manager/CMakeLists.txt (+2/-0)
plugins/folder-manager/File.vala (+79/-101)
plugins/folder-manager/FileItem.vala (+39/-0)
plugins/folder-manager/FileView.vala (+92/-254)
plugins/folder-manager/FolderItem.vala (+196/-0)
plugins/folder-manager/FolderManagerPlugin.vala (+50/-56)
plugins/folder-manager/folder-manager.plugin (+4/-4)
schemas/CMakeLists.txt (+0/-1)
schemas/org.pantheon.scratch.plugins.file-manager.gschema.xml (+0/-10)
To merge this branch: bzr merge lp:~matzipan/scratch/use-rename-event
Reviewer Review Type Date Requested Status
elementary Apps team Pending
Review via email: mp+312213@code.launchpad.net

Description of the change

This branch is WIP.

Currently, if you rename a file in the sidebar, when you perform the action, the selected file cursor jumps to a different file. This is because the sidebar doesn't use the rename GIO event, but instead deletes and creates the row everytime this happens.

However, using the rename event doesn't fully work, because Granite.SourceList doesn't have a way to trigger re-sorting of the elements. It only sorts an element when it is first added.

Thus, I am pushing this now as it is, in the hopes that I will address this issue in my sidebar-widget branch in granite. Then it can be merged into scratch.

To post a comment you must log in.

Unmerged revisions

1780. By Zisu Andrei

Use rename monitor event instead of create/remove

1779. By Zisu Andrei

Simplify file/folder validity check. Move common construct/rename/trash code into superclass. GObject constructor for File

1778. By Zisu Andrei

Merge filemanager into folder-manager

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/CMakeLists.txt'
2--- plugins/CMakeLists.txt 2016-09-03 10:30:53 +0000
3+++ plugins/CMakeLists.txt 2016-11-30 23:31:32 +0000
4@@ -6,8 +6,7 @@
5 )
6
7 add_subdirectory (contractor)
8-add_subdirectory (pastebin)
9-add_subdirectory (filemanager)
10+add_subdirectory (pastebin)
11 add_subdirectory (folder-manager)
12 add_subdirectory (terminal)
13 add_subdirectory (browser-preview)
14
15=== removed directory 'plugins/filemanager'
16=== removed file 'plugins/filemanager/CMakeLists.txt'
17--- plugins/filemanager/CMakeLists.txt 2016-09-03 10:30:53 +0000
18+++ plugins/filemanager/CMakeLists.txt 1970-01-01 00:00:00 +0000
19@@ -1,29 +0,0 @@
20-add_definitions(${NORMAL_CFLAGS})
21-link_directories(${NORMAL_LINK_DIRS})
22-
23-set (PLUGIN_NAME "filemanager")
24-
25-vala_precompile(VALA_C ${PLUGIN_NAME}
26- FileManagerPlugin.vala
27- File.vala
28- Settings.vala
29- FileView.vala
30-PACKAGES
31- gtk+-3.0
32- gee-0.8
33- granite
34- scratchcore
35- libpeas-1.0
36- gtksourceview-3.0
37- ${ZEITGEIST_DEPS}
38-OPTIONS
39- ${DEFAULT_PLUGIN_OPTIONS}
40-)
41-
42-add_library(${PLUGIN_NAME} MODULE ${VALA_C})
43-add_dependencies(${PLUGIN_NAME} ${LIBNAME})
44-
45-install(TARGETS ${PLUGIN_NAME} DESTINATION ${PLUGINDIR}/${PLUGIN_NAME})
46-install(FILES ${PLUGIN_NAME}.plugin DESTINATION ${PLUGINDIR}/${PLUGIN_NAME})
47-
48-message("-- File Manager plugin will be compiled")
49
50=== removed file 'plugins/filemanager/File.vala'
51--- plugins/filemanager/File.vala 2013-07-16 15:56:38 +0000
52+++ plugins/filemanager/File.vala 1970-01-01 00:00:00 +0000
53@@ -1,207 +0,0 @@
54-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
55-/***
56- BEGIN LICENSE
57-
58- Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com>
59- This program is free software: you can redistribute it and/or modify it
60- under the terms of the GNU Lesser General Public License version 3, as published
61- by the Free Software Foundation.
62-
63- This program is distributed in the hope that it will be useful, but
64- WITHOUT ANY WARRANTY; without even the implied warranties of
65- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
66- PURPOSE. See the GNU General Public License for more details.
67-
68- You should have received a copy of the GNU General Public License along
69- with this program. If not, see <http://www.gnu.org/licenses/>
70-
71- END LICENSE
72-***/
73-
74-namespace Scratch.Plugins.FileManager {
75-
76- /**
77- * Class for easily dealing with files.
78- */
79- internal class File : GLib.Object {
80-
81- public GLib.File file;
82- private GLib.FileInfo info;
83-
84- private enum Type {
85- VALID_FILE,
86- VALID_FOLDER,
87- UNKNOWN,
88- INVALID
89- }
90-
91- public File (string path) {
92- file = GLib.File.new_for_path (path);
93-
94- info = new FileInfo ();
95- try {
96- info = file.query_info (
97- GLib.FileAttribute.STANDARD_CONTENT_TYPE + "," +
98- GLib.FileAttribute.STANDARD_IS_BACKUP + "," +
99- GLib.FileAttribute.STANDARD_IS_HIDDEN + "," +
100- GLib.FileAttribute.STANDARD_DISPLAY_NAME + "," +
101- GLib.FileAttribute.STANDARD_TYPE,
102- FileQueryInfoFlags.NONE);
103- } catch (GLib.Error error) {
104- info = null;
105- warning (error.message);
106- }
107- }
108-
109- // returns the path the file
110- string _path = null;
111- public string path {
112- get { return _path != null ? _path : _path = file.get_path (); }
113- }
114-
115- // returns the basename of the file
116- string _name = null;
117- public string name {
118- get { return _name != null ? _name : _name = info.get_display_name (); }
119- }
120-
121- // returns the icon of the file's content type
122- GLib.Icon _icon = null;
123- public GLib.Icon icon {
124- get {
125- if (_icon != null)
126- return _icon;
127- //var content_type = info.get_attribute_string (FileAttribute.STANDARD_FAST_CONTENT_TYPE);
128- var content_type = info.get_content_type ();
129- return _icon = GLib.ContentType.get_icon (content_type);
130- }
131- }
132-
133- // checks if file exists
134- public bool exists {
135- get { return file.query_exists (); }
136- }
137-
138- Type _type = Type.UNKNOWN;
139- // checks if we're dealing with a non-hidden, non-backup directory
140- public bool is_valid_directory {
141- get {
142- if (_type == Type.VALID_FILE)
143- return false;
144- if (_type == Type.VALID_FOLDER)
145- return true;
146- if (_type == Type.INVALID)
147- return false;
148-
149- if (info.get_file_type () != FileType.DIRECTORY ||
150- info.get_is_hidden () || info.get_is_backup ()) {
151- return false;
152- }
153-
154- bool has_valid_children = false;
155-
156- foreach (var child in children) {
157- if (child.is_valid_textfile) {
158- _type = Type.VALID_FOLDER;
159- return has_valid_children = true;
160- }
161- }
162-
163- foreach (var child in children) {
164- if (child.is_valid_directory) {
165- has_valid_children = true;
166- _type = Type.VALID_FOLDER;
167- return has_valid_children = true;
168- }
169- }
170-
171- return false;
172- }
173- }
174-
175- // checks if we're dealing with a textfile
176- public bool is_valid_textfile {
177- get {
178- if (_type == Type.VALID_FILE)
179- return true;
180- if (_type == Type.VALID_FOLDER)
181- return false;
182- if (_type == Type.INVALID)
183- return false;
184-
185- if (info.get_file_type () == FileType.REGULAR) {
186- //var content_type = info.get_attribute_string (FileAttribute.STANDARD_FAST_CONTENT_TYPE);
187- var content_type = info.get_content_type ();
188- if (ContentType.is_a (content_type, "text/*") &&
189- !info.get_is_backup () &&
190- !info.get_is_hidden ()) {
191- _type = Type.VALID_FILE;
192- return true;
193- }
194- }
195-
196- return false;
197- }
198- }
199-
200- // returns a list of all children of a directory
201- GLib.List <File> _children = null;
202- public GLib.List <File> children {
203- get {
204- if (_children != null)
205- return _children;
206-
207- var parent = GLib.File.new_for_path (file.get_path ());
208- try {
209- var enumerator = parent.enumerate_children (
210- GLib.FileAttribute.STANDARD_NAME,
211- FileQueryInfoFlags.NONE
212- );
213-
214- var file_info = new FileInfo ();
215- while ((file_info = enumerator.next_file ()) != null) {
216- var child = parent.get_child (file_info.get_name ());
217- _children.append (new File (child.get_path ()));
218- }
219- } catch (GLib.Error error) {
220- warning (error.message);
221- }
222-
223- return _children;
224- }
225- }
226-
227- public void rename (string name) {
228- try {
229- file.set_display_name (name);
230- } catch (GLib.Error error) {
231- warning (error.message);
232- }
233- }
234-
235- /*public void trash () {
236- try {
237- file.trash ();
238- } catch (GLib.Error error) {
239- warning (error.message);
240- }
241- }*/
242-
243- public void reset_cache () {
244- _name = null;
245- _path = null;
246- _icon = null;
247- _children = null;
248- _type = Type.UNKNOWN;
249- }
250-
251- public static int compare (File a, File b) {
252- if (a.is_valid_directory && b.is_valid_textfile)
253- return -1;
254- if (a.is_valid_textfile && b.is_valid_directory)
255- return 1;
256- return strcmp (a.path.collate_key_for_filename (),
257- b.path.collate_key_for_filename ());
258- }
259- }
260-}
261
262=== removed file 'plugins/filemanager/FileManagerPlugin.vala'
263--- plugins/filemanager/FileManagerPlugin.vala 2016-09-03 11:50:58 +0000
264+++ plugins/filemanager/FileManagerPlugin.vala 1970-01-01 00:00:00 +0000
265@@ -1,113 +0,0 @@
266-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
267-/***
268- BEGIN LICENSE
269-
270- Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com>
271- This program is free software: you can redistribute it and/or modify it
272- under the terms of the GNU Lesser General Public License version 3, as published
273- by the Free Software Foundation.
274-
275- This program is distributed in the hope that it will be useful, but
276- WITHOUT ANY WARRANTY; without even the implied warranties of
277- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
278- PURPOSE. See the GNU General Public License for more details.
279-
280- You should have received a copy of the GNU General Public License along
281- with this program. If not, see <http://www.gnu.org/licenses/>
282-
283- END LICENSE
284-***/
285-
286-public const string NAME = _("Folder Manager");
287-public const string DESCRIPTION = _("Basic folder manager with file browsing");
288-
289-namespace Scratch.Plugins {
290- public class FileManagerPlugin : Peas.ExtensionBase, Peas.Activatable {
291- public Scratch.Services.Interface plugins;
292-
293- Gtk.Box box;
294- FileManager.FileView view;
295-
296- public Object object { owned get; construct; }
297-
298- public FileManagerPlugin () {
299- message ("Starting File Manager Plugin");
300- }
301-
302- public void activate () {
303- plugins = (Scratch.Services.Interface) object;
304- plugins.hook_notebook_sidebar.connect (on_hook_sidebar);
305- }
306-
307- public void deactivate () {
308- if (box != null)
309- box.destroy();
310- }
311-
312- public void update_state () {
313-
314- }
315-
316- void on_hook_sidebar (Gtk.Notebook notebook) {
317- if (view != null)
318- return;
319-
320- box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
321-
322- // File View
323- view = new FileManager.FileView ();
324-
325- view.select.connect ((a) => {
326- var file = GLib.File.new_for_path (a);
327- plugins.open_file (file);
328- });
329-
330- // Toolbar
331- var toolbar = new Gtk.Toolbar ();
332- toolbar.set_icon_size (Gtk.IconSize.SMALL_TOOLBAR);
333- toolbar.get_style_context ().add_class ("inline-toolbar");
334-
335- var parent = new Gtk.ToolButton (null, null);
336- parent.tooltip_text = _("Go to parent");
337- parent.icon_name = "go-up-symbolic";
338- parent.clicked.connect (() => {
339- view.open_parent ();
340- parent.sensitive = !(view.folder.file.file.get_path () == "/");
341- });
342-
343- var spacer = new Gtk.ToolItem ();
344- spacer.set_expand (true);
345-
346- var add = new Gtk.ToolButton (null, null);
347- add.tooltip_text = _("Add file");
348- add.icon_name = "list-add-symbolic";
349- add.clicked.connect (() => {
350- view.add_file ();
351- });
352-
353- var remove = new Gtk.ToolButton (null, null);
354- remove.tooltip_text = _("Remove file");
355- remove.icon_name = "edit-delete-symbolic";
356- remove.clicked.connect (() => {
357- view.remove_file ();
358- });
359-
360- toolbar.insert (parent, -1);
361- toolbar.insert (spacer, -1);
362- toolbar.insert (add, -1);
363- toolbar.insert (remove, -1);
364-
365- box.pack_start (view, true, true, 0);
366- box.pack_start (toolbar, false, false, 0);
367- box.show_all ();
368-
369- notebook.append_page (box, new Gtk.Label (_("File Manager")));
370- }
371- }
372-}
373-
374-[ModuleInit]
375-public void peas_register_types (GLib.TypeModule module) {
376- var objmodule = module as Peas.ObjectModule;
377- objmodule.register_extension_type (typeof (Peas.Activatable), typeof (Scratch.Plugins.FileManagerPlugin));
378-}
379
380=== removed file 'plugins/filemanager/FileView.vala'
381--- plugins/filemanager/FileView.vala 2016-09-03 11:50:58 +0000
382+++ plugins/filemanager/FileView.vala 1970-01-01 00:00:00 +0000
383@@ -1,297 +0,0 @@
384-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
385-/***
386- BEGIN LICENSE
387-
388- Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com>
389- This program is free software: you can redistribute it and/or modify it
390- under the terms of the GNU Lesser General Public License version 3, as published
391- by the Free Software Foundation.
392-
393- This program is distributed in the hope that it will be useful, but
394- WITHOUT ANY WARRANTY; without even the implied warranties of
395- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
396- PURPOSE. See the GNU General Public License for more details.
397-
398- You should have received a copy of the GNU General Public License along
399- with this program. If not, see <http://www.gnu.org/licenses/>
400-
401- END LICENSE
402-***/
403-
404-namespace Scratch.Plugins.FileManager {
405- Settings settings;
406-
407- /**
408- * SourceList that displays folders and their contents.
409- */
410- internal class FileView : Granite.Widgets.SourceList {
411- public FolderItem? folder = null;
412- public signal void select (string file);
413- public FileView () {
414- this.width_request = 180;
415-
416- this.item_selected.connect ((item) => {
417- select ((item as FileItem).path);
418- });
419-
420- this.root.child_removed.connect (() => {
421- this.selected = null;
422- });
423-
424- settings = new Settings ();
425- restore_settings ();
426- }
427-
428- public void open_parent () {
429- GLib.File parent = this.folder.file.file.get_parent ();
430- this.root.remove (this.folder);
431- open_folder (new File (parent.get_path ()));
432- }
433-
434- public void open_folder (File folder, bool expand = true) {
435- if (is_open (folder)) {
436- warning ("Folder '%s' is already open.", folder.path);
437- return;
438- } else if (!folder.is_valid_directory) {
439- warning ("Cannot open invalid directory.");
440- return;
441- }
442-
443- // Clean the SourceList before start adding something
444- if (this.folder != null) {
445- this.root.remove (this.folder);
446- }
447-
448- this.folder = new FolderItem (folder, this);
449- this.root.add (this.folder);
450-
451- this.folder.expanded = expand;
452- write_settings ();
453- }
454-
455- public void add_file () {
456- string path = folder.file.file.get_path () + _("/New File");
457- var file = GLib.File.new_for_path (path);
458- int n = 1;
459- while (file.query_exists ()) {
460- file = GLib.File.new_for_path (path + n.to_string ());
461- n++;
462- }
463-
464- try {
465- file.create (FileCreateFlags.NONE);
466- } catch (Error e) {
467- warning (e.message);
468- }
469-
470- var item = new FileItem (new File (file.get_path ()));
471- this.folder.add (item);
472- }
473-
474- public void remove_file () {
475- if (this.selected is FileItem) {
476- var file = GLib.File.new_for_path (((FileItem)selected).file.file.get_path ());
477- try {
478- file.delete ();
479- this.root.remove (selected);
480- } catch (Error e) {
481- warning (e.message);
482- }
483- }
484-
485- this.selected = null;
486- }
487-
488- private bool is_open (File folder) {
489- foreach (var child in root.children) {
490- if (folder.path == (child as Item).path) {
491- return true;
492- }
493- }
494-
495- return false;
496- }
497-
498- private void write_settings () {
499- settings.opened_folder = this.folder.file.file.get_path ();
500- }
501-
502- private void restore_settings () {
503- var folder = new File (settings.opened_folder);
504- if (settings.opened_folder == "" || settings.opened_folder == null || !folder.is_valid_directory) {
505- settings.opened_folder = GLib.Environment.get_home_dir ();
506- }
507-
508- open_folder (new File (settings.opened_folder));
509- }
510- }
511-
512- /**
513- * Common abstract class for normal and expandable items.
514- */
515- internal class Item : Granite.Widgets.SourceList.ExpandableItem, Granite.Widgets.SourceListSortable {
516- public File file { get; construct; }
517- public string path { get { return file.path; } }
518-
519- public int compare (Granite.Widgets.SourceList.Item a, Granite.Widgets.SourceList.Item b) {
520- if (a is FolderItem && b is FileItem) {
521- return -1;
522- } else if (a is FileItem && b is FolderItem) {
523- return 1;
524- }
525-
526- return File.compare ((a as Item).file, (b as Item).file);
527- }
528-
529- public bool allow_dnd_sorting () {
530- return false;
531- }
532- }
533-
534- /**
535- * Normal item in the source list, represents a textfile.
536- * TODO Remove, Rename
537- */
538- internal class FileItem : Item {
539- //Gtk.Menu menu;
540- //Gtk.MenuItem item_trash;
541- public FileItem (File file) requires (file.is_valid_textfile) {
542- Object (file: file);
543-
544- this.selectable = true;
545- this.editable = true;
546- this.name = file.name;
547- this.icon = file.icon;
548- }
549-
550- public void rename (string new_name) {
551- string new_uri = file.file.get_parent ().get_uri () + "/" + new_name;
552- debug (new_uri);
553- file.rename (new_name);
554- }
555-
556- /*public override Gtk.Menu? get_context_menu () {
557- menu = new Gtk.Menu ();
558- item_trash = new Gtk.MenuItem.with_label (_("Move to Trash"));
559- menu.append (item_trash);
560- item_trash.activate.connect (() => { file.trash (); });
561- menu.show_all ();
562- return menu;
563- }*/
564- }
565-
566- /**
567- * Expandable item in the source list, represents a folder.
568- * Monitored for changes inside the directory.
569- * TODO remove, rename, create new file
570- */
571- internal class FolderItem : Item {
572- public signal void folder_open (GLib.File folder);
573- public FileView view { get; construct; }
574-
575- private GLib.FileMonitor monitor;
576- private bool children_loaded = false;
577-
578- //Gtk.Menu menu;
579- //Gtk.MenuItem item_trash;
580- //Gtk.MenuItem item_create;
581-
582- public FolderItem (File file, FileView view) requires (file.is_valid_directory) {
583- Object (file: file, view: view);
584-
585- this.editable = false;
586- this.selectable = false;
587- this.name = file.name;
588- this.icon = file.icon;
589-
590- this.add (new Granite.Widgets.SourceList.Item ("")); // dummy
591- this.toggled.connect (() => {
592- if (this.expanded && this.n_children <= 1) {
593- this.clear ();
594- this.add_children ();
595- children_loaded = true;
596- }
597- });
598-
599- try {
600- monitor = file.file.monitor_directory (GLib.FileMonitorFlags.NONE);
601- monitor.changed.connect ((s,d,e) => { on_changed (s,d,e); });
602- } catch (GLib.Error e) {
603- warning (e.message);
604- }
605- }
606-
607- public override Gtk.Menu? get_context_menu () {
608- if (this == this.view.root.children.to_array ()[0]) {
609- return null;
610- }
611-
612- var menu = new Gtk.Menu ();
613- var item = new Gtk.MenuItem.with_label (_("Open"));
614- item.activate.connect (() => { this.folder_open (this.file.file); });
615- menu.append (item);
616- menu.show_all ();
617- return menu;
618- }
619-
620- internal void add_children () {
621- foreach (var child in file.children) {
622- if (child.is_valid_directory) {
623- var item = new FolderItem (child, view);
624- item.folder_open.connect (() => {
625- this.view.open_folder (child);
626- });
627-
628- add (item);
629- } else if (child.is_valid_textfile) {
630- var item = new FileItem (child);
631- add (item);
632- item.edited.connect (item.rename);
633- }
634- }
635- }
636-
637- private void on_changed (GLib.File source, GLib.File? dest, GLib.FileMonitorEvent event) {
638- if (!children_loaded) {
639- this.file.reset_cache ();
640- return;
641- }
642-
643- switch (event) {
644- case GLib.FileMonitorEvent.DELETED:
645- var children_tmp = new Gee.ArrayList<Granite.Widgets.SourceList.Item> ();
646- children_tmp.add_all (children);
647- foreach (var item in children_tmp) {
648- if ((item as Item).path == source.get_path ()) {
649- remove (item);
650- }
651- }
652-
653- break;
654- case GLib.FileMonitorEvent.CREATED:
655- if (source.query_exists () == false) {
656- return;
657- }
658-
659- var file = new File (source.get_path ());
660- var exists = false;
661- foreach (var item in children) {
662- if ((item as Item).path == file.path) {
663- exists = true;
664- }
665- }
666-
667- if (!exists) {
668- if (file.is_valid_textfile) {
669- this.add (new FileItem (file));
670- } else if (file.is_valid_directory) {
671- this.add (new FolderItem (file, view));
672- }
673- }
674-
675- break;
676- }
677- }
678- }
679-
680-}
681
682=== removed file 'plugins/filemanager/Settings.vala'
683--- plugins/filemanager/Settings.vala 2013-07-16 15:56:38 +0000
684+++ plugins/filemanager/Settings.vala 1970-01-01 00:00:00 +0000
685@@ -1,36 +0,0 @@
686-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
687-/***
688- BEGIN LICENSE
689-
690- Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com>
691- This program is free software: you can redistribute it and/or modify it
692- under the terms of the GNU Lesser General Public License version 3, as published
693- by the Free Software Foundation.
694-
695- This program is distributed in the hope that it will be useful, but
696- WITHOUT ANY WARRANTY; without even the implied warranties of
697- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
698- PURPOSE. See the GNU General Public License for more details.
699-
700- You should have received a copy of the GNU General Public License along
701- with this program. If not, see <http://www.gnu.org/licenses/>
702-
703- END LICENSE
704-***/
705-
706-namespace Scratch.Plugins.FileManager {
707-
708- /**
709- * Class for interacting with gsettings.
710- */
711- internal class Settings : Granite.Services.Settings {
712-
713- private const string SCHEMA = "org.pantheon.scratch.plugins.file-manager";
714-
715- public string opened_folder { get; set; }
716-
717- public Settings () {
718- base (SCHEMA);
719- }
720- }
721-}
722
723=== removed file 'plugins/filemanager/filemanager.plugin'
724--- plugins/filemanager/filemanager.plugin 2013-07-16 15:56:38 +0000
725+++ plugins/filemanager/filemanager.plugin 1970-01-01 00:00:00 +0000
726@@ -1,10 +0,0 @@
727-[Plugin]
728-Module=filemanager
729-Loader=C
730-IAge=2
731-Name=File Manager
732-Description=Browse files and directories
733-Icon=system-file-manager
734-Authors=Mario Guerriero
735-Copyright=Copyright © 2013 Scratch Developers
736-Website=http://launchpad.net/scratch
737
738=== modified file 'plugins/folder-manager/CMakeLists.txt'
739--- plugins/folder-manager/CMakeLists.txt 2016-09-03 10:30:53 +0000
740+++ plugins/folder-manager/CMakeLists.txt 2016-11-30 23:31:32 +0000
741@@ -8,6 +8,8 @@
742 File.vala
743 Settings.vala
744 FileView.vala
745+ FileItem.vala
746+ FolderItem.vala
747 PACKAGES
748 gtk+-3.0
749 gee-0.8
750
751=== modified file 'plugins/folder-manager/File.vala'
752--- plugins/folder-manager/File.vala 2013-06-02 13:07:08 +0000
753+++ plugins/folder-manager/File.vala 2016-11-30 23:31:32 +0000
754@@ -1,77 +1,66 @@
755 // -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
756-/***
757- BEGIN LICENSE
758-
759- Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com>
760- This program is free software: you can redistribute it and/or modify it
761- under the terms of the GNU Lesser General Public License version 3, as published
762- by the Free Software Foundation.
763-
764- This program is distributed in the hope that it will be useful, but
765- WITHOUT ANY WARRANTY; without even the implied warranties of
766- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
767- PURPOSE. See the GNU General Public License for more details.
768-
769- You should have received a copy of the GNU General Public License along
770- with this program. If not, see <http://www.gnu.org/licenses/>
771-
772- END LICENSE
773-***/
774+/*-
775+ * Copyright (c) 2016 elementary LLC. (https://elementary.io)
776+ *
777+ * This program is free software: you can redistribute it and/or modify
778+ * it under the terms of the GNU General Public License as published by
779+ * the Free Software Foundation, either version 3 of the License, or
780+ * (at your option) any later version.
781+ *
782+ * This program is distributed in the hope that it will be useful,
783+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
784+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
785+ * GNU General Public License for more details.
786+ *
787+ * You should have received a copy of the GNU General Public License
788+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
789+ *
790+ * Authored by: Julien Spautz <spautz.julien@gmail.com>, Andrei-Costin Zisu <matzipan@gmail.com>
791+ */
792
793 namespace Scratch.Plugins.FolderManager {
794
795 /**
796 * Class for easily dealing with files.
797 */
798- internal class File : GLib.Object {
799+ public class File : GLib.Object {
800
801- public GLib.File file;
802+ public GLib.File file { get; private set; }
803 private GLib.FileInfo info;
804
805- private enum Type {
806- VALID_FILE,
807- VALID_FOLDER,
808- UNKNOWN,
809- INVALID
810- }
811-
812 public File (string path) {
813- file = GLib.File.new_for_path (path);
814-
815- info = new FileInfo ();
816- try {
817- info = file.query_info (
818- GLib.FileAttribute.STANDARD_CONTENT_TYPE + "," +
819- GLib.FileAttribute.STANDARD_IS_BACKUP + "," +
820- GLib.FileAttribute.STANDARD_IS_HIDDEN + "," +
821- GLib.FileAttribute.STANDARD_DISPLAY_NAME + "," +
822- GLib.FileAttribute.STANDARD_TYPE,
823- FileQueryInfoFlags.NONE);
824- } catch (GLib.Error error) {
825- info = null;
826- warning (error.message);
827- }
828+ Object (path: path);
829 }
830
831 // returns the path the file
832- string _path = null;
833+ private string _path;
834 public string path {
835- get { return _path != null ? _path : _path = file.get_path (); }
836+ get {
837+ _path = file.get_path ();
838+ return _path;
839+ }
840+ set construct {
841+ load_file_for_path (value);
842+ }
843 }
844
845 // returns the basename of the file
846- string _name = null;
847+ private string _name;
848 public string name {
849- get { return _name != null ? _name : _name = info.get_display_name (); }
850+ get {
851+ _name = info.get_display_name ();
852+ return _name;
853+ }
854 }
855
856 // returns the icon of the file's content type
857 GLib.Icon _icon = null;
858 public GLib.Icon icon {
859 get {
860- if (_icon != null)
861+ if (_icon != null) {
862 return _icon;
863- //var content_type = info.get_attribute_string (FileAttribute.STANDARD_FAST_CONTENT_TYPE);
864+ }
865+
866 var content_type = info.get_content_type ();
867 return _icon = GLib.ContentType.get_icon (content_type);
868 }
869@@ -82,37 +71,15 @@
870 get { return file.query_exists (); }
871 }
872
873- Type _type = Type.UNKNOWN;
874 // checks if we're dealing with a non-hidden, non-backup directory
875 public bool is_valid_directory {
876- get {
877- if (_type == Type.VALID_FILE)
878+ get {
879+ if (info.get_is_hidden () || info.get_is_backup ()) {
880 return false;
881- if (_type == Type.VALID_FOLDER)
882+ }
883+
884+ if (info.get_file_type () == FileType.DIRECTORY) {
885 return true;
886- if (_type == Type.INVALID)
887- return false;
888-
889- if (info.get_file_type () != FileType.DIRECTORY ||
890- info.get_is_hidden () || info.get_is_backup ()) {
891- return false;
892- }
893-
894- bool has_valid_children = false;
895-
896- foreach (var child in children) {
897- if (child.is_valid_textfile) {
898- _type = Type.VALID_FOLDER;
899- return has_valid_children = true;
900- }
901- }
902-
903- foreach (var child in children) {
904- if (child.is_valid_directory) {
905- has_valid_children = true;
906- _type = Type.VALID_FOLDER;
907- return has_valid_children = true;
908- }
909 }
910
911 return false;
912@@ -122,22 +89,13 @@
913 // checks if we're dealing with a textfile
914 public bool is_valid_textfile {
915 get {
916- if (_type == Type.VALID_FILE)
917+ if (info.get_is_hidden () || info.get_is_backup ()) {
918+ return false;
919+ }
920+
921+ if (info.get_file_type () == FileType.REGULAR &&
922+ ContentType.is_a (info.get_content_type (), "text/*")) {
923 return true;
924- if (_type == Type.VALID_FOLDER)
925- return false;
926- if (_type == Type.INVALID)
927- return false;
928-
929- if (info.get_file_type () == FileType.REGULAR) {
930- //var content_type = info.get_attribute_string (FileAttribute.STANDARD_FAST_CONTENT_TYPE);
931- var content_type = info.get_content_type ();
932- if (ContentType.is_a (content_type, "text/*") &&
933- !info.get_is_backup () &&
934- !info.get_is_hidden ()) {
935- _type = Type.VALID_FILE;
936- return true;
937- }
938 }
939
940 return false;
941@@ -148,8 +106,9 @@
942 GLib.List <File> _children = null;
943 public GLib.List <File> children {
944 get {
945- if (_children != null)
946+ if (_children != null) {
947 return _children;
948+ }
949
950 var parent = GLib.File.new_for_path (file.get_path ());
951 try {
952@@ -171,9 +130,27 @@
953 }
954 }
955
956- /*public void rename (string name) {
957- try {
958- file.set_display_name (name);
959+ private void load_file_for_path (string path) {
960+ file = GLib.File.new_for_path (path);
961+
962+ info = new FileInfo ();
963+ try {
964+ info = file.query_info (
965+ GLib.FileAttribute.STANDARD_CONTENT_TYPE + "," +
966+ GLib.FileAttribute.STANDARD_IS_BACKUP + "," +
967+ GLib.FileAttribute.STANDARD_IS_HIDDEN + "," +
968+ GLib.FileAttribute.STANDARD_DISPLAY_NAME + "," +
969+ GLib.FileAttribute.STANDARD_TYPE,
970+ FileQueryInfoFlags.NONE);
971+ } catch (GLib.Error error) {
972+ info = null;
973+ warning (error.message);
974+ }
975+ }
976+
977+ public void rename (string name) {
978+ try {
979+ file.set_display_name (name);
980 } catch (GLib.Error error) {
981 warning (error.message);
982 }
983@@ -185,21 +162,22 @@
984 } catch (GLib.Error error) {
985 warning (error.message);
986 }
987- }*/
988+ }
989
990- public void reset_cache () {
991- _name = null;
992- _path = null;
993+ private void reset_cache () {
994 _icon = null;
995 _children = null;
996- _type = Type.UNKNOWN;
997 }
998
999 public static int compare (File a, File b) {
1000- if (a.is_valid_directory && b.is_valid_textfile)
1001+ if (a.is_valid_directory && b.is_valid_textfile) {
1002 return -1;
1003- if (a.is_valid_textfile && b.is_valid_directory)
1004+ }
1005+
1006+ if (a.is_valid_textfile && b.is_valid_directory) {
1007 return 1;
1008+ }
1009+
1010 return strcmp (a.path.collate_key_for_filename (),
1011 b.path.collate_key_for_filename ());
1012 }
1013
1014=== added file 'plugins/folder-manager/FileItem.vala'
1015--- plugins/folder-manager/FileItem.vala 1970-01-01 00:00:00 +0000
1016+++ plugins/folder-manager/FileItem.vala 2016-11-30 23:31:32 +0000
1017@@ -0,0 +1,39 @@
1018+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1019+/*-
1020+ * Copyright (c) 2016 elementary LLC. (https://elementary.io)
1021+ *
1022+ * This program is free software: you can redistribute it and/or modify
1023+ * it under the terms of the GNU General Public License as published by
1024+ * the Free Software Foundation, either version 3 of the License, or
1025+ * (at your option) any later version.
1026+ *
1027+ * This program is distributed in the hope that it will be useful,
1028+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1029+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1030+ * GNU General Public License for more details.
1031+ *
1032+ * You should have received a copy of the GNU General Public License
1033+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1034+ *
1035+ * Authored by: Corentin Noël <corentin@elementary.io>, Andrei-Costin Zisu <matzipan@gmail.com>
1036+ */
1037+
1038+public class Scratch.Plugins.FolderManager.FileItem : Item {
1039+ public FileItem (Scratch.Plugins.FolderManager.File file, Scratch.Plugins.FolderManager.FileView view) requires (file.is_valid_textfile) {
1040+ Object (file: file, view: view);
1041+ }
1042+
1043+ public override Gtk.Menu? get_context_menu () {
1044+ var menu = new Gtk.Menu ();
1045+ var rename_item = new Gtk.MenuItem.with_label (_("Rename"));
1046+ rename_item.activate.connect (() => view.start_editing_item (this));
1047+ menu.append (rename_item);
1048+
1049+ var delete_item = new Gtk.MenuItem.with_label (_("Move to Trash"));
1050+ delete_item.activate.connect (() => do_remove ());
1051+ menu.append (delete_item);
1052+
1053+ menu.show_all ();
1054+ return menu;
1055+ }
1056+}
1057
1058=== modified file 'plugins/folder-manager/FileView.vala'
1059--- plugins/folder-manager/FileView.vala 2015-09-16 01:11:55 +0000
1060+++ plugins/folder-manager/FileView.vala 2016-11-30 23:31:32 +0000
1061@@ -1,22 +1,22 @@
1062 // -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1063-/***
1064- BEGIN LICENSE
1065-
1066- Copyright (C) 2013 Julien Spautz <spautz.julien@gmail.com>
1067- This program is free software: you can redistribute it and/or modify it
1068- under the terms of the GNU Lesser General Public License version 3, as published
1069- by the Free Software Foundation.
1070-
1071- This program is distributed in the hope that it will be useful, but
1072- WITHOUT ANY WARRANTY; without even the implied warranties of
1073- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1074- PURPOSE. See the GNU General Public License for more details.
1075-
1076- You should have received a copy of the GNU General Public License along
1077- with this program. If not, see <http://www.gnu.org/licenses/>
1078-
1079- END LICENSE
1080-***/
1081+/*-
1082+ * Copyright (c) 2016 elementary LLC. (https://elementary.io)
1083+ *
1084+ * This program is free software: you can redistribute it and/or modify
1085+ * it under the terms of the GNU General Public License as published by
1086+ * the Free Software Foundation, either version 3 of the License, or
1087+ * (at your option) any later version.
1088+ *
1089+ * This program is distributed in the hope that it will be useful,
1090+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1091+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1092+ * GNU General Public License for more details.
1093+ *
1094+ * You should have received a copy of the GNU General Public License
1095+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1096+ *
1097+ * Authored by: Julien Spautz <spautz.julien@gmail.com>, Andrei-Costin Zisu <matzipan@gmail.com>
1098+ */
1099
1100 namespace Scratch.Plugins.FolderManager {
1101 Settings settings;
1102@@ -24,25 +24,31 @@
1103 /**
1104 * SourceList that displays folders and their contents.
1105 */
1106- internal class FileView : Granite.Widgets.SourceList {
1107-
1108- public signal void select (string file);
1109-
1110+ public class FileView : Granite.Widgets.SourceList {
1111+ public signal void select (GLib.File file);
1112+ public signal void welcome_visible (bool visible);
1113 public FileView () {
1114- this.width_request = 180;
1115- this.item_selected.connect ((item) => {
1116- select ((item as FileItem).path);
1117+ width_request = 180;
1118+
1119+ item_selected.connect ((item) => {
1120+ if (item is FileItem) {
1121+ select ((item as FileItem).file.file);
1122+ }
1123+ });
1124+
1125+ root.child_removed.connect (() => {
1126+ this.selected = null;
1127+ if (root.n_children == 0) {
1128+ welcome_visible (true);
1129+ }
1130+
1131+ write_settings ();
1132 });
1133
1134 settings = new Settings ();
1135 }
1136
1137- public void restore_saved_state () {
1138- foreach (var path in settings.opened_folders)
1139- add_folder (new File (path), false);
1140- }
1141-
1142- public void open_folder (File folder) {
1143+ public void open_folder (File folder, bool expand = true) {
1144 if (is_open (folder)) {
1145 warning ("Folder '%s' is already open.", folder.path);
1146 return;
1147@@ -51,64 +57,81 @@
1148 return;
1149 }
1150
1151- add_folder (folder, true);
1152+ var folder_item = new FolderItem (folder, this);
1153+ root.add (folder_item);
1154+ welcome_visible (false);
1155+
1156+ folder_item.expanded = expand;
1157 write_settings ();
1158 }
1159
1160- private void add_folder (File folder, bool expand) {
1161- if (is_open (folder)) {
1162- warning ("Folder '%s' is already open.", folder.path);
1163- return;
1164- } else if (!folder.is_valid_directory) {
1165- warning ("Cannot open invalid directory.");
1166- return;
1167+ public void restore_settings () {
1168+ foreach (var folder_path in settings.opened_folders) {
1169+ if (folder_path == null) {
1170+ continue;
1171+ }
1172+
1173+ var folder = new File (folder_path);
1174+ if (folder.is_valid_directory) {
1175+ open_folder (folder);
1176+ }
1177 }
1178-
1179- var folder_root = new MainFolderItem (folder);
1180- this.root.add (folder_root);
1181-
1182- folder_root.expanded = expand;
1183- folder_root.closed.connect (() => {
1184- root.remove (folder_root);
1185- write_settings ();
1186- });
1187 }
1188
1189 private bool is_open (File folder) {
1190- foreach (var child in root.children)
1191- if (folder.path == (child as Item).path)
1192+ foreach (var child in root.children) {
1193+ if (folder.path == (child as Item).path) {
1194 return true;
1195+ }
1196+ }
1197+
1198 return false;
1199 }
1200
1201 private void write_settings () {
1202- string[] to_save = {};
1203-
1204- foreach (var main_folder in root.children) {
1205- var saved = false;
1206-
1207- foreach (var saved_folder in to_save) {
1208- if ((main_folder as Item).path == saved_folder) {
1209- saved = true;
1210- break;
1211- }
1212- }
1213-
1214- if (!saved) {
1215- to_save += (main_folder as Item).path;
1216+ string[] paths = {};
1217+ foreach (var child in this.root.children) {
1218+ if (child is FolderItem) {
1219+ paths += ((FolderItem) child).path;
1220 }
1221 }
1222
1223- settings.opened_folders = to_save;
1224+ settings.opened_folders = paths;
1225 }
1226 }
1227
1228 /**
1229- * Common abstract class for file and filder items.
1230+ * Common abstract class for normal and expandable items.
1231 */
1232- internal class Item: Granite.Widgets.SourceList.ExpandableItem, Granite.Widgets.SourceListSortable {
1233+ public class Item : Granite.Widgets.SourceList.ExpandableItem, Granite.Widgets.SourceListSortable {
1234 public File file { get; construct; }
1235- public string path { get { return file.path; } }
1236+ public Scratch.Plugins.FolderManager.FileView view { get; construct; }
1237+ public string path {
1238+ get { return file.path; }
1239+ set { file.path = value; }
1240+ }
1241+
1242+ construct {
1243+ selectable = true;
1244+ editable = true;
1245+ update_item ();
1246+
1247+ edited.connect (rename);
1248+ file.notify["path"].connect(update_item);
1249+ }
1250+
1251+ protected void update_item () {
1252+ name = file.name;
1253+ icon = file.icon;
1254+ }
1255+
1256+ protected void rename (string new_name) {
1257+ file.rename (new_name);
1258+ }
1259+
1260+ protected void do_remove () {
1261+ file.trash ();
1262+ }
1263
1264 public int compare (Granite.Widgets.SourceList.Item a, Granite.Widgets.SourceList.Item b) {
1265 if (a is FolderItem && b is FileItem) {
1266@@ -120,193 +143,8 @@
1267 return File.compare ((a as Item).file, (b as Item).file);
1268 }
1269
1270- public bool allow_dnd_sorting () {
1271+ public bool allow_dnd_sorting () {
1272 return false;
1273 }
1274 }
1275-
1276- /**
1277- * Normal item in the source list, represents a textfile.
1278- * TODO Remove, Rename
1279- */
1280- internal class FileItem : Item {
1281-
1282- //Gtk.Menu menu;
1283- //Gtk.MenuItem item_trash;
1284-
1285- public FileItem (File file) requires (file.is_valid_textfile) {
1286- Object (file: file);
1287-
1288- this.selectable = true;
1289- //this.editable = true;
1290- this.name = file.name;
1291- this.icon = file.icon;
1292- }
1293-
1294- /*public void rename (string new_name) {
1295- file.rename (new_name);
1296- }*/
1297-
1298- /*public override Gtk.Menu? get_context_menu () {
1299- menu = new Gtk.Menu ();
1300- item_trash = new Gtk.MenuItem.with_label (_("Move to Trash"));
1301- menu.append (item_trash);
1302- item_trash.activate.connect (() => { file.trash (); });
1303- menu.show_all ();
1304- return menu;
1305- }*/
1306- }
1307-
1308- /**
1309- * Expandable item in the source list, represents a folder.
1310- * Monitored for changes inside the directory.
1311- * TODO remove, rename, create new file
1312- */
1313- internal class FolderItem : Item {
1314-
1315- //Gtk.Menu menu;
1316- //Gtk.MenuItem item_trash;
1317- //Gtk.MenuItem item_create;
1318-
1319- private GLib.FileMonitor monitor;
1320- private bool children_loaded = false;
1321-
1322- public FolderItem (File file) requires (file.is_valid_directory) {
1323- Object (file: file);
1324-
1325- this.editable = false;
1326- this.selectable = false;
1327- this.name = file.name;
1328- this.icon = file.icon;
1329-
1330- this.add (new Granite.Widgets.SourceList.Item ("")); // dummy
1331- this.toggled.connect (() => {
1332- if (this.expanded && this.n_children <= 1) {
1333- this.clear ();
1334- this.add_children ();
1335- children_loaded = true;
1336- }
1337- });
1338-
1339- try {
1340- monitor = file.file.monitor_directory (GLib.FileMonitorFlags.NONE);
1341- monitor.changed.connect ((s,d,e) => { on_changed (s,d,e); });
1342- } catch (GLib.Error e) {
1343- warning (e.message);
1344- }
1345- }
1346-
1347- /*public override Gtk.Menu? get_context_menu () {
1348- menu = new Gtk.Menu ();
1349- item_trash = new Gtk.MenuItem.with_label (_("Move to Trash"));
1350- item_create = new Gtk.MenuItem.with_label (_("Create new File"));
1351- menu.append (item_trash);
1352- menu.append (item_create);
1353- item_trash.activate.connect (() => { file.trash (); });
1354- item_create.activate.connect (() => {
1355- var new_file = GLib.File.new_for_path (file.path + "/new File");
1356-
1357- try {
1358- FileOutputStream os = new_file.create (FileCreateFlags.NONE);
1359- } catch (Error e) {
1360- warning ("Error: %s\n", e.message);
1361- }
1362- });
1363- menu.show_all ();
1364- return menu;
1365- }*/
1366-
1367- internal void add_children () {
1368- foreach (var child in file.children) {
1369- if (child.is_valid_directory) {
1370- var item = new FolderItem (child);
1371- add (item);
1372- } else if (child.is_valid_textfile) {
1373- var item = new FileItem (child);
1374- add (item);
1375- //item.edited.connect (item.rename);
1376- }
1377- }
1378- }
1379-
1380- private void on_changed (GLib.File source, GLib.File? dest, GLib.FileMonitorEvent event) {
1381-
1382- if (!children_loaded) {
1383- this.file.reset_cache ();
1384- return;
1385- }
1386-
1387- switch (event) {
1388- case GLib.FileMonitorEvent.DELETED:
1389- var children_tmp = new Gee.ArrayList<Granite.Widgets.SourceList.Item> ();
1390- children_tmp.add_all (children);
1391- foreach (var item in children_tmp) {
1392- if ((item as Item).path == source.get_path ()) {
1393- remove (item);
1394- }
1395- }
1396-
1397- break;
1398- case GLib.FileMonitorEvent.CREATED:
1399- if (source.query_exists () == false) {
1400- return;
1401- }
1402-
1403- var file = new File (source.get_path ());
1404- var exists = false;
1405- foreach (var item in children) {
1406- if ((item as Item).path == file.path) {
1407- exists = true;
1408- break;
1409- }
1410- }
1411-
1412- if (!exists) {
1413- if (file.is_valid_textfile) {
1414- this.add (new FileItem (file));
1415- } else if (file.is_valid_directory) {
1416- this.add (new FolderItem (file));
1417- }
1418- }
1419-
1420- break;
1421- }
1422- }
1423- }
1424-
1425- /**
1426- * Special root folder.
1427- * TODO rename, create new file
1428- */
1429- internal class MainFolderItem : FolderItem {
1430- public signal void closed ();
1431-
1432- Gtk.Menu menu;
1433- Gtk.MenuItem item_close;
1434- //Gtk.MenuItem item_create;
1435-
1436- public MainFolderItem (File file) requires (file.is_valid_directory) {
1437- base (file);
1438- }
1439-
1440- public override Gtk.Menu? get_context_menu () {
1441- menu = new Gtk.Menu ();
1442- item_close = new Gtk.MenuItem.with_label (_("Close Folder"));
1443- //item_create = new Gtk.MenuItem.with_label (_("Create new File"));
1444- menu.append (item_close);
1445- //menu.append (item_create);
1446- item_close.activate.connect (() => { closed (); });
1447- /*item_create.activate.connect (() => {
1448- var new_file = GLib.File.new_for_path (file.path + "/new File");
1449-
1450- try {
1451- FileOutputStream os = new_file.create (FileCreateFlags.NONE);
1452- } catch (Error e) {
1453- warning ("Error: %s\n", e.message);
1454- }
1455- });*/
1456- menu.show_all ();
1457- return menu;
1458- }
1459- }
1460 }
1461
1462=== added file 'plugins/folder-manager/FolderItem.vala'
1463--- plugins/folder-manager/FolderItem.vala 1970-01-01 00:00:00 +0000
1464+++ plugins/folder-manager/FolderItem.vala 2016-11-30 23:31:32 +0000
1465@@ -0,0 +1,196 @@
1466+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1467+/*-
1468+ * Copyright (c) 2016 elementary LLC. (https://elementary.io)
1469+ *
1470+ * This program is free software: you can redistribute it and/or modify
1471+ * it under the terms of the GNU General Public License as published by
1472+ * the Free Software Foundation, either version 3 of the License, or
1473+ * (at your option) any later version.
1474+ *
1475+ * This program is distributed in the hope that it will be useful,
1476+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1477+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1478+ * GNU General Public License for more details.
1479+ *
1480+ * You should have received a copy of the GNU General Public License
1481+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1482+ *
1483+ * Authored by: Corentin Noël <corentin@elementary.io>, Andrei-Costin Zisu <matzipan@gmail.com>
1484+ */
1485+
1486+public class Scratch.Plugins.FolderManager.FolderItem : Item {
1487+ public signal void folder_open (GLib.File folder);
1488+
1489+ private GLib.FileMonitor monitor;
1490+ private bool children_loaded = false;
1491+
1492+ public FolderItem (Scratch.Plugins.FolderManager.File file, Scratch.Plugins.FolderManager.FileView view) requires (file.is_valid_directory) {
1493+ Object (file: file, view: view);
1494+ }
1495+
1496+ construct {
1497+ if (file.children.length () > 0) {
1498+ add (new Granite.Widgets.SourceList.Item ("")); // dummy
1499+ }
1500+
1501+ toggled.connect (() => {
1502+ if (expanded && n_children <= 1) {
1503+ clear ();
1504+ add_children ();
1505+ children_loaded = true;
1506+ }
1507+ });
1508+
1509+ try {
1510+ monitor = file.file.monitor_directory (GLib.FileMonitorFlags.WATCH_MOVES);
1511+ monitor.changed.connect (on_changed);
1512+ } catch (GLib.Error e) {
1513+ warning (e.message);
1514+ }
1515+ }
1516+
1517+ public override Gtk.Menu? get_context_menu () {
1518+ var menu = new Gtk.Menu ();
1519+ if (parent == view.root) {
1520+ var item = new Gtk.MenuItem.with_label (_("Close Folder"));
1521+ item.activate.connect (() => {
1522+ monitor.cancel ();
1523+ parent.remove (this);
1524+ });
1525+ menu.append (item);
1526+ } else {
1527+ var item = new Gtk.MenuItem.with_label (_("Open"));
1528+ item.activate.connect (() => folder_open (file.file));
1529+ menu.append (item);
1530+ }
1531+
1532+ var rename_item = new Gtk.MenuItem.with_label (_("Rename"));
1533+ rename_item.activate.connect (() => view.start_editing_item (this));
1534+ menu.append (rename_item);
1535+
1536+ var new_file_item = new Gtk.MenuItem.with_label (_("Add file"));
1537+ new_file_item.activate.connect (() => add_file ());
1538+ menu.append (new_file_item);
1539+
1540+ var new_folder_item = new Gtk.MenuItem.with_label (_("Add folder"));
1541+ new_folder_item.activate.connect(() => add_folder ());
1542+ menu.append (new_folder_item);
1543+
1544+ var delete_item = new Gtk.MenuItem.with_label (_("Move to Trash"));
1545+ delete_item.activate.connect (() => do_remove ());
1546+ menu.append (delete_item);
1547+
1548+ menu.show_all ();
1549+ return menu;
1550+ }
1551+
1552+ internal void add_children () {
1553+ foreach (var child in file.children) {
1554+ if (child.is_valid_directory) {
1555+ var item = new FolderItem (child, view);
1556+ item.folder_open.connect (() => {
1557+ view.open_folder (child);
1558+ });
1559+
1560+ add (item);
1561+ } else if (child.is_valid_textfile) {
1562+ var item = new FileItem (child, view);
1563+ add (item);
1564+ }
1565+ }
1566+ }
1567+
1568+ private void on_changed (GLib.File source, GLib.File? dest, GLib.FileMonitorEvent event) {
1569+ if (!children_loaded) {
1570+ return;
1571+ }
1572+
1573+ switch (event) {
1574+ case GLib.FileMonitorEvent.RENAMED:
1575+ foreach (var child in children) {
1576+ var item = child as Item;
1577+ if (item.path == source.get_path ()) {
1578+ item.path = dest.get_path ();
1579+ break;
1580+ }
1581+ }
1582+ break;
1583+ case GLib.FileMonitorEvent.DELETED:
1584+ var children_tmp = new Gee.ArrayList<Granite.Widgets.SourceList.Item> ();
1585+ children_tmp.add_all (children);
1586+ foreach (var item in children_tmp) {
1587+ if ((item as Item).path == source.get_path ()) {
1588+ remove (item);
1589+ }
1590+ }
1591+
1592+ break;
1593+ case GLib.FileMonitorEvent.CREATED:
1594+ if (source.query_exists () == false) {
1595+ return;
1596+ }
1597+
1598+ var file = new File (source.get_path ());
1599+ var exists = false;
1600+ foreach (var item in children) {
1601+ if ((item as Item).path == file.path) {
1602+ exists = true;
1603+ }
1604+ }
1605+
1606+ if (!exists) {
1607+ if (file.is_valid_textfile) {
1608+ add (new FileItem (file, view));
1609+ } else if (file.is_valid_directory) {
1610+ add (new FolderItem (file, view));
1611+ }
1612+ }
1613+
1614+ break;
1615+ }
1616+ }
1617+
1618+ private void add_folder () {
1619+ var child = file.file.get_child (_("New Folder"));
1620+
1621+ var n = 1;
1622+ while (child.query_exists ()) {
1623+ child = file.file.get_child (_("New Folder (%d)").printf (n));
1624+ n++;
1625+ }
1626+
1627+ try {
1628+ child.make_directory ();
1629+
1630+ if (children_loaded) {
1631+ var item = new FolderItem (new File (child.get_path ()), view);
1632+ add (item);
1633+ view.start_editing_item (item);
1634+ }
1635+ } catch (Error e) {
1636+ warning (e.message);
1637+ }
1638+ }
1639+
1640+ private void add_file () {
1641+ var child = file.file.get_child (_("New File"));
1642+
1643+ var n = 1;
1644+ while (child.query_exists ()) {
1645+ child = file.file.get_child (_("New File (%d)").printf (n));
1646+ n++;
1647+ }
1648+
1649+ try {
1650+ child.create (FileCreateFlags.NONE);
1651+
1652+ if (children_loaded) {
1653+ var item = new FileItem (new File (child.get_path ()), view);
1654+ add (item);
1655+ view.start_editing_item (item);
1656+ }
1657+ } catch (Error e) {
1658+ warning (e.message);
1659+ }
1660+ }
1661+}
1662
1663=== modified file 'plugins/folder-manager/FolderManagerPlugin.vala'
1664--- plugins/folder-manager/FolderManagerPlugin.vala 2015-12-01 11:37:53 +0000
1665+++ plugins/folder-manager/FolderManagerPlugin.vala 2016-11-30 23:31:32 +0000
1666@@ -23,13 +23,10 @@
1667
1668 namespace Scratch.Plugins {
1669 public class FolderManagerPlugin : Peas.ExtensionBase, Peas.Activatable {
1670-
1671+ public Scratch.Services.Interface plugins;
1672+ Gtk.Button button;
1673 FolderManager.FileView view;
1674- Gtk.ToolButton tool_button;
1675-
1676- int index = 0;
1677-
1678- Scratch.Services.Interface plugins;
1679+
1680 public Object object { owned get; construct; }
1681
1682 public FolderManagerPlugin () {
1683@@ -43,74 +40,71 @@
1684 }
1685
1686 public void deactivate () {
1687- if (view != null)
1688+ if (view != null) {
1689 view.destroy();
1690- if (tool_button != null) {
1691- //(tool_button.parent as Scratch.Widgets.Toolbar).open_button.visible = true;
1692- tool_button.destroy ();
1693+ view = null;
1694+ }
1695+
1696+ if (button != null) {
1697+ button.destroy();
1698+ button = null;
1699 }
1700 }
1701
1702 public void update_state () {
1703+
1704 }
1705
1706 void on_hook_sidebar (Gtk.Notebook notebook) {
1707- if (view != null)
1708+ if (view != null) {
1709 return;
1710+ }
1711
1712+ // File View
1713 view = new FolderManager.FileView ();
1714-
1715- view.select.connect ((a) => {
1716- var file = GLib.File.new_for_path (a);
1717- plugins.open_file (file);
1718- });
1719-
1720- view.root.child_added.connect (() => {
1721- if (view.get_n_visible_children (view.root) == 0) {
1722- index = notebook.append_page (view, new Gtk.Label (_("Folders")));
1723+ view.select.connect ((file) => plugins.open_file (file));
1724+ view.welcome_visible.connect ((visible) => {
1725+ if (visible) {
1726+ view.parent.remove (view);
1727+ } else if (view.parent == null) {
1728+ view.show_all ();
1729+ var icon = new Gtk.Image.from_icon_name ("folder-symbolic", Gtk.IconSize.MENU);
1730+ icon.tooltip_text = _("File Manager");
1731+ notebook.append_page (view , icon);
1732 }
1733 });
1734
1735- view.root.child_removed.connect (() => {
1736- if (view.get_n_visible_children (view.root) == 1)
1737- notebook.remove_page (index);
1738- });
1739-
1740- view.restore_saved_state ();
1741+ view.restore_settings ();
1742 }
1743
1744 void on_hook_toolbar (Gtk.HeaderBar toolbar) {
1745- if (tool_button != null)
1746+ if (button != null) {
1747 return;
1748-
1749- //(toolbar as Scratch.Widgets.Toolbar).open_button.visible = false;
1750- var icon = new Gtk.Image.from_icon_name ("folder-saved-search", Gtk.IconSize.LARGE_TOOLBAR);
1751- tool_button = new Gtk.ToolButton (icon, _("Open a folder"));
1752- tool_button.tooltip_text = _("Open a folder");
1753- tool_button.clicked.connect (() => {
1754- Gtk.Window window = plugins.manager.window;
1755- Gtk.FileChooserDialog chooser = new Gtk.FileChooserDialog (
1756- "Select a folder.", window, Gtk.FileChooserAction.SELECT_FOLDER,
1757- _("_Cancel"), Gtk.ResponseType.CANCEL,
1758- _("_Open"), Gtk.ResponseType.ACCEPT);
1759- chooser.select_multiple = true;
1760-
1761- if (chooser.run () == Gtk.ResponseType.ACCEPT) {
1762- SList<string> uris = chooser.get_uris ();
1763- foreach (unowned string uri in uris) {
1764- var folder = new FolderManager.File (uri.replace ("file:///", "/"));
1765- view.open_folder (folder); // emit signal
1766- }
1767- }
1768-
1769- chooser.close ();
1770- });
1771-
1772- icon.show ();
1773- tool_button.show ();
1774-
1775- toolbar.pack_start (tool_button);
1776- //toolbar.insert (tool_button, 1);
1777+ }
1778+
1779+ button = new Gtk.Button.from_icon_name ("folder-saved-search", Gtk.IconSize.LARGE_TOOLBAR);
1780+ button.tooltip_text = _("Open a folder");
1781+ button.clicked.connect (() => open_dialog ());
1782+ button.show_all ();
1783+ toolbar.pack_start (button);
1784+ }
1785+
1786+ private void open_dialog () {
1787+ Gtk.Window window = plugins.manager.window;
1788+ Gtk.FileChooserDialog chooser = new Gtk.FileChooserDialog (
1789+ "Select a folder.", window, Gtk.FileChooserAction.SELECT_FOLDER,
1790+ _("_Cancel"), Gtk.ResponseType.CANCEL,
1791+ _("_Open"), Gtk.ResponseType.ACCEPT);
1792+ chooser.select_multiple = true;
1793+
1794+ if (chooser.run () == Gtk.ResponseType.ACCEPT) {
1795+ chooser.get_files ().foreach ((file) => {
1796+ var folder = new Scratch.Plugins.FolderManager.File (file.get_path ());
1797+ view.open_folder (folder);
1798+ });
1799+ }
1800+
1801+ chooser.close ();
1802 }
1803 }
1804 }
1805
1806=== modified file 'plugins/folder-manager/folder-manager.plugin'
1807--- plugins/folder-manager/folder-manager.plugin 2013-06-08 15:17:42 +0000
1808+++ plugins/folder-manager/folder-manager.plugin 2016-11-30 23:31:32 +0000
1809@@ -3,8 +3,8 @@
1810 Loader=C
1811 IAge=2
1812 Name=Folder Manager
1813-Description=Basic folder manager with file browsing
1814-Icon=folder-saved-search
1815-Authors=Julien Spautz <spautz.julien@gmail.com>
1816-Copyright=Copyright © 2013 Scratch Developers
1817+Description=Browse files and directories
1818+Icon=system-file-manager
1819+Authors=Mario Guerriero, Julien Spautz, Corentin Noël, Andrei Zisu
1820+Copyright=Copyright © 2016 elementary LLC
1821 Website=http://launchpad.net/scratch
1822
1823=== modified file 'schemas/CMakeLists.txt'
1824--- schemas/CMakeLists.txt 2015-09-10 00:54:45 +0000
1825+++ schemas/CMakeLists.txt 2016-11-30 23:31:32 +0000
1826@@ -1,6 +1,5 @@
1827 include(GSettings)
1828 add_schema("org.pantheon.scratch.gschema.xml")
1829 add_schema("org.pantheon.scratch.plugins.folder-manager.gschema.xml")
1830-add_schema("org.pantheon.scratch.plugins.file-manager.gschema.xml")
1831 add_schema("org.pantheon.scratch.plugins.terminal.gschema.xml")
1832 add_schema("org.pantheon.scratch.plugins.spell.gschema.xml")
1833
1834=== removed file 'schemas/org.pantheon.scratch.plugins.file-manager.gschema.xml'
1835--- schemas/org.pantheon.scratch.plugins.file-manager.gschema.xml 2013-07-16 15:56:38 +0000
1836+++ schemas/org.pantheon.scratch.plugins.file-manager.gschema.xml 1970-01-01 00:00:00 +0000
1837@@ -1,10 +0,0 @@
1838-<?xml version="1.0" encoding="UTF-8"?>
1839-<schemalist>
1840- <schema path="/org/pantheon/scratch/plugins/file-manager/" id="org.pantheon.scratch.plugins.file-manager" gettext-domain="scratch">
1841- <key name="opened-folder" type="s">
1842- <default>''</default>
1843- <summary>Opened folder.</summary>
1844- <description>Opened folder that should be restored in startup.</description>
1845- </key>
1846- </schema>
1847-</schemalist>

Subscribers

People subscribed via source and target branches