Git Import Wizard
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / repository / RepositorySearchDialog.java
blob40dd43133e760f5d1c9cd7b1149d72484d542135
1 /*******************************************************************************
2 * Copyright (c) 2010 SAP AG.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors:
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.repository;
13 import java.io.File;
14 import java.io.IOException;
15 import java.lang.reflect.InvocationTargetException;
16 import java.util.Collection;
17 import java.util.HashSet;
18 import java.util.Set;
19 import java.util.TreeSet;
21 import org.eclipse.core.resources.ResourcesPlugin;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.IStatus;
24 import org.eclipse.core.runtime.Status;
25 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
26 import org.eclipse.core.runtime.preferences.InstanceScope;
27 import org.eclipse.egit.core.Activator;
28 import org.eclipse.egit.ui.UIText;
29 import org.eclipse.jface.dialogs.Dialog;
30 import org.eclipse.jface.dialogs.IDialogConstants;
31 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
32 import org.eclipse.jface.layout.GridDataFactory;
33 import org.eclipse.jface.operation.IRunnableWithProgress;
34 import org.eclipse.jface.viewers.BaseLabelProvider;
35 import org.eclipse.jface.viewers.CheckStateChangedEvent;
36 import org.eclipse.jface.viewers.CheckboxTableViewer;
37 import org.eclipse.jface.viewers.ICheckStateListener;
38 import org.eclipse.jface.viewers.IColorProvider;
39 import org.eclipse.jface.viewers.IStructuredContentProvider;
40 import org.eclipse.jface.viewers.ITableLabelProvider;
41 import org.eclipse.jface.viewers.Viewer;
42 import org.eclipse.jgit.lib.RepositoryCache;
43 import org.eclipse.osgi.util.NLS;
44 import org.eclipse.swt.SWT;
45 import org.eclipse.swt.events.SelectionAdapter;
46 import org.eclipse.swt.events.SelectionEvent;
47 import org.eclipse.swt.graphics.Color;
48 import org.eclipse.swt.graphics.Image;
49 import org.eclipse.swt.layout.GridData;
50 import org.eclipse.swt.layout.GridLayout;
51 import org.eclipse.swt.widgets.Button;
52 import org.eclipse.swt.widgets.Composite;
53 import org.eclipse.swt.widgets.Control;
54 import org.eclipse.swt.widgets.DirectoryDialog;
55 import org.eclipse.swt.widgets.Label;
56 import org.eclipse.swt.widgets.Shell;
57 import org.eclipse.swt.widgets.Table;
58 import org.eclipse.swt.widgets.Text;
59 import org.osgi.service.prefs.BackingStoreException;
61 /**
62 * Searches for Git directories under a path that can be selected by the user
64 public class RepositorySearchDialog extends Dialog {
66 private static final String PREF_DEEP_SEARCH = "RepositorySearchDialogDeepSearch"; //$NON-NLS-1$
68 private static final String PREF_PATH = "RepositorySearchDialogSearchPath"; //$NON-NLS-1$
70 private final Set<String> existingRepositoryDirs = new HashSet<String>();
72 private Set<String> result;
74 CheckboxTableViewer tv;
76 private Button btnToggleSelect;
78 private Table tab;
80 private final class ContentProvider implements IStructuredContentProvider {
82 @SuppressWarnings("unchecked")
83 public Object[] getElements(Object inputElement) {
84 return ((Set<String>) inputElement).toArray();
87 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
88 // nothing
91 public void dispose() {
92 // nothing
97 private final class LabelProvider extends BaseLabelProvider implements
98 ITableLabelProvider, IColorProvider {
100 public Image getColumnImage(Object element, int columnIndex) {
101 return null;
104 public String getColumnText(Object element, int columnIndex) {
105 return element.toString();
108 public Color getBackground(Object element) {
109 return null;
112 public Color getForeground(Object element) {
113 if (existingRepositoryDirs.contains(element))
114 return getShell().getDisplay().getSystemColor(SWT.COLOR_GRAY);
116 return null;
122 * @param parentShell
123 * @param existingDirs
125 public RepositorySearchDialog(Shell parentShell,
126 Collection<String> existingDirs) {
127 super(parentShell);
128 this.existingRepositoryDirs.addAll(existingDirs);
129 setShellStyle(getShellStyle() | SWT.SHELL_TRIM);
134 * @return the directories
136 public Set<String> getDirectories() {
137 return result;
140 @Override
141 protected void configureShell(Shell newShell) {
142 super.configureShell(newShell);
143 newShell.setText(UIText.RepositorySearchDialog_searchRepositories);
146 @Override
147 protected void okPressed() {
148 result = new HashSet<String>();
149 Object[] checked = tv.getCheckedElements();
150 for (Object o : checked) {
151 result.add((String) o);
153 super.okPressed();
156 @Override
157 protected Control createDialogArea(Composite parent) {
159 final IEclipsePreferences prefs = new InstanceScope().getNode(Activator
160 .getPluginId());
162 Composite main = new Composite(parent, SWT.NONE);
163 main.setLayout(new GridLayout(4, false));
164 main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
166 Label dirLabel = new Label(main, SWT.NONE);
167 dirLabel.setText(UIText.RepositorySearchDialog_directory);
168 final Text dir = new Text(main, SWT.BORDER);
169 GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).grab(true, false).span(2, 1).hint(300,
170 SWT.DEFAULT).applyTo(dir);
172 String initialPath = prefs.get(PREF_PATH, ResourcesPlugin
173 .getWorkspace().getRoot().getLocation().toOSString());
175 dir.setText(initialPath);
177 Button browse = new Button(main, SWT.PUSH);
178 browse.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false,
179 1, 1));
180 browse.setText(UIText.RepositorySearchDialog_browse);
181 browse.addSelectionListener(new SelectionAdapter() {
183 @Override
184 public void widgetSelected(SelectionEvent e) {
185 DirectoryDialog dd = new DirectoryDialog(getShell());
186 dd.setFilterPath(dir.getText());
187 String directory = dd.open();
188 if (directory != null) {
189 dir.setText(directory);
190 prefs.put(PREF_PATH, directory);
191 try {
192 prefs.flush();
193 } catch (BackingStoreException e1) {
194 // ignore here
201 // we fill the room under the "Directory" label
202 new Label(main, SWT.NONE);
204 final Button btnLookForNested = new Button(main, SWT.CHECK);
205 btnLookForNested.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
206 false, false, 2, 1));
207 btnLookForNested
208 .setSelection(prefs.getBoolean(PREF_DEEP_SEARCH, false));
209 btnLookForNested
210 .setText(UIText.RepositorySearchDialog_DeepSearch_button);
212 btnLookForNested.addSelectionListener(new SelectionAdapter() {
214 @Override
215 public void widgetSelected(SelectionEvent e) {
216 prefs.putBoolean(PREF_DEEP_SEARCH, btnLookForNested
217 .getSelection());
218 try {
219 prefs.flush();
220 } catch (BackingStoreException e1) {
221 // ignore
227 Button search = new Button(main, SWT.PUSH);
228 search.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false,
229 1, 1));
230 search.setText(UIText.RepositorySearchDialog_search);
232 tv = CheckboxTableViewer.newCheckList(main, SWT.BORDER);
233 tab = tv.getTable();
234 tab.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
235 tab.setEnabled(false);
237 btnToggleSelect = new Button(main, SWT.NONE);
238 btnToggleSelect.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false,
239 false, 1, 1));
240 btnToggleSelect
241 .setText(UIText.RepositorySearchDialog_ToggleSelection_button);
242 btnToggleSelect.setEnabled(false);
243 btnToggleSelect.addSelectionListener(new SelectionAdapter() {
245 @Override
246 public void widgetSelected(SelectionEvent e) {
248 for (int i = 0; i < tab.getItemCount(); i++) {
249 if (!existingRepositoryDirs.contains(tv.getElementAt(i)))
250 tv.setChecked(tv.getElementAt(i), !tv.getChecked(tv
251 .getElementAt(i)));
253 getButton(IDialogConstants.OK_ID).setEnabled(
254 tv.getCheckedElements().length > 0);
258 tv.addCheckStateListener(new ICheckStateListener() {
260 public void checkStateChanged(CheckStateChangedEvent event) {
261 if (existingRepositoryDirs.contains(event.getElement()))
262 event.getCheckable().setChecked(event.getElement(), false);
263 getButton(IDialogConstants.OK_ID).setEnabled(
264 tv.getCheckedElements().length > 0);
268 tv.setContentProvider(new ContentProvider());
269 tv.setLabelProvider(new LabelProvider());
271 search.addSelectionListener(new SelectionAdapter() {
273 @Override
274 public void widgetSelected(SelectionEvent e) {
275 final TreeSet<String> directories = new TreeSet<String>();
276 final File file = new File(dir.getText());
277 final boolean lookForNested = btnLookForNested.getSelection();
278 if (file.exists()) {
279 try {
280 prefs.put(PREF_PATH, file.getCanonicalPath());
281 try {
282 prefs.flush();
283 } catch (BackingStoreException e1) {
284 // ignore here
286 } catch (IOException e2) {
287 // ignore
290 IRunnableWithProgress action = new IRunnableWithProgress() {
292 public void run(IProgressMonitor monitor)
293 throws InvocationTargetException,
294 InterruptedException {
296 try {
297 findGitDirsRecursive(file, directories,
298 monitor, lookForNested);
299 } catch (Exception ex) {
300 Activator.getDefault().getLog().log(
301 new Status(IStatus.ERROR, Activator
302 .getPluginId(),
303 ex.getMessage(), ex));
307 try {
308 ProgressMonitorDialog pd = new ProgressMonitorDialog(
309 getShell());
311 .getProgressMonitor()
312 .setTaskName(
313 UIText.RepositorySearchDialog_ScanningForRepositories_message);
314 pd.run(true, true, action);
316 } catch (InvocationTargetException e1) {
317 org.eclipse.egit.ui.Activator.handleError(
318 UIText.RepositorySearchDialog_errorOccurred,
319 e1, true);
320 } catch (InterruptedException e1) {
321 // ignore
324 boolean foundNew = false;
326 for (String foundDir : directories) {
327 if (!existingRepositoryDirs.contains(foundDir)) {
328 foundNew = true;
329 break;
333 btnToggleSelect.setEnabled(foundNew);
334 tab.setEnabled(directories.size() > 0);
335 tv.setInput(directories);
341 return main;
344 @Override
345 protected Control createButtonBar(Composite parent) {
346 // disable the OK button until the user selects something
347 Control bar = super.createButtonBar(parent);
348 getButton(IDialogConstants.OK_ID).setEnabled(false);
349 return bar;
352 private void findGitDirsRecursive(File root, TreeSet<String> strings,
353 IProgressMonitor monitor, boolean lookForNestedRepositories) {
355 if (!root.exists() || !root.isDirectory()) {
356 return;
358 File[] children = root.listFiles();
359 // simply ignore null
360 if (children == null)
361 return;
363 for (File child : children) {
364 if (monitor.isCanceled()) {
365 return;
368 if (child.isDirectory()
369 && RepositoryCache.FileKey.isGitRepository(child)) {
370 try {
371 strings.add(child.getCanonicalPath());
372 } catch (IOException e) {
373 // ignore here
375 monitor
376 .setTaskName(NLS
377 .bind(
378 UIText.RepositorySearchDialog_RepositoriesFound_message,
379 new Integer(strings.size())));
380 if (!lookForNestedRepositories)
381 return;
382 } else if (child.isDirectory()) {
383 monitor.subTask(child.getPath());
384 findGitDirsRecursive(child, strings, monitor,
385 lookForNestedRepositories);