From b34670873da6fa6b77757e55811e715143b63d31 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 12 Sep 2017 17:20:07 +0300 Subject: [PATCH] workspace explorer - preserve tree items expand/collapse state and selected item - implement #252 --- dub.json | 2 +- src/dlangide/ui/wspanel.d | 93 +++++++++++++++++++--- src/dlangide/workspace/workspace.d | 21 +++++ src/dlangide/workspace/workspacesettings.d | 24 ++++++ views/VERSION | 2 +- 5 files changed, 130 insertions(+), 12 deletions(-) diff --git a/dub.json b/dub.json index d3c6a2b..5cdbc52 100644 --- a/dub.json +++ b/dub.json @@ -12,7 +12,7 @@ "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/hdpi"], "dependencies": { - "dlangui": "==0.9.126", + "dlangui": "==0.9.127", "dsymbol": "~>0.2.9", "dcd": "~>0.9.1" }, diff --git a/src/dlangide/ui/wspanel.d b/src/dlangide/ui/wspanel.d index 5c5e59e..03a624b 100644 --- a/src/dlangide/ui/wspanel.d +++ b/src/dlangide/ui/wspanel.d @@ -53,6 +53,15 @@ class WorkspacePanel : DockWindow { void onTreeItemSelected(TreeItems source, TreeItem selectedItem, bool activated) { if (!selectedItem) return; + if (_workspace) { + // save selected item id + ProjectItem item = cast(ProjectItem)selectedItem.objectParam; + if (item) { + string id = item.filename; + if (id) + _workspace.selectedWorkspaceItem = id; + } + } if (selectedItem.intParam == ProjectItemType.SourceFile) { // file selected if (sourceFileSelectionListener.assigned) { @@ -70,6 +79,7 @@ class WorkspacePanel : DockWindow { _tree = new TreeWidget("wstree"); _tree.layoutHeight(FILL_PARENT).layoutHeight(FILL_PARENT); _tree.selectionChange = &onTreeItemSelected; + _tree.expandedChange.connect(&onTreeExpandedStateChange); _tree.fontSize = 16; _tree.noCollapseForSingleTopLevelItem = true; _tree.popupMenu = &onTreeItemPopupMenu; @@ -173,6 +183,10 @@ class WorkspacePanel : DockWindow { TreeItem p = root.newChild(child.filename, child.name, "folder"); p.intParam = ProjectItemType.SourceFolder; p.objectParam = child; + if (restoreItemState(child.filename)) + p.expand(); + else + p.collapse(); addProjectItems(p, child); } else { string icon = "text-other"; @@ -201,7 +215,55 @@ class WorkspacePanel : DockWindow { _tree.items.setDefaultItem(defaultItem); } + protected bool[string] _itemStates; + protected bool _itemStatesDirty; + protected void readExpandedStateFromWorkspace() { + _itemStates.clear(); + if (_workspace) { + string[] items = _workspace.expandedItems; + foreach(item; items) + _itemStates[item] = true; + } + } + protected void saveItemState(string itemPath, bool expanded) { + bool changed = restoreItemState(itemPath) != expanded; + if (!_itemStatesDirty && changed) + _itemStatesDirty = true; + if (changed) { + if (expanded) { + _itemStates[itemPath] = true; + } else { + _itemStates.remove(itemPath); + } + string[] items; + items.assumeSafeAppend; + foreach(k,v; _itemStates) { + items ~= k; + } + _workspace.expandedItems = items; + } + debug Log.d("stored Expanded state ", expanded, " for ", itemPath); + } + protected bool restoreItemState(string itemPath) { + if (auto p = itemPath in _itemStates) { + debug Log.d("restored Expanded state for ", itemPath); + return *p; + } + return false; + } + + void onTreeExpandedStateChange(TreeItems source, TreeItem item) { + bool expanded = item.expanded; + ProjectItem prjItem = cast(ProjectItem)item.objectParam; + if (prjItem) { + string fn = prjItem.filename; + debug Log.d("onTreeExpandedStateChange expanded=", expanded, " fn=", fn); + saveItemState(fn, expanded); + } + } + void reloadItems() { + _tree.expandedChange.disconnect(&onTreeExpandedStateChange); _tree.clearAllItems(); if (_workspace) { TreeItem defaultItem = null; @@ -211,6 +273,10 @@ class WorkspacePanel : DockWindow { TreeItem p = root.newChild(project.filename, project.name, project.isDependency ? "project-d-dependency" : "project-d"); p.intParam = ProjectItemType.Project; p.objectParam = project; + if (restoreItemState(project.filename)) + p.expand(); + else + p.collapse(); if (project && _workspace.startupProject is project) defaultItem = p; addProjectItems(p, project.items); @@ -219,24 +285,31 @@ class WorkspacePanel : DockWindow { } else { _tree.items.newChild("none", "No workspace"d, "project-development"); } - _tree.onTreeContentChange(null); - if (_workspace) { - TreeItem root = _tree.items.child(0); - for (int i = 0; i < root.childCount; i++) { - TreeItem child = root.child(i); - if (child.intParam == ProjectItemType.Project) { - Object obj = child.objectParam; - Project prj = cast(Project)obj; - if (prj && prj.isDependency) - child.collapse(); + _tree.expandedChange.connect(&onTreeExpandedStateChange); + + // expand default project if no information about expanded items + if (!_itemStates.length) { + if (_workspace && _workspace.startupProject) { + string fn = _workspace.startupProject.filename; + TreeItem startupProjectItem = _tree.items.findItemById(fn); + if (startupProjectItem) { + startupProjectItem.expand(); + saveItemState(fn, true); } } } + if (_workspace) { + // restore selection + string id = _workspace.selectedWorkspaceItem; + _tree.selectItem(id); + } + updateDefault(); } @property void workspace(Workspace w) { _workspace = w; + readExpandedStateFromWorkspace(); reloadItems(); } diff --git a/src/dlangide/workspace/workspace.d b/src/dlangide/workspace/workspace.d index 119eb41..36083cc 100644 --- a/src/dlangide/workspace/workspace.d +++ b/src/dlangide/workspace/workspace.d @@ -107,6 +107,27 @@ class Workspace : WorkspaceItem { _settings.files(fs); } + /// read list of expanded items from settings + @property string[] expandedItems() { + return _settings.expandedItems(); + } + + /// update list of expanded items in settings + @property void expandedItems(string[] items) { + _settings.expandedItems(items); + } + + /// last selected workspace item in workspace explorer + @property string selectedWorkspaceItem() { + return _settings.selectedWorkspaceItem; + } + + /// update last selected workspace item in workspace explorer + @property void selectedWorkspaceItem(string item) { + if (_settings.selectedWorkspaceItem != item) + _settings.selectedWorkspaceItem = item; + } + /// setups currrent project configuration by name void setStartupProjectConfiguration(string conf) { diff --git a/src/dlangide/workspace/workspacesettings.d b/src/dlangide/workspace/workspacesettings.d index 19ced77..fa00ea1 100644 --- a/src/dlangide/workspace/workspacesettings.d +++ b/src/dlangide/workspace/workspacesettings.d @@ -53,6 +53,30 @@ class WorkspaceSettings : SettingsFile { } } + /// list of expanded workspace explorer items + @property string[] expandedItems() { + Setting obj = _setting.settingByPath("expandedItems", SettingType.ARRAY); + return obj.strArray; + } + + /// update list of expanded workspace explorer items + @property void expandedItems(string[] items) { + Setting obj = _setting.settingByPath("expandedItems", SettingType.ARRAY); + obj.strArray = items; + } + + /// last selected workspace item in workspace explorer + @property string selectedWorkspaceItem() { + Setting obj = _setting.settingByPath("selectedWorkspaceItem", SettingType.STRING); + return obj.str; + } + + /// update last selected workspace item in workspace explorer + @property void selectedWorkspaceItem(string item) { + Setting obj = _setting.settingByPath("selectedWorkspaceItem", SettingType.STRING); + obj.str = item; + } + /// get all breakpoints for project (for specified source file only, if specified) Breakpoint[] getProjectBreakpoints(string projectName, string projectFilePath) { Breakpoint[] res; diff --git a/views/VERSION b/views/VERSION index b1e9e05..63eee66 100644 --- a/views/VERSION +++ b/views/VERSION @@ -1 +1 @@ -v0.7.76 \ No newline at end of file +v0.7.77 \ No newline at end of file