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
.MessageDialog
;
32 import org
.eclipse
.jface
.dialogs
.ProgressMonitorDialog
;
33 import org
.eclipse
.jface
.layout
.GridDataFactory
;
34 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
35 import org
.eclipse
.jface
.viewers
.BaseLabelProvider
;
36 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
37 import org
.eclipse
.jface
.viewers
.CheckboxTableViewer
;
38 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
39 import org
.eclipse
.jface
.viewers
.IColorProvider
;
40 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
41 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
42 import org
.eclipse
.jface
.viewers
.Viewer
;
43 import org
.eclipse
.jgit
.lib
.RepositoryCache
;
44 import org
.eclipse
.osgi
.util
.NLS
;
45 import org
.eclipse
.swt
.SWT
;
46 import org
.eclipse
.swt
.events
.SelectionAdapter
;
47 import org
.eclipse
.swt
.events
.SelectionEvent
;
48 import org
.eclipse
.swt
.graphics
.Color
;
49 import org
.eclipse
.swt
.graphics
.Image
;
50 import org
.eclipse
.swt
.layout
.GridData
;
51 import org
.eclipse
.swt
.layout
.GridLayout
;
52 import org
.eclipse
.swt
.widgets
.Button
;
53 import org
.eclipse
.swt
.widgets
.Composite
;
54 import org
.eclipse
.swt
.widgets
.Control
;
55 import org
.eclipse
.swt
.widgets
.DirectoryDialog
;
56 import org
.eclipse
.swt
.widgets
.Label
;
57 import org
.eclipse
.swt
.widgets
.Shell
;
58 import org
.eclipse
.swt
.widgets
.Table
;
59 import org
.eclipse
.swt
.widgets
.Text
;
60 import org
.osgi
.service
.prefs
.BackingStoreException
;
63 * Searches for Git directories under a path that can be selected by the user
65 public class RepositorySearchDialog
extends Dialog
{
67 private static final String PREF_DEEP_SEARCH
= "RepositorySearchDialogDeepSearch"; //$NON-NLS-1$
69 private static final String PREF_PATH
= "RepositorySearchDialogSearchPath"; //$NON-NLS-1$
71 private final Set
<String
> existingRepositoryDirs
= new HashSet
<String
>();
73 private Set
<String
> result
;
75 CheckboxTableViewer tv
;
77 private Button btnToggleSelect
;
81 private final class ContentProvider
implements IStructuredContentProvider
{
83 @SuppressWarnings("unchecked")
84 public Object
[] getElements(Object inputElement
) {
85 return ((Set
<String
>) inputElement
).toArray();
88 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
92 public void dispose() {
98 private final class LabelProvider
extends BaseLabelProvider
implements
99 ITableLabelProvider
, IColorProvider
{
101 public Image
getColumnImage(Object element
, int columnIndex
) {
105 public String
getColumnText(Object element
, int columnIndex
) {
106 return element
.toString();
109 public Color
getBackground(Object element
) {
113 public Color
getForeground(Object element
) {
114 if (existingRepositoryDirs
.contains(element
))
115 return getShell().getDisplay().getSystemColor(SWT
.COLOR_GRAY
);
124 * @param existingDirs
126 protected RepositorySearchDialog(Shell parentShell
,
127 Collection
<String
> existingDirs
) {
129 this.existingRepositoryDirs
.addAll(existingDirs
);
130 setShellStyle(getShellStyle() | SWT
.SHELL_TRIM
);
135 * @return the directories
137 public Set
<String
> getDirectories() {
142 protected void configureShell(Shell newShell
) {
143 super.configureShell(newShell
);
145 .setText(UIText
.RepositorySearchDialog_SearchRepositoriesHeader
);
149 protected void okPressed() {
150 result
= new HashSet
<String
>();
151 Object
[] checked
= tv
.getCheckedElements();
152 for (Object o
: checked
) {
153 result
.add((String
) o
);
159 protected Control
createDialogArea(Composite parent
) {
161 final IEclipsePreferences prefs
= new InstanceScope().getNode(Activator
164 Composite main
= new Composite(parent
, SWT
.NONE
);
165 main
.setLayout(new GridLayout(4, false));
166 main
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
168 Label dirLabel
= new Label(main
, SWT
.NONE
);
169 dirLabel
.setText(UIText
.RepositorySearchDialog_DirectoryLabel
);
170 final Text dir
= new Text(main
, SWT
.BORDER
);
171 GridDataFactory
.fillDefaults().align(SWT
.FILL
, SWT
.CENTER
).grab(true, false).span(2, 1).hint(300,
172 SWT
.DEFAULT
).applyTo(dir
);
174 String initialPath
= prefs
.get(PREF_PATH
, ResourcesPlugin
175 .getWorkspace().getRoot().getLocation().toOSString());
177 dir
.setText(initialPath
);
179 Button browse
= new Button(main
, SWT
.PUSH
);
180 browse
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, false, false,
182 browse
.setText(UIText
.RepositorySearchDialog_BrowseButton
);
183 browse
.addSelectionListener(new SelectionAdapter() {
186 public void widgetSelected(SelectionEvent e
) {
187 DirectoryDialog dd
= new DirectoryDialog(getShell());
188 dd
.setFilterPath(dir
.getText());
189 String directory
= dd
.open();
190 if (directory
!= null) {
191 dir
.setText(directory
);
192 prefs
.put(PREF_PATH
, directory
);
195 } catch (BackingStoreException e1
) {
203 // we fill the room under the "Directory" label
204 new Label(main
, SWT
.NONE
);
206 final Button btnLookForNested
= new Button(main
, SWT
.CHECK
);
207 btnLookForNested
.setLayoutData(new GridData(SWT
.LEFT
, SWT
.CENTER
,
208 false, false, 2, 1));
210 .setSelection(prefs
.getBoolean(PREF_DEEP_SEARCH
, false));
212 .setText(UIText
.RepositorySearchDialog_DeepSearch_button
);
214 btnLookForNested
.addSelectionListener(new SelectionAdapter() {
217 public void widgetSelected(SelectionEvent e
) {
218 prefs
.putBoolean(PREF_DEEP_SEARCH
, btnLookForNested
222 } catch (BackingStoreException e1
) {
229 Button search
= new Button(main
, SWT
.PUSH
);
230 search
.setLayoutData(new GridData(SWT
.FILL
, SWT
.CENTER
, false, false,
232 search
.setText(UIText
.RepositorySearchDialog_SearchButton
);
234 tv
= CheckboxTableViewer
.newCheckList(main
, SWT
.BORDER
);
236 tab
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, true, 3, 1));
237 tab
.setEnabled(false);
239 btnToggleSelect
= new Button(main
, SWT
.NONE
);
240 btnToggleSelect
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, false,
243 .setText(UIText
.RepositorySearchDialog_ToggleSelection_button
);
244 btnToggleSelect
.setEnabled(false);
245 btnToggleSelect
.addSelectionListener(new SelectionAdapter() {
248 public void widgetSelected(SelectionEvent e
) {
250 for (int i
= 0; i
< tab
.getItemCount(); i
++) {
251 if (!existingRepositoryDirs
.contains(tv
.getElementAt(i
)))
252 tv
.setChecked(tv
.getElementAt(i
), !tv
.getChecked(tv
255 getButton(IDialogConstants
.OK_ID
).setEnabled(
256 tv
.getCheckedElements().length
> 0);
260 tv
.addCheckStateListener(new ICheckStateListener() {
262 public void checkStateChanged(CheckStateChangedEvent event
) {
263 if (existingRepositoryDirs
.contains(event
.getElement()))
264 event
.getCheckable().setChecked(event
.getElement(), false);
265 getButton(IDialogConstants
.OK_ID
).setEnabled(
266 tv
.getCheckedElements().length
> 0);
270 tv
.setContentProvider(new ContentProvider());
271 tv
.setLabelProvider(new LabelProvider());
273 search
.addSelectionListener(new SelectionAdapter() {
276 public void widgetSelected(SelectionEvent e
) {
277 final TreeSet
<String
> directories
= new TreeSet
<String
>();
278 final File file
= new File(dir
.getText());
279 final boolean lookForNested
= btnLookForNested
.getSelection();
282 prefs
.put(PREF_PATH
, file
.getCanonicalPath());
285 } catch (BackingStoreException e1
) {
288 } catch (IOException e2
) {
292 IRunnableWithProgress action
= new IRunnableWithProgress() {
294 public void run(IProgressMonitor monitor
)
295 throws InvocationTargetException
,
296 InterruptedException
{
299 findGitDirsRecursive(file
, directories
,
300 monitor
, lookForNested
);
301 } catch (Exception ex
) {
302 Activator
.getDefault().getLog().log(
303 new Status(IStatus
.ERROR
, Activator
305 ex
.getMessage(), ex
));
310 ProgressMonitorDialog pd
= new ProgressMonitorDialog(
313 .getProgressMonitor()
315 UIText
.RepositorySearchDialog_ScanningForRepositories_message
);
316 pd
.run(true, true, action
);
318 } catch (InvocationTargetException e1
) {
319 MessageDialog
.openError(getShell(),
320 UIText
.RepositorySearchDialog_ErrorHeader
, e1
321 .getCause().getMessage());
322 } catch (InterruptedException e1
) {
326 boolean foundNew
= false;
328 for (String foundDir
: directories
) {
329 if (!existingRepositoryDirs
.contains(foundDir
)) {
335 btnToggleSelect
.setEnabled(foundNew
);
336 tab
.setEnabled(directories
.size() > 0);
337 tv
.setInput(directories
);
347 protected Control
createButtonBar(Composite parent
) {
348 // disable the OK button until the user selects something
349 Control bar
= super.createButtonBar(parent
);
350 getButton(IDialogConstants
.OK_ID
).setEnabled(false);
354 private void findGitDirsRecursive(File root
, TreeSet
<String
> strings
,
355 IProgressMonitor monitor
, boolean lookForNestedRepositories
) {
357 if (!root
.exists() || !root
.isDirectory()) {
360 File
[] children
= root
.listFiles();
361 // simply ignore null
362 if (children
== null)
365 for (File child
: children
) {
366 if (monitor
.isCanceled()) {
370 if (child
.isDirectory()
371 && RepositoryCache
.FileKey
.isGitRepository(child
)) {
373 strings
.add(child
.getCanonicalPath());
374 } catch (IOException e
) {
380 UIText
.RepositorySearchDialog_RepositoriesFound_message
,
381 new Integer(strings
.size())));
382 if (!lookForNestedRepositories
)
384 } else if (child
.isDirectory()) {
385 monitor
.subTask(child
.getPath());
386 findGitDirsRecursive(child
, strings
, monitor
,
387 lookForNestedRepositories
);