1 /*******************************************************************************
2  *  Copyright (c) 2000, 2018 IBM Corporation and others.
3  *
4  *  This program and the accompanying materials
5  *  are made available under the terms of the Eclipse Public License 2.0
6  *  which accompanies this distribution, and is available at
7  *  https://www.eclipse.org/legal/epl-2.0/
8  *
9  *  SPDX-License-Identifier: EPL-2.0
10  *
11  *  Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.team.internal.ccvs.ui.repo;
15 
16 
17 import java.util.Properties;
18 
19 import org.eclipse.core.runtime.IStatus;
20 import org.eclipse.jface.action.*;
21 import org.eclipse.jface.dialogs.IDialogSettings;
22 import org.eclipse.jface.util.IPropertyChangeListener;
23 import org.eclipse.jface.viewers.*;
24 import org.eclipse.jface.wizard.WizardDialog;
25 import org.eclipse.osgi.util.NLS;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.dnd.*;
28 import org.eclipse.swt.events.KeyAdapter;
29 import org.eclipse.swt.events.KeyEvent;
30 import org.eclipse.swt.widgets.*;
31 import org.eclipse.team.core.TeamException;
32 import org.eclipse.team.internal.ccvs.core.*;
33 import org.eclipse.team.internal.ccvs.core.util.KnownRepositories;
34 import org.eclipse.team.internal.ccvs.ui.*;
35 import org.eclipse.team.internal.ccvs.ui.model.AllRootsElement;
36 import org.eclipse.team.internal.ccvs.ui.wizards.NewLocationWizard;
37 import org.eclipse.team.internal.core.TeamPlugin;
38 import org.eclipse.team.internal.ui.actions.TeamAction;
39 import org.eclipse.ui.*;
40 import org.eclipse.ui.actions.ActionFactory;
41 import org.eclipse.ui.dialogs.PropertyDialogAction;
42 import org.eclipse.ui.part.PluginTransfer;
43 import org.eclipse.ui.part.PluginTransferData;
44 
45 /**
46  * RepositoriesView is a view on a set of known CVS repositories
47  * which allows navigation of the structure of the repository and
48  * the performing of CVS-specific operations on the repository contents.
49  */
50 public class RepositoriesView extends RemoteViewPart {
51 	public static final String VIEW_ID = "org.eclipse.team.ccvs.ui.RepositoriesView"; //$NON-NLS-1$
52 
53 	// The root
54 	private AllRootsElement root;
55 
56 	// Actions
57 	private IAction removeAction;
58 	private Action newAction;
59 	private Action newAnonAction;
60 	private PropertyDialogAction propertiesAction;
61 	private RemoveRootAction removeRootAction;
62 	private RemoveDateTagAction removeDateTagAction;
63 	private RepositoriesFilterAction repositoriesFilterAction;
64 	private IAction toggleFilterAction;
65 
66 	private RepositoriesSortingActionGroup repositoriesSortingActionGroup;
67 	private IDialogSettings dialogSettings;
68 	private static final String SELECTED_ORDER_BY = "selectedOrderBy"; //$NON-NLS-1$
69 	private static final String SELECTED_SORTING_ORDER = "selectedSortingOrder"; //$NON-NLS-1$
70 	private RepositoryComparator savedComparator;
71 	private RepositoriesFilter repositoriesFilter;
72 	private static final String FILTER_SHOW_MODULES = "filterShowModules"; //$NON-NLS-1$
73 
74 	IRepositoryListener listener = new IRepositoryListener() {
75 		@Override
76 		public void repositoryAdded(final ICVSRepositoryLocation root) {
77 			getViewer().getControl().getDisplay().asyncExec(() -> {
78 				refreshViewer();
79 				getViewer().setSelection(new StructuredSelection(root));
80 			});
81 		}
82 		@Override
83 		public void repositoriesChanged(ICVSRepositoryLocation[] roots) {
84 			refresh();
85 		}
86 		private void refresh() {
87 			Display display = getViewer().getControl().getDisplay();
88 			display.asyncExec(() -> RepositoriesView.this.refreshViewer());
89 		}
90 	};
91 
92 	private static final class RepositoryDragSourceListener implements DragSourceListener {
93 		private IStructuredSelection selection;
94 
95 		@Override
dragStart(DragSourceEvent event)96 		public void dragStart(DragSourceEvent event) {
97 			if(selection!=null) {
98 				final Object[] array = selection.toArray();
99 				// event.doit = Utils.getResources(array).length > 0;
100 				for (Object a : array) {
101 					if (a instanceof ICVSRemoteFile) {
102 						event.doit = true;
103 						return;
104 					}
105 				}
106 				event.doit = false;
107 			}
108 		}
109 
110 		@Override
dragSetData(DragSourceEvent event)111 		public void dragSetData(DragSourceEvent event) {
112 			if (selection!=null && CVSResourceTransfer.getInstance().isSupportedType(event.dataType)) {
113 				final Object[] array = selection.toArray();
114 				for (Object a : array) {
115 					if (a instanceof ICVSRemoteFile) {
116 						event.data = a;
117 						return;
118 					}
119 				}
120 			} else if (PluginTransfer.getInstance().isSupportedType(event.dataType)) {
121 				final Object[] array = selection.toArray();
122 				for (Object a : array) {
123 					if (a instanceof ICVSRemoteFile) {
124 						event.data = new PluginTransferData("org.eclipse.team.cvs.ui.cvsRemoteDrop", CVSResourceTransfer.getInstance().toByteArray((ICVSRemoteFile) a)); //$NON-NLS-1$
125 						return;
126 					}
127 				}
128 
129 			}
130 		}
131 
132 		@Override
dragFinished( DragSourceEvent event)133 		public void dragFinished( DragSourceEvent event) {
134 		}
135 
updateSelection( IStructuredSelection selection)136 		public void updateSelection( IStructuredSelection selection) {
137 			this.selection = selection;
138 		}
139 	}
140 
141 	RepositoryDragSourceListener repositoryDragSourceListener;
142 
143 	/**
144 	 * Constructor for RepositoriesView.
145 	 */
RepositoriesView()146 	public RepositoriesView() {
147 		super(VIEW_ID);
148 		IDialogSettings workbenchSettings = CVSUIPlugin.getPlugin().getDialogSettings();
149 		dialogSettings = workbenchSettings.getSection(VIEW_ID);
150 		if (dialogSettings == null) {
151 			dialogSettings = workbenchSettings.addNewSection(VIEW_ID);
152 		}
153 
154 		try {
155 			// parse the values
156 			String selectedOrderBy = dialogSettings.get(SELECTED_ORDER_BY);
157 			String selectedSortingOrder = dialogSettings.get(SELECTED_SORTING_ORDER);
158 
159 			int orderBy = Integer.parseInt(selectedOrderBy);
160 			boolean ascending = Boolean.valueOf(selectedSortingOrder).booleanValue();
161 
162 			savedComparator = new RepositoryComparator(orderBy, ascending);
163 		} catch (NumberFormatException e) {
164 			// use default comparator
165 			savedComparator = new RepositoryComparator(
166 					RepositoryComparator.ORDER_BY_LABEL, true);
167 		}
168 
169 		if (dialogSettings.get(FILTER_SHOW_MODULES) != null && !dialogSettings.get(FILTER_SHOW_MODULES).equals("")) //$NON-NLS-1$
170 			repositoriesFilter = new RepositoriesFilter(dialogSettings.getBoolean(FILTER_SHOW_MODULES));
171 	}
172 
173 	/**
174 	 * Contribute actions to the view
175 	 */
176 	@Override
contributeActions()177 	protected void contributeActions() {
178 
179 		final Shell shell = getShell();
180 
181 		// Create actions
182 
183 		// New Repository (popup)
184 		newAction = new Action(CVSUIMessages.RepositoriesView_new, CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_NEWLOCATION)) {
185 			@Override
186 			public void run() {
187 				NewLocationWizard wizard = new NewLocationWizard();
188 				wizard.setSwitchPerspectives(false);
189 				WizardDialog dialog = new WizardDialog(shell, wizard);
190 				dialog.open();
191 			}
192 		};
193 		PlatformUI.getWorkbench().getHelpSystem().setHelp(newAction, IHelpContextIds.NEW_REPOSITORY_LOCATION_ACTION);
194 
195 		if (includeAnonConnection()) {
196 			newAnonAction = new Action(CVSUIMessages.RepositoriesView_newAnonCVS, CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_NEWLOCATION)) {
197 				@Override
198 				public void run() {
199 					Properties p = new Properties();
200 					p.setProperty("connection", "pserver"); //$NON-NLS-1$ //$NON-NLS-2$
201 					p.setProperty("user", "anonymous"); //$NON-NLS-1$ //$NON-NLS-2$
202 					p.setProperty("host", "dev.eclipse.org"); //$NON-NLS-1$ //$NON-NLS-2$
203 					p.setProperty("root", "/cvsroot/eclipse"); //$NON-NLS-1$ //$NON-NLS-2$
204 					NewLocationWizard wizard = new NewLocationWizard(p);
205 					wizard.setSwitchPerspectives(false);
206 					WizardDialog dialog = new WizardDialog(shell, wizard);
207 					dialog.open();
208 				}
209 			};
210 			PlatformUI.getWorkbench().getHelpSystem().setHelp(newAnonAction, IHelpContextIds.NEW_DEV_ECLIPSE_REPOSITORY_LOCATION_ACTION);
211 		}
212 
213 		// Properties
214 		propertiesAction = new PropertyDialogAction(shell, getViewer());
215 		getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.PROPERTIES.getId(), propertiesAction);
216 		IStructuredSelection selection = getViewer().getStructuredSelection();
217 		if (selection.size() == 1 && selection.getFirstElement() instanceof RepositoryRoot) {
218 			propertiesAction.setEnabled(true);
219 		} else {
220 			propertiesAction.setEnabled(false);
221 		}
222 		getViewer().addSelectionChangedListener(event -> {
223 			IStructuredSelection ss = event.getStructuredSelection();
224 			boolean enabled = ss.size() == 1 && ss.getFirstElement() instanceof RepositoryRoot;
225 			propertiesAction.setEnabled(enabled);
226 		});
227 		removeRootAction = new RemoveRootAction(viewer.getControl().getShell(), this);
228 		removeRootAction.selectionChanged((IStructuredSelection)null);
229 		removeDateTagAction = new RemoveDateTagAction();
230 		removeDateTagAction.selectionChanged( (IStructuredSelection)null);
231 		removeAction = new Action(){
232 			@Override
233 			public void run(){
234 				if(removeRootAction.isEnabled()){
235 					removeRootAction.run();
236 				}
237 				if(removeDateTagAction.isEnabled()){
238 					removeDateTagAction.run();
239 				}
240 			}
241 		};
242 		PlatformUI.getWorkbench().getHelpSystem().setHelp(removeRootAction, IHelpContextIds.REMOVE_REPOSITORY_LOCATION_ACTION);
243 		IActionBars bars = getViewSite().getActionBars();
244 		bars.setGlobalActionHandler(ActionFactory.DELETE.getId(), removeAction);
245 
246 		// Sort By action group
247 		IPropertyChangeListener comparatorUpdater = event -> {
248 			String property = event.getProperty();
249 			if (RepositoriesSortingActionGroup.CHANGE_COMPARATOR
250 					.equals(property)) {
251 				Object newValue = event.getNewValue();
252 				getViewer().refresh();
253 				saveSelectedComparator((RepositoryComparator) newValue);
254 			}
255 		};
256 		setActionGroup(new RepositoriesSortingActionGroup(shell,
257 				comparatorUpdater));
258 		// restore comparator selection
259 		getRepositoriesSortingActionGroup().setSelectedComparator(
260 				savedComparator);
261 
262 		super.contributeActions();
263 
264 		toggleFilterAction = new Action(CVSUIMessages.RepositoriesView_NoFilter){
265 			@Override
266 			public void run(){
267 				if (repositoriesFilter != null)
268 					getViewer().removeFilter(repositoriesFilter);
269 					repositoriesFilter = null;
270 					toggleFilterAction.setEnabled(false);
271 					repositoriesFilterAction.setFilter(repositoriesFilter);
272 			}
273 		};
274 		toggleFilterAction.setEnabled(repositoriesFilter != null);
275 
276 		//Create the filter action
277 		repositoriesFilterAction = new RepositoriesFilterAction(this);
278 		repositoriesFilterAction.setText(CVSUIMessages.RepositoriesView_FilterOn);
279 		repositoriesFilterAction.init(getViewer());
280 		repositoriesFilterAction.setFilter(repositoriesFilter);
281 		repositoriesFilterAction.setToolTipText(CVSUIMessages.RepositoriesView_FilterRepositoriesTooltip);
282 		repositoriesFilterAction.setImageDescriptor(CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_FILTER_HISTORY));
283 
284 		IMenuManager actionBarsMenu = bars.getMenuManager();
285 		if (actionBarsMenu != null){
286 			actionBarsMenu.add(new Separator());
287 			actionBarsMenu.add(repositoriesFilterAction);
288 			actionBarsMenu.add(toggleFilterAction);
289 		}
290 	}
291 
saveSelectedComparator(RepositoryComparator selectedComparator)292 	private void saveSelectedComparator(RepositoryComparator selectedComparator) {
293 		if (dialogSettings != null) {
294 			dialogSettings.put(SELECTED_ORDER_BY, selectedComparator.getOrderBy());
295 			dialogSettings.put(SELECTED_SORTING_ORDER, selectedComparator.isAscending());
296 		}
297 	}
298 
299 	/**
300 	 * Returns the action group.
301 	 *
302 	 * @return the action group
303 	 */
getRepositoriesSortingActionGroup()304 	private RepositoriesSortingActionGroup getRepositoriesSortingActionGroup() {
305 		return repositoriesSortingActionGroup;
306 	}
307 
308 	/**
309 	 * Sets the action group.
310 	 *
311 	 * @param actionGroup the action group
312 	 */
setActionGroup(RepositoriesSortingActionGroup actionGroup)313 	private void setActionGroup(RepositoriesSortingActionGroup actionGroup) {
314 		this.repositoriesSortingActionGroup = actionGroup;
315 	}
316 
317 	/**
318 	 * Method includeEclipseConnection.
319 	 * @return boolean
320 	 */
includeAnonConnection()321 	private boolean includeAnonConnection() {
322 		return System.getProperty("eclipse.cvs.anon") != null; //$NON-NLS-1$
323 	}
324 
325 	@Override
addWorkbenchActions(IMenuManager manager)326 	protected void addWorkbenchActions(IMenuManager manager) {
327 		// New actions go next
328 		MenuManager sub = new MenuManager(CVSUIMessages.RepositoriesView_newSubmenu, IWorkbenchActionConstants.GROUP_ADD);
329 		manager.add(sub);
330 		super.addWorkbenchActions(manager);
331 		IStructuredSelection selection = getViewer().getStructuredSelection();
332 
333 		removeRootAction.selectionChanged(selection);
334 		removeDateTagAction.selectionChanged(selection);
335 		if(removeRootAction.isEnabled()) {
336 			manager.add(removeRootAction);
337 		}
338 		if(removeDateTagAction.isEnabled()){
339 			manager.add(removeDateTagAction);
340 		}
341 		if (selection.size() == 1 && selection.getFirstElement() instanceof RepositoryRoot) {
342 			manager.add(new Separator());
343 			manager.add(propertiesAction);
344 		}
345 		sub.add(newAction);
346 		if (newAnonAction != null)
347 			sub.add(newAnonAction);
348 		sub.add(new Separator("group1")); //$NON-NLS-1$
349 	}
350 
351 	@Override
createPartControl(Composite parent)352 	public void createPartControl(Composite parent) {
353 		super.createPartControl(parent);
354 		CVSUIPlugin.getPlugin().getRepositoryManager().addRepositoryListener(listener);
355 		// We need to set comparator on the viewer, in order to modify it by
356 		// repositoriesSortingActionGroup in the future. It's the same object
357 		getViewer().setComparator(savedComparator);
358 		if (repositoriesFilter != null)
359 			getViewer().addFilter(repositoriesFilter);
360 		getRepositoriesSortingActionGroup().fillActionBars(getViewSite().getActionBars());
361 	}
362 
363 	@Override
dispose()364 	public void dispose() {
365 		if (repositoriesFilter != null)
366 			dialogSettings.put(FILTER_SHOW_MODULES, repositoriesFilter.isShowModules());
367 		else
368 			dialogSettings.put(FILTER_SHOW_MODULES, (String) null);
369 		CVSUIPlugin.getPlugin().getRepositoryManager().removeRepositoryListener(listener);
370 		if (getRepositoriesSortingActionGroup() != null) {
371 			getRepositoriesSortingActionGroup().dispose();
372 		}
373 		super.dispose();
374 	}
375 
376 	/**
377 	 * Initialize the repositories and actions
378 	 */
initialize()379 	private void initialize() {
380 		root = new AllRootsElement();
381 	}
382 
383 	@Override
initializeListeners()384 	protected void initializeListeners() {
385 		super.initializeListeners();
386 		viewer.addSelectionChangedListener(removeRootAction);
387 		viewer.addSelectionChangedListener(removeDateTagAction);
388 		viewer.addSelectionChangedListener(event -> {
389 			IStructuredSelection selection = (IStructuredSelection)event.getSelection();
390 			handleChange(selection);
391 		});
392 
393 		repositoryDragSourceListener = new RepositoryDragSourceListener();
394 		viewer.addDragSupport( DND.DROP_LINK | DND.DROP_DEFAULT,
395 				new Transfer[] { CVSResourceTransfer.getInstance(),PluginTransfer.getInstance()},
396 				repositoryDragSourceListener);
397 	}
398 
399 	@Override
getTreeInput()400 	protected Object getTreeInput() {
401 		initialize();
402 		return root;
403 	}
404 
405 	@Override
selectionChanged(IWorkbenchPart part, ISelection selection)406 	public void selectionChanged(IWorkbenchPart part, ISelection selection) {
407 		String msg = getStatusLineMessage(selection);
408 		getViewSite().getActionBars().getStatusLineManager().setMessage(msg);
409 	}
410 
getStatusLineMessage(ISelection selection)411 	private String getStatusLineMessage(ISelection selection) {
412 		if (selection==null || selection.isEmpty()) return ""; //$NON-NLS-1$
413 		if (!(selection instanceof IStructuredSelection)) return ""; //$NON-NLS-1$
414 		IStructuredSelection s = (IStructuredSelection)selection;
415 
416 		if (s.size() > 1)
417 			return NLS.bind(CVSUIMessages.RepositoriesView_NItemsSelected, new String[] { String.valueOf(s.size()) });
418 		Object element = TeamAction.getAdapter(s.getFirstElement(), ICVSResource.class);
419 		if (element instanceof ICVSRemoteResource) {
420 			ICVSRemoteResource res = (ICVSRemoteResource)element;
421 			String name;
422 			if (res.isContainer()) {
423 				name = res.getRepositoryRelativePath();
424 			} else {
425 				try {
426 					name = res.getRepositoryRelativePath() + " " + ((ICVSRemoteFile)res).getRevision(); //$NON-NLS-1$
427 				} catch (TeamException e) {
428 					TeamPlugin.log(IStatus.ERROR, CVSUIMessages.RepositoriesView_CannotGetRevision, e);
429 					name = res.getRepositoryRelativePath();
430 				}
431 			}
432 			return NLS.bind(CVSUIMessages.RepositoriesView_ResourceInRepository, new String[] { name, res.getRepository().getLocation(true) });
433 		}
434 		return CVSUIMessages.RepositoriesView_OneItemSelected;
435 	}
436 
437 	@Override
getHelpContextId()438 	protected String getHelpContextId() {
439 		return IHelpContextIds.REPOSITORIES_VIEW;
440 	}
441 
442 	@Override
getKeyListener()443 	protected KeyAdapter getKeyListener() {
444 		return new KeyAdapter() {
445 			@Override
446 			public void keyPressed(KeyEvent event) {
447 				if (event.keyCode == SWT.F5) {
448 					if (WorkbenchUserAuthenticator.USE_ALTERNATE_PROMPTER) {
449 						ICVSRepositoryLocation[] locations = KnownRepositories.getInstance().getRepositories();
450 						for (ICVSRepositoryLocation location : locations) {
451 							location.flushUserInfo();
452 						}
453 					} else {
454 						refreshAll();
455 					}
456 				} else if (event.keyCode == SWT.F9 && WorkbenchUserAuthenticator.USE_ALTERNATE_PROMPTER) {
457 					refreshAll();
458 				}
459 			}
460 		};
461 	}
462 
463 	private void handleChange(IStructuredSelection selection){
464 		removeRootAction.updateSelection(selection);
465 		removeDateTagAction.updateSelection(selection);
466 		removeAction.setEnabled(removeRootAction.isEnabled() || removeDateTagAction.isEnabled());
467 
468 		repositoryDragSourceListener.updateSelection(selection);
469 	}
470 
471 	public void showFilter(RepositoriesFilter filter) {
472 		if (repositoriesFilter != null)
473 			getViewer().removeFilter(repositoriesFilter);
474 		repositoriesFilter = filter;
475 		getViewer().addFilter(filter);
476 		toggleFilterAction.setEnabled(true);
477 	}
478 
479 }
480