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
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org
.eclipse
.egit
.ui
.internal
.repository
;
14 import java
.io
.IOException
;
15 import java
.lang
.reflect
.InvocationTargetException
;
16 import java
.util
.Collection
;
17 import java
.util
.HashSet
;
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
;
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
;
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
) {
91 public void dispose() {
97 private final class LabelProvider
extends BaseLabelProvider
implements
98 ITableLabelProvider
, IColorProvider
{
100 public Image
getColumnImage(Object element
, int columnIndex
) {
104 public String
getColumnText(Object element
, int columnIndex
) {
105 return element
.toString();
108 public Color
getBackground(Object element
) {
112 public Color
getForeground(Object element
) {
113 if (existingRepositoryDirs
.contains(element
))
114 return getShell().getDisplay().getSystemColor(SWT
.COLOR_GRAY
);
123 * @param existingDirs
125 public RepositorySearchDialog(Shell parentShell
,
126 Collection
<String
> existingDirs
) {
128 this.existingRepositoryDirs
.addAll(existingDirs
);
129 setShellStyle(getShellStyle() | SWT
.SHELL_TRIM
);
134 * @return the directories
136 public Set
<String
> getDirectories() {
141 protected void configureShell(Shell newShell
) {
142 super.configureShell(newShell
);
143 newShell
.setText(UIText
.RepositorySearchDialog_searchRepositories
);
147 protected void okPressed() {
148 result
= new HashSet
<String
>();
149 Object
[] checked
= tv
.getCheckedElements();
150 for (Object o
: checked
) {
151 result
.add((String
) o
);
157 protected Control
createDialogArea(Composite parent
) {
159 final IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
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,
180 browse
.setText(UIText
.RepositorySearchDialog_browse
);
181 browse
.addSelectionListener(new SelectionAdapter() {
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
);
193 } catch (BackingStoreException e1
) {
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));
208 .setSelection(prefs
.getBoolean(PREF_DEEP_SEARCH
, false));
210 .setText(UIText
.RepositorySearchDialog_DeepSearch_button
);
212 btnLookForNested
.addSelectionListener(new SelectionAdapter() {
215 public void widgetSelected(SelectionEvent e
) {
216 prefs
.putBoolean(PREF_DEEP_SEARCH
, btnLookForNested
220 } catch (BackingStoreException e1
) {
227 Button search
= new Button(main
, SWT
.PUSH
);
228 search
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, false, false,
230 search
.setText(UIText
.RepositorySearchDialog_search
);
232 tv
= CheckboxTableViewer
.newCheckList(main
, SWT
.BORDER
);
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,
241 .setText(UIText
.RepositorySearchDialog_ToggleSelection_button
);
242 btnToggleSelect
.setEnabled(false);
243 btnToggleSelect
.addSelectionListener(new SelectionAdapter() {
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
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() {
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();
280 prefs
.put(PREF_PATH
, file
.getCanonicalPath());
283 } catch (BackingStoreException e1
) {
286 } catch (IOException e2
) {
290 IRunnableWithProgress action
= new IRunnableWithProgress() {
292 public void run(IProgressMonitor monitor
)
293 throws InvocationTargetException
,
294 InterruptedException
{
297 findGitDirsRecursive(file
, directories
,
298 monitor
, lookForNested
);
299 } catch (Exception ex
) {
300 Activator
.getDefault().getLog().log(
301 new Status(IStatus
.ERROR
, Activator
303 ex
.getMessage(), ex
));
308 ProgressMonitorDialog pd
= new ProgressMonitorDialog(
311 .getProgressMonitor()
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
,
320 } catch (InterruptedException e1
) {
324 boolean foundNew
= false;
326 for (String foundDir
: directories
) {
327 if (!existingRepositoryDirs
.contains(foundDir
)) {
333 btnToggleSelect
.setEnabled(foundNew
);
334 tab
.setEnabled(directories
.size() > 0);
335 tv
.setInput(directories
);
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);
352 private void findGitDirsRecursive(File root
, TreeSet
<String
> strings
,
353 IProgressMonitor monitor
, boolean lookForNestedRepositories
) {
355 if (!root
.exists() || !root
.isDirectory()) {
358 File
[] children
= root
.listFiles();
359 // simply ignore null
360 if (children
== null)
363 for (File child
: children
) {
364 if (monitor
.isCanceled()) {
368 if (child
.isDirectory()
369 && RepositoryCache
.FileKey
.isGitRepository(child
)) {
371 strings
.add(child
.getCanonicalPath());
372 } catch (IOException e
) {
378 UIText
.RepositorySearchDialog_RepositoriesFound_message
,
379 new Integer(strings
.size())));
380 if (!lookForNestedRepositories
)
382 } else if (child
.isDirectory()) {
383 monitor
.subTask(child
.getPath());
384 findGitDirsRecursive(child
, strings
, monitor
,
385 lookForNestedRepositories
);