Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions data/io.elementary.code.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -243,5 +243,10 @@
<summary>Opened folders.</summary>
<description>Opened folders that should be restored in startup.</description>
</key>
<key name="closed-folders" type="as">
<default>[]</default>
<summary>Recently closed folders.</summary>
<description>Recently closed folders to be shown in project chooser button dropdown.</description>
</key>
</schema>
</schemalist>
55 changes: 49 additions & 6 deletions src/FolderManager/FileView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,7 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane
foreach (var child in root.children) {
var project_folder_item = (ProjectFolderItem) child;
if (project_folder_item != folder_root) {
toplevel_action_group.activate_action (
MainWindow.ACTION_CLOSE_PROJECT_DOCS,
new Variant.string (project_folder_item.path)
);
root.remove (project_folder_item);
git_manager.remove_project (project_folder_item);
project_folder_item.closed (); // Signal not processed 'til loop complete
}
}
//Make remaining project the active one
Expand Down Expand Up @@ -663,13 +658,18 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane
}
Scratch.Services.GitManager.get_instance ().remove_project (folder_root);
write_settings ();
update_recently_closed_projects (folder_root, true);
});

// We do not want to rewrite settings while restoring from settings
// This interferes with fuzzy-finder plugins_manager
// See https://github.com/elementary/code/issues/1533
if (!restoring) {
// Add opened folder to settings
write_settings ();
// Remove folder from recently closed if present
update_recently_closed_projects (folder_root, false);

}

add_folder.callback ();
Expand Down Expand Up @@ -709,4 +709,47 @@ public class Scratch.FolderManager.FileView : Code.Widgets.SourceList, Code.Pane

settings.set_strv ("opened-folders", to_save);
}

private void update_recently_closed_projects (
ProjectFolderItem closed_folder,
bool to_be_added
) {
string[] recently_closed = settings.get_strv ("closed-folders");
var closed_path = closed_folder.path;
bool found = false;
int index = 0;
foreach (string path in recently_closed) {
if (path == closed_path) {
found = true;
break;
}

index++;
}

if ((to_be_added && found) || (!to_be_added && !found)) {
return;
}

if (to_be_added) {
if (recently_closed.length < 10) {
recently_closed += closed_path;
} else {
recently_closed.move (1, 0, 9);
recently_closed[9] = closed_path;
}
} else {
var size = recently_closed.length;
if (index < size - 1) {
recently_closed.move (index + 1, index, size - index);
} else {
recently_closed[index] = null; // Need to use null for resize to work
}


recently_closed.resize (size - 1);
}

settings.set_strv ("closed-folders", recently_closed);
}
}
105 changes: 76 additions & 29 deletions src/Widgets/ChooseProjectButton.vala
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ public class Code.ChooseProjectButton : Gtk.Bin {
return (((ProjectRow) row).project_name.down ().contains (project_filter.text.down ().strip ()));
});

project_listbox.set_header_func ((row, before) => {
if (before == null && ((ProjectRow) row).is_open) {
row.set_header (new Granite.HeaderLabel (_("Open Projects")) { halign = START });
} else if (!((ProjectRow) row).is_open && (before == null || ((ProjectRow) before).is_open)) {
row.set_header (new Granite.HeaderLabel (_("Recently Closed Projects")) { halign = START });
}
});

