From 26cb30e844d66c67311fb39d6e42a5ec56541717 Mon Sep 17 00:00:00 2001 From: Markus Duft Date: Mon, 11 Jun 2012 07:30:10 +0200 Subject: [PATCH] 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 --- org.eclipse.egit.ui/icons/obj16/clean_obj.gif | Bin 0 -> 1024 bytes org.eclipse.egit.ui/plugin.properties | 2 + org.eclipse.egit.ui/plugin.xml | 59 +++++ .../src/org/eclipse/egit/ui/UIIcons.java | 4 + .../src/org/eclipse/egit/ui/UIText.java | 21 ++ .../ui/internal/clean/CleanRepositoryPage.java | 262 +++++++++++++++++++++ .../egit/ui/internal/clean/CleanWizard.java | 38 +++ .../egit/ui/internal/clean/CleanWizardDialog.java | 32 +++ .../repository/tree/command/CleanCommand.java | 34 +++ .../src/org/eclipse/egit/ui/uitext.properties | 7 + 10 files changed, 459 insertions(+) create mode 100644 org.eclipse.egit.ui/icons/obj16/clean_obj.gif create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanRepositoryPage.java create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizard.java create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clean/CleanWizardDialog.java create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/CleanCommand.java diff --git a/org.eclipse.egit.ui/icons/obj16/clean_obj.gif b/org.eclipse.egit.ui/icons/obj16/clean_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..32626119e8ce18f534d62930fa9fe17577802fa8 GIT binary patch literal 1024 zcwX((+fPyf0LSrzkczqjb55NuaO?7rE|-u_Tq>Hnsrk@yZDcxeqhxC%!pqvg2(nVA zhCZkzPAjKQ+sq~#ZIVktGmT8~pd_FOmY`e?x5GK&fB@`1 z0pvM2IUOg<#me%q@}iJW#W+P-#7tS7;#S=3?PwMA>?RYVXJHrEN%PzU^}{qP4=~k| z_v%l0cmP^UwDDs!Pm?rFNhm*Nz4bCGCjWk(1xhGjH&xd|)Ae3OJBq=6DmX|1-(GRP zsse|p;0OgAp@L(n;5Y>wr-BpI^$)48A&&MV4Vr9mPqyekmm6m87-lLgiU-EIn(euo zoq6v5{Jp&ewrR26y2P9NU? zV?b&_sWkgOdqp#3oSlwpke7Z}i%y=Q@yuVn134A=w3||bq8+O|bu>+7lb3UQ5;Iv6 znQ*rxp;K5A8lR%P-j`XY5v(WXsoE%sII(gdxFt4)F?`9}MgoFDf-;op^m9dB=L=~x zLCTvvY-7Bk+57klzJnB8E|5wqg#v!8n(<7{R1wLTW{4-dN#l?F_k`4|k4@fXr8=fMB~ literal 0 HcwPel00001 diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties index 95749efa6..1f75a27aa 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 1aa71ad87..906cc2532 100644 --- a/org.eclipse.egit.ui/plugin.xml +++ b/org.eclipse.egit.ui/plugin.xml @@ -1597,6 +1597,31 @@ + + + + + + + + + + + + + + + + + + + + @@ -2641,6 +2666,31 @@ + + + + + + + + + + + + + + + + + + + + @@ -4321,6 +4376,10 @@ icon="icons/obj16/revert.gif"> + + 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 ecc52d1f9..eb56bef8a 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 2a4c24e48..49318d2d0 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 000000000..62e1c6a01 --- /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 + * + * 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 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 getItemsToClean() { + Set result = new TreeSet(); + 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 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 000000000..4201e8147 --- /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 + * + * 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 000000000..2f112586d --- /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 + * + * 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 000000000..05606302a --- /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 + * + * 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 { + + 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 f13ab69f0..51cacb208 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 -- 2.11.4.GIT