1 module dlangide.ui.wspanel; 2 3 import dlangui; 4 import dlangide.workspace.workspace; 5 import dlangide.workspace.project; 6 import dlangide.ui.commands; 7 8 enum ProjectItemType : int { 9 None, 10 SourceFile, 11 SourceFolder, 12 Project, 13 Workspace 14 } 15 16 interface SourceFileSelectionHandler { 17 bool onSourceFileSelected(ProjectSourceFile file, bool activate); 18 } 19 20 interface WorkspaceActionHandler { 21 bool onWorkspaceAction(const Action a); 22 } 23 24 class WorkspacePanel : DockWindow { 25 protected Workspace _workspace; 26 protected TreeWidget _tree; 27 28 /// handle source file selection change 29 Signal!SourceFileSelectionHandler sourceFileSelectionListener; 30 Signal!WorkspaceActionHandler workspaceActionListener; 31 32 this(string id) { 33 super(id); 34 workspace = null; 35 //layoutWidth = 200; 36 _caption.text = "Workspace Explorer"d; 37 } 38 39 bool selectItem(ProjectItem projectItem) { 40 if (projectItem) { 41 TreeItem item = _tree.findItemById(projectItem.filename); 42 if (item) { 43 _tree.selectItem(item); 44 return true; 45 } 46 } else { 47 _tree.clearSelection(); 48 return true; 49 } 50 return false; 51 } 52 53 void onTreeItemSelected(TreeItems source, TreeItem selectedItem, bool activated) { 54 if (!selectedItem) 55 return; 56 if (selectedItem.intParam == ProjectItemType.SourceFile) { 57 // file selected 58 if (sourceFileSelectionListener.assigned) { 59 ProjectSourceFile sourceFile = cast(ProjectSourceFile)selectedItem.objectParam; 60 if (sourceFile) { 61 sourceFileSelectionListener(sourceFile, activated); 62 } 63 } 64 } else if (selectedItem.intParam == ProjectItemType.SourceFolder) { 65 // folder selected 66 } 67 } 68 69 override protected Widget createBodyWidget() { 70 _tree = new TreeWidget("wstree"); 71 _tree.layoutHeight(FILL_PARENT).layoutHeight(FILL_PARENT); 72 _tree.selectionChange = &onTreeItemSelected; 73 _tree.fontSize = 16; 74 _tree.noCollapseForSingleTopLevelItem = true; 75 _tree.popupMenu = &onTreeItemPopupMenu; 76 77 _workspacePopupMenu = new MenuItem(); 78 _workspacePopupMenu.add(ACTION_PROJECT_FOLDER_REFRESH, 79 ACTION_FILE_WORKSPACE_CLOSE); 80 81 _projectPopupMenu = new MenuItem(); 82 _projectPopupMenu.add(ACTION_PROJECT_SET_STARTUP, 83 ACTION_PROJECT_FOLDER_REFRESH, 84 ACTION_FILE_NEW_SOURCE_FILE, 85 //ACTION_PROJECT_FOLDER_OPEN_ITEM, 86 ACTION_PROJECT_BUILD, 87 ACTION_PROJECT_REBUILD, 88 ACTION_PROJECT_CLEAN, 89 ACTION_PROJECT_UPDATE_DEPENDENCIES, 90 ACTION_PROJECT_REVEAL_IN_EXPLORER, 91 ACTION_PROJECT_SETTINGS, 92 //ACTION_PROJECT_FOLDER_REMOVE_ITEM 93 ); 94 95 _folderPopupMenu = new MenuItem(); 96 _folderPopupMenu.add(ACTION_FILE_NEW_SOURCE_FILE, ACTION_PROJECT_FOLDER_REFRESH, ACTION_PROJECT_FOLDER_OPEN_ITEM, 97 //ACTION_PROJECT_FOLDER_REMOVE_ITEM, 98 //ACTION_PROJECT_FOLDER_RENAME_ITEM 99 ); 100 101 _filePopupMenu = new MenuItem(); 102 _filePopupMenu.add(ACTION_FILE_NEW_SOURCE_FILE, ACTION_PROJECT_FOLDER_REFRESH, 103 ACTION_PROJECT_FOLDER_OPEN_ITEM, 104 ACTION_PROJECT_FOLDER_REMOVE_ITEM, 105 //ACTION_PROJECT_FOLDER_RENAME_ITEM 106 ); 107 return _tree; 108 } 109 110 protected MenuItem _workspacePopupMenu; 111 protected MenuItem _projectPopupMenu; 112 protected MenuItem _folderPopupMenu; 113 protected MenuItem _filePopupMenu; 114 protected string _popupMenuSelectedItemId; 115 protected void onPopupMenuItem(MenuItem item) { 116 if (item.action) 117 handleAction(item.action); 118 } 119 120 protected MenuItem onTreeItemPopupMenu(TreeItems source, TreeItem selectedItem) { 121 MenuItem menu = null; 122 _popupMenuSelectedItemId = selectedItem.id; 123 if (selectedItem.intParam == ProjectItemType.SourceFolder) { 124 menu = _folderPopupMenu; 125 } else if (selectedItem.intParam == ProjectItemType.SourceFile) { 126 menu = _filePopupMenu; 127 } else if (selectedItem.intParam == ProjectItemType.Project) { 128 menu = _projectPopupMenu; 129 } else if (selectedItem.intParam == ProjectItemType.Workspace) { 130 menu = _workspacePopupMenu; 131 } 132 if (menu && menu.subitemCount) { 133 for (int i = 0; i < menu.subitemCount; i++) { 134 Action a = menu.subitem(i).action.clone(); 135 a.objectParam = selectedItem.objectParam; 136 menu.subitem(i).action = a; 137 //menu.subitem(i).menuItemAction = &handleAction; 138 } 139 //menu.onMenuItem = &onPopupMenuItem; 140 //menu.menuItemClick = &onPopupMenuItem; 141 menu.menuItemAction = &handleAction; 142 menu.updateActionState(this); 143 return menu; 144 } 145 return null; 146 } 147 148 @property Workspace workspace() { 149 return _workspace; 150 } 151 152 ProjectSourceFile findSourceFileItem(string filename, bool fullFileName=true) { 153 if (_workspace) 154 return _workspace.findSourceFileItem(filename, fullFileName); 155 return null; 156 } 157 158 void addProjectItems(TreeItem root, ProjectItem items) { 159 for (int i = 0; i < items.childCount; i++) { 160 ProjectItem child = items.child(i); 161 if (child.isFolder) { 162 TreeItem p = root.newChild(child.filename, child.name, "folder"); 163 p.intParam = ProjectItemType.SourceFolder; 164 p.objectParam = child; 165 addProjectItems(p, child); 166 } else { 167 string icon = "text-other"; 168 if (child.isDSourceFile) 169 icon = "text-d"; 170 if (child.isJsonFile) 171 icon = "text-json"; 172 if (child.isDMLFile) 173 icon = "text-dml"; 174 TreeItem p = root.newChild(child.filename, child.name, icon); 175 p.intParam = ProjectItemType.SourceFile; 176 p.objectParam = child; 177 } 178 } 179 } 180 181 void updateDefault() { 182 TreeItem defaultItem = null; 183 if (_workspace && _tree.items.childCount && _workspace.startupProject) { 184 for (int i = 0; i < _tree.items.child(0).childCount; i++) { 185 TreeItem p = _tree.items.child(0).child(i); 186 if (p.objectParam is _workspace.startupProject) 187 defaultItem = p; 188 } 189 } 190 _tree.items.setDefaultItem(defaultItem); 191 } 192 193 void reloadItems() { 194 _tree.clearAllItems(); 195 if (_workspace) { 196 TreeItem defaultItem = null; 197 TreeItem root = _tree.items.newChild(_workspace.filename, _workspace.name, "project-development"); 198 root.intParam = ProjectItemType.Workspace; 199 foreach(project; _workspace.projects) { 200 TreeItem p = root.newChild(project.filename, project.name, project.isDependency ? "project-d-dependency" : "project-d"); 201 p.intParam = ProjectItemType.Project; 202 p.objectParam = project; 203 if (project && _workspace.startupProject is project) 204 defaultItem = p; 205 addProjectItems(p, project.items); 206 } 207 _tree.items.setDefaultItem(defaultItem); 208 } else { 209 _tree.items.newChild("none", "No workspace"d, "project-development"); 210 } 211 _tree.onTreeContentChange(null); 212 if (_workspace) { 213 TreeItem root = _tree.items.child(0); 214 for (int i = 0; i < root.childCount; i++) { 215 TreeItem child = root.child(i); 216 if (child.intParam == ProjectItemType.Project) { 217 Object obj = child.objectParam; 218 Project prj = cast(Project)obj; 219 if (prj && prj.isDependency) 220 child.collapse(); 221 } 222 } 223 } 224 updateDefault(); 225 } 226 227 @property void workspace(Workspace w) { 228 _workspace = w; 229 reloadItems(); 230 } 231 232 /// override to handle specific actions 233 override bool handleAction(const Action a) { 234 if (workspaceActionListener.assigned) 235 return workspaceActionListener(a); 236 return false; 237 } 238 }