project_filter.changed.connect (() => {
project_listbox.invalidate_filter ();
});
Expand Down Expand Up @@ -98,30 +106,13 @@ public class Code.ChooseProjectButton : Gtk.Bin {
child = menu_button;

// Initialise with any pre-existing projects (needed for second and subsequent window)
var git_manager = Scratch.Services.GitManager.get_instance ();
var src = git_manager.project_liststore;
for (int index = 0; index < src.n_items; index++) {
var item = src.get_object (index);
if (item is Scratch.FolderManager.ProjectFolderItem) {
var row = create_project_row ((Scratch.FolderManager.ProjectFolderItem)item);
project_listbox.insert (row, index);
}
}
insert_project_rows ();

git_manager.project_liststore.items_changed.connect ((src, pos, n_removed, n_added) => {
var rows = project_listbox.get_children ();
for (int index = (int)pos; index < pos + n_removed; index++) {
var row = rows.nth_data (index);
row.destroy ();
}

for (int index = (int)pos; index < pos + n_added; index++) {
var item = src.get_object (index);
if (item is Scratch.FolderManager.ProjectFolderItem) {
var row = create_project_row ((Scratch.FolderManager.ProjectFolderItem)item);
project_listbox.insert (row, index);
}
}
// Update the list when projects added to or deleted from git manager
var git_manager = Scratch.Services.GitManager.get_instance ();
git_manager.project_liststore.items_changed.connect (() => {
// Inserting is delayed so the settings should have been updated when runs
insert_project_rows ();
});

menu_button.activate.connect (() => {
Expand All @@ -139,6 +130,51 @@ public class Code.ChooseProjectButton : Gtk.Bin {
update_button ();
}

// Throttle rebuilding the list as gitmanager emits multiple changed signals on startup
// and we need to wait for settings to update
uint insert_timeout_id = 0;
bool insert_wait = false;
private void insert_project_rows () {
if (insert_timeout_id == 0) {
insert_wait = false;
Timeout.add (20, () => {
if (insert_wait) {
insert_wait = false;
return Source.CONTINUE;
}

var rows = project_listbox.get_children ();
foreach (var row in rows) {
row.destroy ();
}

var git_manager = Scratch.Services.GitManager.get_instance ();
var src = git_manager.project_liststore;
int index = 0;
for (index = 0; index < src.n_items; index++) {
var item = src.get_object (index);
if (item is Scratch.FolderManager.ProjectFolderItem) {
var row = create_project_row ((Scratch.FolderManager.ProjectFolderItem)item, true);
project_listbox.insert (row, index);
}
}

var settings = new GLib.Settings ("io.elementary.code.folder-manager");
var recently_closed = settings.get_strv ("closed-folders");
var size = recently_closed.length;
// List in reverse order so most recently closed appears first
for (int idx = size - 1; idx >= 0; idx--) {
var row = new ProjectRow (recently_closed[idx], false);
project_listbox.insert (row, index++);
}

return Source.REMOVE;
});
} else {
insert_wait = true;
}
}

// Set appearance (only) of project chooser button and list according to active path
private void update_button () {
unowned var active_path = Scratch.Services.GitManager.get_instance ().active_project_path;
Expand All @@ -151,9 +187,12 @@ public class Code.ChooseProjectButton : Gtk.Bin {
}
}

private Gtk.Widget create_project_row (Scratch.FolderManager.ProjectFolderItem project_folder) {
private Gtk.Widget create_project_row (
Scratch.FolderManager.ProjectFolderItem project_folder,
bool is_open = true
) {
var project_path = project_folder.file.file.get_path ();
var project_row = new ProjectRow (project_path);
var project_row = new ProjectRow (project_path, is_open);
// Project folder items cannot be renamed in UI, no need to handle

return project_row;
Expand All @@ -172,15 +211,18 @@ public class Code.ChooseProjectButton : Gtk.Bin {
}

public string project_path { get; construct; }
public bool is_open { get; construct; }

public string project_name {
get {
return check_button.label;
}
}

public ProjectRow (string project_path) {
public ProjectRow (string project_path, bool is_open) {
Object (
project_path: project_path
project_path: project_path,
is_open: is_open
);
}

Expand All @@ -192,8 +234,13 @@ public class Code.ChooseProjectButton : Gtk.Bin {

construct {
can_focus = true;
action_name = Scratch.MainWindow.ACTION_PREFIX + Scratch.MainWindow.ACTION_SET_ACTIVE_PROJECT;
action_name = Scratch.MainWindow.ACTION_PREFIX;
action_target = new Variant.string (project_path);
if (is_open) {
action_name += Scratch.MainWindow.ACTION_SET_ACTIVE_PROJECT;
} else {
action_name += Scratch.MainWindow.ACTION_OPEN_FOLDER;
}

check_button = new Gtk.CheckButton.with_label (Path.get_basename (project_path)) {
can_focus = false
Expand All @@ -206,7 +253,7 @@ public class Code.ChooseProjectButton : Gtk.Bin {
button = 0
};
button_controller.released.connect (() => {
activate ();
activate (); // Trigger the linked action
});

show_all ();
Expand Down
Loading