diff options
author | Markus Duft | 2012-06-11 05:30:10 +0000 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org | 2013-01-26 00:45:35 +0000 |
commit | 26cb30e844d66c67311fb39d6e42a5ec56541717 (patch) | |
tree | 3177942be60500418f419d77aa83a839c095723b | |
parent | 99acfe7e14810aece31f10699017f1eb4710f28b (diff) | |
download | egit-26cb30e844d66c67311fb39d6e42a5ec56541717.tar.gz egit-26cb30e844d66c67311fb39d6e42a5ec56541717.tar.xz egit-26cb30e844d66c67311fb39d6e42a5ec56541717.zip |
Add clean action for repositories
This adds a "Clean..." menu item to the repository node in the
repository view. This has the advantage over the last try to add a clean
menu, that one can clean files and directories which are not part of the
workspace.
CQ: 6984
JGit-Dependency: Ibed0459005a5e306c010b9932f5b5fd107fb5448
Change-Id: I5136afd3333c6710b0c67c49618df6217e0d1fcf
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
10 files changed, 459 insertions, 0 deletions
diff --git a/org.eclipse.egit.ui/icons/obj16/clean_obj.gif b/org.eclipse.egit.ui/icons/obj16/clean_obj.gif Binary files differnew file mode 100644 index 0000000000..32626119e8 --- /dev/null +++ b/org.eclipse.egit.ui/icons/obj16/clean_obj.gif diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties index 95749efa61..1f75a27aa2 100644 --- a/org.eclipse.egit.ui/plugin.properties +++ b/org.eclipse.egit.ui/plugin.properties @@ -291,6 +291,8 @@ SubmoduleSyncCommand.name = Sync Submodule SubmoduleSyncCommand.label = Sync Submodule SubmoduleAddCommand.name = Add Submodule SubmoduleAddCommand.label = Add Submodule +CleanCommand.name = Clean... +CleanCommand.label = Clean... StashCreateCommand.name = Stash Changes StashCreateCommand.label = Stash Changes StashApplyCommand.name = Apply Stashed Changes diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml index 1aa71ad870..906cc25329 100644 --- a/org.eclipse.egit.ui/plugin.xml +++ b/org.eclipse.egit.ui/plugin.xml @@ -1597,6 +1597,31 @@ </activeWhen> </handler> <handler + commandId="org.eclipse.egit.ui.team.clean"> + <class + class="org.eclipse.egit.ui.internal.repository.tree.command.CleanCommand"> + </class> + <activeWhen> + <and> + <count + value="1"> + </count> + <iterate> + <and> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> + </instanceof> + <not> + <test + property="GitRepository.isBare"> + </test> + </not> + </and> + </iterate> + </and> + </activeWhen> + </handler> + <handler commandId="org.eclipse.egit.ui.team.stash.create"> <class class="org.eclipse.egit.ui.internal.repository.tree.command.StashCreateCommand"> @@ -2641,6 +2666,31 @@ </and> </visibleWhen> </command> + <command + commandId="org.eclipse.egit.ui.team.clean" + label="%CleanCommand.label" + style="push"> + <visibleWhen + checkEnabled="false"> + <and> + <count + value="1"> + </count> + <iterate> + <and> + <instanceof + value="org.eclipse.egit.ui.internal.repository.tree.RepositoryNode"> + </instanceof> + <not> + <test + property="GitRepository.isBare"> + </test> + </not> + </and> + </iterate> + </and> + </visibleWhen> + </command> <command commandId="org.eclipse.egit.ui.team.stash.create" label="%StashCreateCommand.label" @@ -4069,6 +4119,11 @@ </command> <command categoryId="org.eclipse.egit.ui.commandCategory" + id="org.eclipse.egit.ui.team.clean" + name="%CleanCommand.name"> + </command> + <command + categoryId="org.eclipse.egit.ui.commandCategory" id="org.eclipse.egit.ui.team.stash.create" defaultHandler="org.eclipse.egit.ui.internal.repository.tree.command.StashCreateCommand" name="%StashCreateCommand.name"> @@ -4321,6 +4376,10 @@ icon="icons/obj16/revert.gif"> </image> <image + commandId="org.eclipse.egit.ui.team.clean" + icon="icons/obj16/clean_obj.gif"> + </image> + <image commandId="org.eclipse.egit.ui.team.stash.create" icon="icons/obj16/stash-create.png"> </image> diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java index ecc52d1f97..eb56bef8a4 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIIcons.java @@ -215,6 +215,9 @@ public class UIIcons { /** Submodules icon */ public final static ImageDescriptor SUBMODULES; + /** Clean icon */ + public final static ImageDescriptor CLEAN; + /** Stash icon */ public final static ImageDescriptor STASH; @@ -297,6 +300,7 @@ public class UIIcons { TAG_ANNOTATED = map("obj16/annotated-tag.gif"); //$NON-NLS-1$ CREATE_REPOSITORY = map("etool16/createRepository.gif"); //$NON-NLS-1$ SUBMODULES = map("obj16/submodules.gif"); //$NON-NLS-1$ + CLEAN = map("obj16/clean_obj.gif"); //$NON-NLS-1$ STASH = map("obj16/stash.png"); //$NON-NLS-1$ HIERARCHY = map("elcl16/hierarchicalLayout.gif"); //$NON-NLS-1$ } diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java index 2a4c24e487..49318d2d05 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java @@ -903,6 +903,27 @@ public class UIText extends NLS { public static String RepositorySearchDialog_SomeDirectoriesHiddenMessage; /** */ + public static String CleanRepositoryPage_cleanDirs; + + /** */ + public static String CleanRepositoryPage_cleanFiles; + + /** */ + public static String CleanRepositoryPage_cleaningItems; + + /** */ + public static String CleanRepositoryPage_findingItems; + + /** */ + public static String CleanRepositoryPage_includeIgnored; + + /** */ + public static String CleanRepositoryPage_message; + + /** */ + public static String CleanRepositoryPage_title; + + /** */ public static String ClearCredentialsCommand_clearingCredentialsFailed; /** */ diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanRepositoryPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanRepositoryPage.java new file mode 100644 index 0000000000..62e1c6a01d --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanRepositoryPage.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (C) 2012, Markus Duft <markus.duft@salomon.at> + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.egit.ui.internal.clean; + +import java.lang.reflect.InvocationTargetException; +import java.util.Set; +import java.util.TreeSet; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.egit.core.internal.util.ProjectUtil; +import org.eclipse.egit.ui.Activator; +import org.eclipse.egit.ui.UIText; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.jgit.api.CleanCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +/** + * A page for the Clean wizard presenting all things to be cleaned to the user. + */ +public class CleanRepositoryPage extends WizardPage { + + private Repository repository; + private CheckboxTableViewer cleanTable; + private boolean cleanDirectories; + private boolean includeIgnored; + + /** + * Creates a new page for the given repository. + * @param repository repository to clean. + */ + public CleanRepositoryPage(Repository repository) { + super(UIText.CleanRepositoryPage_title); + this.repository = repository; + + setTitle(UIText.CleanRepositoryPage_title); + setMessage(UIText.CleanRepositoryPage_message); + } + + public void createControl(Composite parent) { + Composite main = new Composite(parent, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, true).applyTo(main); + main.setLayout(new GridLayout()); + + final Button radioCleanFiles = new Button(main, SWT.RADIO); + radioCleanFiles.setText(UIText.CleanRepositoryPage_cleanFiles); + GridDataFactory.fillDefaults().grab(true, false).applyTo(radioCleanFiles); + + final Button radioCleanDirs = new Button(main, SWT.RADIO); + radioCleanDirs.setText(UIText.CleanRepositoryPage_cleanDirs); + GridDataFactory.fillDefaults().grab(true, false).applyTo(radioCleanDirs); + + SelectionAdapter listener = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + cleanDirectories = radioCleanDirs.getSelection(); + updateCleanItems(); + } + }; + + radioCleanFiles.addSelectionListener(listener); + radioCleanDirs.addSelectionListener(listener); + + radioCleanFiles.setSelection(true); + + final Image fileImage = PlatformUI.getWorkbench().getSharedImages() + .getImage(ISharedImages.IMG_OBJ_FILE); + final Image dirImage = PlatformUI.getWorkbench().getSharedImages() + .getImage(ISharedImages.IMG_OBJ_FOLDER); + + cleanTable = CheckboxTableViewer.newCheckList(main, SWT.BORDER); + cleanTable.setContentProvider(new ArrayContentProvider()); + cleanTable.setLabelProvider(new LabelProvider() { + @Override + public Image getImage(Object element) { + if(!(element instanceof String)) + return null; + + if(((String)element).endsWith("/")) //$NON-NLS-1$ + return dirImage; + else + return fileImage; + } + }); + + GridDataFactory.fillDefaults().grab(true, true).applyTo(cleanTable.getControl()); + + Composite lowerComp = new Composite(main, SWT.NONE); + GridDataFactory.fillDefaults().grab(true, false).applyTo(lowerComp); + lowerComp.setLayout(new GridLayout(3, false)); + + final Button checkIncludeIgnored = new Button(lowerComp, SWT.CHECK); + checkIncludeIgnored.setText(UIText.CleanRepositoryPage_includeIgnored); + GridDataFactory.fillDefaults().grab(true, false).applyTo(checkIncludeIgnored); + checkIncludeIgnored.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + includeIgnored = checkIncludeIgnored.getSelection(); + updateCleanItems(); + } + }); + + Button selAll = new Button(lowerComp, SWT.PUSH); + selAll.setText(UIText.WizardProjectsImportPage_selectAll); + GridDataFactory.defaultsFor(selAll).applyTo(selAll); + + Button selNone = new Button(lowerComp, SWT.PUSH); + selNone.setText(UIText.WizardProjectsImportPage_deselectAll); + GridDataFactory.defaultsFor(selNone).applyTo(selNone); + + selAll.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (cleanTable.getInput() instanceof Set<?>) { + Set<?> input = (Set<?>) cleanTable.getInput(); + cleanTable.setCheckedElements(input.toArray()); + } + } + }); + + selNone.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + cleanTable.setCheckedElements(new Object[0]); + } + }); + + setControl(main); + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + + if(visible) + getShell().getDisplay().asyncExec(new Runnable() { + public void run() { + updateCleanItems(); + } + }); + } + + private void updateCleanItems() { + try { + getContainer().run(true, false, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + monitor.beginTask(UIText.CleanRepositoryPage_findingItems, IProgressMonitor.UNKNOWN); + + Git git = Git.wrap(repository); + CleanCommand command = git.clean().setDryRun(true); + command.setCleanDirectories(cleanDirectories); + command.setIgnore(!includeIgnored); + try { + final Set<String> paths = command.call(); + + getShell().getDisplay().syncExec(new Runnable() { + public void run() { + cleanTable.setInput(paths); + } + }); + } catch (GitAPIException ex) { + Activator.logError("cannot call clean command!", ex); //$NON-NLS-1$ + } + + monitor.done(); + } + }); + } catch (InvocationTargetException e) { + Activator.logError("Unexpected exception while finding items to clean", e); //$NON-NLS-1$ + clearPage(); + } catch (InterruptedException e) { + clearPage(); + } + } + + private void clearPage() { + cleanTable.setInput(null); + } + + /** + * Retrieves the items that the user chose to clean. + * @return the items to clean. + */ + public Set<String> getItemsToClean() { + Set<String> result = new TreeSet<String>(); + for(Object ele : cleanTable.getCheckedElements()) { + String str = ele.toString(); + + if(str.endsWith("/")) //$NON-NLS-1$ + result.add(str.substring(0, str.length() - 1)); + else + result.add(str); + } + + return result; + } + + /** + * Do the cleaning with the selected values. + */ + public void finish() { + try { + final Set<String> itemsToClean = getItemsToClean(); + + getContainer().run(true, false, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + monitor.beginTask(UIText.CleanRepositoryPage_cleaningItems, IProgressMonitor.UNKNOWN); + + Git git = Git.wrap(repository); + CleanCommand command = git.clean().setDryRun(false); + command.setCleanDirectories(cleanDirectories); + command.setIgnore(!includeIgnored); + command.setPaths(itemsToClean); + try { + command.call(); + } catch (GitAPIException ex) { + Activator.logError("cannot call clean command!", ex); //$NON-NLS-1$ + } + + try { + IProject[] projects = ProjectUtil.getProjectsContaining(repository, itemsToClean); + ProjectUtil.refreshResources(projects, new SubProgressMonitor(monitor, 1)); + } catch (CoreException e) { + // could not refresh... not a "real" problem + } + + monitor.done(); + } + }); + } catch (Exception e) { + Activator.logError("Unexpected exception while cleaning", e); //$NON-NLS-1$ + } + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizard.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizard.java new file mode 100644 index 0000000000..4201e81472 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizard.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (C) 2012, Markus Duft <markus.duft@salomon.at> + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.egit.ui.internal.clean; + +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jgit.lib.Repository; + +/** + * Represents the contents of the Clean Wizard + */ +public class CleanWizard extends Wizard { + + private CleanRepositoryPage cleanPage; + + /** + * Creates a new Wizard and adds all required pages. + * @param repository the repository to clean + */ + public CleanWizard(Repository repository) { + setNeedsProgressMonitor(true); + cleanPage = new CleanRepositoryPage(repository); + addPage(cleanPage); + } + + @Override + public boolean performFinish() { + cleanPage.finish(); + return true; + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizardDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizardDialog.java new file mode 100644 index 0000000000..2f112586d8 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizardDialog.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (C) 2012, Markus Duft <markus.duft@salomon.at> + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.egit.ui.internal.clean; + +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.swt.widgets.Shell; + +/** + * A Wizard that guides the user through cleaning the repository. + */ +public class CleanWizardDialog extends WizardDialog { + + /** + * Creates a new Clean Wizard instance + * + * @param parentShell + * parent shell + * @param repository + */ + public CleanWizardDialog(Shell parentShell, Repository repository) { + super(parentShell, new CleanWizard(repository)); + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CleanCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CleanCommand.java new file mode 100644 index 0000000000..05606302ac --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CleanCommand.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (C) 2012, Markus Duft <markus.duft@salomon.at> + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ + +package org.eclipse.egit.ui.internal.repository.tree.command; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.egit.ui.internal.clean.CleanWizardDialog; +import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode; +import org.eclipse.jgit.lib.Repository; + +/** + * Performs a clean operation on a repository. + */ +public class CleanCommand extends RepositoriesViewCommandHandler<RepositoryNode> { + + public Object execute(ExecutionEvent event) throws ExecutionException { + RepositoryNode node = getSelectedNodes(event).get(0); + Repository repository = node.getRepository(); + + CleanWizardDialog dlg = new CleanWizardDialog(getShell(event), repository); + dlg.setBlockOnOpen(true); + dlg.open(); + + return null; + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties index f13ab69f07..51cacb208f 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties @@ -237,6 +237,13 @@ GitProjectPropertyPage_ValueEmptyRepository=None (empty repository) GitProjectPropertyPage_ValueUnbornBranch=None (unborn branch) GitProjectsImportPage_NoProjectsMessage=No projects found +CleanRepositoryPage_cleanDirs=Clean selected untracked files and directories +CleanRepositoryPage_cleanFiles=Clean selected untracked files +CleanRepositoryPage_cleaningItems=Cleaning selected items... +CleanRepositoryPage_findingItems=Finding items to clean... +CleanRepositoryPage_includeIgnored=Include ignored resources +CleanRepositoryPage_message=Select items to clean +CleanRepositoryPage_title=Clean Repository ClearCredentialsCommand_clearingCredentialsFailed=Clearing credentials failed. CheckoutConflictDialog_conflictMessage=The files shown below have uncommitted changes which would be lost by the selected operation.\n\nEither commit the changes to the repository or discard the changes by resetting the current branch. CheckoutDialog_Message=Select a ref and choose action to execute |