1 /*******************************************************************************
2 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
5 * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
6 * Copyright (c) 2010, Benjamin Muskalla <bmuskalla@eclipsesource.com>
7 * Copyright (c) 2012, IBM Corporation
9 * All rights reserved. This program and the accompanying materials
10 * are made available under the terms of the Eclipse Public License 2.0
11 * which accompanies this distribution, and is available at
12 * https://www.eclipse.org/legal/epl-2.0/
14 * SPDX-License-Identifier: EPL-2.0
15 *******************************************************************************/
16 package org
.eclipse
.egit
.ui
.internal
.clone
;
18 import java
.lang
.reflect
.InvocationTargetException
;
19 import java
.util
.ArrayList
;
20 import java
.util
.Arrays
;
21 import java
.util
.Collections
;
22 import java
.util
.List
;
24 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
25 import org
.eclipse
.core
.runtime
.jobs
.IJobChangeEvent
;
26 import org
.eclipse
.core
.runtime
.jobs
.JobChangeAdapter
;
27 import org
.eclipse
.egit
.core
.credentials
.UserPasswordCredentials
;
28 import org
.eclipse
.egit
.core
.internal
.credentials
.EGitCredentialsProvider
;
29 import org
.eclipse
.egit
.core
.op
.ListRemoteOperation
;
30 import org
.eclipse
.egit
.core
.settings
.GitSettings
;
31 import org
.eclipse
.egit
.ui
.Activator
;
32 import org
.eclipse
.egit
.ui
.UIPreferences
;
33 import org
.eclipse
.egit
.ui
.UIUtils
;
34 import org
.eclipse
.egit
.ui
.internal
.CommonUtils
;
35 import org
.eclipse
.egit
.ui
.internal
.UIIcons
;
36 import org
.eclipse
.egit
.ui
.internal
.UIText
;
37 import org
.eclipse
.egit
.ui
.internal
.components
.CachedCheckboxTreeViewer
;
38 import org
.eclipse
.egit
.ui
.internal
.components
.FilteredCheckboxTree
;
39 import org
.eclipse
.egit
.ui
.internal
.components
.RepositorySelection
;
40 import org
.eclipse
.egit
.ui
.internal
.dialogs
.SourceBranchFailureDialog
;
41 import org
.eclipse
.egit
.ui
.internal
.repository
.tree
.RepositoryTreeNodeType
;
42 import org
.eclipse
.jface
.dialogs
.Dialog
;
43 import org
.eclipse
.jface
.dialogs
.IMessageProvider
;
44 import org
.eclipse
.jface
.operation
.IRunnableWithProgress
;
45 import org
.eclipse
.jface
.viewers
.CheckStateChangedEvent
;
46 import org
.eclipse
.jface
.viewers
.ICheckStateListener
;
47 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
48 import org
.eclipse
.jface
.viewers
.LabelProvider
;
49 import org
.eclipse
.jface
.viewers
.Viewer
;
50 import org
.eclipse
.jface
.wizard
.WizardPage
;
51 import org
.eclipse
.jgit
.annotations
.NonNull
;
52 import org
.eclipse
.jgit
.api
.errors
.TransportException
;
53 import org
.eclipse
.jgit
.lib
.Constants
;
54 import org
.eclipse
.jgit
.lib
.ObjectId
;
55 import org
.eclipse
.jgit
.lib
.Ref
;
56 import org
.eclipse
.jgit
.transport
.TagOpt
;
57 import org
.eclipse
.jgit
.transport
.URIish
;
58 import org
.eclipse
.osgi
.util
.NLS
;
59 import org
.eclipse
.swt
.SWT
;
60 import org
.eclipse
.swt
.events
.SelectionAdapter
;
61 import org
.eclipse
.swt
.events
.SelectionEvent
;
62 import org
.eclipse
.swt
.graphics
.Image
;
63 import org
.eclipse
.swt
.layout
.GridData
;
64 import org
.eclipse
.swt
.layout
.GridLayout
;
65 import org
.eclipse
.swt
.layout
.RowLayout
;
66 import org
.eclipse
.swt
.widgets
.Button
;
67 import org
.eclipse
.swt
.widgets
.Composite
;
68 import org
.eclipse
.swt
.widgets
.Group
;
69 import org
.eclipse
.swt
.widgets
.Label
;
70 import org
.eclipse
.ui
.PlatformUI
;
71 import org
.eclipse
.ui
.dialogs
.PatternFilter
;
72 import org
.eclipse
.ui
.progress
.WorkbenchJob
;
74 class SourceBranchPage
extends WizardPage
{
76 private RepositorySelection validatedRepoSelection
;
80 private final List
<Ref
> availableRefs
= new ArrayList
<>();
84 private String transportError
;
86 private Button selectB
;
88 private Button unselectB
;
90 private TagOpt tagOption
= TagOpt
.AUTO_FOLLOW
;
92 private CachedCheckboxTreeViewer refsViewer
;
94 private UserPasswordCredentials credentials
;
96 private String helpContext
= null;
99 super(SourceBranchPage
.class.getName());
100 setTitle(UIText
.SourceBranchPage_title
);
101 setDescription(UIText
.SourceBranchPage_description
);
104 List
<Ref
> getSelectedBranches() {
105 Object
[] checkedElements
= refsViewer
.getCheckedElements();
106 Ref
[] checkedRefs
= new Ref
[checkedElements
.length
];
107 System
.arraycopy(checkedElements
, 0, checkedRefs
, 0, checkedElements
.length
);
108 return Arrays
.asList(checkedRefs
);
111 TagOpt
getTagOption() {
115 List
<Ref
> getAvailableBranches() {
116 return availableRefs
;
123 boolean isSourceRepoEmpty() {
124 return availableRefs
.isEmpty();
127 boolean isAllSelected() {
128 return availableRefs
.size() == refsViewer
.getCheckedElements().length
;
132 public void createControl(final Composite parent
) {
133 final Composite panel
= new Composite(parent
, SWT
.NULL
);
134 final GridLayout layout
= new GridLayout();
135 layout
.numColumns
= 1;
136 panel
.setLayout(layout
);
138 label
= new Label(panel
, SWT
.NONE
);
139 label
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
141 FilteredCheckboxTree fTree
= new FilteredCheckboxTree(panel
, null,
142 SWT
.NONE
, new PatternFilter()) {
144 * Overridden to check page when refreshing is done.
147 protected WorkbenchJob
doCreateRefreshJob() {
148 WorkbenchJob refreshJob
= super.doCreateRefreshJob();
149 refreshJob
.addJobChangeListener(new JobChangeAdapter() {
151 public void done(IJobChangeEvent event
) {
152 if (event
.getResult().isOK()) {
153 getDisplay().asyncExec(new Runnable() {
165 UIUtils
.associateLabel(fTree
.getFilterControl(), label
);
166 refsViewer
= fTree
.getCheckboxTreeViewer();
168 ITreeContentProvider provider
= new ITreeContentProvider() {
171 public void inputChanged(Viewer arg0
, Object arg1
, Object arg2
) {
176 public void dispose() {
181 public Object
[] getElements(Object input
) {
182 return ((List
) input
).toArray();
186 public boolean hasChildren(Object element
) {
191 public Object
getParent(Object element
) {
196 public Object
[] getChildren(Object parentElement
) {
200 refsViewer
.setContentProvider(provider
);
201 refsViewer
.setLabelProvider(new LabelProvider() {
203 public String
getText(Object element
) {
204 if (((Ref
)element
).getName().startsWith(Constants
.R_HEADS
))
205 return ((Ref
)element
).getName().substring(Constants
.R_HEADS
.length());
206 return ((Ref
)element
).getName();
210 public Image
getImage(Object element
) {
211 return UIIcons
.getImage(
212 Activator
.getDefault().getResourceManager(),
213 RepositoryTreeNodeType
.REF
.getIcon());
217 refsViewer
.addCheckStateListener(new ICheckStateListener() {
219 public void checkStateChanged(CheckStateChangedEvent event
) {
223 final Composite bPanel
= new Composite(panel
, SWT
.NONE
);
224 bPanel
.setLayout(new RowLayout());
225 selectB
= new Button(bPanel
, SWT
.PUSH
);
226 selectB
.setText(UIText
.SourceBranchPage_selectAll
);
227 selectB
.addSelectionListener(new SelectionAdapter() {
229 public void widgetSelected(final SelectionEvent e
) {
230 refsViewer
.setAllChecked(true);
234 unselectB
= new Button(bPanel
, SWT
.PUSH
);
235 unselectB
.setText(UIText
.SourceBranchPage_selectNone
);
236 unselectB
.addSelectionListener(new SelectionAdapter() {
238 public void widgetSelected(final SelectionEvent e
) {
239 refsViewer
.setAllChecked(false);
243 createTagOptionGroup(panel
);
244 bPanel
.setLayoutData(new GridData(SWT
.FILL
, SWT
.TOP
, true, false));
246 Dialog
.applyDialogFont(panel
);
251 private void createTagOptionGroup(Composite parent
) {
252 final Group tagsGroup
= new Group(parent
, SWT
.NULL
);
253 tagsGroup
.setLayoutData(new GridData(SWT
.FILL
, SWT
.FILL
, true, false));
254 tagsGroup
.setText(UIText
.TagOptions_groupName
);
255 tagsGroup
.setLayout(new GridLayout());
256 createTagOptionButton(tagsGroup
, TagOpt
.AUTO_FOLLOW
,
257 UIText
.TagOptions_autoFollow
);
258 createTagOptionButton(tagsGroup
, TagOpt
.FETCH_TAGS
,
259 UIText
.TagOptions_fetchTags
);
260 createTagOptionButton(tagsGroup
, TagOpt
.NO_TAGS
,
261 UIText
.TagOptions_noTags
);
264 private void createTagOptionButton(Group tagsGroup
, final TagOpt option
,
266 Button button
= new Button(tagsGroup
, SWT
.RADIO
);
267 button
.setText(text
);
268 button
.setSelection(option
== tagOption
);
269 button
.addSelectionListener(new SelectionAdapter() {
271 public void widgetSelected(SelectionEvent e
) {
277 public void setSelection(@NonNull RepositorySelection selection
) {
278 revalidate(selection
);
281 public void setCredentials(UserPasswordCredentials credentials
) {
282 this.credentials
= credentials
;
286 * Set the ID for context sensitive help
291 public void setHelpContext(String id
) {
296 public void performHelp() {
297 PlatformUI
.getWorkbench().getHelpSystem().displayHelp(helpContext
);
301 * Check internal state for page completion status. This method should be
302 * called only when all necessary data from previous form is available.
304 private void checkPage() {
306 int checkedElementCount
= refsViewer
.getCheckedElements().length
;
307 selectB
.setEnabled(checkedElementCount
!= availableRefs
.size());
308 unselectB
.setEnabled(checkedElementCount
!= 0);
309 if (transportError
!= null) {
310 setErrorMessage(transportError
);
311 setPageComplete(false);
315 if (getSelectedBranches().isEmpty()) {
316 setErrorMessage(UIText
.SourceBranchPage_errorBranchRequired
);
317 setPageComplete(false);
320 setErrorMessage(null);
321 setPageComplete(true);
324 private void checkForEmptyRepo() {
325 if (isSourceRepoEmpty()) {
326 setErrorMessage(null);
327 setMessage(UIText
.SourceBranchPage_repoEmpty
, IMessageProvider
.WARNING
);
328 setPageComplete(true);
332 private void revalidate(@NonNull final RepositorySelection newRepoSelection
) {
333 if (newRepoSelection
.equals(validatedRepoSelection
)) {
334 // URI hasn't changed, no need to refill the page with new data
339 label
.setText(NLS
.bind(UIText
.SourceBranchPage_branchList
,
340 newRepoSelection
.getURI().toString()));
341 label
.getParent().layout();
343 validatedRepoSelection
= null;
344 transportError
= null;
346 availableRefs
.clear();
347 refsViewer
.setInput(null);
348 setPageComplete(false);
349 setErrorMessage(null);
351 label
.getDisplay().asyncExec(new Runnable() {
354 revalidateImpl(newRepoSelection
);
359 private void revalidateImpl(final RepositorySelection newRepoSelection
) {
360 if (label
.isDisposed() || !isCurrentPage())
363 final ListRemoteOperation listRemoteOp
;
364 final URIish uri
= newRepoSelection
.getURI();
366 listRemoteOp
= new ListRemoteOperation(uri
,
367 GitSettings
.getRemoteConnectionTimeout());
368 if (credentials
!= null)
370 .setCredentialsProvider(new EGitCredentialsProvider(
371 credentials
.getUser(), credentials
373 getContainer().run(true, true, new IRunnableWithProgress() {
375 public void run(IProgressMonitor monitor
)
376 throws InvocationTargetException
, InterruptedException
{
377 listRemoteOp
.run(monitor
);
380 } catch (InvocationTargetException e
) {
381 Throwable why
= e
.getCause();
383 if (showDetailedFailureDialog())
384 SourceBranchFailureDialog
.show(getShell(), uri
);
386 } catch (InterruptedException e
) {
387 transportError(UIText
.SourceBranchPage_remoteListingCancelled
);
391 final Ref idHEAD
= listRemoteOp
.getRemoteRef(Constants
.HEAD
);
393 boolean headIsMaster
= false;
394 final String masterBranchRef
= Constants
.R_HEADS
+ Constants
.MASTER
;
395 for (final Ref r
: listRemoteOp
.getRemoteRefs()) {
396 final String n
= r
.getName();
397 if (!n
.startsWith(Constants
.R_HEADS
)) {
400 availableRefs
.add(r
);
401 if (idHEAD
== null || headIsMaster
) {
404 ObjectId objectId
= r
.getObjectId();
405 if (objectId
== null) {
408 if (objectId
.equals(idHEAD
.getObjectId())) {
409 headIsMaster
= masterBranchRef
.equals(r
.getName());
410 if (head
== null || headIsMaster
) {
415 Collections
.sort(availableRefs
, CommonUtils
.REF_ASCENDING_COMPARATOR
);
416 if (idHEAD
!= null && head
== null) {
418 availableRefs
.add(0, idHEAD
);
421 validatedRepoSelection
= newRepoSelection
;
422 refsViewer
.setInput(availableRefs
);
423 refsViewer
.setAllChecked(true);
428 private void transportError(final Throwable why
) {
429 Activator
.logError(why
.getMessage(), why
);
430 Throwable cause
= why
.getCause();
431 if (why
instanceof TransportException
&& cause
!= null)
432 transportError(NLS
.bind(getMessage(why
), why
.getMessage(),
433 cause
.getMessage()));
435 transportError(why
.getMessage());
438 private String
getMessage(final Throwable why
) {
439 if (why
.getMessage().endsWith("Auth fail")) //$NON-NLS-1$
440 return UIText
.SourceBranchPage_AuthFailMessage
;
442 return UIText
.SourceBranchPage_CompositeTransportErrorMessage
;
445 private void transportError(final String msg
) {
446 transportError
= msg
;
450 private boolean showDetailedFailureDialog() {
453 .getPreferenceStore()
455 UIPreferences
.CLONE_WIZARD_SHOW_DETAILED_FAILURE_DIALOG
);