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_SETTINGS, 91 //ACTION_PROJECT_FOLDER_REMOVE_ITEM 92 ); 93 94 _folderPopupMenu = new MenuItem(); 95 _folderPopupMenu.add(ACTION_FILE_NEW_SOURCE_FILE, ACTION_PROJECT_FOLDER_REFRESH, ACTION_PROJECT_FOLDER_OPEN_ITEM, 96 //ACTION_PROJECT_FOLDER_REMOVE_ITEM, 97 //ACTION_PROJECT_FOLDER_RENAME_ITEM 98 ); 99 100 _filePopupMenu = new MenuItem(); 101 _filePopupMenu.add(ACTION_FILE_NEW_SOURCE_FILE, ACTION_PROJECT_FOLDER_REFRESH, 102 ACTION_PROJECT_FOLDER_OPEN_ITEM, 103 ACTION_PROJECT_FOLDER_REMOVE_ITEM, 104 //ACTION_PROJECT_FOLDER_RENAME_ITEM 105 ); 106 return _tree; 107 } 108 109 protected MenuItem _workspacePopupMenu; 110 protected MenuItem _projectPopupMenu; 111 protected MenuItem _folderPopupMenu; 112 protected MenuItem _filePopupMenu; 113 protected string _popupMenuSelectedItemId; 114 protected void onPopupMenuItem(MenuItem item) { 115 if (item.action) 116 handleAction(item.action); 117 } 118 119 protected MenuItem onTreeItemPopupMenu(TreeItems source, TreeItem selectedItem) { 120 MenuItem menu = null; 121 _popupMenuSelectedItemId = selectedItem.id; 122 if (selectedItem.intParam == ProjectItemType.SourceFolder) { 123 menu = _folderPopupMenu; 124 } else if (selectedItem.intParam == ProjectItemType.SourceFile) { 125 menu = _filePopupMenu; 126 } else if (selectedItem.intParam == ProjectItemType.Project) { 127 menu = _projectPopupMenu; 128 } else if (selectedItem.intParam == ProjectItemType.Workspace) { 129 menu = _workspacePopupMenu; 130 } 131 if (menu && menu.subitemCount) { 132 for (int i = 0; i < menu.subitemCount; i++) { 133 Action a = menu.subitem(i).action.clone(); 134 a.objectParam = selectedItem.objectParam; 135 menu.subitem(i).action = a; 136 //menu.subitem(i).menuItemAction = &handleAction; 137 } 138 //menu.onMenuItem = &onPopupMenuItem; 139 //menu.menuItemClick = &onPopupMenuItem; 140 menu.menuItemAction = &handleAction; 141 menu.updateActionState(this); 142 return menu; 143 } 144 return null; 145 } 146 147 @property Workspace workspace() { 148 return _workspace; 149 } 150 151 ProjectSourceFile findSourceFileItem(string filename, bool fullFileName=true) { 152 if (_workspace) 153 return _workspace.findSourceFileItem(filename, fullFileName); 154 return null; 155 } 156 157 void addProjectItems(TreeItem root, ProjectItem items) { 158 for (int i = 0; i < items.childCount; i++) { 159 ProjectItem child = items.child(i); 160 if (child.isFolder) { 161 TreeItem p = root.newChild(child.filename, child.name, "folder"); 162 p.intParam = ProjectItemType.SourceFolder; 163 p.objectParam = child; 164 addProjectItems(p, child); 165 } else { 166 TreeItem p = root.newChild(child.filename, child.name, "text-d"); 167 p.intParam = ProjectItemType.SourceFile; 168 p.objectParam = child; 169 } 170 } 171 } 172 173 void reloadItems() { 174 _tree.clearAllItems(); 175 if (_workspace) { 176 TreeItem root = _tree.items.newChild(_workspace.filename, _workspace.name, "project-development"); 177 root.intParam = ProjectItemType.Workspace; 178 foreach(project; _workspace.projects) { 179 TreeItem p = root.newChild(project.filename, project.name, project.isDependency ? "project-d-dependency" : "project-d"); 180 p.intParam = ProjectItemType.Project; 181 p.objectParam = project; 182 addProjectItems(p, project.items); 183 } 184 } else { 185 _tree.items.newChild("none", "No workspace"d, "project-development"); 186 } 187 _tree.onTreeContentChange(null); 188 if (_workspace) { 189 TreeItem root = _tree.items.child(0); 190 for (int i = 0; i < root.childCount; i++) { 191 TreeItem child = root.child(i); 192 if (child.intParam == ProjectItemType.Project) { 193 Object obj = child.objectParam; 194 Project prj = cast(Project)obj; 195 if (prj && prj.isDependency) 196 child.collapse(); 197 } 198 } 199 } 200 } 201 202 @property void workspace(Workspace w) { 203 _workspace = w; 204 reloadItems(); 205 } 206 207 /// override to handle specific actions 208 override bool handleAction(const Action a) { 209 if (workspaceActionListener.assigned) 210 return workspaceActionListener(a); 211 return false; 212 } 213 }