001/*
002  GRANITE DATA SERVICES
003  Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005  This file is part of Granite Data Services.
006
007  Granite Data Services is free software; you can redistribute it and/or modify
008  it under the terms of the GNU Library General Public License as published by
009  the Free Software Foundation; either version 2 of the License, or (at your
010  option) any later version.
011
012  Granite Data Services is distributed in the hope that it will be useful, but
013  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015  for more details.
016
017  You should have received a copy of the GNU Library General Public License
018  along with this library; if not, see <http://www.gnu.org/licenses/>.
019*/
020
021package org.granite.builder.ui;
022
023import java.util.Arrays;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Map;
028import java.util.Set;
029import java.util.TreeSet;
030
031import org.eclipse.core.resources.IFolder;
032import org.eclipse.core.runtime.CoreException;
033import org.eclipse.core.runtime.IPath;
034import org.eclipse.core.runtime.Path;
035import org.eclipse.swt.SWT;
036import org.eclipse.swt.events.SelectionAdapter;
037import org.eclipse.swt.events.SelectionEvent;
038import org.eclipse.swt.graphics.Rectangle;
039import org.eclipse.swt.layout.FillLayout;
040import org.eclipse.swt.layout.GridData;
041import org.eclipse.swt.layout.GridLayout;
042import org.eclipse.swt.widgets.Button;
043import org.eclipse.swt.widgets.Composite;
044import org.eclipse.swt.widgets.Label;
045import org.eclipse.swt.widgets.Tree;
046import org.eclipse.swt.widgets.TreeItem;
047import org.granite.builder.GraniteBuilderContext;
048import org.granite.builder.properties.Gas3Source;
049import org.granite.builder.properties.GraniteProperties;
050import org.granite.builder.util.ProjectUtil;
051import org.granite.builder.util.SWTUtil;
052
053/**
054 * @author Franck WOLFF
055 */
056public class SourcesPanel extends Composite {
057
058        private static final String INCLUDED = "Included: ";
059        private static final String EXCLUDED = "Excluded: ";
060        private static final String OUTPUT = "Output: ";
061        private static final String ALL = "(All)";
062        private static final String NONE = "(None)";
063        
064        private final GraniteBuilderContext context;
065        private final GraniteProperties properties;
066        
067        private Tree sourcesTree = null;
068        private boolean initialized = false;
069        
070        public SourcesPanel(Composite parent, GraniteBuilderContext context) throws CoreException {
071        super(parent, SWT.NONE);
072        if (parent == null || context == null)
073                throw new NullPointerException("parent and context cannot be null");
074        this.context = context;
075        this.properties = context.getProperties();
076        initializeComponents();
077        }
078        
079        public TreeSet<Gas3Source> getSources() {
080                if (!initialized)
081                        return properties.getGas3().getSources();
082                
083                TreeSet<Gas3Source> sources = new TreeSet<Gas3Source>();
084                for (TreeItem root : sourcesTree.getItems())
085                        sources.add((Gas3Source)root.getData());
086                return sources;
087        }
088
089        @Override
090        public Rectangle getClientArea() {
091                initializeContent();
092                return super.getClientArea();
093        }
094        
095        private void initializeContent() {
096                if (!initialized) {
097                for (Gas3Source source : properties.getGas3().getSources())
098                        addSourceFolderTreeItem(source);
099                        initialized = true;
100                }
101        }
102    
103        private void initializeComponents() {
104        setLayout(new GridLayout(2, false));
105        
106        Label text = new Label(this, SWT.NONE);
107        text.setText("Source folders used for generation:");
108        text.setLayoutData(SWTUtil.newGridData(SWT.NONE, 2));
109        
110        sourcesTree = new Tree(this, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
111        sourcesTree.setLayoutData(new GridData(
112            GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL |
113            GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_VERTICAL
114        ));
115
116                Composite buttons = new Composite(this, SWT.NONE);
117                buttons.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
118                buttons.setLayout(new FillLayout(SWT.VERTICAL));
119                
120                final Button addButton = SWTUtil.newButton(buttons, "Add Folder...", true, new SelectionAdapter() {
121                        @Override
122                        public void widgetSelected(SelectionEvent e) {
123                                addFoldersHandler(e);
124                        }
125                });
126                
127                final Button editButton = SWTUtil.newButton(buttons, "Edit...", false, new SelectionAdapter() {
128                        @Override
129                        public void widgetSelected(SelectionEvent e) {
130                                editFolderAttributesHandler(e);
131                        }
132                });
133                
134                final Button removeButton = SWTUtil.newButton(buttons, "Remove", false, new SelectionAdapter() {
135                        @Override
136                        public void widgetSelected(SelectionEvent e) {
137                                // Remove selected root items.
138                                for (TreeItem item : sourcesTree.getSelection()) {
139                                        if (item.getParentItem() == null)
140                                                item.dispose();
141                                }
142                                // Disable remove button if there is no more root nodes.
143                                if (sourcesTree.getItemCount() == 0)
144                                        ((Button)e.getSource()).setEnabled(false);
145                        }
146                });
147                
148                sourcesTree.addSelectionListener(new SelectionAdapter() {
149                        @Override
150                        public void widgetSelected(SelectionEvent e) {
151                                // Enable/Disable buttons based on selected tree item.
152                                boolean isRoot = (((TreeItem)e.item).getParentItem() == null);
153                                removeButton.setEnabled(isRoot);
154                                addButton.setEnabled(isRoot);
155                                editButton.setEnabled(!isRoot);
156                        }
157                });
158        }
159        
160        private TreeItem addSourceFolderTreeItem(Gas3Source source) {
161                IFolder folder = context.getJavaProject().getProject().getFolder(source.getPath());
162                
163                String displayedPath = folder.getFullPath().makeRelative().toString();
164                String icon = folder.exists() ? SWTUtil.IMG_PKG_FOLDER : SWTUtil.IMG_PKG_FOLDER_ERROR;
165                
166        TreeItem root = SWTUtil.addTreeItem(sourcesTree, icon, displayedPath, null, null);
167        SWTUtil.addTreeItem(root, SWTUtil.IMG_INCLUDES, source.getIncludes(), INCLUDED, ALL);
168        SWTUtil.addTreeItem(root, SWTUtil.IMG_EXCLUDES, source.getExcludes(), EXCLUDED, NONE);
169        SWTUtil.addTreeItem(root, SWTUtil.IMG_OUT_FOLDER, source.getOutput(), OUTPUT, null);
170        root.setData(source);
171        return root;
172        }
173        
174        private void addFoldersHandler(SelectionEvent event) {
175                // Get currently configured source folders.
176                TreeItem[] roots = sourcesTree.getItems();
177        IPath[] usedEntries = new IPath[roots.length];
178        for (int i = 0; i < usedEntries.length; i++)
179                usedEntries[i] = new Path(roots[i].getText());
180                
181        // Run add folders dialog.
182                IPath[] selectedPaths = Dialogs.chooseSourceFolderEntries(
183                        context.getJavaProject(),
184                        getDisplay().getActiveShell(),
185                        null,
186                        usedEntries
187                );
188
189                // Rebuild sorted source folders list.
190                if (selectedPaths != null && selectedPaths.length > 0) {
191                        selectedPaths = ProjectUtil.makeRelative(selectedPaths);
192                        IPath projectPath = context.getJavaProject().getPath().makeRelative();
193                        
194                        Set<IPath> newSourceFolders = new TreeSet<IPath>(ProjectUtil.IPATH_COMPARATOR);
195                        newSourceFolders.addAll(Arrays.asList(usedEntries));
196                        List<IPath> jSourceFolders = ProjectUtil.makeRelative(getSourceFolders());
197                        for (IPath selectedPath : selectedPaths) {
198                                if (selectedPath.equals(projectPath)) {
199                                        newSourceFolders.addAll(jSourceFolders);
200                                        break;
201                                }
202                                for (IPath jSourceFolder : jSourceFolders) {
203                                        if (jSourceFolder.matchingFirstSegments(selectedPath) >= 2)
204                                                newSourceFolders.add(jSourceFolder);
205                                }
206                        }
207                        
208                        Map<IPath, TreeItem> rootMap = new HashMap<IPath, TreeItem>(roots.length);
209                        for (TreeItem root : roots)
210                                rootMap.put(new Path(root.getText()), root);
211                        
212                        String defaultOutput = "as3";
213                        for (IPath newSourceFolder : newSourceFolders) {
214                                TreeItem root = rootMap.get(newSourceFolder);
215                                if (root != null)
216                                        addSourceFolderTreeItem((Gas3Source)root.getData());
217                                else {
218                                        String path = newSourceFolder.removeFirstSegments(1).makeRelative().toString();
219                                        TreeItem item = addSourceFolderTreeItem(new Gas3Source(path, null, null, defaultOutput));
220                                        item.setExpanded(true);
221                                }
222                        }
223                        
224                        for (TreeItem root : roots)
225                                root.dispose();
226                }
227        }
228        
229        private void editFolderAttributesHandler(SelectionEvent event) {
230                TreeItem[] selection = sourcesTree.getSelection();
231                if (selection.length == 1 && selection[0].getParentItem() != null && selection[0].getParentItem().getParentItem() == null) {
232                        Gas3Source source = (Gas3Source)selection[0].getParentItem().getData();
233                        source = Dialogs.editSourceFolderAttributes(context.getJavaProject(), getDisplay().getActiveShell(), source);
234                        SWTUtil.setTreeItemText(selection[0].getParentItem().getItem(0), source.getIncludes());
235                        SWTUtil.setTreeItemText(selection[0].getParentItem().getItem(1), source.getExcludes());
236                        SWTUtil.setTreeItemText(selection[0].getParentItem().getItem(2), source.getOutput());
237                        selection[0].getParentItem().setData(source);
238                }
239        }
240        
241        private List<IPath> getSourceFolders() {
242                try {
243                        return ProjectUtil.getSourceFolders(context.getJavaProject());
244                } catch (CoreException e) {
245                        return Collections.emptyList();
246                }
247        }
248}