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 }